schema
The schema
creates a database instance from the given schema.
It accepts a function as the argument, where you define the database structure:
import { schema } from "typesaurus";
const db = schema(($) => ({ users: $.collection<User>().sub({ notes: $.collection<Note>(), }), books: $.collection<Book>(),}));
interface User { name: string;}
interface Note { text: string;}
interface Books { title: string;}
What you return from the function, defines the database structure.
Options
You can pass the options object as the second argument.
app
You can specify the app name in the options to make the web, server, or both to use the particular Firebase app:
schema( ($) => ({ // ... }), // Use app-name app at both client and server { app: "app-name" },);
schema( ($) => ({ // ... }), { // Use server-name app at server server: { app: "server-name" }, // Use client-name app at client client: { app: "client-name" }, },);
If not specified, it will use the default app name ([DEFAULT]
) assigned when calling initializeApp
without the name argument.
preferRest
You can make Admin SDK to use REST requests instead of gRPC where possible by setting the preferRest
option. It improves the cold-start times.
schema( ($) => ({ // ... }), // Prefer REST over gRPC where possible: { server: { preferRest: true } },);
$
helper
The argument function receives $
helper object as the first argument that provides the schema
API.
$
type is TypesaurusCore.SchemaHelpers
.
$.collection
The $.collection
function creates a collection with the given model. The key you assign the collection to, Typesaurus will use as the collection path:
import { schema } from "typesaurus";
const db = schema(($) => ({ // `users` is the the path, `User` is the model users: $.collection<User>(),}));
→ You can customize the path, see collection.name
Generics
Model
You always pass the model interface as the first generic param:
import { schema } from "typesaurus";
const db = schema(($) => ({ accounts: $.collection<Account>(),}));
interface Account { externalId: string; type: string;}
It defines the shape of the documents in the collection.
You can also use a variable model where document can be only one of the given types:
import { schema } from "typesaurus";
const db = schema(($) => ({ // Variable model accounts: $.collection<[GitHubAccount, MicrosoftAccount, GoogleAccount]>(),}));
interface GitHubAccount { type: "github"; userId: string;}
interface MicrosoftAccount { type: "microsoft"; accountId: string;}
interface GoogleAccount { type: "google"; email: string;}
It helps to simplify and secure operations on mixed document types.
→ Read more about variable models
CustomId
The second optional generic param allows to set id type to the collection, allowing accessing i.e., credentials
collection using accountId
and vice versa.
import { schema, Typesaurus } from "typesaurus";
const db = schema(($) => ({ accounts: $.collection<Account>(), credentials: $.collection<AccountCredentials, Typesaurus.Id<"accounts">>(), users: $.User(),}));
await db.credentials.update(accountId, { key: null });
You can also set a string
, enum or union as the id type, that allows you to specify set of allowed ids:
import { schema, Typesaurus } from "typesaurus";
const db = schema(($) => ({ stats: $.collection<Stats, "global" | "sg" | "us">(),}));
await db.stats.update("sg", ($) => ({ users: $.increment(1) }));
$.collection(...).sub
The sub
function creates a subcollection:
import { schema } from "typesaurus";
const db = schema(($) => ({ posts: $.collection<Post>().sub({ comments: $.collection<Comment>(), }),}));
The subcollection path will be posts/{postId}/comments
and the id will be Id<"posts/comments">
.
You can access a subcollection calling the partent collection with an id:
// Fetch all post commentsawait db.posts(postId).comments.all();
The subcollections can be nested as well:
// Fetch all post comment ratingsawait db.posts(postId).comments(commentId).ratings.all();
When you need to access a subcollection, i.e. to convert string to its id, you can use sub
property:
await db.posts.sub.comments.sub.ratings.id("rating-id");
$.collection(...).name
By default the collection has the same name as the key you assign it to. But you can customize it using name
property:
const db = schema(($) => ({ subscriptions: $.collection<Subscription>().name("billing"),}));
It will allow you to access collection via the alias subscription
while keeping the original name in the database:
// Will fetch "billing/{subscriptionId}" documentawait db.subscriptions.get(subscriptionId);
The name also affects the collection id type, so for our example it will be Id<"billing">
.