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
5 changes: 5 additions & 0 deletions .changeset/early-heads-stand.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'@tanstack/angular-db': patch
---

Allow input signals in inject live query
5 changes: 5 additions & 0 deletions packages/angular-db/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -53,11 +53,16 @@
"rxjs": ">=6.0.0"
},
"devDependencies": {
"@analogjs/vite-plugin-angular": "^2.4.5",
"@analogjs/vitest-angular": "^2.4.5",
"@angular/common": "^20.3.16",
"@angular/compiler": "^20.3.16",
"@angular/compiler-cli": "^20.3.16",
"@angular/core": "^20.3.16",
"@angular/platform-browser": "^20.3.16",
"@angular/platform-browser-dynamic": "^20.3.16",
"@testing-library/angular": "^18.1.1",
"@testing-library/jest-dom": "^6.9.1",
"@vitest/coverage-istanbul": "^3.2.4",
"rxjs": "^7.8.2",
"zone.js": "~0.15.0"
Expand Down
25 changes: 7 additions & 18 deletions packages/angular-db/src/index.ts
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
import {
DestroyRef,
assertInInjectionContext,
computed,
effect,
inject,
linkedSignal,
signal,
untracked,
} from '@angular/core'
import { BaseQueryBuilder, createLiveQueryCollection } from '@tanstack/db'
import type {
Expand Down Expand Up @@ -135,7 +135,6 @@ export function injectLiveQuery<
): InjectLiveQueryResultWithSingleResultCollection<TResult, TKey, TUtils>
export function injectLiveQuery(opts: any) {
assertInInjectionContext(injectLiveQuery)
const destroyRef = inject(DestroyRef)

const collection = computed(() => {
// Check if it's an existing collection
Expand Down Expand Up @@ -204,8 +203,8 @@ export function injectLiveQuery(opts: any) {

const state = signal(new Map<string | number, any>())
const internalData = signal<Array<any>>([])
const status = signal<CollectionStatus | `disabled`>(
collection() ? `idle` : `disabled`,
const status = linkedSignal<CollectionStatus | `disabled`>(
() => untracked(collection) ? untracked(collection).status : `disabled`,
)

// Returns single item for singleResult collections, array otherwise
Expand All @@ -231,12 +230,6 @@ export function injectLiveQuery(opts: any) {
status.set(currentCollection.status)
}

let unsub: (() => void) | null = null
const cleanup = () => {
unsub?.()
unsub = null
}

effect((onCleanup) => {
const currentCollection = collection()

Expand All @@ -245,12 +238,9 @@ export function injectLiveQuery(opts: any) {
status.set(`disabled` as const)
state.set(new Map())
internalData.set([])
cleanup()
return
}

cleanup()

// Initialize immediately with current state
syncDataFromCollection(currentCollection)

Expand All @@ -267,18 +257,17 @@ export function injectLiveQuery(opts: any) {
syncDataFromCollection(currentCollection)
},
)
unsub = subscription.unsubscribe.bind(subscription)

// Handle ready state
currentCollection.onFirstReady(() => {
status.set(currentCollection.status)
})

onCleanup(cleanup)
onCleanup(() => {
subscription.unsubscribe()
})
})

destroyRef.onDestroy(cleanup)

return {
state,
data,
Expand Down
66 changes: 59 additions & 7 deletions packages/angular-db/tests/inject-live-query.test.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,15 @@
import { DestroyRef, inject, signal } from '@angular/core'
import {
ApplicationRef,
ChangeDetectionStrategy,
Component,
DestroyRef,
inject,
input,
inputBinding,
signal,
} from '@angular/core'
import { TestBed } from '@angular/core/testing'
import { render } from '@testing-library/angular'
import { describe, expect, it } from 'vitest'
import {
createCollection,
Expand Down Expand Up @@ -56,12 +66,10 @@ const initialPersons: Array<Person> = [
},
]

// Helper function to wait for Angular effects and collection updates
/** Waits until the app has no pending tasks (effects, CD, zone-patched timers). */
async function waitForAngularUpdate() {
// Wait for Angular change detection
await new Promise((resolve) => setTimeout(resolve, 0))
// Additional delay for collection updates
await new Promise((resolve) => setTimeout(resolve, 50))
const appRef = TestBed.inject(ApplicationRef)
await appRef.whenStable()
}

function createMockCollection<T extends object, K extends string | number>(
Expand Down Expand Up @@ -173,6 +181,50 @@ describe(`injectLiveQuery`, () => {
)
})

it(`uses reactive params driven by a required signal input`, async () => {
const personsCollection = createCollection(
mockSyncCollectionOptions<Person>({
id: `test-persons-signal-input`,
getKey: (person: Person) => person.id,
initialData: initialPersons,
}),
)

@Component({
template: `<span>{{ live.data().length }}</span>`,
standalone: true,
changeDetection: ChangeDetectionStrategy.OnPush,
})
class LiveQueryFromInputCmp {
minAge = input.required<number>()
live = injectLiveQuery({
params: () => ({ minAge: this.minAge() }),
query: ({ params, q }) =>
q
.from({ persons: personsCollection })
.where(({ persons }) => gt(persons.age, params.minAge))
.select(({ persons }) => ({
id: persons.id,
name: persons.name,
age: persons.age,
})),
})
}

const minAge = signal(30)
const rendered = await render(LiveQueryFromInputCmp, {
bindings: [inputBinding(`minAge`, minAge.asReadonly())],
})

expect(rendered.fixture.nativeElement.textContent).toContain(`1`)

minAge.set(24)
rendered.fixture.detectChanges()
await waitForAngularUpdate()

expect(rendered.fixture.nativeElement.textContent).toContain(`3`)
})

it(`should work with basic collection and select`, async () => {
await TestBed.runInInjectionContext(async () => {
const collection = createCollection(
Expand Down Expand Up @@ -496,7 +548,7 @@ describe(`injectLiveQuery`, () => {

expect(res.state().get(2)).toEqual({ id: 2, name: `B` })

destroyRef.onDestroy(() => {})
destroyRef.onDestroy(() => { })
})

await TestBed.runInInjectionContext(async () => {
Expand Down
16 changes: 5 additions & 11 deletions packages/angular-db/tests/test-setup.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import 'zone.js'
import 'zone.js/testing'
import { getTestBed } from '@angular/core/testing'
import {
BrowserDynamicTestingModule,
platformBrowserDynamicTesting,
} from '@angular/platform-browser-dynamic/testing'
import '@testing-library/jest-dom/vitest'
import '@angular/compiler'
import '@analogjs/vitest-angular/setup-snapshots'
import { setupTestBed } from '@analogjs/vitest-angular/setup-testbed'

getTestBed().initTestEnvironment(
BrowserDynamicTestingModule,
platformBrowserDynamicTesting(),
)
setupTestBed()
2 changes: 1 addition & 1 deletion packages/angular-db/tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,6 @@
"@tanstack/db-ivm": ["../db-ivm/src"]
}
},
"include": ["src/**/*", "tests", "vite.config.ts"],
"include": ["src/**/*", "tests", "vite.config.ts", "vitest.config.ts"],
"exclude": ["node_modules", "dist"]
}
10 changes: 10 additions & 0 deletions packages/angular-db/tsconfig.spec.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"extends": "./tsconfig.json",
"compilerOptions": {
"noEmit": false,
"target": "ES2022",
"types": ["vitest/globals", "node"]
},
"files": ["tests/test-setup.ts"],
"include": ["tests/**/*.ts"]
}
22 changes: 3 additions & 19 deletions packages/angular-db/vite.config.ts
Original file line number Diff line number Diff line change
@@ -1,22 +1,6 @@
import { defineConfig, mergeConfig } from 'vitest/config'
import { tanstackViteConfig } from '@tanstack/vite-config'
import packageJson from './package.json'

const config = defineConfig({
test: {
name: packageJson.name,
dir: `./tests`,
environment: `jsdom`,
setupFiles: [`./tests/test-setup.ts`],
coverage: { enabled: true, provider: `istanbul`, include: [`src/**/*`] },
typecheck: { enabled: true },
},
export default tanstackViteConfig({
entry: `./src/index.ts`,
srcDir: `./src`,
})

export default mergeConfig(
config,
tanstackViteConfig({
entry: `./src/index.ts`,
srcDir: `./src`,
}),
)
30 changes: 30 additions & 0 deletions packages/angular-db/vitest.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import angular from '@analogjs/vite-plugin-angular'
import { defineConfig, mergeConfig } from 'vitest/config'
import { tanstackViteConfig } from '@tanstack/vite-config'
import packageJson from './package.json'

export default mergeConfig(
defineConfig({
esbuild: {
target: 'es2022',
},
plugins: [
angular({
tsconfig: './tsconfig.spec.json',
jit: false,
}),
],
test: {
name: packageJson.name,
dir: './tests',
environment: 'jsdom',
setupFiles: ['./tests/test-setup.ts'],
coverage: { enabled: true, provider: 'istanbul', include: ['src/**/*'] },
typecheck: { enabled: true },
},
}),
tanstackViteConfig({
entry: `./src/index.ts`,
srcDir: `./src`,
}),
)
Loading