API Reference
Every method, every option, every operator. The page you'll bookmark and actually come back to.
SeedORM
The main entry point. Creates a database instance, manages connections, and registers models. This is the thing you new up before doing anything useful.
new SeedORM(config?)
Creates a new SeedORM instance.
import { SeedORM, AdapterType } from "seedorm";// Default: JSON adapter, data stored in ./data/seedorm.jsonconst db = new SeedORM();// Custom configconst db = new SeedORM({ adapter: { adapter: AdapterType.Json, path: "./my-data" }, migrationsDir: "./my-migrations",});// PostgreSQLconst db = new SeedORM({ adapter: { adapter: AdapterType.Postgres, url: "postgres://user:pass@localhost:5432/mydb" },});| Parameter | Type | Description |
|---|---|---|
config.adapter | AdapterConfig | Storage backend configuration |
config.migrationsDir | string | Path to migrations directory (default: "./migrations") |
db.connect()
Connects to the storage backend. Must be called before defining models. Returns Promise<void>.
await db.connect();db.disconnect()
Flushes pending writes and closes the connection. Always call this before your process exits. Be a good citizen.
await db.disconnect();db.model(definition)
Registers a model and returns a Model instance. If a model with the same name already exists, returns the existing one.
const User = db.model({ name: "User", collection: "users", schema: { name: { type: FieldType.String, required: true }, email: { type: FieldType.String, unique: true }, }, prefix: "usr", // optional, ID prefix (default: first 3 chars of collection) timestamps: true, // optional, auto-manage createdAt/updatedAt (default: true) relations: {}, // optional, define relations to other models (see Relations)});Model
Represents a collection with schema validation. All CRUD operations go through Model methods. This is where the real work happens.
model.init()
Creates the underlying collection if it doesn't exist. Must be called once after defining the model.
await User.init();model.create(data)
Validates data against the schema, generates an ID, sets timestamps, and inserts the document. Returns the fullDocument.
const user = await User.create({ name: "Alice", email: "alice@example.com",});// Returns: { id: "usr_...", name: "Alice", email: "...", createdAt: "...", updatedAt: "..." }Throws ValidationError if data is invalid, UniqueConstraintError if a unique field conflicts.
model.createMany(items)
Creates multiple documents. Returns Promise<Document[]>.
const users = await User.createMany([ { name: "Bob", email: "bob@example.com" }, { name: "Charlie", email: "charlie@example.com" },]);model.findById(id, options?)
Finds a document by its ID. Returns Document | null.
const user = await User.findById("usr_abc123");// With relation populationconst user = await User.findById("usr_abc123", { include: ["posts", "profile"],});model.findByIdOrThrow(id, options?)
Same as findById but throws DocumentNotFoundError if not found. Accepts the same options parameter.
model.findOne(filter, options?)
Finds the first document matching the filter. Returns Document | null.
const admin = await User.findOne({ role: "admin" });const alice = await User.findOne({ email: { $eq: "alice@example.com" } });// With relation populationconst admin = await User.findOne({ role: "admin" }, { include: ["posts"],});model.find(options?)
Queries documents with filtering, sorting, pagination. Returns Document[].
const results = await User.find({ filter: { age: { $gte: 18, $lte: 65 }, role: { $in: ["admin", "moderator"] }, }, sort: { createdAt: -1 }, limit: 20, offset: 0,});| Option | Type | Description |
|---|---|---|
filter | FilterQuery | Query conditions (see operators below) |
sort | SortOption | Sort order: 1 ascending, -1 descending |
limit | number | Max documents to return |
offset | number | Number of documents to skip |
include | string[] | Relation names to populate (see Relations) |
model.findAll()
Returns all documents in the collection.
model.count(filter?)
Returns the number of documents, optionally filtered.
const total = await User.count();const admins = await User.count({ role: "admin" });model.update(id, data)
Partial update: only the fields provided in data are changed. Returns the updated document or null.
const updated = await User.update("usr_abc123", { name: "Alice Updated", age: 31,});model.updateOrThrow(id, data)
Same as update but throws DocumentNotFoundError if not found.
model.delete(id)
Deletes a document by ID. Returns boolean (true if deleted).
model.deleteMany(filter)
Deletes all matching documents. Returns the count deleted.
const count = await User.deleteMany({ active: false });Schema Definition
Schemas define the shape and constraints of your documents. Each field can be a shorthand type string or a full field definition object. Think of it as a contract between "what you want your data to look like" and "what it actually looks like."
Field types
SeedORM exports a FieldType enum, but since it's a string enum you can also use plain strings. They're equivalent.
| Enum | String | JavaScript | PostgreSQL | Description |
|---|---|---|---|---|
FieldType.String | "string" | string | TEXT | Text value |
FieldType.Number | "number" | number | DOUBLE PRECISION | Numeric value |
FieldType.Boolean | "boolean" | boolean | BOOLEAN | True or false |
FieldType.Date | "date" | string (ISO) | TIMESTAMPTZ | Date/time value stored as ISO string |
FieldType.Json | "json" | object | JSONB | Arbitrary JSON data |
FieldType.Array | "array" | unknown[] | JSONB | Array of values |
Field options
import { FieldType } from "seedorm";const schema = { // Shorthand: just a type string (also works) bio: "string", // Full definition email: { type: FieldType.String, required: true, // must be present on create unique: true, // enforced uniqueness index: true, // create an index (auto-set when unique) maxLength: 255, // string constraint }, age: { type: FieldType.Number, min: 0, max: 150, default: 0, // applied on create if not provided }, status: { type: FieldType.String, enum: ["active", "inactive", "banned"], default: "active", },};| Option | Type | Description |
|---|---|---|
type | FieldType | The field type (required) |
required | boolean | Must be present on create (default: false) |
unique | boolean | Enforce uniqueness (default: false) |
index | boolean | Create an index for faster lookups |
default | unknown | Default value applied on create |
minLength | number | Minimum string length |
maxLength | number | Maximum string length |
min | number | Minimum number value |
max | number | Maximum number value |
enum | unknown[] | Allowed values |
Query Operators
SeedORM uses MongoDB-style query operators. These work identically across all storage adapters, so you learn them once and never think about it again.
| Operator | Description | Example |
|---|---|---|
$eq | Equal to | { age: { $eq: 30 } } |
$ne | Not equal to | { status: { $ne: "banned" } } |
$gt | Greater than | { age: { $gt: 18 } } |
$gte | Greater than or equal | { age: { $gte: 18 } } |
$lt | Less than | { age: { $lt: 65 } } |
$lte | Less than or equal | { age: { $lte: 65 } } |
$in | In array | { role: { $in: ["admin", "mod"] } } |
$nin | Not in array | { role: { $nin: ["banned"] } } |
$like | Pattern match (SQL-like) | { name: { $like: "%alice%" } } |
$exists | Field exists / is not null | { email: { $exists: true } } |
Operators can be combined within a single field:
// Range query: 18 <= age <= 65const results = await User.find({ filter: { age: { $gte: 18, $lte: 65 } },});Shorthand equality. These are equivalent:
{ role: "admin" }{ role: { $eq: "admin" } }Switching Adapters
Change the adapter field in your configuration to switch storage backends. No application code changes needed. That's the whole point of this project.
SeedORM exports an AdapterType enum for type-safe adapter configuration in TypeScript. Plain strings also work since the enum is string-backed.
import { AdapterType } from "seedorm";AdapterType.Json // "json"AdapterType.Postgres // "postgres"AdapterType.MySQL // "mysql"JSON (default)
{ "adapter": { "adapter": "json", "path": "./data" }}PostgreSQL
{ "adapter": { "adapter": "postgres", "url": "postgres://user:password@localhost:5432/mydb" }}Requires npm install pg.
MySQL (coming soon)
{ "adapter": { "adapter": "mysql", "url": "mysql://user:password@localhost:3306/mydb" }}Will require npm install mysql2.
SQLite (coming soon)
{ "adapter": { "adapter": "sqlite", "path": "./data/app.db" }}Error Types
SeedORM exports specific error classes so you can catch exactly what went wrong instead of guessing from a generic "something broke" message:
| Error | When |
|---|---|
SeedORMError | Base error class for all seedorm errors |
ValidationError | Schema validation failed (has .field and .reason) |
UniqueConstraintError | Unique field conflict (has .field and .value) |
DocumentNotFoundError | Document not found (from *OrThrow methods) |
CollectionNotFoundError | Collection doesn't exist |
AdapterError | Storage backend error |
import { ValidationError, UniqueConstraintError } from "seedorm";try { await User.create({ email: "duplicate@test.com" });} catch (err) { if (err instanceof UniqueConstraintError) { console.log(err.field); // "email" console.log(err.value); // "duplicate@test.com" } if (err instanceof ValidationError) { console.log(err.field); // field name console.log(err.reason); // human-readable reason }}