Database Layer API

MongoDB-inspired database abstraction for Supabase.

Overview

DirectoryKit wraps Supabase with a MongoDB-inspired API in lib/supabase/database-supabase.ts. All data access goes through the db singleton:

import { db } from '@/lib/supabase/database'

Methods

db.find(table, query, options)

Find multiple documents.

const apps = await db.find("apps", { status: "live" }, {
  sort: { upvotes: -1 },
  limit: 10,
  skip: 20,
  projection: { slug: 1, name: 1 },
})

db.findOne(table, query, options)

Find a single document.

const app = await db.findOne("apps", { slug: "example" })

db.insertOne(table, document)

Insert a single document. Returns { insertedId }.

const { insertedId } = await db.insertOne("apps", {
  name: "My App",
  slug: "my-app",
  status: "pending",
})

db.updateOne(table, filter, update)

Update a single document using $set and/or $inc operators.

await db.updateOne("apps", { id }, {
  $set: { status: "approved" },
})

db.deleteOne(table, filter)

Delete a single document.

await db.deleteOne("apps", { id })

db.count(table, query)

Count matching documents.

const total = await db.count("apps", { status: "live" })

db.rpc(functionName, params)

Call a PostgreSQL function directly.

await db.rpc("increment_upvotes", { app_id: id })

db.incrementField(table, id, field, value)

Increment a numeric field (read-modify-write, not atomic).

await db.incrementField("apps", id, "upvotes", 1)

Query operators

OperatorExampleDescription
$and{ $and: [{ a: 1 }, { b: 2 }] }Logical AND
$or{ $or: [{ a: 1 }, { b: 2 }] }Logical OR
$in{ status: { $in: ["live", "pending"] } }Match any value
$gt, $gte{ upvotes: { $gt: 10 } }Greater than
$lt, $lte{ upvotes: { $lt: 100 } }Less than
$ne{ status: { $ne: "rejected" } }Not equal
$regex{ name: { $regex: "search" } }Pattern match
$exists{ email: { $exists: true } }Field exists
$overlaps{ categories: { $overlaps: ["ai"] } }Array overlap
$contains{ tags: { $contains: ["featured"] } }Array contains

JSONB arrays

The $in operator on JSONB array columns (like categories, tags) uses Supabase .overlaps() internally and may behave differently from scalar columns.