From 6fe41de481f0b1a966a3a61531cb3770b10dfc17 Mon Sep 17 00:00:00 2001 From: saravanakumardb1 Date: Mon, 2 Mar 2026 01:50:09 -0800 Subject: [PATCH] fix(datastore): SQL now emits ARRAY_CONTAINS OR CONTAINS for array+string support --- packages/datastore/src/__tests__/memory.test.ts | 7 +++++++ packages/datastore/src/filter.ts | 10 +++++----- 2 files changed, 12 insertions(+), 5 deletions(-) diff --git a/packages/datastore/src/__tests__/memory.test.ts b/packages/datastore/src/__tests__/memory.test.ts index 3fe979e2..9652d2fc 100644 --- a/packages/datastore/src/__tests__/memory.test.ts +++ b/packages/datastore/src/__tests__/memory.test.ts @@ -266,6 +266,13 @@ describe('filterToCosmosSQL', () => { expect(result.parameters).toHaveLength(2); }); + it('$contains emits ARRAY_CONTAINS OR CONTAINS', () => { + const result = filterToCosmosSQL({ tags: { $contains: 'urgent' } }); + expect(result.query).toContain('ARRAY_CONTAINS(c.tags, @p0)'); + expect(result.query).toContain('CONTAINS(c.tags, @p0)'); + expect(result.parameters).toEqual([{ name: '@p0', value: 'urgent' }]); + }); + it('$or', () => { const result = filterToCosmosSQL({ $or: [{ a: 1 }, { b: 2 }] }); expect(result.query).toContain('OR'); diff --git a/packages/datastore/src/filter.ts b/packages/datastore/src/filter.ts index 7f37282c..6ac78ae2 100644 --- a/packages/datastore/src/filter.ts +++ b/packages/datastore/src/filter.ts @@ -139,11 +139,11 @@ export function filterToCosmosSQL(filter: FilterMap): SqlQuery { } if (op.$contains !== undefined) { - // Could be array or string — use CONTAINS for string, ARRAY_CONTAINS for array - // In Cosmos SQL, we use ARRAY_CONTAINS for arrays and CONTAINS for strings - // Since we can't know the type at SQL-gen time, use CONTAINS (works for strings) - // Callers dealing with arrays should use ARRAY_CONTAINS via rawQuery - parts.push(`CONTAINS(c.${key}, ${nextParam(op.$contains)})`); + // Could be array or string — emit both ARRAY_CONTAINS and CONTAINS. + // Cosmos returns false (not error) when the function doesn't match the field type, + // so OR-ing them handles both array membership and string substring correctly. + const param = nextParam(op.$contains); + parts.push(`(ARRAY_CONTAINS(c.${key}, ${param}) OR CONTAINS(c.${key}, ${param}))`); } if (op.$in !== undefined) {