diff --git a/docs.json b/docs.json index 43f4d40e..35baeb36 100644 --- a/docs.json +++ b/docs.json @@ -15,6 +15,11 @@ "id": "react", "title": "React", "href": "/react" + }, + { + "id": "angular", + "title": "Angular", + "href": "/angular" } ], "sidebar": [ @@ -42,6 +47,37 @@ } ] }, + { + "tab": "angular", + "group": "Data Connect", + "pages": [ + { + "title": "Getting Started", + "href": "/angular/data-connect" + }, + { + "title": "Querying", + "href": "/angular/data-connect/querying" + }, + { + "title": "Mutations", + "href": "/angular/data-connect/mutations" + }, + { + "group": "Functions", + "pages": [ + { + "title": "injectDataConnectQuery", + "href": "/angular/data-connect/functions/injectDataConnectQuery" + }, + { + "title": "injectDataConnectMutation", + "href": "/angular/data-connect/functions/injectDataConnectMutation" + } + ] + } + ] + }, { "tab": "react", "group": "Authentication", diff --git a/docs/angular/data-connect/functions/injectDataConnectMutation.mdx b/docs/angular/data-connect/functions/injectDataConnectMutation.mdx new file mode 100644 index 00000000..1cec4089 --- /dev/null +++ b/docs/angular/data-connect/functions/injectDataConnectMutation.mdx @@ -0,0 +1,42 @@ +--- +title: injectDataConnectMutation +--- + +`injectDataConnectMutation` is an injector designed to simplify handling mutations (creating, updating, deleting) with Firebase Data Connect. + +See [mutations](/angular/data-connect/mutations) for more information. + +## Features + +- Simplifies mutation handling for create, update, and delete operations using Firebase Data Connect. +- Provides type-safe handling of mutations based on your Firebase Data Connect schema. +- Automatically manages pending, success, and error states for mutations. +- Supports optimistic updates and caching to improve user experience and performance. + +## Usage + +```ts +import { injectDataConnectMutation } from "@tanstack-query-firebase/angular/data-connect"; +import { createMovieRef } from "@your-package-name/your-connector"; + +class AddMovieComponent { + createMovie = injectDataConnectMutation( + createMovieRef + ); + addMovie() { + createMovie.mutate({ + title: 'John Wick', + genre: "Action", + imageUrl: "https://example.com/image.jpg", + }); + } + return ( + + ); +} +``` diff --git a/docs/angular/data-connect/functions/injectDataConnectQuery.mdx b/docs/angular/data-connect/functions/injectDataConnectQuery.mdx new file mode 100644 index 00000000..10b5b463 --- /dev/null +++ b/docs/angular/data-connect/functions/injectDataConnectQuery.mdx @@ -0,0 +1,43 @@ +--- +title: injectDataConnectQuery +--- + +`injectDataConnectQuery` is an injector designed to simplify data fetching and state management with Firebase Data Connect. + +See [querying](/angular/data-connect/querying) for more information. + +## Features + +- Provides type-safe handling of queries based on the Firebase Data Connect schema. +- Simplifies data fetching using Firebase Data Connect. +- Automatically manages loading, success, and error states. +- Supports refetching data with integrated caching. + +## Usage + +```ts +import { injectDataConnectQuery } from '@tanstack-query-firebase/angular/data-connect'; +import { listMoviesRef } from "@your-package-name/your-connector"; + +// class +export class MovieListComponent { + movies = injectDataConnectQuery(listMoviesRef()); +} + +// template +@if (movies.isPending()) { + Loading... +} +@if (movies.error()) { + An error has occurred: {{ movies.error() }} +} +@if (movies.data(); as data) { + @for (movie of data.movies; track movie.id) { + + {{movie.description}} + + } @empty { +

No items!

+ } +} +``` diff --git a/docs/angular/data-connect/index.mdx b/docs/angular/data-connect/index.mdx new file mode 100644 index 00000000..78554b9e --- /dev/null +++ b/docs/angular/data-connect/index.mdx @@ -0,0 +1,117 @@ +--- +title: Firebase Data Connect +--- + +Firebase Data Connect is a relational database service for mobile and web apps that lets you build and scale using a fully-managed PostgreSQL database powered by Cloud SQL. It provides secure schema, query and mutation management using GraphQL technology that integrates well with Firebase Authentication. + +To get started, ensure you have setup your Firebase project and have the Data Connect setup in your project. To learn more, +follow the [Firebase Data Connect documentation](https://firebase.google.com/docs/data-connect/quickstart). + +## Setup + +Before using the Tanstack Query Firebase injectors for Data Connect, ensure you have configured your application using your chosen connector: + +```ts +// app.config.ts +export const appConfig: ApplicationConfig = { + providers: [ + ... + provideFirebaseApp(() => + initializeApp(/*Replace with your firebase config*/) + ), + provideDataConnect(() => getDataConnect(connectorConfig)), + provideTanStackQuery(new QueryClient()), + ], +}; +``` + +## Importing + +The package exports are available via the `@tanstack-query-firebase/angular` package under the `data-connect` namespace: + +```ts +import { injectDataConnectQuery } from "@tanstack-query-firebase/angular/data-connect"; +``` + +## Basic Usage + +To use the Tanstack Query Firebase injectors, you can either use the generated SDKs, or the `injectDataConnectQuery` injector to fetch data from the database: + +### Using the Generated SDK + +The generated SDK reduces the boilerplate required to use Tanstack Query Firebase's injectors. Instead of having to provide a ref to `injectDataConnectQuery`, you simply need to call the generated +injector function like so: + +```ts +import { injectListMyPosts } from '@firebasegen/posts/angular' + +@Component({ + ... + template: ` + @if (posts.isPending()) { + Loading... + } + @if (posts.error()) { + An error has occurred: {{ posts.error() }} + } + @if (posts.data(); as data) { + @for (post of data.posts; track post.id) { + + {{post.description}} + + } @empty { +

No items!

+ } + } + `, +}) +export class PostListComponent { + // Calls `injectDataConnectQuery` with the corresponding types. + posts = injectListMyPosts(); +} +``` + +### Using `injectDataConnectQuery` + +Alternatively, you can use the `injectDataConnectQuery` injector. To use this, you need to pass the Response and Data generics: + +```ts +import { injectDataConnectQuery } from "@tanstack-query-firebase/angular"; +import { listMoviesRef } from "@firebasegen/posts"; + +@Component({ + ... + template: ` + @if (posts.isPending()) { + Loading... + } + @if (posts.error()) { + An error has occurred: {{ posts.error() }} + } + @if (posts.data(); as data) { + @for (post of data.posts; track post.id) { + + {{post.description}} + + } @empty { +

No items!

+ } + } + `, +}) +export class PostListComponent { + // Calls `injectDataConnectQuery` with the corresponding types. + // Alternatively: + // injectDataConnectQuery(queryRef(dc, 'ListMovies')) + posts = injectDataConnectQuery(listMoviesRef()); +} +``` + +The injectors will automatically infer the data type from the connector and the query and automtically create a [query key](https://tanstack.com/query/latest/docs/framework/angular/guides/query-keys) for the query. + +## Learning more + +To learn more about the Data Connect functions, check out the following pages: + +- [Querying](/angular/data-connect/querying) +- [Mutations](/angular/data-connect/mutations) diff --git a/docs/angular/data-connect/mutations.mdx b/docs/angular/data-connect/mutations.mdx new file mode 100644 index 00000000..2daacb52 --- /dev/null +++ b/docs/angular/data-connect/mutations.mdx @@ -0,0 +1,84 @@ +--- +title: Mutations +description: Learn how to mutate data in Firebase Data Connect using the Tanstack Query Firebase injectors. +--- + +## Mutating Data + +To mutate data in Firebase Data Connect, you can either use the generated injectors, or use the `injectDataConnectMutation` injector. + +```ts +import { injectCreateMovie } from "@firebasegen/movies/angular"; + +@Component({ + ... + template: ` + + ` +}) +class AddMovieComponent() { + // Calls `injectDataConnectMutation` with the respective types. + // Alternatively: + // import { injectDataConnectMutation } from '@tanstack-query-firebase/angular/data-connect'; + // ... + // createMovie = injectDataConnectMutation(createMovieRef); + createMovie = injectCreateMovie(); + addMovie() { + createMovie.mutate({ + title: 'John Wick', + genre: "Action", + imageUrl: "https://example.com/image.jpg", + }); + } +} +``` + +Additionally, you can provide a factory function to the mutation, which will be called with the mutation variables: + +```ts +createMovie = injectDataConnectMutation(undefined, () => ({ + mutationFn: (title: string) => createMovieRef({ title, reviewDate: Date.now() }) +})); + +// ... +createMovie.mutate("John Wick"); +``` + +## Invalidating Queries + +The function provides an additional [mutation option](https://tanstack.com/query/latest/docs/framework/angular/reference/functions/injectMutation) called `invalidate`. This option accepts a list of query references which will be automatically invalidated when the mutation is successful. + +You can also provide explicit references to the invalidate array, for example: + +```ts +const createMovie = injectDataConnectMutation(createMovieRef, { + invalidate: [getMovieRef({ id: "1" })], +}); +``` + +In this case only the query reference `getMovieRef({ id: "1" })` will be invalidated. + +## Overriding the mutation key + +### Metadata + +Along with the data, the function will also return the `ref`, `source`, and `fetchTime` metadata from the mutation. + +```ts +const createMovie = injectDataConnectMutation(createMovieRef); + +await createMovie.mutateAsync({ + title: 'John Wick', + genre: "Action", + imageUrl: "https://example.com/image.jpg", +}); + +console.log(createMovie.dataConnectResult().ref); +console.log(createMovie.dataConnectResult().source); +console.log(createMovie.dataConnectResult().fetchTime); +``` diff --git a/docs/angular/data-connect/querying.mdx b/docs/angular/data-connect/querying.mdx new file mode 100644 index 00000000..e46eb562 --- /dev/null +++ b/docs/angular/data-connect/querying.mdx @@ -0,0 +1,81 @@ +--- +title: Querying +description: Learn how to query data from Firebase Data Connect using the Tanstack Query Firebase injectors. +--- + +## Querying Data + +To query data from Firebase Data Connect, you can either use the generated injectors, or the `injectDataConnect` injector. This will automatically create a query key and infer the data type and variables associated with the query. + +```ts +import { injectListMyPosts } from '@firebasegen/posts/angular' + +@Component({ + ... + template: ` + @if (movies.isPending()) { + Loading... + } + @if (movies.error()) { + An error has occurred: {{ movies.error() }} + } + @if (movies.data(); as data) { + @for (movie of data.movies; track movie.id) { + + {{movie.description}} + + } @empty { +

No items!

+ } + } + `, +}) +export class PostListComponent { + // Calls `injectDataConnectQuery` with the respective types. + // Alternatively: + // import { injectDataConnectQuery } from '@tanstack-query-firebase/angular/data-connect'; + // ... + // injectDataConnectQuery(listMoviesRef()) + movies = injectListMovies(); +} +``` + +### Query Options + +To leverage the full power of Tanstack Query, you can pass in query options to the `injectDataConnectQuery` injector, for example to refetch the query on a interval: + +```ts +movies = injectListMovies( + { + refetchInterval: 1000, + } +); +``` +The injector extends the [`injectQuery`](https://tanstack.com/query/latest/docs/framework/angular/reference/functions/injectquery) injector, so you can learn more about the available options by reading the [Tanstack Query documentation](https://tanstack.com/query/latest/docs/framework/angular/reference/functions/injectquery). + +### Overriding the query key + +To override the query key, you can pass in a custom query key to the `injectDataConnectQuery` injector: + +```ts +movies = injectListMovies( + listMoviesRef(), + { + queryKey: ['movies', '1'] + } +); +``` +Note that overriding the query key could mean your query is no longer synchronized with mutation invalidations or server side rendering pre-fetching. + +### Metadata + +Along with the data, the injector will also return the `ref`, `source`, and `fetchTime` metadata from the query. + +```ts +const movies = injectListMovies(); + +console.log(movies.dataConnectResult()?.ref); +console.log(movies.dataConnectResult()?.source); +console.log(movies.dataConnectResult()?.fetchTime); +``` + diff --git a/docs/angular/index.mdx b/docs/angular/index.mdx new file mode 100644 index 00000000..d9e7554e --- /dev/null +++ b/docs/angular/index.mdx @@ -0,0 +1,90 @@ +--- +title: Angular +description: Using TanStack Query Firebase with Angular +--- + +To get started using TanStack Query Firebase with Angular, you will need to install the following packages: + +```bash +npm i --save firebase @tanstack/angular-query-experimental @tanstack-query-firebase/angular +``` + +Both `@angular/fire` and `@tanstack/angular-query-experimental` are peer dependencies of `@tanstack-query-firebase/angular`. + +## Usage + +TanStack Query Firebase provides a hands-off approach to integrate with TanStack Query - you are +still responsible for both setting up Firebase in your application and configuring TanStack Query. + +If you haven't already done so, [initialize your Firebase project](https://firebase.google.com/docs/web/setup) +and [configure TanStack Query](https://tanstack.com/query/latest/docs/framework/angular/quick-start): + +### Automatic Setup +To automatically set up AngularFire, just run: +```shell +ng add @angular/fire +``` + +### Manual Setup + +```ts +// app.config.ts +import { initializeApp, provideFirebaseApp } from '@angular/fire/app'; +import { getDataConnect, provideDataConnect } from '@angular/fire/data-connect'; +import { connectorConfig } from '@firebasegen/movies'; +import { provideTanStackQuery, QueryClient } from '@tanstack/angular-query-experimental'; + + +export const appConfig: ApplicationConfig = { + providers: [ + ... + provideFirebaseApp(() => + initializeApp(/*Replace with your firebase config*/) + ), + provideDataConnect(() => getDataConnect(connectorConfig)), + provideTanStackQuery(new QueryClient()), + ], +}; +``` + +And be sure to add `angular: true` to your `connector.yaml`: + +```yaml +generate: + javascriptSdk: + angular: true + outputDir: "../movies-generated" + package: "@movie-app/movies" + packageJsonDir: "../../" +``` + +## Example Usage + +Next, you can start to use injectors provided by `@tanstack-query-firebase/angular`. For example, to +fetch a query from Data Connect: + +```ts +import { injectListMovies } from '@firebasegen/movies/angular' + +// class +export class MovieListComponent { + movies = injectListMovies(); +} + +// template +@if (movies.isPending()) { + Loading... +} +@if (movies.error()) { + An error has occurred: {{ movies.error() }} +} +@if (movies.data(); as data) { + @for (movie of data.movies; track movie.id) { + + {{movie.description}} + + } @empty { +

No items!

+ } +} +``` diff --git a/docs/react/data-connect/querying.mdx b/docs/react/data-connect/querying.mdx index 52a7eccd..6f9faa55 100644 --- a/docs/react/data-connect/querying.mdx +++ b/docs/react/data-connect/querying.mdx @@ -5,7 +5,7 @@ description: Learn how to query data from Firebase Data Connect using the Tansta ## Querying Data -To query data from Firebase Data Connect, you can use the `useDataConnectQuery` hook. This hook will automatically infer the data type from the connector and the query and automtically create a [query key](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) for the query. +To query data from Firebase Data Connect, you can use the `useDataConnectQuery` hook. This hook will automatically infer the data type from the connector and the query and automatically create a [query key](https://tanstack.com/query/latest/docs/framework/react/guides/query-keys) for the query. ```tsx import { useDataConnectQuery } from "@tanstack-query-firebase/react/data-connect";