Add sort in updatesince api and default sorting by updatedAt in descending order

This commit is contained in:
Hongbo Wu
2022-11-25 11:44:55 +08:00
parent db3d4c7cfd
commit 64fd0cfdc6
5 changed files with 114 additions and 70 deletions

View File

@ -1538,6 +1538,7 @@ export type QueryUpdatesSinceArgs = {
after?: InputMaybe<Scalars['String']>;
first?: InputMaybe<Scalars['Int']>;
since: Scalars['Date'];
sort?: InputMaybe<SortParams>;
};

View File

@ -1061,7 +1061,7 @@ type Query {
sharedArticle(selectedHighlightId: String, slug: String!, username: String!): SharedArticleResult!
subscriptions(sort: SortParams): SubscriptionsResult!
typeaheadSearch(first: Int, query: String!): TypeaheadSearchResult!
updatesSince(after: String, first: Int, since: Date!): UpdatesSinceResult!
updatesSince(after: String, first: Int, since: Date!, sort: SortParams): UpdatesSinceResult!
user(userId: ID, username: String): UserResult!
users: UsersResult!
validateUsername(username: String!): Boolean!

View File

@ -14,6 +14,7 @@ import {
CreateArticleErrorCode,
CreateArticleSuccess,
FeedArticle,
InputMaybe,
MutationCreateArticleArgs,
MutationSaveArticleReadingProgressArgs,
MutationSetBookmarkArticleArgs,
@ -37,6 +38,7 @@ import {
SetShareArticleError,
SetShareArticleErrorCode,
SetShareArticleSuccess,
SortParams,
TypeaheadSearchError,
TypeaheadSearchErrorCode,
TypeaheadSearchSuccess,
@ -966,74 +968,84 @@ export const updatesSinceResolver = authorized<
UpdatesSinceSuccess,
UpdatesSinceError,
QueryUpdatesSinceArgs
>(async (_obj, { since, first, after }, { claims: { uid } }) => {
if (!uid) {
return { errorCodes: [UpdatesSinceErrorCode.Unauthorized] }
}
analytics.track({
userId: uid,
event: 'updatesSince',
properties: {
env: env.server.apiEnv,
since,
first,
after,
},
})
const startCursor = after || ''
const size = first || 10
const startDate = new Date(since)
const [pages, totalCount] = (await searchPages(
{
from: Number(startCursor),
size: size + 1, // fetch one more item to get next cursor
includeDeleted: true,
dateFilters: [{ field: 'updatedAt', startDate }],
sort: { by: SortBy.UPDATED, order: SortOrder.ASCENDING },
},
uid
)) || [[], 0]
const start =
startCursor && !isNaN(Number(startCursor)) ? Number(startCursor) : 0
const hasNextPage = pages.length > size
const endCursor = String(start + pages.length - (hasNextPage ? 1 : 0))
//TODO: refactor so that the lastCursor included
if (hasNextPage) {
// remove an extra if exists
pages.pop()
}
const edges = pages.map((p) => {
const updateReason = getUpdateReason(p, startDate)
return {
node: {
...p,
image: p.image && createImageProxyUrl(p.image, 260, 260),
isArchived: !!p.archivedAt,
contentReader:
p.pageType === PageType.File ? ContentReader.Pdf : ContentReader.Web,
} as SearchItem,
cursor: endCursor,
itemID: p.id,
updateReason,
>(
async (
_obj,
{ since, first, after, sort: sortParams },
{ claims: { uid } }
) => {
if (!uid) {
return { errorCodes: [UpdatesSinceErrorCode.Unauthorized] }
}
})
return {
edges,
pageInfo: {
hasPreviousPage: false,
startCursor,
hasNextPage,
endCursor,
totalCount,
},
analytics.track({
userId: uid,
event: 'updatesSince',
properties: {
env: env.server.apiEnv,
since,
first,
after,
},
})
const sort = sortParamsToElasticSort(sortParams)
const startCursor = after || ''
const size = first || 10
const startDate = new Date(since)
const [pages, totalCount] = (await searchPages(
{
from: Number(startCursor),
size: size + 1, // fetch one more item to get next cursor
includeDeleted: true,
dateFilters: [{ field: 'updatedAt', startDate }],
sort,
},
uid
)) || [[], 0]
const start =
startCursor && !isNaN(Number(startCursor)) ? Number(startCursor) : 0
const hasNextPage = pages.length > size
const endCursor = String(start + pages.length - (hasNextPage ? 1 : 0))
//TODO: refactor so that the lastCursor included
if (hasNextPage) {
// remove an extra if exists
pages.pop()
}
const edges = pages.map((p) => {
const updateReason = getUpdateReason(p, startDate)
return {
node: {
...p,
image: p.image && createImageProxyUrl(p.image, 260, 260),
isArchived: !!p.archivedAt,
contentReader:
p.pageType === PageType.File
? ContentReader.Pdf
: ContentReader.Web,
} as SearchItem,
cursor: endCursor,
itemID: p.id,
updateReason,
}
})
return {
edges,
pageInfo: {
hasPreviousPage: false,
startCursor,
hasNextPage,
endCursor,
totalCount,
},
}
}
})
)
const getUpdateReason = (page: Page, since: Date) => {
if (page.state === ArticleSavingRequestStatus.Deleted) {
@ -1044,3 +1056,29 @@ const getUpdateReason = (page: Page, since: Date) => {
}
return UpdateReason.Updated
}
const sortParamsToElasticSort = (
sortParams: InputMaybe<SortParams> | undefined
) => {
const sort = { by: SortBy.UPDATED, order: SortOrder.DESCENDING }
if (sortParams) {
sortParams.order === 'ASCENDING' && (sort.order = SortOrder.ASCENDING)
switch (sortParams.by) {
case 'UPDATED_TIME':
sort.by = SortBy.UPDATED
break
case 'SCORE':
sort.by = SortBy.SCORE
break
case 'PUBLISHED_AT':
sort.by = SortBy.PUBLISHED
break
case 'SAVED_AT':
sort.by = SortBy.SAVED
break
}
}
return sort
}

View File

@ -2167,7 +2167,12 @@ const schema = gql`
webhook(id: ID!): WebhookResult!
apiKeys: ApiKeysResult!
typeaheadSearch(query: String!, first: Int): TypeaheadSearchResult!
updatesSince(after: String, first: Int, since: Date!): UpdatesSinceResult!
updatesSince(
after: String
first: Int
since: Date!
sort: SortParams
): UpdatesSinceResult!
integrations: IntegrationsResult!
recentSearches: RecentSearchesResult!
rules(enabled: Boolean): RulesResult!

View File

@ -1071,15 +1071,15 @@ describe('Article API', () => {
).length
).to.eql(3)
expect(res.body.data.updatesSince.edges[0].itemID).to.eq(
deletedPages[0].id
deletedPages[2].id
)
expect(res.body.data.updatesSince.edges[1].itemID).to.eq(
deletedPages[1].id
)
expect(res.body.data.updatesSince.edges[2].itemID).to.eq(
deletedPages[2].id
deletedPages[0].id
)
expect(res.body.data.updatesSince.edges[2].updateReason).to.eq(
expect(res.body.data.updatesSince.edges[0].updateReason).to.eq(
UpdateReason.Deleted
)
})