From fd5fc239e8f66a065ec3effc1d15c27ddd7eed7d Mon Sep 17 00:00:00 2001 From: TristanH Date: Sat, 19 Oct 2024 20:20:46 -0400 Subject: [PATCH] make the unescape function copy rather than modify the query --- dist/cjs/rx-query-helper.js | 15 ++++++--------- dist/cjs/rx-query-helper.js.map | 2 +- dist/esm/rx-query-helper.js | 15 ++++++--------- dist/esm/rx-query-helper.js.map | 2 +- src/rx-query-helper.ts | 15 ++++++--------- 5 files changed, 20 insertions(+), 29 deletions(-) diff --git a/dist/cjs/rx-query-helper.js b/dist/cjs/rx-query-helper.js index f9ab78b6615..5aeda9140b6 100644 --- a/dist/cjs/rx-query-helper.js +++ b/dist/cjs/rx-query-helper.js @@ -195,24 +195,21 @@ function getSortComparator(schema, query) { // so that the event reduce library can work properly and not remove tagged documents from results. function unescapeTagKeysInSelector(query) { if (typeof query === 'object' && query !== null) { + var newQuery = Array.isArray(query) ? [] : {}; // loop through all keys of the object for (var key in query) { // eslint-disable-next-line no-prototype-builtins if (query.hasOwnProperty(key)) { // check if key matches the pattern "tags.\"x\"" + var newKey = key; if (key.startsWith('tags.') && key.includes('"')) { - var newKey = key.replace(/\\"/g, ''); - // reassign the value to the new key - query[newKey] = query[key]; - // delete the old key - delete query[key]; - } - // if value is an object, apply the function recursively - if (typeof query[key] === 'object') { - query[key] = unescapeTagKeysInSelector(query[key]); + newKey = key.replace(/"/g, ''); } + // recursively process the value + newQuery[newKey] = unescapeTagKeysInSelector(query[key]); } } + return newQuery; } return query; } diff --git a/dist/cjs/rx-query-helper.js.map b/dist/cjs/rx-query-helper.js.map index 94f943ddb2b..7c4cd77b5ba 100644 --- a/dist/cjs/rx-query-helper.js.map +++ b/dist/cjs/rx-query-helper.js.map @@ -1 +1 @@ -{"version":3,"file":"rx-query-helper.js","names":["_queryPlanner","require","_rxSchemaHelper","_index","_util","_rxError","_rxQueryMingo","normalizeMangoQuery","schema","mangoQuery","primaryKey","getPrimaryFieldOfPrimaryKey","flatClone","normalizedMangoQuery","clone","skip","selector","Object","entries","forEach","field","matcher","$eq","index","indexAr","toArray","includes","push","sort","map","indexes","fieldsWithLogicalOperator","Set","hasLogical","keys","find","operator","LOGICAL_OPERATORS","has","add","currentFieldsAmount","currentBestIndexForSort","useIndex","isMaybeReadonlyArray","firstWrongIndex","findIndex","indexField","isPrimaryInSort","p","firstPropertyNameOfObject","slice","getSortComparator","query","newRxError","sortParts","sortBlock","key","direction","values","getValueFn","objectPathMonad","fun","a","b","i","length","sortPart","valueA","valueB","ret","mingoSortComparator","unescapeTagKeysInSelector","hasOwnProperty","startsWith","newKey","replace","getQueryMatcher","_schema","mingoQuery","getMingoQuery","doc","test","runQueryUpdateFunction","rxQuery","fn","docs","exec","Array","isArray","Promise","all","result","selectorIncludesDeleted","isTrue","value","isNotFalse","$ne","hasDeletedTrue","condition","_deleted","$or","some","$and","$nor","every"],"sources":["../../src/rx-query-helper.ts"],"sourcesContent":["import { LOGICAL_OPERATORS } from './query-planner.ts';\nimport { getPrimaryFieldOfPrimaryKey } from './rx-schema-helper.ts';\nimport type {\n DeepReadonly,\n DeterministicSortComparator,\n FilledMangoQuery,\n MangoQuery,\n MangoQueryOperators,\n MangoQuerySelector,\n MangoQuerySortDirection,\n PropertyType,\n QueryMatcher,\n RxDocument,\n RxDocumentData,\n RxJsonSchema,\n RxQuery\n} from './types/index.d.ts';\nimport {\n clone,\n firstPropertyNameOfObject,\n toArray,\n isMaybeReadonlyArray,\n flatClone,\n objectPathMonad,\n ObjectPathMonadFunction\n} from './plugins/utils/index.ts';\nimport {\n compare as mingoSortComparator\n} from 'mingo/util';\nimport { newRxError } from './rx-error.ts';\nimport { getMingoQuery } from './rx-query-mingo.ts';\n\n/**\n * Normalize the query to ensure we have all fields set\n * and queries that represent the same query logic are detected as equal by the caching.\n */\nexport function normalizeMangoQuery(\n schema: RxJsonSchema>,\n mangoQuery: MangoQuery\n): FilledMangoQuery {\n const primaryKey: string = getPrimaryFieldOfPrimaryKey(schema.primaryKey);\n mangoQuery = flatClone(mangoQuery);\n\n const normalizedMangoQuery: FilledMangoQuery = clone(mangoQuery) as any;\n if (typeof normalizedMangoQuery.skip !== 'number') {\n normalizedMangoQuery.skip = 0;\n }\n\n if (!normalizedMangoQuery.selector) {\n normalizedMangoQuery.selector = {};\n } else {\n normalizedMangoQuery.selector = normalizedMangoQuery.selector;\n /**\n * In mango query, it is possible to have an\n * equals comparison by directly assigning a value\n * to a property, without the '$eq' operator.\n * Like:\n * selector: {\n * foo: 'bar'\n * }\n * For normalization, we have to normalize this\n * so our checks can perform properly.\n *\n *\n * TODO this must work recursive with nested queries that\n * contain multiple selectors via $and or $or etc.\n */\n Object\n .entries(normalizedMangoQuery.selector)\n .forEach(([field, matcher]) => {\n if (typeof matcher !== 'object' || matcher === null) {\n (normalizedMangoQuery as any).selector[field] = {\n $eq: matcher\n };\n }\n });\n }\n\n /**\n * Ensure that if an index is specified,\n * the primaryKey is inside of it.\n */\n if (normalizedMangoQuery.index) {\n const indexAr = toArray(normalizedMangoQuery.index);\n if (!indexAr.includes(primaryKey)) {\n indexAr.push(primaryKey);\n }\n normalizedMangoQuery.index = indexAr;\n }\n\n /**\n * To ensure a deterministic sorting,\n * we have to ensure the primary key is always part\n * of the sort query.\n * Primary sorting is added as last sort parameter,\n * similar to how we add the primary key to indexes that do not have it.\n *\n */\n if (!normalizedMangoQuery.sort) {\n /**\n * If no sort is given at all,\n * we can assume that the user does not care about sort order at al.\n *\n * we cannot just use the primary key as sort parameter\n * because it would likely cause the query to run over the primary key index\n * which has a bad performance in most cases.\n */\n if (normalizedMangoQuery.index) {\n normalizedMangoQuery.sort = normalizedMangoQuery.index.map((field: string) => {\n return { [field as any]: 'asc' } as any;\n });\n } else {\n /**\n * Find the index that best matches the fields with the logical operators\n */\n if (schema.indexes) {\n const fieldsWithLogicalOperator: Set = new Set();\n Object.entries(normalizedMangoQuery.selector).forEach(([field, matcher]) => {\n let hasLogical = false;\n if (typeof matcher === 'object' && matcher !== null) {\n hasLogical = !!Object.keys(matcher).find(operator => LOGICAL_OPERATORS.has(operator));\n } else {\n hasLogical = true;\n }\n if (hasLogical) {\n fieldsWithLogicalOperator.add(field);\n }\n });\n\n\n let currentFieldsAmount = -1;\n let currentBestIndexForSort: string[] | readonly string[] | undefined;\n schema.indexes.forEach(index => {\n const useIndex = isMaybeReadonlyArray(index) ? index : [index];\n const firstWrongIndex = useIndex.findIndex(indexField => !fieldsWithLogicalOperator.has(indexField));\n if (\n firstWrongIndex > 0 &&\n firstWrongIndex > currentFieldsAmount\n ) {\n currentFieldsAmount = firstWrongIndex;\n currentBestIndexForSort = useIndex;\n }\n });\n if (currentBestIndexForSort) {\n normalizedMangoQuery.sort = currentBestIndexForSort.map((field: string) => {\n return { [field as any]: 'asc' } as any;\n });\n }\n\n }\n\n /**\n * Fall back to the primary key as sort order\n * if no better one has been found\n */\n if (!normalizedMangoQuery.sort) {\n normalizedMangoQuery.sort = [{ [primaryKey]: 'asc' }] as any;\n }\n }\n } else {\n const isPrimaryInSort = normalizedMangoQuery.sort\n .find(p => firstPropertyNameOfObject(p) === primaryKey);\n if (!isPrimaryInSort) {\n normalizedMangoQuery.sort = normalizedMangoQuery.sort.slice(0);\n normalizedMangoQuery.sort.push({ [primaryKey]: 'asc' } as any);\n }\n }\n\n return normalizedMangoQuery;\n}\n\n/**\n * Returns the sort-comparator,\n * which is able to sort documents in the same way\n * a query over the db would do.\n */\nexport function getSortComparator(\n schema: RxJsonSchema>,\n query: FilledMangoQuery\n): DeterministicSortComparator {\n if (!query.sort) {\n throw newRxError('SNH', { query });\n }\n const sortParts: {\n key: string;\n direction: MangoQuerySortDirection;\n getValueFn: ObjectPathMonadFunction;\n }[] = [];\n query.sort.forEach(sortBlock => {\n const key = Object.keys(sortBlock)[0];\n const direction = Object.values(sortBlock)[0];\n sortParts.push({\n key,\n direction,\n getValueFn: objectPathMonad(key)\n });\n });\n const fun: DeterministicSortComparator = (a: RxDocType, b: RxDocType) => {\n for (let i = 0; i < sortParts.length; ++i) {\n const sortPart = sortParts[i];\n const valueA = sortPart.getValueFn(a);\n const valueB = sortPart.getValueFn(b);\n if (valueA !== valueB) {\n const ret = sortPart.direction === 'asc' ? mingoSortComparator(valueA, valueB) : mingoSortComparator(valueB, valueA);\n return ret as any;\n }\n }\n };\n\n return fun;\n}\n\n// When the rxdb adapter is sqlite, we escape tag names by wrapping them in quotes:\n// https://github.com/TristanH/rekindled/blob/e42d2fa40305ba98dfab12e8dd7aed07ddb17ebf/reading-clients/shared/database/queryHelpers.ts#L18\n//\n// Although sqlite can match tag keys escaped with quotes, the rxdb event-reduce query matcher (mingo) says that a document like\n// {\n// 'tags': 'a': {...}}\n// }\n// does not match the query:\n// {\"tags.\\\"a\\\"\":{\"$exists\":1}}\n//\n// What this function does is \"fix\" the sqlite queries to unescape the tag keys (basically, remove the quotes).\n// so that the event reduce library can work properly and not remove tagged documents from results.\nfunction unescapeTagKeysInSelector(query: any): any {\n if (typeof query === 'object' && query !== null) {\n // loop through all keys of the object\n for (const key in query) {\n // eslint-disable-next-line no-prototype-builtins\n if (query.hasOwnProperty(key)) {\n // check if key matches the pattern \"tags.\\\"x\\\"\"\n if (key.startsWith('tags.') && key.includes('\"')) {\n const newKey = key.replace(/\\\\\"/g, '');\n // reassign the value to the new key\n query[newKey] = query[key];\n // delete the old key\n delete query[key];\n }\n // if value is an object, apply the function recursively\n if (typeof query[key] === 'object') {\n query[key] = unescapeTagKeysInSelector(query[key]);\n }\n }\n }\n }\n return query;\n}\n\n\n/**\n * Returns a function\n * that can be used to check if a document\n * matches the query.\n */\nexport function getQueryMatcher(\n _schema: RxJsonSchema | RxJsonSchema>,\n query: FilledMangoQuery\n): QueryMatcher> {\n if (!query.sort) {\n throw newRxError('SNH', { query });\n }\n\n const mingoQuery = getMingoQuery(unescapeTagKeysInSelector(query.selector as any));\n\n const fun: QueryMatcher> = (doc: RxDocumentData | DeepReadonly>) => {\n return mingoQuery.test(doc);\n };\n return fun;\n}\n\n\nexport async function runQueryUpdateFunction(\n rxQuery: RxQuery,\n fn: (doc: RxDocument) => Promise>\n): Promise {\n const docs = await rxQuery.exec();\n if (!docs) {\n // only findOne() queries can return null\n return null as any;\n }\n if (Array.isArray(docs)) {\n return Promise.all(\n docs.map(doc => fn(doc))\n ) as any;\n } else {\n // via findOne()\n const result = await fn(docs as any);\n return result as any;\n }\n}\n\n/**\n * Checks if a given selector includes deleted documents.\n * @param selector The MangoQuerySelector to check\n * @returns True if the selector includes deleted documents, false otherwise\n */\nexport function selectorIncludesDeleted(\n selector: MangoQuerySelector | undefined\n): boolean {\n if (!selector) {\n return false;\n }\n\n const isTrue = (value: unknown): boolean =>\n value === true ||\n (typeof value === 'object' &&\n value !== null &&\n '$eq' in value &&\n (value as MangoQueryOperators).$eq === true);\n\n\n const isNotFalse = (value: unknown): boolean =>\n value === true ||\n (typeof value === 'object' &&\n value !== null &&\n '$ne' in value &&\n (value as MangoQueryOperators).$ne === false);\n\n const hasDeletedTrue = (\n condition: MangoQuerySelector\n ): boolean =>\n '_deleted' in condition &&\n (isTrue(condition._deleted as PropertyType) ||\n isNotFalse(\n condition._deleted as PropertyType\n ));\n\n if ('_deleted' in selector) {\n return (\n isTrue(selector._deleted as PropertyType) ||\n isNotFalse(selector._deleted as PropertyType)\n );\n }\n\n if ('$or' in selector && Array.isArray(selector.$or)) {\n return selector.$or.some(hasDeletedTrue);\n }\n\n if ('$and' in selector && Array.isArray(selector.$and)) {\n return selector.$and.some(hasDeletedTrue);\n }\n\n if ('$nor' in selector && Array.isArray(selector.$nor)) {\n return !selector.$nor.every((condition) => !hasDeletedTrue(condition));\n }\n\n return false;\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file +{"version":3,"file":"rx-query-helper.js","names":["_queryPlanner","require","_rxSchemaHelper","_index","_util","_rxError","_rxQueryMingo","normalizeMangoQuery","schema","mangoQuery","primaryKey","getPrimaryFieldOfPrimaryKey","flatClone","normalizedMangoQuery","clone","skip","selector","Object","entries","forEach","field","matcher","$eq","index","indexAr","toArray","includes","push","sort","map","indexes","fieldsWithLogicalOperator","Set","hasLogical","keys","find","operator","LOGICAL_OPERATORS","has","add","currentFieldsAmount","currentBestIndexForSort","useIndex","isMaybeReadonlyArray","firstWrongIndex","findIndex","indexField","isPrimaryInSort","p","firstPropertyNameOfObject","slice","getSortComparator","query","newRxError","sortParts","sortBlock","key","direction","values","getValueFn","objectPathMonad","fun","a","b","i","length","sortPart","valueA","valueB","ret","mingoSortComparator","unescapeTagKeysInSelector","newQuery","Array","isArray","hasOwnProperty","newKey","startsWith","replace","getQueryMatcher","_schema","mingoQuery","getMingoQuery","doc","test","runQueryUpdateFunction","rxQuery","fn","docs","exec","Promise","all","result","selectorIncludesDeleted","isTrue","value","isNotFalse","$ne","hasDeletedTrue","condition","_deleted","$or","some","$and","$nor","every"],"sources":["../../src/rx-query-helper.ts"],"sourcesContent":["import { LOGICAL_OPERATORS } from './query-planner.ts';\nimport { getPrimaryFieldOfPrimaryKey } from './rx-schema-helper.ts';\nimport type {\n DeepReadonly,\n DeterministicSortComparator,\n FilledMangoQuery,\n MangoQuery,\n MangoQueryOperators,\n MangoQuerySelector,\n MangoQuerySortDirection,\n PropertyType,\n QueryMatcher,\n RxDocument,\n RxDocumentData,\n RxJsonSchema,\n RxQuery\n} from './types/index.d.ts';\nimport {\n clone,\n firstPropertyNameOfObject,\n toArray,\n isMaybeReadonlyArray,\n flatClone,\n objectPathMonad,\n ObjectPathMonadFunction\n} from './plugins/utils/index.ts';\nimport {\n compare as mingoSortComparator\n} from 'mingo/util';\nimport { newRxError } from './rx-error.ts';\nimport { getMingoQuery } from './rx-query-mingo.ts';\n\n/**\n * Normalize the query to ensure we have all fields set\n * and queries that represent the same query logic are detected as equal by the caching.\n */\nexport function normalizeMangoQuery(\n schema: RxJsonSchema>,\n mangoQuery: MangoQuery\n): FilledMangoQuery {\n const primaryKey: string = getPrimaryFieldOfPrimaryKey(schema.primaryKey);\n mangoQuery = flatClone(mangoQuery);\n\n const normalizedMangoQuery: FilledMangoQuery = clone(mangoQuery) as any;\n if (typeof normalizedMangoQuery.skip !== 'number') {\n normalizedMangoQuery.skip = 0;\n }\n\n if (!normalizedMangoQuery.selector) {\n normalizedMangoQuery.selector = {};\n } else {\n normalizedMangoQuery.selector = normalizedMangoQuery.selector;\n /**\n * In mango query, it is possible to have an\n * equals comparison by directly assigning a value\n * to a property, without the '$eq' operator.\n * Like:\n * selector: {\n * foo: 'bar'\n * }\n * For normalization, we have to normalize this\n * so our checks can perform properly.\n *\n *\n * TODO this must work recursive with nested queries that\n * contain multiple selectors via $and or $or etc.\n */\n Object\n .entries(normalizedMangoQuery.selector)\n .forEach(([field, matcher]) => {\n if (typeof matcher !== 'object' || matcher === null) {\n (normalizedMangoQuery as any).selector[field] = {\n $eq: matcher\n };\n }\n });\n }\n\n /**\n * Ensure that if an index is specified,\n * the primaryKey is inside of it.\n */\n if (normalizedMangoQuery.index) {\n const indexAr = toArray(normalizedMangoQuery.index);\n if (!indexAr.includes(primaryKey)) {\n indexAr.push(primaryKey);\n }\n normalizedMangoQuery.index = indexAr;\n }\n\n /**\n * To ensure a deterministic sorting,\n * we have to ensure the primary key is always part\n * of the sort query.\n * Primary sorting is added as last sort parameter,\n * similar to how we add the primary key to indexes that do not have it.\n *\n */\n if (!normalizedMangoQuery.sort) {\n /**\n * If no sort is given at all,\n * we can assume that the user does not care about sort order at al.\n *\n * we cannot just use the primary key as sort parameter\n * because it would likely cause the query to run over the primary key index\n * which has a bad performance in most cases.\n */\n if (normalizedMangoQuery.index) {\n normalizedMangoQuery.sort = normalizedMangoQuery.index.map((field: string) => {\n return { [field as any]: 'asc' } as any;\n });\n } else {\n /**\n * Find the index that best matches the fields with the logical operators\n */\n if (schema.indexes) {\n const fieldsWithLogicalOperator: Set = new Set();\n Object.entries(normalizedMangoQuery.selector).forEach(([field, matcher]) => {\n let hasLogical = false;\n if (typeof matcher === 'object' && matcher !== null) {\n hasLogical = !!Object.keys(matcher).find(operator => LOGICAL_OPERATORS.has(operator));\n } else {\n hasLogical = true;\n }\n if (hasLogical) {\n fieldsWithLogicalOperator.add(field);\n }\n });\n\n\n let currentFieldsAmount = -1;\n let currentBestIndexForSort: string[] | readonly string[] | undefined;\n schema.indexes.forEach(index => {\n const useIndex = isMaybeReadonlyArray(index) ? index : [index];\n const firstWrongIndex = useIndex.findIndex(indexField => !fieldsWithLogicalOperator.has(indexField));\n if (\n firstWrongIndex > 0 &&\n firstWrongIndex > currentFieldsAmount\n ) {\n currentFieldsAmount = firstWrongIndex;\n currentBestIndexForSort = useIndex;\n }\n });\n if (currentBestIndexForSort) {\n normalizedMangoQuery.sort = currentBestIndexForSort.map((field: string) => {\n return { [field as any]: 'asc' } as any;\n });\n }\n\n }\n\n /**\n * Fall back to the primary key as sort order\n * if no better one has been found\n */\n if (!normalizedMangoQuery.sort) {\n normalizedMangoQuery.sort = [{ [primaryKey]: 'asc' }] as any;\n }\n }\n } else {\n const isPrimaryInSort = normalizedMangoQuery.sort\n .find(p => firstPropertyNameOfObject(p) === primaryKey);\n if (!isPrimaryInSort) {\n normalizedMangoQuery.sort = normalizedMangoQuery.sort.slice(0);\n normalizedMangoQuery.sort.push({ [primaryKey]: 'asc' } as any);\n }\n }\n\n return normalizedMangoQuery;\n}\n\n/**\n * Returns the sort-comparator,\n * which is able to sort documents in the same way\n * a query over the db would do.\n */\nexport function getSortComparator(\n schema: RxJsonSchema>,\n query: FilledMangoQuery\n): DeterministicSortComparator {\n if (!query.sort) {\n throw newRxError('SNH', { query });\n }\n const sortParts: {\n key: string;\n direction: MangoQuerySortDirection;\n getValueFn: ObjectPathMonadFunction;\n }[] = [];\n query.sort.forEach(sortBlock => {\n const key = Object.keys(sortBlock)[0];\n const direction = Object.values(sortBlock)[0];\n sortParts.push({\n key,\n direction,\n getValueFn: objectPathMonad(key)\n });\n });\n const fun: DeterministicSortComparator = (a: RxDocType, b: RxDocType) => {\n for (let i = 0; i < sortParts.length; ++i) {\n const sortPart = sortParts[i];\n const valueA = sortPart.getValueFn(a);\n const valueB = sortPart.getValueFn(b);\n if (valueA !== valueB) {\n const ret = sortPart.direction === 'asc' ? mingoSortComparator(valueA, valueB) : mingoSortComparator(valueB, valueA);\n return ret as any;\n }\n }\n };\n\n return fun;\n}\n\n// When the rxdb adapter is sqlite, we escape tag names by wrapping them in quotes:\n// https://github.com/TristanH/rekindled/blob/e42d2fa40305ba98dfab12e8dd7aed07ddb17ebf/reading-clients/shared/database/queryHelpers.ts#L18\n//\n// Although sqlite can match tag keys escaped with quotes, the rxdb event-reduce query matcher (mingo) says that a document like\n// {\n// 'tags': 'a': {...}}\n// }\n// does not match the query:\n// {\"tags.\\\"a\\\"\":{\"$exists\":1}}\n//\n// What this function does is \"fix\" the sqlite queries to unescape the tag keys (basically, remove the quotes).\n// so that the event reduce library can work properly and not remove tagged documents from results.\nfunction unescapeTagKeysInSelector(query: any): any {\n if (typeof query === 'object' && query !== null) {\n const newQuery: any = Array.isArray(query) ? [] : {};\n // loop through all keys of the object\n for (const key in query) {\n // eslint-disable-next-line no-prototype-builtins\n if (query.hasOwnProperty(key)) {\n // check if key matches the pattern \"tags.\\\"x\\\"\"\n let newKey = key;\n if (key.startsWith('tags.') && key.includes('\"')) {\n newKey = key.replace(/\"/g, '');\n }\n // recursively process the value\n newQuery[newKey] = unescapeTagKeysInSelector(query[key]);\n }\n }\n return newQuery;\n }\n return query;\n}\n\n\n/**\n * Returns a function\n * that can be used to check if a document\n * matches the query.\n */\nexport function getQueryMatcher(\n _schema: RxJsonSchema | RxJsonSchema>,\n query: FilledMangoQuery\n): QueryMatcher> {\n if (!query.sort) {\n throw newRxError('SNH', { query });\n }\n\n const mingoQuery = getMingoQuery(unescapeTagKeysInSelector(query.selector as any));\n\n const fun: QueryMatcher> = (doc: RxDocumentData | DeepReadonly>) => {\n return mingoQuery.test(doc);\n };\n return fun;\n}\n\n\nexport async function runQueryUpdateFunction(\n rxQuery: RxQuery,\n fn: (doc: RxDocument) => Promise>\n): Promise {\n const docs = await rxQuery.exec();\n if (!docs) {\n // only findOne() queries can return null\n return null as any;\n }\n if (Array.isArray(docs)) {\n return Promise.all(\n docs.map(doc => fn(doc))\n ) as any;\n } else {\n // via findOne()\n const result = await fn(docs as any);\n return result as any;\n }\n}\n\n/**\n * Checks if a given selector includes deleted documents.\n * @param selector The MangoQuerySelector to check\n * @returns True if the selector includes deleted documents, false otherwise\n */\nexport function selectorIncludesDeleted(\n selector: MangoQuerySelector | undefined\n): boolean {\n if (!selector) {\n return false;\n }\n\n const isTrue = (value: unknown): boolean =>\n value === true ||\n (typeof value === 'object' &&\n value !== null &&\n '$eq' in value &&\n (value as MangoQueryOperators).$eq === true);\n\n\n const isNotFalse = (value: unknown): boolean =>\n value === true ||\n (typeof value === 'object' &&\n value !== null &&\n '$ne' in value &&\n (value as MangoQueryOperators).$ne === false);\n\n const hasDeletedTrue = (\n condition: MangoQuerySelector\n ): boolean =>\n '_deleted' in condition &&\n (isTrue(condition._deleted as PropertyType) ||\n isNotFalse(\n condition._deleted as PropertyType\n ));\n\n if ('_deleted' in selector) {\n return (\n isTrue(selector._deleted as PropertyType) ||\n isNotFalse(selector._deleted as PropertyType)\n );\n }\n\n if ('$or' in selector && Array.isArray(selector.$or)) {\n return selector.$or.some(hasDeletedTrue);\n }\n\n if ('$and' in selector && Array.isArray(selector.$and)) {\n return selector.$and.some(hasDeletedTrue);\n }\n\n if ('$nor' in selector && Array.isArray(selector.$nor)) {\n return !selector.$nor.every((condition) => !hasDeletedTrue(condition));\n }\n\n return false;\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/dist/esm/rx-query-helper.js b/dist/esm/rx-query-helper.js index 4a358acc262..2d6deac88cf 100644 --- a/dist/esm/rx-query-helper.js +++ b/dist/esm/rx-query-helper.js @@ -186,24 +186,21 @@ export function getSortComparator(schema, query) { // so that the event reduce library can work properly and not remove tagged documents from results. function unescapeTagKeysInSelector(query) { if (typeof query === 'object' && query !== null) { + var newQuery = Array.isArray(query) ? [] : {}; // loop through all keys of the object for (var key in query) { // eslint-disable-next-line no-prototype-builtins if (query.hasOwnProperty(key)) { // check if key matches the pattern "tags.\"x\"" + var newKey = key; if (key.startsWith('tags.') && key.includes('"')) { - var newKey = key.replace(/\\"/g, ''); - // reassign the value to the new key - query[newKey] = query[key]; - // delete the old key - delete query[key]; - } - // if value is an object, apply the function recursively - if (typeof query[key] === 'object') { - query[key] = unescapeTagKeysInSelector(query[key]); + newKey = key.replace(/"/g, ''); } + // recursively process the value + newQuery[newKey] = unescapeTagKeysInSelector(query[key]); } } + return newQuery; } return query; } diff --git a/dist/esm/rx-query-helper.js.map b/dist/esm/rx-query-helper.js.map index eea803db8b7..aa0ddd579ef 100644 --- a/dist/esm/rx-query-helper.js.map +++ b/dist/esm/rx-query-helper.js.map @@ -1 +1 @@ -{"version":3,"file":"rx-query-helper.js","names":["LOGICAL_OPERATORS","getPrimaryFieldOfPrimaryKey","clone","firstPropertyNameOfObject","toArray","isMaybeReadonlyArray","flatClone","objectPathMonad","compare","mingoSortComparator","newRxError","getMingoQuery","normalizeMangoQuery","schema","mangoQuery","primaryKey","normalizedMangoQuery","skip","selector","Object","entries","forEach","field","matcher","$eq","index","indexAr","includes","push","sort","map","indexes","fieldsWithLogicalOperator","Set","hasLogical","keys","find","operator","has","add","currentFieldsAmount","currentBestIndexForSort","useIndex","firstWrongIndex","findIndex","indexField","isPrimaryInSort","p","slice","getSortComparator","query","sortParts","sortBlock","key","direction","values","getValueFn","fun","a","b","i","length","sortPart","valueA","valueB","ret","unescapeTagKeysInSelector","hasOwnProperty","startsWith","newKey","replace","getQueryMatcher","_schema","mingoQuery","doc","test","runQueryUpdateFunction","rxQuery","fn","docs","exec","Array","isArray","Promise","all","result","selectorIncludesDeleted","isTrue","value","isNotFalse","$ne","hasDeletedTrue","condition","_deleted","$or","some","$and","$nor","every"],"sources":["../../src/rx-query-helper.ts"],"sourcesContent":["import { LOGICAL_OPERATORS } from './query-planner.ts';\nimport { getPrimaryFieldOfPrimaryKey } from './rx-schema-helper.ts';\nimport type {\n DeepReadonly,\n DeterministicSortComparator,\n FilledMangoQuery,\n MangoQuery,\n MangoQueryOperators,\n MangoQuerySelector,\n MangoQuerySortDirection,\n PropertyType,\n QueryMatcher,\n RxDocument,\n RxDocumentData,\n RxJsonSchema,\n RxQuery\n} from './types/index.d.ts';\nimport {\n clone,\n firstPropertyNameOfObject,\n toArray,\n isMaybeReadonlyArray,\n flatClone,\n objectPathMonad,\n ObjectPathMonadFunction\n} from './plugins/utils/index.ts';\nimport {\n compare as mingoSortComparator\n} from 'mingo/util';\nimport { newRxError } from './rx-error.ts';\nimport { getMingoQuery } from './rx-query-mingo.ts';\n\n/**\n * Normalize the query to ensure we have all fields set\n * and queries that represent the same query logic are detected as equal by the caching.\n */\nexport function normalizeMangoQuery(\n schema: RxJsonSchema>,\n mangoQuery: MangoQuery\n): FilledMangoQuery {\n const primaryKey: string = getPrimaryFieldOfPrimaryKey(schema.primaryKey);\n mangoQuery = flatClone(mangoQuery);\n\n const normalizedMangoQuery: FilledMangoQuery = clone(mangoQuery) as any;\n if (typeof normalizedMangoQuery.skip !== 'number') {\n normalizedMangoQuery.skip = 0;\n }\n\n if (!normalizedMangoQuery.selector) {\n normalizedMangoQuery.selector = {};\n } else {\n normalizedMangoQuery.selector = normalizedMangoQuery.selector;\n /**\n * In mango query, it is possible to have an\n * equals comparison by directly assigning a value\n * to a property, without the '$eq' operator.\n * Like:\n * selector: {\n * foo: 'bar'\n * }\n * For normalization, we have to normalize this\n * so our checks can perform properly.\n *\n *\n * TODO this must work recursive with nested queries that\n * contain multiple selectors via $and or $or etc.\n */\n Object\n .entries(normalizedMangoQuery.selector)\n .forEach(([field, matcher]) => {\n if (typeof matcher !== 'object' || matcher === null) {\n (normalizedMangoQuery as any).selector[field] = {\n $eq: matcher\n };\n }\n });\n }\n\n /**\n * Ensure that if an index is specified,\n * the primaryKey is inside of it.\n */\n if (normalizedMangoQuery.index) {\n const indexAr = toArray(normalizedMangoQuery.index);\n if (!indexAr.includes(primaryKey)) {\n indexAr.push(primaryKey);\n }\n normalizedMangoQuery.index = indexAr;\n }\n\n /**\n * To ensure a deterministic sorting,\n * we have to ensure the primary key is always part\n * of the sort query.\n * Primary sorting is added as last sort parameter,\n * similar to how we add the primary key to indexes that do not have it.\n *\n */\n if (!normalizedMangoQuery.sort) {\n /**\n * If no sort is given at all,\n * we can assume that the user does not care about sort order at al.\n *\n * we cannot just use the primary key as sort parameter\n * because it would likely cause the query to run over the primary key index\n * which has a bad performance in most cases.\n */\n if (normalizedMangoQuery.index) {\n normalizedMangoQuery.sort = normalizedMangoQuery.index.map((field: string) => {\n return { [field as any]: 'asc' } as any;\n });\n } else {\n /**\n * Find the index that best matches the fields with the logical operators\n */\n if (schema.indexes) {\n const fieldsWithLogicalOperator: Set = new Set();\n Object.entries(normalizedMangoQuery.selector).forEach(([field, matcher]) => {\n let hasLogical = false;\n if (typeof matcher === 'object' && matcher !== null) {\n hasLogical = !!Object.keys(matcher).find(operator => LOGICAL_OPERATORS.has(operator));\n } else {\n hasLogical = true;\n }\n if (hasLogical) {\n fieldsWithLogicalOperator.add(field);\n }\n });\n\n\n let currentFieldsAmount = -1;\n let currentBestIndexForSort: string[] | readonly string[] | undefined;\n schema.indexes.forEach(index => {\n const useIndex = isMaybeReadonlyArray(index) ? index : [index];\n const firstWrongIndex = useIndex.findIndex(indexField => !fieldsWithLogicalOperator.has(indexField));\n if (\n firstWrongIndex > 0 &&\n firstWrongIndex > currentFieldsAmount\n ) {\n currentFieldsAmount = firstWrongIndex;\n currentBestIndexForSort = useIndex;\n }\n });\n if (currentBestIndexForSort) {\n normalizedMangoQuery.sort = currentBestIndexForSort.map((field: string) => {\n return { [field as any]: 'asc' } as any;\n });\n }\n\n }\n\n /**\n * Fall back to the primary key as sort order\n * if no better one has been found\n */\n if (!normalizedMangoQuery.sort) {\n normalizedMangoQuery.sort = [{ [primaryKey]: 'asc' }] as any;\n }\n }\n } else {\n const isPrimaryInSort = normalizedMangoQuery.sort\n .find(p => firstPropertyNameOfObject(p) === primaryKey);\n if (!isPrimaryInSort) {\n normalizedMangoQuery.sort = normalizedMangoQuery.sort.slice(0);\n normalizedMangoQuery.sort.push({ [primaryKey]: 'asc' } as any);\n }\n }\n\n return normalizedMangoQuery;\n}\n\n/**\n * Returns the sort-comparator,\n * which is able to sort documents in the same way\n * a query over the db would do.\n */\nexport function getSortComparator(\n schema: RxJsonSchema>,\n query: FilledMangoQuery\n): DeterministicSortComparator {\n if (!query.sort) {\n throw newRxError('SNH', { query });\n }\n const sortParts: {\n key: string;\n direction: MangoQuerySortDirection;\n getValueFn: ObjectPathMonadFunction;\n }[] = [];\n query.sort.forEach(sortBlock => {\n const key = Object.keys(sortBlock)[0];\n const direction = Object.values(sortBlock)[0];\n sortParts.push({\n key,\n direction,\n getValueFn: objectPathMonad(key)\n });\n });\n const fun: DeterministicSortComparator = (a: RxDocType, b: RxDocType) => {\n for (let i = 0; i < sortParts.length; ++i) {\n const sortPart = sortParts[i];\n const valueA = sortPart.getValueFn(a);\n const valueB = sortPart.getValueFn(b);\n if (valueA !== valueB) {\n const ret = sortPart.direction === 'asc' ? mingoSortComparator(valueA, valueB) : mingoSortComparator(valueB, valueA);\n return ret as any;\n }\n }\n };\n\n return fun;\n}\n\n// When the rxdb adapter is sqlite, we escape tag names by wrapping them in quotes:\n// https://github.com/TristanH/rekindled/blob/e42d2fa40305ba98dfab12e8dd7aed07ddb17ebf/reading-clients/shared/database/queryHelpers.ts#L18\n//\n// Although sqlite can match tag keys escaped with quotes, the rxdb event-reduce query matcher (mingo) says that a document like\n// {\n// 'tags': 'a': {...}}\n// }\n// does not match the query:\n// {\"tags.\\\"a\\\"\":{\"$exists\":1}}\n//\n// What this function does is \"fix\" the sqlite queries to unescape the tag keys (basically, remove the quotes).\n// so that the event reduce library can work properly and not remove tagged documents from results.\nfunction unescapeTagKeysInSelector(query: any): any {\n if (typeof query === 'object' && query !== null) {\n // loop through all keys of the object\n for (const key in query) {\n // eslint-disable-next-line no-prototype-builtins\n if (query.hasOwnProperty(key)) {\n // check if key matches the pattern \"tags.\\\"x\\\"\"\n if (key.startsWith('tags.') && key.includes('\"')) {\n const newKey = key.replace(/\\\\\"/g, '');\n // reassign the value to the new key\n query[newKey] = query[key];\n // delete the old key\n delete query[key];\n }\n // if value is an object, apply the function recursively\n if (typeof query[key] === 'object') {\n query[key] = unescapeTagKeysInSelector(query[key]);\n }\n }\n }\n }\n return query;\n}\n\n\n/**\n * Returns a function\n * that can be used to check if a document\n * matches the query.\n */\nexport function getQueryMatcher(\n _schema: RxJsonSchema | RxJsonSchema>,\n query: FilledMangoQuery\n): QueryMatcher> {\n if (!query.sort) {\n throw newRxError('SNH', { query });\n }\n\n const mingoQuery = getMingoQuery(unescapeTagKeysInSelector(query.selector as any));\n\n const fun: QueryMatcher> = (doc: RxDocumentData | DeepReadonly>) => {\n return mingoQuery.test(doc);\n };\n return fun;\n}\n\n\nexport async function runQueryUpdateFunction(\n rxQuery: RxQuery,\n fn: (doc: RxDocument) => Promise>\n): Promise {\n const docs = await rxQuery.exec();\n if (!docs) {\n // only findOne() queries can return null\n return null as any;\n }\n if (Array.isArray(docs)) {\n return Promise.all(\n docs.map(doc => fn(doc))\n ) as any;\n } else {\n // via findOne()\n const result = await fn(docs as any);\n return result as any;\n }\n}\n\n/**\n * Checks if a given selector includes deleted documents.\n * @param selector The MangoQuerySelector to check\n * @returns True if the selector includes deleted documents, false otherwise\n */\nexport function selectorIncludesDeleted(\n selector: MangoQuerySelector | undefined\n): boolean {\n if (!selector) {\n return false;\n }\n\n const isTrue = (value: unknown): boolean =>\n value === true ||\n (typeof value === 'object' &&\n value !== null &&\n '$eq' in value &&\n (value as MangoQueryOperators).$eq === true);\n\n\n const isNotFalse = (value: unknown): boolean =>\n value === true ||\n (typeof value === 'object' &&\n value !== null &&\n '$ne' in value &&\n (value as MangoQueryOperators).$ne === false);\n\n const hasDeletedTrue = (\n condition: MangoQuerySelector\n ): boolean =>\n '_deleted' in condition &&\n (isTrue(condition._deleted as PropertyType) ||\n isNotFalse(\n condition._deleted as PropertyType\n ));\n\n if ('_deleted' in selector) {\n return (\n isTrue(selector._deleted as PropertyType) ||\n isNotFalse(selector._deleted as PropertyType)\n );\n }\n\n if ('$or' in selector && Array.isArray(selector.$or)) {\n return selector.$or.some(hasDeletedTrue);\n }\n\n if ('$and' in selector && Array.isArray(selector.$and)) {\n return selector.$and.some(hasDeletedTrue);\n }\n\n if ('$nor' in selector && Array.isArray(selector.$nor)) {\n return !selector.$nor.every((condition) => !hasDeletedTrue(condition));\n }\n\n return false;\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file +{"version":3,"file":"rx-query-helper.js","names":["LOGICAL_OPERATORS","getPrimaryFieldOfPrimaryKey","clone","firstPropertyNameOfObject","toArray","isMaybeReadonlyArray","flatClone","objectPathMonad","compare","mingoSortComparator","newRxError","getMingoQuery","normalizeMangoQuery","schema","mangoQuery","primaryKey","normalizedMangoQuery","skip","selector","Object","entries","forEach","field","matcher","$eq","index","indexAr","includes","push","sort","map","indexes","fieldsWithLogicalOperator","Set","hasLogical","keys","find","operator","has","add","currentFieldsAmount","currentBestIndexForSort","useIndex","firstWrongIndex","findIndex","indexField","isPrimaryInSort","p","slice","getSortComparator","query","sortParts","sortBlock","key","direction","values","getValueFn","fun","a","b","i","length","sortPart","valueA","valueB","ret","unescapeTagKeysInSelector","newQuery","Array","isArray","hasOwnProperty","newKey","startsWith","replace","getQueryMatcher","_schema","mingoQuery","doc","test","runQueryUpdateFunction","rxQuery","fn","docs","exec","Promise","all","result","selectorIncludesDeleted","isTrue","value","isNotFalse","$ne","hasDeletedTrue","condition","_deleted","$or","some","$and","$nor","every"],"sources":["../../src/rx-query-helper.ts"],"sourcesContent":["import { LOGICAL_OPERATORS } from './query-planner.ts';\nimport { getPrimaryFieldOfPrimaryKey } from './rx-schema-helper.ts';\nimport type {\n DeepReadonly,\n DeterministicSortComparator,\n FilledMangoQuery,\n MangoQuery,\n MangoQueryOperators,\n MangoQuerySelector,\n MangoQuerySortDirection,\n PropertyType,\n QueryMatcher,\n RxDocument,\n RxDocumentData,\n RxJsonSchema,\n RxQuery\n} from './types/index.d.ts';\nimport {\n clone,\n firstPropertyNameOfObject,\n toArray,\n isMaybeReadonlyArray,\n flatClone,\n objectPathMonad,\n ObjectPathMonadFunction\n} from './plugins/utils/index.ts';\nimport {\n compare as mingoSortComparator\n} from 'mingo/util';\nimport { newRxError } from './rx-error.ts';\nimport { getMingoQuery } from './rx-query-mingo.ts';\n\n/**\n * Normalize the query to ensure we have all fields set\n * and queries that represent the same query logic are detected as equal by the caching.\n */\nexport function normalizeMangoQuery(\n schema: RxJsonSchema>,\n mangoQuery: MangoQuery\n): FilledMangoQuery {\n const primaryKey: string = getPrimaryFieldOfPrimaryKey(schema.primaryKey);\n mangoQuery = flatClone(mangoQuery);\n\n const normalizedMangoQuery: FilledMangoQuery = clone(mangoQuery) as any;\n if (typeof normalizedMangoQuery.skip !== 'number') {\n normalizedMangoQuery.skip = 0;\n }\n\n if (!normalizedMangoQuery.selector) {\n normalizedMangoQuery.selector = {};\n } else {\n normalizedMangoQuery.selector = normalizedMangoQuery.selector;\n /**\n * In mango query, it is possible to have an\n * equals comparison by directly assigning a value\n * to a property, without the '$eq' operator.\n * Like:\n * selector: {\n * foo: 'bar'\n * }\n * For normalization, we have to normalize this\n * so our checks can perform properly.\n *\n *\n * TODO this must work recursive with nested queries that\n * contain multiple selectors via $and or $or etc.\n */\n Object\n .entries(normalizedMangoQuery.selector)\n .forEach(([field, matcher]) => {\n if (typeof matcher !== 'object' || matcher === null) {\n (normalizedMangoQuery as any).selector[field] = {\n $eq: matcher\n };\n }\n });\n }\n\n /**\n * Ensure that if an index is specified,\n * the primaryKey is inside of it.\n */\n if (normalizedMangoQuery.index) {\n const indexAr = toArray(normalizedMangoQuery.index);\n if (!indexAr.includes(primaryKey)) {\n indexAr.push(primaryKey);\n }\n normalizedMangoQuery.index = indexAr;\n }\n\n /**\n * To ensure a deterministic sorting,\n * we have to ensure the primary key is always part\n * of the sort query.\n * Primary sorting is added as last sort parameter,\n * similar to how we add the primary key to indexes that do not have it.\n *\n */\n if (!normalizedMangoQuery.sort) {\n /**\n * If no sort is given at all,\n * we can assume that the user does not care about sort order at al.\n *\n * we cannot just use the primary key as sort parameter\n * because it would likely cause the query to run over the primary key index\n * which has a bad performance in most cases.\n */\n if (normalizedMangoQuery.index) {\n normalizedMangoQuery.sort = normalizedMangoQuery.index.map((field: string) => {\n return { [field as any]: 'asc' } as any;\n });\n } else {\n /**\n * Find the index that best matches the fields with the logical operators\n */\n if (schema.indexes) {\n const fieldsWithLogicalOperator: Set = new Set();\n Object.entries(normalizedMangoQuery.selector).forEach(([field, matcher]) => {\n let hasLogical = false;\n if (typeof matcher === 'object' && matcher !== null) {\n hasLogical = !!Object.keys(matcher).find(operator => LOGICAL_OPERATORS.has(operator));\n } else {\n hasLogical = true;\n }\n if (hasLogical) {\n fieldsWithLogicalOperator.add(field);\n }\n });\n\n\n let currentFieldsAmount = -1;\n let currentBestIndexForSort: string[] | readonly string[] | undefined;\n schema.indexes.forEach(index => {\n const useIndex = isMaybeReadonlyArray(index) ? index : [index];\n const firstWrongIndex = useIndex.findIndex(indexField => !fieldsWithLogicalOperator.has(indexField));\n if (\n firstWrongIndex > 0 &&\n firstWrongIndex > currentFieldsAmount\n ) {\n currentFieldsAmount = firstWrongIndex;\n currentBestIndexForSort = useIndex;\n }\n });\n if (currentBestIndexForSort) {\n normalizedMangoQuery.sort = currentBestIndexForSort.map((field: string) => {\n return { [field as any]: 'asc' } as any;\n });\n }\n\n }\n\n /**\n * Fall back to the primary key as sort order\n * if no better one has been found\n */\n if (!normalizedMangoQuery.sort) {\n normalizedMangoQuery.sort = [{ [primaryKey]: 'asc' }] as any;\n }\n }\n } else {\n const isPrimaryInSort = normalizedMangoQuery.sort\n .find(p => firstPropertyNameOfObject(p) === primaryKey);\n if (!isPrimaryInSort) {\n normalizedMangoQuery.sort = normalizedMangoQuery.sort.slice(0);\n normalizedMangoQuery.sort.push({ [primaryKey]: 'asc' } as any);\n }\n }\n\n return normalizedMangoQuery;\n}\n\n/**\n * Returns the sort-comparator,\n * which is able to sort documents in the same way\n * a query over the db would do.\n */\nexport function getSortComparator(\n schema: RxJsonSchema>,\n query: FilledMangoQuery\n): DeterministicSortComparator {\n if (!query.sort) {\n throw newRxError('SNH', { query });\n }\n const sortParts: {\n key: string;\n direction: MangoQuerySortDirection;\n getValueFn: ObjectPathMonadFunction;\n }[] = [];\n query.sort.forEach(sortBlock => {\n const key = Object.keys(sortBlock)[0];\n const direction = Object.values(sortBlock)[0];\n sortParts.push({\n key,\n direction,\n getValueFn: objectPathMonad(key)\n });\n });\n const fun: DeterministicSortComparator = (a: RxDocType, b: RxDocType) => {\n for (let i = 0; i < sortParts.length; ++i) {\n const sortPart = sortParts[i];\n const valueA = sortPart.getValueFn(a);\n const valueB = sortPart.getValueFn(b);\n if (valueA !== valueB) {\n const ret = sortPart.direction === 'asc' ? mingoSortComparator(valueA, valueB) : mingoSortComparator(valueB, valueA);\n return ret as any;\n }\n }\n };\n\n return fun;\n}\n\n// When the rxdb adapter is sqlite, we escape tag names by wrapping them in quotes:\n// https://github.com/TristanH/rekindled/blob/e42d2fa40305ba98dfab12e8dd7aed07ddb17ebf/reading-clients/shared/database/queryHelpers.ts#L18\n//\n// Although sqlite can match tag keys escaped with quotes, the rxdb event-reduce query matcher (mingo) says that a document like\n// {\n// 'tags': 'a': {...}}\n// }\n// does not match the query:\n// {\"tags.\\\"a\\\"\":{\"$exists\":1}}\n//\n// What this function does is \"fix\" the sqlite queries to unescape the tag keys (basically, remove the quotes).\n// so that the event reduce library can work properly and not remove tagged documents from results.\nfunction unescapeTagKeysInSelector(query: any): any {\n if (typeof query === 'object' && query !== null) {\n const newQuery: any = Array.isArray(query) ? [] : {};\n // loop through all keys of the object\n for (const key in query) {\n // eslint-disable-next-line no-prototype-builtins\n if (query.hasOwnProperty(key)) {\n // check if key matches the pattern \"tags.\\\"x\\\"\"\n let newKey = key;\n if (key.startsWith('tags.') && key.includes('\"')) {\n newKey = key.replace(/\"/g, '');\n }\n // recursively process the value\n newQuery[newKey] = unescapeTagKeysInSelector(query[key]);\n }\n }\n return newQuery;\n }\n return query;\n}\n\n\n/**\n * Returns a function\n * that can be used to check if a document\n * matches the query.\n */\nexport function getQueryMatcher(\n _schema: RxJsonSchema | RxJsonSchema>,\n query: FilledMangoQuery\n): QueryMatcher> {\n if (!query.sort) {\n throw newRxError('SNH', { query });\n }\n\n const mingoQuery = getMingoQuery(unescapeTagKeysInSelector(query.selector as any));\n\n const fun: QueryMatcher> = (doc: RxDocumentData | DeepReadonly>) => {\n return mingoQuery.test(doc);\n };\n return fun;\n}\n\n\nexport async function runQueryUpdateFunction(\n rxQuery: RxQuery,\n fn: (doc: RxDocument) => Promise>\n): Promise {\n const docs = await rxQuery.exec();\n if (!docs) {\n // only findOne() queries can return null\n return null as any;\n }\n if (Array.isArray(docs)) {\n return Promise.all(\n docs.map(doc => fn(doc))\n ) as any;\n } else {\n // via findOne()\n const result = await fn(docs as any);\n return result as any;\n }\n}\n\n/**\n * Checks if a given selector includes deleted documents.\n * @param selector The MangoQuerySelector to check\n * @returns True if the selector includes deleted documents, false otherwise\n */\nexport function selectorIncludesDeleted(\n selector: MangoQuerySelector | undefined\n): boolean {\n if (!selector) {\n return false;\n }\n\n const isTrue = (value: unknown): boolean =>\n value === true ||\n (typeof value === 'object' &&\n value !== null &&\n '$eq' in value &&\n (value as MangoQueryOperators).$eq === true);\n\n\n const isNotFalse = (value: unknown): boolean =>\n value === true ||\n (typeof value === 'object' &&\n value !== null &&\n '$ne' in value &&\n (value as MangoQueryOperators).$ne === false);\n\n const hasDeletedTrue = (\n condition: MangoQuerySelector\n ): boolean =>\n '_deleted' in condition &&\n (isTrue(condition._deleted as PropertyType) ||\n isNotFalse(\n condition._deleted as PropertyType\n ));\n\n if ('_deleted' in selector) {\n return (\n isTrue(selector._deleted as PropertyType) ||\n isNotFalse(selector._deleted as PropertyType)\n );\n }\n\n if ('$or' in selector && Array.isArray(selector.$or)) {\n return selector.$or.some(hasDeletedTrue);\n }\n\n if ('$and' in selector && Array.isArray(selector.$and)) {\n return selector.$and.some(hasDeletedTrue);\n }\n\n if ('$nor' in selector && Array.isArray(selector.$nor)) {\n return !selector.$nor.every((condition) => !hasDeletedTrue(condition));\n }\n\n return false;\n}\n"],"mappings":"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","ignoreList":[]} \ No newline at end of file diff --git a/src/rx-query-helper.ts b/src/rx-query-helper.ts index fb364c3c9e6..82a7e43f86c 100644 --- a/src/rx-query-helper.ts +++ b/src/rx-query-helper.ts @@ -224,24 +224,21 @@ export function getSortComparator( // so that the event reduce library can work properly and not remove tagged documents from results. function unescapeTagKeysInSelector(query: any): any { if (typeof query === 'object' && query !== null) { + const newQuery: any = Array.isArray(query) ? [] : {}; // loop through all keys of the object for (const key in query) { // eslint-disable-next-line no-prototype-builtins if (query.hasOwnProperty(key)) { // check if key matches the pattern "tags.\"x\"" + let newKey = key; if (key.startsWith('tags.') && key.includes('"')) { - const newKey = key.replace(/\\"/g, ''); - // reassign the value to the new key - query[newKey] = query[key]; - // delete the old key - delete query[key]; - } - // if value is an object, apply the function recursively - if (typeof query[key] === 'object') { - query[key] = unescapeTagKeysInSelector(query[key]); + newKey = key.replace(/"/g, ''); } + // recursively process the value + newQuery[newKey] = unescapeTagKeysInSelector(query[key]); } } + return newQuery; } return query; }