Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
138 changes: 138 additions & 0 deletions packages/angular-db/tests/inject-live-query.test-d.ts
Original file line number Diff line number Diff line change
@@ -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<Person>({
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<Person | undefined>()
})

it(`should type findOne config object to return a single row`, () => {
const collection = createCollection(
mockSyncCollectionOptions<Person>({
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<Person | undefined>()
})

it(`should type findOne collection using liveQueryCollectionOptions to return a single row`, () => {
const collection = createCollection(
mockSyncCollectionOptions<Person>({
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<SingleResult>()

const { data } = injectLiveQuery(liveQueryCollection)

// findOne returns a single result or undefined
expectTypeOf(data()).toEqualTypeOf<Person | undefined>()
})

it(`should type findOne collection using createLiveQueryCollection to return a single row`, () => {
const collection = createCollection(
mockSyncCollectionOptions<Person>({
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<SingleResult>()

const { data } = injectLiveQuery(liveQueryCollection)

// findOne returns a single result or undefined
expectTypeOf(data()).toEqualTypeOf<Person | undefined>()
})

it(`should type regular query to return an array`, () => {
const collection = createCollection(
mockSyncCollectionOptions<Person>({
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<Array<{ id: string; name: string }>>()
})
})
60 changes: 48 additions & 12 deletions packages/angular-db/tests/inject-live-query.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import type {
CollectionStatus,
Context,
LiveQueryCollectionConfig,
NonSingleResult,
QueryBuilder,
} from '@tanstack/db'

Expand Down Expand Up @@ -66,12 +67,13 @@ async function waitForAngularUpdate() {
function createMockCollection<T extends object, K extends string | number>(
initial: Array<T & Record<`id`, K>> = [],
initialStatus: CollectionStatus = `ready`,
): Collection<T, K, Record<string, never>> & {
__setStatus: (s: CollectionStatus) => void
__replaceAll: (rows: Array<T & Record<`id`, K>>) => void
__upsert: (row: T & Record<`id`, K>) => void
__delete: (key: K) => void
} {
): Collection<T, K, Record<string, never>> &
NonSingleResult & {
__setStatus: (s: CollectionStatus) => void
__replaceAll: (rows: Array<T & Record<`id`, K>>) => void
__upsert: (row: T & Record<`id`, K>) => void
__delete: (key: K) => void
} {
const map = new Map<K, T>()
for (const r of initial) {
map.set(r.id, r)
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -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)
})
})
Expand Down Expand Up @@ -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)
Expand Down Expand Up @@ -752,6 +754,40 @@ describe(`injectLiveQuery`, () => {
})
})

it(`should return a single object for findOne query`, async () => {
await TestBed.runInInjectionContext(async () => {
const collection = createCollection(
mockSyncCollectionOptions<Person>({
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 () => {
Expand Down Expand Up @@ -795,7 +831,7 @@ describe(`injectLiveQuery`, () => {
})

// Start the live query sync manually
liveQueryCollection().preload()
liveQueryCollection()!.preload()

await waitForAngularUpdate()

Expand Down Expand Up @@ -907,7 +943,7 @@ describe(`injectLiveQuery`, () => {
})

// Start the live query sync manually
liveQueryCollection().preload()
liveQueryCollection()!.preload()

await waitForAngularUpdate()

Expand Down Expand Up @@ -1007,7 +1043,7 @@ describe(`injectLiveQuery`, () => {
})

// Start the live query sync manually
liveQueryCollection().preload()
liveQueryCollection()!.preload()

await waitForAngularUpdate()

Expand Down
Loading