TypeScript
SlintORM is written in TypeScript with full generic typing throughout. This page documents every exported type and interface.
ModelAPI<T>
// ModelAPI<T> — all 24 methods
// Returned by orm.defineModel<T>(table, name, hooks?)
interface ModelAPI<T> {
insert(data: Partial<T>): Promise<EntityWithUpdate<T>>;
insertMany(data: Partial<T>[]): Promise<EntityWithUpdate<T>[]>;
get(filter: Partial<T>): Promise<EntityWithUpdate<T> | null>;
getAll(filter?: Partial<T>): Promise<EntityWithUpdate<T>[]>;
update(filter: Partial<T>, data: Partial<T>): Promise<number>;
updateMany(filter: Partial<T>, data: Partial<T>): Promise<number>;
delete(filter: Partial<T>): Promise<number>;
deleteMany(filter: Partial<T>): Promise<number>;
upsert(data: Partial<T>, conflictKey: keyof T): Promise<EntityWithUpdate<T>>;
findOrCreate(filter: Partial<T>, defaults?: Partial<T>): Promise<{ record: EntityWithUpdate<T>; created: boolean }>;
exists(filter: Partial<T>): Promise<boolean>;
count(filter?: Partial<T>): Promise<number>;
sum(col: keyof T, filter?: Partial<T>): Promise<number>;
avg(col: keyof T, filter?: Partial<T>): Promise<number>;
min(col: keyof T, filter?: Partial<T>): Promise<number | string>;
max(col: keyof T, filter?: Partial<T>): Promise<number | string>;
truncate(): Promise<void>;
restore(filter: Partial<T>): Promise<void>;
validate(data: Partial<T>, rules: FieldRules<T>): Promise<void>;
check(data: Partial<T>, rules: FieldRules<T>): Promise<Record<string, string> | null>;
query(): QueryBuilder<T>;
advanced(): AdvancedQueryBuilder<T>;
softDelete(): SoftDeleteQueryBuilder<T>;
extended(): ExtendedQueryBuilder<T>;
}EntityWithUpdate<T>
// EntityWithUpdate<T>
// Rows returned by get(), insert(), findOrCreate() are augmented with:
type EntityWithUpdate<T> = T & {
update(data: Partial<T>): Promise<EntityWithUpdate<T>>;
delete(): Promise<void>;
refresh(): Promise<EntityWithUpdate<T>>;
toJSON(): T;
};
// Example:
const user = await User.insert({ email: 'a@b.com', name: 'Alice' });
// user is EntityWithUpdate<User>
const updated = await user.update({ name: 'Bob' }); // -> EntityWithUpdate<User>
await user.delete(); // -> void
const fresh = await user.refresh(); // re-fetches from DB
const plain = user.toJSON(); // -> User (no ORM methods)DBStore / ReadonlyDBStore
// DBStore<TModelMap> — typed db object
// Access all models without individual exports
import ORMManager from 'slintorm';
import type { ModelMap } from './schema/generated';
const orm = new ORMManager<ModelMap>({
driver: 'sqlite',
databaseUrl: './dev.db',
modelMap: {} as ModelMap,
});
export const db: DBStore<ModelMap> = orm.db;
// Fully typed:
db.User.insert(...) // knows User fields
db.Post.getAll() // knows Post fields
db.Comment.query() // QueryBuilder<Comment>// ReadonlyDBStore<TModelMap>
// Same as DBStore but all models are readonly (no insert/update/delete)
// Useful for passing to functions that should only read
function listUsers(db: ReadonlyDBStore<ModelMap>) {
return db.User.getAll(); // allowed
// db.User.insert(...) // TypeScript error
}ORMManagerConfig
// ORMManagerConfig<TModelMap>
interface ORMManagerConfig<TModelMap = Record<string, unknown>> {
driver: DBDriver;
databaseUrl: string;
dir?: string;
logs?: boolean;
schema?: object;
modelMap?: TModelMap;
}
type DBDriver = 'sqlite' | 'postgres' | 'mysql' | 'mongodb';Utility types
// Utility types
// SQLExecResult — returned by adapter.exec()
interface SQLExecResult {
rows: unknown[];
rowsAffected: number;
lastInsertId: number | null;
}
// ExecFn — the adapter's core execute function
type ExecFn = (sql: string, params?: unknown[]) => Promise<SQLExecResult>;
// OpComparison — valid WHERE operators
type OpComparison = '=' | '!=' | '<' | '<=' | '>' | '>=' | 'LIKE' | 'ILIKE';
// RelationKind — valid relation types
type RelationKind = 'onetomany' | 'manytoone' | 'onetoone' | 'manytomany';
// RelationDef — parsed from @relation annotations
interface RelationDef {
kind: RelationKind;
modelName: string;
foreignKey: string;
relatedKey?: string;
through?: string;
onDelete?: 'CASCADE' | 'SET NULL';
}FieldMeta
// FieldMeta — parsed annotation data per field
// Used internally by Migrator and QueryBuilder
interface FieldMeta {
auto?: boolean;
primaryKey?: boolean;
unique?: boolean;
index?: boolean;
nullable?: boolean;
notNull?: boolean;
length?: number;
json?: boolean;
softDelete?: boolean;
enum?: string[];
default?: string;
comment?: string;
relation?: RelationDef;
}FieldRules / ModelHooks
// FieldRules<T> — per-field validation rules
type FieldRules<T> = {
[K in keyof T]?: {
required?: boolean;
email?: boolean;
minLength?: number;
maxLength?: number;
min?: number;
max?: number;
match?: RegExp;
custom?: (value: unknown, row: Partial<T>) => string | null | Promise<string | null>;
};
};
// ModelHooks<T> — lifecycle hooks
interface ModelHooks<T> {
onCreateBefore?: (data: T) => T | void | Promise<T | void>;
onCreateAfter?: (item: T) => void | Promise<void>;
onUpdateBefore?: (oldData: T, newData: Partial<T>) => Partial<T> | void | Promise<Partial<T> | void>;
onUpdateAfter?: (oldData: T, newData: Partial<T>) => void | Promise<void>;
onDeleteBefore?: (deleted: T) => void;
onDeleteAfter?: (deleted: T) => void;
}ModelMap pattern
// ModelMap pattern — generated by 'npx slintorm generate'
// src/schema/generated.ts (auto-generated — do not edit)
export const ModelMap = {
User: {} as ModelAPI<User>,
Post: {} as ModelAPI<Post>,
Comment: {} as ModelAPI<Comment>,
Team: {} as ModelAPI<Team>,
};
export type ModelMap = typeof ModelMap;
// Usage in db.ts:
import ORMManager from 'slintorm';
import type { ModelMap } from './schema/generated';
const orm = new ORMManager<ModelMap>({
driver: 'sqlite',
databaseUrl: './dev.db',
modelMap: {} as ModelMap,
});
// orm.db is typed as DBStore<ModelMap>
// orm.db.User, orm.db.Post, etc. are all fully typed