Commit 14712b42 authored by Steven's avatar Steven

chore: add pagination to list inboxes

parent b4d72e33
...@@ -61,10 +61,20 @@ message Inbox { ...@@ -61,10 +61,20 @@ message Inbox {
message ListInboxesRequest { message ListInboxesRequest {
// Format: users/{id} // Format: users/{id}
string user = 1; string user = 1;
// The maximum number of inbox to return.
int32 page_size = 2;
// Provide this to retrieve the subsequent page.
string page_token = 3;
} }
message ListInboxesResponse { message ListInboxesResponse {
repeated Inbox inboxes = 1; repeated Inbox inboxes = 1;
// A token, which can be sent as `page_token` to retrieve the next page.
// If this field is omitted, there are no subsequent pages.
string next_page_token = 2;
} }
message UpdateInboxRequest { message UpdateInboxRequest {
......
This diff is collapsed.
...@@ -194,6 +194,17 @@ paths: ...@@ -194,6 +194,17 @@ paths:
in: query in: query
required: false required: false
type: string type: string
- name: pageSize
description: The maximum number of inbox to return.
in: query
required: false
type: integer
format: int32
- name: pageToken
description: Provide this to retrieve the subsequent page.
in: query
required: false
type: string
tags: tags:
- InboxService - InboxService
/api/v1/markdown/link:metadata: /api/v1/markdown/link:metadata:
...@@ -2491,6 +2502,11 @@ definitions: ...@@ -2491,6 +2502,11 @@ definitions:
items: items:
type: object type: object
$ref: '#/definitions/v1Inbox' $ref: '#/definitions/v1Inbox'
nextPageToken:
type: string
description: |-
A token, which can be sent as `page_token` to retrieve the next page.
If this field is omitted, there are no subsequent pages.
v1ListMemoCommentsResponse: v1ListMemoCommentsResponse:
type: object type: object
properties: properties:
......
...@@ -14,30 +14,58 @@ import ( ...@@ -14,30 +14,58 @@ import (
"github.com/usememos/memos/store" "github.com/usememos/memos/store"
) )
func (s *APIV1Service) ListInboxes(ctx context.Context, _ *v1pb.ListInboxesRequest) (*v1pb.ListInboxesResponse, error) { func (s *APIV1Service) ListInboxes(ctx context.Context, request *v1pb.ListInboxesRequest) (*v1pb.ListInboxesResponse, error) {
user, err := s.GetCurrentUser(ctx) user, err := s.GetCurrentUser(ctx)
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get user") return nil, status.Errorf(codes.Internal, "failed to get user")
} }
var limit, offset int
if request.PageToken != "" {
var pageToken v1pb.PageToken
if err := unmarshalPageToken(request.PageToken, &pageToken); err != nil {
return nil, status.Errorf(codes.InvalidArgument, "invalid page token: %v", err)
}
limit = int(pageToken.Limit)
offset = int(pageToken.Offset)
} else {
limit = int(request.PageSize)
}
if limit <= 0 {
limit = DefaultPageSize
}
limitPlusOne := limit + 1
inboxes, err := s.Store.ListInboxes(ctx, &store.FindInbox{ inboxes, err := s.Store.ListInboxes(ctx, &store.FindInbox{
ReceiverID: &user.ID, ReceiverID: &user.ID,
Limit: &limitPlusOne,
Offset: &offset,
}) })
if err != nil { if err != nil {
return nil, status.Errorf(codes.Internal, "failed to list inbox: %v", err) return nil, status.Errorf(codes.Internal, "failed to list inbox: %v", err)
} }
response := &v1pb.ListInboxesResponse{ inboxMessages := []*v1pb.Inbox{}
Inboxes: []*v1pb.Inbox{}, nextPageToken := ""
if len(inboxes) == limitPlusOne {
inboxes = inboxes[:limit]
nextPageToken, err = getPageToken(limit, offset+limit)
if err != nil {
return nil, status.Errorf(codes.Internal, "failed to get next page token, error: %v", err)
}
} }
for _, inbox := range inboxes { for _, inbox := range inboxes {
inboxMessage := convertInboxFromStore(inbox) inboxMessage := convertInboxFromStore(inbox)
if inboxMessage.Type == v1pb.Inbox_TYPE_UNSPECIFIED { if inboxMessage.Type == v1pb.Inbox_TYPE_UNSPECIFIED {
continue continue
} }
response.Inboxes = append(response.Inboxes, inboxMessage) inboxMessages = append(inboxMessages, inboxMessage)
} }
response := &v1pb.ListInboxesResponse{
Inboxes: inboxMessages,
NextPageToken: nextPageToken,
}
return response, nil return response, nil
} }
......
...@@ -30,6 +30,7 @@ import ( ...@@ -30,6 +30,7 @@ import (
) )
const ( const (
// DefaultPageSize is the default page size for listing memos.
DefaultPageSize = 10 DefaultPageSize = 10
) )
......
...@@ -2,6 +2,7 @@ package mysql ...@@ -2,6 +2,7 @@ package mysql
import ( import (
"context" "context"
"fmt"
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
...@@ -61,6 +62,12 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I ...@@ -61,6 +62,12 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I
} }
query := "SELECT `id`, UNIX_TIMESTAMP(`created_ts`), `sender_id`, `receiver_id`, `status`, `message` FROM `inbox` WHERE " + strings.Join(where, " AND ") + " ORDER BY `created_ts` DESC" query := "SELECT `id`, UNIX_TIMESTAMP(`created_ts`), `sender_id`, `receiver_id`, `status`, `message` FROM `inbox` WHERE " + strings.Join(where, " AND ") + " ORDER BY `created_ts` DESC"
if find.Limit != nil {
query = fmt.Sprintf("%s LIMIT %d", query, *find.Limit)
if find.Offset != nil {
query = fmt.Sprintf("%s OFFSET %d", query, *find.Offset)
}
}
rows, err := d.db.QueryContext(ctx, query, args...) rows, err := d.db.QueryContext(ctx, query, args...)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -2,6 +2,7 @@ package postgres ...@@ -2,6 +2,7 @@ package postgres
import ( import (
"context" "context"
"fmt"
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
...@@ -51,6 +52,12 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I ...@@ -51,6 +52,12 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I
} }
query := "SELECT id, created_ts, sender_id, receiver_id, status, message FROM inbox WHERE " + strings.Join(where, " AND ") + " ORDER BY created_ts DESC" query := "SELECT id, created_ts, sender_id, receiver_id, status, message FROM inbox WHERE " + strings.Join(where, " AND ") + " ORDER BY created_ts DESC"
if find.Limit != nil {
query = fmt.Sprintf("%s LIMIT %d", query, *find.Limit)
if find.Offset != nil {
query = fmt.Sprintf("%s OFFSET %d", query, *find.Offset)
}
}
rows, err := d.db.QueryContext(ctx, query, args...) rows, err := d.db.QueryContext(ctx, query, args...)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -2,6 +2,7 @@ package sqlite ...@@ -2,6 +2,7 @@ package sqlite
import ( import (
"context" "context"
"fmt"
"strings" "strings"
"github.com/pkg/errors" "github.com/pkg/errors"
...@@ -53,6 +54,12 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I ...@@ -53,6 +54,12 @@ func (d *DB) ListInboxes(ctx context.Context, find *store.FindInbox) ([]*store.I
} }
query := "SELECT `id`, `created_ts`, `sender_id`, `receiver_id`, `status`, `message` FROM `inbox` WHERE " + strings.Join(where, " AND ") + " ORDER BY `created_ts` DESC" query := "SELECT `id`, `created_ts`, `sender_id`, `receiver_id`, `status`, `message` FROM `inbox` WHERE " + strings.Join(where, " AND ") + " ORDER BY `created_ts` DESC"
if find.Limit != nil {
query = fmt.Sprintf("%s LIMIT %d", query, *find.Limit)
if find.Offset != nil {
query = fmt.Sprintf("%s OFFSET %d", query, *find.Offset)
}
}
rows, err := d.db.QueryContext(ctx, query, args...) rows, err := d.db.QueryContext(ctx, query, args...)
if err != nil { if err != nil {
return nil, err return nil, err
......
...@@ -37,6 +37,10 @@ type FindInbox struct { ...@@ -37,6 +37,10 @@ type FindInbox struct {
SenderID *int32 SenderID *int32
ReceiverID *int32 ReceiverID *int32
Status *InboxStatus Status *InboxStatus
// Pagination
Limit *int
Offset *int
} }
type DeleteInbox struct { type DeleteInbox struct {
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment