### Setup Firestore Emulator for Unit Tests Source: https://github.com/kossnocorp/typesaurus/blob/main/CONTRIBUTING.md Run this command once before executing unit tests to download the Firestore emulator. ```bash make test-setup ``` -------------------------------- ### Get Document by ID Source: https://context7.com/kossnocorp/typesaurus/llms.txt Retrieve single documents by ID using `get`. This example shows fetching as a promise and setting up real-time subscriptions. ```typescript import { schema } from 'typesaurus'; interface User { name: string; } const db = schema(($) => ({ users: $.collection(), })); // Get document as a promise const userId = db.users.id("user-123"); const user = await db.users.get(userId); if (user) { console.log(user.data.name); console.log(user.ref.id); } else { console.log("User not found"); } // Get with real-time subscription const off = db.users.get(userId).on((user) => { if (user) { console.log(`User updated: ${user.data.name}`); } }); // Unsubscribe when done off(); // Get via ref const userRef = db.users.ref(userId); const userFromRef = await userRef.get(); ``` -------------------------------- ### Create User and Post with References Source: https://context7.com/kossnocorp/typesaurus/llms.txt Example of creating a user and then a post, storing a reference to the user within the post document. Requires `User` and `Post` interfaces and a schema definition. ```typescript import { schema, Typesaurus } from 'typesaurus'; interface User { name: string; } interface Post { author: Typesaurus.Ref; title: string; } const db = schema(($) => ({ users: $.collection(), posts: $.collection(), })); // Create user and post with reference const userRef = await db.users.add({ name: "Sasha" }); const postRef = await db.posts.add({ author: userRef, // Store reference to user title: "Hello World", }); ``` -------------------------------- ### Install Typesaurus with Firebase Source: https://github.com/kossnocorp/typesaurus/blob/main/README.md Install Typesaurus along with the necessary Firebase packages for web or Node.js environments. Note that Firebase packages are not automatic dependencies. ```sh npm install --save typesaurus firebase firebase-admin ``` -------------------------------- ### Transfer Money Between Accounts with Transactions Source: https://context7.com/kossnocorp/typesaurus/llms.txt Use transactions for atomic read-then-write operations. This example demonstrates transferring funds between two accounts, ensuring data consistency. ```typescript import { schema, transaction, Typesaurus } from 'typesaurus'; interface Account { balance: number; } const db = schema(($) => ({ accounts: $.collection(), })); // Transfer money between accounts async function transfer( fromId: Typesaurus.Id<"accounts">, toId: Typesaurus.Id<"accounts">, amount: number ) { return transaction(db) .read(($) => [ $.db.accounts.get(fromId), $.db.accounts.get(toId), ]) .write(($) => { const [from, to] = $.result; if (!from || !to) { throw new Error("Account not found"); } if (from.data.balance < amount) { throw new Error("Insufficient funds"); } from.update({ balance: from.data.balance - amount }); to.update({ balance: to.data.balance + amount }); return { success: true }; }); } ``` -------------------------------- ### Add Document with Auto-Generated ID Source: https://context7.com/kossnocorp/typesaurus/llms.txt Use the `add` function to create a new document with an auto-generated ID. This example demonstrates adding a user with a server timestamp. ```typescript import { schema, Typesaurus } from 'typesaurus'; interface User { name: string; createdAt: Typesaurus.ServerDate; } const db = schema(($) => ({ users: $.collection(), })); // Add a document with server date using helper function const userRef = await db.users.add(($) => ({ name: "Sasha", createdAt: $.serverDate(), })); console.log(`Created user with ID: ${userRef.id}`); // Retrieve the created document const user = await userRef.get(); console.log(user?.data.name); // "Sasha" ``` -------------------------------- ### Getting All Documents in Typesaurus Source: https://context7.com/kossnocorp/typesaurus/llms.txt Retrieve all documents from a collection using the `all` method. This can be done as a one-time promise or as a real-time subscription to monitor changes. ```typescript import { schema } from 'typesaurus'; interface Book { title: string; author: string; } const db = schema(($) => ({ books: $.collection(), })); // Get all documents as promise const allBooks = await db.books.all(); console.log(allBooks.map((doc) => doc.data.title)); // Real-time subscription to all documents const off = db.books.all().on((docs, { changes, empty }) => { console.log(`Total books: ${docs.length}`); for (const change of changes()) { console.log(`${change.type}: ${change.doc.data.title}`); } }); // Unsubscribe off(); ``` -------------------------------- ### Firestore Security Rules for System Tests Source: https://github.com/kossnocorp/typesaurus/blob/main/CONTRIBUTING.md Example Firestore security rules to allow read and write operations for a specific authenticated user. This is optional and recommended only if your web API key is public. ```firestore rules_version = '2'; service cloud.firestore { match /databases/{database}/documents { match /{document=**} { allow read, write: if request.auth.uid == "xxx"; } } } ``` -------------------------------- ### Set Document with Merge Option in Typesaurus Source: https://github.com/kossnocorp/typesaurus/blob/main/CHANGELOG.md Demonstrates how to use the `set` function with the `merge: true` option to update a document, using current document values as defaults for unset fields. Ensure the `set` and `get` functions are imported. ```typescript await set(user.ref, { name: "Sasha", date: new Date(1987, 1, 11) }); await set(user.ref, { name: "Sasha" }, { merge: true }); await get(user.ref); //=> { data: { name: 'Sasha', date: new Date(1987, 1, 11) }, ... } ``` -------------------------------- ### Getting Multiple Documents by IDs in Typesaurus Source: https://context7.com/kossnocorp/typesaurus/llms.txt Fetch multiple documents from a collection by providing an array of their IDs using the `many` method. It returns an array where each element is either a document or null if the document was not found. ```typescript import { schema } from 'typesaurus'; interface User { name: string; } const db = schema(($) => ({ users: $.collection(), })); const ids = [ db.users.id("user-1"), db.users.id("user-2"), db.users.id("user-3"), ]; // Returns array with docs or null for missing documents const users = await db.users.many(ids); for (const user of users) { if (user) { console.log(user.data.name); } else { console.log("User not found"); } } ``` -------------------------------- ### Run Unit Tests Source: https://github.com/kossnocorp/typesaurus/blob/main/CONTRIBUTING.md Execute unit tests once or in watch mode. ```bash # Run tests once make test # Run tests in the watch mode make test-watch ``` -------------------------------- ### Run System Tests (Node.js and Browser) Source: https://github.com/kossnocorp/typesaurus/blob/main/CONTRIBUTING.md Execute system tests for both Node.js and browser environments. ```bash # Run tests both in Node.js and browser: make test-system # Run only Node.js tests: make test-system-node # Run Node.js tests in the watch mode make test-system-node-watch # Run only browser tests: make test-system-browser # Run browser tests in the watch mode make test-system-browser-watch ``` -------------------------------- ### Create Document Reference Manually Source: https://context7.com/kossnocorp/typesaurus/llms.txt Demonstrates creating a document reference directly using a known document ID, without needing to fetch the document first. ```typescript // Create reference without fetching const userId = db.users.id("user-123"); const manualRef = db.users.ref(userId); await db.posts.add({ author: manualRef, title: "Another Post", }); ``` -------------------------------- ### Run Concurrent Transactions Safely Source: https://context7.com/kossnocorp/typesaurus/llms.txt Demonstrates running multiple increment operations concurrently using `Promise.all` to ensure they are handled safely by the transaction system. ```typescript // Run concurrent transactions safely const accountId = db.accounts.id("counter"); await db.accounts.set(accountId, { balance: 0 }); const results = await Promise.all([ incrementCounter(accountId), incrementCounter(accountId), incrementCounter(accountId), ]); const final = await db.accounts.get(accountId); console.log(final?.data.balance); // 3 ``` -------------------------------- ### Use Derived Types in Functions Source: https://context7.com/kossnocorp/typesaurus/llms.txt Shows how to use schema-derived types like `Doc`, `Data`, `Id`, and `Ref` to strongly type function parameters and return values. ```typescript // Use derived types in functions function processUser(user: Schema["users"]["Doc"]) { console.log(user.data.name); console.log(user.ref.id); } function createUser(data: Schema["users"]["Data"]) { return db.users.add(data); } // Typed ID function getUserById(id: Schema["users"]["Id"]) { return db.users.get(id); } // Typed Ref function processRef(ref: Schema["users"]["Ref"]) { return ref.get(); } ``` -------------------------------- ### Add Event with Server Date Source: https://context7.com/kossnocorp/typesaurus/llms.txt Adds a new event document, setting the `createdAt` field to the current server timestamp using `$.serverDate()`. ```typescript import { schema, Typesaurus } from 'typesaurus'; interface Event { name: string; createdAt: Typesaurus.ServerDate; updatedAt?: Typesaurus.ServerDate; scheduledFor: Date; // Regular date for specific times } const db = schema(($) => ({ events: $.collection(), })); // Add with server date const eventRef = await db.events.add(($) => ({ name: "Conference", createdAt: $.serverDate(), scheduledFor: new Date("2024-06-15"), })); ``` -------------------------------- ### Retrieve and Expand Document Reference Source: https://context7.com/kossnocorp/typesaurus/llms.txt Fetches a post document and then uses the stored author reference to retrieve the full author document. The `author` field is a typed reference object. ```typescript // Retrieve and expand reference const post = await postRef.get(); if (post) { // The author field is a typed reference console.log(post.data.author.type); // "ref" console.log(post.data.author.id); // Fetch the referenced document const author = await post.data.author.get(); console.log(author?.data.name); // "Sasha" } ``` -------------------------------- ### Read Server Date as Date Object Source: https://context7.com/kossnocorp/typesaurus/llms.txt Shows that server dates are automatically converted to JavaScript `Date` objects when reading documents. ```typescript // Server dates are converted to Date objects when reading const event = await eventRef.get(); console.log(event?.data.createdAt instanceof Date); // true ``` -------------------------------- ### Querying Documents in Typesaurus Source: https://context7.com/kossnocorp/typesaurus/llms.txt Query collections using a fluent API that supports filters, ordering, limits, and pagination. Real-time subscriptions can be set up to listen for changes. ```typescript import { schema, Typesaurus } from 'typesaurus'; interface Contact { ownerId: string; name: string; age: number; birthday: Date; tags: string[]; } const db = schema(($) => ({ contacts: $.collection(), })); // Simple equality query const contacts = await db.contacts.query(($) => $.field("ownerId").eq("user-123") ); // Multiple conditions (AND) const adults = await db.contacts.query(($) => [ $.field("ownerId").eq("user-123"), $.field("age").gte(18), ]); // Query with ordering and limit const topContacts = await db.contacts.query(($) => [ $.field("ownerId").eq("user-123"), $.field("age").order("desc"), $.limit(10), ]); // Pagination with cursors const page1 = await db.contacts.query(($) => [ $.field("ownerId").eq("user-123"), $.field("age").order("asc", $.startAfter(undefined)), $.limit(20), ]); const lastDoc = page1[page1.length - 1]; const page2 = await db.contacts.query(($) => [ $.field("ownerId").eq("user-123"), $.field("age").order("asc", $.startAfter(lastDoc?.data.age)), $.limit(20), ]); // Array contains const withTag = await db.contacts.query(($) => [ $.field("tags").contains("vip"), ]); // Array contains any const withAnyTag = await db.contacts.query(($) => [ $.field("tags").containsAny(["vip", "premium"]), ]); // In query const specificAges = await db.contacts.query(($) => [ $.field("age").in([25, 30, 35]), ]); // OR query const orQuery = await db.contacts.query(($) => [ $.field("ownerId").eq("user-123"), $.or($.field("name").eq("Sasha"), $.field("name").eq("Tati")), ]); // Real-time subscription const off = db.contacts .query(($) => $.field("ownerId").eq("user-123")) .on((docs, { changes, empty }) => { console.log(`Got ${docs.length} contacts`); console.log(`Changes: ${changes().length}`); console.log(`Empty: ${empty}`); }); ``` -------------------------------- ### Define Database Schema Source: https://context7.com/kossnocorp/typesaurus/llms.txt Define your database schema using the `schema` function with typed collections and optional subcollections. Export schema types for application-wide use. ```typescript import { schema, Typesaurus } from 'typesaurus'; // Define your model interfaces interface User { name: string; email: string; createdAt: Typesaurus.ServerDate; } interface Post { author: Typesaurus.Ref; title: string; content: string; likes: number; tags: string[]; } interface Comment { author: Typesaurus.Ref; text: string; } // Create the database schema const db = schema(($) => ({ users: $.collection(), posts: $.collection().sub({ comments: $.collection(), }), })); // Export schema types for use across your application type Schema = Typesaurus.Schema; ``` -------------------------------- ### Infer Schema Types Source: https://context7.com/kossnocorp/typesaurus/llms.txt Demonstrates how to infer TypeScript types directly from your Typesaurus schema definition for use in functions. ```typescript import { schema, Typesaurus } from 'typesaurus'; interface User { name: string; age: number; } const db = schema(($) => ({ users: $.collection(), })); // Infer schema types type Schema = Typesaurus.Schema; ``` -------------------------------- ### Update Event with Server Date Source: https://context7.com/kossnocorp/typesaurus/llms.txt Updates an existing event document, setting the `updatedAt` field to the current server timestamp. ```typescript // Update with server date await eventRef.update(($) => ({ updatedAt: $.serverDate(), })); ``` -------------------------------- ### Count, Sum, and Average Documents in Typesaurus Source: https://context7.com/kossnocorp/typesaurus/llms.txt Use aggregate functions to count documents, sum numeric fields, or calculate averages. Supports counting all documents or those matching a query. ```typescript import { schema, groups } from 'typesaurus'; interface Product { name: string; price: number; category: string; } const db = schema(($) => ({ products: $.collection().sub({ reviews: $.collection<{ rating: number }>(), }), })); // Count all documents in collection const totalProducts = await db.products.count(); console.log(`Total products: ${totalProducts}`); // Count with query const electronicsCount = await db.products .query(($) => $.field("category").eq("electronics")) .count(); // Sum numeric field const totalValue = await db.products.sum("price"); console.log(`Total inventory value: ${totalValue}`); // Average numeric field const avgPrice = await db.products.average("price"); console.log(`Average price: ${avgPrice}`); // Count in collection groups const totalReviews = await groups(db).reviews.count(); ``` -------------------------------- ### Managing Subcollections in Typesaurus Source: https://context7.com/kossnocorp/typesaurus/llms.txt Add, set, query, or retrieve all documents from subcollections. Ensure the parent document exists before interacting with its subcollections. ```typescript import { schema } from 'typesaurus'; interface User { name: string; } interface Order { product: string; quantity: number; } const db = schema(($) => ({ users: $.collection().sub({ orders: $.collection(), }), })); const userId = await db.users.id(); await db.users.set(userId, { name: "Sasha" }); // Add to subcollection const orderRef = await db.users(userId).orders.add({ product: "Laptop", quantity: 1, }); // Set in subcollection const orderId = await db.users.sub.orders.id(); await db.users(userId).orders.set(orderId, { product: "Phone", quantity: 2, }); // Query subcollection const orders = await db.users(userId).orders.query(($) => $.field("quantity").gte(1) ); // Get all from subcollection const allOrders = await db.users(userId).orders.all(); // Access subcollection ID helper const newOrderId = await db.users.sub.orders.id(); ``` -------------------------------- ### Set Document with Specific ID Source: https://context7.com/kossnocorp/typesaurus/llms.txt Use the `set` function to create or overwrite a document with a specific ID. This includes generating a new ID or using a known string ID. ```typescript import { schema } from 'typesaurus'; interface User { name: string; email: string; } const db = schema(($) => ({ users: $.collection(), })); // Generate a new ID const userId = await db.users.id(); // Set document with specific ID await db.users.set(userId, { name: "Sasha", email: "sasha@example.com", }); // Using a known string ID const knownId = db.users.id("custom-user-id"); await db.users.set(knownId, { name: "Tati", email: "tati@example.com", }); // Set overwrites existing documents await db.users.set(userId, { name: "Sasha Koss", email: "sasha.koss@example.com", }); ``` -------------------------------- ### Increment Counter with Transactions Source: https://context7.com/kossnocorp/typesaurus/llms.txt A simple transaction to increment a counter. Handles cases where the document might not exist by defaulting to 0. ```typescript // Simple counter with transaction async function incrementCounter(counterId: Typesaurus.Id<"accounts">) { return transaction(db) .read(($) => $.db.accounts.get(counterId)) .write(($) => { const newBalance = ($.result?.data.balance || 0) + 1; $.result?.set({ balance: newBalance }); return newBalance; }); } ``` -------------------------------- ### Performing Batch Operations in Typesaurus Source: https://context7.com/kossnocorp/typesaurus/llms.txt Execute multiple write operations (set, update, remove) atomically using batched writes. This ensures all operations succeed or fail together, maintaining data consistency. ```typescript import { schema, batch } from 'typesaurus'; interface User { name: string; balance: number; } const db = schema(($) => ({ users: $.collection(), })); // Create batch const $ = batch(db); // Queue multiple operations const sashaId = db.users.id("sasha"); const tatiId = db.users.id("tati"); const edId = db.users.id("ed"); $.users.set(sashaId, { name: "Sasha", balance: 100 }); $.users.set(tatiId, { name: "Tati", balance: 100 }); $.users.set(edId, { name: "Ed", balance: 100 }); // Execute all operations atomically await $(); // Batch with updates and removes const $2 = batch(db); $2.users.update(sashaId, { balance: 150 }); $2.users.update(tatiId, { balance: 50 }); $2.users.remove(edId); await $2(); // Batch with subcollections const $3 = batch(db); // $3.users(userId).orders.set(orderId, { ... }); ``` -------------------------------- ### Upserting Documents in Typesaurus Source: https://context7.com/kossnocorp/typesaurus/llms.txt Use `upset` to update a document if it exists or create it if it doesn't. It supports automatic merging of data and can be used with collection IDs, references, and documents. ```typescript import { schema, Typesaurus } from 'typesaurus'; interface Counter { count: number; lastUpdated?: Typesaurus.ServerDate; } const db = schema(($) => ({ counters: $.collection(), })); const counterId = db.counters.id("page-views"); // Creates document if it doesn't exist await db.counters.upset(counterId, { count: 1 }); // Merges with existing data (preserves fields not in update) await db.counters.upset(counterId, ($) => ({ count: $.increment(1), lastUpdated: $.serverDate(), })); // Works on refs and docs too const counterRef = db.counters.ref(counterId); await counterRef.upset({ count: 100 }); ``` -------------------------------- ### Update Document Fields Source: https://context7.com/kossnocorp/typesaurus/llms.txt Update specific fields in existing documents without overwriting the entire document. Supports simple field updates, helper functions like increment, and nested field paths. ```typescript import { schema, Typesaurus } from 'typesaurus'; interface User { name: string; visits: number; address: { city: string; country: string }; lastSeen?: Typesaurus.ServerDate; } const db = schema(($) => ({ users: $.collection(), })); const userId = db.users.id("user-123"); // Simple field update await db.users.update(userId, { name: "Sasha Koss" }); // Update with helper functions await db.users.update(userId, ($) => ({ visits: $.increment(1), lastSeen: $.serverDate(), })); // Update nested fields using field paths await db.users.update(userId, ($) => [ $.field("name").set("Alexander"), $.field("address", "city").set("New York"), $.field("visits").set($.increment(5)), ]); // Remove optional fields await db.users.update(userId, ($) => ({ lastSeen: $.remove(), })); // Build update incrementally const $ = db.users.update.build(userId); $.field("name").set("Sasha"); $.field("visits").set($.increment(1)); await $.run(); ``` -------------------------------- ### Removing Documents in Typesaurus Source: https://context7.com/kossnocorp/typesaurus/llms.txt Delete documents from the database using the `remove` method. This can be done by specifying the collection and document ID, using a reference, or directly from a fetched document object. ```typescript import { schema } from 'typesaurus'; interface User { name: string; } const db = schema(($) => ({ users: $.collection(), })); // Remove by collection and ID const userId = db.users.id("user-123"); await db.users.remove(userId); // Remove via ref const userRef = db.users.ref(db.users.id("user-456")); await userRef.remove(); // Remove via doc const user = await db.users.get(db.users.id("user-789")); if (user) { await user.remove(); } ``` -------------------------------- ### Querying Collection Groups in Typesaurus Source: https://context7.com/kossnocorp/typesaurus/llms.txt Query across all subcollections with the same name, regardless of their parent document. Useful for global searches or aggregated data from similar nested collections. ```typescript import { schema, groups } from 'typesaurus'; interface Post { title: string; } interface Comment { text: string; authorId: string; } const db = schema(($) => ({ posts: $.collection().sub({ comments: $.collection(), }), })); // Get all comments across all posts const allComments = await groups(db).comments.all(); // Query across all comments const userComments = await groups(db).comments.query(($) => $.field("authorId").eq("user-123") ); // Real-time subscription to collection group const off = groups(db).comments .query(($) => $.field("authorId").eq("user-123")) .on((comments) => { console.log(`User has ${comments.length} comments`); }); ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.