@cheetah.js/orm 0.1.45 → 0.1.46
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/SqlBuilder.d.ts +18 -33
- package/dist/SqlBuilder.js +99 -586
- package/dist/driver/bun-driver.base.d.ts +35 -1
- package/dist/driver/bun-driver.base.js +132 -0
- package/dist/driver/bun-mysql.driver.d.ts +13 -6
- package/dist/driver/bun-mysql.driver.js +47 -72
- package/dist/driver/bun-pg.driver.d.ts +12 -6
- package/dist/driver/bun-pg.driver.js +27 -59
- package/dist/driver/driver.interface.d.ts +1 -1
- package/dist/query/model-transformer.d.ts +21 -0
- package/dist/query/model-transformer.js +118 -0
- package/dist/query/sql-column-manager.d.ts +25 -0
- package/dist/query/sql-column-manager.js +124 -0
- package/dist/query/sql-condition-builder.d.ts +36 -0
- package/dist/query/sql-condition-builder.js +160 -0
- package/dist/query/sql-join-manager.d.ts +39 -0
- package/dist/query/sql-join-manager.js +224 -0
- package/dist/utils/value-processor.d.ts +14 -0
- package/dist/utils/value-processor.js +84 -0
- package/package.json +3 -3
- package/build.ts +0 -14
- package/cheetah.config.ts +0 -14
- package/dist/SqlBuilder.js.map +0 -1
- package/dist/bun/index.js +0 -233434
- package/dist/bun/index.js.map +0 -336
- package/dist/common/email.vo.js.map +0 -1
- package/dist/common/uuid.js.map +0 -1
- package/dist/common/value-object.js.map +0 -1
- package/dist/constants.js.map +0 -1
- package/dist/decorators/entity.decorator.js.map +0 -1
- package/dist/decorators/enum.decorator.js.map +0 -1
- package/dist/decorators/event-hook.decorator.js.map +0 -1
- package/dist/decorators/index.decorator.js.map +0 -1
- package/dist/decorators/one-many.decorator.js.map +0 -1
- package/dist/decorators/primary-key.decorator.js.map +0 -1
- package/dist/decorators/property.decorator.js.map +0 -1
- package/dist/domain/base-entity.js.map +0 -1
- package/dist/domain/collection.js.map +0 -1
- package/dist/domain/entities.js.map +0 -1
- package/dist/domain/reference.js.map +0 -1
- package/dist/driver/bun-driver.base.js.map +0 -1
- package/dist/driver/bun-mysql.driver.js.map +0 -1
- package/dist/driver/bun-pg.driver.js.map +0 -1
- package/dist/driver/driver.interface.js.map +0 -1
- package/dist/driver/pg-driver.d.ts +0 -63
- package/dist/driver/pg-driver.js +0 -335
- package/dist/driver/pg-driver.js.map +0 -1
- package/dist/entry.js.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/orm.js.map +0 -1
- package/dist/orm.service.js.map +0 -1
- package/dist/utils.js.map +0 -1
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { SQL } from 'bun';
|
|
2
|
-
import { ConnectionSettings, DriverInterface } from './driver.interface';
|
|
2
|
+
import { ConnectionSettings, DriverInterface, Statement, SnapshotConstraintInfo, ColDiff } from './driver.interface';
|
|
3
3
|
export declare abstract class BunDriverBase implements Partial<DriverInterface> {
|
|
4
4
|
protected sql: SQL;
|
|
5
5
|
connectionString: string;
|
|
@@ -7,6 +7,7 @@ export declare abstract class BunDriverBase implements Partial<DriverInterface>
|
|
|
7
7
|
constructor(options: ConnectionSettings);
|
|
8
8
|
protected buildConnectionString(options: ConnectionSettings): string;
|
|
9
9
|
protected abstract getProtocol(): string;
|
|
10
|
+
protected abstract getIdentifierQuote(): string;
|
|
10
11
|
connect(): Promise<void>;
|
|
11
12
|
protected validateConnection(): Promise<void>;
|
|
12
13
|
disconnect(): Promise<void>;
|
|
@@ -18,4 +19,37 @@ export declare abstract class BunDriverBase implements Partial<DriverInterface>
|
|
|
18
19
|
protected buildOrderByClause(orderBy: string[] | undefined): string;
|
|
19
20
|
protected buildLimitClause(limit: number | undefined): string;
|
|
20
21
|
protected buildOffsetClause(offset: number | undefined): string;
|
|
22
|
+
protected quote(identifier: string): string;
|
|
23
|
+
protected buildTableIdentifier(schema: string | undefined, tableName: string): string;
|
|
24
|
+
protected buildColumnConstraints(colDiff: ColDiff): string;
|
|
25
|
+
protected abstract buildAutoIncrementType(colDiff: ColDiff): string;
|
|
26
|
+
protected abstract buildEnumType(schema: string | undefined, tableName: string, colDiff: ColDiff): {
|
|
27
|
+
beforeSql: string;
|
|
28
|
+
columnType: string;
|
|
29
|
+
};
|
|
30
|
+
protected abstract handleInsertReturn(statement: Statement<any>, result: any, sql: string, startTime: number): Promise<{
|
|
31
|
+
query: any;
|
|
32
|
+
startTime: number;
|
|
33
|
+
sql: string;
|
|
34
|
+
}>;
|
|
35
|
+
executeStatement(statement: Statement<any>): Promise<{
|
|
36
|
+
query: any;
|
|
37
|
+
startTime: number;
|
|
38
|
+
sql: string;
|
|
39
|
+
}>;
|
|
40
|
+
protected buildInsertSqlWithReturn(statement: Statement<any>): string;
|
|
41
|
+
protected abstract appendReturningClause(sql: string, statement: Statement<any>): string;
|
|
42
|
+
protected buildStatementSql(statement: Statement<any>): string;
|
|
43
|
+
protected buildBaseSql(statement: Statement<any>): string;
|
|
44
|
+
protected buildInsertSql(table: string, values: any, columns: string[] | undefined, alias: string): string;
|
|
45
|
+
protected buildUpdateSql(table: string, values: any, alias: string): string;
|
|
46
|
+
protected buildJoinClause(statement: Statement<any>): string;
|
|
47
|
+
protected buildWhereAndOrderClauses(statement: Statement<any>): string;
|
|
48
|
+
protected buildLimitAndOffsetClause(statement: Statement<any>): string;
|
|
49
|
+
protected getForeignKeysFromConstraints(constraints: SnapshotConstraintInfo[], row: any, columnNameField: string): any[];
|
|
50
|
+
protected isForeignKeyConstraint(constraint: SnapshotConstraintInfo, columnName: string): boolean;
|
|
51
|
+
protected parseForeignKeyDefinition(consDef: string): {
|
|
52
|
+
referencedColumnName: string;
|
|
53
|
+
referencedTableName: string;
|
|
54
|
+
};
|
|
21
55
|
}
|
|
@@ -83,4 +83,136 @@ export class BunDriverBase {
|
|
|
83
83
|
}
|
|
84
84
|
return ` OFFSET ${offset}`;
|
|
85
85
|
}
|
|
86
|
+
quote(identifier) {
|
|
87
|
+
const q = this.getIdentifierQuote();
|
|
88
|
+
return `${q}${identifier}${q}`;
|
|
89
|
+
}
|
|
90
|
+
buildTableIdentifier(schema, tableName) {
|
|
91
|
+
return schema
|
|
92
|
+
? `${this.quote(schema)}.${this.quote(tableName)}`
|
|
93
|
+
: this.quote(tableName);
|
|
94
|
+
}
|
|
95
|
+
buildColumnConstraints(colDiff) {
|
|
96
|
+
const parts = [];
|
|
97
|
+
if (!colDiff.colChanges?.nullable) {
|
|
98
|
+
parts.push('NOT NULL');
|
|
99
|
+
}
|
|
100
|
+
if (colDiff.colChanges?.primary) {
|
|
101
|
+
parts.push('PRIMARY KEY');
|
|
102
|
+
}
|
|
103
|
+
if (colDiff.colChanges?.unique) {
|
|
104
|
+
parts.push('UNIQUE');
|
|
105
|
+
}
|
|
106
|
+
if (colDiff.colChanges?.default) {
|
|
107
|
+
parts.push(`DEFAULT ${colDiff.colChanges.default}`);
|
|
108
|
+
}
|
|
109
|
+
return parts.length > 0 ? ' ' + parts.join(' ') : '';
|
|
110
|
+
}
|
|
111
|
+
async executeStatement(statement) {
|
|
112
|
+
const startTime = Date.now();
|
|
113
|
+
if (statement.statement === 'insert') {
|
|
114
|
+
const sql = this.buildInsertSqlWithReturn(statement);
|
|
115
|
+
const result = await this.sql.unsafe(sql);
|
|
116
|
+
return this.handleInsertReturn(statement, result, sql, startTime);
|
|
117
|
+
}
|
|
118
|
+
const sql = this.buildStatementSql(statement);
|
|
119
|
+
const result = await this.sql.unsafe(sql);
|
|
120
|
+
return {
|
|
121
|
+
query: { rows: Array.isArray(result) ? result : [] },
|
|
122
|
+
startTime,
|
|
123
|
+
sql,
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
buildInsertSqlWithReturn(statement) {
|
|
127
|
+
const baseSql = this.buildInsertSql(statement.table, statement.values, statement.columns, statement.alias);
|
|
128
|
+
return this.appendReturningClause(baseSql, statement);
|
|
129
|
+
}
|
|
130
|
+
buildStatementSql(statement) {
|
|
131
|
+
let sql = this.buildBaseSql(statement);
|
|
132
|
+
sql += this.buildJoinClause(statement);
|
|
133
|
+
sql += this.buildWhereAndOrderClauses(statement);
|
|
134
|
+
return sql;
|
|
135
|
+
}
|
|
136
|
+
buildBaseSql(statement) {
|
|
137
|
+
const { statement: type, table, columns, values, alias } = statement;
|
|
138
|
+
switch (type) {
|
|
139
|
+
case 'select':
|
|
140
|
+
return `SELECT ${columns ? columns.join(', ') : '*'} FROM ${table} ${alias}`;
|
|
141
|
+
case 'insert':
|
|
142
|
+
return this.buildInsertSql(table, values, columns, alias);
|
|
143
|
+
case 'update':
|
|
144
|
+
return this.buildUpdateSql(table, values, alias);
|
|
145
|
+
default:
|
|
146
|
+
return '';
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
buildInsertSql(table, values, columns, alias) {
|
|
150
|
+
const q = this.getIdentifierQuote();
|
|
151
|
+
const fields = Object.keys(values)
|
|
152
|
+
.map((v) => `${q}${v}${q}`)
|
|
153
|
+
.join(', ');
|
|
154
|
+
const vals = Object.values(values)
|
|
155
|
+
.map((value) => this.toDatabaseValue(value))
|
|
156
|
+
.join(', ');
|
|
157
|
+
return `INSERT INTO ${table} (${fields}) VALUES (${vals})`;
|
|
158
|
+
}
|
|
159
|
+
buildUpdateSql(table, values, alias) {
|
|
160
|
+
const sets = Object.entries(values)
|
|
161
|
+
.map(([key, value]) => `${key} = ${this.toDatabaseValue(value)}`)
|
|
162
|
+
.join(', ');
|
|
163
|
+
return `UPDATE ${table} as ${alias} SET ${sets}`;
|
|
164
|
+
}
|
|
165
|
+
buildJoinClause(statement) {
|
|
166
|
+
if (!statement.join)
|
|
167
|
+
return '';
|
|
168
|
+
return statement.join
|
|
169
|
+
.map((join) => {
|
|
170
|
+
const table = `${join.joinSchema}.${join.joinTable}`;
|
|
171
|
+
return ` ${join.type} JOIN ${table} ${join.joinAlias} ON ${join.on}`;
|
|
172
|
+
})
|
|
173
|
+
.join('');
|
|
174
|
+
}
|
|
175
|
+
buildWhereAndOrderClauses(statement) {
|
|
176
|
+
if (statement.statement === 'insert')
|
|
177
|
+
return '';
|
|
178
|
+
let sql = this.buildWhereClause(statement.where);
|
|
179
|
+
sql += this.buildOrderByClause(statement.orderBy);
|
|
180
|
+
sql += this.buildLimitAndOffsetClause(statement);
|
|
181
|
+
return sql;
|
|
182
|
+
}
|
|
183
|
+
buildLimitAndOffsetClause(statement) {
|
|
184
|
+
const { offset, limit } = statement;
|
|
185
|
+
if (offset && limit) {
|
|
186
|
+
return this.buildOffsetClause(offset) + this.buildLimitClause(limit);
|
|
187
|
+
}
|
|
188
|
+
if (limit) {
|
|
189
|
+
return this.buildLimitClause(limit);
|
|
190
|
+
}
|
|
191
|
+
return '';
|
|
192
|
+
}
|
|
193
|
+
getForeignKeysFromConstraints(constraints, row, columnNameField) {
|
|
194
|
+
const columnName = row[columnNameField];
|
|
195
|
+
return constraints
|
|
196
|
+
.filter((c) => this.isForeignKeyConstraint(c, columnName))
|
|
197
|
+
.map((c) => this.parseForeignKeyDefinition(c.consDef));
|
|
198
|
+
}
|
|
199
|
+
isForeignKeyConstraint(constraint, columnName) {
|
|
200
|
+
return (constraint.type === 'FOREIGN KEY' &&
|
|
201
|
+
constraint.consDef.includes(columnName));
|
|
202
|
+
}
|
|
203
|
+
parseForeignKeyDefinition(consDef) {
|
|
204
|
+
const q = this.getIdentifierQuote();
|
|
205
|
+
const pattern = new RegExp(`REFERENCES\\s+${q}([^${q}]+)${q}\\s*\\(([^)]+)\\)`);
|
|
206
|
+
const filter = consDef.match(pattern);
|
|
207
|
+
if (!filter) {
|
|
208
|
+
throw new Error('Invalid constraint definition');
|
|
209
|
+
}
|
|
210
|
+
return {
|
|
211
|
+
referencedColumnName: filter[2]
|
|
212
|
+
.split(',')[0]
|
|
213
|
+
.trim()
|
|
214
|
+
.replace(new RegExp(q, 'g'), ''),
|
|
215
|
+
referencedTableName: filter[1],
|
|
216
|
+
};
|
|
217
|
+
}
|
|
86
218
|
}
|
|
@@ -4,6 +4,19 @@ export declare class BunMysqlDriver extends BunDriverBase implements DriverInter
|
|
|
4
4
|
readonly dbType: "mysql";
|
|
5
5
|
constructor(options: ConnectionSettings);
|
|
6
6
|
protected getProtocol(): string;
|
|
7
|
+
protected getIdentifierQuote(): string;
|
|
8
|
+
protected buildAutoIncrementType(colDiff: ColDiff): string;
|
|
9
|
+
protected buildEnumType(schema: string | undefined, tableName: string, colDiff: ColDiff): {
|
|
10
|
+
beforeSql: string;
|
|
11
|
+
columnType: string;
|
|
12
|
+
};
|
|
13
|
+
protected appendReturningClause(sql: string, statement: Statement<any>): string;
|
|
14
|
+
protected handleInsertReturn(statement: Statement<any>, result: any, sql: string, startTime: number): Promise<{
|
|
15
|
+
query: any;
|
|
16
|
+
startTime: number;
|
|
17
|
+
sql: string;
|
|
18
|
+
}>;
|
|
19
|
+
protected buildLimitAndOffsetClause(statement: Statement<any>): string;
|
|
7
20
|
getCreateTableInstruction(schema: string | undefined, tableName: string, creates: ColDiff[]): string;
|
|
8
21
|
getAlterTableFkInstruction(schema: string | undefined, tableName: string, colDiff: ColDiff, fk: ForeignKeyInfo): string;
|
|
9
22
|
getCreateIndex(index: {
|
|
@@ -29,14 +42,8 @@ export declare class BunMysqlDriver extends BunDriverBase implements DriverInter
|
|
|
29
42
|
getDropTypeEnumInstruction(param: {
|
|
30
43
|
name: string;
|
|
31
44
|
}, schema: string | undefined, tableName: string): string;
|
|
32
|
-
executeStatement(statement: Statement<any>): Promise<{
|
|
33
|
-
query: any;
|
|
34
|
-
startTime: number;
|
|
35
|
-
sql: string;
|
|
36
|
-
}>;
|
|
37
45
|
snapshot(tableName: string, options: any): Promise<SnapshotTable | undefined>;
|
|
38
46
|
private parseEnumValues;
|
|
39
|
-
private getForeignKeys;
|
|
40
47
|
index(tableName: string, options: any): Promise<SnapshotIndexInfo[] | undefined>;
|
|
41
48
|
constraints(tableName: string, options: any): Promise<SnapshotConstraintInfo[] | undefined>;
|
|
42
49
|
}
|
|
@@ -7,6 +7,52 @@ export class BunMysqlDriver extends BunDriverBase {
|
|
|
7
7
|
getProtocol() {
|
|
8
8
|
return 'mysql';
|
|
9
9
|
}
|
|
10
|
+
getIdentifierQuote() {
|
|
11
|
+
return '`';
|
|
12
|
+
}
|
|
13
|
+
buildAutoIncrementType(colDiff) {
|
|
14
|
+
return 'INT AUTO_INCREMENT';
|
|
15
|
+
}
|
|
16
|
+
buildEnumType(schema, tableName, colDiff) {
|
|
17
|
+
const enumValues = colDiff.colChanges.enumItems
|
|
18
|
+
.map((item) => `'${item}'`)
|
|
19
|
+
.join(', ');
|
|
20
|
+
return {
|
|
21
|
+
beforeSql: '',
|
|
22
|
+
columnType: `ENUM(${enumValues})`,
|
|
23
|
+
};
|
|
24
|
+
}
|
|
25
|
+
appendReturningClause(sql, statement) {
|
|
26
|
+
return sql;
|
|
27
|
+
}
|
|
28
|
+
async handleInsertReturn(statement, result, sql, startTime) {
|
|
29
|
+
if (!statement.columns) {
|
|
30
|
+
return {
|
|
31
|
+
query: { rows: Array.isArray(result) ? result : [] },
|
|
32
|
+
startTime,
|
|
33
|
+
sql,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
const insertId = result.lastInsertRowid;
|
|
37
|
+
const cols = statement.columns.join(', ').replaceAll(`${statement.alias}.`, '');
|
|
38
|
+
const selectSql = `SELECT ${cols} FROM ${statement.table} WHERE id = ${insertId}`;
|
|
39
|
+
const selectResult = await this.sql.unsafe(selectSql);
|
|
40
|
+
return {
|
|
41
|
+
query: { rows: Array.isArray(selectResult) ? selectResult : [] },
|
|
42
|
+
startTime,
|
|
43
|
+
sql,
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
buildLimitAndOffsetClause(statement) {
|
|
47
|
+
const { offset, limit } = statement;
|
|
48
|
+
if (offset && limit) {
|
|
49
|
+
return ` LIMIT ${offset}, ${limit}`;
|
|
50
|
+
}
|
|
51
|
+
if (limit) {
|
|
52
|
+
return this.buildLimitClause(limit);
|
|
53
|
+
}
|
|
54
|
+
return '';
|
|
55
|
+
}
|
|
10
56
|
getCreateTableInstruction(schema, tableName, creates) {
|
|
11
57
|
let beforeSql = ``;
|
|
12
58
|
const st = `CREATE TABLE \`${schema}\`.\`${tableName}\` (${creates
|
|
@@ -114,63 +160,6 @@ export class BunMysqlDriver extends BunDriverBase {
|
|
|
114
160
|
getDropTypeEnumInstruction(param, schema, tableName) {
|
|
115
161
|
return '';
|
|
116
162
|
}
|
|
117
|
-
async executeStatement(statement) {
|
|
118
|
-
let { statement: statementType, table, columns, where, limit, alias } = statement;
|
|
119
|
-
let sql = '';
|
|
120
|
-
switch (statementType) {
|
|
121
|
-
case 'select':
|
|
122
|
-
sql = `SELECT ${columns ? columns.join(', ') : '*'} FROM ${table} ${alias}`;
|
|
123
|
-
break;
|
|
124
|
-
case 'insert':
|
|
125
|
-
const fields = Object.keys(statement.values)
|
|
126
|
-
.map((v) => `\`${v}\``)
|
|
127
|
-
.join(', ');
|
|
128
|
-
const values = Object.values(statement.values)
|
|
129
|
-
.map((value) => this.toDatabaseValue(value))
|
|
130
|
-
.join(', ');
|
|
131
|
-
sql = `INSERT INTO ${table} (${fields}) VALUES (${values})`;
|
|
132
|
-
break;
|
|
133
|
-
case 'update':
|
|
134
|
-
sql = `UPDATE ${table} as ${alias} SET ${Object.entries(statement.values)
|
|
135
|
-
.map(([key, value]) => `${key} = ${this.toDatabaseValue(value)}`)
|
|
136
|
-
.join(', ')}`;
|
|
137
|
-
break;
|
|
138
|
-
case 'delete':
|
|
139
|
-
break;
|
|
140
|
-
}
|
|
141
|
-
if (statement.join) {
|
|
142
|
-
statement.join.forEach((join) => {
|
|
143
|
-
sql += ` ${join.type} JOIN ${join.joinSchema}.${join.joinTable} ${join.joinAlias} ON ${join.on}`;
|
|
144
|
-
});
|
|
145
|
-
}
|
|
146
|
-
if (statementType !== 'insert') {
|
|
147
|
-
sql += this.buildWhereClause(where);
|
|
148
|
-
sql += this.buildOrderByClause(statement.orderBy);
|
|
149
|
-
if (statement.offset && limit) {
|
|
150
|
-
sql += ` LIMIT ${statement.offset}, ${limit}`;
|
|
151
|
-
}
|
|
152
|
-
else if (limit) {
|
|
153
|
-
sql += this.buildLimitClause(limit);
|
|
154
|
-
}
|
|
155
|
-
}
|
|
156
|
-
const startTime = Date.now();
|
|
157
|
-
const result = await this.sql.unsafe(sql);
|
|
158
|
-
if (statementType === 'insert' && statement.columns) {
|
|
159
|
-
const insertId = result.lastInsertRowid;
|
|
160
|
-
const selectSql = `SELECT ${statement.columns.join(', ').replaceAll(`${alias}.`, '')} FROM ${table} WHERE id = ${insertId}`;
|
|
161
|
-
const insertResult = await this.sql.unsafe(selectSql);
|
|
162
|
-
return {
|
|
163
|
-
query: { rows: Array.isArray(insertResult) ? insertResult : [] },
|
|
164
|
-
startTime,
|
|
165
|
-
sql,
|
|
166
|
-
};
|
|
167
|
-
}
|
|
168
|
-
return {
|
|
169
|
-
query: { rows: Array.isArray(result) ? result : [] },
|
|
170
|
-
startTime,
|
|
171
|
-
sql,
|
|
172
|
-
};
|
|
173
|
-
}
|
|
174
163
|
async snapshot(tableName, options) {
|
|
175
164
|
const schema = (options && options.schema) || 'information_schema';
|
|
176
165
|
const sql = `SELECT * FROM information_schema.columns WHERE table_name = '${tableName}' AND table_schema = DATABASE()`;
|
|
@@ -195,7 +184,7 @@ export class BunMysqlDriver extends BunDriverBase {
|
|
|
195
184
|
primary: row.COLUMN_KEY === 'PRI',
|
|
196
185
|
unique: row.COLUMN_KEY === 'UNI' || row.COLUMN_KEY === 'PRI',
|
|
197
186
|
type: row.DATA_TYPE,
|
|
198
|
-
foreignKeys: this.
|
|
187
|
+
foreignKeys: this.getForeignKeysFromConstraints(constraints, row, 'COLUMN_NAME'),
|
|
199
188
|
isEnum: row.DATA_TYPE === 'enum',
|
|
200
189
|
enumItems: row.DATA_TYPE === 'enum' ? this.parseEnumValues(row.COLUMN_TYPE) : undefined,
|
|
201
190
|
precision: row.NUMERIC_PRECISION,
|
|
@@ -212,20 +201,6 @@ export class BunMysqlDriver extends BunDriverBase {
|
|
|
212
201
|
}
|
|
213
202
|
return match[1].split(',').map((v) => v.trim().replace(/'/g, ''));
|
|
214
203
|
}
|
|
215
|
-
getForeignKeys(constraints, row) {
|
|
216
|
-
return constraints
|
|
217
|
-
.filter((c) => c.type === 'FOREIGN KEY' && c.consDef.includes(row.COLUMN_NAME))
|
|
218
|
-
.map((c) => {
|
|
219
|
-
const filter = c.consDef.match(/REFERENCES\s+`([^`]+)`\s*\(([^)]+)\)/);
|
|
220
|
-
if (!filter) {
|
|
221
|
-
throw new Error('Invalid constraint definition');
|
|
222
|
-
}
|
|
223
|
-
return {
|
|
224
|
-
referencedColumnName: filter[2].split(',')[0].trim().replace(/`/g, ''),
|
|
225
|
-
referencedTableName: filter[1],
|
|
226
|
-
};
|
|
227
|
-
});
|
|
228
|
-
}
|
|
229
204
|
async index(tableName, options) {
|
|
230
205
|
const result = await this.sql.unsafe(`SHOW INDEX FROM \`${tableName}\` FROM \`${options.schema || 'information_schema'}\``);
|
|
231
206
|
return result
|
|
@@ -4,6 +4,18 @@ export declare class BunPgDriver extends BunDriverBase implements DriverInterfac
|
|
|
4
4
|
readonly dbType: "postgres";
|
|
5
5
|
constructor(options: ConnectionSettings);
|
|
6
6
|
protected getProtocol(): string;
|
|
7
|
+
protected getIdentifierQuote(): string;
|
|
8
|
+
protected buildAutoIncrementType(colDiff: ColDiff): string;
|
|
9
|
+
protected buildEnumType(schema: string | undefined, tableName: string, colDiff: ColDiff): {
|
|
10
|
+
beforeSql: string;
|
|
11
|
+
columnType: string;
|
|
12
|
+
};
|
|
13
|
+
protected appendReturningClause(sql: string, statement: Statement<any>): string;
|
|
14
|
+
protected handleInsertReturn(statement: Statement<any>, result: any, sql: string, startTime: number): Promise<{
|
|
15
|
+
query: any;
|
|
16
|
+
startTime: number;
|
|
17
|
+
sql: string;
|
|
18
|
+
}>;
|
|
7
19
|
getCreateTableInstruction(schema: string | undefined, tableName: string, creates: ColDiff[]): string;
|
|
8
20
|
getAlterTableFkInstruction(schema: string | undefined, tableName: string, colDiff: ColDiff, fk: ForeignKeyInfo): string;
|
|
9
21
|
getCreateIndex(index: {
|
|
@@ -29,13 +41,7 @@ export declare class BunPgDriver extends BunDriverBase implements DriverInterfac
|
|
|
29
41
|
getDropTypeEnumInstruction(param: {
|
|
30
42
|
name: string;
|
|
31
43
|
}, schema: string | undefined, tableName: string): string;
|
|
32
|
-
executeStatement(statement: Statement<any>): Promise<{
|
|
33
|
-
query: any;
|
|
34
|
-
startTime: number;
|
|
35
|
-
sql: string;
|
|
36
|
-
}>;
|
|
37
44
|
snapshot(tableName: string, options: any): Promise<SnapshotTable | undefined>;
|
|
38
|
-
private getForeignKeys;
|
|
39
45
|
index(tableName: string, options: any): Promise<SnapshotIndexInfo[] | undefined>;
|
|
40
46
|
constraints(tableName: string, options: any): Promise<SnapshotConstraintInfo[] | undefined>;
|
|
41
47
|
private getEnums;
|
|
@@ -7,6 +7,32 @@ export class BunPgDriver extends BunDriverBase {
|
|
|
7
7
|
getProtocol() {
|
|
8
8
|
return 'postgres';
|
|
9
9
|
}
|
|
10
|
+
getIdentifierQuote() {
|
|
11
|
+
return '"';
|
|
12
|
+
}
|
|
13
|
+
buildAutoIncrementType(colDiff) {
|
|
14
|
+
return 'SERIAL';
|
|
15
|
+
}
|
|
16
|
+
buildEnumType(schema, tableName, colDiff) {
|
|
17
|
+
const enumName = `${schema}_${tableName}_${colDiff.colName}_enum`;
|
|
18
|
+
const enumValues = colDiff.colChanges.enumItems
|
|
19
|
+
.map((item) => `'${item}'`)
|
|
20
|
+
.join(', ');
|
|
21
|
+
const beforeSql = `CREATE TYPE "${enumName}" AS ENUM (${enumValues});`;
|
|
22
|
+
const columnType = `"${enumName}"`;
|
|
23
|
+
return { beforeSql, columnType };
|
|
24
|
+
}
|
|
25
|
+
appendReturningClause(sql, statement) {
|
|
26
|
+
const cols = statement.columns.join(', ').replaceAll(`${statement.alias}.`, '');
|
|
27
|
+
return `${sql} RETURNING ${cols}`;
|
|
28
|
+
}
|
|
29
|
+
async handleInsertReturn(statement, result, sql, startTime) {
|
|
30
|
+
return {
|
|
31
|
+
query: { rows: Array.isArray(result) ? result : [] },
|
|
32
|
+
startTime,
|
|
33
|
+
sql,
|
|
34
|
+
};
|
|
35
|
+
}
|
|
10
36
|
getCreateTableInstruction(schema, tableName, creates) {
|
|
11
37
|
let beforeSql = ``;
|
|
12
38
|
const st = `CREATE TABLE "${schema}"."${tableName}" (${creates
|
|
@@ -106,49 +132,6 @@ export class BunPgDriver extends BunDriverBase {
|
|
|
106
132
|
getDropTypeEnumInstruction(param, schema, tableName) {
|
|
107
133
|
return `DROP TYPE IF EXISTS "${param.name}";`;
|
|
108
134
|
}
|
|
109
|
-
async executeStatement(statement) {
|
|
110
|
-
let { statement: statementType, table, columns, where, limit, alias } = statement;
|
|
111
|
-
let sql = '';
|
|
112
|
-
switch (statementType) {
|
|
113
|
-
case 'select':
|
|
114
|
-
sql = `SELECT ${columns ? columns.join(', ') : '*'} FROM ${table} ${alias}`;
|
|
115
|
-
break;
|
|
116
|
-
case 'insert':
|
|
117
|
-
const fields = Object.keys(statement.values)
|
|
118
|
-
.map((v) => `"${v}"`)
|
|
119
|
-
.join(', ');
|
|
120
|
-
const values = Object.values(statement.values)
|
|
121
|
-
.map((value) => this.toDatabaseValue(value))
|
|
122
|
-
.join(', ');
|
|
123
|
-
sql = `INSERT INTO ${table} (${fields}) VALUES (${values}) RETURNING ${statement.columns.join(', ').replaceAll(`${alias}.`, '')}`;
|
|
124
|
-
break;
|
|
125
|
-
case 'update':
|
|
126
|
-
sql = `UPDATE ${table} as ${alias} SET ${Object.entries(statement.values)
|
|
127
|
-
.map(([key, value]) => `${key} = ${this.toDatabaseValue(value)}`)
|
|
128
|
-
.join(', ')}`;
|
|
129
|
-
break;
|
|
130
|
-
case 'delete':
|
|
131
|
-
break;
|
|
132
|
-
}
|
|
133
|
-
if (statement.join) {
|
|
134
|
-
statement.join.forEach((join) => {
|
|
135
|
-
sql += ` ${join.type} JOIN ${join.joinSchema}.${join.joinTable} ${join.joinAlias} ON ${join.on}`;
|
|
136
|
-
});
|
|
137
|
-
}
|
|
138
|
-
if (statementType !== 'insert') {
|
|
139
|
-
sql += this.buildWhereClause(where);
|
|
140
|
-
sql += this.buildOrderByClause(statement.orderBy);
|
|
141
|
-
sql += this.buildOffsetClause(statement.offset);
|
|
142
|
-
sql += this.buildLimitClause(limit);
|
|
143
|
-
}
|
|
144
|
-
const startTime = Date.now();
|
|
145
|
-
const result = await this.sql.unsafe(sql);
|
|
146
|
-
return {
|
|
147
|
-
query: { rows: Array.isArray(result) ? result : [] },
|
|
148
|
-
startTime,
|
|
149
|
-
sql,
|
|
150
|
-
};
|
|
151
|
-
}
|
|
152
135
|
async snapshot(tableName, options) {
|
|
153
136
|
const schema = (options && options.schema) || 'public';
|
|
154
137
|
const sql = `SELECT * FROM information_schema.columns WHERE table_name = '${tableName}' AND table_schema = '${schema}'`;
|
|
@@ -182,7 +165,7 @@ export class BunPgDriver extends BunDriverBase {
|
|
|
182
165
|
unique: constraints.some((c) => (c.type === 'UNIQUE' || c.type === 'PRIMARY KEY') &&
|
|
183
166
|
c.consDef.includes(row.column_name)),
|
|
184
167
|
type: row.data_type,
|
|
185
|
-
foreignKeys: this.
|
|
168
|
+
foreignKeys: this.getForeignKeysFromConstraints(constraints, row, 'column_name'),
|
|
186
169
|
isEnum: row.data_type === 'USER-DEFINED',
|
|
187
170
|
enumItems: row.data_type === 'USER-DEFINED'
|
|
188
171
|
? enums[`${schema}_${tableName}_${row.column_name}_enum`]
|
|
@@ -194,21 +177,6 @@ export class BunPgDriver extends BunDriverBase {
|
|
|
194
177
|
}),
|
|
195
178
|
};
|
|
196
179
|
}
|
|
197
|
-
getForeignKeys(constraints, row) {
|
|
198
|
-
return constraints
|
|
199
|
-
.filter((c) => c.type === 'FOREIGN KEY' &&
|
|
200
|
-
c.consDef.match(new RegExp(`FOREIGN KEY \\("${row.column_name}"\\)`)))
|
|
201
|
-
.map((c) => {
|
|
202
|
-
const filter = c.consDef.match(/REFERENCES\s+"([^"]+)"\s*\(([^)]+)\)/);
|
|
203
|
-
if (!filter) {
|
|
204
|
-
throw new Error('Invalid constraint definition');
|
|
205
|
-
}
|
|
206
|
-
return {
|
|
207
|
-
referencedColumnName: filter[2].split(',')[0].trim(),
|
|
208
|
-
referencedTableName: filter[1],
|
|
209
|
-
};
|
|
210
|
-
});
|
|
211
|
-
}
|
|
212
180
|
async index(tableName, options) {
|
|
213
181
|
const schema = (options && options.schema) || 'public';
|
|
214
182
|
let result = await this.sql.unsafe(`SELECT indexname AS index_name, indexdef AS column_name, tablename AS table_name
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { Statement } from '../driver/driver.interface';
|
|
2
|
+
import { EntityStorage } from '../domain/entities';
|
|
3
|
+
export declare class ModelTransformer {
|
|
4
|
+
private entityStorage;
|
|
5
|
+
constructor(entityStorage: EntityStorage);
|
|
6
|
+
transform<T>(model: any, statement: Statement<any>, data: any): T;
|
|
7
|
+
private createInstances;
|
|
8
|
+
private createInstance;
|
|
9
|
+
private addJoinedInstances;
|
|
10
|
+
private buildOptionsMap;
|
|
11
|
+
private populateProperties;
|
|
12
|
+
private parseColumnKey;
|
|
13
|
+
private setPropertyValue;
|
|
14
|
+
private findPropertyByColumnName;
|
|
15
|
+
private isValueObjectType;
|
|
16
|
+
private linkJoinedEntities;
|
|
17
|
+
private linkSingleJoin;
|
|
18
|
+
private findRelationProperty;
|
|
19
|
+
private attachJoinedEntity;
|
|
20
|
+
private appendToArray;
|
|
21
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { ValueObject } from '../common/value-object';
|
|
2
|
+
import { extendsFrom } from '../utils';
|
|
3
|
+
export class ModelTransformer {
|
|
4
|
+
constructor(entityStorage) {
|
|
5
|
+
this.entityStorage = entityStorage;
|
|
6
|
+
}
|
|
7
|
+
transform(model, statement, data) {
|
|
8
|
+
const instanceMap = this.createInstances(model, statement);
|
|
9
|
+
const optionsMap = this.buildOptionsMap(instanceMap);
|
|
10
|
+
this.populateProperties(data, instanceMap, optionsMap);
|
|
11
|
+
this.linkJoinedEntities(statement, instanceMap, optionsMap);
|
|
12
|
+
return instanceMap[statement.alias];
|
|
13
|
+
}
|
|
14
|
+
createInstances(model, statement) {
|
|
15
|
+
const instance = this.createInstance(model);
|
|
16
|
+
const instanceMap = {
|
|
17
|
+
[statement.alias]: instance,
|
|
18
|
+
};
|
|
19
|
+
if (statement.join) {
|
|
20
|
+
this.addJoinedInstances(statement, instanceMap);
|
|
21
|
+
}
|
|
22
|
+
return instanceMap;
|
|
23
|
+
}
|
|
24
|
+
createInstance(model) {
|
|
25
|
+
const instance = new model();
|
|
26
|
+
instance.$_isPersisted = true;
|
|
27
|
+
return instance;
|
|
28
|
+
}
|
|
29
|
+
addJoinedInstances(statement, instanceMap) {
|
|
30
|
+
statement.join.forEach(join => {
|
|
31
|
+
const joinInstance = this.createInstance(join.joinEntity);
|
|
32
|
+
instanceMap[join.joinAlias] = joinInstance;
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
buildOptionsMap(instanceMap) {
|
|
36
|
+
const optionsMap = new Map();
|
|
37
|
+
for (const [alias, instance] of Object.entries(instanceMap)) {
|
|
38
|
+
const options = this.entityStorage.get(instance.constructor);
|
|
39
|
+
if (options) {
|
|
40
|
+
optionsMap.set(alias, options);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return optionsMap;
|
|
44
|
+
}
|
|
45
|
+
populateProperties(data, instanceMap, optionsMap) {
|
|
46
|
+
Object.entries(data).forEach(([key, value]) => {
|
|
47
|
+
const { alias, propertyName } = this.parseColumnKey(key);
|
|
48
|
+
const entity = instanceMap[alias];
|
|
49
|
+
if (!entity) {
|
|
50
|
+
return;
|
|
51
|
+
}
|
|
52
|
+
this.setPropertyValue(entity, propertyName, value, optionsMap.get(alias));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
parseColumnKey(key) {
|
|
56
|
+
const index = key.indexOf('_');
|
|
57
|
+
return {
|
|
58
|
+
alias: key.substring(0, index),
|
|
59
|
+
propertyName: key.substring(index + 1),
|
|
60
|
+
};
|
|
61
|
+
}
|
|
62
|
+
setPropertyValue(entity, columnName, value, options) {
|
|
63
|
+
const propertyInfo = this.findPropertyByColumnName(columnName, options);
|
|
64
|
+
if (!propertyInfo) {
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
const { key, property } = propertyInfo;
|
|
68
|
+
if (this.isValueObjectType(property.type)) {
|
|
69
|
+
entity[key] = new property.type(value);
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
entity[key] = value;
|
|
73
|
+
}
|
|
74
|
+
findPropertyByColumnName(columnName, options) {
|
|
75
|
+
const entry = Object.entries(options.properties).find(([_, prop]) => prop.options.columnName === columnName);
|
|
76
|
+
if (!entry) {
|
|
77
|
+
return null;
|
|
78
|
+
}
|
|
79
|
+
return { key: entry[0], property: entry[1] };
|
|
80
|
+
}
|
|
81
|
+
isValueObjectType(type) {
|
|
82
|
+
return extendsFrom(ValueObject, type?.prototype);
|
|
83
|
+
}
|
|
84
|
+
linkJoinedEntities(statement, instanceMap, optionsMap) {
|
|
85
|
+
if (!statement.join) {
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
statement.join.forEach(join => {
|
|
89
|
+
this.linkSingleJoin(join, instanceMap, optionsMap);
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
linkSingleJoin(join, instanceMap, optionsMap) {
|
|
93
|
+
const { joinAlias, originAlias, propertyKey } = join;
|
|
94
|
+
const originEntity = instanceMap[originAlias];
|
|
95
|
+
const joinEntity = instanceMap[joinAlias];
|
|
96
|
+
if (!originEntity || !joinEntity) {
|
|
97
|
+
return;
|
|
98
|
+
}
|
|
99
|
+
const property = this.findRelationProperty(originAlias, propertyKey, optionsMap);
|
|
100
|
+
if (property) {
|
|
101
|
+
this.attachJoinedEntity(originEntity, joinEntity, propertyKey, property);
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
findRelationProperty(alias, propertyKey, optionsMap) {
|
|
105
|
+
return optionsMap.get(alias)?.relations.find(rel => rel.propertyKey === propertyKey);
|
|
106
|
+
}
|
|
107
|
+
attachJoinedEntity(originEntity, joinEntity, propertyKey, property) {
|
|
108
|
+
if (property.type === Array) {
|
|
109
|
+
originEntity[propertyKey] = this.appendToArray(originEntity[propertyKey], joinEntity);
|
|
110
|
+
}
|
|
111
|
+
else {
|
|
112
|
+
originEntity[propertyKey] = joinEntity;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
appendToArray(existingArray, newItem) {
|
|
116
|
+
return existingArray ? [...existingArray, newItem] : [newItem];
|
|
117
|
+
}
|
|
118
|
+
}
|