Skip to content

Commit 4352bab

Browse files
authored
Merge pull request #227 from maneesht/mtewani/fix-signals
Fix issue where signal updates weren't getting picked up for injectDataConnect functions
2 parents 547d5b1 + 692ec8a commit 4352bab

File tree

8 files changed

+1378
-1800
lines changed

8 files changed

+1378
-1800
lines changed

.changeset/brown-ways-compare.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
---
2+
"@tanstack-query-firebase/angular": patch
3+
---
4+
5+
Fix issue where signal updates weren't getting picked up

dataconnect-sdk/js/default-connector/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,6 @@
2020
"./package.json": "./package.json"
2121
},
2222
"peerDependencies": {
23-
"firebase": "^10.14.0 || ^11.3.0"
23+
"firebase": "^10.14.0 || ^11.3.0 || ^12.0.0"
2424
}
2525
}

package.json

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -16,10 +16,10 @@
1616
"build": "turbo build"
1717
},
1818
"devDependencies": {
19-
"@angular/core": "^19.1.8",
19+
"@angular/core": "^20.0.0",
2020
"@biomejs/biome": "2.1.1",
2121
"@changesets/cli": "^2.29.4",
22-
"@tanstack/angular-query-experimental": "5.66.4",
22+
"@tanstack/angular-query-experimental": "^5.66.4",
2323
"@tanstack/react-query": "^5.55.4",
2424
"@types/jsonwebtoken": "^9.0.7",
2525
"@vitest/coverage-istanbul": "^2.0.5",
@@ -33,6 +33,6 @@
3333
"vitest": "^2.0.5"
3434
},
3535
"dependencies": {
36-
"@angular/fire": "^19.0.0"
36+
"@angular/fire": "^20.0.0"
3737
}
3838
}

packages/angular/package.json

Lines changed: 6 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -36,17 +36,15 @@
3636
"license": "Apache-2.0",
3737
"devDependencies": {
3838
"@dataconnect/default-connector": "file:../../dataconnect-sdk/js/default-connector",
39-
"@analogjs/vite-plugin-angular": "^1.13.0",
40-
"@angular/animations": "^19.0.0",
41-
"@testing-library/angular": "^17.3.5",
39+
"@testing-library/angular": "^18.0.0",
4240
"@testing-library/dom": "^10.4.0",
4341
"tsup": "^8.4.0"
4442
},
4543
"peerDependencies": {
46-
"@tanstack/angular-query-experimental": "5.66.4",
47-
"@angular/core": "^19.0.0",
48-
"@angular/fire": "^19.0.0",
49-
"@angular/common": "^19.0.0",
50-
"@angular/platform-browser-dynamic": "^19.0.0"
44+
"@angular/common": "^20.0.0 || ^19.0.0",
45+
"@angular/core": "^20.0.0 || ^19.0.0",
46+
"@angular/fire": "^20.0.0 || ^19.0.0",
47+
"@angular/platform-browser-dynamic": "^20.0.0 || ^19.0.0",
48+
"@tanstack/angular-query-experimental": "^5.66.4"
5149
}
5250
}

packages/angular/src/data-connect/index.ts

Lines changed: 29 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import {
2+
computed,
23
EnvironmentInjector,
34
type Injector,
45
inject,
@@ -60,36 +61,38 @@ export function injectDataConnectQuery<Data, Variables>(
6061
Partial<QueryResult<Data, Variables>> | undefined
6162
>(undefined);
6263
const finalInjector = injector || inject(EnvironmentInjector);
63-
const queryKey = signal<QueryKey>([]);
64-
65-
function fdcOptionsFn() {
66-
const passedInOptions =
67-
typeof queryRefOrOptionsFn === "function"
68-
? queryRefOrOptionsFn()
69-
: undefined;
70-
71-
const modifiedFn = async (): Promise<Data> => {
72-
const ref: QueryRef<Data, Variables> =
73-
passedInOptions?.queryFn() ||
74-
(queryRefOrOptionsFn as QueryRef<Data, Variables>);
75-
dataConnectResult.set({ ref });
76-
// @ts-expect-error function is hidden under `DataConnect`.
77-
ref.dataConnect._setCallerSdkType(_callerSdkType);
78-
queryKey.set([ref.name, ref.variables]);
79-
const response = await executeQuery(ref);
80-
dataConnectResult.set(response);
81-
return response.data;
82-
};
64+
const derivedOptions = computed(() => {
65+
if (typeof queryRefOrOptionsFn === "function") {
66+
const options = queryRefOrOptionsFn();
67+
const queryRef = options.queryFn();
68+
return { options, queryRef };
69+
}
8370
return {
84-
queryKey: queryKey(),
85-
...passedInOptions,
86-
queryFn: modifiedFn,
71+
options: undefined,
72+
queryRef: queryRefOrOptionsFn as QueryRef<Data, Variables>,
8773
};
88-
}
74+
});
75+
const queryRefSignal = computed(() => derivedOptions().queryRef);
76+
const optionsSignal = computed(() => derivedOptions().options);
77+
const varsSignal = computed(() => derivedOptions().queryRef.variables);
8978

90-
const originalResult = injectQuery(fdcOptionsFn, finalInjector);
79+
async function queryFn() {
80+
const queryRef = queryRefSignal();
81+
// @ts-expect-error function is hidden under `DataConnect`.
82+
queryRef.dataConnect._setCallerSdkType(_callerSdkType);
83+
const response = await executeQuery(queryRef);
84+
dataConnectResult.set(response);
85+
return response.data;
86+
}
87+
const injectQueryResult = injectQuery(() => {
88+
return {
89+
queryKey: [queryRefSignal().name, varsSignal()],
90+
...optionsSignal(),
91+
queryFn: queryFn,
92+
};
93+
}, finalInjector);
9194
return {
92-
...originalResult,
95+
...injectQueryResult,
9396
dataConnectResult,
9497
};
9598
}

packages/angular/src/data-connect/injectDataConnectMutation.test.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
import { provideHttpClient } from "@angular/common/http";
2-
import { provideExperimentalZonelessChangeDetection } from "@angular/core";
2+
import { provideZonelessChangeDetection } from "@angular/core";
33
import { TestBed } from "@angular/core/testing";
44
import { initializeApp, provideFirebaseApp } from "@angular/fire/app";
55
import {
@@ -44,7 +44,7 @@ describe("injectDataConnectMutation", () => {
4444
invalidateQueriesSpy = vi.spyOn(queryClient, "invalidateQueries");
4545
TestBed.configureTestingModule({
4646
providers: [
47-
provideExperimentalZonelessChangeDetection(), // Required as angularfire's ZoneScheduler breaks tests.
47+
provideZonelessChangeDetection(), // Required as angularfire's ZoneScheduler breaks tests.
4848
provideFirebaseApp(() => initializeApp({ projectId: "p" })),
4949
provideDataConnect(() => {
5050
const dc = getDataConnect(connectorConfig);

packages/angular/src/data-connect/injectDataConnectQuery.test.ts

Lines changed: 34 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
import { provideHttpClient } from "@angular/common/http";
2-
import {
3-
inject,
4-
provideExperimentalZonelessChangeDetection,
5-
} from "@angular/core";
2+
import { inject, provideZonelessChangeDetection, signal } from "@angular/core";
63
import { TestBed } from "@angular/core/testing";
74
import { initializeApp, provideFirebaseApp } from "@angular/fire/app";
85
import {
@@ -35,7 +32,7 @@ describe("injectDataConnectQuery", () => {
3532
queryClient.clear();
3633
TestBed.configureTestingModule({
3734
providers: [
38-
provideExperimentalZonelessChangeDetection(), // Required as angularfire's ZoneScheduler breaks tests.
35+
provideZonelessChangeDetection(), // Required as angularfire's ZoneScheduler breaks tests.
3936
provideFirebaseApp(() => initializeApp({ projectId: "p" })),
4037
provideDataConnect(() => {
4138
const dc = getDataConnect(connectorConfig);
@@ -243,4 +240,36 @@ describe("injectDataConnectQuery", () => {
243240
// // })
244241
// expect(r).toBeDefined();
245242
});
243+
test("signal updates are received", async () => {
244+
const movieData = {
245+
title: "tanstack query firebase",
246+
genre: "library",
247+
imageUrl: "https://invertase.io/",
248+
};
249+
const createdMovie = await createMovie(movieData);
250+
251+
const movieId = createdMovie?.data?.movie_insert?.id;
252+
const movieIdSignal = signal("");
253+
254+
const result = TestBed.runInInjectionContext(() =>
255+
injectDataConnectQuery(() => ({
256+
queryFn: () => getMovieByIdRef({ id: movieIdSignal() }),
257+
retry: false,
258+
})),
259+
);
260+
261+
expect(result.isPending()).toBe(true);
262+
263+
await waitFor(() => expect(result.isPending()).toBe(false));
264+
expect(result.isSuccess()).to.be.false;
265+
expect(result.data()).toBeUndefined();
266+
expect(result.error()).toBeDefined();
267+
268+
movieIdSignal.set(movieId);
269+
await waitFor(() => expect(result.isSuccess()).toBe(true));
270+
expect(result.data()!.movie).to.deep.equal({
271+
id: movieId,
272+
...movieData,
273+
});
274+
});
246275
});

0 commit comments

Comments
 (0)