@simplysm/orm-common 13.0.82 → 13.0.84
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/README.md +106 -0
- package/dist/ddl/initialize.d.ts +2 -2
- package/dist/ddl/initialize.js +1 -1
- package/dist/ddl/initialize.js.map +1 -1
- package/dist/ddl/table-ddl.d.ts +1 -1
- package/dist/exec/queryable.d.ts +115 -115
- package/dist/exec/queryable.js +68 -68
- package/dist/exec/queryable.js.map +1 -1
- package/dist/expr/expr.d.ts +248 -248
- package/dist/expr/expr.js +250 -250
- package/dist/query-builder/base/expr-renderer-base.d.ts +7 -7
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts +3 -3
- package/dist/query-builder/mssql/mssql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-expr-renderer.js +5 -5
- package/dist/query-builder/mssql/mssql-query-builder.d.ts +2 -2
- package/dist/query-builder/mssql/mssql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/mssql/mssql-query-builder.js +7 -7
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts +2 -2
- package/dist/query-builder/mysql/mysql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-expr-renderer.js +4 -4
- package/dist/query-builder/mysql/mysql-query-builder.d.ts +10 -10
- package/dist/query-builder/mysql/mysql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/mysql/mysql-query-builder.js +4 -4
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts +2 -2
- package/dist/query-builder/postgresql/postgresql-expr-renderer.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-expr-renderer.js +4 -4
- package/dist/query-builder/postgresql/postgresql-query-builder.d.ts +8 -8
- package/dist/query-builder/postgresql/postgresql-query-builder.d.ts.map +1 -1
- package/dist/query-builder/postgresql/postgresql-query-builder.js +7 -7
- package/dist/query-builder/query-builder.d.ts +1 -1
- package/dist/schema/factory/column-builder.d.ts +46 -46
- package/dist/schema/factory/column-builder.js +25 -25
- package/dist/schema/factory/index-builder.d.ts +22 -22
- package/dist/schema/factory/index-builder.js +14 -14
- package/dist/schema/factory/relation-builder.d.ts +93 -93
- package/dist/schema/factory/relation-builder.d.ts.map +1 -1
- package/dist/schema/factory/relation-builder.js +37 -37
- package/dist/schema/procedure-builder.d.ts +38 -38
- package/dist/schema/procedure-builder.d.ts.map +1 -1
- package/dist/schema/procedure-builder.js +26 -26
- package/dist/schema/table-builder.d.ts +38 -38
- package/dist/schema/table-builder.d.ts.map +1 -1
- package/dist/schema/table-builder.js +29 -29
- package/dist/schema/view-builder.d.ts +26 -26
- package/dist/schema/view-builder.d.ts.map +1 -1
- package/dist/schema/view-builder.js +18 -18
- package/dist/types/db.d.ts +40 -40
- package/dist/types/expr.d.ts +75 -75
- package/dist/types/expr.d.ts.map +1 -1
- package/dist/types/query-def.d.ts +32 -32
- package/dist/types/query-def.d.ts.map +1 -1
- package/docs/db-context.md +238 -0
- package/docs/expressions.md +413 -0
- package/docs/query-builder.md +198 -0
- package/docs/queryable.md +420 -0
- package/docs/schema-builders.md +216 -0
- package/docs/types-and-utilities.md +353 -0
- package/package.json +4 -3
- package/src/ddl/initialize.ts +16 -16
- package/src/ddl/table-ddl.ts +1 -1
- package/src/exec/queryable.ts +163 -163
- package/src/expr/expr.ts +257 -257
- package/src/query-builder/base/expr-renderer-base.ts +8 -8
- package/src/query-builder/mssql/mssql-expr-renderer.ts +20 -20
- package/src/query-builder/mssql/mssql-query-builder.ts +28 -28
- package/src/query-builder/mysql/mysql-expr-renderer.ts +22 -22
- package/src/query-builder/mysql/mysql-query-builder.ts +65 -65
- package/src/query-builder/postgresql/postgresql-expr-renderer.ts +15 -15
- package/src/query-builder/postgresql/postgresql-query-builder.ts +43 -43
- package/src/query-builder/query-builder.ts +1 -1
- package/src/schema/factory/column-builder.ts +48 -48
- package/src/schema/factory/index-builder.ts +22 -22
- package/src/schema/factory/relation-builder.ts +95 -95
- package/src/schema/procedure-builder.ts +38 -38
- package/src/schema/table-builder.ts +38 -38
- package/src/schema/view-builder.ts +28 -28
- package/src/types/db.ts +41 -41
- package/src/types/expr.ts +79 -79
- package/src/types/query-def.ts +37 -37
- package/tests/ddl/basic.expected.ts +8 -8
|
@@ -38,25 +38,25 @@ import { PostgresqlExprRenderer } from "./postgresql-expr-renderer";
|
|
|
38
38
|
/**
|
|
39
39
|
* PostgreSQL QueryBuilder
|
|
40
40
|
*
|
|
41
|
-
* PostgreSQL
|
|
42
|
-
* - OUTPUT: RETURNING
|
|
43
|
-
* - TRUNCATE: RESTART IDENTITY option
|
|
44
|
-
* - UPSERT: CTE
|
|
45
|
-
* - AUTO_INCREMENT: GENERATED BY DEFAULT AS IDENTITY (explicit value
|
|
46
|
-
* -
|
|
41
|
+
* PostgreSQL specifics:
|
|
42
|
+
* - OUTPUT: uses RETURNING clause (native support)
|
|
43
|
+
* - TRUNCATE: RESTART IDENTITY option required
|
|
44
|
+
* - UPSERT: CTE approach (INSERT ... ON CONFLICT only supports single unique constraint)
|
|
45
|
+
* - AUTO_INCREMENT: GENERATED BY DEFAULT AS IDENTITY (allows explicit value assignment)
|
|
46
|
+
* - Separate index generation needed when adding FK (unlike MySQL)
|
|
47
47
|
*/
|
|
48
48
|
export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
49
49
|
protected expr = new PostgresqlExprRenderer((def) => this.select(def).sql);
|
|
50
50
|
|
|
51
|
-
//#region ==========
|
|
51
|
+
//#region ========== Utilities ==========
|
|
52
52
|
|
|
53
|
-
/**
|
|
53
|
+
/** Render table name (PostgreSQL: database is handled by connection, uses schema.table only) */
|
|
54
54
|
protected tableName(obj: QueryDefObjectName): string {
|
|
55
55
|
const schema = obj.schema ?? "public";
|
|
56
56
|
return `${this.expr.wrap(schema)}.${this.expr.wrap(obj.name)}`;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
|
-
/** LIMIT...OFFSET
|
|
59
|
+
/** Render LIMIT...OFFSET clause */
|
|
60
60
|
protected renderLimit(limit: [number, number] | undefined, top: number | undefined): string {
|
|
61
61
|
if (limit != null) {
|
|
62
62
|
const [offset, count] = limit;
|
|
@@ -71,15 +71,15 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
71
71
|
protected renderJoin(join: SelectQueryDefJoin): string {
|
|
72
72
|
const alias = this.expr.wrap(join.as);
|
|
73
73
|
|
|
74
|
-
// LATERAL JOIN
|
|
74
|
+
// Detect if LATERAL JOIN is needed
|
|
75
75
|
if (this.needsLateral(join)) {
|
|
76
|
-
// from
|
|
77
|
-
//
|
|
76
|
+
// If from is an array (UNION ALL), use renderFrom(join.from),
|
|
77
|
+
// otherwise (orderBy, top, select, etc.) use renderFrom(join) to generate subquery
|
|
78
78
|
const from = Array.isArray(join.from) ? this.renderFrom(join.from) : this.renderFrom(join);
|
|
79
79
|
return ` LEFT OUTER JOIN LATERAL ${from} AS ${alias} ON TRUE`;
|
|
80
80
|
}
|
|
81
81
|
|
|
82
|
-
//
|
|
82
|
+
// Normal JOIN
|
|
83
83
|
const from = this.renderFrom(join.from);
|
|
84
84
|
const where =
|
|
85
85
|
join.where != null && join.where.length > 0
|
|
@@ -169,14 +169,14 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
169
169
|
|
|
170
170
|
let sql = `INSERT INTO ${table} (${colList})`;
|
|
171
171
|
|
|
172
|
-
// GENERATED BY DEFAULT AS IDENTITY
|
|
173
|
-
// overrideIdentity
|
|
174
|
-
// PostgreSQL
|
|
175
|
-
// (
|
|
172
|
+
// GENERATED BY DEFAULT AS IDENTITY, so no additional clause needed for explicit value insertion
|
|
173
|
+
// overrideIdentity parameter is kept for MSSQL (SET IDENTITY_INSERT) compatibility, but
|
|
174
|
+
// PostgreSQL's GENERATED BY DEFAULT automatically allows explicit values
|
|
175
|
+
// (note: OVERRIDING SYSTEM VALUE would be needed if GENERATED ALWAYS was used)
|
|
176
176
|
|
|
177
177
|
sql += ` VALUES ${valuesList.join(", ")}`;
|
|
178
178
|
|
|
179
|
-
// RETURNING (PostgreSQL
|
|
179
|
+
// RETURNING (PostgreSQL native support)
|
|
180
180
|
if (def.output != null) {
|
|
181
181
|
const outputCols = def.output.columns.map((c) => this.expr.wrap(c)).join(", ");
|
|
182
182
|
sql += ` RETURNING ${outputCols}`;
|
|
@@ -192,7 +192,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
192
192
|
const colList = columns.map((c) => this.expr.wrap(c)).join(", ");
|
|
193
193
|
const values = columns.map((c) => this.expr.escapeValue(def.record[c])).join(", ");
|
|
194
194
|
|
|
195
|
-
// existsSelectQuery
|
|
195
|
+
// Render existsSelectQuery as SELECT 1 AS _
|
|
196
196
|
const existsQuerySql = this.select({
|
|
197
197
|
...def.existsSelectQuery,
|
|
198
198
|
select: { _: { type: "value", value: 1 } },
|
|
@@ -213,7 +213,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
213
213
|
const table = this.tableName(def.table);
|
|
214
214
|
const selectSql = this.select(def.recordsSelectQuery).sql;
|
|
215
215
|
|
|
216
|
-
// INSERT INTO SELECT
|
|
216
|
+
// Extract columns from INSERT INTO SELECT
|
|
217
217
|
const selectDef = def.recordsSelectQuery;
|
|
218
218
|
const colList =
|
|
219
219
|
selectDef.select != null
|
|
@@ -248,7 +248,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
248
248
|
|
|
249
249
|
let sql = `UPDATE ${table} AS ${alias} SET ${setParts.join(", ")}`;
|
|
250
250
|
|
|
251
|
-
// PostgreSQL:
|
|
251
|
+
// PostgreSQL: JOINs are handled via FROM clause
|
|
252
252
|
if (def.joins != null && def.joins.length > 0) {
|
|
253
253
|
const joinTables = def.joins.map((j) => {
|
|
254
254
|
const from = this.renderFrom(j.from);
|
|
@@ -256,7 +256,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
256
256
|
});
|
|
257
257
|
sql += ` FROM ${joinTables.join(", ")}`;
|
|
258
258
|
|
|
259
|
-
// JOIN ON
|
|
259
|
+
// Add JOIN ON conditions to WHERE
|
|
260
260
|
const joinConditions = def.joins
|
|
261
261
|
.filter((j) => j.where != null && j.where.length > 0)
|
|
262
262
|
.map((j) => this.expr.renderWhere(j.where!));
|
|
@@ -292,7 +292,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
292
292
|
|
|
293
293
|
let sql = `DELETE FROM ${table} AS ${alias}`;
|
|
294
294
|
|
|
295
|
-
// PostgreSQL:
|
|
295
|
+
// PostgreSQL: JOINs are handled via USING clause
|
|
296
296
|
if (def.joins != null && def.joins.length > 0) {
|
|
297
297
|
const joinTables = def.joins.map((j) => {
|
|
298
298
|
const from = this.renderFrom(j.from);
|
|
@@ -300,7 +300,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
300
300
|
});
|
|
301
301
|
sql += ` USING ${joinTables.join(", ")}`;
|
|
302
302
|
|
|
303
|
-
// JOIN ON
|
|
303
|
+
// Add JOIN ON conditions to WHERE
|
|
304
304
|
const joinConditions = def.joins
|
|
305
305
|
.filter((j) => j.where != null && j.where.length > 0)
|
|
306
306
|
.map((j) => this.expr.renderWhere(j.where!));
|
|
@@ -317,7 +317,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
317
317
|
sql += this.renderWhere(def.where);
|
|
318
318
|
}
|
|
319
319
|
|
|
320
|
-
// RETURNING (PostgreSQL: DELETE
|
|
320
|
+
// RETURNING (PostgreSQL: also supported for DELETE)
|
|
321
321
|
if (def.output != null) {
|
|
322
322
|
const outputCols = def.output.columns.map((c) => this.expr.wrap(c)).join(", ");
|
|
323
323
|
sql += ` RETURNING ${outputCols}`;
|
|
@@ -331,7 +331,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
331
331
|
//#region ========== DML - UPSERT ==========
|
|
332
332
|
|
|
333
333
|
protected upsert(def: UpsertQueryDef): QueryBuildResult {
|
|
334
|
-
// PostgreSQL: CTE
|
|
334
|
+
// PostgreSQL: CTE approach (uses CTE for generality since ON CONFLICT only supports single unique constraint)
|
|
335
335
|
const table = this.tableName(def.table);
|
|
336
336
|
const alias = this.expr.wrap(def.existsSelectQuery.as);
|
|
337
337
|
|
|
@@ -355,7 +355,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
355
355
|
const outputCols =
|
|
356
356
|
def.output != null ? def.output.columns.map((c) => this.expr.wrap(c)).join(", ") : "*";
|
|
357
357
|
|
|
358
|
-
// CTE
|
|
358
|
+
// CTE-based UPSERT
|
|
359
359
|
let sql = `WITH matched AS (\n`;
|
|
360
360
|
sql += ` SELECT ${alias}.* FROM ${table} AS ${alias} WHERE ${whereCondition}\n`;
|
|
361
361
|
sql += `),\n`;
|
|
@@ -424,7 +424,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
424
424
|
}
|
|
425
425
|
|
|
426
426
|
protected truncate(def: TruncateQueryDef): QueryBuildResult {
|
|
427
|
-
// PostgreSQL: RESTART IDENTITY
|
|
427
|
+
// PostgreSQL: reset sequence with RESTART IDENTITY
|
|
428
428
|
return { sql: `TRUNCATE TABLE ${this.tableName(def.table)} RESTART IDENTITY` };
|
|
429
429
|
}
|
|
430
430
|
|
|
@@ -466,22 +466,22 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
466
466
|
const table = this.tableName(def.table);
|
|
467
467
|
const col = def.column;
|
|
468
468
|
|
|
469
|
-
// PostgreSQL: ALTER COLUMN
|
|
469
|
+
// PostgreSQL: ALTER COLUMN requires multiple ALTER statements
|
|
470
470
|
const parts: string[] = [];
|
|
471
471
|
|
|
472
|
-
// TYPE
|
|
472
|
+
// Change TYPE
|
|
473
473
|
parts.push(
|
|
474
474
|
`ALTER COLUMN ${this.expr.wrap(col.name)} TYPE ${this.expr.renderDataType(col.dataType)}`,
|
|
475
475
|
);
|
|
476
476
|
|
|
477
|
-
// NULL
|
|
477
|
+
// Change NULL constraint
|
|
478
478
|
if (col.nullable === false) {
|
|
479
479
|
parts.push(`ALTER COLUMN ${this.expr.wrap(col.name)} SET NOT NULL`);
|
|
480
480
|
} else {
|
|
481
481
|
parts.push(`ALTER COLUMN ${this.expr.wrap(col.name)} DROP NOT NULL`);
|
|
482
482
|
}
|
|
483
483
|
|
|
484
|
-
// DEFAULT
|
|
484
|
+
// Change DEFAULT
|
|
485
485
|
if (col.default !== undefined) {
|
|
486
486
|
parts.push(
|
|
487
487
|
`ALTER COLUMN ${this.expr.wrap(col.name)} SET DEFAULT ${this.expr.escapeValue(col.default)}`,
|
|
@@ -526,7 +526,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
526
526
|
|
|
527
527
|
let sql = `ALTER TABLE ${table} ADD CONSTRAINT ${this.expr.wrap(fk.name)} FOREIGN KEY (${fkCols}) REFERENCES ${targetTable} (${targetCols})`;
|
|
528
528
|
|
|
529
|
-
// PostgreSQL:
|
|
529
|
+
// PostgreSQL: separate index generation needed for FK
|
|
530
530
|
const idxName = `IDX_${def.table.name}_${fk.name.replace(/^FK_/, "")}`;
|
|
531
531
|
sql += `;\nCREATE INDEX ${this.expr.wrap(idxName)} ON ${table} (${fkCols});`;
|
|
532
532
|
|
|
@@ -548,7 +548,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
548
548
|
}
|
|
549
549
|
|
|
550
550
|
protected dropIndex(def: DropIndexQueryDef): QueryBuildResult {
|
|
551
|
-
// PostgreSQL:
|
|
551
|
+
// PostgreSQL: indexes are unique at schema level so table name is not needed, but schema must be specified
|
|
552
552
|
const schema = def.table.schema ?? "public";
|
|
553
553
|
return { sql: `DROP INDEX ${this.expr.wrap(schema)}.${this.expr.wrap(def.index)}` };
|
|
554
554
|
}
|
|
@@ -570,7 +570,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
570
570
|
protected createProc(def: CreateProcQueryDef): QueryBuildResult {
|
|
571
571
|
const proc = this.tableName(def.procedure);
|
|
572
572
|
|
|
573
|
-
// params
|
|
573
|
+
// Process params
|
|
574
574
|
const paramList =
|
|
575
575
|
def.params
|
|
576
576
|
?.map((p) => {
|
|
@@ -582,7 +582,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
582
582
|
})
|
|
583
583
|
.join(", ") ?? "";
|
|
584
584
|
|
|
585
|
-
// returns
|
|
585
|
+
// Process returns
|
|
586
586
|
let returnClause = "VOID";
|
|
587
587
|
if (def.returns && def.returns.length > 0) {
|
|
588
588
|
const returnFields = def.returns
|
|
@@ -625,7 +625,7 @@ export class PostgresqlQueryBuilder extends QueryBuilderBase {
|
|
|
625
625
|
|
|
626
626
|
protected clearSchema(def: ClearSchemaQueryDef): QueryBuildResult {
|
|
627
627
|
const schemaName = def.schema ?? "public";
|
|
628
|
-
// SQL
|
|
628
|
+
// SQL injection prevention: schema name validation
|
|
629
629
|
if (!/^[a-zA-Z_][a-zA-Z0-9_]*$/.test(schemaName)) {
|
|
630
630
|
throw new Error(`Invalid schema name: ${schemaName}`);
|
|
631
631
|
}
|
|
@@ -636,7 +636,7 @@ DO $$
|
|
|
636
636
|
DECLARE
|
|
637
637
|
r RECORD;
|
|
638
638
|
BEGIN
|
|
639
|
-
-- FK
|
|
639
|
+
-- Drop FK constraints
|
|
640
640
|
FOR r IN (SELECT conname, conrelid::regclass AS tablename
|
|
641
641
|
FROM pg_constraint
|
|
642
642
|
WHERE contype = 'f' AND connamespace = '${schema}'::regnamespace)
|
|
@@ -644,19 +644,19 @@ BEGIN
|
|
|
644
644
|
EXECUTE 'ALTER TABLE ' || r.tablename || ' DROP CONSTRAINT ' || quote_ident(r.conname);
|
|
645
645
|
END LOOP;
|
|
646
646
|
|
|
647
|
-
-- Drop
|
|
647
|
+
-- Drop tables
|
|
648
648
|
FOR r IN (SELECT tablename FROM pg_tables WHERE schemaname = '${schema}')
|
|
649
649
|
LOOP
|
|
650
650
|
EXECUTE 'DROP TABLE IF EXISTS ' || quote_ident(r.tablename) || ' CASCADE';
|
|
651
651
|
END LOOP;
|
|
652
652
|
|
|
653
|
-
-- Drop
|
|
653
|
+
-- Drop views
|
|
654
654
|
FOR r IN (SELECT viewname FROM pg_views WHERE schemaname = '${schema}')
|
|
655
655
|
LOOP
|
|
656
656
|
EXECUTE 'DROP VIEW IF EXISTS ' || quote_ident(r.viewname) || ' CASCADE';
|
|
657
657
|
END LOOP;
|
|
658
658
|
|
|
659
|
-
--
|
|
659
|
+
-- Drop functions
|
|
660
660
|
FOR r IN (SELECT proname, pg_get_function_identity_arguments(oid) AS args
|
|
661
661
|
FROM pg_proc WHERE pronamespace = '${schema}'::regnamespace)
|
|
662
662
|
LOOP
|
|
@@ -675,10 +675,10 @@ END $$`,
|
|
|
675
675
|
protected switchFk(def: SwitchFkQueryDef): QueryBuildResult {
|
|
676
676
|
const table = this.tableName(def.table);
|
|
677
677
|
if (def.enabled) {
|
|
678
|
-
// PostgreSQL:
|
|
678
|
+
// PostgreSQL: enable all FK triggers on the table
|
|
679
679
|
return { sql: `ALTER TABLE ${table} ENABLE TRIGGER ALL` };
|
|
680
680
|
}
|
|
681
|
-
// PostgreSQL:
|
|
681
|
+
// PostgreSQL: disable all FK triggers on the table
|
|
682
682
|
return { sql: `ALTER TABLE ${table} DISABLE TRIGGER ALL` };
|
|
683
683
|
}
|
|
684
684
|
|
|
@@ -5,7 +5,7 @@ import { MysqlQueryBuilder } from "./mysql/mysql-query-builder";
|
|
|
5
5
|
import { PostgresqlQueryBuilder } from "./postgresql/postgresql-query-builder";
|
|
6
6
|
|
|
7
7
|
/**
|
|
8
|
-
*
|
|
8
|
+
* Generate a QueryBuilder instance matching the given Dialect
|
|
9
9
|
*/
|
|
10
10
|
export function createQueryBuilder(dialect: Dialect): QueryBuilderBase {
|
|
11
11
|
switch (dialect) {
|
|
@@ -10,8 +10,8 @@ import type { DataRecord } from "../../types/db";
|
|
|
10
10
|
/**
|
|
11
11
|
* Column definition builder
|
|
12
12
|
*
|
|
13
|
-
*
|
|
14
|
-
* TableBuilder.columns()
|
|
13
|
+
* Define column type, nullable, autoIncrement, default, and description via Fluent API
|
|
14
|
+
* Used in TableBuilder.columns()
|
|
15
15
|
*
|
|
16
16
|
* @template TValue - Column value type
|
|
17
17
|
* @template TMeta - Column Metadata type
|
|
@@ -24,7 +24,7 @@ import type { DataRecord } from "../../types/db";
|
|
|
24
24
|
* name: c.varchar(100), // varchar(100), required
|
|
25
25
|
* email: c.varchar(200).nullable(), // varchar(200), nullable
|
|
26
26
|
* status: c.varchar(20).default("active"), // varchar(20), default value
|
|
27
|
-
* createdAt: c.datetime().description("
|
|
27
|
+
* createdAt: c.datetime().description("created datetime"),
|
|
28
28
|
* }));
|
|
29
29
|
* ```
|
|
30
30
|
*
|
|
@@ -38,9 +38,9 @@ export class ColumnBuilder<TValue extends ColumnPrimitive, TMeta extends ColumnM
|
|
|
38
38
|
constructor(readonly meta: TMeta) {}
|
|
39
39
|
|
|
40
40
|
/**
|
|
41
|
-
* Auto Increment
|
|
41
|
+
* Auto Increment configuration
|
|
42
42
|
*
|
|
43
|
-
*
|
|
43
|
+
* Auto increments on INSERT. Treated as optional in INSERT Type inference
|
|
44
44
|
*
|
|
45
45
|
* @returns new ColumnBuilder instance
|
|
46
46
|
*
|
|
@@ -54,9 +54,9 @@ export class ColumnBuilder<TValue extends ColumnPrimitive, TMeta extends ColumnM
|
|
|
54
54
|
}
|
|
55
55
|
|
|
56
56
|
/**
|
|
57
|
-
* Nullable
|
|
57
|
+
* Nullable configuration
|
|
58
58
|
*
|
|
59
|
-
* Allow NULL.
|
|
59
|
+
* Allow NULL. Adds undefined to the value type
|
|
60
60
|
*
|
|
61
61
|
* @returns new ColumnBuilder instance
|
|
62
62
|
*
|
|
@@ -70,9 +70,9 @@ export class ColumnBuilder<TValue extends ColumnPrimitive, TMeta extends ColumnM
|
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
/**
|
|
73
|
-
* Default value
|
|
73
|
+
* Default value configuration
|
|
74
74
|
*
|
|
75
|
-
*
|
|
75
|
+
* Used when no value is specified on INSERT. Treated as optional in INSERT Type inference
|
|
76
76
|
*
|
|
77
77
|
* @param value - Default value
|
|
78
78
|
* @returns new ColumnBuilder instance
|
|
@@ -92,12 +92,12 @@ export class ColumnBuilder<TValue extends ColumnPrimitive, TMeta extends ColumnM
|
|
|
92
92
|
/**
|
|
93
93
|
* column set description
|
|
94
94
|
*
|
|
95
|
-
* @param desc - Column description (DDL Comment
|
|
95
|
+
* @param desc - Column description (used as DDL Comment)
|
|
96
96
|
* @returns new ColumnBuilder instance
|
|
97
97
|
*
|
|
98
98
|
* @example
|
|
99
99
|
* ```typescript
|
|
100
|
-
* createdAt: c.datetime().description("
|
|
100
|
+
* createdAt: c.datetime().description("record creation datetime")
|
|
101
101
|
* ```
|
|
102
102
|
*/
|
|
103
103
|
description(desc: string): ColumnBuilder<TValue, TMeta & { description: string }> {
|
|
@@ -110,12 +110,12 @@ export class ColumnBuilder<TValue extends ColumnPrimitive, TMeta extends ColumnM
|
|
|
110
110
|
// ============================================
|
|
111
111
|
|
|
112
112
|
/**
|
|
113
|
-
* Column builder factory
|
|
113
|
+
* Column builder factory creation
|
|
114
114
|
*
|
|
115
|
-
* TableBuilder.columns()
|
|
116
|
-
*
|
|
115
|
+
* Column type factory used in TableBuilder.columns()
|
|
116
|
+
* Provides builder creation methods for all basic data types
|
|
117
117
|
*
|
|
118
|
-
* @returns
|
|
118
|
+
* @returns Object containing builder creation methods for each Column type
|
|
119
119
|
*
|
|
120
120
|
* @example
|
|
121
121
|
* ```typescript
|
|
@@ -126,12 +126,12 @@ export class ColumnBuilder<TValue extends ColumnPrimitive, TMeta extends ColumnM
|
|
|
126
126
|
* count: c.int(),
|
|
127
127
|
* price: c.decimal(10, 2),
|
|
128
128
|
*
|
|
129
|
-
* //
|
|
129
|
+
* // String type
|
|
130
130
|
* name: c.varchar(100),
|
|
131
131
|
* code: c.char(10),
|
|
132
132
|
* content: c.text(),
|
|
133
133
|
*
|
|
134
|
-
* // Date
|
|
134
|
+
* // Date/time type
|
|
135
135
|
* createdAt: c.datetime(),
|
|
136
136
|
* birthDate: c.date(),
|
|
137
137
|
* startTime: c.time(),
|
|
@@ -166,7 +166,7 @@ export function createColumnFactory() {
|
|
|
166
166
|
},
|
|
167
167
|
|
|
168
168
|
/**
|
|
169
|
-
* FLOAT column (4 bytes,
|
|
169
|
+
* FLOAT column (4 bytes, single-precision floating point)
|
|
170
170
|
*
|
|
171
171
|
* @returns ColumnBuilder instance
|
|
172
172
|
*/
|
|
@@ -175,7 +175,7 @@ export function createColumnFactory() {
|
|
|
175
175
|
},
|
|
176
176
|
|
|
177
177
|
/**
|
|
178
|
-
* DOUBLE column (8 bytes,
|
|
178
|
+
* DOUBLE column (8 bytes, double-precision floating point)
|
|
179
179
|
*
|
|
180
180
|
* @returns ColumnBuilder instance
|
|
181
181
|
*/
|
|
@@ -184,10 +184,10 @@ export function createColumnFactory() {
|
|
|
184
184
|
},
|
|
185
185
|
|
|
186
186
|
/**
|
|
187
|
-
* DECIMAL column (
|
|
187
|
+
* DECIMAL column (fixed-point)
|
|
188
188
|
*
|
|
189
|
-
* @param precision -
|
|
190
|
-
* @param scale -
|
|
189
|
+
* @param precision - Total number of digits
|
|
190
|
+
* @param scale - Number of digits after the decimal point (optional)
|
|
191
191
|
* @returns ColumnBuilder instance
|
|
192
192
|
*
|
|
193
193
|
* @example
|
|
@@ -206,9 +206,9 @@ export function createColumnFactory() {
|
|
|
206
206
|
},
|
|
207
207
|
|
|
208
208
|
/**
|
|
209
|
-
* VARCHAR column (
|
|
209
|
+
* VARCHAR column (variable-length string)
|
|
210
210
|
*
|
|
211
|
-
* @param length -
|
|
211
|
+
* @param length - Maximum length
|
|
212
212
|
* @returns ColumnBuilder instance
|
|
213
213
|
*
|
|
214
214
|
* @example
|
|
@@ -223,9 +223,9 @@ export function createColumnFactory() {
|
|
|
223
223
|
},
|
|
224
224
|
|
|
225
225
|
/**
|
|
226
|
-
* CHAR column (
|
|
226
|
+
* CHAR column (fixed-length string)
|
|
227
227
|
*
|
|
228
|
-
* @param length -
|
|
228
|
+
* @param length - Fixed length
|
|
229
229
|
* @returns ColumnBuilder instance
|
|
230
230
|
*
|
|
231
231
|
* @example
|
|
@@ -240,7 +240,7 @@ export function createColumnFactory() {
|
|
|
240
240
|
},
|
|
241
241
|
|
|
242
242
|
/**
|
|
243
|
-
* TEXT column (
|
|
243
|
+
* TEXT column (large text)
|
|
244
244
|
*
|
|
245
245
|
* @returns ColumnBuilder instance
|
|
246
246
|
*/
|
|
@@ -249,9 +249,9 @@ export function createColumnFactory() {
|
|
|
249
249
|
},
|
|
250
250
|
|
|
251
251
|
/**
|
|
252
|
-
* BINARY column (
|
|
252
|
+
* BINARY column (binary data)
|
|
253
253
|
*
|
|
254
|
-
* DBMS
|
|
254
|
+
* Per DBMS: MySQL=LONGBLOB, MSSQL=VARBINARY(MAX), PostgreSQL=BYTEA
|
|
255
255
|
*
|
|
256
256
|
* @returns ColumnBuilder instance
|
|
257
257
|
*/
|
|
@@ -262,7 +262,7 @@ export function createColumnFactory() {
|
|
|
262
262
|
/**
|
|
263
263
|
* BOOLEAN column
|
|
264
264
|
*
|
|
265
|
-
* DBMS
|
|
265
|
+
* Per DBMS: MySQL=TINYINT(1), MSSQL=BIT, PostgreSQL=BOOLEAN
|
|
266
266
|
*
|
|
267
267
|
* @returns ColumnBuilder instance
|
|
268
268
|
*/
|
|
@@ -271,7 +271,7 @@ export function createColumnFactory() {
|
|
|
271
271
|
},
|
|
272
272
|
|
|
273
273
|
/**
|
|
274
|
-
* DATETIME column (
|
|
274
|
+
* DATETIME column (date + time)
|
|
275
275
|
*
|
|
276
276
|
* @returns ColumnBuilder instance
|
|
277
277
|
*/
|
|
@@ -280,7 +280,7 @@ export function createColumnFactory() {
|
|
|
280
280
|
},
|
|
281
281
|
|
|
282
282
|
/**
|
|
283
|
-
* DATE column (
|
|
283
|
+
* DATE column (date only)
|
|
284
284
|
*
|
|
285
285
|
* @returns ColumnBuilder instance
|
|
286
286
|
*/
|
|
@@ -289,7 +289,7 @@ export function createColumnFactory() {
|
|
|
289
289
|
},
|
|
290
290
|
|
|
291
291
|
/**
|
|
292
|
-
* TIME column (
|
|
292
|
+
* TIME column (time only)
|
|
293
293
|
*
|
|
294
294
|
* @returns ColumnBuilder instance
|
|
295
295
|
*/
|
|
@@ -300,7 +300,7 @@ export function createColumnFactory() {
|
|
|
300
300
|
/**
|
|
301
301
|
* UUID column
|
|
302
302
|
*
|
|
303
|
-
* DBMS
|
|
303
|
+
* Per DBMS: MySQL=BINARY(16), MSSQL=UNIQUEIDENTIFIER, PostgreSQL=UUID
|
|
304
304
|
*
|
|
305
305
|
* @returns ColumnBuilder instance
|
|
306
306
|
*/
|
|
@@ -311,22 +311,22 @@ export function createColumnFactory() {
|
|
|
311
311
|
}
|
|
312
312
|
|
|
313
313
|
// ============================================
|
|
314
|
-
// ColumnDefRecord - Column builder
|
|
314
|
+
// ColumnDefRecord - Column builder record
|
|
315
315
|
// ============================================
|
|
316
316
|
|
|
317
317
|
/**
|
|
318
318
|
* Column builder record type
|
|
319
319
|
*
|
|
320
|
-
* TableBuilder.columns()
|
|
320
|
+
* Used as the return type of TableBuilder.columns()
|
|
321
321
|
*/
|
|
322
322
|
export type ColumnBuilderRecord = Record<string, ColumnBuilder<ColumnPrimitive, ColumnMeta>>;
|
|
323
323
|
|
|
324
324
|
// ============================================
|
|
325
|
-
// Infer - Type inference
|
|
325
|
+
// Infer - Type inference utilities
|
|
326
326
|
// ============================================
|
|
327
327
|
|
|
328
328
|
/**
|
|
329
|
-
*
|
|
329
|
+
* Infer actual value types from a Column builder record
|
|
330
330
|
*
|
|
331
331
|
* @template T - Column builder record type
|
|
332
332
|
*
|
|
@@ -341,7 +341,7 @@ export type InferColumns<TBuilders extends ColumnBuilderRecord> = {
|
|
|
341
341
|
};
|
|
342
342
|
|
|
343
343
|
/**
|
|
344
|
-
*
|
|
344
|
+
* Infer expression input types from a Column builder record
|
|
345
345
|
*
|
|
346
346
|
* @template T - Column builder record type
|
|
347
347
|
*/
|
|
@@ -350,9 +350,9 @@ export type InferColumnExprs<TBuilders extends ColumnBuilderRecord> = {
|
|
|
350
350
|
};
|
|
351
351
|
|
|
352
352
|
/**
|
|
353
|
-
*
|
|
353
|
+
* Extract required column keys for INSERT
|
|
354
354
|
*
|
|
355
|
-
* autoIncrement, nullable, default
|
|
355
|
+
* Only columns without autoIncrement, nullable, or default are required
|
|
356
356
|
*
|
|
357
357
|
* @template T - Column builder record type
|
|
358
358
|
*/
|
|
@@ -369,9 +369,9 @@ export type RequiredInsertKeys<TBuilders extends ColumnBuilderRecord> = {
|
|
|
369
369
|
}[keyof TBuilders];
|
|
370
370
|
|
|
371
371
|
/**
|
|
372
|
-
*
|
|
372
|
+
* Extract optional column keys for INSERT
|
|
373
373
|
*
|
|
374
|
-
* autoIncrement, nullable, default
|
|
374
|
+
* Columns with autoIncrement, nullable, or default are optional
|
|
375
375
|
*
|
|
376
376
|
* @template T - Column builder record type
|
|
377
377
|
*/
|
|
@@ -381,9 +381,9 @@ export type OptionalInsertKeys<TBuilders extends ColumnBuilderRecord> = Exclude<
|
|
|
381
381
|
>;
|
|
382
382
|
|
|
383
383
|
/**
|
|
384
|
-
* INSERT
|
|
384
|
+
* INSERT Type inference
|
|
385
385
|
*
|
|
386
|
-
*
|
|
386
|
+
* Required columns are required, optional columns are Partial
|
|
387
387
|
*
|
|
388
388
|
* @template T - Column builder record type
|
|
389
389
|
*
|
|
@@ -400,9 +400,9 @@ export type InferInsertColumns<TBuilders extends ColumnBuilderRecord> = Pick<
|
|
|
400
400
|
Partial<Pick<InferColumns<TBuilders>, OptionalInsertKeys<TBuilders>>>;
|
|
401
401
|
|
|
402
402
|
/**
|
|
403
|
-
* UPDATE
|
|
403
|
+
* UPDATE Type inference
|
|
404
404
|
*
|
|
405
|
-
*
|
|
405
|
+
* All columns are optional
|
|
406
406
|
*
|
|
407
407
|
* @template T - Column builder record type
|
|
408
408
|
*/
|
|
@@ -411,7 +411,7 @@ export type InferUpdateColumns<TBuilders extends ColumnBuilderRecord> = Partial<
|
|
|
411
411
|
>;
|
|
412
412
|
|
|
413
413
|
/**
|
|
414
|
-
* data
|
|
414
|
+
* Transform from data record to Column builder record
|
|
415
415
|
*
|
|
416
416
|
* @template TData - data record type
|
|
417
417
|
*/
|