metal-orm 1.0.11 → 1.0.12
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 +4 -3
- package/dist/decorators/index.cjs +15 -2
- package/dist/decorators/index.cjs.map +1 -1
- package/dist/decorators/index.d.cts +1 -1
- package/dist/decorators/index.d.ts +1 -1
- package/dist/decorators/index.js +15 -2
- package/dist/decorators/index.js.map +1 -1
- package/dist/index.cjs +1394 -149
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +257 -23
- package/dist/index.d.ts +257 -23
- package/dist/index.js +1376 -149
- package/dist/index.js.map +1 -1
- package/dist/{select-654m4qy8.d.cts → select-BKlr2ivY.d.cts} +141 -4
- package/dist/{select-654m4qy8.d.ts → select-BKlr2ivY.d.ts} +141 -4
- package/package.json +1 -1
- package/src/core/ddl/dialects/base-schema-dialect.ts +48 -0
- package/src/core/ddl/dialects/index.ts +5 -0
- package/src/core/ddl/dialects/mssql-schema-dialect.ts +97 -0
- package/src/core/ddl/dialects/mysql-schema-dialect.ts +109 -0
- package/src/core/ddl/dialects/postgres-schema-dialect.ts +99 -0
- package/src/core/ddl/dialects/sqlite-schema-dialect.ts +103 -0
- package/src/core/ddl/introspect/mssql.ts +149 -0
- package/src/core/ddl/introspect/mysql.ts +99 -0
- package/src/core/ddl/introspect/postgres.ts +154 -0
- package/src/core/ddl/introspect/sqlite.ts +66 -0
- package/src/core/ddl/introspect/types.ts +19 -0
- package/src/core/ddl/introspect/utils.ts +27 -0
- package/src/core/ddl/schema-diff.ts +179 -0
- package/src/core/ddl/schema-generator.ts +229 -0
- package/src/core/ddl/schema-introspect.ts +32 -0
- package/src/core/ddl/schema-types.ts +39 -0
- package/src/core/dialect/base/sql-dialect.ts +161 -0
- package/src/core/dialect/mysql/index.ts +18 -112
- package/src/core/dialect/postgres/index.ts +30 -126
- package/src/core/dialect/sqlite/index.ts +29 -129
- package/src/index.ts +4 -0
- package/src/schema/column.ts +206 -27
- package/src/schema/table.ts +89 -32
- package/src/schema/types.ts +8 -5
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
import { CompilerContext
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* SQLite dialect implementation
|
|
7
|
-
*/
|
|
8
|
-
export class SqliteDialect extends
|
|
9
|
-
/**
|
|
10
|
-
* Creates a new SqliteDialect instance
|
|
11
|
-
*/
|
|
12
|
-
public constructor() {
|
|
1
|
+
import { CompilerContext } from '../abstract.js';
|
|
2
|
+
import { JsonPathNode, ColumnNode } from '../../ast/expression.js';
|
|
3
|
+
import { SqlDialectBase } from '../base/sql-dialect.js';
|
|
4
|
+
|
|
5
|
+
/**
|
|
6
|
+
* SQLite dialect implementation
|
|
7
|
+
*/
|
|
8
|
+
export class SqliteDialect extends SqlDialectBase {
|
|
9
|
+
/**
|
|
10
|
+
* Creates a new SqliteDialect instance
|
|
11
|
+
*/
|
|
12
|
+
public constructor() {
|
|
13
13
|
super();
|
|
14
14
|
}
|
|
15
15
|
|
|
@@ -27,120 +27,20 @@ export class SqliteDialect extends Dialect {
|
|
|
27
27
|
* @param node - JSON path node
|
|
28
28
|
* @returns SQLite JSON path expression
|
|
29
29
|
*/
|
|
30
|
-
protected compileJsonPath(node: JsonPathNode): string {
|
|
31
|
-
const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
32
|
-
// SQLite uses json_extract(col, '$.path')
|
|
33
|
-
return `json_extract(${col}, '${node.path}')`;
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
} else if (c.type === 'Column') {
|
|
48
|
-
expr = `${this.quoteIdentifier(c.table)}.${this.quoteIdentifier(c.name)}`;
|
|
49
|
-
} else if (c.type === 'ScalarSubquery') {
|
|
50
|
-
expr = this.compileOperand(c, ctx);
|
|
51
|
-
} else if (c.type === 'CaseExpression') {
|
|
52
|
-
expr = this.compileOperand(c, ctx);
|
|
53
|
-
} else if (c.type === 'WindowFunction') {
|
|
54
|
-
expr = this.compileOperand(c, ctx);
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
// Handle alias
|
|
58
|
-
if (c.alias) {
|
|
59
|
-
// Backward compat for the raw string parsing alias hack in playground
|
|
60
|
-
if (c.alias.includes('(')) return c.alias;
|
|
61
|
-
return `${expr} AS ${this.quoteIdentifier(c.alias)}`;
|
|
62
|
-
}
|
|
63
|
-
return expr;
|
|
64
|
-
}).join(', ');
|
|
65
|
-
|
|
66
|
-
const distinct = ast.distinct ? 'DISTINCT ' : '';
|
|
67
|
-
const from = `${this.quoteIdentifier(ast.from.name)}`;
|
|
68
|
-
|
|
69
|
-
const joins = ast.joins.map(j => {
|
|
70
|
-
const table = this.quoteIdentifier(j.table.name);
|
|
71
|
-
const cond = this.compileExpression(j.condition, ctx);
|
|
72
|
-
return `${j.kind} JOIN ${table} ON ${cond}`;
|
|
73
|
-
}).join(' ');
|
|
74
|
-
const whereClause = this.compileWhere(ast.where, ctx);
|
|
75
|
-
|
|
76
|
-
const groupBy = ast.groupBy && ast.groupBy.length > 0
|
|
77
|
-
? ' GROUP BY ' + ast.groupBy.map(c => `${this.quoteIdentifier(c.table)}.${this.quoteIdentifier(c.name)}`).join(', ')
|
|
78
|
-
: '';
|
|
79
|
-
|
|
80
|
-
const having = ast.having
|
|
81
|
-
? ` HAVING ${this.compileExpression(ast.having, ctx)}`
|
|
82
|
-
: '';
|
|
83
|
-
|
|
84
|
-
const orderBy = ast.orderBy && ast.orderBy.length > 0
|
|
85
|
-
? ' ORDER BY ' + ast.orderBy.map(o => `${this.quoteIdentifier(o.column.table)}.${this.quoteIdentifier(o.column.name)} ${o.direction}`).join(', ')
|
|
86
|
-
: '';
|
|
87
|
-
|
|
88
|
-
const limit = ast.limit ? ` LIMIT ${ast.limit}` : '';
|
|
89
|
-
const offset = ast.offset ? ` OFFSET ${ast.offset}` : '';
|
|
90
|
-
|
|
91
|
-
const ctes = ast.ctes && ast.ctes.length > 0
|
|
92
|
-
? (() => {
|
|
93
|
-
const hasRecursive = ast.ctes.some(cte => cte.recursive);
|
|
94
|
-
const prefix = hasRecursive ? 'WITH RECURSIVE ' : 'WITH ';
|
|
95
|
-
const cteDefs = ast.ctes.map(cte => {
|
|
96
|
-
const name = this.quoteIdentifier(cte.name);
|
|
97
|
-
const cols = cte.columns ? `(${cte.columns.map(c => this.quoteIdentifier(c)).join(', ')})` : '';
|
|
98
|
-
const query = this.compileSelectAst(cte.query, ctx).trim().replace(/;$/, '');
|
|
99
|
-
return `${name}${cols} AS (${query})`;
|
|
100
|
-
}).join(', ');
|
|
101
|
-
return prefix + cteDefs + ' ';
|
|
102
|
-
})()
|
|
103
|
-
: '';
|
|
104
|
-
|
|
105
|
-
return `${ctes}SELECT ${distinct}${columns} FROM ${from}${joins ? ' ' + joins : ''}${whereClause}${groupBy}${having}${orderBy}${limit}${offset};`;
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
protected compileInsertAst(ast: InsertQueryNode, ctx: CompilerContext): string {
|
|
109
|
-
const table = this.quoteIdentifier(ast.into.name);
|
|
110
|
-
const columnList = ast.columns.map(column => `${this.quoteIdentifier(column.table)}.${this.quoteIdentifier(column.name)}`).join(', ');
|
|
111
|
-
const values = ast.values.map(row => `(${row.map(value => this.compileOperand(value, ctx)).join(', ')})`).join(', ');
|
|
112
|
-
const returning = this.compileReturning(ast.returning, ctx);
|
|
113
|
-
return `INSERT INTO ${table} (${columnList}) VALUES ${values}${returning};`;
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
protected compileUpdateAst(ast: UpdateQueryNode, ctx: CompilerContext): string {
|
|
117
|
-
const table = this.quoteIdentifier(ast.table.name);
|
|
118
|
-
const assignments = ast.set.map(assignment => {
|
|
119
|
-
const col = assignment.column;
|
|
120
|
-
const target = `${this.quoteIdentifier(col.table)}.${this.quoteIdentifier(col.name)}`;
|
|
121
|
-
const value = this.compileOperand(assignment.value, ctx);
|
|
122
|
-
return `${target} = ${value}`;
|
|
123
|
-
}).join(', ');
|
|
124
|
-
const whereClause = this.compileWhere(ast.where, ctx);
|
|
125
|
-
const returning = this.compileReturning(ast.returning, ctx);
|
|
126
|
-
return `UPDATE ${table} SET ${assignments}${whereClause}${returning};`;
|
|
127
|
-
}
|
|
128
|
-
|
|
129
|
-
protected compileDeleteAst(ast: DeleteQueryNode, ctx: CompilerContext): string {
|
|
130
|
-
const table = this.quoteIdentifier(ast.from.name);
|
|
131
|
-
const whereClause = this.compileWhere(ast.where, ctx);
|
|
132
|
-
const returning = this.compileReturning(ast.returning, ctx);
|
|
133
|
-
return `DELETE FROM ${table}${whereClause}${returning};`;
|
|
134
|
-
}
|
|
135
|
-
|
|
136
|
-
protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
|
|
137
|
-
if (!returning || returning.length === 0) return '';
|
|
138
|
-
const columns = returning
|
|
139
|
-
.map(column => {
|
|
140
|
-
const tablePart = column.table ? `${this.quoteIdentifier(column.table)}.` : '';
|
|
141
|
-
return `${tablePart}${this.quoteIdentifier(column.name)}`;
|
|
142
|
-
})
|
|
143
|
-
.join(', ');
|
|
144
|
-
return ` RETURNING ${columns}`;
|
|
145
|
-
}
|
|
146
|
-
}
|
|
30
|
+
protected compileJsonPath(node: JsonPathNode): string {
|
|
31
|
+
const col = `${this.quoteIdentifier(node.column.table)}.${this.quoteIdentifier(node.column.name)}`;
|
|
32
|
+
// SQLite uses json_extract(col, '$.path')
|
|
33
|
+
return `json_extract(${col}, '${node.path}')`;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
protected compileReturning(returning: ColumnNode[] | undefined, ctx: CompilerContext): string {
|
|
37
|
+
if (!returning || returning.length === 0) return '';
|
|
38
|
+
const columns = returning
|
|
39
|
+
.map(column => {
|
|
40
|
+
const tablePart = column.table ? `${this.quoteIdentifier(column.table)}.` : '';
|
|
41
|
+
return `${tablePart}${this.quoteIdentifier(column.name)}`;
|
|
42
|
+
})
|
|
43
|
+
.join(', ');
|
|
44
|
+
return ` RETURNING ${columns}`;
|
|
45
|
+
}
|
|
46
|
+
}
|
package/src/index.ts
CHANGED
|
@@ -12,6 +12,10 @@ export * from './core/dialect/mysql/index.js';
|
|
|
12
12
|
export * from './core/dialect/mssql/index.js';
|
|
13
13
|
export * from './core/dialect/sqlite/index.js';
|
|
14
14
|
export * from './core/dialect/postgres/index.js';
|
|
15
|
+
export * from './core/ddl/schema-generator.js';
|
|
16
|
+
export * from './core/ddl/schema-types.js';
|
|
17
|
+
export * from './core/ddl/schema-diff.js';
|
|
18
|
+
export * from './core/ddl/schema-introspect.js';
|
|
15
19
|
export * from './orm/als.js';
|
|
16
20
|
export * from './orm/hydration.js';
|
|
17
21
|
export * from './codegen/typescript.js';
|
package/src/schema/column.ts
CHANGED
|
@@ -4,22 +4,68 @@
|
|
|
4
4
|
export type ColumnType =
|
|
5
5
|
| 'INT'
|
|
6
6
|
| 'INTEGER'
|
|
7
|
+
| 'BIGINT'
|
|
7
8
|
| 'VARCHAR'
|
|
8
9
|
| 'TEXT'
|
|
9
10
|
| 'JSON'
|
|
10
11
|
| 'ENUM'
|
|
12
|
+
| 'DECIMAL'
|
|
13
|
+
| 'FLOAT'
|
|
14
|
+
| 'DOUBLE'
|
|
15
|
+
| 'UUID'
|
|
16
|
+
| 'DATE'
|
|
17
|
+
| 'DATETIME'
|
|
18
|
+
| 'TIMESTAMP'
|
|
19
|
+
| 'TIMESTAMPTZ'
|
|
11
20
|
| 'BOOLEAN'
|
|
12
21
|
| 'int'
|
|
13
22
|
| 'integer'
|
|
23
|
+
| 'bigint'
|
|
14
24
|
| 'varchar'
|
|
15
25
|
| 'text'
|
|
16
26
|
| 'json'
|
|
17
27
|
| 'enum'
|
|
28
|
+
| 'decimal'
|
|
29
|
+
| 'float'
|
|
30
|
+
| 'double'
|
|
31
|
+
| 'uuid'
|
|
32
|
+
| 'date'
|
|
33
|
+
| 'datetime'
|
|
34
|
+
| 'timestamp'
|
|
35
|
+
| 'timestamptz'
|
|
18
36
|
| 'boolean';
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
37
|
+
|
|
38
|
+
export type ReferentialAction =
|
|
39
|
+
| 'NO ACTION'
|
|
40
|
+
| 'RESTRICT'
|
|
41
|
+
| 'CASCADE'
|
|
42
|
+
| 'SET NULL'
|
|
43
|
+
| 'SET DEFAULT';
|
|
44
|
+
|
|
45
|
+
export interface RawDefaultValue {
|
|
46
|
+
raw: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export type DefaultValue = unknown | RawDefaultValue;
|
|
50
|
+
|
|
51
|
+
export interface ForeignKeyReference {
|
|
52
|
+
/** Target table name */
|
|
53
|
+
table: string;
|
|
54
|
+
/** Target column name */
|
|
55
|
+
column: string;
|
|
56
|
+
/** Optional constraint name */
|
|
57
|
+
name?: string;
|
|
58
|
+
/** ON DELETE action */
|
|
59
|
+
onDelete?: ReferentialAction;
|
|
60
|
+
/** ON UPDATE action */
|
|
61
|
+
onUpdate?: ReferentialAction;
|
|
62
|
+
/** Whether the constraint is deferrable (Postgres) */
|
|
63
|
+
deferrable?: boolean;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
/**
|
|
67
|
+
* Definition of a database column
|
|
68
|
+
*/
|
|
23
69
|
export interface ColumnDef<T extends ColumnType = ColumnType> {
|
|
24
70
|
/** Column name (filled at runtime by defineTable) */
|
|
25
71
|
name: string;
|
|
@@ -29,12 +75,26 @@ export interface ColumnDef<T extends ColumnType = ColumnType> {
|
|
|
29
75
|
primary?: boolean;
|
|
30
76
|
/** Whether this column cannot be null */
|
|
31
77
|
notNull?: boolean;
|
|
78
|
+
/** Whether this column must be unique (or name of the unique constraint) */
|
|
79
|
+
unique?: boolean | string;
|
|
80
|
+
/** Default value for the column */
|
|
81
|
+
default?: DefaultValue;
|
|
82
|
+
/** Whether the column auto-increments / identity */
|
|
83
|
+
autoIncrement?: boolean;
|
|
84
|
+
/** Identity strategy where supported */
|
|
85
|
+
generated?: 'always' | 'byDefault';
|
|
86
|
+
/** Inline check constraint expression */
|
|
87
|
+
check?: string;
|
|
88
|
+
/** Foreign key reference */
|
|
89
|
+
references?: ForeignKeyReference;
|
|
90
|
+
/** Column comment/description */
|
|
91
|
+
comment?: string;
|
|
32
92
|
/** Additional arguments for the column type (e.g., VARCHAR length) */
|
|
33
93
|
args?: any[];
|
|
34
94
|
/** Table name this column belongs to (filled at runtime by defineTable) */
|
|
35
95
|
table?: string;
|
|
36
96
|
}
|
|
37
|
-
|
|
97
|
+
|
|
38
98
|
/**
|
|
39
99
|
* Factory for creating column definitions with common data types
|
|
40
100
|
*/
|
|
@@ -44,30 +104,149 @@ export const col = {
|
|
|
44
104
|
* @returns ColumnDef with INT type
|
|
45
105
|
*/
|
|
46
106
|
int: (): ColumnDef<'INT'> => ({ name: '', type: 'INT' }),
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Creates a
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
107
|
+
|
|
108
|
+
/**
|
|
109
|
+
* Creates a big integer column definition
|
|
110
|
+
*/
|
|
111
|
+
bigint: (): ColumnDef<'BIGINT'> => ({ name: '', type: 'BIGINT' }),
|
|
112
|
+
|
|
113
|
+
/**
|
|
114
|
+
* Creates a variable character column definition
|
|
115
|
+
* @param length - Maximum length of the string
|
|
116
|
+
* @returns ColumnDef with VARCHAR type
|
|
117
|
+
*/
|
|
53
118
|
varchar: (length: number): ColumnDef<'VARCHAR'> => ({ name: '', type: 'VARCHAR', args: [length] }),
|
|
54
|
-
|
|
55
|
-
/**
|
|
56
|
-
* Creates a
|
|
57
|
-
|
|
58
|
-
|
|
119
|
+
|
|
120
|
+
/**
|
|
121
|
+
* Creates a fixed precision decimal column definition
|
|
122
|
+
*/
|
|
123
|
+
decimal: (precision: number, scale = 0): ColumnDef<'DECIMAL'> => ({
|
|
124
|
+
name: '',
|
|
125
|
+
type: 'DECIMAL',
|
|
126
|
+
args: [precision, scale]
|
|
127
|
+
}),
|
|
128
|
+
|
|
129
|
+
/**
|
|
130
|
+
* Creates a floating point column definition
|
|
131
|
+
*/
|
|
132
|
+
float: (precision?: number): ColumnDef<'FLOAT'> => ({
|
|
133
|
+
name: '',
|
|
134
|
+
type: 'FLOAT',
|
|
135
|
+
args: precision !== undefined ? [precision] : undefined
|
|
136
|
+
}),
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Creates a UUID column definition
|
|
140
|
+
*/
|
|
141
|
+
uuid: (): ColumnDef<'UUID'> => ({ name: '', type: 'UUID' }),
|
|
142
|
+
|
|
143
|
+
/**
|
|
144
|
+
* Creates a timestamp column definition
|
|
145
|
+
*/
|
|
146
|
+
timestamp: (): ColumnDef<'TIMESTAMP'> => ({ name: '', type: 'TIMESTAMP' }),
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Creates a timestamptz column definition
|
|
150
|
+
*/
|
|
151
|
+
timestamptz: (): ColumnDef<'TIMESTAMPTZ'> => ({ name: '', type: 'TIMESTAMPTZ' }),
|
|
152
|
+
|
|
153
|
+
/**
|
|
154
|
+
* Creates a date column definition
|
|
155
|
+
*/
|
|
156
|
+
date: (): ColumnDef<'DATE'> => ({ name: '', type: 'DATE' }),
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* Creates a datetime column definition
|
|
160
|
+
*/
|
|
161
|
+
datetime: (): ColumnDef<'DATETIME'> => ({ name: '', type: 'DATETIME' }),
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Creates a JSON column definition
|
|
165
|
+
* @returns ColumnDef with JSON type
|
|
166
|
+
*/
|
|
59
167
|
json: (): ColumnDef<'JSON'> => ({ name: '', type: 'JSON' }),
|
|
60
168
|
|
|
61
|
-
/**
|
|
62
|
-
* Creates a boolean column definition
|
|
63
|
-
* @returns ColumnDef with BOOLEAN type
|
|
64
|
-
*/
|
|
169
|
+
/**
|
|
170
|
+
* Creates a boolean column definition
|
|
171
|
+
* @returns ColumnDef with BOOLEAN type
|
|
172
|
+
*/
|
|
65
173
|
boolean: (): ColumnDef<'BOOLEAN'> => ({ name: '', type: 'BOOLEAN' }),
|
|
66
|
-
|
|
67
|
-
/**
|
|
68
|
-
*
|
|
69
|
-
* @param
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Creates an enum column definition
|
|
177
|
+
* @param values - Enum values
|
|
178
|
+
*/
|
|
179
|
+
enum: (values: string[]): ColumnDef<'ENUM'> => ({ name: '', type: 'ENUM', args: values }),
|
|
180
|
+
|
|
181
|
+
/**
|
|
182
|
+
* Marks a column definition as a primary key
|
|
183
|
+
* @param def - Column definition to modify
|
|
184
|
+
* @returns Modified ColumnDef with primary: true
|
|
185
|
+
*/
|
|
186
|
+
primaryKey: <T extends ColumnType>(def: ColumnDef<T>): ColumnDef<T> =>
|
|
187
|
+
({ ...def, primary: true }),
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Marks a column as NOT NULL
|
|
191
|
+
*/
|
|
192
|
+
notNull: <T extends ColumnType>(def: ColumnDef<T>): ColumnDef<T> =>
|
|
193
|
+
({ ...def, notNull: true }),
|
|
194
|
+
|
|
195
|
+
/**
|
|
196
|
+
* Marks a column as UNIQUE
|
|
197
|
+
*/
|
|
198
|
+
unique: <T extends ColumnType>(def: ColumnDef<T>, name?: string): ColumnDef<T> =>
|
|
199
|
+
({
|
|
200
|
+
...def,
|
|
201
|
+
unique: name ?? true
|
|
202
|
+
}),
|
|
203
|
+
|
|
204
|
+
/**
|
|
205
|
+
* Sets a default value for the column
|
|
206
|
+
*/
|
|
207
|
+
default: <T extends ColumnType>(def: ColumnDef<T>, value: unknown): ColumnDef<T> =>
|
|
208
|
+
({
|
|
209
|
+
...def,
|
|
210
|
+
default: value
|
|
211
|
+
}),
|
|
212
|
+
|
|
213
|
+
/**
|
|
214
|
+
* Sets a raw SQL default value for the column
|
|
215
|
+
*/
|
|
216
|
+
defaultRaw: <T extends ColumnType>(def: ColumnDef<T>, expression: string): ColumnDef<T> =>
|
|
217
|
+
({
|
|
218
|
+
...def,
|
|
219
|
+
default: { raw: expression }
|
|
220
|
+
}),
|
|
221
|
+
|
|
222
|
+
/**
|
|
223
|
+
* Marks a column as auto-increment / identity
|
|
224
|
+
*/
|
|
225
|
+
autoIncrement: <T extends ColumnType>(
|
|
226
|
+
def: ColumnDef<T>,
|
|
227
|
+
strategy: ColumnDef['generated'] = 'byDefault'
|
|
228
|
+
): ColumnDef<T> =>
|
|
229
|
+
({
|
|
230
|
+
...def,
|
|
231
|
+
autoIncrement: true,
|
|
232
|
+
generated: strategy
|
|
233
|
+
}),
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Adds a foreign key reference
|
|
237
|
+
*/
|
|
238
|
+
references: <T extends ColumnType>(def: ColumnDef<T>, ref: ForeignKeyReference): ColumnDef<T> =>
|
|
239
|
+
({
|
|
240
|
+
...def,
|
|
241
|
+
references: ref
|
|
242
|
+
}),
|
|
243
|
+
|
|
244
|
+
/**
|
|
245
|
+
* Adds a check constraint to the column
|
|
246
|
+
*/
|
|
247
|
+
check: <T extends ColumnType>(def: ColumnDef<T>, expression: string): ColumnDef<T> =>
|
|
248
|
+
({
|
|
249
|
+
...def,
|
|
250
|
+
check: expression
|
|
251
|
+
})
|
|
73
252
|
};
|
package/src/schema/table.ts
CHANGED
|
@@ -1,11 +1,40 @@
|
|
|
1
|
-
import { ColumnDef } from './column.js';
|
|
2
|
-
import { RelationDef } from './relation.js';
|
|
3
|
-
|
|
4
|
-
export interface
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
1
|
+
import { ColumnDef } from './column.js';
|
|
2
|
+
import { RelationDef } from './relation.js';
|
|
3
|
+
|
|
4
|
+
export interface IndexColumn {
|
|
5
|
+
column: string;
|
|
6
|
+
order?: 'ASC' | 'DESC';
|
|
7
|
+
nulls?: 'FIRST' | 'LAST';
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export interface IndexDef {
|
|
11
|
+
name?: string;
|
|
12
|
+
columns: (string | IndexColumn)[];
|
|
13
|
+
unique?: boolean;
|
|
14
|
+
where?: string;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
export interface CheckConstraint {
|
|
18
|
+
name?: string;
|
|
19
|
+
expression: string;
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface TableOptions {
|
|
23
|
+
schema?: string;
|
|
24
|
+
primaryKey?: string[];
|
|
25
|
+
indexes?: IndexDef[];
|
|
26
|
+
checks?: CheckConstraint[];
|
|
27
|
+
comment?: string;
|
|
28
|
+
engine?: string;
|
|
29
|
+
charset?: string;
|
|
30
|
+
collation?: string;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
export interface TableHooks {
|
|
34
|
+
beforeInsert?(ctx: unknown, entity: any): Promise<void> | void;
|
|
35
|
+
afterInsert?(ctx: unknown, entity: any): Promise<void> | void;
|
|
36
|
+
beforeUpdate?(ctx: unknown, entity: any): Promise<void> | void;
|
|
37
|
+
afterUpdate?(ctx: unknown, entity: any): Promise<void> | void;
|
|
9
38
|
beforeDelete?(ctx: unknown, entity: any): Promise<void> | void;
|
|
10
39
|
afterDelete?(ctx: unknown, entity: any): Promise<void> | void;
|
|
11
40
|
}
|
|
@@ -14,16 +43,30 @@ export interface TableHooks {
|
|
|
14
43
|
* Definition of a database table with its columns and relationships
|
|
15
44
|
* @typeParam T - Type of the columns record
|
|
16
45
|
*/
|
|
17
|
-
export interface TableDef<T extends Record<string, ColumnDef> = Record<string, ColumnDef>> {
|
|
18
|
-
/** Name of the table */
|
|
19
|
-
name: string;
|
|
20
|
-
/**
|
|
21
|
-
|
|
22
|
-
/** Record of
|
|
23
|
-
|
|
24
|
-
/**
|
|
25
|
-
|
|
26
|
-
|
|
46
|
+
export interface TableDef<T extends Record<string, ColumnDef> = Record<string, ColumnDef>> {
|
|
47
|
+
/** Name of the table */
|
|
48
|
+
name: string;
|
|
49
|
+
/** Optional schema/catalog name */
|
|
50
|
+
schema?: string;
|
|
51
|
+
/** Record of column definitions keyed by column name */
|
|
52
|
+
columns: T;
|
|
53
|
+
/** Record of relationship definitions keyed by relation name */
|
|
54
|
+
relations: Record<string, RelationDef>;
|
|
55
|
+
/** Optional lifecycle hooks */
|
|
56
|
+
hooks?: TableHooks;
|
|
57
|
+
/** Composite primary key definition (falls back to column.primary flags) */
|
|
58
|
+
primaryKey?: string[];
|
|
59
|
+
/** Secondary indexes */
|
|
60
|
+
indexes?: IndexDef[];
|
|
61
|
+
/** Table-level check constraints */
|
|
62
|
+
checks?: CheckConstraint[];
|
|
63
|
+
/** Table comment/description */
|
|
64
|
+
comment?: string;
|
|
65
|
+
/** Dialect-specific options */
|
|
66
|
+
engine?: string;
|
|
67
|
+
charset?: string;
|
|
68
|
+
collation?: string;
|
|
69
|
+
}
|
|
27
70
|
|
|
28
71
|
/**
|
|
29
72
|
* Creates a table definition with columns and relationships
|
|
@@ -42,17 +85,31 @@ export interface TableDef<T extends Record<string, ColumnDef> = Record<string, C
|
|
|
42
85
|
* });
|
|
43
86
|
* ```
|
|
44
87
|
*/
|
|
45
|
-
export const defineTable = <T extends Record<string, ColumnDef>>(
|
|
46
|
-
name: string,
|
|
47
|
-
columns: T,
|
|
48
|
-
relations: Record<string, RelationDef> = {},
|
|
49
|
-
hooks?: TableHooks
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
88
|
+
export const defineTable = <T extends Record<string, ColumnDef>>(
|
|
89
|
+
name: string,
|
|
90
|
+
columns: T,
|
|
91
|
+
relations: Record<string, RelationDef> = {},
|
|
92
|
+
hooks?: TableHooks,
|
|
93
|
+
options: TableOptions = {}
|
|
94
|
+
): TableDef<T> => {
|
|
95
|
+
// Runtime mutability to assign names to column definitions for convenience
|
|
96
|
+
const colsWithNames = Object.entries(columns).reduce((acc, [key, def]) => {
|
|
97
|
+
(acc as any)[key] = { ...def, name: key, table: name };
|
|
98
|
+
return acc;
|
|
99
|
+
}, {} as T);
|
|
100
|
+
|
|
101
|
+
return {
|
|
102
|
+
name,
|
|
103
|
+
schema: options.schema,
|
|
104
|
+
columns: colsWithNames,
|
|
105
|
+
relations,
|
|
106
|
+
hooks,
|
|
107
|
+
primaryKey: options.primaryKey,
|
|
108
|
+
indexes: options.indexes,
|
|
109
|
+
checks: options.checks,
|
|
110
|
+
comment: options.comment,
|
|
111
|
+
engine: options.engine,
|
|
112
|
+
charset: options.charset,
|
|
113
|
+
collation: options.collation
|
|
114
|
+
};
|
|
115
|
+
};
|
package/src/schema/types.ts
CHANGED
|
@@ -10,11 +10,14 @@ import {
|
|
|
10
10
|
/**
|
|
11
11
|
* Maps a ColumnDef to its TypeScript type representation
|
|
12
12
|
*/
|
|
13
|
-
export type ColumnToTs<T extends ColumnDef> =
|
|
14
|
-
T['type'] extends 'INT' | 'INTEGER' | 'int' | 'integer' ? number :
|
|
15
|
-
T['type'] extends '
|
|
16
|
-
T['type'] extends '
|
|
17
|
-
|
|
13
|
+
export type ColumnToTs<T extends ColumnDef> =
|
|
14
|
+
T['type'] extends 'INT' | 'INTEGER' | 'int' | 'integer' ? number :
|
|
15
|
+
T['type'] extends 'BIGINT' | 'bigint' ? number | bigint :
|
|
16
|
+
T['type'] extends 'DECIMAL' | 'decimal' | 'FLOAT' | 'float' | 'DOUBLE' | 'double' ? number :
|
|
17
|
+
T['type'] extends 'BOOLEAN' | 'boolean' ? boolean :
|
|
18
|
+
T['type'] extends 'JSON' | 'json' ? unknown :
|
|
19
|
+
T['type'] extends 'DATE' | 'date' | 'DATETIME' | 'datetime' | 'TIMESTAMP' | 'timestamp' | 'TIMESTAMPTZ' | 'timestamptz' ? string :
|
|
20
|
+
string;
|
|
18
21
|
|
|
19
22
|
/**
|
|
20
23
|
* Infers a row shape from a table definition
|