mirror of
https://github.com/hcengineering/platform.git
synced 2026-09-12 20:57:45 +02:00
Refresh queries (#85)
Signed-off-by: Kristina Fefelova <kristin.fefelova@gmail.com>
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
import { CollaboratorsQuery, LabelsQuery, MessagesQuery, NotificationContextsQuery, NotificationsQuery } from './query'
|
||||
|
||||
export type { MessageQueryParams } from '@hcengineering/communication-query'
|
||||
export { initLiveQueries } from './init'
|
||||
export { initLiveQueries, refreshLiveQueries } from './init'
|
||||
|
||||
export function createMessagesQuery (dontDestroy?: boolean): MessagesQuery {
|
||||
return new MessagesQuery(dontDestroy)
|
||||
|
||||
@@ -46,3 +46,9 @@ export function initLiveQueries (
|
||||
|
||||
lq = new LiveQueries(client, workspace, filesUrl)
|
||||
}
|
||||
|
||||
export async function refreshLiveQueries (): Promise<void> {
|
||||
if (lq != null) {
|
||||
await lq.refresh()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,15 +15,15 @@
|
||||
|
||||
import type { AccountID, Collaborator, FindCollaboratorsParams, WorkspaceID } from '@hcengineering/communication-types'
|
||||
import {
|
||||
AddCollaboratorsEvent,
|
||||
CardEventType,
|
||||
type Event,
|
||||
type EventResult,
|
||||
type FindClient,
|
||||
type QueryCallback,
|
||||
type Event,
|
||||
NotificationEventType,
|
||||
CardEventType,
|
||||
AddCollaboratorsEvent,
|
||||
RemoveCollaboratorsEvent,
|
||||
RemoveCardEvent
|
||||
type QueryCallback,
|
||||
RemoveCardEvent,
|
||||
RemoveCollaboratorsEvent
|
||||
} from '@hcengineering/communication-sdk-types'
|
||||
|
||||
import { QueryResult } from '../result'
|
||||
@@ -47,6 +47,9 @@ export class CollaboratorsQuery implements Query<Collaborator, FindCollaborators
|
||||
void this.notify()
|
||||
} else {
|
||||
this.result = this.initResult()
|
||||
void this.result.then(() => {
|
||||
void this.notify()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -123,10 +126,7 @@ export class CollaboratorsQuery implements Query<Collaborator, FindCollaborators
|
||||
private async initResult (): Promise<QueryResult<Collaborator>> {
|
||||
try {
|
||||
const res = await this.find(this.params)
|
||||
const result = new QueryResult(res, (c) => c.account)
|
||||
|
||||
void this.notify()
|
||||
return result
|
||||
return new QueryResult(res, (c) => c.account)
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize query:', error)
|
||||
return new QueryResult([] as Collaborator[], (c) => c.account)
|
||||
@@ -175,4 +175,9 @@ export class CollaboratorsQuery implements Query<Collaborator, FindCollaborators
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
public async refresh (): Promise<void> {
|
||||
this.result = new QueryResult([] as Collaborator[], (c) => c.account)
|
||||
await this.initResult()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,16 +15,16 @@
|
||||
|
||||
import type { FindLabelsParams, Label, WorkspaceID } from '@hcengineering/communication-types'
|
||||
import {
|
||||
type EventResult,
|
||||
type FindClient,
|
||||
type QueryCallback,
|
||||
type Event,
|
||||
LabelEventType,
|
||||
CardEventType,
|
||||
CreateLabelEvent,
|
||||
type Event,
|
||||
type EventResult,
|
||||
type FindClient,
|
||||
LabelEventType,
|
||||
type QueryCallback,
|
||||
RemoveCardEvent,
|
||||
RemoveLabelEvent,
|
||||
UpdateCardTypeEvent,
|
||||
RemoveCardEvent
|
||||
UpdateCardTypeEvent
|
||||
} from '@hcengineering/communication-sdk-types'
|
||||
|
||||
import { QueryResult } from '../result'
|
||||
@@ -52,6 +52,9 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
|
||||
void this.notify()
|
||||
} else {
|
||||
this.result = this.initResult()
|
||||
void this.result.then(() => {
|
||||
void this.notify()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,10 +189,7 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
|
||||
private async initResult (): Promise<QueryResult<Label>> {
|
||||
try {
|
||||
const res = await this.find(this.params)
|
||||
const result = new QueryResult(res, getId)
|
||||
|
||||
void this.notify()
|
||||
return result
|
||||
return new QueryResult(res, getId)
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize query:', error)
|
||||
return new QueryResult([] as Label[], getId)
|
||||
@@ -251,4 +251,9 @@ export class LabelsQuery implements Query<Label, FindLabelsParams> {
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
async refresh (): Promise<void> {
|
||||
this.result = new QueryResult([] as Label[], getId)
|
||||
await this.initResult()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,4 +221,19 @@ export class LiveQueries {
|
||||
this.queries.clear()
|
||||
this.unsubscribed.clear()
|
||||
}
|
||||
|
||||
async refresh (): Promise<void> {
|
||||
for (const [id, query] of this.queries.entries()) {
|
||||
if (this.unsubscribed.has(id)) {
|
||||
this.unsubscribe(id)
|
||||
continue
|
||||
}
|
||||
|
||||
try {
|
||||
await query.refresh()
|
||||
} catch (e) {
|
||||
console.error('Failed to refresh live query', e, query.id, query.params)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ const GROUPS_LIMIT = 4
|
||||
export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
|
||||
private result: Promise<QueryResult<Message>> | QueryResult<Message>
|
||||
|
||||
private readonly groupsBuffer: MessagesGroup[] = []
|
||||
private groupsBuffer: MessagesGroup[] = []
|
||||
|
||||
private firstGroup?: MessagesGroup
|
||||
private lastGroup?: MessagesGroup
|
||||
@@ -69,6 +69,9 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
|
||||
private readonly limit: number
|
||||
private initialized = false
|
||||
|
||||
nexLoadedPagesCount = 0
|
||||
prevLoadedPagesCount = 0
|
||||
|
||||
private readonly next = {
|
||||
hasMessages: true,
|
||||
hasGroups: true,
|
||||
@@ -250,33 +253,37 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
|
||||
await this.client.unsubscribeQuery(this.id)
|
||||
}
|
||||
|
||||
async requestLoadNextPage (): Promise<void> {
|
||||
if (this.isCardRemoved) return
|
||||
async requestLoadNextPage (notify = true): Promise<{ isDone: boolean }> {
|
||||
if (this.isCardRemoved) return { isDone: true }
|
||||
if (this.result instanceof Promise) this.result = await this.result
|
||||
|
||||
if (!this.result.isTail()) {
|
||||
this.result = this.loadPage(Direction.Forward, this.result)
|
||||
void this.result
|
||||
.then(() => this.notify())
|
||||
.catch((error) => {
|
||||
console.error('Failed to load messages', error)
|
||||
void this.notify()
|
||||
})
|
||||
if (this.result.isTail()) return { isDone: true }
|
||||
|
||||
const pagePromise = this.loadPage(Direction.Forward, this.result)
|
||||
this.nexLoadedPagesCount++
|
||||
this.result = pagePromise
|
||||
|
||||
const r = await pagePromise
|
||||
if (notify) {
|
||||
await this.notify()
|
||||
}
|
||||
return { isDone: r.isTail() }
|
||||
}
|
||||
|
||||
async requestLoadPrevPage (): Promise<void> {
|
||||
if (this.isCardRemoved) return
|
||||
async requestLoadPrevPage (notify = true): Promise<{ isDone: boolean }> {
|
||||
if (this.isCardRemoved) return { isDone: true }
|
||||
if (this.result instanceof Promise) this.result = await this.result
|
||||
if (!this.result.isHead()) {
|
||||
this.result = this.loadPage(Direction.Backward, this.result)
|
||||
void this.result
|
||||
.then(() => this.notify())
|
||||
.catch((error) => {
|
||||
console.error('Failed to load messages', error)
|
||||
void this.notify()
|
||||
})
|
||||
if (this.result.isHead()) return { isDone: true }
|
||||
|
||||
const pagePromise = this.loadPage(Direction.Backward, this.result)
|
||||
this.prevLoadedPagesCount++
|
||||
this.result = pagePromise
|
||||
const r = await pagePromise
|
||||
|
||||
if (notify) {
|
||||
await this.notify()
|
||||
}
|
||||
return { isDone: r.isHead() }
|
||||
}
|
||||
|
||||
removeCallback (): void {
|
||||
@@ -845,4 +852,50 @@ export class MessagesQuery implements PagedQuery<Message, MessageQueryParams> {
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
async refresh (): Promise<void> {
|
||||
const nextPagesCount = this.nexLoadedPagesCount
|
||||
const prevPagesCount = this.prevLoadedPagesCount
|
||||
|
||||
this.nexLoadedPagesCount = 0
|
||||
this.prevLoadedPagesCount = 0
|
||||
|
||||
this.groupsBuffer = []
|
||||
this.firstGroup = undefined
|
||||
this.lastGroup = undefined
|
||||
|
||||
this.firstLoadedGroup = undefined
|
||||
this.lastLoadedGroup = undefined
|
||||
|
||||
this.lastGroupsDirection = undefined
|
||||
|
||||
this.next.hasMessages = true
|
||||
this.next.hasGroups = true
|
||||
this.next.buffer = []
|
||||
this.prev.hasMessages = true
|
||||
this.prev.hasGroups = true
|
||||
this.prev.buffer = []
|
||||
|
||||
this.createdPatches.clear()
|
||||
this.tmpMessages.clear()
|
||||
|
||||
this.result = new QueryResult([] as Message[], (x) => x.id)
|
||||
this.result.setTail(this.params.from == null)
|
||||
this.result.setHead(this.params.from == null)
|
||||
this.initialized = false
|
||||
|
||||
for (let i = 0; i < nextPagesCount; i++) {
|
||||
const { isDone } = await this.requestLoadNextPage(false)
|
||||
this.initialized = true
|
||||
if (!isDone) break
|
||||
}
|
||||
|
||||
for (let i = 0; i < prevPagesCount; i++) {
|
||||
const { isDone } = await this.requestLoadPrevPage(false)
|
||||
this.initialized = true
|
||||
if (!isDone) break
|
||||
}
|
||||
|
||||
await this.notify()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -59,8 +59,11 @@ import { findMessage, loadMessageFromGroup, matchNotification } from '../utils'
|
||||
const allowedPatchTypes = [PatchType.update, PatchType.remove, PatchType.blob]
|
||||
export class NotificationContextsQuery implements PagedQuery<NotificationContext, FindNotificationContextParams> {
|
||||
private result: QueryResult<NotificationContext> | Promise<QueryResult<NotificationContext>>
|
||||
private forward: Promise<NotificationContext[]> | NotificationContext[] = []
|
||||
private backward: Promise<NotificationContext[]> | NotificationContext[] = []
|
||||
private forward: Promise<{ isDone: boolean }> | { isDone: boolean } = { isDone: false }
|
||||
private backward: Promise<{ isDone: boolean }> | { isDone: boolean } = { isDone: false }
|
||||
|
||||
nexLoadedPagesCount = 0
|
||||
prevLoadedPagesCount = 0
|
||||
|
||||
constructor (
|
||||
private readonly client: FindClient,
|
||||
@@ -76,39 +79,46 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
|
||||
limit: params.limit,
|
||||
order: params.order ?? defaultQueryParams.order
|
||||
}
|
||||
const limit = params.limit != null ? params.limit + 1 : undefined
|
||||
|
||||
if (initialResult !== undefined) {
|
||||
this.result = initialResult
|
||||
void this.notify()
|
||||
} else {
|
||||
this.result = this.initResult()
|
||||
void this.result.then(() => {
|
||||
void this.notify()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private async rawInitResult (): Promise<QueryResult<NotificationContext>> {
|
||||
const limit = this.params.limit != null ? this.params.limit + 1 : undefined
|
||||
const findParams: FindNotificationContextParams = {
|
||||
...this.params,
|
||||
order: this.params.order ?? defaultQueryParams.order,
|
||||
limit
|
||||
}
|
||||
|
||||
if (initialResult !== undefined) {
|
||||
this.result = initialResult
|
||||
void this.notify()
|
||||
} else {
|
||||
const findPromise = this.find(findParams)
|
||||
this.result = findPromise.then((res) => {
|
||||
const allLoaded = limit == null || res.length < limit
|
||||
const isTail = allLoaded || (params.lastNotify == null && params.order === SortingOrder.Descending)
|
||||
const isHead = allLoaded || (params.lastNotify == null && params.order === SortingOrder.Ascending)
|
||||
const res = await this.find(findParams)
|
||||
const isComplete = limit == null || res.length < limit
|
||||
if (!isComplete) res.pop()
|
||||
|
||||
if (limit != null && res.length >= limit) {
|
||||
res.pop()
|
||||
}
|
||||
const qResult = new QueryResult(res, (x) => x.id)
|
||||
qResult.setTail(isTail)
|
||||
qResult.setHead(isHead)
|
||||
const isTail = isComplete || (this.params.lastNotify == null && this.params.order === SortingOrder.Descending)
|
||||
const isHead = isComplete || (this.params.lastNotify == null && this.params.order === SortingOrder.Ascending)
|
||||
|
||||
return qResult
|
||||
})
|
||||
this.result
|
||||
.then(async () => {
|
||||
await this.notify()
|
||||
})
|
||||
.catch((err: any) => {
|
||||
console.error('Failed to update Live query: ', err)
|
||||
})
|
||||
const result = new QueryResult(res, (it) => it.id)
|
||||
result.setTail(isTail)
|
||||
result.setHead(isHead)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private async initResult (): Promise<QueryResult<NotificationContext>> {
|
||||
try {
|
||||
return await this.rawInitResult()
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize query:', error)
|
||||
return new QueryResult([] as NotificationContext[], (it) => it.id)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -156,18 +166,14 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
|
||||
await this.client.unsubscribeQuery(this.id)
|
||||
}
|
||||
|
||||
async requestLoadNextPage (): Promise<void> {
|
||||
if (this.result instanceof Promise) {
|
||||
this.result = await this.result
|
||||
}
|
||||
if (this.forward instanceof Promise) {
|
||||
this.forward = await this.forward
|
||||
}
|
||||
async requestLoadNextPage (notify = true): Promise<{ isDone: boolean }> {
|
||||
if (this.result instanceof Promise) this.result = await this.result
|
||||
if (this.forward instanceof Promise) this.forward = await this.forward
|
||||
|
||||
if (this.result.isTail()) return
|
||||
if (this.result.isTail()) return { isDone: true }
|
||||
|
||||
const last = this.result.getLast()
|
||||
if (last === undefined) return
|
||||
if (last === undefined) return { isDone: false }
|
||||
|
||||
const limit = this.params.limit ?? defaultQueryParams.limit
|
||||
const findParams: FindNotificationContextParams = {
|
||||
@@ -180,8 +186,7 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
|
||||
}
|
||||
|
||||
const forward = this.find(findParams)
|
||||
|
||||
this.forward = forward.then(async (res) => {
|
||||
const forwardPromise = forward.then(async (res) => {
|
||||
if (this.result instanceof Promise) {
|
||||
this.result = await this.result
|
||||
}
|
||||
@@ -191,23 +196,28 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
|
||||
}
|
||||
this.result.append(res)
|
||||
this.result.setTail(isTail)
|
||||
await this.notify()
|
||||
return res
|
||||
this.nexLoadedPagesCount++
|
||||
|
||||
if (notify) {
|
||||
await this.notify()
|
||||
}
|
||||
|
||||
return { isDone: isTail }
|
||||
})
|
||||
|
||||
this.forward = forwardPromise
|
||||
|
||||
return await forwardPromise
|
||||
}
|
||||
|
||||
async requestLoadPrevPage (): Promise<void> {
|
||||
if (this.result instanceof Promise) {
|
||||
this.result = await this.result
|
||||
}
|
||||
if (this.backward instanceof Promise) {
|
||||
this.backward = await this.backward
|
||||
}
|
||||
async requestLoadPrevPage (notify = true): Promise<{ isDone: boolean }> {
|
||||
if (this.result instanceof Promise) this.result = await this.result
|
||||
if (this.backward instanceof Promise) this.backward = await this.backward
|
||||
|
||||
if (this.result.isHead()) return
|
||||
if (this.result.isHead()) return { isDone: true }
|
||||
|
||||
const first = this.params.order === SortingOrder.Ascending ? this.result.getFirst() : this.result.getLast()
|
||||
if (first === undefined) return
|
||||
if (first === undefined) return { isDone: false }
|
||||
|
||||
const limit = this.params.limit ?? defaultQueryParams.limit
|
||||
const findParams: FindNotificationContextParams = {
|
||||
@@ -220,10 +230,9 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
|
||||
}
|
||||
|
||||
const backward = this.find(findParams)
|
||||
this.backward = backward.then(async (res) => {
|
||||
if (this.result instanceof Promise) {
|
||||
this.result = await this.result
|
||||
}
|
||||
const backwardPromise = backward.then(async (res) => {
|
||||
if (this.result instanceof Promise) this.result = await this.result
|
||||
|
||||
const isHead = res.length <= limit
|
||||
if (!isHead) {
|
||||
res.pop()
|
||||
@@ -236,9 +245,16 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
|
||||
this.result.append(res)
|
||||
}
|
||||
this.result.setHead(isHead)
|
||||
await this.notify()
|
||||
return res
|
||||
this.prevLoadedPagesCount++
|
||||
if (notify) {
|
||||
await this.notify()
|
||||
}
|
||||
return { isDone: isHead }
|
||||
})
|
||||
|
||||
this.backward = backwardPromise
|
||||
|
||||
return await backwardPromise
|
||||
}
|
||||
|
||||
removeCallback (): void {
|
||||
@@ -711,4 +727,27 @@ export class NotificationContextsQuery implements PagedQuery<NotificationContext
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
async refresh (): Promise<void> {
|
||||
const nextPagesCount = this.nexLoadedPagesCount
|
||||
const prevPagesCount = this.prevLoadedPagesCount
|
||||
|
||||
this.result = new QueryResult([] as NotificationContext[], (it) => it.id)
|
||||
this.nexLoadedPagesCount = 0
|
||||
this.prevLoadedPagesCount = 0
|
||||
|
||||
this.result = await this.rawInitResult()
|
||||
|
||||
for (let i = 0; i < nextPagesCount; i++) {
|
||||
const { isDone } = await this.requestLoadNextPage(false)
|
||||
if (!isDone) break
|
||||
}
|
||||
|
||||
for (let i = 0; i < prevPagesCount; i++) {
|
||||
const { isDone } = await this.requestLoadPrevPage(false)
|
||||
if (!isDone) break
|
||||
}
|
||||
|
||||
await this.notify()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,19 +25,19 @@ import {
|
||||
type WorkspaceID
|
||||
} from '@hcengineering/communication-types'
|
||||
import {
|
||||
type FindClient,
|
||||
type PagedQueryCallback,
|
||||
type Event,
|
||||
NotificationEventType,
|
||||
MessageEventType,
|
||||
CardEventType,
|
||||
CreateNotificationEvent,
|
||||
UpdateNotificationContextEvent,
|
||||
UpdateNotificationEvent,
|
||||
RemoveNotificationsEvent,
|
||||
RemoveNotificationContextEvent,
|
||||
type Event,
|
||||
type FindClient,
|
||||
MessageEventType,
|
||||
NotificationEventType,
|
||||
type PagedQueryCallback,
|
||||
PatchEvent,
|
||||
RemoveCardEvent,
|
||||
PatchEvent
|
||||
RemoveNotificationContextEvent,
|
||||
RemoveNotificationsEvent,
|
||||
UpdateNotificationContextEvent,
|
||||
UpdateNotificationEvent
|
||||
} from '@hcengineering/communication-sdk-types'
|
||||
import { applyPatches, MessageProcessor, NotificationProcessor } from '@hcengineering/communication-shared'
|
||||
|
||||
@@ -51,6 +51,9 @@ const allowedPatchTypes = [PatchType.update, PatchType.remove, PatchType.blob]
|
||||
export class NotificationQuery implements PagedQuery<Notification, NotificationQueryParams> {
|
||||
private result: QueryResult<Notification> | Promise<QueryResult<Notification>>
|
||||
|
||||
nexLoadedPagesCount = 0
|
||||
prevLoadedPagesCount = 0
|
||||
|
||||
constructor (
|
||||
private readonly client: FindClient,
|
||||
private readonly workspace: WorkspaceID,
|
||||
@@ -60,33 +63,39 @@ export class NotificationQuery implements PagedQuery<Notification, NotificationQ
|
||||
private callback?: PagedQueryCallback<Notification>,
|
||||
initialResult?: QueryResult<Notification>
|
||||
) {
|
||||
const limit = this.params.limit ?? defaultQueryParams.limit
|
||||
const findParams: FindNotificationsParams = {
|
||||
...this.params,
|
||||
order: this.params.order ?? defaultQueryParams.order,
|
||||
limit: this.params.strict === true ? limit : limit + 1
|
||||
}
|
||||
|
||||
if (initialResult !== undefined) {
|
||||
this.result = initialResult
|
||||
void this.notify()
|
||||
} else {
|
||||
this.result = this.initResult(findParams, limit)
|
||||
this.result = this.initResult()
|
||||
void this.result.then(() => {
|
||||
void this.notify()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private async initResult (findParams: FindNotificationsParams, limit: number): Promise<QueryResult<Notification>> {
|
||||
private async rawInitResult (): Promise<QueryResult<Notification>> {
|
||||
const limit = this.params.limit != null ? this.params.limit + 1 : undefined
|
||||
const findParams: FindNotificationsParams = {
|
||||
...this.params,
|
||||
order: this.params.order ?? defaultQueryParams.order,
|
||||
limit: this.params.strict === true ? this.params.limit : limit
|
||||
}
|
||||
|
||||
const res = await this.find(findParams)
|
||||
const isComplete = this.params.limit == null || this.params.strict === true || res.length < this.params.limit
|
||||
if (!isComplete) res.pop()
|
||||
|
||||
const result = new QueryResult(res, (it) => it.id)
|
||||
result.setTail(isComplete)
|
||||
result.setHead(isComplete)
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private async initResult (): Promise<QueryResult<Notification>> {
|
||||
try {
|
||||
const res = await this.find(findParams)
|
||||
const isComplete = res.length <= limit
|
||||
if (!isComplete) res.pop()
|
||||
|
||||
const result = new QueryResult(res, (it) => it.id)
|
||||
result.setTail(isComplete)
|
||||
result.setHead(isComplete)
|
||||
|
||||
void this.notify()
|
||||
return result
|
||||
return await this.rawInitResult()
|
||||
} catch (error) {
|
||||
console.error('Failed to initialize query:', error)
|
||||
return new QueryResult([] as Notification[], (it) => it.id)
|
||||
@@ -131,24 +140,33 @@ export class NotificationQuery implements PagedQuery<Notification, NotificationQ
|
||||
await this.client.unsubscribeQuery(this.id)
|
||||
}
|
||||
|
||||
async requestLoadNextPage (): Promise<void> {
|
||||
if (this.params.strict === true) return
|
||||
async requestLoadNextPage (notify = true): Promise<{ isDone: boolean }> {
|
||||
if (this.params.strict === true) return { isDone: true }
|
||||
if (this.result instanceof Promise) this.result = await this.result
|
||||
if (this.result.isTail()) return { isDone: true }
|
||||
|
||||
await this.loadPage(SortingOrder.Ascending, this.result.getLast()?.created)
|
||||
const result = await this.loadPage(SortingOrder.Ascending, this.result.getLast()?.created, notify)
|
||||
this.nexLoadedPagesCount++
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
async requestLoadPrevPage (): Promise<void> {
|
||||
if (this.params.strict === true) return
|
||||
async requestLoadPrevPage (notify = true): Promise<{ isDone: boolean }> {
|
||||
if (this.params.strict === true) return { isDone: true }
|
||||
if (this.result instanceof Promise) this.result = await this.result
|
||||
await this.loadPage(SortingOrder.Descending, this.result.getFirst()?.created)
|
||||
if (this.result.isHead()) return { isDone: true }
|
||||
const result = await this.loadPage(SortingOrder.Descending, this.result.getFirst()?.created, notify)
|
||||
this.prevLoadedPagesCount++
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
private async loadPage (order: SortingOrder, created?: Date): Promise<void> {
|
||||
if (created == null) return
|
||||
private async loadPage (order: SortingOrder, created?: Date, notify = true): Promise<{ isDone: boolean }> {
|
||||
if (created == null) return { isDone: false }
|
||||
if (this.params.limit == null) return { isDone: true }
|
||||
if (this.result instanceof Promise) this.result = await this.result
|
||||
|
||||
const limit = this.getLimit()
|
||||
const limit = this.params.limit
|
||||
const findParams: FindNotificationsParams = {
|
||||
...this.params,
|
||||
created: order === SortingOrder.Ascending ? { greater: created } : { less: created },
|
||||
@@ -158,21 +176,27 @@ export class NotificationQuery implements PagedQuery<Notification, NotificationQ
|
||||
|
||||
try {
|
||||
const res = await this.find(findParams)
|
||||
const isComplete = res.length <= limit
|
||||
if (!isComplete) res.pop()
|
||||
const isDone = res.length <= limit
|
||||
if (!isDone) res.pop()
|
||||
|
||||
if (order === SortingOrder.Ascending) {
|
||||
this.result.append(res)
|
||||
this.result.setTail(isComplete)
|
||||
this.result.setTail(isDone)
|
||||
} else {
|
||||
this.result.prepend(res)
|
||||
this.result.setHead(isComplete)
|
||||
this.result.setHead(isDone)
|
||||
}
|
||||
|
||||
await this.notify()
|
||||
if (notify) {
|
||||
await this.notify()
|
||||
}
|
||||
|
||||
return { isDone }
|
||||
} catch (error) {
|
||||
console.error(`Failed to load ${order === SortingOrder.Ascending ? 'next' : 'previous'} page:`, error)
|
||||
}
|
||||
|
||||
return { isDone: false }
|
||||
}
|
||||
|
||||
removeCallback (): void {
|
||||
@@ -278,8 +302,9 @@ export class NotificationQuery implements PagedQuery<Notification, NotificationQ
|
||||
}
|
||||
|
||||
const newLength = result.length
|
||||
const { limit } = this.params
|
||||
|
||||
if (currentLength !== newLength && currentLength >= this.getLimit() && newLength < this.getLimit()) {
|
||||
if (limit != null && currentLength !== newLength && currentLength >= limit && newLength < limit) {
|
||||
await this.reinit(currentLength)
|
||||
} else {
|
||||
void this.notify()
|
||||
@@ -312,8 +337,9 @@ export class NotificationQuery implements PagedQuery<Notification, NotificationQ
|
||||
}
|
||||
|
||||
const newLength = this.result.length
|
||||
const { limit } = this.params
|
||||
|
||||
if (currentLength >= this.getLimit() && newLength < this.getLimit()) {
|
||||
if (limit != null && currentLength >= limit && newLength < limit) {
|
||||
void this.reinit(currentLength)
|
||||
} else if (isDeleted) {
|
||||
void this.notify()
|
||||
@@ -339,7 +365,8 @@ export class NotificationQuery implements PagedQuery<Notification, NotificationQ
|
||||
this.result.delete(notification.id)
|
||||
}
|
||||
|
||||
if (length >= this.getLimit() && this.result.length < this.getLimit()) {
|
||||
const { limit } = this.params
|
||||
if (limit != null && length >= limit && this.result.length < limit) {
|
||||
void this.reinit(this.result.length)
|
||||
} else {
|
||||
void this.notify()
|
||||
@@ -380,10 +407,6 @@ export class NotificationQuery implements PagedQuery<Notification, NotificationQ
|
||||
this.callback(window)
|
||||
}
|
||||
|
||||
private getLimit (): number {
|
||||
return this.params.limit ?? defaultQueryParams.limit
|
||||
}
|
||||
|
||||
private async reinit (limit: number): Promise<void> {
|
||||
if (this.result instanceof Promise) this.result = await this.result
|
||||
this.result = this.find({ ...this.params, limit: limit + 1 }).then((res) => {
|
||||
@@ -429,4 +452,27 @@ export class NotificationQuery implements PagedQuery<Notification, NotificationQ
|
||||
|
||||
return isUpdated
|
||||
}
|
||||
|
||||
async refresh (): Promise<void> {
|
||||
const nextPagesCount = this.nexLoadedPagesCount
|
||||
const prevPagesCount = this.prevLoadedPagesCount
|
||||
|
||||
this.result = new QueryResult([] as Notification[], (it) => it.id)
|
||||
this.nexLoadedPagesCount = 0
|
||||
this.prevLoadedPagesCount = 0
|
||||
|
||||
this.result = await this.rawInitResult()
|
||||
|
||||
for (let i = 0; i < nextPagesCount; i++) {
|
||||
const { isDone } = await this.requestLoadNextPage(false)
|
||||
if (!isDone) break
|
||||
}
|
||||
|
||||
for (let i = 0; i < prevPagesCount; i++) {
|
||||
const { isDone } = await this.requestLoadPrevPage(false)
|
||||
if (!isDone) break
|
||||
}
|
||||
|
||||
await this.notify()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -51,13 +51,18 @@ interface BaseQuery<R = any, P = FindParams> {
|
||||
removeCallback: () => void
|
||||
setCallback: (callback: (result: any) => void) => void
|
||||
copyResult: () => QueryResult<R> | undefined
|
||||
|
||||
refresh: () => Promise<void>
|
||||
}
|
||||
|
||||
export interface PagedQuery<R = any, P = FindParams> extends BaseQuery<R, P> {
|
||||
readonly id: QueryId
|
||||
readonly params: P
|
||||
nexLoadedPagesCount: number
|
||||
prevLoadedPagesCount: number
|
||||
|
||||
requestLoadNextPage: () => Promise<void>
|
||||
requestLoadPrevPage: () => Promise<void>
|
||||
requestLoadNextPage: (notify?: boolean) => Promise<{ isDone: boolean }>
|
||||
requestLoadPrevPage: (notify?: boolean) => Promise<{ isDone: boolean }>
|
||||
setCallback: (callback: (window: Window<R>) => void) => void
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user