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.json
const db = new SeedORM();
// Custom config
const db = new SeedORM({
adapter: { adapter: AdapterType.Json, path: "./my-data" },
migrationsDir: "./my-migrations",
});
// PostgreSQL
const db = new SeedORM({
adapter: { adapter: AdapterType.Postgres, url: "postgres://user:pass@localhost:5432/mydb" },
});
ParameterTypeDescription
config.adapterAdapterConfigStorage backend configuration
config.migrationsDirstringPath 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 population
const 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 population
const 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,
});
OptionTypeDescription
filterFilterQueryQuery conditions (see operators below)
sortSortOptionSort order: 1 ascending, -1 descending
limitnumberMax documents to return
offsetnumberNumber of documents to skip
includestring[]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.

EnumStringJavaScriptPostgreSQLDescription
FieldType.String"string"stringTEXTText value
FieldType.Number"number"numberDOUBLE PRECISIONNumeric value
FieldType.Boolean"boolean"booleanBOOLEANTrue or false
FieldType.Date"date"string (ISO)TIMESTAMPTZDate/time value stored as ISO string
FieldType.Json"json"objectJSONBArbitrary JSON data
FieldType.Array"array"unknown[]JSONBArray 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",
},
};
OptionTypeDescription
typeFieldTypeThe field type (required)
requiredbooleanMust be present on create (default: false)
uniquebooleanEnforce uniqueness (default: false)
indexbooleanCreate an index for faster lookups
defaultunknownDefault value applied on create
minLengthnumberMinimum string length
maxLengthnumberMaximum string length
minnumberMinimum number value
maxnumberMaximum number value
enumunknown[]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.

OperatorDescriptionExample
$eqEqual to{ age: { $eq: 30 } }
$neNot equal to{ status: { $ne: "banned" } }
$gtGreater than{ age: { $gt: 18 } }
$gteGreater than or equal{ age: { $gte: 18 } }
$ltLess than{ age: { $lt: 65 } }
$lteLess than or equal{ age: { $lte: 65 } }
$inIn array{ role: { $in: ["admin", "mod"] } }
$ninNot in array{ role: { $nin: ["banned"] } }
$likePattern match (SQL-like){ name: { $like: "%alice%" } }
$existsField exists / is not null{ email: { $exists: true } }

Operators can be combined within a single field:

// Range query: 18 <= age <= 65
const 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)

seedorm.config.jsonjson
{
"adapter": {
"adapter": "json",
"path": "./data"
}
}

PostgreSQL

seedorm.config.jsonjson
{
"adapter": {
"adapter": "postgres",
"url": "postgres://user:password@localhost:5432/mydb"
}
}

Requires npm install pg.

MySQL (coming soon)

seedorm.config.jsonjson
{
"adapter": {
"adapter": "mysql",
"url": "mysql://user:password@localhost:3306/mydb"
}
}

Will require npm install mysql2.

SQLite (coming soon)

seedorm.config.jsonjson
{
"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:

ErrorWhen
SeedORMErrorBase error class for all seedorm errors
ValidationErrorSchema validation failed (has .field and .reason)
UniqueConstraintErrorUnique field conflict (has .field and .value)
DocumentNotFoundErrorDocument not found (from *OrThrow methods)
CollectionNotFoundErrorCollection doesn't exist
AdapterErrorStorage 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
}
}