diff --git a/CHANGELOG-Unreleased.md b/CHANGELOG-Unreleased.md index 9d43e2bdd..92f09d781 100644 --- a/CHANGELOG-Unreleased.md +++ b/CHANGELOG-Unreleased.md @@ -11,6 +11,8 @@ - [LokiJS] Multitab sync issue fix - [Android] Added linker flag for building with 16kB page alignment - [TS] make catchError visible to typescript +- [Observation] Fixed `canEncodeMatcher()` reporting queries containing `Q.unsafeSqlExpr`, + `Q.unsafeLokiExpr`, or a `Q.on` nested inside `Q.and`/`Q.or` as encodable. ### Performance diff --git a/src/observation/encodeMatcher/canEncode.js b/src/observation/encodeMatcher/canEncode.js index dd6ab8d08..007851915 100644 --- a/src/observation/encodeMatcher/canEncode.js +++ b/src/observation/encodeMatcher/canEncode.js @@ -1,11 +1,23 @@ // @flow -import type { QueryDescription } from '../../QueryDescription' +import type { QueryDescription, Where } from '../../QueryDescription' -export const forbiddenError = `Queries with joins, sortBy, take, skip, lokiTransform can't be encoded into a matcher` +export const forbiddenError = `Queries with joins, sortBy, take, skip, lokiTransform, Q.unsafeSqlExpr, Q.unsafeLokiExpr can't be encoded into a matcher` + +const isEncodableWhere = (where: Where): boolean => { + switch (where.type) { + case 'where': + return true + case 'and': + case 'or': + return where.conditions.every(isEncodableWhere) + default: + return false + } +} export default function canEncodeMatcher(query: QueryDescription): boolean { - const { joinTables, nestedJoinTables, sortBy, take, skip, lokiTransform, sql } = query + const { joinTables, nestedJoinTables, sortBy, take, skip, lokiTransform, sql, where } = query return ( !joinTables.length && @@ -14,6 +26,7 @@ export default function canEncodeMatcher(query: QueryDescription): boolean { !take && !skip && !lokiTransform && - !sql + !sql && + where.every(isEncodableWhere) ) } diff --git a/src/observation/encodeMatcher/test.js b/src/observation/encodeMatcher/test.js index 5be8bfd77..f69dd5a99 100644 --- a/src/observation/encodeMatcher/test.js +++ b/src/observation/encodeMatcher/test.js @@ -23,6 +23,11 @@ const unencodableQueries = [ [Q.take(100)], [Q.unsafeLokiTransform(() => {})], [Q.unsafeSqlQuery('select * from tasks')], + [Q.unsafeSqlExpr('')], + [Q.unsafeLokiExpr({})], + [Q.or(Q.on('projects', 'team_id', 'abcdef'))], + [Q.or(Q.unsafeSqlExpr(''))], + [Q.or(Q.unsafeLokiExpr({}))], ] describe('SQLite encodeMatcher', () => { @@ -61,9 +66,6 @@ describe('SQLite encodeMatcher', () => { // console.log(query) expect(() => makeMatcher(query)).toThrow(`can't be encoded into a matcher`) }) - expect(() => makeMatcher([Q.or(Q.on('projects', 'team_id', 'abcdef'))])).toThrow('Illegal Q.on') - expect(() => makeMatcher([Q.or(Q.unsafeSqlExpr(''))])).toThrow('Illegal') - expect(() => makeMatcher([Q.or(Q.unsafeLokiExpr({}))])).toThrow('Illegal') }) }) diff --git a/src/observation/test.js b/src/observation/test.js index f4d6eadfe..1104fe6b1 100644 --- a/src/observation/test.js +++ b/src/observation/test.js @@ -96,4 +96,17 @@ describe('common observation tests', () => { subscribeToQueryWithColumns(mockDb.tasks.query(...complexQuery), ['position'], observer), ) }) + const unencodableQuery = Q.unsafeLokiExpr({ is_completed: true }) + it(`updates list before model - test with an unencodable where clause`, async () => { + const mockDb = mockDatabase() + await updatesListBeforeModelTest(mockDb, (observer) => + subscribeToQuery(mockDb.tasks.query(unencodableQuery), observer), + ) + }) + it(`updates list before model - test with an unencodable where clause and columns`, async () => { + const mockDb = mockDatabase() + await updatesListBeforeModelTest(mockDb, (observer) => + subscribeToQueryWithColumns(mockDb.tasks.query(unencodableQuery), ['position'], observer), + ) + }) })