From 78734ba91be84644b7f4f27b3ddfcdb5632637d6 Mon Sep 17 00:00:00 2001 From: "claude[bot]" <41898282+claude[bot]@users.noreply.github.com> Date: Thu, 19 Feb 2026 13:57:32 +0000 Subject: [PATCH 1/3] test: assert findOne returns single object in angular-db (issue #1261) Co-Authored-By: Claude Opus 4.6 --- .../tests/inject-live-query.test.ts | 34 +++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/packages/angular-db/tests/inject-live-query.test.ts b/packages/angular-db/tests/inject-live-query.test.ts index 2f4db01ca..1175c20a5 100644 --- a/packages/angular-db/tests/inject-live-query.test.ts +++ b/packages/angular-db/tests/inject-live-query.test.ts @@ -752,6 +752,40 @@ describe(`injectLiveQuery`, () => { }) }) + it(`should return a single object for findOne query`, async () => { + await TestBed.runInInjectionContext(async () => { + const collection = createCollection( + mockSyncCollectionOptions({ + id: `test-persons-findone-angular`, + getKey: (person: Person) => person.id, + initialData: initialPersons, + }), + ) + + const { state, data } = injectLiveQuery((q) => + q + .from({ collection }) + .where(({ collection: c }) => eq(c.id, `3`)) + .findOne(), + ) + + await waitForAngularUpdate() + + expect(state().size).toBe(1) + expect(state().get(`3`)).toMatchObject({ + id: `3`, + name: `John Smith`, + }) + + // findOne should return a single object, not an array + expect(Array.isArray(data())).toBe(false) + expect(data()).toMatchObject({ + id: `3`, + name: `John Smith`, + }) + }) + }) + describe(`eager execution during sync`, () => { it(`should show state while isLoading is true during sync`, async () => { await TestBed.runInInjectionContext(async () => { From 0689ccc8ab91a6199665847e016370031fd6dde4 Mon Sep 17 00:00:00 2001 From: Kevin De Porre Date: Thu, 19 Feb 2026 15:19:24 +0100 Subject: [PATCH 2/3] test: add type assertions for injectLiveQuery findOne in angular-db Adds inject-live-query.test-d.ts with expectTypeOf assertions verifying that injectLiveQuery with findOne() types data as Signal and regular queries type data as Signal>. Co-Authored-By: Claude Opus 4.6 --- .../tests/inject-live-query.test-d.ts | 138 ++++++++++++++++++ 1 file changed, 138 insertions(+) create mode 100644 packages/angular-db/tests/inject-live-query.test-d.ts diff --git a/packages/angular-db/tests/inject-live-query.test-d.ts b/packages/angular-db/tests/inject-live-query.test-d.ts new file mode 100644 index 000000000..667e11314 --- /dev/null +++ b/packages/angular-db/tests/inject-live-query.test-d.ts @@ -0,0 +1,138 @@ +import { describe, expectTypeOf, it } from 'vitest' +import { createCollection } from '../../db/src/collection/index' +import { mockSyncCollectionOptions } from '../../db/tests/utils' +import { + createLiveQueryCollection, + eq, + liveQueryCollectionOptions, +} from '../../db/src/query/index' +import { injectLiveQuery } from '../src/index' +import type { SingleResult } from '../../db/src/types' + +type Person = { + id: string + name: string + age: number + email: string + isActive: boolean + team: string +} + +describe(`injectLiveQuery type assertions`, () => { + it(`should type findOne query builder to return a single row`, () => { + const collection = createCollection( + mockSyncCollectionOptions({ + id: `test-persons-findone-angular`, + getKey: (person: Person) => person.id, + initialData: [], + }), + ) + + const { data } = injectLiveQuery((q) => + q + .from({ collection }) + .where(({ collection: c }) => eq(c.id, `3`)) + .findOne(), + ) + + // findOne returns a single result or undefined + expectTypeOf(data()).toEqualTypeOf() + }) + + it(`should type findOne config object to return a single row`, () => { + const collection = createCollection( + mockSyncCollectionOptions({ + id: `test-persons-findone-config-angular`, + getKey: (person: Person) => person.id, + initialData: [], + }), + ) + + const { data } = injectLiveQuery({ + params: () => ({ id: `3` }), + query: ({ params, q }) => + q + .from({ collection }) + .where(({ collection: c }) => eq(c.id, params.id)) + .findOne(), + }) + + // findOne returns a single result or undefined + expectTypeOf(data()).toEqualTypeOf() + }) + + it(`should type findOne collection using liveQueryCollectionOptions to return a single row`, () => { + const collection = createCollection( + mockSyncCollectionOptions({ + id: `test-persons-findone-options-angular`, + getKey: (person: Person) => person.id, + initialData: [], + }), + ) + + const options = liveQueryCollectionOptions({ + query: (q) => + q + .from({ collection }) + .where(({ collection: c }) => eq(c.id, `3`)) + .findOne(), + }) + + const liveQueryCollection = createCollection(options) + + expectTypeOf(liveQueryCollection).toExtend() + + const { data } = injectLiveQuery(liveQueryCollection) + + // findOne returns a single result or undefined + expectTypeOf(data()).toEqualTypeOf() + }) + + it(`should type findOne collection using createLiveQueryCollection to return a single row`, () => { + const collection = createCollection( + mockSyncCollectionOptions({ + id: `test-persons-findone-create-angular`, + getKey: (person: Person) => person.id, + initialData: [], + }), + ) + + const liveQueryCollection = createLiveQueryCollection({ + query: (q) => + q + .from({ collection }) + .where(({ collection: c }) => eq(c.id, `3`)) + .findOne(), + }) + + expectTypeOf(liveQueryCollection).toExtend() + + const { data } = injectLiveQuery(liveQueryCollection) + + // findOne returns a single result or undefined + expectTypeOf(data()).toEqualTypeOf() + }) + + it(`should type regular query to return an array`, () => { + const collection = createCollection( + mockSyncCollectionOptions({ + id: `test-persons-array-angular`, + getKey: (person: Person) => person.id, + initialData: [], + }), + ) + + const { data } = injectLiveQuery((q) => + q + .from({ collection }) + .where(({ collection: c }) => eq(c.isActive, true)) + .select(({ collection: c }) => ({ + id: c.id, + name: c.name, + })), + ) + + // Regular queries should return an array + expectTypeOf(data()).toEqualTypeOf>() + }) +}) From a137fcaa65bbd9cf8c0a9c9142eb33ddc855902e Mon Sep 17 00:00:00 2001 From: Kevin De Porre Date: Thu, 19 Feb 2026 15:35:16 +0100 Subject: [PATCH 3/3] test: fix type errors in inject-live-query test helpers - Add NonSingleResult to createMockCollection return type since mock collections are never singleResult - Add non-null assertions for collection() signal access in tests Co-Authored-By: Claude Opus 4.6 --- .../tests/inject-live-query.test.ts | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/packages/angular-db/tests/inject-live-query.test.ts b/packages/angular-db/tests/inject-live-query.test.ts index 1175c20a5..81fbb12a9 100644 --- a/packages/angular-db/tests/inject-live-query.test.ts +++ b/packages/angular-db/tests/inject-live-query.test.ts @@ -14,6 +14,7 @@ import type { CollectionStatus, Context, LiveQueryCollectionConfig, + NonSingleResult, QueryBuilder, } from '@tanstack/db' @@ -66,12 +67,13 @@ async function waitForAngularUpdate() { function createMockCollection( initial: Array> = [], initialStatus: CollectionStatus = `ready`, -): Collection> & { - __setStatus: (s: CollectionStatus) => void - __replaceAll: (rows: Array>) => void - __upsert: (row: T & Record<`id`, K>) => void - __delete: (key: K) => void -} { +): Collection> & + NonSingleResult & { + __setStatus: (s: CollectionStatus) => void + __replaceAll: (rows: Array>) => void + __upsert: (row: T & Record<`id`, K>) => void + __delete: (key: K) => void + } { const map = new Map() for (const r of initial) { map.set(r.id, r) @@ -532,7 +534,7 @@ describe(`injectLiveQuery`, () => { await waitForAngularUpdate() - expect(res.collection().id).toEqual(expect.any(String)) + expect(res.collection()!.id).toEqual(expect.any(String)) expect(res.status()).toBe(`ready`) expect(Array.isArray(res.data())).toBe(true) expect(res.state() instanceof Map).toBe(true) @@ -565,7 +567,7 @@ describe(`injectLiveQuery`, () => { const res = injectLiveQuery(config) await waitForAngularUpdate() - expect(res.collection().id).toEqual(expect.any(String)) + expect(res.collection()!.id).toEqual(expect.any(String)) expect(res.isReady()).toBe(true) }) }) @@ -611,7 +613,7 @@ describe(`injectLiveQuery`, () => { await waitForAngularUpdate() - expect(res.collection().id).toEqual(expect.any(String)) + expect(res.collection()!.id).toEqual(expect.any(String)) expect(res.status()).toBe(`ready`) expect(Array.isArray(res.data())).toBe(true) expect(res.state() instanceof Map).toBe(true) @@ -829,7 +831,7 @@ describe(`injectLiveQuery`, () => { }) // Start the live query sync manually - liveQueryCollection().preload() + liveQueryCollection()!.preload() await waitForAngularUpdate() @@ -941,7 +943,7 @@ describe(`injectLiveQuery`, () => { }) // Start the live query sync manually - liveQueryCollection().preload() + liveQueryCollection()!.preload() await waitForAngularUpdate() @@ -1041,7 +1043,7 @@ describe(`injectLiveQuery`, () => { }) // Start the live query sync manually - liveQueryCollection().preload() + liveQueryCollection()!.preload() await waitForAngularUpdate()