Skip to content

$col

A clean abstraction for working with Firestore collections in a consistent, typesafe, and test-friendly way. This utility standardizes how you add, fetch, and delete documents from Firestore collections, while handling errors gracefully using Result<T, E> wrappers.

Overview

This utility provides a uniform API for interacting with Firestore collections through:

  • add – Add or upsert documents to a collection
  • get – Retrieve all matching documents
  • delete – Remove a document by ID

Each method returns a Result<T, string> for observability, testing, and consistent error handling.

API: $col(path, constraints?)

ts
$col<Path extends string>(path: Path, constraints: QueryConstraint[] = [])

Returns an object containing collection methods scoped to the given path.

Parameters

  • path: A string path to the Firestore collection (e.g., "users", "projects/123/tasks")
  • constraints: Optional Firestore query constraints (e.g., filters, ordering, limits)

Methods

add(data: any, id?: string): Promise<Result<string, string>>

Adds a document to the collection. Optionally lets you specify the document ID.

ts
await $col("projects").add({ name: "My Project" })
await $col("users").add({ name: "Alice" }, "user_123")
  • If id is provided, performs an upsert using setDoc()
  • If no id, uses addDoc() and returns the generated ID
  • Always returns a Result<string, string>

get(): Promise<Result<any[], string>>

Fetches all documents in the collection, optionally filtered via query constraints.

ts
const res = await $col("users").get()

$res.match({
    ok: ({ data }) => console.log("Users:", data),
    err: ({ data }) => console.error("Failed to fetch users:", data),
})
  • Automatically maps document IDs into returned data objects
  • Returns a Result<T[], string>

delete(id: string): Promise<Result<string, string>>

Deletes a document by ID.

ts
await $col("users").delete("user_123")
  • Uses the path/id format internally
  • Returns a Result<string, string> containing the ID on success

SSR/Test Safe

In server-side or test environments (!import.meta.client), stub implementations are returned to avoid accidental reads/writes during rendering or test bootstrapping. These return successful ok(null) results and do not interact with Firestore.

Benefits

  • ✅ Unified shape across all Firestore operations
  • ✅ Type-safe and IDE-friendly
  • ✅ Built-in error observability via Result
  • ✅ SSR/test environment aware
  • ✅ Pairs beautifully with the $doc() and $result() helpers

Example

ts
const projects = await $col("projects").get()

projects.match({
    ok: ({ data }) => console.log("Projects:", data),
    err: ({ data }) => console.error("Failed to load projects", data),
})

This utility ensures you're never handling Firestore directly in your core logic. It’s composable, consistent, and built for scale.

Use it everywhere. No raw Firestore calls ever again.™