Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

✨ Add pagination support for listing Connection, Cred Ex, and Pres Ex records #3033

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 19 additions & 2 deletions aries_cloudagent/messaging/models/paginated_query.py
Original file line number Diff line number Diff line change
@@ -1,10 +1,12 @@
"""Class for paginated query parameters."""

from marshmallow import fields
from typing import Tuple

from aries_cloudagent.storage.base import DEFAULT_PAGE_SIZE, MAXIMUM_PAGE_SIZE
from aiohttp.web import BaseRequest
from marshmallow import fields

from ...messaging.models.openapi import OpenAPISchema
from ...storage.base import DEFAULT_PAGE_SIZE, MAXIMUM_PAGE_SIZE


class PaginatedQuerySchema(OpenAPISchema):
Expand All @@ -29,3 +31,18 @@ class PaginatedQuerySchema(OpenAPISchema):
metadata={"description": "Offset for pagination", "example": 0},
error_messages={"validator_failed": "Value must be 0 or greater"},
)


def get_limit_offset(request: BaseRequest) -> Tuple[int, int]:
"""Read the limit and offset query parameters from a request as ints, with defaults.

Args:
request: aiohttp request object

Returns:
A tuple of the limit and offset values
"""

limit = int(request.query.get("limit", DEFAULT_PAGE_SIZE))
offset = int(request.query.get("offset", 0))
return limit, offset
6 changes: 2 additions & 4 deletions aries_cloudagent/multitenant/admin/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,9 @@
from ...core.profile import ProfileManagerProvider
from ...messaging.models.base import BaseModelError
from ...messaging.models.openapi import OpenAPISchema
from ...messaging.models.paginated_query import PaginatedQuerySchema
from ...messaging.models.paginated_query import PaginatedQuerySchema, get_limit_offset
from ...messaging.valid import UUID4_EXAMPLE, JSONWebToken
from ...multitenant.base import BaseMultitenantManager
from ...storage.base import DEFAULT_PAGE_SIZE
from ...storage.error import StorageError, StorageNotFoundError
from ...utils.endorsement_setup import attempt_auto_author_with_endorser_setup
from ...utils.profiles import subwallet_type_not_same_as_base_wallet_raise_web_exception
Expand Down Expand Up @@ -382,8 +381,7 @@ async def wallets_list(request: web.BaseRequest):
if wallet_name:
query["wallet_name"] = wallet_name

limit = int(request.query.get("limit", DEFAULT_PAGE_SIZE))
offset = int(request.query.get("offset", 0))
limit, offset = get_limit_offset(request)

try:
async with profile.session() as session:
Expand Down
12 changes: 10 additions & 2 deletions aries_cloudagent/protocols/connections/v1_0/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from ....connections.models.conn_record import ConnRecord, ConnRecordSchema
from ....messaging.models.base import BaseModelError
from ....messaging.models.openapi import OpenAPISchema
from ....messaging.models.paginated_query import PaginatedQuerySchema, get_limit_offset
from ....messaging.valid import (
ENDPOINT_EXAMPLE,
ENDPOINT_VALIDATE,
Expand Down Expand Up @@ -236,7 +237,7 @@ class ConnectionStaticResultSchema(OpenAPISchema):
record = fields.Nested(ConnRecordSchema(), required=True)


class ConnectionsListQueryStringSchema(OpenAPISchema):
class ConnectionsListQueryStringSchema(PaginatedQuerySchema):
"""Parameters and validators for connections list request query string."""

alias = fields.Str(
Expand Down Expand Up @@ -468,11 +469,18 @@ async def connections_list(request: web.BaseRequest):
if request.query.get("connection_protocol"):
post_filter["connection_protocol"] = request.query["connection_protocol"]

limit, offset = get_limit_offset(request)

profile = context.profile
try:
async with profile.session() as session:
records = await ConnRecord.query(
session, tag_filter, post_filter_positive=post_filter, alt=True
session,
tag_filter,
limit=limit,
offset=offset,
post_filter_positive=post_filter,
alt=True,
)
results = [record.serialize() for record in records]
results.sort(key=connection_sort_key)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,8 @@ async def test_connections_list(self):
"their_public_did": "a_public_did",
"invitation_msg_id": "dummy_msg",
},
limit=100,
offset=0,
post_filter_positive={
"their_role": list(ConnRecord.Role.REQUESTER.value),
"connection_protocol": "connections/1.0",
Expand Down
7 changes: 6 additions & 1 deletion aries_cloudagent/protocols/issue_credential/v1_0/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
from ....messaging.credential_definitions.util import CRED_DEF_TAGS
from ....messaging.models.base import BaseModelError
from ....messaging.models.openapi import OpenAPISchema
from ....messaging.models.paginated_query import PaginatedQuerySchema, get_limit_offset
from ....messaging.valid import (
INDY_CRED_DEF_ID_EXAMPLE,
INDY_CRED_DEF_ID_VALIDATE,
Expand Down Expand Up @@ -57,7 +58,7 @@ class IssueCredentialModuleResponseSchema(OpenAPISchema):
"""Response schema for Issue Credential Module."""


class V10CredentialExchangeListQueryStringSchema(OpenAPISchema):
class V10CredentialExchangeListQueryStringSchema(PaginatedQuerySchema):
"""Parameters and validators for credential exchange list query."""

connection_id = fields.Str(
Expand Down Expand Up @@ -403,11 +404,15 @@ async def credential_exchange_list(request: web.BaseRequest):
if request.query.get(k, "") != ""
}

limit, offset = get_limit_offset(request)

try:
async with context.profile.session() as session:
records = await V10CredentialExchange.query(
session=session,
tag_filter=tag_filter,
limit=limit,
offset=offset,
post_filter_positive=post_filter,
)
results = [record.serialize() for record in records]
Expand Down
7 changes: 6 additions & 1 deletion aries_cloudagent/protocols/issue_credential/v2_0/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from ....messaging.decorators.attach_decorator import AttachDecorator
from ....messaging.models.base import BaseModelError
from ....messaging.models.openapi import OpenAPISchema
from ....messaging.models.paginated_query import PaginatedQuerySchema, get_limit_offset
from ....messaging.valid import (
INDY_CRED_DEF_ID_EXAMPLE,
INDY_CRED_DEF_ID_VALIDATE,
Expand Down Expand Up @@ -63,7 +64,7 @@ class V20IssueCredentialModuleResponseSchema(OpenAPISchema):
"""Response schema for v2.0 Issue Credential Module."""


class V20CredExRecordListQueryStringSchema(OpenAPISchema):
class V20CredExRecordListQueryStringSchema(PaginatedQuerySchema):
"""Parameters and validators for credential exchange record list query."""

connection_id = fields.Str(
Expand Down Expand Up @@ -566,11 +567,15 @@ async def credential_exchange_list(request: web.BaseRequest):
if request.query.get(k, "") != ""
}

limit, offset = get_limit_offset(request)

try:
async with profile.session() as session:
cred_ex_records = await V20CredExRecord.query(
session=session,
tag_filter=tag_filter,
limit=limit,
offset=offset,
post_filter_positive=post_filter,
)

Expand Down
7 changes: 6 additions & 1 deletion aries_cloudagent/protocols/present_proof/v1_0/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
from ....messaging.decorators.attach_decorator import AttachDecorator
from ....messaging.models.base import BaseModelError
from ....messaging.models.openapi import OpenAPISchema
from ....messaging.models.paginated_query import PaginatedQuerySchema, get_limit_offset
from ....messaging.valid import (
INDY_EXTRA_WQL_EXAMPLE,
INDY_EXTRA_WQL_VALIDATE,
Expand Down Expand Up @@ -54,7 +55,7 @@ class V10PresentProofModuleResponseSchema(OpenAPISchema):
"""Response schema for Present Proof Module."""


class V10PresentationExchangeListQueryStringSchema(OpenAPISchema):
class V10PresentationExchangeListQueryStringSchema(PaginatedQuerySchema):
"""Parameters and validators for presentation exchange list query."""

connection_id = fields.Str(
Expand Down Expand Up @@ -310,11 +311,15 @@ async def presentation_exchange_list(request: web.BaseRequest):
if request.query.get(k, "") != ""
}

limit, offset = get_limit_offset(request)

try:
async with context.profile.session() as session:
records = await V10PresentationExchange.query(
session=session,
tag_filter=tag_filter,
limit=limit,
offset=offset,
post_filter_positive=post_filter,
)
results = [record.serialize() for record in records]
Expand Down
7 changes: 6 additions & 1 deletion aries_cloudagent/protocols/present_proof/v2_0/routes.py
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@
from ....messaging.decorators.attach_decorator import AttachDecorator
from ....messaging.models.base import BaseModelError
from ....messaging.models.openapi import OpenAPISchema
from ....messaging.models.paginated_query import PaginatedQuerySchema, get_limit_offset
from ....messaging.valid import (
INDY_EXTRA_WQL_EXAMPLE,
INDY_EXTRA_WQL_VALIDATE,
Expand Down Expand Up @@ -70,7 +71,7 @@ class V20PresentProofModuleResponseSchema(OpenAPISchema):
"""Response schema for Present Proof Module."""


class V20PresExRecordListQueryStringSchema(OpenAPISchema):
class V20PresExRecordListQueryStringSchema(PaginatedQuerySchema):
"""Parameters and validators for presentation exchange list query."""

connection_id = fields.Str(
Expand Down Expand Up @@ -448,11 +449,15 @@ async def present_proof_list(request: web.BaseRequest):
if request.query.get(k, "") != ""
}

limit, offset = get_limit_offset(request)

try:
async with profile.session() as session:
records = await V20PresExRecord.query(
session=session,
tag_filter=tag_filter,
limit=limit,
offset=offset,
post_filter_positive=post_filter,
)
results = [record.serialize() for record in records]
Expand Down
Loading