tempest-db-js 0.2.0 → 0.4.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.cts CHANGED
@@ -380,14 +380,14 @@ declare function del<C extends ModelClass>(model: C): DeleteBuilder<InferModel<C
380
380
  * detection, so URLs copied from a Python service still work here.
381
381
  */
382
382
  /** A database dialect tempest-db-js can target. */
383
- type Dialect = "sqlite" | "postgresql";
383
+ type Dialect = "sqlite" | "postgresql" | "mysql";
384
384
  /** A parsed database URL, dialect-neutral. */
385
385
  interface ParsedDatabaseUrl {
386
386
  /** The detected dialect. */
387
387
  readonly dialect: Dialect;
388
388
  /** Driver after the `+` in the scheme (e.g. `better-sqlite3`), or `null`. */
389
389
  readonly driver: string | null;
390
- /** Host (PostgreSQL), or `null` for SQLite. */
390
+ /** Host (PostgreSQL/MySQL), or `null` for SQLite. */
391
391
  readonly host: string | null;
392
392
  /** Port, or `null`. */
393
393
  readonly port: number | null;
@@ -610,7 +610,7 @@ type QueryNode = SelectNode | InsertNode | UpdateNode | DeleteNode | JoinNode;
610
610
  * actually differs between databases (placeholder syntax, `ILIKE` support).
611
611
  */
612
612
  declare abstract class BaseDialect {
613
- abstract readonly name: "sqlite" | "postgresql";
613
+ abstract readonly name: Dialect;
614
614
  /**
615
615
  * INSERT SQL templates keyed by structure (dialect|table|columns|rowCount|
616
616
  * returning). Shared across dialect instances — the key namespaces by dialect
@@ -647,10 +647,19 @@ declare abstract class BaseDialect {
647
647
  * So a per-row insert loop compiles the string once and reuses it every row.
648
648
  */
649
649
  private insertTemplate;
650
+ /**
651
+ * Render the conflict-handling clause. Standard SQL (SQLite/PostgreSQL) uses
652
+ * `ON CONFLICT (...) DO NOTHING | DO UPDATE SET ...`; MySQL overrides this.
653
+ *
654
+ * @param onConflict The conflict clause from the node.
655
+ * @param conflictCols The columns to overwrite on `DO UPDATE` (empty for nothing).
656
+ * @param nextPlaceholder Yields the next positional placeholder (advances the count).
657
+ */
658
+ protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[], nextPlaceholder: () => string): string;
650
659
  private compileUpdate;
651
660
  private compileDelete;
652
661
  private compileJoin;
653
- private compileReturning;
662
+ protected compileReturning(returning: readonly string[] | "*" | null): string;
654
663
  /**
655
664
  * Compile a condition tree (fields / and / or / not) to SQL. `idFor` renders a
656
665
  * key to a quoted identifier — `quoteId` for single-table, `qualify` for joins —
@@ -672,8 +681,21 @@ declare class PostgresDialect extends BaseDialect {
672
681
  protected placeholder(index: number): string;
673
682
  protected ilike(column: string, param: string): string;
674
683
  }
684
+ /**
685
+ * MySQL dialect: `?` placeholders, backtick identifiers, `ON DUPLICATE KEY
686
+ * UPDATE` for upsert, and case-insensitive `LIKE` (default collation). MySQL has
687
+ * no `RETURNING`, so requesting it throws.
688
+ */
689
+ declare class MysqlDialect extends BaseDialect {
690
+ readonly name: "mysql";
691
+ protected placeholder(): string;
692
+ protected ilike(column: string, param: string): string;
693
+ protected quoteId(name: string): string;
694
+ protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[], nextPlaceholder: () => string): string;
695
+ protected compileReturning(returning: readonly string[] | "*" | null): string;
696
+ }
675
697
  /** Get a dialect instance by name. */
676
- declare function getDialect(name: "sqlite" | "postgresql"): BaseDialect;
698
+ declare function getDialect(name: Dialect): BaseDialect;
677
699
 
678
700
  /** The outcome of running one statement. */
679
701
  interface DriverResult {
@@ -1135,6 +1157,11 @@ interface ColumnFlags {
1135
1157
  readonly primaryKey: boolean;
1136
1158
  readonly notNull: boolean;
1137
1159
  readonly hasDefault: boolean;
1160
+ /**
1161
+ * A `UNIQUE` constraint on the column. Does NOT influence the inferred type —
1162
+ * it is DDL-only metadata (mirrors SQLAlchemy's `mapped_column(unique=True)`).
1163
+ */
1164
+ readonly unique: boolean;
1138
1165
  }
1139
1166
  /**
1140
1167
  * The canonical, dialect-neutral kind of a column type. Mirrors SQLAlchemy's
@@ -1196,9 +1223,31 @@ declare const sql: {
1196
1223
  /** Escape hatch: a verbatim SQL expression rendered as-is. */
1197
1224
  readonly raw: (expression: string) => DefaultValue;
1198
1225
  };
1226
+ /**
1227
+ * A referential action for a foreign key's `ON DELETE` / `ON UPDATE` clause.
1228
+ * Dialect-neutral tokens rendered uppercase at the DDL edge (mirrors
1229
+ * SQLAlchemy's `ForeignKey(ondelete=..., onupdate=...)`).
1230
+ */
1231
+ type FkAction = "cascade" | "restrict" | "set null" | "set default" | "no action";
1232
+ /**
1233
+ * A resolved foreign-key reference: the target `table.column` plus optional
1234
+ * referential actions. Produced by `Column.references("table.column", ...)`.
1235
+ */
1236
+ interface ForeignKeyRef {
1237
+ readonly table: string;
1238
+ readonly column: string;
1239
+ readonly onDelete?: FkAction | undefined;
1240
+ readonly onUpdate?: FkAction | undefined;
1241
+ }
1242
+ /** Options for a foreign-key reference (referential actions). */
1243
+ interface ForeignKeyOptions {
1244
+ readonly onDelete?: FkAction | undefined;
1245
+ readonly onUpdate?: FkAction | undefined;
1246
+ }
1199
1247
  /**
1200
1248
  * A typed column builder. Holds runtime metadata (structured `type`, `flags`,
1201
- * `default`, `onUpdate`) and a phantom static type `T` used purely for inference.
1249
+ * `default`, `onUpdate`, foreign-key `reference`) and a phantom static type `T`
1250
+ * used purely for inference.
1202
1251
  */
1203
1252
  declare class Column<T, F extends ColumnFlags = ColumnFlags> {
1204
1253
  readonly type: ColumnType;
@@ -1207,13 +1256,17 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
1207
1256
  readonly defaultValue: DefaultValue | null;
1208
1257
  /** The value re-applied on update (e.g. `updated_at`), or `null`. */
1209
1258
  readonly onUpdateValue: DefaultValue | null;
1259
+ /** The foreign-key reference this column points to, or `null` for none. */
1260
+ readonly reference: ForeignKeyRef | null;
1210
1261
  /** Phantom: never read at runtime, only inspected by the type system. */
1211
1262
  readonly [TYPE]: T;
1212
1263
  constructor(type: ColumnType, flags: F,
1213
1264
  /** The default applied on insert, or `null` for none. */
1214
1265
  defaultValue?: DefaultValue | null,
1215
1266
  /** The value re-applied on update (e.g. `updated_at`), or `null`. */
1216
- onUpdateValue?: DefaultValue | null);
1267
+ onUpdateValue?: DefaultValue | null,
1268
+ /** The foreign-key reference this column points to, or `null` for none. */
1269
+ reference?: ForeignKeyRef | null);
1217
1270
  primaryKey(): Column<T, F & {
1218
1271
  primaryKey: true;
1219
1272
  hasDefault: true;
@@ -1221,6 +1274,24 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
1221
1274
  notNull(): Column<T, F & {
1222
1275
  notNull: true;
1223
1276
  }>;
1277
+ /**
1278
+ * Add a `UNIQUE` constraint to the column (mirrors SQLAlchemy's
1279
+ * `mapped_column(unique=True)`). DDL-only — does not change the inferred type.
1280
+ */
1281
+ unique(): Column<T, F & {
1282
+ unique: true;
1283
+ }>;
1284
+ /**
1285
+ * Declare a foreign-key reference to another table's column, à la SQLAlchemy's
1286
+ * `mapped_column(ForeignKey("table.column", ondelete=...))`. DDL-only — does
1287
+ * not change the inferred type.
1288
+ *
1289
+ * @param ref The target as `"table.column"` (e.g. `"users.id"`).
1290
+ * @param options Optional `onDelete` / `onUpdate` referential actions.
1291
+ * @returns A new column carrying the reference.
1292
+ * @throws Error When `ref` is not a valid `"table.column"` string.
1293
+ */
1294
+ references(ref: string, options?: ForeignKeyOptions): Column<T, F>;
1224
1295
  /**
1225
1296
  * Set the insert-time default: a constant value of type `T`, or a portable
1226
1297
  * server-side expression from {@link sql} (e.g. `sql.now()`, `sql.uuidv4()`).
@@ -1300,9 +1371,58 @@ declare const column: {
1300
1371
  /** `ENUM(...values)` → a string-literal union of the given values. */
1301
1372
  readonly enum: <const E extends string>(...values: E[]) => Column<E, ColumnFlags>;
1302
1373
  };
1374
+ /**
1375
+ * A table-level constraint declared via a model's `static tableArgs`. Mirrors
1376
+ * SQLAlchemy's `__table_args__` entries (`UniqueConstraint`, `ForeignKeyConstraint`).
1377
+ * Use the {@link unique} and {@link foreignKey} helpers to build these.
1378
+ */
1379
+ type TableConstraint = {
1380
+ readonly kind: "unique";
1381
+ readonly name?: string | undefined;
1382
+ readonly columns: readonly string[];
1383
+ } | {
1384
+ readonly kind: "foreignKey";
1385
+ readonly name?: string | undefined;
1386
+ readonly columns: readonly string[];
1387
+ readonly refTable: string;
1388
+ readonly refColumns: readonly string[];
1389
+ readonly onDelete?: FkAction | undefined;
1390
+ readonly onUpdate?: FkAction | undefined;
1391
+ };
1392
+ /**
1393
+ * Declare a (possibly composite) `UNIQUE` table constraint over the given
1394
+ * columns. Mirrors SQLAlchemy's `UniqueConstraint("a", "b")`.
1395
+ *
1396
+ * @param columns The column names covered by the constraint.
1397
+ * @returns A unique {@link TableConstraint}.
1398
+ * @throws Error When no columns are given.
1399
+ */
1400
+ declare function unique(...columns: string[]): TableConstraint;
1401
+ /**
1402
+ * Declare a (possibly composite) foreign-key table constraint. Mirrors
1403
+ * SQLAlchemy's `ForeignKeyConstraint([...], [...], ondelete=...)`.
1404
+ *
1405
+ * @param columns The local column names.
1406
+ * @param refTable The referenced table name.
1407
+ * @param refColumns The referenced column names (same length as `columns`).
1408
+ * @param options Optional constraint `name` and referential actions.
1409
+ * @returns A foreign-key {@link TableConstraint}.
1410
+ * @throws Error When the column arrays are empty or mismatched in length.
1411
+ */
1412
+ declare function foreignKey(columns: string[], refTable: string, refColumns: string[], options?: {
1413
+ name?: string;
1414
+ onDelete?: FkAction;
1415
+ onUpdate?: FkAction;
1416
+ }): TableConstraint;
1303
1417
  /** Base class every model extends, SQLAlchemy-declarative style. */
1304
1418
  declare abstract class Model {
1305
1419
  static tablename: string;
1420
+ /**
1421
+ * Optional table-level constraints (composite unique / foreign keys), returned
1422
+ * by a thunk so forward references resolve lazily. Mirrors SQLAlchemy's
1423
+ * `__table_args__`.
1424
+ */
1425
+ static tableArgs?: () => readonly TableConstraint[];
1306
1426
  }
1307
1427
  /**
1308
1428
  * Reflect a model class into its column map at runtime, keyed by column name.
@@ -1327,6 +1447,7 @@ type ColumnKeys<M> = {
1327
1447
  /** Constructor type for a Model subclass. */
1328
1448
  type ModelClass = (new () => Model) & {
1329
1449
  tablename: string;
1450
+ tableArgs?: () => readonly TableConstraint[];
1330
1451
  };
1331
1452
  /** Flatten an intersection into a single object literal for clean inference. */
1332
1453
  type Simplify<T> = {
@@ -1364,4 +1485,4 @@ type InferInsert<C extends ModelClass> = Simplify<{
1364
1485
  [K in Exclude<ColumnKeys<InstanceType<C>>, OptionalInsertKeys<InstanceType<C>>>]: ColValue<InstanceType<C>[K]>;
1365
1486
  }>;
1366
1487
 
1367
- export { ActiveRecord, type ActiveRecordManager, Agg, type AggregateTerm, type AsyncDriver, AsyncEngine, AsyncResult, AsyncSession, BaseDialect, BaseRepository, type BelongsTo, type ColRef, type ColType, Column, type ColumnFlags, type ColumnType, type ColumnTypeKind, type ColumnTypeMeta, type CompiledQuery, type CondNode, type Condition, type DefaultValue, DeleteBuilder, type DeleteNode, type Dialect, type DriverResult, type EngineOptions, type Executable, type HasMany, type InferInsert, type InferModel, InsertBuilder, type InsertNode, InvalidDatabaseUrl, JoinBuilder, type JoinClause, type JoinNode, type JoinOn, type JoinSelection, type JoinWhereInput, Model, type ModelClass, NoResultError, NodeSqliteDriver, OPERATORS, type OnConflict, type Operator, type OperatorsFor, type OrderTerm, type PaginationFilter, type PaginationResult, type ParsedDatabaseUrl, type PoolOptions, type PortableExpression, PostgresDialect, QueryExecutionError, type QueryLogger, type QueryNode, RecordNotFound, type Relation, type RelationValue, type ReservedAsyncDriver, type Returning, type RowOf, SelectBuilder, type SelectNode, type SortDirection, type Sources, SqliteDialect, type SyncDriver, SyncEngine, SyncResult, SyncSession, UpdateBuilder, type UpdateNode, ValidationError, type WhereArg, type WhereInput, type WithRelations, activeRecord, and, avg, belongsTo, column, columnsOf, count, createEngine, createSyncEngine, del, detectDialect, fromDict, getDialect, hasMany, insert, isCondition, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toCondNode, toDict, toJSON, update };
1488
+ export { ActiveRecord, type ActiveRecordManager, Agg, type AggregateTerm, type AsyncDriver, AsyncEngine, AsyncResult, AsyncSession, BaseDialect, BaseRepository, type BelongsTo, type ColRef, type ColType, Column, type ColumnFlags, type ColumnType, type ColumnTypeKind, type ColumnTypeMeta, type CompiledQuery, type CondNode, type Condition, type DefaultValue, DeleteBuilder, type DeleteNode, type Dialect, type DriverResult, type EngineOptions, type Executable, type FkAction, type ForeignKeyOptions, type ForeignKeyRef, type HasMany, type InferInsert, type InferModel, InsertBuilder, type InsertNode, InvalidDatabaseUrl, JoinBuilder, type JoinClause, type JoinNode, type JoinOn, type JoinSelection, type JoinWhereInput, Model, type ModelClass, MysqlDialect, NoResultError, NodeSqliteDriver, OPERATORS, type OnConflict, type Operator, type OperatorsFor, type OrderTerm, type PaginationFilter, type PaginationResult, type ParsedDatabaseUrl, type PoolOptions, type PortableExpression, PostgresDialect, QueryExecutionError, type QueryLogger, type QueryNode, RecordNotFound, type Relation, type RelationValue, type ReservedAsyncDriver, type Returning, type RowOf, SelectBuilder, type SelectNode, type SortDirection, type Sources, SqliteDialect, type SyncDriver, SyncEngine, SyncResult, SyncSession, type TableConstraint, UpdateBuilder, type UpdateNode, ValidationError, type WhereArg, type WhereInput, type WithRelations, activeRecord, and, avg, belongsTo, column, columnsOf, count, createEngine, createSyncEngine, del, detectDialect, foreignKey, fromDict, getDialect, hasMany, insert, isCondition, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toCondNode, toDict, toJSON, unique, update };
package/dist/index.d.ts CHANGED
@@ -380,14 +380,14 @@ declare function del<C extends ModelClass>(model: C): DeleteBuilder<InferModel<C
380
380
  * detection, so URLs copied from a Python service still work here.
381
381
  */
382
382
  /** A database dialect tempest-db-js can target. */
383
- type Dialect = "sqlite" | "postgresql";
383
+ type Dialect = "sqlite" | "postgresql" | "mysql";
384
384
  /** A parsed database URL, dialect-neutral. */
385
385
  interface ParsedDatabaseUrl {
386
386
  /** The detected dialect. */
387
387
  readonly dialect: Dialect;
388
388
  /** Driver after the `+` in the scheme (e.g. `better-sqlite3`), or `null`. */
389
389
  readonly driver: string | null;
390
- /** Host (PostgreSQL), or `null` for SQLite. */
390
+ /** Host (PostgreSQL/MySQL), or `null` for SQLite. */
391
391
  readonly host: string | null;
392
392
  /** Port, or `null`. */
393
393
  readonly port: number | null;
@@ -610,7 +610,7 @@ type QueryNode = SelectNode | InsertNode | UpdateNode | DeleteNode | JoinNode;
610
610
  * actually differs between databases (placeholder syntax, `ILIKE` support).
611
611
  */
612
612
  declare abstract class BaseDialect {
613
- abstract readonly name: "sqlite" | "postgresql";
613
+ abstract readonly name: Dialect;
614
614
  /**
615
615
  * INSERT SQL templates keyed by structure (dialect|table|columns|rowCount|
616
616
  * returning). Shared across dialect instances — the key namespaces by dialect
@@ -647,10 +647,19 @@ declare abstract class BaseDialect {
647
647
  * So a per-row insert loop compiles the string once and reuses it every row.
648
648
  */
649
649
  private insertTemplate;
650
+ /**
651
+ * Render the conflict-handling clause. Standard SQL (SQLite/PostgreSQL) uses
652
+ * `ON CONFLICT (...) DO NOTHING | DO UPDATE SET ...`; MySQL overrides this.
653
+ *
654
+ * @param onConflict The conflict clause from the node.
655
+ * @param conflictCols The columns to overwrite on `DO UPDATE` (empty for nothing).
656
+ * @param nextPlaceholder Yields the next positional placeholder (advances the count).
657
+ */
658
+ protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[], nextPlaceholder: () => string): string;
650
659
  private compileUpdate;
651
660
  private compileDelete;
652
661
  private compileJoin;
653
- private compileReturning;
662
+ protected compileReturning(returning: readonly string[] | "*" | null): string;
654
663
  /**
655
664
  * Compile a condition tree (fields / and / or / not) to SQL. `idFor` renders a
656
665
  * key to a quoted identifier — `quoteId` for single-table, `qualify` for joins —
@@ -672,8 +681,21 @@ declare class PostgresDialect extends BaseDialect {
672
681
  protected placeholder(index: number): string;
673
682
  protected ilike(column: string, param: string): string;
674
683
  }
684
+ /**
685
+ * MySQL dialect: `?` placeholders, backtick identifiers, `ON DUPLICATE KEY
686
+ * UPDATE` for upsert, and case-insensitive `LIKE` (default collation). MySQL has
687
+ * no `RETURNING`, so requesting it throws.
688
+ */
689
+ declare class MysqlDialect extends BaseDialect {
690
+ readonly name: "mysql";
691
+ protected placeholder(): string;
692
+ protected ilike(column: string, param: string): string;
693
+ protected quoteId(name: string): string;
694
+ protected renderConflict(onConflict: NonNullable<InsertNode["onConflict"]>, conflictCols: readonly string[], nextPlaceholder: () => string): string;
695
+ protected compileReturning(returning: readonly string[] | "*" | null): string;
696
+ }
675
697
  /** Get a dialect instance by name. */
676
- declare function getDialect(name: "sqlite" | "postgresql"): BaseDialect;
698
+ declare function getDialect(name: Dialect): BaseDialect;
677
699
 
678
700
  /** The outcome of running one statement. */
679
701
  interface DriverResult {
@@ -1135,6 +1157,11 @@ interface ColumnFlags {
1135
1157
  readonly primaryKey: boolean;
1136
1158
  readonly notNull: boolean;
1137
1159
  readonly hasDefault: boolean;
1160
+ /**
1161
+ * A `UNIQUE` constraint on the column. Does NOT influence the inferred type —
1162
+ * it is DDL-only metadata (mirrors SQLAlchemy's `mapped_column(unique=True)`).
1163
+ */
1164
+ readonly unique: boolean;
1138
1165
  }
1139
1166
  /**
1140
1167
  * The canonical, dialect-neutral kind of a column type. Mirrors SQLAlchemy's
@@ -1196,9 +1223,31 @@ declare const sql: {
1196
1223
  /** Escape hatch: a verbatim SQL expression rendered as-is. */
1197
1224
  readonly raw: (expression: string) => DefaultValue;
1198
1225
  };
1226
+ /**
1227
+ * A referential action for a foreign key's `ON DELETE` / `ON UPDATE` clause.
1228
+ * Dialect-neutral tokens rendered uppercase at the DDL edge (mirrors
1229
+ * SQLAlchemy's `ForeignKey(ondelete=..., onupdate=...)`).
1230
+ */
1231
+ type FkAction = "cascade" | "restrict" | "set null" | "set default" | "no action";
1232
+ /**
1233
+ * A resolved foreign-key reference: the target `table.column` plus optional
1234
+ * referential actions. Produced by `Column.references("table.column", ...)`.
1235
+ */
1236
+ interface ForeignKeyRef {
1237
+ readonly table: string;
1238
+ readonly column: string;
1239
+ readonly onDelete?: FkAction | undefined;
1240
+ readonly onUpdate?: FkAction | undefined;
1241
+ }
1242
+ /** Options for a foreign-key reference (referential actions). */
1243
+ interface ForeignKeyOptions {
1244
+ readonly onDelete?: FkAction | undefined;
1245
+ readonly onUpdate?: FkAction | undefined;
1246
+ }
1199
1247
  /**
1200
1248
  * A typed column builder. Holds runtime metadata (structured `type`, `flags`,
1201
- * `default`, `onUpdate`) and a phantom static type `T` used purely for inference.
1249
+ * `default`, `onUpdate`, foreign-key `reference`) and a phantom static type `T`
1250
+ * used purely for inference.
1202
1251
  */
1203
1252
  declare class Column<T, F extends ColumnFlags = ColumnFlags> {
1204
1253
  readonly type: ColumnType;
@@ -1207,13 +1256,17 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
1207
1256
  readonly defaultValue: DefaultValue | null;
1208
1257
  /** The value re-applied on update (e.g. `updated_at`), or `null`. */
1209
1258
  readonly onUpdateValue: DefaultValue | null;
1259
+ /** The foreign-key reference this column points to, or `null` for none. */
1260
+ readonly reference: ForeignKeyRef | null;
1210
1261
  /** Phantom: never read at runtime, only inspected by the type system. */
1211
1262
  readonly [TYPE]: T;
1212
1263
  constructor(type: ColumnType, flags: F,
1213
1264
  /** The default applied on insert, or `null` for none. */
1214
1265
  defaultValue?: DefaultValue | null,
1215
1266
  /** The value re-applied on update (e.g. `updated_at`), or `null`. */
1216
- onUpdateValue?: DefaultValue | null);
1267
+ onUpdateValue?: DefaultValue | null,
1268
+ /** The foreign-key reference this column points to, or `null` for none. */
1269
+ reference?: ForeignKeyRef | null);
1217
1270
  primaryKey(): Column<T, F & {
1218
1271
  primaryKey: true;
1219
1272
  hasDefault: true;
@@ -1221,6 +1274,24 @@ declare class Column<T, F extends ColumnFlags = ColumnFlags> {
1221
1274
  notNull(): Column<T, F & {
1222
1275
  notNull: true;
1223
1276
  }>;
1277
+ /**
1278
+ * Add a `UNIQUE` constraint to the column (mirrors SQLAlchemy's
1279
+ * `mapped_column(unique=True)`). DDL-only — does not change the inferred type.
1280
+ */
1281
+ unique(): Column<T, F & {
1282
+ unique: true;
1283
+ }>;
1284
+ /**
1285
+ * Declare a foreign-key reference to another table's column, à la SQLAlchemy's
1286
+ * `mapped_column(ForeignKey("table.column", ondelete=...))`. DDL-only — does
1287
+ * not change the inferred type.
1288
+ *
1289
+ * @param ref The target as `"table.column"` (e.g. `"users.id"`).
1290
+ * @param options Optional `onDelete` / `onUpdate` referential actions.
1291
+ * @returns A new column carrying the reference.
1292
+ * @throws Error When `ref` is not a valid `"table.column"` string.
1293
+ */
1294
+ references(ref: string, options?: ForeignKeyOptions): Column<T, F>;
1224
1295
  /**
1225
1296
  * Set the insert-time default: a constant value of type `T`, or a portable
1226
1297
  * server-side expression from {@link sql} (e.g. `sql.now()`, `sql.uuidv4()`).
@@ -1300,9 +1371,58 @@ declare const column: {
1300
1371
  /** `ENUM(...values)` → a string-literal union of the given values. */
1301
1372
  readonly enum: <const E extends string>(...values: E[]) => Column<E, ColumnFlags>;
1302
1373
  };
1374
+ /**
1375
+ * A table-level constraint declared via a model's `static tableArgs`. Mirrors
1376
+ * SQLAlchemy's `__table_args__` entries (`UniqueConstraint`, `ForeignKeyConstraint`).
1377
+ * Use the {@link unique} and {@link foreignKey} helpers to build these.
1378
+ */
1379
+ type TableConstraint = {
1380
+ readonly kind: "unique";
1381
+ readonly name?: string | undefined;
1382
+ readonly columns: readonly string[];
1383
+ } | {
1384
+ readonly kind: "foreignKey";
1385
+ readonly name?: string | undefined;
1386
+ readonly columns: readonly string[];
1387
+ readonly refTable: string;
1388
+ readonly refColumns: readonly string[];
1389
+ readonly onDelete?: FkAction | undefined;
1390
+ readonly onUpdate?: FkAction | undefined;
1391
+ };
1392
+ /**
1393
+ * Declare a (possibly composite) `UNIQUE` table constraint over the given
1394
+ * columns. Mirrors SQLAlchemy's `UniqueConstraint("a", "b")`.
1395
+ *
1396
+ * @param columns The column names covered by the constraint.
1397
+ * @returns A unique {@link TableConstraint}.
1398
+ * @throws Error When no columns are given.
1399
+ */
1400
+ declare function unique(...columns: string[]): TableConstraint;
1401
+ /**
1402
+ * Declare a (possibly composite) foreign-key table constraint. Mirrors
1403
+ * SQLAlchemy's `ForeignKeyConstraint([...], [...], ondelete=...)`.
1404
+ *
1405
+ * @param columns The local column names.
1406
+ * @param refTable The referenced table name.
1407
+ * @param refColumns The referenced column names (same length as `columns`).
1408
+ * @param options Optional constraint `name` and referential actions.
1409
+ * @returns A foreign-key {@link TableConstraint}.
1410
+ * @throws Error When the column arrays are empty or mismatched in length.
1411
+ */
1412
+ declare function foreignKey(columns: string[], refTable: string, refColumns: string[], options?: {
1413
+ name?: string;
1414
+ onDelete?: FkAction;
1415
+ onUpdate?: FkAction;
1416
+ }): TableConstraint;
1303
1417
  /** Base class every model extends, SQLAlchemy-declarative style. */
1304
1418
  declare abstract class Model {
1305
1419
  static tablename: string;
1420
+ /**
1421
+ * Optional table-level constraints (composite unique / foreign keys), returned
1422
+ * by a thunk so forward references resolve lazily. Mirrors SQLAlchemy's
1423
+ * `__table_args__`.
1424
+ */
1425
+ static tableArgs?: () => readonly TableConstraint[];
1306
1426
  }
1307
1427
  /**
1308
1428
  * Reflect a model class into its column map at runtime, keyed by column name.
@@ -1327,6 +1447,7 @@ type ColumnKeys<M> = {
1327
1447
  /** Constructor type for a Model subclass. */
1328
1448
  type ModelClass = (new () => Model) & {
1329
1449
  tablename: string;
1450
+ tableArgs?: () => readonly TableConstraint[];
1330
1451
  };
1331
1452
  /** Flatten an intersection into a single object literal for clean inference. */
1332
1453
  type Simplify<T> = {
@@ -1364,4 +1485,4 @@ type InferInsert<C extends ModelClass> = Simplify<{
1364
1485
  [K in Exclude<ColumnKeys<InstanceType<C>>, OptionalInsertKeys<InstanceType<C>>>]: ColValue<InstanceType<C>[K]>;
1365
1486
  }>;
1366
1487
 
1367
- export { ActiveRecord, type ActiveRecordManager, Agg, type AggregateTerm, type AsyncDriver, AsyncEngine, AsyncResult, AsyncSession, BaseDialect, BaseRepository, type BelongsTo, type ColRef, type ColType, Column, type ColumnFlags, type ColumnType, type ColumnTypeKind, type ColumnTypeMeta, type CompiledQuery, type CondNode, type Condition, type DefaultValue, DeleteBuilder, type DeleteNode, type Dialect, type DriverResult, type EngineOptions, type Executable, type HasMany, type InferInsert, type InferModel, InsertBuilder, type InsertNode, InvalidDatabaseUrl, JoinBuilder, type JoinClause, type JoinNode, type JoinOn, type JoinSelection, type JoinWhereInput, Model, type ModelClass, NoResultError, NodeSqliteDriver, OPERATORS, type OnConflict, type Operator, type OperatorsFor, type OrderTerm, type PaginationFilter, type PaginationResult, type ParsedDatabaseUrl, type PoolOptions, type PortableExpression, PostgresDialect, QueryExecutionError, type QueryLogger, type QueryNode, RecordNotFound, type Relation, type RelationValue, type ReservedAsyncDriver, type Returning, type RowOf, SelectBuilder, type SelectNode, type SortDirection, type Sources, SqliteDialect, type SyncDriver, SyncEngine, SyncResult, SyncSession, UpdateBuilder, type UpdateNode, ValidationError, type WhereArg, type WhereInput, type WithRelations, activeRecord, and, avg, belongsTo, column, columnsOf, count, createEngine, createSyncEngine, del, detectDialect, fromDict, getDialect, hasMany, insert, isCondition, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toCondNode, toDict, toJSON, update };
1488
+ export { ActiveRecord, type ActiveRecordManager, Agg, type AggregateTerm, type AsyncDriver, AsyncEngine, AsyncResult, AsyncSession, BaseDialect, BaseRepository, type BelongsTo, type ColRef, type ColType, Column, type ColumnFlags, type ColumnType, type ColumnTypeKind, type ColumnTypeMeta, type CompiledQuery, type CondNode, type Condition, type DefaultValue, DeleteBuilder, type DeleteNode, type Dialect, type DriverResult, type EngineOptions, type Executable, type FkAction, type ForeignKeyOptions, type ForeignKeyRef, type HasMany, type InferInsert, type InferModel, InsertBuilder, type InsertNode, InvalidDatabaseUrl, JoinBuilder, type JoinClause, type JoinNode, type JoinOn, type JoinSelection, type JoinWhereInput, Model, type ModelClass, MysqlDialect, NoResultError, NodeSqliteDriver, OPERATORS, type OnConflict, type Operator, type OperatorsFor, type OrderTerm, type PaginationFilter, type PaginationResult, type ParsedDatabaseUrl, type PoolOptions, type PortableExpression, PostgresDialect, QueryExecutionError, type QueryLogger, type QueryNode, RecordNotFound, type Relation, type RelationValue, type ReservedAsyncDriver, type Returning, type RowOf, SelectBuilder, type SelectNode, type SortDirection, type Sources, SqliteDialect, type SyncDriver, SyncEngine, SyncResult, SyncSession, type TableConstraint, UpdateBuilder, type UpdateNode, ValidationError, type WhereArg, type WhereInput, type WithRelations, activeRecord, and, avg, belongsTo, column, columnsOf, count, createEngine, createSyncEngine, del, detectDialect, foreignKey, fromDict, getDialect, hasMany, insert, isCondition, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toCondNode, toDict, toJSON, unique, update };
package/dist/index.js CHANGED
@@ -1,3 +1,3 @@
1
- export { ActiveRecord, Agg, AsyncEngine, AsyncResult, AsyncSession, BaseDialect, BaseRepository, Column, DeleteBuilder, InsertBuilder, InvalidDatabaseUrl, JoinBuilder, Model, NoResultError, NodeSqliteDriver, OPERATORS, PostgresDialect, QueryExecutionError, RecordNotFound, SelectBuilder, SqliteDialect, SyncEngine, SyncResult, SyncSession, UpdateBuilder, ValidationError, activeRecord, and, avg, belongsTo, column, columnsOf, count, createEngine, createSyncEngine, del, detectDialect, fromDict, getDialect, hasMany, insert, isCondition, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toCondNode, toDict, toJSON, update } from './chunk-AGDD7K3F.js';
1
+ export { ActiveRecord, Agg, AsyncEngine, AsyncResult, AsyncSession, BaseDialect, BaseRepository, Column, DeleteBuilder, InsertBuilder, InvalidDatabaseUrl, JoinBuilder, Model, MysqlDialect, NoResultError, NodeSqliteDriver, OPERATORS, PostgresDialect, QueryExecutionError, RecordNotFound, SelectBuilder, SqliteDialect, SyncEngine, SyncResult, SyncSession, UpdateBuilder, ValidationError, activeRecord, and, avg, belongsTo, column, columnsOf, count, createEngine, createSyncEngine, del, detectDialect, foreignKey, fromDict, getDialect, hasMany, insert, isCondition, join, loadRelations, max, min, not, or, parse, parseDatabaseUrl, select, sql, stringify, sum, toCondNode, toDict, toJSON, unique, update } from './chunk-JR4MLFQN.js';
2
2
  //# sourceMappingURL=index.js.map
3
3
  //# sourceMappingURL=index.js.map