alepha
Version:
Easy-to-use modern TypeScript framework for building many kind of applications.
1,512 lines • 99.8 kB
TypeScript
import { Alepha, AlephaError, KIND, Middleware, Page, Page as Page$1, PageQuery, PageQuery as PageQuery$1, Primitive, SchemaValidator, Service, Static, StaticEncode, TBigInt, TInteger, TNull, TNumber, TNumberOptions, TObject, TOptional, TPage, TSchema, TString, TStringOptions, TUnion, pageQuerySchema, pageSchema } from "alepha";
import { DateTime, DateTimeProvider } from "alepha/datetime";
import * as drizzle from "drizzle-orm";
import { BuildColumns, BuildExtraConfigColumns, SQL, SQLWrapper, sql } from "drizzle-orm";
import { LockConfig, LockStrength, PgColumn, PgColumnBuilderBase, PgDatabase, PgInsertValue, PgSelectBase, PgSequenceOptions, PgTableExtraConfigValue, PgTableWithColumns, PgTransaction, UpdateDeleteAction } from "drizzle-orm/pg-core";
import { CryptoProvider } from "alepha/crypto";
import * as pg from "drizzle-orm/sqlite-core";
import { SQLiteColumnBuilderBase } from "drizzle-orm/sqlite-core";
import { DatabaseSync } from "node:sqlite";
import { UpdateDeleteAction as UpdateDeleteAction$1 } from "drizzle-orm/pg-core/foreign-keys";
import { PgTransactionConfig } from "drizzle-orm/pg-core/session";
import * as DrizzleKit from "drizzle-kit/api";
import { DrizzleD1Database } from "drizzle-orm/d1";
import { Database } from "bun:sqlite";
import { BunSQLiteDatabase } from "drizzle-orm/bun-sqlite";
export * from "drizzle-orm/pg-core";
//#region ../../src/orm/core/constants/PG_SYMBOLS.d.ts
declare const PG_DEFAULT: unique symbol;
declare const PG_PRIMARY_KEY: unique symbol;
declare const PG_CREATED_AT: unique symbol;
declare const PG_UPDATED_AT: unique symbol;
declare const PG_DELETED_AT: unique symbol;
declare const PG_VERSION: unique symbol;
declare const PG_IDENTITY: unique symbol;
declare const PG_ENUM: unique symbol;
declare const PG_REF: unique symbol;
declare const PG_GENERATED: unique symbol;
declare const PG_ORGANIZATION: unique symbol;
/**
* @deprecated Use `PG_IDENTITY` instead.
*/
declare const PG_SERIAL: unique symbol;
type PgDefault = typeof PG_DEFAULT;
type PgRef = typeof PG_REF;
type PgPrimaryKey = typeof PG_PRIMARY_KEY;
type PgSymbols = {
[PG_DEFAULT]: {};
[PG_PRIMARY_KEY]: {};
[PG_CREATED_AT]: {};
[PG_UPDATED_AT]: {};
[PG_DELETED_AT]: {};
[PG_VERSION]: {};
[PG_IDENTITY]: PgIdentityOptions;
[PG_REF]: PgRefOptions;
[PG_ENUM]: PgEnumOptions;
[PG_GENERATED]: PgGeneratedOptions;
[PG_ORGANIZATION]: PgOrganizationOptions;
/**
* @deprecated Use `PG_IDENTITY` instead.
*/
[PG_SERIAL]: {};
};
type PgSymbolKeys = keyof PgSymbols;
interface PgOrganizationOptions {
/**
* Fail-closed tenant scoping. When `true`, the repository (a) refuses any
* read/write with no resolved tenant instead of falling through to an
* unfiltered "see/write everything" query, and (b) drops the
* `OR organizationId IS NULL` "global row" escape — a scoped tenant never
* sees NULL/global rows. Use for security-sensitive tables. Defaults to
* `false` (the historic fail-open semantics).
*/
strict?: boolean;
}
type PgIdentityOptions = {
mode: "always" | "byDefault";
} & PgSequenceOptions & {
name?: string;
};
interface PgEnumOptions {
name?: string;
description?: string;
}
interface PgGeneratedOptions {
/**
* SQL expression for the generated column.
*/
expression: SQL;
/**
* Storage mode for the generated column.
* - `"stored"` — value is computed on write and stored on disk (default for PostgreSQL).
* - `"virtual"` — value is computed on read (default for SQLite).
*/
mode?: "stored" | "virtual";
}
interface PgRefOptions {
ref: () => {
name: string;
entity: EntityPrimitive;
};
actions?: {
onUpdate?: UpdateDeleteAction;
onDelete?: UpdateDeleteAction;
};
}
//#endregion
//#region ../../src/orm/core/schemas/insertSchema.d.ts
/**
* Transforms a TObject schema for insert operations.
* All default properties at the root level are made optional.
* Generated columns are excluded entirely.
*
* @example
* Before: { name: string; age: number(default=0); fullName: generated }
* After: { name: string; age?: number; }
*/
type TObjectInsert<T extends TObject> = TObject<{ [K in keyof T["shape"] as T["shape"][K] extends {
[PG_GENERATED]: any;
} ? never : K]: T["shape"][K] extends {
[PG_DEFAULT]: any;
} | {
[PG_ORGANIZATION]: any;
} ? TOptional<Extract<T["shape"][K], TSchema>> : T["shape"][K]; }>;
declare const insertSchema: <T extends TObject>(obj: T) => TObjectInsert<T>;
//#endregion
//#region ../../src/orm/core/schemas/updateSchema.d.ts
/**
* Transforms a TObject schema for update operations.
* All optional properties at the root level are made nullable (i.e., `T | null`).
* Generated columns are excluded entirely.
*
* @example
* Before: { name?: string; age: number; fullName: generated }
* After: { name?: string | null; age: number; }
*/
type TObjectUpdate<T extends TObject> = TObject<{ [K in keyof T["shape"] as T["shape"][K] extends {
[PG_GENERATED]: any;
} ? never : K]: T["shape"][K] extends TOptional<infer U extends TSchema> ? TOptional<TUnion<[U, TNull]>> : T["shape"][K]; }>;
declare const updateSchema: <T extends TObject>(schema: T) => TObjectUpdate<T>;
//#endregion
//#region ../../src/orm/core/primitives/$entity.d.ts
/**
* Creates a database entity primitive that defines table structure using TypeBox schemas.
*
* @example
* ```ts
* import { z } from "alepha";
* import { $entity } from "alepha/orm";
*
* const userEntity = $entity({
* name: "users",
* schema: z.object({
* id: pg.primaryKey(),
* name: z.text(),
* email: z.email(),
* }),
* });
* ```
*/
declare const $entity: {
<TSchema extends TObject>(options: EntityPrimitiveOptions<TSchema>): EntityPrimitive<TSchema>;
[KIND]: typeof EntityPrimitive;
};
interface EntityPrimitiveOptions<T extends TObject, Keys = keyof Static<T>> {
/**
* The database table name that will be created for this entity.
* If not provided, name will be inferred from the $repository variable name.
*/
name: string;
/**
* TypeBox schema defining the table structure and column types.
*/
schema: T;
/**
* Database indexes to create for query optimization.
*/
indexes?: (Keys | {
/**
* Single column to index.
*/
column: Keys;
/**
* Whether this should be a unique index (enforces uniqueness constraint).
*/
unique?: boolean;
/**
* Custom name for the index. If not provided, generates name automatically.
*/
name?: string;
/**
* Partial index condition. Only rows matching this SQL expression are indexed.
*/
where?: SQL;
} | {
/**
* Multiple columns for composite index (order matters for query optimization).
*/
columns: Keys[];
/**
* Whether this should be a unique index (enforces uniqueness constraint).
*/
unique?: boolean;
/**
* Custom name for the index. If not provided, generates name automatically.
*/
name?: string;
/**
* Partial index condition. Only rows matching this SQL expression are indexed.
*/
where?: SQL;
} | {
/**
* SQL expressions for expression-based indexes.
*
* Can include column references and SQL functions like `LOWER()`, `UPPER()`, etc.
* Columns and expressions can be mixed together.
*
* @example
* ```ts
* // Case-insensitive unique username per realm
* indexes: [{
* expressions: (self) => [self.realm, sql`LOWER(${self.username})`],
* unique: true,
* name: "users_realm_username_lower_idx",
* }]
* ```
*/
expressions: (self: Record<Keys & string, any>) => (SQL | any)[];
/**
* Whether this should be a unique index (enforces uniqueness constraint).
*/
unique?: boolean;
/**
* Custom name for the index. If not provided, generates name automatically.
*/
name: string;
/**
* Partial index condition. Only rows matching this SQL expression are indexed.
*/
where?: SQL;
})[];
/**
* Foreign key constraints to maintain referential integrity.
*/
foreignKeys?: Array<{
/**
* Optional name for the foreign key constraint.
*/
name?: string;
/**
* Local columns that reference the foreign table.
*/
columns: Array<keyof Static<T>>;
/**
* Referenced columns in the foreign table.
* Must be EntityColumn references from other entities.
*/
foreignColumns: Array<() => EntityColumn<any>>;
}>;
/**
* Additional table constraints for data validation.
*
* Constraints enforce business rules at the database level, providing
* an additional layer of data integrity beyond application validation.
*
* **Constraint Types**:
* - **Unique constraints**: Prevent duplicate values across columns
* - **Check constraints**: Enforce custom validation rules with SQL expressions
*
* @example
* ```ts
* constraints: [
* {
* name: "unique_user_email",
* columns: ["email"],
* unique: true
* },
* {
* name: "valid_age_range",
* columns: ["age"],
* check: sql`age >= 0 AND age <= 150`
* },
* {
* name: "unique_user_username_per_tenant",
* columns: ["tenantId", "username"],
* unique: true
* }
* ]
* ```
*/
constraints?: Array<{
/**
* Columns involved in this constraint.
*/
columns: Array<keyof Static<T>>;
/**
* Optional name for the constraint.
*/
name?: string;
/**
* Whether this is a unique constraint.
*/
unique?: boolean | {};
/**
* SQL expression for check constraint validation.
*/
check?: SQL;
}>;
/**
* Advanced Drizzle ORM configuration for complex table setups.
*/
config?: (self: BuildExtraConfigColumns<string, FromSchema<T>, "pg">) => PgTableExtraConfigValue[];
}
declare class EntityPrimitive<T extends TObject = TObject> {
readonly options: EntityPrimitiveOptions<T>;
constructor(options: EntityPrimitiveOptions<T>);
alias(alias: string): this;
get cols(): EntityColumns<T>;
get name(): string;
get schema(): T;
protected _insertSchema?: TObjectInsert<T>;
get insertSchema(): TObjectInsert<T>;
protected _updateSchema?: TObjectUpdate<T>;
get updateSchema(): TObjectUpdate<T>;
}
/**
* Convert a schema to columns.
*/
type FromSchema<T extends TObject> = { [key in keyof T["properties"]]: PgColumnBuilderBase; };
type SchemaToTableConfig<T extends TObject> = {
name: string;
schema: string | undefined;
columns: { [key in keyof T["properties"]]: PgColumn; };
dialect: string;
};
type EntityColumn<T extends TObject> = {
name: string;
entity: EntityPrimitive<T>;
};
type EntityColumns<T extends TObject> = { [key in keyof T["properties"]]: EntityColumn<T>; };
//#endregion
//#region ../../src/orm/core/errors/DbError.d.ts
declare class DbError extends AlephaError {
name: string;
constructor(message: string, cause?: unknown);
}
//#endregion
//#region ../../src/orm/core/errors/DbColumnNotFoundError.d.ts
/**
* Error thrown when a column does not exist.
*
* This typically happens when:
* - Column name is misspelled
* - Migrations haven't been run
* - Using wrong schema version
*/
declare class DbColumnNotFoundError extends DbError {
readonly name = "DbColumnNotFoundError";
readonly status = 500;
/**
* The column that was not found.
*/
readonly column?: string;
/**
* The table where the column was expected.
*/
readonly table?: string;
constructor(message: string, cause?: unknown, options?: {
column?: string;
table?: string;
});
/**
* Parse a database column not found error and create a DbColumnNotFoundError.
* Supports both PostgreSQL and SQLite error formats.
*/
static fromDatabaseError(error: Error): DbColumnNotFoundError;
}
//#endregion
//#region ../../src/orm/core/errors/DbConnectionError.d.ts
/**
* Error thrown when a database connection fails.
*
* This can happen due to:
* - Connection refused (server not running)
* - Connection timeout
* - Authentication failure
* - Network issues
* - Database file not found (SQLite)
*/
declare class DbConnectionError extends DbError {
readonly name = "DbConnectionError";
readonly status = 503;
/**
* The type of connection error.
*/
readonly errorType?: "refused" | "timeout" | "auth" | "not_found" | "locked" | "unknown";
/**
* Whether this error is retryable.
* Connection errors are often transient and can be retried.
*/
readonly retryable: boolean;
constructor(message: string, cause?: unknown, options?: {
errorType?: DbConnectionError["errorType"];
retryable?: boolean;
});
/**
* Parse a database connection error message and create a DbConnectionError.
* Supports both PostgreSQL and SQLite error formats.
*/
static fromDatabaseError(error: Error): DbConnectionError;
}
//#endregion
//#region ../../src/orm/core/errors/DbDeadlockError.d.ts
/**
* Error thrown when a deadlock is detected.
*
* This happens when two or more transactions are waiting for each other
* to release locks. The database automatically aborts one transaction
* to resolve the deadlock.
*
* This error is useful for implementing retry logic.
*/
declare class DbDeadlockError extends DbError {
readonly name = "DbDeadlockError";
readonly status = 409;
/**
* Whether this error is retryable.
* Deadlocks are typically safe to retry.
*/
readonly retryable = true;
/**
* Parse a database deadlock error message and create a DbDeadlockError.
* Supports PostgreSQL. SQLite doesn't have true deadlocks (uses SQLITE_BUSY instead).
*/
static fromDatabaseError(error: Error): DbDeadlockError;
}
//#endregion
//#region ../../src/orm/core/errors/DbEntityNotFoundError.d.ts
declare class DbEntityNotFoundError extends DbError {
readonly name = "DbEntityNotFoundError";
readonly status = 404;
constructor(entityName: string);
}
//#endregion
//#region ../../src/orm/core/errors/DbForeignKeyError.d.ts
/**
* Error thrown when a foreign key constraint is violated.
*
* This typically happens when trying to delete an entity that is
* referenced by another entity.
*/
declare class DbForeignKeyError extends DbError {
readonly name = "DbForeignKeyError";
readonly status = 409;
/**
* The table that references the entity being deleted.
*/
readonly referencingTable?: string;
/**
* The constraint name that was violated.
*/
readonly constraintName?: string;
constructor(message: string, cause?: unknown, options?: {
referencingTable?: string;
constraintName?: string;
});
/**
* Parse a database foreign key error message and create a DbForeignKeyError.
* Supports both PostgreSQL and SQLite error formats.
*/
static fromDatabaseError(error: Error, tableName: string): DbForeignKeyError;
}
//#endregion
//#region ../../src/orm/core/errors/DbNotNullError.d.ts
/**
* Error thrown when a NOT NULL constraint is violated.
*
* This happens when inserting or updating a NULL value into a column
* that has a NOT NULL constraint.
*/
declare class DbNotNullError extends DbError {
readonly name = "DbNotNullError";
readonly status = 400;
/**
* The column that violated the NOT NULL constraint.
*/
readonly column?: string;
/**
* The table containing the column.
*/
readonly table?: string;
constructor(message: string, cause?: unknown, options?: {
column?: string;
table?: string;
});
/**
* Parse a database NOT NULL error message and create a DbNotNullError.
* Supports both PostgreSQL and SQLite error formats.
*/
static fromDatabaseError(error: Error, tableName: string): DbNotNullError;
}
//#endregion
//#region ../../src/orm/core/errors/DbTableNotFoundError.d.ts
/**
* Error thrown when a table does not exist.
*
* This typically happens when:
* - Migrations haven't been run
* - Table name is misspelled
* - Wrong database/schema is being used
*/
declare class DbTableNotFoundError extends DbError {
readonly name = "DbTableNotFoundError";
readonly status = 500;
/**
* The table that was not found.
*/
readonly table?: string;
constructor(message: string, cause?: unknown, options?: {
table?: string;
});
/**
* Parse a database table not found error and create a DbTableNotFoundError.
* Supports both PostgreSQL and SQLite error formats.
*/
static fromDatabaseError(error: Error): DbTableNotFoundError;
}
//#endregion
//#region ../../src/orm/core/helpers/pgAttr.d.ts
/**
* Decorates a typebox schema with a Postgres attribute.
*
* > It's just a fancy way to add Symbols to a field.
*
* @example
* ```ts
* import { z } from "alepha";
* import { PG_UPDATED_AT } from "../constants/PG_SYMBOLS";
*
* export const updatedAtSchema = pgAttr(
* z.datetime(), PG_UPDATED_AT,
* );
* ```
*/
declare const pgAttr: <T extends TSchema, Attr extends PgSymbolKeys>(type: T, attr: Attr, value?: PgSymbols[Attr]) => PgAttr<T, Attr>;
/**
* Retrieves the fields of a schema that have a specific attribute.
*/
declare const getAttrFields: (schema: TObject, name: PgSymbolKeys) => PgAttrField[];
/**
* Type representation.
*/
type PgAttr<T extends TSchema, TAttr extends PgSymbolKeys> = T & { [K in TAttr]: PgSymbols[K]; };
interface PgAttrField {
key: string;
type: TSchema;
data: any;
nested?: any[];
one?: boolean;
}
//#endregion
//#region ../../src/orm/core/interfaces/FilterOperators.d.ts
interface FilterOperators<TValue> {
/**
* Test that two values are equal.
*
* Remember that the SQL standard dictates that
* two NULL values are not equal, so if you want to test
* whether a value is null, you may want to use
* `isNull` instead.
*
* ## Examples
*
* ```ts
* // Select cars made by Ford
* db.select().from(cars)
* .where(eq(cars.make, 'Ford'))
* ```
*
* @see isNull for a way to test equality to NULL.
*/
eq?: TValue;
/**
* Test that two values are not equal.
*
* Remember that the SQL standard dictates that
* two NULL values are not equal, so if you want to test
* whether a value is not null, you may want to use
* `isNotNull` instead.
*
* ## Examples
*
* ```ts
* // Select cars not made by Ford
* db.select().from(cars)
* .where(ne(cars.make, 'Ford'))
* ```
*
* @see isNotNull for a way to test whether a value is not null.
*/
ne?: TValue;
/**
* Test that the first expression passed is greater than
* the second expression.
*
* ## Examples
*
* ```ts
* // Select cars made after 2000.
* db.select().from(cars)
* .where(gt(cars.year, 2000))
* ```
*
* @see gte for greater-than-or-equal
*/
gt?: TValue;
/**
* Test that the first expression passed is greater than
* or equal to the second expression. Use `gt` to
* test whether an expression is strictly greater
* than another.
*
* ## Examples
*
* ```ts
* // Select cars made on or after 2000.
* db.select().from(cars)
* .where(gte(cars.year, 2000))
* ```
*
* @see gt for a strictly greater-than condition
*/
gte?: TValue;
/**
* Test that the first expression passed is less than
* the second expression.
*
* ## Examples
*
* ```ts
* // Select cars made before 2000.
* db.select().from(cars)
* .where(lt(cars.year, 2000))
* ```
*
* @see lte for greater-than-or-equal
*/
lt?: TValue;
/**
* Test that the first expression passed is less than
* or equal to the second expression.
*
* ## Examples
*
* ```ts
* // Select cars made before 2000.
* db.select().from(cars)
* .where(lte(cars.year, 2000))
* ```
*
* @see lt for a strictly less-than condition
*/
lte?: TValue;
/**
* Test whether the first parameter, a column or expression,
* has a value from a list passed as the second argument.
*
* ## Throws
*
* The argument passed in the second array can't be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select cars made by Ford or GM.
* db.select().from(cars)
* .where(inArray(cars.make, ['Ford', 'GM']))
* ```
*
* @see notInArray for the inverse of this test
*/
inArray?: TValue[];
/**
* Test whether the first parameter, a column or expression,
* has a value that is not present in a list passed as the
* second argument.
*
* ## Throws
*
* The argument passed in the second array can't be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select cars made by any company except Ford or GM.
* db.select().from(cars)
* .where(notInArray(cars.make, ['Ford', 'GM']))
* ```
*
* @see inArray for the inverse of this test
*/
notInArray?: TValue[];
/**
* Test whether an expression is not NULL. By the SQL standard,
* NULL is neither equal nor not equal to itself, so
* it's recommended to use `isNull` and `notIsNull` for
* comparisons to NULL.
*
* ## Examples
*
* ```ts
* // Select cars that have been discontinued.
* db.select().from(cars)
* .where(isNotNull(cars.discontinuedAt))
* ```
*
* @see isNull for the inverse of this test
*/
isNotNull?: true;
/**
* Test whether an expression is NULL. By the SQL standard,
* NULL is neither equal nor not equal to itself, so
* it's recommended to use `isNull` and `notIsNull` for
* comparisons to NULL.
*
* ## Examples
*
* ```ts
* // Select cars that have no discontinuedAt date.
* db.select().from(cars)
* .where(isNull(cars.discontinuedAt))
* ```
*
* @see isNotNull for the inverse of this test
*/
isNull?: true;
/**
* Test whether an expression is between two values. This
* is an easier way to express range tests, which would be
* expressed mathematically as `x <= a <= y` but in SQL
* would have to be like `a >= x AND a <= y`.
*
* Between is inclusive of the endpoints: if `column`
* is equal to `min` or `max`, it will be TRUE.
*
* ## Examples
*
* ```ts
* // Select cars made between 1990 and 2000
* db.select().from(cars)
* .where(between(cars.year, 1990, 2000))
* ```
*
* @see notBetween for the inverse of this test
*/
between?: [number, number];
/**
* Test whether an expression is not between two values.
*
* This, like `between`, includes its endpoints, so if
* the `column` is equal to `min` or `max`, in this case
* it will evaluate to FALSE.
*
* ## Examples
*
* ```ts
* // Exclude cars made in the 1970s
* db.select().from(cars)
* .where(notBetween(cars.year, 1970, 1979))
* ```
*
* @see between for the inverse of this test
*/
notBetween?: [number, number];
/**
* Compare a column to a pattern, which can include `%` and `_`
* characters to match multiple variations. Including `%`
* in the pattern matches zero or more characters, and including
* `_` will match a single character.
*
* ## Examples
*
* ```ts
* // Select all cars with 'Turbo' in their names.
* db.select().from(cars)
* .where(like(cars.name, '%Turbo%'))
* ```
*
* @see ilike for a case-insensitive version of this condition
*/
like?: string;
/**
* The inverse of like - this tests that a given column
* does not match a pattern, which can include `%` and `_`
* characters to match multiple variations. Including `%`
* in the pattern matches zero or more characters, and including
* `_` will match a single character.
*
* ## Examples
*
* ```ts
* // Select all cars that don't have "ROver" in their name.
* db.select().from(cars)
* .where(notLike(cars.name, '%Rover%'))
* ```
*
* @see like for the inverse condition
* @see notIlike for a case-insensitive version of this condition
*/
notLike?: string;
/**
* Case-insensitively compare a column to a pattern,
* which can include `%` and `_`
* characters to match multiple variations. Including `%`
* in the pattern matches zero or more characters, and including
* `_` will match a single character.
*
* Unlike like, this performs a case-insensitive comparison.
*
* ## Examples
*
* ```ts
* // Select all cars with 'Turbo' in their names.
* db.select().from(cars)
* .where(ilike(cars.name, '%Turbo%'))
* ```
*
* @see like for a case-sensitive version of this condition
*/
ilike?: string;
/**
* The inverse of ilike - this case-insensitively tests that a given column
* does not match a pattern, which can include `%` and `_`
* characters to match multiple variations. Including `%`
* in the pattern matches zero or more characters, and including
* `_` will match a single character.
*
* ## Examples
*
* ```ts
* // Select all cars that don't have "Rover" in their name.
* db.select().from(cars)
* .where(notLike(cars.name, '%Rover%'))
* ```
*
* @see ilike for the inverse condition
* @see notLike for a case-sensitive version of this condition
*/
notIlike?: string;
/**
* Syntactic sugar for case-insensitive substring matching.
* Automatically wraps the value with `%` wildcards on both sides.
*
* Equivalent to: `ilike: '%value%'`
*
* ## Examples
*
* ```ts
* // Select all cars with "Turbo" anywhere in their name.
* db.select().from(cars)
* .where({ name: { contains: 'Turbo' } })
* // Same as: .where(ilike(cars.name, '%Turbo%'))
* ```
*
* @see ilike for manual pattern matching
* @see startsWith for prefix matching
* @see endsWith for suffix matching
*/
contains?: string;
/**
* Syntactic sugar for case-insensitive prefix matching.
* Automatically appends a `%` wildcard to the end of the value.
*
* Equivalent to: `ilike: 'value%'`
*
* ## Examples
*
* ```ts
* // Select all cars whose names start with "Ford".
* db.select().from(cars)
* .where({ name: { startsWith: 'Ford' } })
* // Same as: .where(ilike(cars.name, 'Ford%'))
* ```
*
* @see ilike for manual pattern matching
* @see contains for substring matching
* @see endsWith for suffix matching
*/
startsWith?: string;
/**
* Syntactic sugar for case-insensitive suffix matching.
* Automatically prepends a `%` wildcard to the beginning of the value.
*
* Equivalent to: `ilike: '%value'`
*
* ## Examples
*
* ```ts
* // Select all cars whose names end with "Turbo".
* db.select().from(cars)
* .where({ name: { endsWith: 'Turbo' } })
* // Same as: .where(ilike(cars.name, '%Turbo'))
* ```
*
* @see ilike for manual pattern matching
* @see contains for substring matching
* @see startsWith for prefix matching
*/
endsWith?: string;
/**
* Test that a column or expression contains all elements of
* the list passed as the second argument.
*
* ## Throws
*
* The argument passed in the second array can't be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select posts where its tags contain "Typescript" and "ORM".
* db.select().from(posts)
* .where(arrayContains(posts.tags, ['Typescript', 'ORM']))
* ```
*
* @see arrayContained to find if an array contains all elements of a column or expression
* @see arrayOverlaps to find if a column or expression contains any elements of an array
*/
arrayContains?: TValue;
/**
* Test that the list passed as the second argument contains
* all elements of a column or expression.
*
* ## Throws
*
* The argument passed in the second array can't be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select posts where its tags contain "Typescript", "ORM" or both,
* // but filtering posts that have additional tags.
* db.select().from(posts)
* .where(arrayContained(posts.tags, ['Typescript', 'ORM']))
* ```
*
* @see arrayContains to find if a column or expression contains all elements of an array
* @see arrayOverlaps to find if a column or expression contains any elements of an array
*/
arrayContained?: TValue;
/**
* Test that a column or expression contains any elements of
* the list passed as the second argument.
*
* ## Throws
*
* The argument passed in the second array can't be empty:
* if an empty is provided, this method will throw.
*
* ## Examples
*
* ```ts
* // Select posts where its tags contain "Typescript", "ORM" or both.
* db.select().from(posts)
* .where(arrayOverlaps(posts.tags, ['Typescript', 'ORM']))
* ```
*
* @see arrayContains to find if a column or expression contains all elements of an array
* @see arrayContained to find if an array contains all elements of a column or expression
*/
arrayOverlaps?: TValue;
}
//#endregion
//#region ../../src/orm/core/interfaces/PgQuery.d.ts
/**
* Order direction for sorting
*/
type OrderDirection = "asc" | "desc";
/**
* Single order by clause with column and direction
*/
interface OrderByClause<T> {
column: keyof T;
direction?: OrderDirection;
}
/**
* Order by parameter - supports 3 modes:
* 1. String: orderBy: "name" (defaults to ASC)
* 2. Single object: orderBy: { column: "name", direction: "desc" }
* 3. Array: orderBy: [{ column: "name", direction: "asc" }, { column: "age", direction: "desc" }]
*/
type OrderBy<T> = keyof T | OrderByClause<T> | Array<OrderByClause<T>>;
/**
* Generic query interface for PostgreSQL entities
*/
interface PgQuery<T extends TObject = TObject> {
distinct?: (keyof Static<T>)[];
columns?: (keyof Static<T>)[];
where?: PgQueryWhereOrSQL<T>;
limit?: number;
offset?: number;
orderBy?: OrderBy<Static<T>>;
groupBy?: (keyof Static<T>)[];
}
type PgStatic<T extends TObject, Relations extends PgRelationMap<T>> = Static<T> & { [K in keyof Relations]: Static<Relations[K]["join"]["schema"]> & (Relations[K]["with"] extends PgRelationMap<TObject> ? PgStatic<Relations[K]["join"]["schema"], Relations[K]["with"]> : {}); };
interface PgQueryRelations<T extends TObject = TObject, Relations extends PgRelationMap<T> | undefined = undefined> extends PgQuery<T> {
with?: Relations;
where?: PgQueryWhereOrSQL<T, Relations>;
}
type PgRelationMap<Base extends TObject> = Record<string, PgRelation<Base>>;
type PgRelation<Base extends TObject> = {
type?: "left" | "inner" | "right";
join: {
schema: TObject;
name: string;
};
on: SQLWrapper | readonly [keyof Static<Base>, {
name: string;
}];
with?: PgRelationMap<TObject>;
};
//#endregion
//#region ../../src/orm/core/interfaces/PgQueryWhere.d.ts
type PgQueryWhere<T extends TObject, Relations extends PgRelationMap<TObject> | undefined = undefined> = (PgQueryWhereOperators<T> & PgQueryWhereConditions<T>) | (PgQueryWhereRelations<Relations> & PgQueryWhereOperators<T> & PgQueryWhereConditions<T, Relations>);
type PgQueryWhereOrSQL<T extends TObject, Relations extends PgRelationMap<TObject> | undefined = undefined> = SQLWrapper | PgQueryWhere<T, Relations>;
type PgQueryWhereOperators<T extends TObject> = { [Key in keyof Static<T>]?: FilterOperators<Static<T>[Key]> | Static<T>[Key]; };
type PgQueryWhereConditions<T extends TObject, Relations extends PgRelationMap<TObject> | undefined = undefined> = {
/**
* Combine a list of conditions with the `and` operator. Conditions
* that are equal `undefined` are automatically ignored.
*
* ## Examples
*
* ```ts
* db.select().from(cars)
* .where(
* and(
* eq(cars.make, 'Volvo'),
* eq(cars.year, 1950),
* )
* )
* ```
*/
and?: Array<PgQueryWhereOrSQL<T, Relations>>;
/**
* Combine a list of conditions with the `or` operator. Conditions
* that are equal `undefined` are automatically ignored.
*
* ## Examples
*
* ```ts
* db.select().from(cars)
* .where(
* or(
* eq(cars.make, 'GM'),
* eq(cars.make, 'Ford'),
* )
* )
* ```
*/
or?: Array<PgQueryWhereOrSQL<T, Relations>>;
/**
* Negate the meaning of an expression using the `not` keyword.
*
* ## Examples
*
* ```ts
* // Select cars _not_ made by GM or Ford.
* db.select().from(cars)
* .where(not(inArray(cars.make, ['GM', 'Ford'])))
* ```
*/
not?: PgQueryWhereOrSQL<T, Relations>;
/**
* Test whether a subquery evaluates to have any rows.
*
* ## Examples
*
* ```ts
* // Users whose `homeCity` column has a match in a cities
* // table.
* db
* .select()
* .from(users)
* .where(
* exists(db.select()
* .from(cities)
* .where(eq(users.homeCity, cities.id))),
* );
* ```
*
* @see notExists for the inverse of this test
*/
exists?: SQLWrapper;
/**
* Test whether a subquery evaluates to have no rows.
*
* @see exists for the inverse of this test
*/
notExists?: SQLWrapper;
};
type PgQueryWhereRelations<Relations extends PgRelationMap<TObject> | undefined = undefined> = Relations extends PgRelationMap<TObject> ? { [K in keyof Relations]?: PgQueryWhere<Relations[K]["join"]["schema"], Relations[K]["with"]>; } : {};
//#endregion
//#region ../../src/orm/core/interfaces/AggregateQuery.d.ts
type AggregateOp = "count" | "sum" | "avg" | "min" | "max";
/**
* Select definition for aggregate queries.
* - `true` means select the column value as-is (used for groupBy columns).
* - `{ sum: true, avg: true, ... }` means compute those aggregations.
*/
type AggregateColumnSelect = true | Partial<Record<AggregateOp, true>>;
type AggregateSelect<T extends TObject> = { [K in keyof Static<T>]?: AggregateColumnSelect; };
/**
* Maps a single column's select definition to its result type.
* - `true` → original column type
* - `{ sum: true, avg: true }` → `{ sum: number; avg: number }`
*/
type AggregateColumnResult<TValue, TSelect> = TSelect extends true ? TValue : { [Op in AggregateOp as TSelect extends Record<Op, true> ? Op : never]: number; };
/**
* Result type for an aggregate query.
*/
type AggregateResult<T extends TObject, S extends AggregateSelect<T>> = { [K in keyof S & keyof Static<T>]: AggregateColumnResult<Static<T>[K], NonNullable<S[K]>>; };
/**
* HAVING clause for aggregate queries.
* Only applies to columns with aggregate operations (not `true`).
*/
type AggregateHaving<T extends TObject, S extends AggregateSelect<T>> = { [K in keyof S & keyof Static<T>]?: S[K] extends true ? never : { [Op in AggregateOp as S[K] extends Record<Op, true> ? Op : never]?: {
gt?: number;
gte?: number;
lt?: number;
lte?: number;
eq?: number;
ne?: number;
}; }; };
/**
* Full aggregate query definition.
*/
interface AggregateQuery<T extends TObject, S extends AggregateSelect<T>> {
/**
* Columns and aggregate operations to select.
*/
select: S;
/**
* WHERE clause to filter rows before aggregation.
*/
where?: PgQueryWhereOrSQL<T>;
/**
* Columns to group by.
*/
groupBy?: (keyof Static<T>)[];
/**
* HAVING clause to filter groups after aggregation.
*/
having?: AggregateHaving<T, S>;
/**
* Order results. Supports dot notation for aggregate columns (e.g. "amount.sum").
*/
orderBy?: string | {
column: string;
direction: "asc" | "desc";
} | Array<{
column: string;
direction: "asc" | "desc";
}>;
/**
* Limit the number of results.
*/
limit?: number;
/**
* Offset for pagination.
*/
offset?: number;
}
//#endregion
//#region ../../src/orm/core/providers/DatabaseTypeProvider.d.ts
declare class DatabaseTypeProvider {
readonly attr: typeof pgAttr;
/**
* Creates a primary key with an identity column.
*/
readonly identityPrimaryKey: (identity?: PgIdentityOptions) => PgAttr<PgAttr<PgAttr<import("zod").ZodInt, typeof PG_PRIMARY_KEY>, typeof PG_IDENTITY>, typeof PG_DEFAULT>;
/**
* Creates a primary key with a big identity column. (default)
*/
readonly bigIdentityPrimaryKey: (identity?: PgIdentityOptions) => PgAttr<PgAttr<PgAttr<import("zod").ZodInt, typeof PG_PRIMARY_KEY>, typeof PG_IDENTITY>, typeof PG_DEFAULT>;
/**
* Creates a primary key with a UUID column.
*/
readonly uuidPrimaryKey: () => PgAttr<PgAttr<import("zod").ZodString, typeof PG_PRIMARY_KEY>, typeof PG_DEFAULT>;
/**
* Creates a primary key for a given type. Supports:
* - `t.integer()` -> PG INT (default)
* - `t.bigint()` -> PG BIGINT
* - `t.uuid()` -> PG UUID
*/
primaryKey(): PgAttr<PgAttr<TInteger, PgPrimaryKey>, PgDefault>;
primaryKey(type: TString, options?: TStringOptions): PgAttr<PgAttr<TString, PgPrimaryKey>, PgDefault>;
primaryKey(type: TInteger, options?: TNumberOptions, identity?: PgIdentityOptions): PgAttr<PgAttr<TInteger, PgPrimaryKey>, PgDefault>;
primaryKey(type: TNumber, options?: TNumberOptions, identity?: PgIdentityOptions): PgAttr<PgAttr<TNumber, PgPrimaryKey>, PgDefault>;
primaryKey(type: TBigInt, options?: TNumberOptions, identity?: PgIdentityOptions): PgAttr<PgAttr<TBigInt, PgPrimaryKey>, PgDefault>;
/**
* Wrap a schema with "default" attribute.
* This is used to set a default value for a column in the database.
*/
readonly default: <T extends TSchema>(type: T, value?: Static<T>) => PgAttr<T, PgDefault>;
/**
* Creates a column 'version'.
*
* This is used to track the version of a row in the database.
*
* You can use it for optimistic concurrency control (OCC) with {@link RepositoryPrimitive#save}.
*
* @see {@link RepositoryPrimitive#save}
* @see {@link PgVersionMismatchError}
*/
readonly version: () => PgAttr<PgAttr<import("zod").ZodInt, typeof PG_VERSION>, typeof PG_DEFAULT>;
/**
* Creates a column Created At. So just a datetime column with a default value of the current timestamp.
*/
readonly createdAt: () => PgAttr<PgAttr<import("zod").ZodString, typeof PG_CREATED_AT>, typeof PG_DEFAULT>;
/**
* Creates a column Updated At. Like createdAt, but it is updated on every update of the row.
*/
readonly updatedAt: () => PgAttr<PgAttr<import("zod").ZodString, typeof PG_UPDATED_AT>, typeof PG_DEFAULT>;
/**
* Creates a column Deleted At for soft delete functionality.
* This is used to mark rows as deleted without actually removing them from the database.
* The column is nullable - NULL means not deleted, timestamp means deleted.
*/
readonly deletedAt: () => PgAttr<import("zod").ZodOptional<import("zod").ZodString>, typeof PG_DELETED_AT>;
/**
* Creates an organization column for multi-tenant row scoping.
*
* When present, queries are automatically filtered by the current user's organization.
* On create, the column is auto-stamped with the current user's organization.
*
* @param options.nullable - When `false`, the column is NOT NULL in the database and
* the ORM rejects inserts that arrive without an organization context.
* Defaults to `true` (nullable) — unless `strict` is set, which flips the
* default to non-nullable. NULL rows are visible to every tenant (the
* historic "global row" semantics) only when the column is nullable AND
* not strict.
* @param options.strict - Fail-closed tenant scoping for security-sensitive
* tables. Refuses reads/writes with no resolved tenant (instead of a
* fail-open "see/write everything") and drops the `OR org IS NULL` escape
* so a scoped tenant never sees global rows. Defaults to `false`.
*/
readonly organization: (options?: {
nullable?: boolean;
strict?: boolean;
}) => PgAttr<import("zod").ZodOptional<import("zod").ZodString> | import("zod").ZodString, typeof PG_ORGANIZATION>;
/**
* Creates a reference to another table or schema. Basically a foreign key.
*/
readonly ref: <T extends TSchema>(type: T, ref: () => any, actions?: {
onUpdate?: UpdateDeleteAction$1;
onDelete?: UpdateDeleteAction$1;
}) => PgAttr<T, PgRef>;
/**
* Creates a page schema for a given object schema.
* It's used by {@link Repository#paginate} method.
*/
readonly page: <T extends TObject>(resource: T) => TPage<T>;
}
/**
* Wrapper of TypeProvider (`t`) for database types.
*
* Use `db` for improve TypeBox schema definitions with database-specific attributes.
*
* @example
* ```ts
* import { t } from "alepha";
* import { db } from "alepha/orm";
*
* const userSchema = t.object({
* id: db.primaryKey(t.uuid()),
* email: t.email(),
* createdAt: db.createdAt(),
* });
* ```
*/
declare const db: DatabaseTypeProvider;
//#endregion
//#region ../../src/orm/core/schemas/legacyIdSchema.d.ts
/**
* @deprecated Use `pg.primaryKey()` instead.
*/
declare const legacyIdSchema: PgAttr<PgAttr<PgAttr<import("zod").ZodInt, typeof PG_PRIMARY_KEY>, typeof PG_SERIAL>, typeof PG_DEFAULT>;
//#endregion
//#region ../../src/orm/core/entities/alephaSequences.d.ts
/**
* Storage table for the {@link SequenceProvider}.
*
* Each row represents one counter, identified by `(name, scope)`:
* - `name` is the sequence primitive name (defaulted from its property key).
* - `scope` is an arbitrary string passed by the caller, defaulted to "default"
* for the global, unscoped form. Use this column to namespace per-tenant /
* per-campaign / per-anything counters off the same primitive.
* - `value` is the current counter value. Incremented atomically by
* `SequenceProvider.advance()` through an `INSERT ... ON CONFLICT DO UPDATE`
* on `(name, scope)` — works identically on Postgres, SQLite, and D1.
*/
declare const alephaSequences: EntityPrimitive<import("zod").ZodObject<{
id: PgAttr<PgAttr<import("zod").ZodString, typeof PG_PRIMARY_KEY>, typeof PG_DEFAULT>;
createdAt: PgAttr<PgAttr<import("zod").ZodString, typeof PG_CREATED_AT>, typeof PG_DEFAULT>;
updatedAt: PgAttr<PgAttr<import("zod").ZodString, typeof PG_UPDATED_AT>, typeof PG_DEFAULT>;
name: import("zod").ZodString;
scope: import("zod").ZodString;
value: import("zod").ZodInt;
}, import("zod/v4/core").$strip>>;
type AlephaSequence = Static<typeof alephaSequences.schema>;
//#endregion
//#region ../../src/orm/core/errors/DbConflictError.d.ts
declare class DbConflictError extends DbError {
readonly name = "DbConflictError";
readonly status = 409;
}
//#endregion
//#region ../../src/orm/core/errors/DbMigrationError.d.ts
declare class DbMigrationError extends DbError {
readonly name = "DbMigrationError";
constructor(cause?: unknown);
}
//#endregion
//#region ../../src/orm/core/errors/DbVersionMismatchError.d.ts
/**
* Error thrown when there is a version mismatch.
* It's thrown by {@link Repository#save} when the updated entity version does not match the one in the database.
* This is used for optimistic concurrency control.
*/
declare class DbVersionMismatchError extends DbError {
readonly name = "DbVersionMismatchError";
constructor(table: string, id: any);
}
//#endregion
//#region ../../src/orm/core/providers/DbCacheProvider.d.ts
/**
* Database query cache using a simple in-memory Map.
*
* Uses `{tableName}:{cacheKey}` as the storage key.
* Provides per-table invalidation for write-through cache busting.
*
* This is intentionally self-contained (no external cache dependencies)
* so the ORM module does not force `AlephaCache` on all consumers.
*/
declare class DbCacheProvider {
protected readonly dateTime: DateTimeProvider;
protected readonly store: Map<string, {
value: unknown;
expiresAt?: number;
}>;
protected storeKey(tableName: string, cacheKey: string): string;
/**
* Get a cached query result.
*/
get<T>(tableName: string, cacheKey: string): Promise<T | undefined>;
/**
* Store a query result in the cache.
*/
set<T>(tableName: string, cacheKey: string, value: T, ttl?: number): Promise<void>;
/**
* Invalidate all cached queries for a table.
*/
invalidateTable(tableName: string): Promise<void>;
}
//#endregion
//#region ../../src/orm/core/services/ModelBuilder.d.ts
/**
* Database-specific table configuration functions
*/
interface TableConfigBuilders<TConfig> {
index: (name: string) => {
on: (...columns: any[]) => TConfig;
};
uniqueIndex: (name: string) => {
on: (...columns: any[]) => TConfig;
};
unique: (name: string) => {
on: (...columns: any[]) => TConfig;
};
check: (name: string, sql: SQL) => TConfig;
foreignKey: (config: {
name: string;
columns: any[];
foreignColumns: any[];
}) => TConfig;
}
/**
* Abstract base class for transforming Alepha Primitives (Entity, Sequence, etc...)
* into drizzle models (tables, enums, sequences, etc...).
*/
declare abstract class ModelBuilder {
/**
* Build a table from an entity primitive.
*/
abstract buildTable(entity: EntityPrimitive, options: {
tables: Map<string, unknown>;
enums: Map<string, unknown>;
schemas: Map<string, unknown>;
schema: string;
}): void;
/**
* Build a sequence from a sequence primitive.
*/
abstract buildSequence(sequence: SequencePrimitive, options: {
sequences: Map<string, unknown>;
schema: string;
}): void;
/**
* Convert camelCase to snake_case for column names.
*/
protected toColumnName(str: string): string;
/**
* Build the table configuration function for any database.
* This includes indexes, foreign keys, constraints, and custom config.
*
* @param entity - The entity primitive
* @param builders - Database-specific builder functions
* @param tableResolver - Function to resolve entity references to table columns
* @param customConfigHandler - Optional handler for custom config
*/
protected buildTableConfig<TConfig, TSelf>(entity: EntityPrimitive, builders: TableConfigBuilders<TConfig>, tableResolver?: (entityName: string) => any, customConfigHandler?: (config: any, self: TSelf) => TConfig[]): ((self: TSelf) => TConfig[]) | undefined;
}
//#endregion
//#region ../../src/orm/core/providers/DrizzleKitProvider.d.ts
declare class DrizzleKitProvider {
protected readonly log: import("alepha/logger").Logger;
protected readonly dateTime: DateTimeProvider;
protected readonly alepha: Alepha;
/**
* Push-based synchronization using Drizzle Kit's introspection API.
*
* Reads the actual database state, diffs against current entity definitions,
* and applies changes. No stored snapshots — no drift, no corruption.
*
* - SQLite: uses `pushSQLiteSchema` (requires sync driver — node:sqlite shim or bun-sqlite)
* - PostgreSQL: uses `pushSchema` with schema filters
*
* Does nothing in production mode — use file-based migrations instead.
*/
synchronize(provider: DatabaseProvider): Promise<void>;
/**
* Generate SQL migration statements by diffing two schema states.
*
* Used by tests (schema validation) and CLI (`alepha db migrations generate`).
* Not part of the push sync flow.
*
* When `withoutSchema` is true, models are rebuilt without schema qualifiers
* so the generated SQL is portable across different PostgreSQL schemas.
*/
generateMigration(provider: DatabaseProvider, prevSnapshot?: any, options?: {
withoutSchema?: boolean;
}): Promise<{
statements: string[];
models: Record<string, unknown>;
snapshot?: any;
}>;
/**
* Load all tables, enums, sequences, etc. from the provider's repositories.
*/
getModels(provider: DatabaseProvider): Record<string, unknown>;
/**
* Build schema-free models for migration generation.
*
* Rebuilds all entities with `schema = "public"` so Drizzle produces
* SQL without schema qualifiers (e.g. `CREATE TABLE "users"` instead
* of `CREATE TABLE "myschema"."users"`).
*
* The actual schema is applied at migration execution time via `search_path`.
*/
getModelsWithoutSchema(provider: DatabaseProvider): Record<string, unknown>;
/**
* Preview schema push without executing any statements.
*
* Returns the SQL statements that would be executed, warnings, and
* whether data loss would occur. Does NOT execute any SQL.
*/
dryRunPush(provider: DatabaseProvider): Promise<{
statements: string[];
warnings: string[];
hasDataLoss: boolean;
}>;
protected pushSqlite(kit: typeof DrizzleKit, models: Record<string, unknown>, provider: DatabaseProvider): Promise<void>;
/**
* Push schema changes to PostgreSQL using Drizzle Kit's pushSchema with schema filters.
*/
protected pushPostgres(kit: typeof DrizzleKit, models: Record<string, unknown>, provider: DatabaseProvider): Promise<void>;
/**
* Execute a list of SQL statements against the provider.
*/
protected executeStatements(statements: string[], provider: DatabaseProvider): Promise<void>;
/**
* Execute SQL statements, ignoring "already exists" errors.
*
* Used by the fallback migration path where push may have partially
* applied changes before erroring, leaving some objects already created.
*/
protected executeStatementsLenient(statements: string[], provider: DatabaseProvider): Promise<void>;
protected createSchemaIfNotExists(provider: DatabaseProvider, schemaName: string): Promise<void>;
/**
* Wrap a Drizzle PgDatabase instance for compatibility with Drizzle Kit.
*
* Drizzle Kit's pushSchema expects execute() to return { rows: T[] }
* (node-postgres/pg format), but postgres.js returns a Result that
* extends Array directly — no .rows property.
*/
protected wrapDbForDrizzleKit(db: any): any;
/**
* Try to load the official Drizzle Kit API.
*/
importDrizzleKit(): typeof DrizzleKit;
}
//#endregion
//#region ../../src/orm/core/providers/drivers/DatabaseProvider.d.ts
type SQLLike = SQLWrapper | string;
declare abstract class DatabaseProvider {
protected readonly alepha: Alepha;
protected readonly dateTime: DateTimeProv