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/brown-ways-compare.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
"@tanstack-query-firebase/angular": patch
---

Fix issue where signal updates weren't getting picked up
2 changes: 1 addition & 1 deletion dataconnect-sdk/js/default-connector/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,6 @@
"./package.json": "./package.json"
},
"peerDependencies": {
"firebase": "^10.14.0 || ^11.3.0"
"firebase": "^10.14.0 || ^11.3.0 || ^12.0.0"
}
}
6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,10 @@
"build": "turbo build"
},
"devDependencies": {
"@angular/core": "^19.1.8",
"@angular/core": "^20.0.0",
"@biomejs/biome": "2.1.1",
"@changesets/cli": "^2.29.4",
"@tanstack/angular-query-experimental": "5.66.4",
"@tanstack/angular-query-experimental": "^5.66.4",
"@tanstack/react-query": "^5.55.4",
"@types/jsonwebtoken": "^9.0.7",
"@vitest/coverage-istanbul": "^2.0.5",
Expand All @@ -33,6 +33,6 @@
"vitest": "^2.0.5"
},
"dependencies": {
"@angular/fire": "^19.0.0"
"@angular/fire": "^20.0.0"
}
}
14 changes: 6 additions & 8 deletions packages/angular/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,17 +36,15 @@
"license": "Apache-2.0",
"devDependencies": {
"@dataconnect/default-connector": "file:../../dataconnect-sdk/js/default-connector",
"@analogjs/vite-plugin-angular": "^1.13.0",
"@angular/animations": "^19.0.0",
"@testing-library/angular": "^17.3.5",
"@testing-library/angular": "^18.0.0",
"@testing-library/dom": "^10.4.0",
"tsup": "^8.4.0"
},
"peerDependencies": {
"@tanstack/angular-query-experimental": "5.66.4",
"@angular/core": "^19.0.0",
"@angular/fire": "^19.0.0",
"@angular/common": "^19.0.0",
"@angular/platform-browser-dynamic": "^19.0.0"
"@angular/common": "^20.0.0 || ^19.0.0",
"@angular/core": "^20.0.0 || ^19.0.0",
"@angular/fire": "^20.0.0 || ^19.0.0",
"@angular/platform-browser-dynamic": "^20.0.0 || ^19.0.0",
"@tanstack/angular-query-experimental": "^5.66.4"
}
}
55 changes: 29 additions & 26 deletions packages/angular/src/data-connect/index.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import {
computed,
EnvironmentInjector,
type Injector,
inject,
Expand Down Expand Up @@ -60,36 +61,38 @@ export function injectDataConnectQuery<Data, Variables>(
Partial<QueryResult<Data, Variables>> | undefined
>(undefined);
const finalInjector = injector || inject(EnvironmentInjector);
const queryKey = signal<QueryKey>([]);

function fdcOptionsFn() {
const passedInOptions =
typeof queryRefOrOptionsFn === "function"
? queryRefOrOptionsFn()
: undefined;

const modifiedFn = async (): Promise<Data> => {
const ref: QueryRef<Data, Variables> =
passedInOptions?.queryFn() ||
(queryRefOrOptionsFn as QueryRef<Data, Variables>);
dataConnectResult.set({ ref });
// @ts-expect-error function is hidden under `DataConnect`.
ref.dataConnect._setCallerSdkType(_callerSdkType);
queryKey.set([ref.name, ref.variables]);
const response = await executeQuery(ref);
dataConnectResult.set(response);
return response.data;
};
const derivedOptions = computed(() => {
if (typeof queryRefOrOptionsFn === "function") {
const options = queryRefOrOptionsFn();
const queryRef = options.queryFn();
return { options, queryRef };
}
return {
queryKey: queryKey(),
...passedInOptions,
queryFn: modifiedFn,
options: undefined,
queryRef: queryRefOrOptionsFn as QueryRef<Data, Variables>,
};
}
});
const queryRefSignal = computed(() => derivedOptions().queryRef);
const optionsSignal = computed(() => derivedOptions().options);
const varsSignal = computed(() => derivedOptions().queryRef.variables);

const originalResult = injectQuery(fdcOptionsFn, finalInjector);
async function queryFn() {
const queryRef = queryRefSignal();
// @ts-expect-error function is hidden under `DataConnect`.
queryRef.dataConnect._setCallerSdkType(_callerSdkType);
const response = await executeQuery(queryRef);
dataConnectResult.set(response);
return response.data;
}
const injectQueryResult = injectQuery(() => {
return {
queryKey: [queryRefSignal().name, varsSignal()],
...optionsSignal(),
queryFn: queryFn,
};
}, finalInjector);
return {
...originalResult,
...injectQueryResult,
dataConnectResult,
};
}
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { provideHttpClient } from "@angular/common/http";
import { provideExperimentalZonelessChangeDetection } from "@angular/core";
import { provideZonelessChangeDetection } from "@angular/core";
import { TestBed } from "@angular/core/testing";
import { initializeApp, provideFirebaseApp } from "@angular/fire/app";
import {
Expand Down Expand Up @@ -44,7 +44,7 @@ describe("injectDataConnectMutation", () => {
invalidateQueriesSpy = vi.spyOn(queryClient, "invalidateQueries");
TestBed.configureTestingModule({
providers: [
provideExperimentalZonelessChangeDetection(), // Required as angularfire's ZoneScheduler breaks tests.
provideZonelessChangeDetection(), // Required as angularfire's ZoneScheduler breaks tests.
provideFirebaseApp(() => initializeApp({ projectId: "p" })),
provideDataConnect(() => {
const dc = getDataConnect(connectorConfig);
Expand Down
39 changes: 34 additions & 5 deletions packages/angular/src/data-connect/injectDataConnectQuery.test.ts
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
import { provideHttpClient } from "@angular/common/http";
import {
inject,
provideExperimentalZonelessChangeDetection,
} from "@angular/core";
import { inject, provideZonelessChangeDetection, signal } from "@angular/core";
import { TestBed } from "@angular/core/testing";
import { initializeApp, provideFirebaseApp } from "@angular/fire/app";
import {
Expand Down Expand Up @@ -35,7 +32,7 @@ describe("injectDataConnectQuery", () => {
queryClient.clear();
TestBed.configureTestingModule({
providers: [
provideExperimentalZonelessChangeDetection(), // Required as angularfire's ZoneScheduler breaks tests.
provideZonelessChangeDetection(), // Required as angularfire's ZoneScheduler breaks tests.
provideFirebaseApp(() => initializeApp({ projectId: "p" })),
provideDataConnect(() => {
const dc = getDataConnect(connectorConfig);
Expand Down Expand Up @@ -243,4 +240,36 @@ describe("injectDataConnectQuery", () => {
// // })
// expect(r).toBeDefined();
});
test("signal updates are received", async () => {
const movieData = {
title: "tanstack query firebase",
genre: "library",
imageUrl: "https://invertase.io/",
};
const createdMovie = await createMovie(movieData);

const movieId = createdMovie?.data?.movie_insert?.id;
const movieIdSignal = signal("");

const result = TestBed.runInInjectionContext(() =>
injectDataConnectQuery(() => ({
queryFn: () => getMovieByIdRef({ id: movieIdSignal() }),
retry: false,
})),
);

expect(result.isPending()).toBe(true);

await waitFor(() => expect(result.isPending()).toBe(false));
expect(result.isSuccess()).to.be.false;
expect(result.data()).toBeUndefined();
expect(result.error()).toBeDefined();

movieIdSignal.set(movieId);
await waitFor(() => expect(result.isSuccess()).toBe(true));
expect(result.data()!.movie).to.deep.equal({
id: movieId,
...movieData,
});
});
});
Loading