@uql/core 3.4.0 → 3.4.2
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/CHANGELOG.md +2 -5
- package/README.md +8 -14
- package/dist/browser/uql-browser.min.js +949 -2085
- package/dist/browser/uql-browser.min.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,2150 +1,1014 @@
|
|
|
1
|
-
import {
|
|
2
|
-
|
|
3
|
-
import {
|
|
4
|
-
import
|
|
5
|
-
import {
|
|
6
|
-
import
|
|
7
|
-
import {
|
|
8
|
-
import { pathToFileURL } from 'node:url';
|
|
1
|
+
import { _ as _apply_decs_2203_r } from './cc-BEf4wTUm.js';
|
|
2
|
+
import { randomUUID } from 'node:crypto';
|
|
3
|
+
import { Id, Field, ManyToOne, Entity, OneToOne, OneToMany, ManyToMany } from '../entity/index.js';
|
|
4
|
+
import '../type/index.js';
|
|
5
|
+
import { raw, lowerFirst, upperFirst, getKeys } from '../util/index.js';
|
|
6
|
+
import 'reflect-metadata';
|
|
7
|
+
import { describe, afterAll, afterEach, beforeEach, beforeAll, it } from 'bun:test';
|
|
9
8
|
|
|
9
|
+
var _dec, _dec1, _dec2, _dec3, _dec4, _dec5, _dec6, /**
|
|
10
|
+
* auto-generated primary-key (when the `onInsert` property is omitted).
|
|
11
|
+
*/ _init_id, /**
|
|
12
|
+
* foreign-keys are really simple to specify with the `reference` property.
|
|
13
|
+
*/ _init_companyId, /**
|
|
14
|
+
* The `Relation` wrapper type can be used in ESM projects for the relations to
|
|
15
|
+
* avoid circular dependency issues.
|
|
16
|
+
*/ _init_company, _init_creatorId, _init_creator, /**
|
|
17
|
+
* 'onInsert' property can be used to specify a custom mechanism for
|
|
18
|
+
* obtaining the value of a field when inserting:
|
|
19
|
+
*/ _init_createdAt, /**
|
|
20
|
+
* 'onUpdate' property can be used to specify a custom mechanism for
|
|
21
|
+
* obtaining the value of a field when updating:
|
|
22
|
+
*/ _init_updatedAt, _dec7, _initClass, _BaseEntity, _dec8, _dec9, _dec10, _init_name, _init_description, _init_kind, _dec11, _initClass1, _BaseEntity1, _dec12, _dec13, /**
|
|
23
|
+
* an entity can specify its own ID Field and still inherit the others
|
|
24
|
+
* columns/relations from its parent entity.
|
|
25
|
+
*/ _init_pk, _init_picture, _dec14, _initClass2, _BaseEntity2, _dec15, _dec16, _dec17, _dec18, _dec19, _init_name1, _init_email, _init_password, /**
|
|
26
|
+
* `mappedBy` property can be a callback or a string (callback is useful for auto-refactoring).
|
|
27
|
+
*/ _init_profile, _init_users, _dec20, _initClass3, _dec21, _dec22, _init_id1, _init_name2, _dec23, _initClass4, _BaseEntity3, _dec24, _dec25, _dec26, _dec27, _init_name3, _init_description1, _init_parentLedgerId, _init_parentLedger, _dec28, _initClass5, _BaseEntity4, _dec29, _dec30, _dec31, /**
|
|
28
|
+
* an entity can override the ID Field and still inherit the others
|
|
29
|
+
* columns/relations from its parent entity.
|
|
30
|
+
* 'onInsert' property can be used to specify a custom mechanism for
|
|
31
|
+
* auto-generating the primary-key's value when inserting.
|
|
32
|
+
*/ _init_pk1, _init_name4, _init_description2, _dec32, _initClass6, _BaseEntity5, _dec33, _dec34, _dec35, _dec36, _dec37, _init_name5, _init_percentage, _init_categoryId, _init_category, _init_description3, _dec38, _initClass7, _BaseEntity6, _dec39, _dec40, _dec41, _init_name6, _init_measureUnits, /**
|
|
33
|
+
* `onDelete` callback allows to specify which field will be used when deleting/querying this entity.
|
|
34
|
+
*/ _init_deletedAt, _dec42, _initClass8, _BaseEntity7, _dec43, _dec44, _dec45, _dec46, _init_name7, _init_categoryId1, _init_category1, _init_deletedAt1, _dec47, _initClass9, _BaseEntity8, _dec48, _dec49, _dec50, _init_name8, _init_address, _init_description4, _dec51, _initClass10, _BaseEntity9, _dec52, _dec53, _dec54, _dec55, _dec56, _dec57, _dec58, _dec59, _dec60, _dec61, _dec62, _dec63, _dec64, _dec65, _dec66, _init_name9, _init_description5, _init_code, _init_buyLedgerAccountId, _init_buyLedgerAccount, _init_saleLedgerAccountId, _init_saleLedgerAccount, _init_taxId, _init_tax, _init_measureUnitId, _init_measureUnit, _init_salePrice, _init_inventoryable, _init_tags, _init_tagsCount, _dec67, _initClass11, _BaseEntity10, _dec68, _dec69, _dec70, _init_name10, _init_items, _init_itemsCount, _dec71, _initClass12, _dec72, _dec73, _dec74, _init_id2, _init_itemId, _init_tagId, _dec75, _initClass13, _BaseEntity11, _dec76, _dec77, _dec78, _init_itemAdjustments, _init_date, _init_description6, _dec79, _initClass14, _BaseEntity12, _dec80, _dec81, _dec82, _dec83, _dec84, _dec85, _dec86, _dec87, _init_itemId1, _init_item, _init_number, _init_buyPrice, _init_storehouseId, _init_storehouse, _init_inventoryAdjustmentId, _init_inventoryAdjustment;
|
|
35
|
+
_dec = Id(), _dec1 = Field({
|
|
36
|
+
reference: ()=>_Company
|
|
37
|
+
}), _dec2 = ManyToOne({
|
|
38
|
+
entity: ()=>_Company
|
|
39
|
+
}), _dec3 = Field({
|
|
40
|
+
reference: ()=>_User
|
|
41
|
+
}), _dec4 = ManyToOne({
|
|
42
|
+
entity: ()=>_User
|
|
43
|
+
}), _dec5 = Field({
|
|
44
|
+
onInsert: Date.now
|
|
45
|
+
}), _dec6 = Field({
|
|
46
|
+
onUpdate: Date.now
|
|
47
|
+
});
|
|
10
48
|
/**
|
|
11
|
-
*
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
// Drop columns
|
|
62
|
-
if (diff.columnsToDrop?.length) {
|
|
63
|
-
for (const columnName of diff.columnsToDrop){
|
|
64
|
-
statements.push(`ALTER TABLE ${tableName} DROP COLUMN ${this.escapeId(columnName)};`);
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
// Add indexes
|
|
68
|
-
if (diff.indexesToAdd?.length) {
|
|
69
|
-
for (const index of diff.indexesToAdd){
|
|
70
|
-
statements.push(this.generateCreateIndex(diff.tableName, index));
|
|
71
|
-
}
|
|
72
|
-
}
|
|
73
|
-
// Drop indexes
|
|
74
|
-
if (diff.indexesToDrop?.length) {
|
|
75
|
-
for (const indexName of diff.indexesToDrop){
|
|
76
|
-
statements.push(this.generateDropIndex(diff.tableName, indexName));
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
return statements;
|
|
80
|
-
}
|
|
81
|
-
generateAlterTableDown(diff) {
|
|
82
|
-
const statements = [];
|
|
83
|
-
const tableName = this.escapeId(diff.tableName);
|
|
84
|
-
// Rollback additions by dropping columns
|
|
85
|
-
if (diff.columnsToAdd?.length) {
|
|
86
|
-
for (const column of diff.columnsToAdd){
|
|
87
|
-
statements.push(`ALTER TABLE ${tableName} DROP COLUMN ${this.escapeId(column.name)};`);
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
return statements;
|
|
91
|
-
}
|
|
92
|
-
generateCreateIndex(tableName, index) {
|
|
93
|
-
const unique = index.unique ? 'UNIQUE ' : '';
|
|
94
|
-
const columns = index.columns.map((c)=>this.escapeId(c)).join(', ');
|
|
95
|
-
return `CREATE ${unique}INDEX ${this.escapeId(index.name)} ON ${this.escapeId(tableName)} (${columns});`;
|
|
96
|
-
}
|
|
97
|
-
generateDropIndex(tableName, indexName) {
|
|
98
|
-
return `DROP INDEX IF EXISTS ${this.escapeId(indexName)};`;
|
|
99
|
-
}
|
|
100
|
-
/**
|
|
101
|
-
* Generate column definitions from entity metadata
|
|
102
|
-
*/ generateColumnDefinitions(meta) {
|
|
103
|
-
const columns = [];
|
|
104
|
-
const fieldKeys = getKeys(meta.fields);
|
|
105
|
-
for (const key of fieldKeys){
|
|
106
|
-
const field = meta.fields[key];
|
|
107
|
-
if (field?.virtual) continue; // Skip virtual fields
|
|
108
|
-
const colDef = this.generateColumnDefinition(key, field, meta);
|
|
109
|
-
columns.push(colDef);
|
|
110
|
-
}
|
|
111
|
-
return columns;
|
|
112
|
-
}
|
|
113
|
-
/**
|
|
114
|
-
* Generate a single column definition
|
|
115
|
-
*/ generateColumnDefinition(fieldKey, field, meta) {
|
|
116
|
-
const columnName = this.escapeId(this.resolveColumnName(fieldKey, field));
|
|
117
|
-
const isId = field.isId === true;
|
|
118
|
-
const isPrimaryKey = isId && meta.id === fieldKey;
|
|
119
|
-
// Determine SQL type
|
|
120
|
-
let sqlType;
|
|
121
|
-
if (isPrimaryKey && field.autoIncrement !== false && !field.onInsert) {
|
|
122
|
-
// Auto-increment primary key
|
|
123
|
-
sqlType = this.serialPrimaryKeyType;
|
|
124
|
-
} else {
|
|
125
|
-
sqlType = this.getSqlType(field, field.type);
|
|
126
|
-
}
|
|
127
|
-
let definition = `${columnName} ${sqlType}`;
|
|
128
|
-
// PRIMARY KEY constraint (for non-serial types)
|
|
129
|
-
if (isPrimaryKey && !sqlType.includes('PRIMARY KEY')) {
|
|
130
|
-
definition += ' PRIMARY KEY';
|
|
131
|
-
}
|
|
132
|
-
// NULL/NOT NULL
|
|
133
|
-
if (!isPrimaryKey) {
|
|
134
|
-
const nullable = field.nullable ?? true;
|
|
135
|
-
if (!nullable) {
|
|
136
|
-
definition += ' NOT NULL';
|
|
137
|
-
}
|
|
138
|
-
}
|
|
139
|
-
// UNIQUE constraint
|
|
140
|
-
if (field.unique && !isPrimaryKey) {
|
|
141
|
-
definition += ' UNIQUE';
|
|
142
|
-
}
|
|
143
|
-
// DEFAULT value
|
|
144
|
-
if (field.defaultValue !== undefined) {
|
|
145
|
-
definition += ` DEFAULT ${this.formatDefaultValue(field.defaultValue)}`;
|
|
146
|
-
}
|
|
147
|
-
// COMMENT (if supported)
|
|
148
|
-
if (field.comment) {
|
|
149
|
-
definition += this.generateColumnComment(this.resolveTableName(meta.entity, meta), this.resolveColumnName(fieldKey, field), field.comment);
|
|
150
|
-
}
|
|
151
|
-
return definition;
|
|
152
|
-
}
|
|
153
|
-
/**
|
|
154
|
-
* Generate column definition from a ColumnSchema object
|
|
155
|
-
*/ generateColumnDefinitionFromSchema(column) {
|
|
156
|
-
const columnName = this.escapeId(column.name);
|
|
157
|
-
let type = column.type;
|
|
158
|
-
if (column.length && !type.includes('(')) {
|
|
159
|
-
type = `${type}(${column.length})`;
|
|
160
|
-
} else if (column.precision !== undefined && !type.includes('(')) {
|
|
161
|
-
if (column.scale !== undefined) {
|
|
162
|
-
type = `${type}(${column.precision}, ${column.scale})`;
|
|
163
|
-
} else {
|
|
164
|
-
type = `${type}(${column.precision})`;
|
|
165
|
-
}
|
|
166
|
-
}
|
|
167
|
-
let definition = `${columnName} ${type}`;
|
|
168
|
-
if (column.isPrimaryKey) {
|
|
169
|
-
definition += ' PRIMARY KEY';
|
|
170
|
-
}
|
|
171
|
-
if (!column.nullable && !column.isPrimaryKey) {
|
|
172
|
-
definition += ' NOT NULL';
|
|
173
|
-
}
|
|
174
|
-
if (column.isUnique && !column.isPrimaryKey) {
|
|
175
|
-
definition += ' UNIQUE';
|
|
176
|
-
}
|
|
177
|
-
if (column.defaultValue !== undefined) {
|
|
178
|
-
definition += ` DEFAULT ${this.formatDefaultValue(column.defaultValue)}`;
|
|
179
|
-
}
|
|
180
|
-
return definition;
|
|
181
|
-
}
|
|
182
|
-
/**
|
|
183
|
-
* Generate table constraints (indexes, foreign keys, etc.)
|
|
184
|
-
*/ generateTableConstraints(meta) {
|
|
185
|
-
const constraints = [];
|
|
186
|
-
const fieldKeys = getKeys(meta.fields);
|
|
187
|
-
const tableName = this.resolveTableName(meta.entity, meta);
|
|
188
|
-
// Generate indexes from field options
|
|
189
|
-
for (const key of fieldKeys){
|
|
190
|
-
const field = meta.fields[key];
|
|
191
|
-
if (field?.index) {
|
|
192
|
-
const columnName = this.resolveColumnName(key, field);
|
|
193
|
-
const indexName = typeof field.index === 'string' ? field.index : `idx_${tableName}_${columnName}`;
|
|
194
|
-
constraints.push(`INDEX ${this.escapeId(indexName)} (${this.escapeId(columnName)})`);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
|
-
// Generate foreign key constraints from references
|
|
198
|
-
for (const key of fieldKeys){
|
|
199
|
-
const field = meta.fields[key];
|
|
200
|
-
if (field?.reference) {
|
|
201
|
-
const refEntity = field.reference();
|
|
202
|
-
const refMeta = getMeta(refEntity);
|
|
203
|
-
const refIdField = refMeta.fields[refMeta.id];
|
|
204
|
-
const columnName = this.resolveColumnName(key, field);
|
|
205
|
-
const refTableName = this.resolveTableName(refEntity, refMeta);
|
|
206
|
-
const refColumnName = this.resolveColumnName(refMeta.id, refIdField);
|
|
207
|
-
const fkName = `fk_${tableName}_${columnName}`;
|
|
208
|
-
constraints.push(`CONSTRAINT ${this.escapeId(fkName)} FOREIGN KEY (${this.escapeId(columnName)}) ` + `REFERENCES ${this.escapeId(refTableName)} (${this.escapeId(refColumnName)})`);
|
|
209
|
-
}
|
|
210
|
-
}
|
|
211
|
-
return constraints;
|
|
212
|
-
}
|
|
213
|
-
getSqlType(field, fieldType) {
|
|
214
|
-
// Use explicit column type if specified
|
|
215
|
-
if (field.columnType) {
|
|
216
|
-
return this.mapColumnType(field.columnType, field);
|
|
217
|
-
}
|
|
218
|
-
// Handle special types
|
|
219
|
-
if (field.type === 'json' || field.type === 'jsonb') {
|
|
220
|
-
return this.mapColumnType(field.type, field);
|
|
221
|
-
}
|
|
222
|
-
if (field.type === 'vector') {
|
|
223
|
-
return this.mapColumnType('vector', field);
|
|
224
|
-
}
|
|
225
|
-
// Infer from TypeScript type
|
|
226
|
-
const type = fieldType ?? field.type;
|
|
227
|
-
if (type === Number || type === 'number') {
|
|
228
|
-
return field.precision ? this.mapColumnType('decimal', field) : 'BIGINT';
|
|
229
|
-
}
|
|
230
|
-
if (type === String || type === 'string') {
|
|
231
|
-
const length = field.length ?? 255;
|
|
232
|
-
return `VARCHAR(${length})`;
|
|
233
|
-
}
|
|
234
|
-
if (type === Boolean || type === 'boolean') {
|
|
235
|
-
return this.getBooleanType();
|
|
236
|
-
}
|
|
237
|
-
if (type === Date || type === 'date') {
|
|
238
|
-
return 'TIMESTAMP';
|
|
239
|
-
}
|
|
240
|
-
if (type === BigInt || type === 'bigint') {
|
|
241
|
-
return 'BIGINT';
|
|
242
|
-
}
|
|
243
|
-
// Default to VARCHAR
|
|
244
|
-
return `VARCHAR(${field.length ?? 255})`;
|
|
245
|
-
}
|
|
246
|
-
/**
|
|
247
|
-
* Get table options (e.g., ENGINE for MySQL)
|
|
248
|
-
*/ getTableOptions(meta) {
|
|
249
|
-
return '';
|
|
250
|
-
}
|
|
251
|
-
/**
|
|
252
|
-
* Format a default value for SQL
|
|
253
|
-
*/ formatDefaultValue(value) {
|
|
254
|
-
if (value === null) {
|
|
255
|
-
return 'NULL';
|
|
256
|
-
}
|
|
257
|
-
if (typeof value === 'string') {
|
|
258
|
-
return `'${value.replace(/'/g, "''")}'`;
|
|
259
|
-
}
|
|
260
|
-
if (typeof value === 'boolean') {
|
|
261
|
-
return value ? 'TRUE' : 'FALSE';
|
|
262
|
-
}
|
|
263
|
-
if (typeof value === 'number' || typeof value === 'bigint') {
|
|
264
|
-
return String(value);
|
|
265
|
-
}
|
|
266
|
-
if (value instanceof Date) {
|
|
267
|
-
return `'${value.toISOString()}'`;
|
|
268
|
-
}
|
|
269
|
-
return String(value);
|
|
270
|
-
}
|
|
271
|
-
/**
|
|
272
|
-
* Compare two schemas and return the differences
|
|
273
|
-
*/ diffSchema(entity, currentSchema) {
|
|
274
|
-
const meta = getMeta(entity);
|
|
275
|
-
if (!currentSchema) {
|
|
276
|
-
// Table doesn't exist, need to create
|
|
277
|
-
return {
|
|
278
|
-
tableName: this.resolveTableName(entity, meta),
|
|
279
|
-
type: 'create'
|
|
280
|
-
};
|
|
281
|
-
}
|
|
282
|
-
const columnsToAdd = [];
|
|
283
|
-
const columnsToAlter = [];
|
|
284
|
-
const columnsToDrop = [];
|
|
285
|
-
const currentColumns = new Map(currentSchema.columns.map((c)=>[
|
|
286
|
-
c.name,
|
|
287
|
-
c
|
|
288
|
-
]));
|
|
289
|
-
const fieldKeys = getKeys(meta.fields);
|
|
290
|
-
// Check for new or altered columns
|
|
291
|
-
for (const key of fieldKeys){
|
|
292
|
-
const field = meta.fields[key];
|
|
293
|
-
if (field?.virtual) continue;
|
|
294
|
-
const columnName = this.resolveColumnName(key, field);
|
|
295
|
-
const currentColumn = currentColumns.get(columnName);
|
|
296
|
-
if (!currentColumn) {
|
|
297
|
-
// Column needs to be added
|
|
298
|
-
columnsToAdd.push(this.fieldToColumnSchema(key, field, meta));
|
|
299
|
-
} else {
|
|
300
|
-
// Check if column needs alteration
|
|
301
|
-
const desiredColumn = this.fieldToColumnSchema(key, field, meta);
|
|
302
|
-
if (this.columnsNeedAlteration(currentColumn, desiredColumn)) {
|
|
303
|
-
columnsToAlter.push({
|
|
304
|
-
from: currentColumn,
|
|
305
|
-
to: desiredColumn
|
|
306
|
-
});
|
|
307
|
-
}
|
|
308
|
-
}
|
|
309
|
-
currentColumns.delete(columnName);
|
|
310
|
-
}
|
|
311
|
-
// Remaining columns in currentColumns should be dropped
|
|
312
|
-
for (const [name] of currentColumns){
|
|
313
|
-
columnsToDrop.push(name);
|
|
314
|
-
}
|
|
315
|
-
if (columnsToAdd.length === 0 && columnsToAlter.length === 0 && columnsToDrop.length === 0) {
|
|
316
|
-
return undefined; // No changes needed
|
|
317
|
-
}
|
|
318
|
-
return {
|
|
319
|
-
tableName: this.resolveTableName(entity, meta),
|
|
320
|
-
type: 'alter',
|
|
321
|
-
columnsToAdd: columnsToAdd.length > 0 ? columnsToAdd : undefined,
|
|
322
|
-
columnsToAlter: columnsToAlter.length > 0 ? columnsToAlter : undefined,
|
|
323
|
-
columnsToDrop: columnsToDrop.length > 0 ? columnsToDrop : undefined
|
|
324
|
-
};
|
|
325
|
-
}
|
|
326
|
-
/**
|
|
327
|
-
* Convert field options to ColumnSchema
|
|
328
|
-
*/ fieldToColumnSchema(fieldKey, field, meta) {
|
|
329
|
-
const isId = field.isId === true;
|
|
330
|
-
const isPrimaryKey = isId && meta.id === fieldKey;
|
|
331
|
-
return {
|
|
332
|
-
name: this.resolveColumnName(fieldKey, field),
|
|
333
|
-
type: this.getSqlType(field, field.type),
|
|
334
|
-
nullable: field.nullable ?? !isPrimaryKey,
|
|
335
|
-
defaultValue: field.defaultValue,
|
|
336
|
-
isPrimaryKey,
|
|
337
|
-
isAutoIncrement: isPrimaryKey && field.autoIncrement !== false && !field.onInsert,
|
|
338
|
-
isUnique: field.unique ?? false,
|
|
339
|
-
length: field.length,
|
|
340
|
-
precision: field.precision,
|
|
341
|
-
scale: field.scale,
|
|
342
|
-
comment: field.comment
|
|
343
|
-
};
|
|
344
|
-
}
|
|
345
|
-
/**
|
|
346
|
-
* Check if two columns differ enough to require alteration
|
|
347
|
-
*/ columnsNeedAlteration(current, desired) {
|
|
348
|
-
// Compare relevant properties
|
|
349
|
-
return current.type.toLowerCase() !== desired.type.toLowerCase() || current.nullable !== desired.nullable || current.isUnique !== desired.isUnique || JSON.stringify(current.defaultValue) !== JSON.stringify(desired.defaultValue);
|
|
49
|
+
* an `abstract` class can (optionally) be used as the base "template" for the entities
|
|
50
|
+
* (so common fields' declaration is easily reused).
|
|
51
|
+
*/ class BaseEntity {
|
|
52
|
+
static{
|
|
53
|
+
({ e: [_init_id, _init_companyId, _init_company, _init_creatorId, _init_creator, _init_createdAt, _init_updatedAt] } = _apply_decs_2203_r(this, [
|
|
54
|
+
[
|
|
55
|
+
_dec,
|
|
56
|
+
0,
|
|
57
|
+
"id"
|
|
58
|
+
],
|
|
59
|
+
[
|
|
60
|
+
_dec1,
|
|
61
|
+
0,
|
|
62
|
+
"companyId"
|
|
63
|
+
],
|
|
64
|
+
[
|
|
65
|
+
_dec2,
|
|
66
|
+
0,
|
|
67
|
+
"company"
|
|
68
|
+
],
|
|
69
|
+
[
|
|
70
|
+
_dec3,
|
|
71
|
+
0,
|
|
72
|
+
"creatorId"
|
|
73
|
+
],
|
|
74
|
+
[
|
|
75
|
+
_dec4,
|
|
76
|
+
0,
|
|
77
|
+
"creator"
|
|
78
|
+
],
|
|
79
|
+
[
|
|
80
|
+
_dec5,
|
|
81
|
+
0,
|
|
82
|
+
"createdAt"
|
|
83
|
+
],
|
|
84
|
+
[
|
|
85
|
+
_dec6,
|
|
86
|
+
0,
|
|
87
|
+
"updatedAt"
|
|
88
|
+
]
|
|
89
|
+
], []));
|
|
90
|
+
}
|
|
91
|
+
constructor(){
|
|
92
|
+
this.id = _init_id(this);
|
|
93
|
+
this.companyId = _init_companyId(this);
|
|
94
|
+
this.company = _init_company(this);
|
|
95
|
+
this.creatorId = _init_creatorId(this);
|
|
96
|
+
this.creator = _init_creator(this);
|
|
97
|
+
this.createdAt = _init_createdAt(this);
|
|
98
|
+
this.updatedAt = _init_updatedAt(this);
|
|
350
99
|
}
|
|
351
100
|
}
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
359
|
-
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
|
|
373
|
-
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
|
|
378
|
-
|
|
379
|
-
|
|
380
|
-
case 'char':
|
|
381
|
-
return `CHAR(${field.length ?? 1})`;
|
|
382
|
-
case 'varchar':
|
|
383
|
-
return `VARCHAR(${field.length ?? 255})`;
|
|
384
|
-
case 'text':
|
|
385
|
-
return 'TEXT';
|
|
386
|
-
case 'uuid':
|
|
387
|
-
return 'CHAR(36)';
|
|
388
|
-
case 'date':
|
|
389
|
-
return 'DATE';
|
|
390
|
-
case 'time':
|
|
391
|
-
return 'TIME';
|
|
392
|
-
case 'timestamp':
|
|
393
|
-
case 'timestamptz':
|
|
394
|
-
return 'TIMESTAMP';
|
|
395
|
-
case 'json':
|
|
396
|
-
case 'jsonb':
|
|
397
|
-
return 'JSON';
|
|
398
|
-
case 'blob':
|
|
399
|
-
case 'bytea':
|
|
400
|
-
return 'BLOB';
|
|
401
|
-
case 'vector':
|
|
402
|
-
// MySQL doesn't have native vector support, use JSON
|
|
403
|
-
return 'JSON';
|
|
404
|
-
case 'serial':
|
|
405
|
-
return 'INT AUTO_INCREMENT';
|
|
406
|
-
case 'bigserial':
|
|
407
|
-
return 'BIGINT AUTO_INCREMENT';
|
|
408
|
-
default:
|
|
409
|
-
return 'TEXT';
|
|
410
|
-
}
|
|
411
|
-
}
|
|
412
|
-
getBooleanType() {
|
|
413
|
-
return 'TINYINT(1)';
|
|
414
|
-
}
|
|
415
|
-
generateAlterColumnStatements(tableName, column, newDefinition) {
|
|
416
|
-
return [
|
|
417
|
-
`ALTER TABLE ${this.escapeId(tableName)} MODIFY COLUMN ${newDefinition};`
|
|
418
|
-
];
|
|
419
|
-
}
|
|
420
|
-
generateColumnComment(tableName, columnName, comment) {
|
|
421
|
-
const escapedComment = comment.replace(/'/g, "''");
|
|
422
|
-
return ` COMMENT '${escapedComment}'`;
|
|
423
|
-
}
|
|
424
|
-
getTableOptions() {
|
|
425
|
-
return ' ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci';
|
|
426
|
-
}
|
|
427
|
-
generateDropIndex(tableName, indexName) {
|
|
428
|
-
// MySQL requires table name in DROP INDEX
|
|
429
|
-
return `DROP INDEX ${this.escapeId(indexName)} ON ${this.escapeId(tableName)};`;
|
|
101
|
+
let _Company;
|
|
102
|
+
_dec7 = Entity(), _dec8 = Field(), _dec9 = Field(), _dec10 = Field({
|
|
103
|
+
type: 'jsonb'
|
|
104
|
+
});
|
|
105
|
+
class Company extends (_BaseEntity = BaseEntity) {
|
|
106
|
+
static{
|
|
107
|
+
({ e: [_init_name, _init_description, _init_kind], c: [_Company, _initClass] } = _apply_decs_2203_r(this, [
|
|
108
|
+
[
|
|
109
|
+
_dec8,
|
|
110
|
+
0,
|
|
111
|
+
"name"
|
|
112
|
+
],
|
|
113
|
+
[
|
|
114
|
+
_dec9,
|
|
115
|
+
0,
|
|
116
|
+
"description"
|
|
117
|
+
],
|
|
118
|
+
[
|
|
119
|
+
_dec10,
|
|
120
|
+
0,
|
|
121
|
+
"kind"
|
|
122
|
+
]
|
|
123
|
+
], [
|
|
124
|
+
_dec7
|
|
125
|
+
], _BaseEntity));
|
|
126
|
+
}
|
|
127
|
+
static{
|
|
128
|
+
_initClass();
|
|
430
129
|
}
|
|
431
130
|
constructor(...args){
|
|
432
|
-
super(...args), this.
|
|
131
|
+
super(...args), this.name = _init_name(this), this.description = _init_description(this), this.kind = _init_kind(this);
|
|
433
132
|
}
|
|
434
133
|
}
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
134
|
+
let _Profile;
|
|
135
|
+
_dec11 = Entity({
|
|
136
|
+
name: 'user_profile'
|
|
137
|
+
}), _dec12 = Id(), _dec13 = Field({
|
|
138
|
+
name: 'image'
|
|
139
|
+
});
|
|
140
|
+
class Profile extends (_BaseEntity1 = BaseEntity) {
|
|
141
|
+
static{
|
|
142
|
+
({ e: [_init_pk, _init_picture], c: [_Profile, _initClass1] } = _apply_decs_2203_r(this, [
|
|
143
|
+
[
|
|
144
|
+
_dec12,
|
|
145
|
+
0,
|
|
146
|
+
"pk"
|
|
147
|
+
],
|
|
148
|
+
[
|
|
149
|
+
_dec13,
|
|
150
|
+
0,
|
|
151
|
+
"picture"
|
|
152
|
+
]
|
|
153
|
+
], [
|
|
154
|
+
_dec11
|
|
155
|
+
], _BaseEntity1));
|
|
156
|
+
}
|
|
157
|
+
static{
|
|
158
|
+
_initClass1();
|
|
441
159
|
}
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
case 'int':
|
|
445
|
-
return 'INTEGER';
|
|
446
|
-
case 'smallint':
|
|
447
|
-
return 'SMALLINT';
|
|
448
|
-
case 'bigint':
|
|
449
|
-
return 'BIGINT';
|
|
450
|
-
case 'float':
|
|
451
|
-
case 'double':
|
|
452
|
-
case 'real':
|
|
453
|
-
return 'DOUBLE PRECISION';
|
|
454
|
-
case 'decimal':
|
|
455
|
-
case 'numeric':
|
|
456
|
-
if (field.precision !== undefined) {
|
|
457
|
-
if (field.scale !== undefined) {
|
|
458
|
-
return `NUMERIC(${field.precision}, ${field.scale})`;
|
|
459
|
-
}
|
|
460
|
-
return `NUMERIC(${field.precision})`;
|
|
461
|
-
}
|
|
462
|
-
return 'NUMERIC';
|
|
463
|
-
case 'boolean':
|
|
464
|
-
return 'BOOLEAN';
|
|
465
|
-
case 'char':
|
|
466
|
-
return `CHAR(${field.length ?? 1})`;
|
|
467
|
-
case 'varchar':
|
|
468
|
-
return `VARCHAR(${field.length ?? 255})`;
|
|
469
|
-
case 'text':
|
|
470
|
-
return 'TEXT';
|
|
471
|
-
case 'uuid':
|
|
472
|
-
return 'UUID';
|
|
473
|
-
case 'date':
|
|
474
|
-
return 'DATE';
|
|
475
|
-
case 'time':
|
|
476
|
-
return 'TIME';
|
|
477
|
-
case 'timestamp':
|
|
478
|
-
return 'TIMESTAMP';
|
|
479
|
-
case 'timestamptz':
|
|
480
|
-
return 'TIMESTAMPTZ';
|
|
481
|
-
case 'json':
|
|
482
|
-
return 'JSON';
|
|
483
|
-
case 'jsonb':
|
|
484
|
-
return 'JSONB';
|
|
485
|
-
case 'blob':
|
|
486
|
-
case 'bytea':
|
|
487
|
-
return 'BYTEA';
|
|
488
|
-
case 'vector':
|
|
489
|
-
if (field.length) {
|
|
490
|
-
return `VECTOR(${field.length})`;
|
|
491
|
-
}
|
|
492
|
-
return 'VECTOR';
|
|
493
|
-
case 'serial':
|
|
494
|
-
return 'SERIAL';
|
|
495
|
-
case 'bigserial':
|
|
496
|
-
return 'BIGSERIAL';
|
|
497
|
-
default:
|
|
498
|
-
return 'TEXT';
|
|
499
|
-
}
|
|
500
|
-
}
|
|
501
|
-
getBooleanType() {
|
|
502
|
-
return 'BOOLEAN';
|
|
503
|
-
}
|
|
504
|
-
generateAlterColumnStatements(tableName, column, newDefinition) {
|
|
505
|
-
const statements = [];
|
|
506
|
-
const escapedTableName = this.escapeId(tableName);
|
|
507
|
-
const escapedColumnName = this.escapeId(column.name);
|
|
508
|
-
// PostgreSQL uses separate ALTER COLUMN clauses for different changes
|
|
509
|
-
// 1. Change type
|
|
510
|
-
statements.push(`ALTER TABLE ${escapedTableName} ALTER COLUMN ${escapedColumnName} TYPE ${column.type};`);
|
|
511
|
-
// 2. Change nullability
|
|
512
|
-
if (column.nullable) {
|
|
513
|
-
statements.push(`ALTER TABLE ${escapedTableName} ALTER COLUMN ${escapedColumnName} DROP NOT NULL;`);
|
|
514
|
-
} else {
|
|
515
|
-
statements.push(`ALTER TABLE ${escapedTableName} ALTER COLUMN ${escapedColumnName} SET NOT NULL;`);
|
|
516
|
-
}
|
|
517
|
-
// 3. Change default value
|
|
518
|
-
if (column.defaultValue !== undefined) {
|
|
519
|
-
statements.push(`ALTER TABLE ${escapedTableName} ALTER COLUMN ${escapedColumnName} SET DEFAULT ${this.formatDefaultValue(column.defaultValue)};`);
|
|
520
|
-
} else {
|
|
521
|
-
statements.push(`ALTER TABLE ${escapedTableName} ALTER COLUMN ${escapedColumnName} DROP DEFAULT;`);
|
|
522
|
-
}
|
|
523
|
-
return statements;
|
|
524
|
-
}
|
|
525
|
-
generateColumnComment(tableName, columnName, comment) {
|
|
526
|
-
// PostgreSQL handles comments separately via COMMENT ON COLUMN
|
|
527
|
-
return '';
|
|
528
|
-
}
|
|
529
|
-
/**
|
|
530
|
-
* Generate COMMENT ON COLUMN statement for PostgreSQL
|
|
531
|
-
*/ generateColumnCommentStatement(tableName, columnName, comment) {
|
|
532
|
-
const escapedComment = comment.replace(/'/g, "''");
|
|
533
|
-
return `COMMENT ON COLUMN ${this.escapeId(tableName)}.${this.escapeId(columnName)} IS '${escapedComment}';`;
|
|
534
|
-
}
|
|
535
|
-
generateDropIndex(tableName, indexName) {
|
|
536
|
-
// PostgreSQL doesn't require table name in DROP INDEX
|
|
537
|
-
return `DROP INDEX IF EXISTS ${this.escapeId(indexName)};`;
|
|
160
|
+
constructor(...args){
|
|
161
|
+
super(...args), this.pk = _init_pk(this), this.picture = _init_picture(this);
|
|
538
162
|
}
|
|
539
163
|
}
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
// SQLite has very limited ALTER TABLE support
|
|
588
|
-
// Column type changes require recreating the table
|
|
589
|
-
throw new Error(`SQLite does not support altering column '${column.name}' in table '${tableName}'. ` + 'You need to recreate the table to change column types.');
|
|
590
|
-
}
|
|
591
|
-
generateColumnComment(tableName, columnName, comment) {
|
|
592
|
-
return '';
|
|
593
|
-
}
|
|
594
|
-
generateDropIndex(tableName, indexName) {
|
|
595
|
-
return `DROP INDEX IF EXISTS ${this.escapeId(indexName)};`;
|
|
596
|
-
}
|
|
597
|
-
formatDefaultValue(value) {
|
|
598
|
-
if (typeof value === 'boolean') {
|
|
599
|
-
return value ? '1' : '0';
|
|
600
|
-
}
|
|
601
|
-
return super.formatDefaultValue(value);
|
|
164
|
+
let _User;
|
|
165
|
+
_dec14 = Entity(), _dec15 = Field(), _dec16 = Field({
|
|
166
|
+
updatable: false
|
|
167
|
+
}), _dec17 = Field({
|
|
168
|
+
eager: false
|
|
169
|
+
}), _dec18 = OneToOne({
|
|
170
|
+
entity: ()=>_Profile,
|
|
171
|
+
mappedBy: (profile)=>profile.creator,
|
|
172
|
+
cascade: true
|
|
173
|
+
}), _dec19 = OneToMany({
|
|
174
|
+
entity: ()=>_User,
|
|
175
|
+
mappedBy: 'creator'
|
|
176
|
+
});
|
|
177
|
+
class User extends (_BaseEntity2 = BaseEntity) {
|
|
178
|
+
static{
|
|
179
|
+
({ e: [_init_name1, _init_email, _init_password, _init_profile, _init_users], c: [_User, _initClass2] } = _apply_decs_2203_r(this, [
|
|
180
|
+
[
|
|
181
|
+
_dec15,
|
|
182
|
+
0,
|
|
183
|
+
"name"
|
|
184
|
+
],
|
|
185
|
+
[
|
|
186
|
+
_dec16,
|
|
187
|
+
0,
|
|
188
|
+
"email"
|
|
189
|
+
],
|
|
190
|
+
[
|
|
191
|
+
_dec17,
|
|
192
|
+
0,
|
|
193
|
+
"password"
|
|
194
|
+
],
|
|
195
|
+
[
|
|
196
|
+
_dec18,
|
|
197
|
+
0,
|
|
198
|
+
"profile"
|
|
199
|
+
],
|
|
200
|
+
[
|
|
201
|
+
_dec19,
|
|
202
|
+
0,
|
|
203
|
+
"users"
|
|
204
|
+
]
|
|
205
|
+
], [
|
|
206
|
+
_dec14
|
|
207
|
+
], _BaseEntity2));
|
|
208
|
+
}
|
|
209
|
+
static{
|
|
210
|
+
_initClass2();
|
|
602
211
|
}
|
|
603
212
|
constructor(...args){
|
|
604
|
-
super(...args), this.
|
|
213
|
+
super(...args), this.name = _init_name1(this), this.email = _init_email(this), this.password = _init_password(this), this.profile = _init_profile(this), this.users = _init_users(this);
|
|
605
214
|
}
|
|
606
215
|
}
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
};
|
|
635
|
-
} finally{
|
|
636
|
-
await querier.release();
|
|
637
|
-
}
|
|
638
|
-
}
|
|
639
|
-
async getTableNames() {
|
|
640
|
-
const querier = await this.getQuerier();
|
|
641
|
-
try {
|
|
642
|
-
const sql = `
|
|
643
|
-
SELECT TABLE_NAME as table_name
|
|
644
|
-
FROM information_schema.TABLES
|
|
645
|
-
WHERE TABLE_SCHEMA = DATABASE()
|
|
646
|
-
AND TABLE_TYPE = 'BASE TABLE'
|
|
647
|
-
ORDER BY TABLE_NAME
|
|
648
|
-
`;
|
|
649
|
-
const results = await querier.all(sql);
|
|
650
|
-
return results.map((r)=>r.table_name);
|
|
651
|
-
} finally{
|
|
652
|
-
await querier.release();
|
|
653
|
-
}
|
|
654
|
-
}
|
|
655
|
-
async tableExists(tableName) {
|
|
656
|
-
const querier = await this.getQuerier();
|
|
657
|
-
try {
|
|
658
|
-
return this.tableExistsInternal(querier, tableName);
|
|
659
|
-
} finally{
|
|
660
|
-
await querier.release();
|
|
661
|
-
}
|
|
662
|
-
}
|
|
663
|
-
async tableExistsInternal(querier, tableName) {
|
|
664
|
-
const sql = `
|
|
665
|
-
SELECT COUNT(*) as count
|
|
666
|
-
FROM information_schema.TABLES
|
|
667
|
-
WHERE TABLE_SCHEMA = DATABASE()
|
|
668
|
-
AND TABLE_NAME = ?
|
|
669
|
-
`;
|
|
670
|
-
const results = await querier.all(sql, [
|
|
671
|
-
tableName
|
|
672
|
-
]);
|
|
673
|
-
return (results[0]?.count ?? 0) > 0;
|
|
674
|
-
}
|
|
675
|
-
async getQuerier() {
|
|
676
|
-
const querier = await this.pool.getQuerier();
|
|
677
|
-
if (!isSqlQuerier(querier)) {
|
|
678
|
-
await querier.release();
|
|
679
|
-
throw new Error('MysqlSchemaIntrospector requires a SQL-based querier');
|
|
680
|
-
}
|
|
681
|
-
return querier;
|
|
682
|
-
}
|
|
683
|
-
async getColumns(querier, tableName) {
|
|
684
|
-
const sql = `
|
|
685
|
-
SELECT
|
|
686
|
-
COLUMN_NAME as column_name,
|
|
687
|
-
DATA_TYPE as data_type,
|
|
688
|
-
COLUMN_TYPE as column_type,
|
|
689
|
-
IS_NULLABLE as is_nullable,
|
|
690
|
-
COLUMN_DEFAULT as column_default,
|
|
691
|
-
CHARACTER_MAXIMUM_LENGTH as character_maximum_length,
|
|
692
|
-
NUMERIC_PRECISION as numeric_precision,
|
|
693
|
-
NUMERIC_SCALE as numeric_scale,
|
|
694
|
-
COLUMN_KEY as column_key,
|
|
695
|
-
EXTRA as extra,
|
|
696
|
-
COLUMN_COMMENT as column_comment
|
|
697
|
-
FROM information_schema.COLUMNS
|
|
698
|
-
WHERE TABLE_SCHEMA = DATABASE()
|
|
699
|
-
AND TABLE_NAME = ?
|
|
700
|
-
ORDER BY ORDINAL_POSITION
|
|
701
|
-
`;
|
|
702
|
-
const results = await querier.all(sql, [
|
|
703
|
-
tableName
|
|
704
|
-
]);
|
|
705
|
-
return results.map((row)=>({
|
|
706
|
-
name: row.column_name,
|
|
707
|
-
type: row.data_type.toUpperCase(),
|
|
708
|
-
nullable: row.is_nullable === 'YES',
|
|
709
|
-
defaultValue: this.parseDefaultValue(row.column_default),
|
|
710
|
-
isPrimaryKey: row.column_key === 'PRI',
|
|
711
|
-
isAutoIncrement: row.extra.toLowerCase().includes('auto_increment'),
|
|
712
|
-
isUnique: row.column_key === 'UNI',
|
|
713
|
-
length: row.character_maximum_length ?? undefined,
|
|
714
|
-
precision: row.numeric_precision ?? undefined,
|
|
715
|
-
scale: row.numeric_scale ?? undefined,
|
|
716
|
-
comment: row.column_comment || undefined
|
|
717
|
-
}));
|
|
718
|
-
}
|
|
719
|
-
async getIndexes(querier, tableName) {
|
|
720
|
-
const sql = `
|
|
721
|
-
SELECT
|
|
722
|
-
INDEX_NAME as index_name,
|
|
723
|
-
GROUP_CONCAT(COLUMN_NAME ORDER BY SEQ_IN_INDEX) as columns,
|
|
724
|
-
NOT NON_UNIQUE as is_unique
|
|
725
|
-
FROM information_schema.STATISTICS
|
|
726
|
-
WHERE TABLE_SCHEMA = DATABASE()
|
|
727
|
-
AND TABLE_NAME = ?
|
|
728
|
-
AND INDEX_NAME != 'PRIMARY'
|
|
729
|
-
GROUP BY INDEX_NAME, NON_UNIQUE
|
|
730
|
-
ORDER BY INDEX_NAME
|
|
731
|
-
`;
|
|
732
|
-
const results = await querier.all(sql, [
|
|
733
|
-
tableName
|
|
734
|
-
]);
|
|
735
|
-
return results.map((row)=>({
|
|
736
|
-
name: row.index_name,
|
|
737
|
-
columns: row.columns.split(','),
|
|
738
|
-
unique: Boolean(row.is_unique)
|
|
739
|
-
}));
|
|
740
|
-
}
|
|
741
|
-
async getForeignKeys(querier, tableName) {
|
|
742
|
-
const sql = `
|
|
743
|
-
SELECT
|
|
744
|
-
kcu.CONSTRAINT_NAME as constraint_name,
|
|
745
|
-
GROUP_CONCAT(kcu.COLUMN_NAME ORDER BY kcu.ORDINAL_POSITION) as columns,
|
|
746
|
-
kcu.REFERENCED_TABLE_NAME as referenced_table,
|
|
747
|
-
GROUP_CONCAT(kcu.REFERENCED_COLUMN_NAME ORDER BY kcu.ORDINAL_POSITION) as referenced_columns,
|
|
748
|
-
rc.DELETE_RULE as delete_rule,
|
|
749
|
-
rc.UPDATE_RULE as update_rule
|
|
750
|
-
FROM information_schema.KEY_COLUMN_USAGE kcu
|
|
751
|
-
JOIN information_schema.REFERENTIAL_CONSTRAINTS rc
|
|
752
|
-
ON kcu.CONSTRAINT_NAME = rc.CONSTRAINT_NAME
|
|
753
|
-
AND kcu.TABLE_SCHEMA = rc.CONSTRAINT_SCHEMA
|
|
754
|
-
WHERE kcu.TABLE_SCHEMA = DATABASE()
|
|
755
|
-
AND kcu.TABLE_NAME = ?
|
|
756
|
-
AND kcu.REFERENCED_TABLE_NAME IS NOT NULL
|
|
757
|
-
GROUP BY kcu.CONSTRAINT_NAME, kcu.REFERENCED_TABLE_NAME, rc.DELETE_RULE, rc.UPDATE_RULE
|
|
758
|
-
ORDER BY kcu.CONSTRAINT_NAME
|
|
759
|
-
`;
|
|
760
|
-
const results = await querier.all(sql, [
|
|
761
|
-
tableName
|
|
762
|
-
]);
|
|
763
|
-
return results.map((row)=>({
|
|
764
|
-
name: row.constraint_name,
|
|
765
|
-
columns: row.columns.split(','),
|
|
766
|
-
referencedTable: row.referenced_table,
|
|
767
|
-
referencedColumns: row.referenced_columns.split(','),
|
|
768
|
-
onDelete: this.normalizeReferentialAction(row.delete_rule),
|
|
769
|
-
onUpdate: this.normalizeReferentialAction(row.update_rule)
|
|
770
|
-
}));
|
|
771
|
-
}
|
|
772
|
-
async getPrimaryKey(querier, tableName) {
|
|
773
|
-
const sql = `
|
|
774
|
-
SELECT COLUMN_NAME as column_name
|
|
775
|
-
FROM information_schema.KEY_COLUMN_USAGE
|
|
776
|
-
WHERE TABLE_SCHEMA = DATABASE()
|
|
777
|
-
AND TABLE_NAME = ?
|
|
778
|
-
AND CONSTRAINT_NAME = 'PRIMARY'
|
|
779
|
-
ORDER BY ORDINAL_POSITION
|
|
780
|
-
`;
|
|
781
|
-
const results = await querier.all(sql, [
|
|
782
|
-
tableName
|
|
783
|
-
]);
|
|
784
|
-
if (results.length === 0) {
|
|
785
|
-
return undefined;
|
|
786
|
-
}
|
|
787
|
-
return results.map((r)=>r.column_name);
|
|
788
|
-
}
|
|
789
|
-
parseDefaultValue(defaultValue) {
|
|
790
|
-
if (defaultValue === null) {
|
|
791
|
-
return undefined;
|
|
792
|
-
}
|
|
793
|
-
// Check for common patterns
|
|
794
|
-
if (defaultValue === 'NULL') {
|
|
795
|
-
return null;
|
|
796
|
-
}
|
|
797
|
-
if (defaultValue === 'CURRENT_TIMESTAMP') {
|
|
798
|
-
return defaultValue;
|
|
799
|
-
}
|
|
800
|
-
if (/^'.*'$/.test(defaultValue)) {
|
|
801
|
-
return defaultValue.slice(1, -1);
|
|
802
|
-
}
|
|
803
|
-
if (/^-?\d+$/.test(defaultValue)) {
|
|
804
|
-
return Number.parseInt(defaultValue, 10);
|
|
805
|
-
}
|
|
806
|
-
if (/^-?\d+\.\d+$/.test(defaultValue)) {
|
|
807
|
-
return Number.parseFloat(defaultValue);
|
|
808
|
-
}
|
|
809
|
-
return defaultValue;
|
|
810
|
-
}
|
|
811
|
-
normalizeReferentialAction(action) {
|
|
812
|
-
switch(action.toUpperCase()){
|
|
813
|
-
case 'CASCADE':
|
|
814
|
-
return 'CASCADE';
|
|
815
|
-
case 'SET NULL':
|
|
816
|
-
return 'SET NULL';
|
|
817
|
-
case 'RESTRICT':
|
|
818
|
-
return 'RESTRICT';
|
|
819
|
-
case 'NO ACTION':
|
|
820
|
-
return 'NO ACTION';
|
|
821
|
-
default:
|
|
822
|
-
return undefined;
|
|
823
|
-
}
|
|
216
|
+
let _UserWithNonUpdatableId;
|
|
217
|
+
_dec20 = Entity(), _dec21 = Id({
|
|
218
|
+
updatable: false
|
|
219
|
+
}), _dec22 = Field();
|
|
220
|
+
class UserWithNonUpdatableId {
|
|
221
|
+
static{
|
|
222
|
+
({ e: [_init_id1, _init_name2], c: [_UserWithNonUpdatableId, _initClass3] } = _apply_decs_2203_r(this, [
|
|
223
|
+
[
|
|
224
|
+
_dec21,
|
|
225
|
+
0,
|
|
226
|
+
"id"
|
|
227
|
+
],
|
|
228
|
+
[
|
|
229
|
+
_dec22,
|
|
230
|
+
0,
|
|
231
|
+
"name"
|
|
232
|
+
]
|
|
233
|
+
], [
|
|
234
|
+
_dec20
|
|
235
|
+
]));
|
|
236
|
+
}
|
|
237
|
+
static{
|
|
238
|
+
_initClass3();
|
|
239
|
+
}
|
|
240
|
+
constructor(){
|
|
241
|
+
this.id = _init_id1(this);
|
|
242
|
+
this.name = _init_name2(this);
|
|
824
243
|
}
|
|
825
244
|
}
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
}
|
|
860
|
-
}
|
|
861
|
-
async getTableNames() {
|
|
862
|
-
const querier = await this.getQuerier();
|
|
863
|
-
try {
|
|
864
|
-
const sql = `
|
|
865
|
-
SELECT table_name
|
|
866
|
-
FROM information_schema.tables
|
|
867
|
-
WHERE table_schema = 'public'
|
|
868
|
-
AND table_type = 'BASE TABLE'
|
|
869
|
-
ORDER BY table_name
|
|
870
|
-
`;
|
|
871
|
-
const results = await querier.all(sql);
|
|
872
|
-
return results.map((r)=>r.table_name);
|
|
873
|
-
} finally{
|
|
874
|
-
await querier.release();
|
|
875
|
-
}
|
|
245
|
+
let _LedgerAccount;
|
|
246
|
+
_dec23 = Entity(), _dec24 = Field(), _dec25 = Field(), _dec26 = Field({
|
|
247
|
+
reference: ()=>_LedgerAccount
|
|
248
|
+
}), _dec27 = ManyToOne();
|
|
249
|
+
class LedgerAccount extends (_BaseEntity3 = BaseEntity) {
|
|
250
|
+
static{
|
|
251
|
+
({ e: [_init_name3, _init_description1, _init_parentLedgerId, _init_parentLedger], c: [_LedgerAccount, _initClass4] } = _apply_decs_2203_r(this, [
|
|
252
|
+
[
|
|
253
|
+
_dec24,
|
|
254
|
+
0,
|
|
255
|
+
"name"
|
|
256
|
+
],
|
|
257
|
+
[
|
|
258
|
+
_dec25,
|
|
259
|
+
0,
|
|
260
|
+
"description"
|
|
261
|
+
],
|
|
262
|
+
[
|
|
263
|
+
_dec26,
|
|
264
|
+
0,
|
|
265
|
+
"parentLedgerId"
|
|
266
|
+
],
|
|
267
|
+
[
|
|
268
|
+
_dec27,
|
|
269
|
+
0,
|
|
270
|
+
"parentLedger"
|
|
271
|
+
]
|
|
272
|
+
], [
|
|
273
|
+
_dec23
|
|
274
|
+
], _BaseEntity3));
|
|
275
|
+
}
|
|
276
|
+
static{
|
|
277
|
+
_initClass4();
|
|
876
278
|
}
|
|
877
|
-
|
|
878
|
-
|
|
879
|
-
try {
|
|
880
|
-
return this.tableExistsInternal(querier, tableName);
|
|
881
|
-
} finally{
|
|
882
|
-
await querier.release();
|
|
883
|
-
}
|
|
884
|
-
}
|
|
885
|
-
async tableExistsInternal(querier, tableName) {
|
|
886
|
-
const sql = `
|
|
887
|
-
SELECT EXISTS (
|
|
888
|
-
SELECT FROM information_schema.tables
|
|
889
|
-
WHERE table_schema = 'public'
|
|
890
|
-
AND table_name = $1
|
|
891
|
-
) AS exists
|
|
892
|
-
`;
|
|
893
|
-
const results = await querier.all(sql, [
|
|
894
|
-
tableName
|
|
895
|
-
]);
|
|
896
|
-
return results[0]?.exists ?? false;
|
|
897
|
-
}
|
|
898
|
-
async getQuerier() {
|
|
899
|
-
const querier = await this.pool.getQuerier();
|
|
900
|
-
if (!isSqlQuerier(querier)) {
|
|
901
|
-
await querier.release();
|
|
902
|
-
throw new Error('PostgresSchemaIntrospector requires a SQL-based querier');
|
|
903
|
-
}
|
|
904
|
-
return querier;
|
|
905
|
-
}
|
|
906
|
-
async getColumns(querier, tableName) {
|
|
907
|
-
const sql = /*sql*/ `
|
|
908
|
-
SELECT
|
|
909
|
-
c.column_name,
|
|
910
|
-
c.data_type,
|
|
911
|
-
c.udt_name,
|
|
912
|
-
c.is_nullable,
|
|
913
|
-
c.column_default,
|
|
914
|
-
c.character_maximum_length,
|
|
915
|
-
c.numeric_precision,
|
|
916
|
-
c.numeric_scale,
|
|
917
|
-
COALESCE(
|
|
918
|
-
(SELECT TRUE FROM information_schema.table_constraints tc
|
|
919
|
-
JOIN information_schema.key_column_usage kcu
|
|
920
|
-
ON tc.constraint_name = kcu.constraint_name
|
|
921
|
-
WHERE tc.table_name = c.table_name
|
|
922
|
-
AND tc.constraint_type = 'PRIMARY KEY'
|
|
923
|
-
AND kcu.column_name = c.column_name
|
|
924
|
-
LIMIT 1),
|
|
925
|
-
FALSE
|
|
926
|
-
) AS is_primary_key,
|
|
927
|
-
COALESCE(
|
|
928
|
-
(SELECT TRUE FROM information_schema.table_constraints tc
|
|
929
|
-
JOIN information_schema.key_column_usage kcu
|
|
930
|
-
ON tc.constraint_name = kcu.constraint_name
|
|
931
|
-
WHERE tc.table_name = c.table_name
|
|
932
|
-
AND tc.constraint_type = 'UNIQUE'
|
|
933
|
-
AND kcu.column_name = c.column_name
|
|
934
|
-
LIMIT 1),
|
|
935
|
-
FALSE
|
|
936
|
-
) AS is_unique,
|
|
937
|
-
pg_catalog.col_description(
|
|
938
|
-
(SELECT oid FROM pg_catalog.pg_class WHERE relname = c.table_name),
|
|
939
|
-
c.ordinal_position
|
|
940
|
-
) AS column_comment
|
|
941
|
-
FROM information_schema.columns c
|
|
942
|
-
WHERE c.table_schema = 'public'
|
|
943
|
-
AND c.table_name = $1
|
|
944
|
-
ORDER BY c.ordinal_position
|
|
945
|
-
`;
|
|
946
|
-
const results = await querier.all(sql, [
|
|
947
|
-
tableName
|
|
948
|
-
]);
|
|
949
|
-
return results.map((row)=>({
|
|
950
|
-
name: row.column_name,
|
|
951
|
-
type: this.normalizeType(row.data_type, row.udt_name),
|
|
952
|
-
nullable: row.is_nullable === 'YES',
|
|
953
|
-
defaultValue: this.parseDefaultValue(row.column_default),
|
|
954
|
-
isPrimaryKey: row.is_primary_key,
|
|
955
|
-
isAutoIncrement: this.isAutoIncrement(row.column_default),
|
|
956
|
-
isUnique: row.is_unique,
|
|
957
|
-
length: row.character_maximum_length ?? undefined,
|
|
958
|
-
precision: row.numeric_precision ?? undefined,
|
|
959
|
-
scale: row.numeric_scale ?? undefined,
|
|
960
|
-
comment: row.column_comment ?? undefined
|
|
961
|
-
}));
|
|
962
|
-
}
|
|
963
|
-
async getIndexes(querier, tableName) {
|
|
964
|
-
const sql = /*sql*/ `
|
|
965
|
-
SELECT
|
|
966
|
-
i.relname AS index_name,
|
|
967
|
-
array_agg(a.attname ORDER BY k.n) AS columns,
|
|
968
|
-
ix.indisunique AS is_unique
|
|
969
|
-
FROM pg_class t
|
|
970
|
-
JOIN pg_index ix ON t.oid = ix.indrelid
|
|
971
|
-
JOIN pg_class i ON i.oid = ix.indexrelid
|
|
972
|
-
JOIN pg_namespace n ON n.oid = t.relnamespace
|
|
973
|
-
CROSS JOIN LATERAL unnest(ix.indkey) WITH ORDINALITY AS k(attnum, n)
|
|
974
|
-
JOIN pg_attribute a ON a.attrelid = t.oid AND a.attnum = k.attnum
|
|
975
|
-
WHERE t.relname = $1
|
|
976
|
-
AND n.nspname = 'public'
|
|
977
|
-
AND NOT ix.indisprimary
|
|
978
|
-
GROUP BY i.relname, ix.indisunique
|
|
979
|
-
ORDER BY i.relname
|
|
980
|
-
`;
|
|
981
|
-
const results = await querier.all(sql, [
|
|
982
|
-
tableName
|
|
983
|
-
]);
|
|
984
|
-
return results.map((row)=>({
|
|
985
|
-
name: row.index_name,
|
|
986
|
-
columns: row.columns,
|
|
987
|
-
unique: row.is_unique
|
|
988
|
-
}));
|
|
989
|
-
}
|
|
990
|
-
async getForeignKeys(querier, tableName) {
|
|
991
|
-
const sql = /*sql*/ `
|
|
992
|
-
SELECT
|
|
993
|
-
tc.constraint_name,
|
|
994
|
-
array_agg(kcu.column_name ORDER BY kcu.ordinal_position) AS columns,
|
|
995
|
-
ccu.table_name AS referenced_table,
|
|
996
|
-
array_agg(ccu.column_name ORDER BY kcu.ordinal_position) AS referenced_columns,
|
|
997
|
-
rc.delete_rule,
|
|
998
|
-
rc.update_rule
|
|
999
|
-
FROM information_schema.table_constraints tc
|
|
1000
|
-
JOIN information_schema.key_column_usage kcu
|
|
1001
|
-
ON tc.constraint_name = kcu.constraint_name
|
|
1002
|
-
AND tc.table_schema = kcu.table_schema
|
|
1003
|
-
JOIN information_schema.constraint_column_usage ccu
|
|
1004
|
-
ON ccu.constraint_name = tc.constraint_name
|
|
1005
|
-
AND ccu.table_schema = tc.table_schema
|
|
1006
|
-
JOIN information_schema.referential_constraints rc
|
|
1007
|
-
ON rc.constraint_name = tc.constraint_name
|
|
1008
|
-
AND rc.constraint_schema = tc.table_schema
|
|
1009
|
-
WHERE tc.constraint_type = 'FOREIGN KEY'
|
|
1010
|
-
AND tc.table_name = $1
|
|
1011
|
-
AND tc.table_schema = 'public'
|
|
1012
|
-
GROUP BY tc.constraint_name, ccu.table_name, rc.delete_rule, rc.update_rule
|
|
1013
|
-
ORDER BY tc.constraint_name
|
|
1014
|
-
`;
|
|
1015
|
-
const results = await querier.all(sql, [
|
|
1016
|
-
tableName
|
|
1017
|
-
]);
|
|
1018
|
-
return results.map((row)=>({
|
|
1019
|
-
name: row.constraint_name,
|
|
1020
|
-
columns: row.columns,
|
|
1021
|
-
referencedTable: row.referenced_table,
|
|
1022
|
-
referencedColumns: row.referenced_columns,
|
|
1023
|
-
onDelete: this.normalizeReferentialAction(row.delete_rule),
|
|
1024
|
-
onUpdate: this.normalizeReferentialAction(row.update_rule)
|
|
1025
|
-
}));
|
|
1026
|
-
}
|
|
1027
|
-
async getPrimaryKey(querier, tableName) {
|
|
1028
|
-
const sql = /*sql*/ `
|
|
1029
|
-
SELECT kcu.column_name
|
|
1030
|
-
FROM information_schema.table_constraints tc
|
|
1031
|
-
JOIN information_schema.key_column_usage kcu
|
|
1032
|
-
ON tc.constraint_name = kcu.constraint_name
|
|
1033
|
-
AND tc.table_schema = kcu.table_schema
|
|
1034
|
-
WHERE tc.constraint_type = 'PRIMARY KEY'
|
|
1035
|
-
AND tc.table_name = $1
|
|
1036
|
-
AND tc.table_schema = 'public'
|
|
1037
|
-
ORDER BY kcu.ordinal_position
|
|
1038
|
-
`;
|
|
1039
|
-
const results = await querier.all(sql, [
|
|
1040
|
-
tableName
|
|
1041
|
-
]);
|
|
1042
|
-
if (results.length === 0) {
|
|
1043
|
-
return undefined;
|
|
1044
|
-
}
|
|
1045
|
-
return results.map((r)=>r.column_name);
|
|
1046
|
-
}
|
|
1047
|
-
normalizeType(dataType, udtName) {
|
|
1048
|
-
// Handle user-defined types and arrays
|
|
1049
|
-
if (dataType === 'USER-DEFINED') {
|
|
1050
|
-
return udtName.toUpperCase();
|
|
1051
|
-
}
|
|
1052
|
-
if (dataType === 'ARRAY') {
|
|
1053
|
-
return `${udtName.replace(/^_/, '')}[]`;
|
|
1054
|
-
}
|
|
1055
|
-
return dataType.toUpperCase();
|
|
1056
|
-
}
|
|
1057
|
-
parseDefaultValue(defaultValue) {
|
|
1058
|
-
if (!defaultValue) {
|
|
1059
|
-
return undefined;
|
|
1060
|
-
}
|
|
1061
|
-
// Remove type casting
|
|
1062
|
-
const cleaned = defaultValue.replace(/::[a-z_]+(\[\])?/gi, '').trim();
|
|
1063
|
-
// Check for common patterns
|
|
1064
|
-
if (cleaned.startsWith("'") && cleaned.endsWith("'")) {
|
|
1065
|
-
return cleaned.slice(1, -1);
|
|
1066
|
-
}
|
|
1067
|
-
if (cleaned === 'true' || cleaned === 'false') {
|
|
1068
|
-
return cleaned === 'true';
|
|
1069
|
-
}
|
|
1070
|
-
if (cleaned === 'NULL') {
|
|
1071
|
-
return null;
|
|
1072
|
-
}
|
|
1073
|
-
if (/^-?\d+$/.test(cleaned)) {
|
|
1074
|
-
return Number.parseInt(cleaned, 10);
|
|
1075
|
-
}
|
|
1076
|
-
if (/^-?\d+\.\d+$/.test(cleaned)) {
|
|
1077
|
-
return Number.parseFloat(cleaned);
|
|
1078
|
-
}
|
|
1079
|
-
// Return as-is for functions like CURRENT_TIMESTAMP, nextval(), etc.
|
|
1080
|
-
return defaultValue;
|
|
1081
|
-
}
|
|
1082
|
-
isAutoIncrement(defaultValue) {
|
|
1083
|
-
if (!defaultValue) {
|
|
1084
|
-
return false;
|
|
1085
|
-
}
|
|
1086
|
-
return defaultValue.includes('nextval(');
|
|
1087
|
-
}
|
|
1088
|
-
normalizeReferentialAction(action) {
|
|
1089
|
-
switch(action.toUpperCase()){
|
|
1090
|
-
case 'CASCADE':
|
|
1091
|
-
return 'CASCADE';
|
|
1092
|
-
case 'SET NULL':
|
|
1093
|
-
return 'SET NULL';
|
|
1094
|
-
case 'RESTRICT':
|
|
1095
|
-
return 'RESTRICT';
|
|
1096
|
-
case 'NO ACTION':
|
|
1097
|
-
return 'NO ACTION';
|
|
1098
|
-
default:
|
|
1099
|
-
return undefined;
|
|
1100
|
-
}
|
|
279
|
+
constructor(...args){
|
|
280
|
+
super(...args), this.name = _init_name3(this), this.description = _init_description1(this), this.parentLedgerId = _init_parentLedgerId(this), this.parentLedger = _init_parentLedger(this);
|
|
1101
281
|
}
|
|
1102
282
|
}
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
283
|
+
let _TaxCategory;
|
|
284
|
+
_dec28 = Entity(), _dec29 = Id({
|
|
285
|
+
onInsert: randomUUID
|
|
286
|
+
}), _dec30 = Field(), _dec31 = Field();
|
|
287
|
+
class TaxCategory extends (_BaseEntity4 = BaseEntity) {
|
|
288
|
+
static{
|
|
289
|
+
({ e: [_init_pk1, _init_name4, _init_description2], c: [_TaxCategory, _initClass5] } = _apply_decs_2203_r(this, [
|
|
290
|
+
[
|
|
291
|
+
_dec29,
|
|
292
|
+
0,
|
|
293
|
+
"pk"
|
|
294
|
+
],
|
|
295
|
+
[
|
|
296
|
+
_dec30,
|
|
297
|
+
0,
|
|
298
|
+
"name"
|
|
299
|
+
],
|
|
300
|
+
[
|
|
301
|
+
_dec31,
|
|
302
|
+
0,
|
|
303
|
+
"description"
|
|
304
|
+
]
|
|
305
|
+
], [
|
|
306
|
+
_dec28
|
|
307
|
+
], _BaseEntity4));
|
|
308
|
+
}
|
|
309
|
+
static{
|
|
310
|
+
_initClass5();
|
|
1109
311
|
}
|
|
1110
|
-
|
|
1111
|
-
|
|
1112
|
-
try {
|
|
1113
|
-
const exists = await this.tableExistsInternal(querier, tableName);
|
|
1114
|
-
if (!exists) {
|
|
1115
|
-
return undefined;
|
|
1116
|
-
}
|
|
1117
|
-
const [columns, indexes, foreignKeys, primaryKey] = await Promise.all([
|
|
1118
|
-
this.getColumns(querier, tableName),
|
|
1119
|
-
this.getIndexes(querier, tableName),
|
|
1120
|
-
this.getForeignKeys(querier, tableName),
|
|
1121
|
-
this.getPrimaryKey(querier, tableName)
|
|
1122
|
-
]);
|
|
1123
|
-
return {
|
|
1124
|
-
name: tableName,
|
|
1125
|
-
columns,
|
|
1126
|
-
primaryKey,
|
|
1127
|
-
indexes,
|
|
1128
|
-
foreignKeys
|
|
1129
|
-
};
|
|
1130
|
-
} finally{
|
|
1131
|
-
await querier.release();
|
|
1132
|
-
}
|
|
1133
|
-
}
|
|
1134
|
-
async getTableNames() {
|
|
1135
|
-
const querier = await this.getQuerier();
|
|
1136
|
-
try {
|
|
1137
|
-
const sql = /*sql*/ `
|
|
1138
|
-
SELECT name
|
|
1139
|
-
FROM sqlite_master
|
|
1140
|
-
WHERE type = 'table'
|
|
1141
|
-
AND name NOT LIKE 'sqlite_%'
|
|
1142
|
-
ORDER BY name
|
|
1143
|
-
`;
|
|
1144
|
-
const results = await querier.all(sql);
|
|
1145
|
-
return results.map((r)=>r.name);
|
|
1146
|
-
} finally{
|
|
1147
|
-
await querier.release();
|
|
1148
|
-
}
|
|
1149
|
-
}
|
|
1150
|
-
async tableExists(tableName) {
|
|
1151
|
-
const querier = await this.getQuerier();
|
|
1152
|
-
try {
|
|
1153
|
-
return this.tableExistsInternal(querier, tableName);
|
|
1154
|
-
} finally{
|
|
1155
|
-
await querier.release();
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
async tableExistsInternal(querier, tableName) {
|
|
1159
|
-
const sql = /*sql*/ `
|
|
1160
|
-
SELECT COUNT(*) as count
|
|
1161
|
-
FROM sqlite_master
|
|
1162
|
-
WHERE type = 'table'
|
|
1163
|
-
AND name = ?
|
|
1164
|
-
`;
|
|
1165
|
-
const results = await querier.all(sql, [
|
|
1166
|
-
tableName
|
|
1167
|
-
]);
|
|
1168
|
-
return (results[0]?.count ?? 0) > 0;
|
|
1169
|
-
}
|
|
1170
|
-
async getQuerier() {
|
|
1171
|
-
const querier = await this.pool.getQuerier();
|
|
1172
|
-
if (!isSqlQuerier(querier)) {
|
|
1173
|
-
await querier.release();
|
|
1174
|
-
throw new Error('SqliteSchemaIntrospector requires a SQL-based querier');
|
|
1175
|
-
}
|
|
1176
|
-
return querier;
|
|
1177
|
-
}
|
|
1178
|
-
async getColumns(querier, tableName) {
|
|
1179
|
-
// SQLite uses PRAGMA for table info
|
|
1180
|
-
const sql = `PRAGMA table_info(${this.escapeId(tableName)})`;
|
|
1181
|
-
const results = await querier.all(sql);
|
|
1182
|
-
// Get unique columns from indexes
|
|
1183
|
-
const uniqueColumns = await this.getUniqueColumns(querier, tableName);
|
|
1184
|
-
return results.map((row)=>({
|
|
1185
|
-
name: row.name,
|
|
1186
|
-
type: this.normalizeType(row.type),
|
|
1187
|
-
nullable: row.notnull === 0,
|
|
1188
|
-
defaultValue: this.parseDefaultValue(row.dflt_value),
|
|
1189
|
-
isPrimaryKey: row.pk > 0,
|
|
1190
|
-
isAutoIncrement: row.pk > 0 && row.type.toUpperCase() === 'INTEGER',
|
|
1191
|
-
isUnique: uniqueColumns.has(row.name),
|
|
1192
|
-
length: this.extractLength(row.type),
|
|
1193
|
-
precision: undefined,
|
|
1194
|
-
scale: undefined,
|
|
1195
|
-
comment: undefined
|
|
1196
|
-
}));
|
|
1197
|
-
}
|
|
1198
|
-
async getUniqueColumns(querier, tableName) {
|
|
1199
|
-
const sql = `PRAGMA index_list(${this.escapeId(tableName)})`;
|
|
1200
|
-
const indexes = await querier.all(sql);
|
|
1201
|
-
const uniqueColumns = new Set();
|
|
1202
|
-
for (const index of indexes){
|
|
1203
|
-
if (index.unique && index.origin === 'u') {
|
|
1204
|
-
const indexInfo = await querier.all(`PRAGMA index_info(${this.escapeId(index.name)})`);
|
|
1205
|
-
// Only single-column unique constraints
|
|
1206
|
-
if (indexInfo.length === 1) {
|
|
1207
|
-
uniqueColumns.add(indexInfo[0].name);
|
|
1208
|
-
}
|
|
1209
|
-
}
|
|
1210
|
-
}
|
|
1211
|
-
return uniqueColumns;
|
|
312
|
+
constructor(...args){
|
|
313
|
+
super(...args), this.pk = _init_pk1(this), this.name = _init_name4(this), this.description = _init_description2(this);
|
|
1212
314
|
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
|
|
1219
|
-
|
|
1220
|
-
|
|
1221
|
-
|
|
1222
|
-
|
|
1223
|
-
|
|
1224
|
-
name
|
|
1225
|
-
|
|
1226
|
-
|
|
1227
|
-
|
|
1228
|
-
|
|
1229
|
-
|
|
315
|
+
}
|
|
316
|
+
let _Tax;
|
|
317
|
+
_dec32 = Entity(), _dec33 = Field(), _dec34 = Field(), _dec35 = Field({
|
|
318
|
+
reference: ()=>_TaxCategory
|
|
319
|
+
}), _dec36 = ManyToOne(), _dec37 = Field();
|
|
320
|
+
class Tax extends (_BaseEntity5 = BaseEntity) {
|
|
321
|
+
static{
|
|
322
|
+
({ e: [_init_name5, _init_percentage, _init_categoryId, _init_category, _init_description3], c: [_Tax, _initClass6] } = _apply_decs_2203_r(this, [
|
|
323
|
+
[
|
|
324
|
+
_dec33,
|
|
325
|
+
0,
|
|
326
|
+
"name"
|
|
327
|
+
],
|
|
328
|
+
[
|
|
329
|
+
_dec34,
|
|
330
|
+
0,
|
|
331
|
+
"percentage"
|
|
332
|
+
],
|
|
333
|
+
[
|
|
334
|
+
_dec35,
|
|
335
|
+
0,
|
|
336
|
+
"categoryId"
|
|
337
|
+
],
|
|
338
|
+
[
|
|
339
|
+
_dec36,
|
|
340
|
+
0,
|
|
341
|
+
"category"
|
|
342
|
+
],
|
|
343
|
+
[
|
|
344
|
+
_dec37,
|
|
345
|
+
0,
|
|
346
|
+
"description"
|
|
347
|
+
]
|
|
348
|
+
], [
|
|
349
|
+
_dec32
|
|
350
|
+
], _BaseEntity5));
|
|
351
|
+
}
|
|
352
|
+
static{
|
|
353
|
+
_initClass6();
|
|
1230
354
|
}
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
const results = await querier.all(sql);
|
|
1234
|
-
// Group by id to handle composite foreign keys
|
|
1235
|
-
const grouped = new Map();
|
|
1236
|
-
for (const row of results){
|
|
1237
|
-
const existing = grouped.get(row.id) ?? [];
|
|
1238
|
-
existing.push(row);
|
|
1239
|
-
grouped.set(row.id, existing);
|
|
1240
|
-
}
|
|
1241
|
-
return Array.from(grouped.entries()).map(([id, rows])=>{
|
|
1242
|
-
const first = rows[0];
|
|
1243
|
-
return {
|
|
1244
|
-
name: `fk_${tableName}_${id}`,
|
|
1245
|
-
columns: rows.map((r)=>r.from),
|
|
1246
|
-
referencedTable: first.table,
|
|
1247
|
-
referencedColumns: rows.map((r)=>r.to),
|
|
1248
|
-
onDelete: this.normalizeReferentialAction(first.on_delete),
|
|
1249
|
-
onUpdate: this.normalizeReferentialAction(first.on_update)
|
|
1250
|
-
};
|
|
1251
|
-
});
|
|
355
|
+
constructor(...args){
|
|
356
|
+
super(...args), this.name = _init_name5(this), this.percentage = _init_percentage(this), this.categoryId = _init_categoryId(this), this.category = _init_category(this), this.description = _init_description3(this);
|
|
1252
357
|
}
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
|
|
1257
|
-
|
|
1258
|
-
|
|
1259
|
-
|
|
1260
|
-
|
|
358
|
+
}
|
|
359
|
+
let _MeasureUnitCategory;
|
|
360
|
+
_dec38 = Entity({
|
|
361
|
+
softDelete: true
|
|
362
|
+
}), _dec39 = Field(), _dec40 = OneToMany({
|
|
363
|
+
entity: ()=>_MeasureUnit,
|
|
364
|
+
mappedBy: (measureUnit)=>measureUnit.categoryId
|
|
365
|
+
}), _dec41 = Field({
|
|
366
|
+
onDelete: Date.now
|
|
367
|
+
});
|
|
368
|
+
class MeasureUnitCategory extends (_BaseEntity6 = BaseEntity) {
|
|
369
|
+
static{
|
|
370
|
+
({ e: [_init_name6, _init_measureUnits, _init_deletedAt], c: [_MeasureUnitCategory, _initClass7] } = _apply_decs_2203_r(this, [
|
|
371
|
+
[
|
|
372
|
+
_dec39,
|
|
373
|
+
0,
|
|
374
|
+
"name"
|
|
375
|
+
],
|
|
376
|
+
[
|
|
377
|
+
_dec40,
|
|
378
|
+
0,
|
|
379
|
+
"measureUnits"
|
|
380
|
+
],
|
|
381
|
+
[
|
|
382
|
+
_dec41,
|
|
383
|
+
0,
|
|
384
|
+
"deletedAt"
|
|
385
|
+
]
|
|
386
|
+
], [
|
|
387
|
+
_dec38
|
|
388
|
+
], _BaseEntity6));
|
|
389
|
+
}
|
|
390
|
+
static{
|
|
391
|
+
_initClass7();
|
|
1261
392
|
}
|
|
1262
|
-
|
|
1263
|
-
|
|
393
|
+
constructor(...args){
|
|
394
|
+
super(...args), this.name = _init_name6(this), this.measureUnits = _init_measureUnits(this), this.deletedAt = _init_deletedAt(this);
|
|
1264
395
|
}
|
|
1265
|
-
|
|
1266
|
-
|
|
1267
|
-
|
|
1268
|
-
|
|
396
|
+
}
|
|
397
|
+
let _MeasureUnit;
|
|
398
|
+
_dec42 = Entity({
|
|
399
|
+
softDelete: true
|
|
400
|
+
}), _dec43 = Field(), _dec44 = Field({
|
|
401
|
+
reference: ()=>_MeasureUnitCategory
|
|
402
|
+
}), _dec45 = ManyToOne({
|
|
403
|
+
cascade: 'persist'
|
|
404
|
+
}), _dec46 = Field({
|
|
405
|
+
onDelete: Date.now
|
|
406
|
+
});
|
|
407
|
+
class MeasureUnit extends (_BaseEntity7 = BaseEntity) {
|
|
408
|
+
static{
|
|
409
|
+
({ e: [_init_name7, _init_categoryId1, _init_category1, _init_deletedAt1], c: [_MeasureUnit, _initClass8] } = _apply_decs_2203_r(this, [
|
|
410
|
+
[
|
|
411
|
+
_dec43,
|
|
412
|
+
0,
|
|
413
|
+
"name"
|
|
414
|
+
],
|
|
415
|
+
[
|
|
416
|
+
_dec44,
|
|
417
|
+
0,
|
|
418
|
+
"categoryId"
|
|
419
|
+
],
|
|
420
|
+
[
|
|
421
|
+
_dec45,
|
|
422
|
+
0,
|
|
423
|
+
"category"
|
|
424
|
+
],
|
|
425
|
+
[
|
|
426
|
+
_dec46,
|
|
427
|
+
0,
|
|
428
|
+
"deletedAt"
|
|
429
|
+
]
|
|
430
|
+
], [
|
|
431
|
+
_dec42
|
|
432
|
+
], _BaseEntity7));
|
|
433
|
+
}
|
|
434
|
+
static{
|
|
435
|
+
_initClass8();
|
|
1269
436
|
}
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
return match ? Number.parseInt(match[1], 10) : undefined;
|
|
437
|
+
constructor(...args){
|
|
438
|
+
super(...args), this.name = _init_name7(this), this.categoryId = _init_categoryId1(this), this.category = _init_category1(this), this.deletedAt = _init_deletedAt1(this);
|
|
1273
439
|
}
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
|
|
1285
|
-
|
|
1286
|
-
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
|
|
1292
|
-
|
|
1293
|
-
|
|
1294
|
-
|
|
440
|
+
}
|
|
441
|
+
let _Storehouse;
|
|
442
|
+
_dec47 = Entity(), _dec48 = Field(), _dec49 = Field(), _dec50 = Field();
|
|
443
|
+
class Storehouse extends (_BaseEntity8 = BaseEntity) {
|
|
444
|
+
static{
|
|
445
|
+
({ e: [_init_name8, _init_address, _init_description4], c: [_Storehouse, _initClass9] } = _apply_decs_2203_r(this, [
|
|
446
|
+
[
|
|
447
|
+
_dec48,
|
|
448
|
+
0,
|
|
449
|
+
"name"
|
|
450
|
+
],
|
|
451
|
+
[
|
|
452
|
+
_dec49,
|
|
453
|
+
0,
|
|
454
|
+
"address"
|
|
455
|
+
],
|
|
456
|
+
[
|
|
457
|
+
_dec50,
|
|
458
|
+
0,
|
|
459
|
+
"description"
|
|
460
|
+
]
|
|
461
|
+
], [
|
|
462
|
+
_dec47
|
|
463
|
+
], _BaseEntity8));
|
|
464
|
+
}
|
|
465
|
+
static{
|
|
466
|
+
_initClass9();
|
|
1295
467
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
case 'CASCADE':
|
|
1299
|
-
return 'CASCADE';
|
|
1300
|
-
case 'SET NULL':
|
|
1301
|
-
return 'SET NULL';
|
|
1302
|
-
case 'RESTRICT':
|
|
1303
|
-
return 'RESTRICT';
|
|
1304
|
-
case 'NO ACTION':
|
|
1305
|
-
return 'NO ACTION';
|
|
1306
|
-
default:
|
|
1307
|
-
return undefined;
|
|
1308
|
-
}
|
|
468
|
+
constructor(...args){
|
|
469
|
+
super(...args), this.name = _init_name8(this), this.address = _init_address(this), this.description = _init_description4(this);
|
|
1309
470
|
}
|
|
1310
471
|
}
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
472
|
+
let _Item;
|
|
473
|
+
_dec51 = Entity(), _dec52 = Field(), _dec53 = Field(), _dec54 = Field(), _dec55 = Field({
|
|
474
|
+
reference: ()=>_LedgerAccount
|
|
475
|
+
}), _dec56 = ManyToOne(), _dec57 = Field({
|
|
476
|
+
reference: ()=>_LedgerAccount
|
|
477
|
+
}), _dec58 = ManyToOne(), _dec59 = Field({
|
|
478
|
+
reference: ()=>_Tax
|
|
479
|
+
}), _dec60 = ManyToOne(), _dec61 = Field({
|
|
480
|
+
reference: ()=>_MeasureUnit
|
|
481
|
+
}), _dec62 = ManyToOne(), _dec63 = Field(), _dec64 = Field(), _dec65 = ManyToMany({
|
|
482
|
+
entity: ()=>_Tag,
|
|
483
|
+
through: ()=>_ItemTag,
|
|
484
|
+
cascade: true
|
|
485
|
+
}), _dec66 = Field({
|
|
486
|
+
/**
|
|
487
|
+
* `virtual` property allows defining the value for a non-persistent field,
|
|
488
|
+
* such value might be a scalar or a (`raw`) function. Virtual-fields can
|
|
489
|
+
* be used in `$select` and `$where` as a common field whose value is
|
|
490
|
+
* replaced is replaced at runtime.
|
|
491
|
+
*/ virtual: raw(({ ctx, escapedPrefix, dialect })=>{
|
|
492
|
+
ctx.append('(');
|
|
493
|
+
dialect.count(ctx, _ItemTag, {
|
|
494
|
+
$where: {
|
|
495
|
+
itemId: raw(({ ctx })=>{
|
|
496
|
+
ctx.append(escapedPrefix + dialect.escapeId('id'));
|
|
497
|
+
})
|
|
498
|
+
}
|
|
499
|
+
}, {
|
|
500
|
+
autoPrefix: true
|
|
1335
501
|
});
|
|
502
|
+
ctx.append(')');
|
|
503
|
+
})
|
|
504
|
+
});
|
|
505
|
+
class Item extends (_BaseEntity9 = BaseEntity) {
|
|
506
|
+
static{
|
|
507
|
+
({ e: [_init_name9, _init_description5, _init_code, _init_buyLedgerAccountId, _init_buyLedgerAccount, _init_saleLedgerAccountId, _init_saleLedgerAccount, _init_taxId, _init_tax, _init_measureUnitId, _init_measureUnit, _init_salePrice, _init_inventoryable, _init_tags, _init_tagsCount], c: [_Item, _initClass10] } = _apply_decs_2203_r(this, [
|
|
508
|
+
[
|
|
509
|
+
_dec52,
|
|
510
|
+
0,
|
|
511
|
+
"name"
|
|
512
|
+
],
|
|
513
|
+
[
|
|
514
|
+
_dec53,
|
|
515
|
+
0,
|
|
516
|
+
"description"
|
|
517
|
+
],
|
|
518
|
+
[
|
|
519
|
+
_dec54,
|
|
520
|
+
0,
|
|
521
|
+
"code"
|
|
522
|
+
],
|
|
523
|
+
[
|
|
524
|
+
_dec55,
|
|
525
|
+
0,
|
|
526
|
+
"buyLedgerAccountId"
|
|
527
|
+
],
|
|
528
|
+
[
|
|
529
|
+
_dec56,
|
|
530
|
+
0,
|
|
531
|
+
"buyLedgerAccount"
|
|
532
|
+
],
|
|
533
|
+
[
|
|
534
|
+
_dec57,
|
|
535
|
+
0,
|
|
536
|
+
"saleLedgerAccountId"
|
|
537
|
+
],
|
|
538
|
+
[
|
|
539
|
+
_dec58,
|
|
540
|
+
0,
|
|
541
|
+
"saleLedgerAccount"
|
|
542
|
+
],
|
|
543
|
+
[
|
|
544
|
+
_dec59,
|
|
545
|
+
0,
|
|
546
|
+
"taxId"
|
|
547
|
+
],
|
|
548
|
+
[
|
|
549
|
+
_dec60,
|
|
550
|
+
0,
|
|
551
|
+
"tax"
|
|
552
|
+
],
|
|
553
|
+
[
|
|
554
|
+
_dec61,
|
|
555
|
+
0,
|
|
556
|
+
"measureUnitId"
|
|
557
|
+
],
|
|
558
|
+
[
|
|
559
|
+
_dec62,
|
|
560
|
+
0,
|
|
561
|
+
"measureUnit"
|
|
562
|
+
],
|
|
563
|
+
[
|
|
564
|
+
_dec63,
|
|
565
|
+
0,
|
|
566
|
+
"salePrice"
|
|
567
|
+
],
|
|
568
|
+
[
|
|
569
|
+
_dec64,
|
|
570
|
+
0,
|
|
571
|
+
"inventoryable"
|
|
572
|
+
],
|
|
573
|
+
[
|
|
574
|
+
_dec65,
|
|
575
|
+
0,
|
|
576
|
+
"tags"
|
|
577
|
+
],
|
|
578
|
+
[
|
|
579
|
+
_dec66,
|
|
580
|
+
0,
|
|
581
|
+
"tagsCount"
|
|
582
|
+
]
|
|
583
|
+
], [
|
|
584
|
+
_dec51
|
|
585
|
+
], _BaseEntity9));
|
|
586
|
+
}
|
|
587
|
+
static{
|
|
588
|
+
_initClass10();
|
|
1336
589
|
}
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
const collectionName = this.resolveTableName(entity, meta);
|
|
1340
|
-
return JSON.stringify({
|
|
1341
|
-
action: 'dropCollection',
|
|
1342
|
-
name: collectionName
|
|
1343
|
-
});
|
|
1344
|
-
}
|
|
1345
|
-
generateAlterTable(diff) {
|
|
1346
|
-
const statements = [];
|
|
1347
|
-
if (diff.indexesToAdd?.length) {
|
|
1348
|
-
for (const index of diff.indexesToAdd){
|
|
1349
|
-
statements.push(this.generateCreateIndex(diff.tableName, index));
|
|
1350
|
-
}
|
|
1351
|
-
}
|
|
1352
|
-
return statements;
|
|
1353
|
-
}
|
|
1354
|
-
generateAlterTableDown(diff) {
|
|
1355
|
-
const statements = [];
|
|
1356
|
-
if (diff.indexesToAdd?.length) {
|
|
1357
|
-
for (const index of diff.indexesToAdd){
|
|
1358
|
-
statements.push(this.generateDropIndex(diff.tableName, index.name));
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
return statements;
|
|
1362
|
-
}
|
|
1363
|
-
generateCreateIndex(tableName, index) {
|
|
1364
|
-
const key = {};
|
|
1365
|
-
for (const col of index.columns){
|
|
1366
|
-
key[col] = 1;
|
|
1367
|
-
}
|
|
1368
|
-
return JSON.stringify({
|
|
1369
|
-
action: 'createIndex',
|
|
1370
|
-
collection: tableName,
|
|
1371
|
-
name: index.name,
|
|
1372
|
-
key,
|
|
1373
|
-
options: {
|
|
1374
|
-
unique: index.unique,
|
|
1375
|
-
name: index.name
|
|
1376
|
-
}
|
|
1377
|
-
});
|
|
590
|
+
constructor(...args){
|
|
591
|
+
super(...args), this.name = _init_name9(this), this.description = _init_description5(this), this.code = _init_code(this), this.buyLedgerAccountId = _init_buyLedgerAccountId(this), this.buyLedgerAccount = _init_buyLedgerAccount(this), this.saleLedgerAccountId = _init_saleLedgerAccountId(this), this.saleLedgerAccount = _init_saleLedgerAccount(this), this.taxId = _init_taxId(this), this.tax = _init_tax(this), this.measureUnitId = _init_measureUnitId(this), this.measureUnit = _init_measureUnit(this), this.salePrice = _init_salePrice(this), this.inventoryable = _init_inventoryable(this), this.tags = _init_tags(this), this.tagsCount = _init_tagsCount(this);
|
|
1378
592
|
}
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
593
|
+
}
|
|
594
|
+
let _Tag;
|
|
595
|
+
_dec67 = Entity(), _dec68 = Field(), _dec69 = ManyToMany({
|
|
596
|
+
entity: ()=>_Item,
|
|
597
|
+
mappedBy: (item)=>item.tags
|
|
598
|
+
}), _dec70 = Field({
|
|
599
|
+
virtual: raw(({ ctx, escapedPrefix, dialect })=>{
|
|
600
|
+
ctx.append('(');
|
|
601
|
+
dialect.count(ctx, _ItemTag, {
|
|
602
|
+
$where: {
|
|
603
|
+
tagId: raw(({ ctx })=>{
|
|
604
|
+
ctx.append(escapedPrefix + dialect.escapeId('id'));
|
|
605
|
+
})
|
|
606
|
+
}
|
|
607
|
+
}, {
|
|
608
|
+
autoPrefix: true
|
|
1384
609
|
});
|
|
610
|
+
ctx.append(')');
|
|
611
|
+
})
|
|
612
|
+
});
|
|
613
|
+
class Tag extends (_BaseEntity10 = BaseEntity) {
|
|
614
|
+
static{
|
|
615
|
+
({ e: [_init_name10, _init_items, _init_itemsCount], c: [_Tag, _initClass11] } = _apply_decs_2203_r(this, [
|
|
616
|
+
[
|
|
617
|
+
_dec68,
|
|
618
|
+
0,
|
|
619
|
+
"name"
|
|
620
|
+
],
|
|
621
|
+
[
|
|
622
|
+
_dec69,
|
|
623
|
+
0,
|
|
624
|
+
"items"
|
|
625
|
+
],
|
|
626
|
+
[
|
|
627
|
+
_dec70,
|
|
628
|
+
0,
|
|
629
|
+
"itemsCount"
|
|
630
|
+
]
|
|
631
|
+
], [
|
|
632
|
+
_dec67
|
|
633
|
+
], _BaseEntity10));
|
|
634
|
+
}
|
|
635
|
+
static{
|
|
636
|
+
_initClass11();
|
|
1385
637
|
}
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
}
|
|
1389
|
-
diffSchema(entity, currentSchema) {
|
|
1390
|
-
const meta = getMeta(entity);
|
|
1391
|
-
const collectionName = this.resolveTableName(entity, meta);
|
|
1392
|
-
if (!currentSchema) {
|
|
1393
|
-
return {
|
|
1394
|
-
tableName: collectionName,
|
|
1395
|
-
type: 'create'
|
|
1396
|
-
};
|
|
1397
|
-
}
|
|
1398
|
-
const indexesToAdd = [];
|
|
1399
|
-
const existingIndexes = new Set(currentSchema.indexes?.map((i)=>i.name) ?? []);
|
|
1400
|
-
for(const key in meta.fields){
|
|
1401
|
-
const field = meta.fields[key];
|
|
1402
|
-
if (field.index) {
|
|
1403
|
-
const columnName = this.resolveColumnName(key, field);
|
|
1404
|
-
const indexName = typeof field.index === 'string' ? field.index : `idx_${collectionName}_${columnName}`;
|
|
1405
|
-
if (!existingIndexes.has(indexName)) {
|
|
1406
|
-
indexesToAdd.push({
|
|
1407
|
-
name: indexName,
|
|
1408
|
-
columns: [
|
|
1409
|
-
columnName
|
|
1410
|
-
],
|
|
1411
|
-
unique: !!field.unique
|
|
1412
|
-
});
|
|
1413
|
-
}
|
|
1414
|
-
}
|
|
1415
|
-
}
|
|
1416
|
-
if (indexesToAdd.length === 0) {
|
|
1417
|
-
return undefined;
|
|
1418
|
-
}
|
|
1419
|
-
return {
|
|
1420
|
-
tableName: collectionName,
|
|
1421
|
-
type: 'alter',
|
|
1422
|
-
indexesToAdd
|
|
1423
|
-
};
|
|
638
|
+
constructor(...args){
|
|
639
|
+
super(...args), this.name = _init_name10(this), this.items = _init_items(this), this.itemsCount = _init_itemsCount(this);
|
|
1424
640
|
}
|
|
1425
641
|
}
|
|
1426
|
-
|
|
1427
|
-
|
|
1428
|
-
|
|
1429
|
-
|
|
1430
|
-
|
|
1431
|
-
|
|
1432
|
-
|
|
1433
|
-
|
|
1434
|
-
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
return collections.map((c)=>c.name);
|
|
1462
|
-
} finally{
|
|
1463
|
-
await querier.release();
|
|
1464
|
-
}
|
|
1465
|
-
}
|
|
1466
|
-
async tableExists(tableName) {
|
|
1467
|
-
const names = await this.getTableNames();
|
|
1468
|
-
return names.includes(tableName);
|
|
642
|
+
let _ItemTag;
|
|
643
|
+
_dec71 = Entity(), _dec72 = Id(), _dec73 = Field({
|
|
644
|
+
reference: ()=>_Item
|
|
645
|
+
}), _dec74 = Field({
|
|
646
|
+
reference: ()=>_Tag
|
|
647
|
+
});
|
|
648
|
+
class ItemTag {
|
|
649
|
+
static{
|
|
650
|
+
({ e: [_init_id2, _init_itemId, _init_tagId], c: [_ItemTag, _initClass12] } = _apply_decs_2203_r(this, [
|
|
651
|
+
[
|
|
652
|
+
_dec72,
|
|
653
|
+
0,
|
|
654
|
+
"id"
|
|
655
|
+
],
|
|
656
|
+
[
|
|
657
|
+
_dec73,
|
|
658
|
+
0,
|
|
659
|
+
"itemId"
|
|
660
|
+
],
|
|
661
|
+
[
|
|
662
|
+
_dec74,
|
|
663
|
+
0,
|
|
664
|
+
"tagId"
|
|
665
|
+
]
|
|
666
|
+
], [
|
|
667
|
+
_dec71
|
|
668
|
+
]));
|
|
669
|
+
}
|
|
670
|
+
static{
|
|
671
|
+
_initClass12();
|
|
672
|
+
}
|
|
673
|
+
constructor(){
|
|
674
|
+
this.id = _init_id2(this);
|
|
675
|
+
this.itemId = _init_itemId(this);
|
|
676
|
+
this.tagId = _init_tagId(this);
|
|
1469
677
|
}
|
|
1470
678
|
}
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1478
|
-
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
679
|
+
let _InventoryAdjustment;
|
|
680
|
+
_dec75 = Entity(), _dec76 = OneToMany({
|
|
681
|
+
entity: ()=>_ItemAdjustment,
|
|
682
|
+
mappedBy: (rel)=>rel.inventoryAdjustment,
|
|
683
|
+
cascade: true
|
|
684
|
+
}), _dec77 = Field(), _dec78 = Field();
|
|
685
|
+
class InventoryAdjustment extends (_BaseEntity11 = BaseEntity) {
|
|
686
|
+
static{
|
|
687
|
+
({ e: [_init_itemAdjustments, _init_date, _init_description6], c: [_InventoryAdjustment, _initClass13] } = _apply_decs_2203_r(this, [
|
|
688
|
+
[
|
|
689
|
+
_dec76,
|
|
690
|
+
0,
|
|
691
|
+
"itemAdjustments"
|
|
692
|
+
],
|
|
693
|
+
[
|
|
694
|
+
_dec77,
|
|
695
|
+
0,
|
|
696
|
+
"date"
|
|
697
|
+
],
|
|
698
|
+
[
|
|
699
|
+
_dec78,
|
|
700
|
+
0,
|
|
701
|
+
"description"
|
|
702
|
+
]
|
|
703
|
+
], [
|
|
704
|
+
_dec75
|
|
705
|
+
], _BaseEntity11));
|
|
706
|
+
}
|
|
707
|
+
static{
|
|
708
|
+
_initClass13();
|
|
1496
709
|
}
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
const sql = `
|
|
1500
|
-
CREATE TABLE IF NOT EXISTS ${escapeId(this.tableName)} (
|
|
1501
|
-
${escapeId('name')} VARCHAR(255) PRIMARY KEY,
|
|
1502
|
-
${escapeId('executed_at')} TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
1503
|
-
)
|
|
1504
|
-
`;
|
|
1505
|
-
await querier.run(sql);
|
|
1506
|
-
}
|
|
1507
|
-
async executed() {
|
|
1508
|
-
await this.ensureStorage();
|
|
1509
|
-
const querier = await this.pool.getQuerier();
|
|
1510
|
-
if (!isSqlQuerier(querier)) {
|
|
1511
|
-
await querier.release();
|
|
1512
|
-
throw new Error('DatabaseMigrationStorage requires a SQL-based querier');
|
|
1513
|
-
}
|
|
1514
|
-
try {
|
|
1515
|
-
const { escapeId } = querier.dialect;
|
|
1516
|
-
const sql = `SELECT ${escapeId('name')} FROM ${escapeId(this.tableName)} ORDER BY ${escapeId('name')} ASC`;
|
|
1517
|
-
const results = await querier.all(sql);
|
|
1518
|
-
return results.map((r)=>r.name);
|
|
1519
|
-
} finally{
|
|
1520
|
-
await querier.release();
|
|
1521
|
-
}
|
|
710
|
+
constructor(...args){
|
|
711
|
+
super(...args), this.itemAdjustments = _init_itemAdjustments(this), this.date = _init_date(this), this.description = _init_description6(this);
|
|
1522
712
|
}
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
713
|
+
}
|
|
714
|
+
let _ItemAdjustment;
|
|
715
|
+
_dec79 = Entity(), _dec80 = Field({
|
|
716
|
+
reference: ()=>_Item
|
|
717
|
+
}), _dec81 = ManyToOne(), _dec82 = Field(), _dec83 = Field(), _dec84 = Field({
|
|
718
|
+
reference: ()=>_Storehouse
|
|
719
|
+
}), _dec85 = ManyToOne(), _dec86 = Field({
|
|
720
|
+
reference: ()=>_InventoryAdjustment
|
|
721
|
+
}), _dec87 = ManyToOne();
|
|
722
|
+
class ItemAdjustment extends (_BaseEntity12 = BaseEntity) {
|
|
723
|
+
static{
|
|
724
|
+
({ e: [_init_itemId1, _init_item, _init_number, _init_buyPrice, _init_storehouseId, _init_storehouse, _init_inventoryAdjustmentId, _init_inventoryAdjustment], c: [_ItemAdjustment, _initClass14] } = _apply_decs_2203_r(this, [
|
|
725
|
+
[
|
|
726
|
+
_dec80,
|
|
727
|
+
0,
|
|
728
|
+
"itemId"
|
|
729
|
+
],
|
|
730
|
+
[
|
|
731
|
+
_dec81,
|
|
732
|
+
0,
|
|
733
|
+
"item"
|
|
734
|
+
],
|
|
735
|
+
[
|
|
736
|
+
_dec82,
|
|
737
|
+
0,
|
|
738
|
+
"number"
|
|
739
|
+
],
|
|
740
|
+
[
|
|
741
|
+
_dec83,
|
|
742
|
+
0,
|
|
743
|
+
"buyPrice"
|
|
744
|
+
],
|
|
745
|
+
[
|
|
746
|
+
_dec84,
|
|
747
|
+
0,
|
|
748
|
+
"storehouseId"
|
|
749
|
+
],
|
|
750
|
+
[
|
|
751
|
+
_dec85,
|
|
752
|
+
0,
|
|
753
|
+
"storehouse"
|
|
754
|
+
],
|
|
755
|
+
[
|
|
756
|
+
_dec86,
|
|
757
|
+
0,
|
|
758
|
+
"inventoryAdjustmentId"
|
|
759
|
+
],
|
|
760
|
+
[
|
|
761
|
+
_dec87,
|
|
762
|
+
0,
|
|
763
|
+
"inventoryAdjustment"
|
|
764
|
+
]
|
|
765
|
+
], [
|
|
766
|
+
_dec79
|
|
767
|
+
], _BaseEntity12));
|
|
768
|
+
}
|
|
769
|
+
static{
|
|
770
|
+
_initClass14();
|
|
1532
771
|
}
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
*/ async unlogWithQuerier(querier, migrationName) {
|
|
1536
|
-
await this.ensureStorage();
|
|
1537
|
-
const { escapeId, placeholder } = querier.dialect;
|
|
1538
|
-
const sql = `DELETE FROM ${escapeId(this.tableName)} WHERE ${escapeId('name')} = ${placeholder(1)}`;
|
|
1539
|
-
await querier.run(sql, [
|
|
1540
|
-
migrationName
|
|
1541
|
-
]);
|
|
772
|
+
constructor(...args){
|
|
773
|
+
super(...args), this.itemId = _init_itemId1(this), this.item = _init_item(this), this.number = _init_number(this), this.buyPrice = _init_buyPrice(this), this.storehouseId = _init_storehouseId(this), this.storehouse = _init_storehouse(this), this.inventoryAdjustmentId = _init_inventoryAdjustmentId(this), this.inventoryAdjustment = _init_inventoryAdjustment(this);
|
|
1542
774
|
}
|
|
1543
775
|
}
|
|
1544
776
|
|
|
1545
|
-
|
|
1546
|
-
|
|
1547
|
-
|
|
1548
|
-
|
|
1549
|
-
|
|
1550
|
-
|
|
1551
|
-
|
|
1552
|
-
|
|
1553
|
-
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1560
|
-
|
|
1561
|
-
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
|
|
1565
|
-
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1572
|
-
|
|
1573
|
-
|
|
1574
|
-
|
|
1575
|
-
|
|
1576
|
-
return new MongoSchemaIntrospector(this.pool);
|
|
1577
|
-
default:
|
|
1578
|
-
return undefined;
|
|
1579
|
-
}
|
|
1580
|
-
}
|
|
1581
|
-
createGenerator(namingStrategy) {
|
|
1582
|
-
switch(this.dialect){
|
|
1583
|
-
case 'postgres':
|
|
1584
|
-
return new PostgresSchemaGenerator(namingStrategy);
|
|
1585
|
-
case 'mysql':
|
|
1586
|
-
return new MysqlSchemaGenerator(namingStrategy);
|
|
1587
|
-
case 'mariadb':
|
|
1588
|
-
return new MysqlSchemaGenerator(namingStrategy);
|
|
1589
|
-
case 'sqlite':
|
|
1590
|
-
return new SqliteSchemaGenerator(namingStrategy);
|
|
1591
|
-
case 'mongodb':
|
|
1592
|
-
return new MongoSchemaGenerator(namingStrategy);
|
|
1593
|
-
default:
|
|
1594
|
-
return undefined;
|
|
1595
|
-
}
|
|
1596
|
-
}
|
|
1597
|
-
/**
|
|
1598
|
-
* Get the SQL dialect
|
|
1599
|
-
*/ getDialect() {
|
|
1600
|
-
return this.dialect;
|
|
1601
|
-
}
|
|
1602
|
-
/**
|
|
1603
|
-
* Get all discovered migrations from the migrations directory
|
|
1604
|
-
*/ async getMigrations() {
|
|
1605
|
-
const files = await this.getMigrationFiles();
|
|
1606
|
-
const migrations = [];
|
|
1607
|
-
for (const file of files){
|
|
1608
|
-
const migration = await this.loadMigration(file);
|
|
1609
|
-
if (migration) {
|
|
1610
|
-
migrations.push(migration);
|
|
1611
|
-
}
|
|
1612
|
-
}
|
|
1613
|
-
// Sort by name (which typically includes timestamp)
|
|
1614
|
-
return migrations.sort((a, b)=>a.name.localeCompare(b.name));
|
|
1615
|
-
}
|
|
1616
|
-
/**
|
|
1617
|
-
* Get list of pending migrations (not yet executed)
|
|
1618
|
-
*/ async pending() {
|
|
1619
|
-
const [migrations, executed] = await Promise.all([
|
|
1620
|
-
this.getMigrations(),
|
|
1621
|
-
this.storage.executed()
|
|
1622
|
-
]);
|
|
1623
|
-
const executedSet = new Set(executed);
|
|
1624
|
-
return migrations.filter((m)=>!executedSet.has(m.name));
|
|
1625
|
-
}
|
|
1626
|
-
/**
|
|
1627
|
-
* Get list of executed migrations
|
|
1628
|
-
*/ async executed() {
|
|
1629
|
-
return this.storage.executed();
|
|
1630
|
-
}
|
|
1631
|
-
/**
|
|
1632
|
-
* Run all pending migrations
|
|
1633
|
-
*/ async up(options = {}) {
|
|
1634
|
-
const pendingMigrations = await this.pending();
|
|
1635
|
-
const results = [];
|
|
1636
|
-
let migrationsToRun = pendingMigrations;
|
|
1637
|
-
if (options.to) {
|
|
1638
|
-
const toIndex = migrationsToRun.findIndex((m)=>m.name === options.to);
|
|
1639
|
-
if (toIndex === -1) {
|
|
1640
|
-
throw new Error(`Migration '${options.to}' not found`);
|
|
1641
|
-
}
|
|
1642
|
-
migrationsToRun = migrationsToRun.slice(0, toIndex + 1);
|
|
1643
|
-
}
|
|
1644
|
-
if (options.step !== undefined) {
|
|
1645
|
-
migrationsToRun = migrationsToRun.slice(0, options.step);
|
|
1646
|
-
}
|
|
1647
|
-
for (const migration of migrationsToRun){
|
|
1648
|
-
const result = await this.runMigration(migration, 'up');
|
|
1649
|
-
results.push(result);
|
|
1650
|
-
if (!result.success) {
|
|
1651
|
-
break; // Stop on first failure
|
|
1652
|
-
}
|
|
1653
|
-
}
|
|
1654
|
-
return results;
|
|
1655
|
-
}
|
|
1656
|
-
/**
|
|
1657
|
-
* Rollback migrations
|
|
1658
|
-
*/ async down(options = {}) {
|
|
1659
|
-
const [migrations, executed] = await Promise.all([
|
|
1660
|
-
this.getMigrations(),
|
|
1661
|
-
this.storage.executed()
|
|
1662
|
-
]);
|
|
1663
|
-
const executedSet = new Set(executed);
|
|
1664
|
-
const executedMigrations = migrations.filter((m)=>executedSet.has(m.name)).reverse(); // Rollback in reverse order
|
|
1665
|
-
const results = [];
|
|
1666
|
-
let migrationsToRun = executedMigrations;
|
|
1667
|
-
if (options.to) {
|
|
1668
|
-
const toIndex = migrationsToRun.findIndex((m)=>m.name === options.to);
|
|
1669
|
-
if (toIndex === -1) {
|
|
1670
|
-
throw new Error(`Migration '${options.to}' not found`);
|
|
1671
|
-
}
|
|
1672
|
-
migrationsToRun = migrationsToRun.slice(0, toIndex + 1);
|
|
1673
|
-
}
|
|
1674
|
-
if (options.step !== undefined) {
|
|
1675
|
-
migrationsToRun = migrationsToRun.slice(0, options.step);
|
|
1676
|
-
}
|
|
1677
|
-
for (const migration of migrationsToRun){
|
|
1678
|
-
const result = await this.runMigration(migration, 'down');
|
|
1679
|
-
results.push(result);
|
|
1680
|
-
if (!result.success) {
|
|
1681
|
-
break; // Stop on first failure
|
|
1682
|
-
}
|
|
1683
|
-
}
|
|
1684
|
-
return results;
|
|
1685
|
-
}
|
|
1686
|
-
/**
|
|
1687
|
-
* Run a single migration within a transaction
|
|
1688
|
-
*/ async runMigration(migration, direction) {
|
|
1689
|
-
const startTime = Date.now();
|
|
1690
|
-
const querier = await this.pool.getQuerier();
|
|
1691
|
-
if (!isSqlQuerier(querier)) {
|
|
1692
|
-
await querier.release();
|
|
1693
|
-
throw new Error('Migrator requires a SQL-based querier');
|
|
1694
|
-
}
|
|
1695
|
-
try {
|
|
1696
|
-
this.logger(`${direction === 'up' ? 'Running' : 'Reverting'} migration: ${migration.name}`);
|
|
1697
|
-
await querier.beginTransaction();
|
|
1698
|
-
if (direction === 'up') {
|
|
1699
|
-
await migration.up(querier);
|
|
1700
|
-
// Log within the same transaction
|
|
1701
|
-
await this.storage.logWithQuerier(querier, migration.name);
|
|
1702
|
-
} else {
|
|
1703
|
-
await migration.down(querier);
|
|
1704
|
-
// Unlog within the same transaction
|
|
1705
|
-
await this.storage.unlogWithQuerier(querier, migration.name);
|
|
1706
|
-
}
|
|
1707
|
-
await querier.commitTransaction();
|
|
1708
|
-
const duration = Date.now() - startTime;
|
|
1709
|
-
this.logger(`Migration ${migration.name} ${direction === 'up' ? 'applied' : 'reverted'} in ${duration}ms`);
|
|
1710
|
-
return {
|
|
1711
|
-
name: migration.name,
|
|
1712
|
-
direction,
|
|
1713
|
-
duration,
|
|
1714
|
-
success: true
|
|
1715
|
-
};
|
|
1716
|
-
} catch (error) {
|
|
1717
|
-
await querier.rollbackTransaction();
|
|
1718
|
-
const duration = Date.now() - startTime;
|
|
1719
|
-
this.logger(`Migration ${migration.name} failed: ${error.message}`);
|
|
1720
|
-
return {
|
|
1721
|
-
name: migration.name,
|
|
1722
|
-
direction,
|
|
1723
|
-
duration,
|
|
1724
|
-
success: false,
|
|
1725
|
-
error: error
|
|
1726
|
-
};
|
|
1727
|
-
} finally{
|
|
1728
|
-
await querier.release();
|
|
1729
|
-
}
|
|
777
|
+
const holder = globalThis;
|
|
778
|
+
const metaKey = '@uql/core/entity/decorator';
|
|
779
|
+
const metas = holder[metaKey] ?? new Map();
|
|
780
|
+
holder[metaKey] = metas;
|
|
781
|
+
function getEntities() {
|
|
782
|
+
return [
|
|
783
|
+
...metas.entries()
|
|
784
|
+
].reduce((acc, [key, val])=>{
|
|
785
|
+
if (val.id) {
|
|
786
|
+
acc.push(key);
|
|
787
|
+
}
|
|
788
|
+
return acc;
|
|
789
|
+
}, []);
|
|
790
|
+
}
|
|
791
|
+
function ensureMeta(entity) {
|
|
792
|
+
let meta = metas.get(entity);
|
|
793
|
+
if (meta) {
|
|
794
|
+
return meta;
|
|
795
|
+
}
|
|
796
|
+
meta = {
|
|
797
|
+
entity,
|
|
798
|
+
fields: {},
|
|
799
|
+
relations: {}
|
|
800
|
+
};
|
|
801
|
+
metas.set(entity, meta);
|
|
802
|
+
return meta;
|
|
803
|
+
}
|
|
804
|
+
function getMeta(entity) {
|
|
805
|
+
const meta = metas.get(entity);
|
|
806
|
+
if (!meta) {
|
|
807
|
+
throw TypeError(`'${entity.name}' is not an entity`);
|
|
1730
808
|
}
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
*/ async generate(name) {
|
|
1734
|
-
const timestamp = this.getTimestamp();
|
|
1735
|
-
const fileName = `${timestamp}_${this.slugify(name)}.ts`;
|
|
1736
|
-
const filePath = join(this.migrationsPath, fileName);
|
|
1737
|
-
const content = this.generateMigrationContent(name);
|
|
1738
|
-
const { writeFile, mkdir } = await import('node:fs/promises');
|
|
1739
|
-
await mkdir(this.migrationsPath, {
|
|
1740
|
-
recursive: true
|
|
1741
|
-
});
|
|
1742
|
-
await writeFile(filePath, content, 'utf-8');
|
|
1743
|
-
this.logger(`Created migration: ${filePath}`);
|
|
1744
|
-
return filePath;
|
|
809
|
+
if (meta.processed) {
|
|
810
|
+
return meta;
|
|
1745
811
|
}
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
812
|
+
meta.processed = true;
|
|
813
|
+
return fillRelations(meta);
|
|
814
|
+
}
|
|
815
|
+
function fillRelations(meta) {
|
|
816
|
+
for(const relKey in meta.relations){
|
|
817
|
+
const relOpts = meta.relations[relKey];
|
|
818
|
+
if (relOpts.references) {
|
|
819
|
+
continue;
|
|
820
|
+
}
|
|
821
|
+
if (relOpts.mappedBy) {
|
|
822
|
+
fillInverseSideRelations(relOpts);
|
|
823
|
+
continue;
|
|
824
|
+
}
|
|
825
|
+
const relEntity = relOpts.entity();
|
|
826
|
+
const relMeta = ensureMeta(relEntity);
|
|
827
|
+
if (relOpts.cardinality === 'mm') {
|
|
828
|
+
const idName = meta.fields[meta.id].name;
|
|
829
|
+
const relIdName = relMeta.fields[relMeta.id].name;
|
|
830
|
+
const source = lowerFirst(meta.name) + upperFirst(idName);
|
|
831
|
+
const target = lowerFirst(relMeta.name) + upperFirst(relIdName);
|
|
832
|
+
relOpts.references = [
|
|
833
|
+
{
|
|
834
|
+
local: source,
|
|
835
|
+
foreign: meta.id
|
|
836
|
+
},
|
|
837
|
+
{
|
|
838
|
+
local: target,
|
|
839
|
+
foreign: relMeta.id
|
|
1761
840
|
}
|
|
1762
|
-
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
}
|
|
1769
|
-
if (upStatements.length === 0) {
|
|
1770
|
-
this.logger('No schema changes detected.');
|
|
1771
|
-
return '';
|
|
1772
|
-
}
|
|
1773
|
-
const timestamp = this.getTimestamp();
|
|
1774
|
-
const fileName = `${timestamp}_${this.slugify(name)}.ts`;
|
|
1775
|
-
const filePath = join(this.migrationsPath, fileName);
|
|
1776
|
-
const content = this.generateMigrationContentWithStatements(name, upStatements, downStatements.reverse());
|
|
1777
|
-
const { writeFile, mkdir } = await import('node:fs/promises');
|
|
1778
|
-
await mkdir(this.migrationsPath, {
|
|
1779
|
-
recursive: true
|
|
1780
|
-
});
|
|
1781
|
-
await writeFile(filePath, content, 'utf-8');
|
|
1782
|
-
this.logger(`Created migration from entities: ${filePath}`);
|
|
1783
|
-
return filePath;
|
|
1784
|
-
}
|
|
1785
|
-
/**
|
|
1786
|
-
* Get all schema differences between entities and database
|
|
1787
|
-
*/ async getDiffs() {
|
|
1788
|
-
if (!this.schemaGenerator || !this.schemaIntrospector) {
|
|
1789
|
-
throw new Error('Schema generator and introspector must be set');
|
|
1790
|
-
}
|
|
1791
|
-
const entities = this.entities.length > 0 ? this.entities : getEntities();
|
|
1792
|
-
const diffs = [];
|
|
1793
|
-
for (const entity of entities){
|
|
1794
|
-
const meta = getMeta(entity);
|
|
1795
|
-
const tableName = this.schemaGenerator.resolveTableName(entity, meta);
|
|
1796
|
-
const currentSchema = await this.schemaIntrospector.getTableSchema(tableName);
|
|
1797
|
-
const diff = this.schemaGenerator.diffSchema(entity, currentSchema);
|
|
1798
|
-
if (diff) {
|
|
1799
|
-
diffs.push(diff);
|
|
1800
|
-
}
|
|
1801
|
-
}
|
|
1802
|
-
return diffs;
|
|
1803
|
-
}
|
|
1804
|
-
findEntityForTable(tableName) {
|
|
1805
|
-
const entities = this.entities.length > 0 ? this.entities : getEntities();
|
|
1806
|
-
for (const entity of entities){
|
|
1807
|
-
const meta = getMeta(entity);
|
|
1808
|
-
const name = this.schemaGenerator.resolveTableName(entity, meta);
|
|
1809
|
-
if (name === tableName) {
|
|
1810
|
-
return entity;
|
|
1811
|
-
}
|
|
1812
|
-
}
|
|
1813
|
-
return undefined;
|
|
1814
|
-
}
|
|
1815
|
-
/**
|
|
1816
|
-
* Sync schema directly (for development only - not for production!)
|
|
1817
|
-
*/ async sync(options = {}) {
|
|
1818
|
-
if (options.force) {
|
|
1819
|
-
return this.syncForce();
|
|
1820
|
-
}
|
|
1821
|
-
return this.autoSync({
|
|
1822
|
-
safe: true
|
|
1823
|
-
});
|
|
1824
|
-
}
|
|
1825
|
-
/**
|
|
1826
|
-
* Drops and recreates all tables (Development only!)
|
|
1827
|
-
*/ async syncForce() {
|
|
1828
|
-
if (!this.schemaGenerator) {
|
|
1829
|
-
throw new Error('Schema generator not set. Call setSchemaGenerator() first.');
|
|
1830
|
-
}
|
|
1831
|
-
const entities = this.entities.length > 0 ? this.entities : getEntities();
|
|
1832
|
-
const querier = await this.pool.getQuerier();
|
|
1833
|
-
if (!isSqlQuerier(querier)) {
|
|
1834
|
-
await querier.release();
|
|
1835
|
-
throw new Error('Migrator requires a SQL-based querier');
|
|
1836
|
-
}
|
|
1837
|
-
try {
|
|
1838
|
-
await querier.beginTransaction();
|
|
1839
|
-
// Drop all tables first (in reverse order for foreign keys)
|
|
1840
|
-
for (const entity of [
|
|
1841
|
-
...entities
|
|
1842
|
-
].reverse()){
|
|
1843
|
-
const dropSql = this.schemaGenerator.generateDropTable(entity);
|
|
1844
|
-
this.logger(`Executing: ${dropSql}`);
|
|
1845
|
-
await querier.run(dropSql);
|
|
1846
|
-
}
|
|
1847
|
-
// Create all tables
|
|
1848
|
-
for (const entity of entities){
|
|
1849
|
-
const createSql = this.schemaGenerator.generateCreateTable(entity);
|
|
1850
|
-
this.logger(`Executing: ${createSql}`);
|
|
1851
|
-
await querier.run(createSql);
|
|
1852
|
-
}
|
|
1853
|
-
await querier.commitTransaction();
|
|
1854
|
-
this.logger('Schema sync (force) completed');
|
|
1855
|
-
} catch (error) {
|
|
1856
|
-
await querier.rollbackTransaction();
|
|
1857
|
-
throw error;
|
|
1858
|
-
} finally{
|
|
1859
|
-
await querier.release();
|
|
1860
|
-
}
|
|
1861
|
-
}
|
|
1862
|
-
/**
|
|
1863
|
-
* Safely synchronizes the schema by only adding missing tables and columns.
|
|
1864
|
-
*/ async autoSync(options = {}) {
|
|
1865
|
-
if (!this.schemaGenerator || !this.schemaIntrospector) {
|
|
1866
|
-
throw new Error('Schema generator and introspector must be set');
|
|
1867
|
-
}
|
|
1868
|
-
const diffs = await this.getDiffs();
|
|
1869
|
-
const statements = [];
|
|
1870
|
-
for (const diff of diffs){
|
|
1871
|
-
if (diff.type === 'create') {
|
|
1872
|
-
const entity = this.findEntityForTable(diff.tableName);
|
|
1873
|
-
if (entity) {
|
|
1874
|
-
statements.push(this.schemaGenerator.generateCreateTable(entity));
|
|
841
|
+
];
|
|
842
|
+
} else {
|
|
843
|
+
relOpts.references = [
|
|
844
|
+
{
|
|
845
|
+
local: `${relKey}Id`,
|
|
846
|
+
foreign: relMeta.id
|
|
1875
847
|
}
|
|
1876
|
-
|
|
1877
|
-
const filteredDiff = this.filterDiff(diff, options);
|
|
1878
|
-
const alterStatements = this.schemaGenerator.generateAlterTable(filteredDiff);
|
|
1879
|
-
statements.push(...alterStatements);
|
|
1880
|
-
}
|
|
1881
|
-
}
|
|
1882
|
-
if (statements.length === 0) {
|
|
1883
|
-
if (options.logging) this.logger('Schema is already in sync.');
|
|
1884
|
-
return;
|
|
848
|
+
];
|
|
1885
849
|
}
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
filterDiff(diff, options) {
|
|
1889
|
-
const filteredDiff = {
|
|
1890
|
-
...diff
|
|
1891
|
-
};
|
|
1892
|
-
if (options.safe !== false) {
|
|
1893
|
-
// In safe mode, we only allow additions
|
|
1894
|
-
delete filteredDiff.columnsToDrop;
|
|
1895
|
-
delete filteredDiff.indexesToDrop;
|
|
1896
|
-
delete filteredDiff.foreignKeysToDrop;
|
|
1897
|
-
}
|
|
1898
|
-
if (!options.drop) {
|
|
1899
|
-
delete filteredDiff.columnsToDrop;
|
|
1900
|
-
}
|
|
1901
|
-
return filteredDiff;
|
|
1902
|
-
}
|
|
1903
|
-
async executeSyncStatements(statements, options) {
|
|
1904
|
-
const querier = await this.pool.getQuerier();
|
|
1905
|
-
try {
|
|
1906
|
-
if (this.dialect === 'mongodb') {
|
|
1907
|
-
await this.executeMongoSyncStatements(statements, options, querier);
|
|
1908
|
-
} else {
|
|
1909
|
-
await this.executeSqlSyncStatements(statements, options, querier);
|
|
1910
|
-
}
|
|
1911
|
-
if (options.logging) this.logger('Schema synchronization completed');
|
|
1912
|
-
} catch (error) {
|
|
1913
|
-
if (this.dialect !== 'mongodb' && isSqlQuerier(querier)) {
|
|
1914
|
-
await querier.rollbackTransaction();
|
|
1915
|
-
}
|
|
1916
|
-
throw error;
|
|
1917
|
-
} finally{
|
|
1918
|
-
await querier.release();
|
|
850
|
+
if (relOpts.through) {
|
|
851
|
+
fillThroughRelations(relOpts.through());
|
|
1919
852
|
}
|
|
1920
853
|
}
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1926
|
-
|
|
1927
|
-
|
|
1928
|
-
|
|
854
|
+
return meta;
|
|
855
|
+
}
|
|
856
|
+
function fillInverseSideRelations(relOpts) {
|
|
857
|
+
const relEntity = relOpts.entity();
|
|
858
|
+
const relMeta = getMeta(relEntity);
|
|
859
|
+
relOpts.mappedBy = getMappedByRelationKey(relOpts);
|
|
860
|
+
if (relMeta.fields[relOpts.mappedBy]) {
|
|
861
|
+
relOpts.references = [
|
|
862
|
+
{
|
|
863
|
+
local: relMeta.id,
|
|
864
|
+
foreign: relOpts.mappedBy
|
|
1929
865
|
}
|
|
1930
|
-
|
|
1931
|
-
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
1940
|
-
|
|
1941
|
-
|
|
1942
|
-
|
|
866
|
+
];
|
|
867
|
+
return;
|
|
868
|
+
}
|
|
869
|
+
const mappedByRelation = relMeta.relations[relOpts.mappedBy];
|
|
870
|
+
if (relOpts.cardinality === 'm1' || relOpts.cardinality === 'mm') {
|
|
871
|
+
relOpts.references = mappedByRelation.references.slice().reverse();
|
|
872
|
+
relOpts.through = mappedByRelation.through;
|
|
873
|
+
return;
|
|
874
|
+
}
|
|
875
|
+
relOpts.references = mappedByRelation.references.map(({ local, foreign })=>({
|
|
876
|
+
local: foreign,
|
|
877
|
+
foreign: local
|
|
878
|
+
}));
|
|
879
|
+
}
|
|
880
|
+
function fillThroughRelations(entity) {
|
|
881
|
+
const meta = ensureMeta(entity);
|
|
882
|
+
meta.relations = getKeys(meta.fields).reduce((relations, key)=>{
|
|
883
|
+
const { reference } = meta.fields[key];
|
|
884
|
+
if (reference) {
|
|
885
|
+
const relEntity = reference();
|
|
886
|
+
const relMeta = ensureMeta(relEntity);
|
|
887
|
+
const relKey = key.slice(0, -relMeta.id.length);
|
|
888
|
+
const relOpts = {
|
|
889
|
+
entity: reference,
|
|
890
|
+
cardinality: 'm1',
|
|
891
|
+
references: [
|
|
892
|
+
{
|
|
893
|
+
local: key,
|
|
894
|
+
foreign: relMeta.id
|
|
1943
895
|
}
|
|
1944
|
-
|
|
1945
|
-
}
|
|
1946
|
-
|
|
1947
|
-
} else if (cmd.action === 'createIndex') {
|
|
1948
|
-
await collection.createIndex(cmd.key, cmd.options);
|
|
1949
|
-
} else if (cmd.action === 'dropIndex') {
|
|
1950
|
-
await collection.dropIndex(cmd.name);
|
|
1951
|
-
}
|
|
1952
|
-
}
|
|
1953
|
-
}
|
|
1954
|
-
async executeSqlSyncStatements(statements, options, querier) {
|
|
1955
|
-
if (!isSqlQuerier(querier)) {
|
|
1956
|
-
throw new Error('Migrator requires a SQL-based querier for this dialect');
|
|
1957
|
-
}
|
|
1958
|
-
await querier.beginTransaction();
|
|
1959
|
-
for (const sql of statements){
|
|
1960
|
-
if (options.logging) this.logger(`Executing: ${sql}`);
|
|
1961
|
-
await querier.run(sql);
|
|
1962
|
-
}
|
|
1963
|
-
await querier.commitTransaction();
|
|
1964
|
-
}
|
|
1965
|
-
/**
|
|
1966
|
-
* Get migration status
|
|
1967
|
-
*/ async status() {
|
|
1968
|
-
const [pending, executed] = await Promise.all([
|
|
1969
|
-
this.pending().then((m)=>m.map((x)=>x.name)),
|
|
1970
|
-
this.executed()
|
|
1971
|
-
]);
|
|
1972
|
-
return {
|
|
1973
|
-
pending,
|
|
1974
|
-
executed
|
|
1975
|
-
};
|
|
1976
|
-
}
|
|
1977
|
-
/**
|
|
1978
|
-
* Get migration files from the migrations directory
|
|
1979
|
-
*/ async getMigrationFiles() {
|
|
1980
|
-
try {
|
|
1981
|
-
const files = await readdir(this.migrationsPath);
|
|
1982
|
-
return files.filter((f)=>/\.(ts|js|mjs)$/.test(f)).filter((f)=>!f.endsWith('.d.ts')).sort();
|
|
1983
|
-
} catch (error) {
|
|
1984
|
-
if (error.code === 'ENOENT') {
|
|
1985
|
-
return [];
|
|
1986
|
-
}
|
|
1987
|
-
throw error;
|
|
1988
|
-
}
|
|
1989
|
-
}
|
|
1990
|
-
/**
|
|
1991
|
-
* Load a migration from a file
|
|
1992
|
-
*/ async loadMigration(fileName) {
|
|
1993
|
-
const filePath = join(this.migrationsPath, fileName);
|
|
1994
|
-
const fileUrl = pathToFileURL(filePath).href;
|
|
1995
|
-
try {
|
|
1996
|
-
const module = await import(fileUrl);
|
|
1997
|
-
const migration = module.default ?? module;
|
|
1998
|
-
if (this.isMigration(migration)) {
|
|
1999
|
-
return {
|
|
2000
|
-
name: this.getMigrationName(fileName),
|
|
2001
|
-
up: migration.up.bind(migration),
|
|
2002
|
-
down: migration.down.bind(migration)
|
|
2003
|
-
};
|
|
2004
|
-
}
|
|
2005
|
-
this.logger(`Warning: ${fileName} is not a valid migration`);
|
|
2006
|
-
return undefined;
|
|
2007
|
-
} catch (error) {
|
|
2008
|
-
this.logger(`Error loading migration ${fileName}: ${error.message}`);
|
|
2009
|
-
return undefined;
|
|
896
|
+
]
|
|
897
|
+
};
|
|
898
|
+
relations[relKey] = relOpts;
|
|
2010
899
|
}
|
|
2011
|
-
|
|
2012
|
-
|
|
2013
|
-
* Check if an object is a valid migration
|
|
2014
|
-
*/ isMigration(obj) {
|
|
2015
|
-
return typeof obj === 'object' && obj !== undefined && obj !== null && typeof obj.up === 'function' && typeof obj.down === 'function';
|
|
2016
|
-
}
|
|
2017
|
-
/**
|
|
2018
|
-
* Extract migration name from filename
|
|
2019
|
-
*/ getMigrationName(fileName) {
|
|
2020
|
-
return basename(fileName, extname(fileName));
|
|
2021
|
-
}
|
|
2022
|
-
/**
|
|
2023
|
-
* Generate timestamp string for migration names
|
|
2024
|
-
*/ getTimestamp() {
|
|
2025
|
-
const now = new Date();
|
|
2026
|
-
return [
|
|
2027
|
-
now.getFullYear(),
|
|
2028
|
-
String(now.getMonth() + 1).padStart(2, '0'),
|
|
2029
|
-
String(now.getDate()).padStart(2, '0'),
|
|
2030
|
-
String(now.getHours()).padStart(2, '0'),
|
|
2031
|
-
String(now.getMinutes()).padStart(2, '0'),
|
|
2032
|
-
String(now.getSeconds()).padStart(2, '0')
|
|
2033
|
-
].join('');
|
|
2034
|
-
}
|
|
2035
|
-
/**
|
|
2036
|
-
* Convert a string to a slug for filenames
|
|
2037
|
-
*/ slugify(text) {
|
|
2038
|
-
return text.toLowerCase().replace(/[^a-z0-9]+/g, '_').replace(/^_+|_+$/g, '');
|
|
2039
|
-
}
|
|
2040
|
-
/**
|
|
2041
|
-
* Generate migration file content
|
|
2042
|
-
*/ generateMigrationContent(name) {
|
|
2043
|
-
return /*ts*/ `import type { SqlQuerier } from '@uql/migrate';
|
|
2044
|
-
|
|
2045
|
-
/**
|
|
2046
|
-
* Migration: ${name}
|
|
2047
|
-
* Created: ${new Date().toISOString()}
|
|
2048
|
-
*/
|
|
2049
|
-
export default {
|
|
2050
|
-
async up(querier: SqlQuerier): Promise<void> {
|
|
2051
|
-
// Add your migration logic here
|
|
2052
|
-
// Example:
|
|
2053
|
-
// await querier.run(\`
|
|
2054
|
-
// CREATE TABLE "users" (
|
|
2055
|
-
// "id" SERIAL PRIMARY KEY,
|
|
2056
|
-
// "name" VARCHAR(255) NOT NULL,
|
|
2057
|
-
// "email" VARCHAR(255) UNIQUE NOT NULL,
|
|
2058
|
-
// "createdAt" TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
2059
|
-
// )
|
|
2060
|
-
// \`);
|
|
2061
|
-
},
|
|
2062
|
-
|
|
2063
|
-
async down(querier: SqlQuerier): Promise<void> {
|
|
2064
|
-
// Add your rollback logic here
|
|
2065
|
-
// Example:
|
|
2066
|
-
// await querier.run(\`DROP TABLE IF EXISTS "users"\`);
|
|
2067
|
-
},
|
|
2068
|
-
};
|
|
2069
|
-
`;
|
|
2070
|
-
}
|
|
2071
|
-
/**
|
|
2072
|
-
* Generate migration file content with SQL statements
|
|
2073
|
-
*/ generateMigrationContentWithStatements(name, upStatements, downStatements) {
|
|
2074
|
-
const upSql = upStatements.map((s)=>/*ts*/ ` await querier.run(\`${s}\`);`).join('\n');
|
|
2075
|
-
const downSql = downStatements.map((s)=>/*ts*/ ` await querier.run(\`${s}\`);`).join('\n');
|
|
2076
|
-
return /*ts*/ `import type { SqlQuerier } from '@uql/migrate';
|
|
2077
|
-
|
|
2078
|
-
/**
|
|
2079
|
-
* Migration: ${name}
|
|
2080
|
-
* Created: ${new Date().toISOString()}
|
|
2081
|
-
* Generated from entity definitions
|
|
2082
|
-
*/
|
|
2083
|
-
export default {
|
|
2084
|
-
async up(querier: SqlQuerier): Promise<void> {
|
|
2085
|
-
${upSql}
|
|
2086
|
-
},
|
|
2087
|
-
|
|
2088
|
-
async down(querier: SqlQuerier): Promise<void> {
|
|
2089
|
-
${downSql}
|
|
2090
|
-
},
|
|
2091
|
-
};
|
|
2092
|
-
`;
|
|
2093
|
-
}
|
|
900
|
+
return relations;
|
|
901
|
+
}, {});
|
|
2094
902
|
}
|
|
2095
|
-
|
|
2096
|
-
|
|
2097
|
-
|
|
2098
|
-
|
|
903
|
+
function getMappedByRelationKey(relOpts) {
|
|
904
|
+
if (typeof relOpts.mappedBy === 'function') {
|
|
905
|
+
const relEntity = relOpts.entity();
|
|
906
|
+
const relMeta = ensureMeta(relEntity);
|
|
907
|
+
const keyMap = getRelationKeyMap(relMeta);
|
|
908
|
+
return relOpts.mappedBy(keyMap);
|
|
909
|
+
}
|
|
910
|
+
return relOpts.mappedBy;
|
|
911
|
+
}
|
|
912
|
+
function getRelationKeyMap(meta) {
|
|
913
|
+
return getKeys(meta.fields).concat(getKeys(meta.relations)).reduce((acc, key)=>{
|
|
914
|
+
acc[key] = key;
|
|
915
|
+
return acc;
|
|
916
|
+
}, {});
|
|
2099
917
|
}
|
|
2100
918
|
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
2122
|
-
|
|
2123
|
-
|
|
2124
|
-
|
|
2125
|
-
|
|
919
|
+
async function createTables(querier, primaryKeyType) {
|
|
920
|
+
const entities = getEntities();
|
|
921
|
+
await Promise.all(entities.map((entity)=>{
|
|
922
|
+
const sql = getDdlForTable(entity, querier, primaryKeyType);
|
|
923
|
+
return querier.run(sql);
|
|
924
|
+
}));
|
|
925
|
+
}
|
|
926
|
+
async function dropTables(querier) {
|
|
927
|
+
const entities = getEntities();
|
|
928
|
+
await Promise.all(entities.map((entity)=>{
|
|
929
|
+
const meta = getMeta(entity);
|
|
930
|
+
const sql = `DROP TABLE IF EXISTS ${querier.dialect.escapeId(meta.name)}`;
|
|
931
|
+
return querier.run(sql);
|
|
932
|
+
}));
|
|
933
|
+
}
|
|
934
|
+
async function clearTables(querier) {
|
|
935
|
+
const entities = getEntities();
|
|
936
|
+
await Promise.all(entities.map((entity)=>{
|
|
937
|
+
const ctx = querier.dialect.createContext();
|
|
938
|
+
querier.dialect.delete(ctx, entity, {});
|
|
939
|
+
return querier.run(ctx.sql, ctx.values);
|
|
940
|
+
}));
|
|
941
|
+
}
|
|
942
|
+
function getDdlForTable(entity, querier, primaryKeyType) {
|
|
943
|
+
const meta = getMeta(entity);
|
|
944
|
+
let sql = `CREATE TABLE ${querier.dialect.escapeId(meta.name)} (\n\t`;
|
|
945
|
+
const insertableIdType = 'VARCHAR(36)';
|
|
946
|
+
const defaultType = 'VARCHAR(255)';
|
|
947
|
+
const columns = getKeys(meta.fields).map((key)=>{
|
|
948
|
+
const field = meta.fields[key];
|
|
949
|
+
let propSql = querier.dialect.escapeId(field.name) + ' ';
|
|
950
|
+
if (field.isId) {
|
|
951
|
+
propSql += field.onInsert ? `${insertableIdType} PRIMARY KEY` : primaryKeyType;
|
|
952
|
+
} else {
|
|
953
|
+
if (field.type === Number) {
|
|
954
|
+
propSql += 'BIGINT';
|
|
955
|
+
} else if (field.type === Date) {
|
|
956
|
+
propSql += 'TIMESTAMP';
|
|
957
|
+
} else {
|
|
958
|
+
propSql += defaultType;
|
|
959
|
+
}
|
|
2126
960
|
}
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
961
|
+
return propSql;
|
|
962
|
+
});
|
|
963
|
+
sql += columns.join(',\n\t');
|
|
964
|
+
sql += `\n);`;
|
|
965
|
+
// log('sql', sql);
|
|
966
|
+
return sql;
|
|
967
|
+
}
|
|
968
|
+
|
|
969
|
+
function createSpec(spec) {
|
|
970
|
+
const proto = Object.getPrototypeOf(spec);
|
|
971
|
+
let describeFn;
|
|
972
|
+
const specName = proto.constructor.name;
|
|
973
|
+
if (specName.startsWith('fff')) {
|
|
974
|
+
describeFn = describe.only;
|
|
975
|
+
} else if (specName.startsWith('xxx')) {
|
|
976
|
+
describeFn = describe.skip;
|
|
977
|
+
} else {
|
|
978
|
+
describeFn = describe;
|
|
979
|
+
}
|
|
980
|
+
describeFn(specName, ()=>createTestCases(spec));
|
|
981
|
+
}
|
|
982
|
+
function createTestCases(spec) {
|
|
983
|
+
let proto = Object.getPrototypeOf(spec);
|
|
984
|
+
const processedMethodsMap = {};
|
|
985
|
+
while(proto.constructor !== Object){
|
|
986
|
+
for (const key of Object.getOwnPropertyNames(proto)){
|
|
987
|
+
const isProcessed = processedMethodsMap[key];
|
|
988
|
+
processedMethodsMap[key] = true;
|
|
989
|
+
if (isProcessed || key === 'constructor' || typeof spec[key] !== 'function') {
|
|
990
|
+
continue;
|
|
991
|
+
}
|
|
992
|
+
const callback = spec[key].bind(spec);
|
|
993
|
+
if (hooks[key]) {
|
|
994
|
+
hooks[key](callback);
|
|
995
|
+
} else if (key.startsWith('should')) {
|
|
996
|
+
it(key, callback);
|
|
997
|
+
} else if (key.startsWith('fffShould')) {
|
|
998
|
+
it.only(key, callback);
|
|
999
|
+
} else if (key.startsWith('xxxShould')) {
|
|
1000
|
+
it.skip(key, callback);
|
|
1001
|
+
}
|
|
2134
1002
|
}
|
|
2135
|
-
|
|
2136
|
-
async load() {
|
|
2137
|
-
const content = await readFile(this.filePath, 'utf-8');
|
|
2138
|
-
this.cache = JSON.parse(content);
|
|
2139
|
-
}
|
|
2140
|
-
async save(migrations) {
|
|
2141
|
-
await mkdir(dirname(this.filePath), {
|
|
2142
|
-
recursive: true
|
|
2143
|
-
});
|
|
2144
|
-
await writeFile(this.filePath, JSON.stringify(migrations, null, 2), 'utf-8');
|
|
2145
|
-
this.cache = migrations;
|
|
1003
|
+
proto = Object.getPrototypeOf(proto);
|
|
2146
1004
|
}
|
|
2147
1005
|
}
|
|
1006
|
+
const hooks = {
|
|
1007
|
+
beforeAll,
|
|
1008
|
+
beforeEach,
|
|
1009
|
+
afterEach,
|
|
1010
|
+
afterAll
|
|
1011
|
+
};
|
|
2148
1012
|
|
|
2149
|
-
export {
|
|
1013
|
+
export { BaseEntity, _Company as Company, _InventoryAdjustment as InventoryAdjustment, _Item as Item, _ItemAdjustment as ItemAdjustment, _ItemTag as ItemTag, _LedgerAccount as LedgerAccount, _MeasureUnit as MeasureUnit, _MeasureUnitCategory as MeasureUnitCategory, _Profile as Profile, _Storehouse as Storehouse, _Tag as Tag, _Tax as Tax, _TaxCategory as TaxCategory, _User as User, _UserWithNonUpdatableId as UserWithNonUpdatableId, clearTables, createSpec, createTables, dropTables };
|
|
2150
1014
|
//# sourceMappingURL=uql-browser.min.js.map
|