mirror of
https://github.com/hcengineering/platform.git
synced 2024-11-26 13:47:26 +03:00
Fix mixin query (#2239)
Signed-off-by: Denis Bykhov <80476319+BykhovDenis@users.noreply.github.com>
This commit is contained in:
parent
4a9740e64d
commit
e7c0740b62
@ -253,6 +253,73 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
return {}
|
return {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private async checkSearch (q: Query, pos: number, _id: Ref<Doc>): Promise<boolean> {
|
||||||
|
if (q.result instanceof Promise) {
|
||||||
|
q.result = await q.result
|
||||||
|
}
|
||||||
|
const match = await this.findOne(q._class, { $search: q.query.$search, _id }, q.options)
|
||||||
|
if (match === undefined) {
|
||||||
|
if (q.options?.limit === q.result.length) {
|
||||||
|
await this.refresh(q)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
q.result.splice(pos, 1)
|
||||||
|
q.total--
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
q.result[pos] = match
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private async getCurrentDoc (q: Query, pos: number, _id: Ref<Doc>): Promise<boolean> {
|
||||||
|
if (q.result instanceof Promise) {
|
||||||
|
q.result = await q.result
|
||||||
|
}
|
||||||
|
const current = await this.findOne(q._class, { _id }, q.options)
|
||||||
|
if (current !== undefined && this.match(q, current)) {
|
||||||
|
q.result[pos] = current
|
||||||
|
} else {
|
||||||
|
if (q.options?.limit === q.result.length) {
|
||||||
|
await this.refresh(q)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
q.result.splice(pos, 1)
|
||||||
|
q.total--
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
private async __updateMixinDoc (q: Query, updatedDoc: WithLookup<Doc>, tx: TxMixin<Doc, Doc>): Promise<void> {
|
||||||
|
updatedDoc = TxProcessor.updateMixin4Doc(updatedDoc, tx)
|
||||||
|
|
||||||
|
const ops = {
|
||||||
|
...tx.attributes,
|
||||||
|
modifiedBy: tx.modifiedBy,
|
||||||
|
modifiedOn: tx.modifiedOn
|
||||||
|
}
|
||||||
|
await this.__updateLookup(q, updatedDoc, ops)
|
||||||
|
}
|
||||||
|
|
||||||
|
private async checkUpdatedDocMatch (q: Query, pos: number, updatedDoc: WithLookup<Doc>): Promise<boolean> {
|
||||||
|
if (q.result instanceof Promise) {
|
||||||
|
q.result = await q.result
|
||||||
|
}
|
||||||
|
if (!this.match(q, updatedDoc)) {
|
||||||
|
if (q.options?.limit === q.result.length) {
|
||||||
|
await this.refresh(q)
|
||||||
|
return true
|
||||||
|
} else {
|
||||||
|
q.result.splice(pos, 1)
|
||||||
|
q.total--
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
q.result[pos] = updatedDoc
|
||||||
|
}
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
protected override async txMixin (tx: TxMixin<Doc, Doc>): Promise<TxResult> {
|
protected override async txMixin (tx: TxMixin<Doc, Doc>): Promise<TxResult> {
|
||||||
const hierarchy = this.client.getHierarchy()
|
const hierarchy = this.client.getHierarchy()
|
||||||
for (const queries of this.queries) {
|
for (const queries of this.queries) {
|
||||||
@ -267,12 +334,25 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
if (q.result instanceof Promise) {
|
if (q.result instanceof Promise) {
|
||||||
q.result = await q.result
|
q.result = await q.result
|
||||||
}
|
}
|
||||||
let updatedDoc = q.result.find((p) => p._id === tx.objectId)
|
const pos = q.result.findIndex((p) => p._id === tx.objectId)
|
||||||
if (updatedDoc !== undefined) {
|
if (pos !== -1) {
|
||||||
// Create or apply mixin value
|
// If query contains search we must check use fulltext
|
||||||
updatedDoc = TxProcessor.updateMixin4Doc(updatedDoc, tx)
|
if (q.query.$search != null && q.query.$search.length > 0) {
|
||||||
await this.__updateLookup(q, updatedDoc, tx.attributes)
|
const searchRefresh = await this.checkSearch(q, pos, tx.objectId)
|
||||||
await this.updatedDocCallback(updatedDoc, q)
|
if (searchRefresh) return {}
|
||||||
|
} else {
|
||||||
|
const updatedDoc = q.result[pos]
|
||||||
|
if (updatedDoc.modifiedOn < tx.modifiedOn) {
|
||||||
|
await this.__updateMixinDoc(q, updatedDoc, tx)
|
||||||
|
const updateRefresh = await this.checkUpdatedDocMatch(q, pos, updatedDoc)
|
||||||
|
if (updateRefresh) return {}
|
||||||
|
} else {
|
||||||
|
const currentRefresh = await this.getCurrentDoc(q, pos, updatedDoc._id)
|
||||||
|
if (currentRefresh) return {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
this.sort(q, tx)
|
||||||
|
await this.updatedDocCallback(q.result[pos], q)
|
||||||
} else if (isMixin) {
|
} else if (isMixin) {
|
||||||
// Mixin potentially added to object we doesn't have in out results
|
// Mixin potentially added to object we doesn't have in out results
|
||||||
const doc = await this.findOne(q._class, { _id: tx.objectId }, q.options)
|
const doc = await this.findOne(q._class, { _id: tx.objectId }, q.options)
|
||||||
@ -280,6 +360,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
await this.handleDocAdd(q, doc, false)
|
await this.handleDocAdd(q, doc, false)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
await this.handleDocUpdateLookup(q, tx)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return {}
|
return {}
|
||||||
@ -340,43 +421,17 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
if (pos !== -1) {
|
if (pos !== -1) {
|
||||||
// If query contains search we must check use fulltext
|
// If query contains search we must check use fulltext
|
||||||
if (q.query.$search != null && q.query.$search.length > 0) {
|
if (q.query.$search != null && q.query.$search.length > 0) {
|
||||||
const match = await this.findOne(q._class, { $search: q.query.$search, _id: tx.objectId }, q.options)
|
const searchRefresh = await this.checkSearch(q, pos, tx.objectId)
|
||||||
if (match === undefined) {
|
if (searchRefresh) return
|
||||||
if (q.options?.limit === q.result.length) {
|
|
||||||
return await this.refresh(q)
|
|
||||||
} else {
|
|
||||||
q.result.splice(pos, 1)
|
|
||||||
q.total--
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
q.result[pos] = match
|
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
const updatedDoc = q.result[pos]
|
const updatedDoc = q.result[pos]
|
||||||
if (updatedDoc.modifiedOn < tx.modifiedOn) {
|
if (updatedDoc.modifiedOn < tx.modifiedOn) {
|
||||||
await this.__updateDoc(q, updatedDoc, tx)
|
await this.__updateDoc(q, updatedDoc, tx)
|
||||||
if (!this.match(q, updatedDoc)) {
|
const updateRefresh = await this.checkUpdatedDocMatch(q, pos, updatedDoc)
|
||||||
if (q.options?.limit === q.result.length) {
|
if (updateRefresh) return
|
||||||
return await this.refresh(q)
|
|
||||||
} else {
|
} else {
|
||||||
q.result.splice(pos, 1)
|
const currentRefresh = await this.getCurrentDoc(q, pos, updatedDoc._id)
|
||||||
q.total--
|
if (currentRefresh) return
|
||||||
}
|
|
||||||
} else {
|
|
||||||
q.result[pos] = updatedDoc
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const current = await this.findOne(q._class, { _id: updatedDoc._id }, q.options)
|
|
||||||
if (current !== undefined && this.match(q, current)) {
|
|
||||||
q.result[pos] = current
|
|
||||||
} else {
|
|
||||||
if (q.options?.limit === q.result.length) {
|
|
||||||
return await this.refresh(q)
|
|
||||||
} else {
|
|
||||||
q.result.splice(pos, 1)
|
|
||||||
q.total--
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
this.sort(q, tx)
|
this.sort(q, tx)
|
||||||
@ -388,7 +443,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
await this.handleDocUpdateLookup(q, tx)
|
await this.handleDocUpdateLookup(q, tx)
|
||||||
}
|
}
|
||||||
|
|
||||||
private async handleDocUpdateLookup (q: Query, tx: TxUpdateDoc<Doc>): Promise<void> {
|
private async handleDocUpdateLookup (q: Query, tx: TxUpdateDoc<Doc> | TxMixin<Doc, Doc>): Promise<void> {
|
||||||
if (q.options?.lookup === undefined) return
|
if (q.options?.lookup === undefined) return
|
||||||
const lookup = q.options.lookup
|
const lookup = q.options.lookup
|
||||||
if (q.result instanceof Promise) {
|
if (q.result instanceof Promise) {
|
||||||
@ -405,7 +460,11 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private async proccesLookupUpdateDoc (docs: Doc[], lookup: Lookup<Doc>, tx: TxUpdateDoc<Doc>): Promise<boolean> {
|
private async proccesLookupUpdateDoc (
|
||||||
|
docs: Doc[],
|
||||||
|
lookup: Lookup<Doc>,
|
||||||
|
tx: TxUpdateDoc<Doc> | TxMixin<Doc, Doc>
|
||||||
|
): Promise<boolean> {
|
||||||
let needCallback = false
|
let needCallback = false
|
||||||
const lookupWays = this.getLookupWays(lookup, tx.objectClass)
|
const lookupWays = this.getLookupWays(lookup, tx.objectClass)
|
||||||
for (const lookupWay of lookupWays) {
|
for (const lookupWay of lookupWays) {
|
||||||
@ -418,7 +477,11 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
let index = value.findIndex((p) => p._id === tx.objectId)
|
let index = value.findIndex((p) => p._id === tx.objectId)
|
||||||
if (this.client.getHierarchy().isDerived(tx.objectClass, core.class.AttachedDoc)) {
|
if (this.client.getHierarchy().isDerived(tx.objectClass, core.class.AttachedDoc)) {
|
||||||
if (reverseLookupKey !== undefined) {
|
if (reverseLookupKey !== undefined) {
|
||||||
const reverseLookupValue = (tx.operations as any)[reverseLookupKey]
|
const reverseLookupValue = (
|
||||||
|
tx._class === core.class.TxMixin
|
||||||
|
? ((tx as TxMixin<Doc, Doc>).attributes as any)
|
||||||
|
: ((tx as TxUpdateDoc<Doc>).operations as any)
|
||||||
|
)[reverseLookupKey]
|
||||||
if (index !== -1 && reverseLookupValue !== undefined && reverseLookupValue !== obj._id) {
|
if (index !== -1 && reverseLookupValue !== undefined && reverseLookupValue !== obj._id) {
|
||||||
value.splice(index, 1)
|
value.splice(index, 1)
|
||||||
index = -1
|
index = -1
|
||||||
@ -432,13 +495,21 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (index !== -1) {
|
if (index !== -1) {
|
||||||
TxProcessor.updateDoc2Doc(value[index], tx)
|
if (tx._class === core.class.TxMixin) {
|
||||||
|
TxProcessor.updateMixin4Doc(value[index], tx as TxMixin<Doc, Doc>)
|
||||||
|
} else {
|
||||||
|
TxProcessor.updateDoc2Doc(value[index], tx as TxUpdateDoc<Doc>)
|
||||||
|
}
|
||||||
needCallback = true
|
needCallback = true
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (obj[key] === tx.objectId) {
|
if (obj[key] === tx.objectId) {
|
||||||
if (obj.$lookup[key] !== undefined) {
|
if (obj.$lookup[key] !== undefined) {
|
||||||
TxProcessor.updateDoc2Doc(obj.$lookup[key], tx)
|
if (tx._class === core.class.TxMixin) {
|
||||||
|
TxProcessor.updateMixin4Doc(obj.$lookup[key], tx as TxMixin<Doc, Doc>)
|
||||||
|
} else {
|
||||||
|
TxProcessor.updateDoc2Doc(obj.$lookup[key], tx as TxUpdateDoc<Doc>)
|
||||||
|
}
|
||||||
needCallback = true
|
needCallback = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -875,7 +946,7 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
await this.__updateLookup(q, updatedDoc, ops)
|
await this.__updateLookup(q, updatedDoc, ops)
|
||||||
}
|
}
|
||||||
|
|
||||||
private sort (q: Query, tx: TxUpdateDoc<Doc>): void {
|
private sort (q: Query, tx: TxUpdateDoc<Doc> | TxMixin<Doc, Doc>): void {
|
||||||
const sort = q.options?.sort
|
const sort = q.options?.sort
|
||||||
if (sort === undefined) return
|
if (sort === undefined) return
|
||||||
let needSort = sort.modifiedBy !== undefined || sort.modifiedOn !== undefined
|
let needSort = sort.modifiedBy !== undefined || sort.modifiedOn !== undefined
|
||||||
@ -884,8 +955,11 @@ export class LiveQuery extends TxProcessor implements Client {
|
|||||||
if (needSort) resultSort(q.result as Doc[], sort, q._class, this.getHierarchy())
|
if (needSort) resultSort(q.result as Doc[], sort, q._class, this.getHierarchy())
|
||||||
}
|
}
|
||||||
|
|
||||||
private checkNeedSort (sort: SortingQuery<Doc>, tx: TxUpdateDoc<Doc>): boolean {
|
private checkNeedSort (sort: SortingQuery<Doc>, tx: TxUpdateDoc<Doc> | TxMixin<Doc, Doc>): boolean {
|
||||||
const ops = tx.operations as any
|
const ops =
|
||||||
|
tx._class === core.class.TxMixin
|
||||||
|
? (tx as TxMixin<Doc, Doc>).attributes
|
||||||
|
: ((tx as TxUpdateDoc<Doc>).operations as any)
|
||||||
for (const key in ops) {
|
for (const key in ops) {
|
||||||
if (key.startsWith('$')) {
|
if (key.startsWith('$')) {
|
||||||
for (const opKey in ops[key]) {
|
for (const opKey in ops[key]) {
|
||||||
|
Loading…
Reference in New Issue
Block a user