diff --git a/packages/entity-database-adapter-knex-testing-utils/src/StubPostgresDatabaseAdapter.ts b/packages/entity-database-adapter-knex-testing-utils/src/StubPostgresDatabaseAdapter.ts index b076661656..70d1c3293c 100644 --- a/packages/entity-database-adapter-knex-testing-utils/src/StubPostgresDatabaseAdapter.ts +++ b/packages/entity-database-adapter-knex-testing-utils/src/StubPostgresDatabaseAdapter.ts @@ -75,7 +75,7 @@ export class StubPostgresDatabaseAdapter< ): Promise { const objectCollection = this.getObjectCollectionForTable(tableName); const results = StubPostgresDatabaseAdapter.uniqBy(tableTuples, (tuple) => - tuple.join(':'), + JSON.stringify(tuple), ).reduce( (acc, tableTuple) => { return acc.concat( diff --git a/packages/entity-database-adapter-knex-testing-utils/src/__tests__/StubPostgresDatabaseAdapter-test.ts b/packages/entity-database-adapter-knex-testing-utils/src/__tests__/StubPostgresDatabaseAdapter-test.ts index 062e9306b9..f012c47cd6 100644 --- a/packages/entity-database-adapter-knex-testing-utils/src/__tests__/StubPostgresDatabaseAdapter-test.ts +++ b/packages/entity-database-adapter-knex-testing-utils/src/__tests__/StubPostgresDatabaseAdapter-test.ts @@ -174,6 +174,55 @@ describe(StubPostgresDatabaseAdapter, () => { const id2Results = results.get(new SingleFieldValueHolder('id2')); expect(id2Results?.[0]).toMatchObject({ customIdField: 'id2', stringField: 'test2' }); }); + + it('does not collapse distinct composite tuples that stringify with the same delimiter join', async () => { + const queryContext = instance(mock(EntityQueryContext)); + const databaseAdapter = new StubPostgresDatabaseAdapter( + testEntityConfiguration, + StubPostgresDatabaseAdapter.convertFieldObjectsToDataStore( + testEntityConfiguration, + new Map([ + [ + testEntityConfiguration.tableName, + [ + { + customIdField: 'id1', + testIndexedField: 'b', + intField: 5, + stringField: 'a:b', + dateField: new Date(), + nullableField: null, + }, + { + customIdField: 'id2', + testIndexedField: 'b:c', + intField: 10, + stringField: 'a', + dateField: new Date(), + nullableField: null, + }, + ], + ], + ]), + ), + ); + + const results = await databaseAdapter.fetchManyWhereAsync( + queryContext, + new CompositeFieldHolder(['stringField', 'testIndexedField']), + [ + new CompositeFieldValueHolder({ stringField: 'a:b', testIndexedField: 'c' }), + new CompositeFieldValueHolder({ stringField: 'a', testIndexedField: 'b:c' }), + ], + ); + + expect( + results.get(new CompositeFieldValueHolder({ stringField: 'a:b', testIndexedField: 'c' })), + ).toHaveLength(0); + expect( + results.get(new CompositeFieldValueHolder({ stringField: 'a', testIndexedField: 'b:c' })), + ).toHaveLength(1); + }); }); describe('fetchOneWhereAsync', () => { diff --git a/packages/entity-database-adapter-knex/src/__tests__/fixtures/StubPostgresDatabaseAdapter.ts b/packages/entity-database-adapter-knex/src/__tests__/fixtures/StubPostgresDatabaseAdapter.ts index fe10d3947f..af77a4d5e7 100644 --- a/packages/entity-database-adapter-knex/src/__tests__/fixtures/StubPostgresDatabaseAdapter.ts +++ b/packages/entity-database-adapter-knex/src/__tests__/fixtures/StubPostgresDatabaseAdapter.ts @@ -76,7 +76,7 @@ export class StubPostgresDatabaseAdapter< ): Promise { const objectCollection = this.getObjectCollectionForTable(tableName); const results = StubPostgresDatabaseAdapter.uniqBy(tableTuples, (tuple) => - tuple.join(':'), + JSON.stringify(tuple), ).reduce( (acc, tableTuple) => { return acc.concat( diff --git a/packages/entity-testing-utils/src/StubDatabaseAdapter.ts b/packages/entity-testing-utils/src/StubDatabaseAdapter.ts index 5d8f141eed..c47469a2bc 100644 --- a/packages/entity-testing-utils/src/StubDatabaseAdapter.ts +++ b/packages/entity-testing-utils/src/StubDatabaseAdapter.ts @@ -63,7 +63,9 @@ export class StubDatabaseAdapter< tableTuples: (readonly any[])[], ): Promise { const objectCollection = this.getObjectCollectionForTable(tableName); - const results = StubDatabaseAdapter.uniqBy(tableTuples, (tuple) => tuple.join(':')).reduce( + const results = StubDatabaseAdapter.uniqBy(tableTuples, (tuple) => + JSON.stringify(tuple), + ).reduce( (acc, tableTuple) => { return acc.concat( objectCollection.filter((obj) => { diff --git a/packages/entity-testing-utils/src/__tests__/StubDatabaseAdapter-test.ts b/packages/entity-testing-utils/src/__tests__/StubDatabaseAdapter-test.ts index 68d0b4a336..2a9cd6bf20 100644 --- a/packages/entity-testing-utils/src/__tests__/StubDatabaseAdapter-test.ts +++ b/packages/entity-testing-utils/src/__tests__/StubDatabaseAdapter-test.ts @@ -117,6 +117,55 @@ describe(StubDatabaseAdapter, () => { results2.get(new CompositeFieldValueHolder({ stringField: 'not-in-db', intField: 5 })), ).toHaveLength(0); }); + + it('does not collapse distinct composite tuples that stringify with the same delimiter join', async () => { + const queryContext = instance(mock(EntityQueryContext)); + const databaseAdapter = new StubDatabaseAdapter( + testEntityConfiguration, + StubDatabaseAdapter.convertFieldObjectsToDataStore( + testEntityConfiguration, + new Map([ + [ + testEntityConfiguration.tableName, + [ + { + customIdField: 'id1', + testIndexedField: 'b', + intField: 5, + stringField: 'a:b', + dateField: new Date(), + nullableField: null, + }, + { + customIdField: 'id2', + testIndexedField: 'b:c', + intField: 10, + stringField: 'a', + dateField: new Date(), + nullableField: null, + }, + ], + ], + ]), + ), + ); + + const results = await databaseAdapter.fetchManyWhereAsync( + queryContext, + new CompositeFieldHolder(['stringField', 'testIndexedField']), + [ + new CompositeFieldValueHolder({ stringField: 'a:b', testIndexedField: 'c' }), + new CompositeFieldValueHolder({ stringField: 'a', testIndexedField: 'b:c' }), + ], + ); + + expect( + results.get(new CompositeFieldValueHolder({ stringField: 'a:b', testIndexedField: 'c' })), + ).toHaveLength(0); + expect( + results.get(new CompositeFieldValueHolder({ stringField: 'a', testIndexedField: 'b:c' })), + ).toHaveLength(1); + }); }); describe('fetchOneWhereAsync', () => { diff --git a/packages/entity/src/utils/__testfixtures__/StubDatabaseAdapter.ts b/packages/entity/src/utils/__testfixtures__/StubDatabaseAdapter.ts index 25b86c5a1d..3d9a70e554 100644 --- a/packages/entity/src/utils/__testfixtures__/StubDatabaseAdapter.ts +++ b/packages/entity/src/utils/__testfixtures__/StubDatabaseAdapter.ts @@ -63,7 +63,9 @@ export class StubDatabaseAdapter< tableTuples: (readonly any[])[], ): Promise { const objectCollection = this.getObjectCollectionForTable(tableName); - const results = StubDatabaseAdapter.uniqBy(tableTuples, (tuple) => tuple.join(':')).reduce( + const results = StubDatabaseAdapter.uniqBy(tableTuples, (tuple) => + JSON.stringify(tuple), + ).reduce( (acc, tableTuple) => { return acc.concat( objectCollection.filter((obj) => {