diff --git a/packages/core/src/__tests__/memdb.test.ts b/packages/core/src/__tests__/memdb.test.ts index 4e3061448b7..ccdab870436 100644 --- a/packages/core/src/__tests__/memdb.test.ts +++ b/packages/core/src/__tests__/memdb.test.ts @@ -13,7 +13,7 @@ // limitations under the License. // -import { Client } from '..' +import { Client, generateId, mergeQueries } from '..' import type { Class, Doc, Obj, Ref } from '../classes' import core from '../component' import { Hierarchy } from '../hierarchy' @@ -396,4 +396,39 @@ describe('memdb', () => { expect(e).toEqual(new Error('createDoc cannot be used for objects inherited from AttachedDoc')) } }) + + it('mergeQueries', () => { + const id1 = generateId() + const id2 = generateId() + const q1 = { + space: id1, + unique: 'item', + age: { $gt: 10 } + } as any + const q2 = { + space: { $in: [id1, id2] }, + age: 30 + } as any + const resCompare = { + space: id1, + unique: 'item', + age: { $gt: 30 } + } as any + expect(mergeQueries(q1, q2)).toEqual(resCompare) + expect(mergeQueries(q2, q1)).toEqual(resCompare) + + const q3 = { + space: { $nin: [id1] }, + age: 20 + } as any + const resCompare2 = { + space: { $ne: id1 }, + age: [] + } as any + expect(mergeQueries(q2, q3)).toEqual(resCompare2) + expect(mergeQueries(q3, q2)).toEqual(resCompare2) + + expect(mergeQueries({ age: { $lt: 20 } } as any, { age: { $gt: 25 } } as any)).toEqual({ age: { $gt: 25 } }) + expect(mergeQueries({ age: { $gt: 25 } } as any, { age: { $lt: 20 } } as any)).toEqual({ age: { $lt: 20 } }) + }) }) diff --git a/packages/core/src/utils.ts b/packages/core/src/utils.ts index 6f6923327d1..c419a48972c 100644 --- a/packages/core/src/utils.ts +++ b/packages/core/src/utils.ts @@ -16,7 +16,8 @@ import { Account, AnyAttribute, Class, Doc, DocData, DocIndexState, IndexKind, Obj, Ref, Space } from './classes' import core from './component' import { Hierarchy } from './hierarchy' -import { FindResult } from './storage' +import { DocumentQuery, FindResult } from './storage' +import { isPredicate } from './predicate' function toHex (value: number, chars: number): string { const result = value.toString(16) @@ -331,3 +332,64 @@ export class RateLimitter { await await Promise.race(this.processingQueue.values()) } } + +export function mergeQueries (query1: DocumentQuery, query2: DocumentQuery): DocumentQuery { + const q = Object.assign({}, query1) + for (const k in query2) { + if (!Object.keys(query1).includes(k)) { + Object.assign(q, { [k]: query2[k] }) + continue + } + Object.assign(q, { [k]: getInNiN(query1[k], query2[k]) }) + if (isPredicate(query2[k]) || isPredicate(query1[k])) { + const toIterate = isPredicate(query2[k]) ? query2[k] : query1[k] + for (const x in toIterate) { + if (['$lt', '$gt'].includes(x)) { + const val1 = isPredicate(query1[k]) ? query1[k][x] : query1[k] + const val2 = isPredicate(query2[k]) ? query2[k][x] : query2[k] + if (x === '$lt') { + Object.assign(q, { [k]: { $lt: val1 < val2 ? val1 : val2 } }) + continue + } + if (x === '$gt') { + Object.assign(q, { [k]: { $gt: val1 > val2 ? val1 : val2 } }) + } + } + } + } + } + return q +} + +function getInNiN (query1: any, query2: any): Object { + const aIn = + (typeof query1 === 'object' && '$in' in query1 ? query1.$in : undefined) ?? + (typeof query1 !== 'object' && query1 !== undefined ? [query1] : []) + const aNIn = + (typeof query1 === 'object' && '$nin' in query1 ? query1.$nin : undefined) ?? + (typeof query1 === 'object' && query1.$ne !== undefined ? [query1.$ne] : []) + const bIn = + (typeof query2 === 'object' && '$in' in query2 ? query2.$in : undefined) ?? + (typeof query2 !== 'object' && query2 !== undefined ? [query2] : []) + const bNIn = + (typeof query2 === 'object' && '$nin' in query2 ? query2.$nin : undefined) ?? + (typeof query2 === 'object' && query2.$ne !== undefined ? [query2.$ne] : []) + const finalIn = + aIn.length - bIn.length < 0 ? bIn.filter((c: any) => aIn.includes(c)) : aIn.filter((c: any) => bIn.includes(c)) + const finalNin = Array.from(new Set([...aNIn, ...bNIn])) + if (finalIn.length === 1 && finalNin.length === 0) { + return aIn[0] + } + if (finalIn.length === 0 && finalNin.length === 1) { + return { $ne: finalNin[0] } + } + const res: any = {} + if (finalIn.length > 0) { + res.$in = finalIn + } + if (finalNin.length > 0) { + res.$nin = finalNin + } + if (aIn.length === 1 && bIn.length === 1) return [] + return res +} diff --git a/plugins/task-resources/src/components/TypesView.svelte b/plugins/task-resources/src/components/TypesView.svelte index 13c337f4b6c..20caea131d5 100644 --- a/plugins/task-resources/src/components/TypesView.svelte +++ b/plugins/task-resources/src/components/TypesView.svelte @@ -13,7 +13,7 @@ // limitations under the License. -->