relq 1.0.83 → 1.0.85
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cjs/cli/utils/ast-codegen.cjs +14 -3
- package/dist/cjs/cli/utils/cockroachdb/introspect.cjs +1 -1
- package/dist/cjs/cli/utils/dsql/introspect.cjs +1 -1
- package/dist/cjs/cli/utils/nile/introspect.cjs +1 -1
- package/dist/cjs/cli/utils/postgres/introspect.cjs +1 -1
- package/dist/cjs/cli/utils/schema-to-ast.cjs +1 -1
- package/dist/cjs/core/helpers/ConnectedSelectBuilder.cjs +29 -4
- package/dist/cjs/core/helpers/select-joins.cjs +11 -1
- package/dist/cjs/core/shared/column-mapping.cjs +1 -1
- package/dist/cjs/core/shared/transform.cjs +6 -2
- package/dist/cjs/schema-definition/pg-schema/column-types/column-builder.cjs +5 -5
- package/dist/cjs/schema-definition/pg-schema/column-types/custom-types.cjs +2 -2
- package/dist/cjs/schema-definition/pg-schema/column-types/domain-types.cjs +4 -4
- package/dist/cjs/schema-definition/pg-schema/pg-enum.cjs +3 -1
- package/dist/cjs/schema-definition/pg-schema/schema-builder.cjs +1 -1
- package/dist/cjs/schema-definition/pg-schema/table-definition/sql-generation.cjs +1 -1
- package/dist/cjs/schema-definition/pg-schema/validate-schema/validators.cjs +1 -1
- package/dist/cjs/schema-definition/sqlite-schema/table-definition/ast-generation.cjs +1 -1
- package/dist/cjs/schema-definition/sqlite-schema/table-definition/sql-generation.cjs +1 -1
- package/dist/cjs/schema-definition/sqlite-schema/table-definition/table-core.cjs +1 -1
- package/dist/cjs/utils/type-coercion.cjs +4 -2
- package/dist/esm/cli/utils/ast-codegen.js +14 -3
- package/dist/esm/cli/utils/cockroachdb/introspect.js +1 -1
- package/dist/esm/cli/utils/dsql/introspect.js +1 -1
- package/dist/esm/cli/utils/nile/introspect.js +1 -1
- package/dist/esm/cli/utils/postgres/introspect.js +1 -1
- package/dist/esm/cli/utils/schema-to-ast.js +1 -1
- package/dist/esm/core/helpers/ConnectedSelectBuilder.js +29 -4
- package/dist/esm/core/helpers/select-joins.js +11 -1
- package/dist/esm/core/shared/column-mapping.js +1 -1
- package/dist/esm/core/shared/transform.js +6 -2
- package/dist/esm/schema-definition/pg-schema/column-types/column-builder.js +5 -5
- package/dist/esm/schema-definition/pg-schema/column-types/custom-types.js +2 -2
- package/dist/esm/schema-definition/pg-schema/column-types/domain-types.js +4 -4
- package/dist/esm/schema-definition/pg-schema/pg-enum.js +3 -1
- package/dist/esm/schema-definition/pg-schema/schema-builder.js +1 -1
- package/dist/esm/schema-definition/pg-schema/table-definition/sql-generation.js +1 -1
- package/dist/esm/schema-definition/pg-schema/validate-schema/validators.js +1 -1
- package/dist/esm/schema-definition/sqlite-schema/table-definition/ast-generation.js +1 -1
- package/dist/esm/schema-definition/sqlite-schema/table-definition/sql-generation.js +1 -1
- package/dist/esm/schema-definition/sqlite-schema/table-definition/table-core.js +1 -1
- package/dist/esm/utils/type-coercion.js +4 -2
- package/dist/index.d.ts +6 -0
- package/package.json +1 -1
|
@@ -255,11 +255,21 @@ function generateColumnCode(col, useCamelCase, enumNames, domainNames, checkOver
|
|
|
255
255
|
const normalizedType = col.type.toLowerCase();
|
|
256
256
|
if (enumNames.has(normalizedType) || enumNames.has(col.type)) {
|
|
257
257
|
const enumName = `${(0, utils_1.toCamelCase)(col.type)}Enum`;
|
|
258
|
-
|
|
258
|
+
if (useCamelCase && colName !== col.name) {
|
|
259
|
+
line = ` ${colName}: ${enumName}('${col.name}')`;
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
line = ` ${colName}: ${enumName}()`;
|
|
263
|
+
}
|
|
259
264
|
}
|
|
260
265
|
else if (domainNames.has(normalizedType) || domainNames.has(col.type)) {
|
|
261
266
|
const domainName = `${(0, utils_1.toCamelCase)(col.type)}Domain`;
|
|
262
|
-
|
|
267
|
+
if (useCamelCase && colName !== col.name) {
|
|
268
|
+
line = ` ${colName}: ${domainName}('${col.name}')`;
|
|
269
|
+
}
|
|
270
|
+
else {
|
|
271
|
+
line = ` ${colName}: ${domainName}()`;
|
|
272
|
+
}
|
|
263
273
|
}
|
|
264
274
|
else {
|
|
265
275
|
let typeBuilder;
|
|
@@ -676,7 +686,8 @@ function generateTableCode(table, useCamelCase, enumNames, domainNames, columnTy
|
|
|
676
686
|
function generateEnumCode(enumDef, useCamelCase) {
|
|
677
687
|
const baseName = useCamelCase ? (0, utils_1.toCamelCase)(enumDef.name) : enumDef.name;
|
|
678
688
|
const enumName = `${baseName}Enum`;
|
|
679
|
-
const
|
|
689
|
+
const values = Array.isArray(enumDef.values) ? enumDef.values : typeof enumDef.values === 'string' ? enumDef.values.replace(/^\{|\}$/g, '').split(',').filter(Boolean) : [];
|
|
690
|
+
const valuesStr = values.map(v => `'${(0, utils_1.escapeString)(v)}'`).join(', ');
|
|
680
691
|
const trackingId = enumDef.trackingId || generateTrackingId('e');
|
|
681
692
|
return `export const ${enumName} = pgEnum('${enumDef.name}', [${valuesStr}]).$id('${trackingId}')`;
|
|
682
693
|
}
|
|
@@ -212,7 +212,7 @@ async function introspectCockroachDB(connection, options) {
|
|
|
212
212
|
const enums = enumsResult.rows.map(row => ({
|
|
213
213
|
name: row.enum_name,
|
|
214
214
|
schema: row.enum_schema,
|
|
215
|
-
values: row.enum_values
|
|
215
|
+
values: Array.isArray(row.enum_values) ? row.enum_values : typeof row.enum_values === 'string' ? row.enum_values.replace(/^\{|\}$/g, '').split(',').filter(Boolean) : [],
|
|
216
216
|
}));
|
|
217
217
|
onProgress?.('processing');
|
|
218
218
|
const columnsByTable = new Map();
|
|
@@ -196,7 +196,7 @@ async function introspectDsql(connection, options) {
|
|
|
196
196
|
const enums = enumsResult.rows.map(row => ({
|
|
197
197
|
name: row.enum_name,
|
|
198
198
|
schema: row.enum_schema,
|
|
199
|
-
values: row.enum_values
|
|
199
|
+
values: Array.isArray(row.enum_values) ? row.enum_values : typeof row.enum_values === 'string' ? row.enum_values.replace(/^\{|\}$/g, '').split(',').filter(Boolean) : [],
|
|
200
200
|
}));
|
|
201
201
|
onProgress?.('processing');
|
|
202
202
|
const columnsByTable = new Map();
|
|
@@ -231,7 +231,7 @@ async function introspectNile(connection, options) {
|
|
|
231
231
|
const enums = enumsResult.rows.map(row => ({
|
|
232
232
|
name: row.enum_name,
|
|
233
233
|
schema: row.enum_schema,
|
|
234
|
-
values: row.enum_values
|
|
234
|
+
values: Array.isArray(row.enum_values) ? row.enum_values : typeof row.enum_values === 'string' ? row.enum_values.replace(/^\{|\}$/g, '').split(',').filter(Boolean) : [],
|
|
235
235
|
}));
|
|
236
236
|
onProgress?.('processing');
|
|
237
237
|
const columnsByTable = new Map();
|
|
@@ -224,7 +224,7 @@ async function introspectPostgres(connection, options) {
|
|
|
224
224
|
const enums = enumsResult.rows.map(row => ({
|
|
225
225
|
name: row.enum_name,
|
|
226
226
|
schema: row.enum_schema,
|
|
227
|
-
values: row.enum_values
|
|
227
|
+
values: Array.isArray(row.enum_values) ? row.enum_values : typeof row.enum_values === 'string' ? row.enum_values.replace(/^\{|\}$/g, '').split(',').filter(Boolean) : [],
|
|
228
228
|
}));
|
|
229
229
|
onProgress?.('processing');
|
|
230
230
|
const columnsByTable = new Map();
|
|
@@ -538,7 +538,7 @@ function compositeToAST(composite) {
|
|
|
538
538
|
const config = fieldDef.$config || fieldDef;
|
|
539
539
|
attributes.push({
|
|
540
540
|
name: fieldName,
|
|
541
|
-
type: config.$type || 'text',
|
|
541
|
+
type: config.$sqlType || (typeof config.$type === 'string' ? config.$type : null) || 'text',
|
|
542
542
|
collation: config.$collation,
|
|
543
543
|
});
|
|
544
544
|
}
|
|
@@ -63,30 +63,55 @@ class ConnectedSelectBuilder {
|
|
|
63
63
|
}
|
|
64
64
|
const tableColumns = joinedTableDef.$columns || joinedTableDef;
|
|
65
65
|
const dbToProp = new Map();
|
|
66
|
+
const propTypes = new Map();
|
|
66
67
|
for (const [propName, colDef] of Object.entries(tableColumns)) {
|
|
67
68
|
const dbColName = colDef?.$columnName ?? propName;
|
|
68
69
|
dbToProp.set(dbColName, propName);
|
|
70
|
+
const snakeCase = propName.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
71
|
+
if (snakeCase !== propName && !dbToProp.has(snakeCase)) {
|
|
72
|
+
dbToProp.set(snakeCase, propName);
|
|
73
|
+
}
|
|
74
|
+
const sqlType = colDef?.$sqlType || (typeof colDef?.$type === 'string' ? colDef.$type : undefined);
|
|
75
|
+
if (sqlType) {
|
|
76
|
+
propTypes.set(propName, sqlType.toLowerCase());
|
|
77
|
+
}
|
|
69
78
|
}
|
|
70
79
|
if (Array.isArray(nestedData)) {
|
|
71
|
-
transformed[alias] = nestedData.map((item) => this.transformNestedObject(item, dbToProp));
|
|
80
|
+
transformed[alias] = nestedData.map((item) => this.transformNestedObject(item, dbToProp, propTypes));
|
|
72
81
|
}
|
|
73
82
|
else {
|
|
74
|
-
transformed[alias] = this.transformNestedObject(nestedData, dbToProp);
|
|
83
|
+
transformed[alias] = this.transformNestedObject(nestedData, dbToProp, propTypes);
|
|
75
84
|
}
|
|
76
85
|
}
|
|
77
86
|
return transformed;
|
|
78
87
|
});
|
|
79
88
|
}
|
|
80
|
-
transformNestedObject(obj, dbToProp) {
|
|
89
|
+
transformNestedObject(obj, dbToProp, propTypes) {
|
|
81
90
|
if (!obj || typeof obj !== 'object')
|
|
82
91
|
return obj;
|
|
83
92
|
const result = {};
|
|
84
93
|
for (const [key, value] of Object.entries(obj)) {
|
|
85
94
|
const propName = dbToProp.get(key) ?? key;
|
|
86
|
-
result[propName] = value;
|
|
95
|
+
result[propName] = propTypes ? this.coerceValue(value, propTypes.get(propName)) : value;
|
|
87
96
|
}
|
|
88
97
|
return result;
|
|
89
98
|
}
|
|
99
|
+
coerceValue(value, sqlType) {
|
|
100
|
+
if (value === null || value === undefined || !sqlType)
|
|
101
|
+
return value;
|
|
102
|
+
switch (sqlType) {
|
|
103
|
+
case 'timestamp':
|
|
104
|
+
case 'timestamptz':
|
|
105
|
+
case 'timestamp without time zone':
|
|
106
|
+
case 'timestamp with time zone':
|
|
107
|
+
return typeof value === 'string' ? new Date(value) : value;
|
|
108
|
+
case 'bigint':
|
|
109
|
+
case 'int8':
|
|
110
|
+
return typeof value === 'number' ? BigInt(value) : typeof value === 'string' ? BigInt(value) : value;
|
|
111
|
+
default:
|
|
112
|
+
return value;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
90
115
|
where(callback) {
|
|
91
116
|
this.builder.where(callback);
|
|
92
117
|
return this;
|
|
@@ -42,14 +42,24 @@ function executeTypeSafeJoin(ctx, joinType, tableOrAlias, callback) {
|
|
|
42
42
|
}
|
|
43
43
|
const selectedProps = conditionInternals.getSelectedColumns();
|
|
44
44
|
let selectColumns;
|
|
45
|
+
const toSnake = (s) => s.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`);
|
|
45
46
|
if (selectedProps && selectedProps.length > 0) {
|
|
46
47
|
const rightColumns = rightTableDef?.$columns || rightTableDef;
|
|
47
48
|
selectColumns = selectedProps.map(prop => {
|
|
48
49
|
const columnDef = rightColumns?.[prop];
|
|
49
|
-
const sqlName = columnDef?.$columnName || prop;
|
|
50
|
+
const sqlName = columnDef?.$columnName || toSnake(prop);
|
|
50
51
|
return { property: prop, sqlName };
|
|
51
52
|
});
|
|
52
53
|
}
|
|
54
|
+
else if (rightTableDef) {
|
|
55
|
+
const rightColumns = rightTableDef.$columns || rightTableDef;
|
|
56
|
+
selectColumns = Object.entries(rightColumns)
|
|
57
|
+
.filter(([_, colDef]) => colDef && typeof colDef === 'object' && '$type' in colDef)
|
|
58
|
+
.map(([propName, colDef]) => ({
|
|
59
|
+
property: propName,
|
|
60
|
+
sqlName: colDef.$columnName || toSnake(propName),
|
|
61
|
+
}));
|
|
62
|
+
}
|
|
53
63
|
const joinClause = {
|
|
54
64
|
type: joinType,
|
|
55
65
|
table: rightTableName,
|
|
@@ -24,7 +24,7 @@ function buildColumnMappings(schema, mappings, debugLog) {
|
|
|
24
24
|
const propToFields = new Map();
|
|
25
25
|
for (const [propName, colDef] of Object.entries(columns)) {
|
|
26
26
|
const dbColName = colDef?.$columnName ?? propName;
|
|
27
|
-
const colType = colDef?.$type
|
|
27
|
+
const colType = colDef?.$sqlType || (typeof colDef?.$type === 'string' ? colDef.$type : undefined) || 'TEXT';
|
|
28
28
|
propToDb.set(propName, dbColName);
|
|
29
29
|
dbToProp.set(dbColName, propName);
|
|
30
30
|
propToType.set(propName, colType);
|
|
@@ -23,8 +23,12 @@ function buildColumnTypeMap(tableDef) {
|
|
|
23
23
|
const typeMap = new Map();
|
|
24
24
|
const columns = tableDef.$columns || tableDef;
|
|
25
25
|
for (const [key, colDef] of Object.entries(columns)) {
|
|
26
|
-
if (colDef && typeof colDef === 'object'
|
|
27
|
-
|
|
26
|
+
if (colDef && typeof colDef === 'object') {
|
|
27
|
+
const col = colDef;
|
|
28
|
+
const sqlType = col.$sqlType || (typeof col.$type === 'string' ? col.$type : undefined);
|
|
29
|
+
if (sqlType) {
|
|
30
|
+
typeMap.set(key, sqlType);
|
|
31
|
+
}
|
|
28
32
|
}
|
|
29
33
|
}
|
|
30
34
|
return typeMap;
|
|
@@ -151,7 +151,7 @@ function createColumn(type) {
|
|
|
151
151
|
config.$length = len;
|
|
152
152
|
const baseType = config.$type.replace(/\(\d+\)/, '');
|
|
153
153
|
config.$type = `${baseType}(${len})`;
|
|
154
|
-
return Object.assign(this, { $length: len, $type: config.$type });
|
|
154
|
+
return Object.assign(this, { $length: len, $type: config.$type, $sqlType: config.$type });
|
|
155
155
|
},
|
|
156
156
|
precision(p) {
|
|
157
157
|
config.$precision = p;
|
|
@@ -159,7 +159,7 @@ function createColumn(type) {
|
|
|
159
159
|
config.$type = config.$scale !== undefined
|
|
160
160
|
? `${base}(${p}, ${config.$scale})`
|
|
161
161
|
: `${base}(${p})`;
|
|
162
|
-
return Object.assign(this, { $precision: p, $type: config.$type });
|
|
162
|
+
return Object.assign(this, { $precision: p, $type: config.$type, $sqlType: config.$type });
|
|
163
163
|
},
|
|
164
164
|
scale(s) {
|
|
165
165
|
config.$scale = s;
|
|
@@ -167,7 +167,7 @@ function createColumn(type) {
|
|
|
167
167
|
config.$type = config.$precision !== undefined
|
|
168
168
|
? `${base}(${config.$precision}, ${s})`
|
|
169
169
|
: `${base}(38, ${s})`;
|
|
170
|
-
return Object.assign(this, { $scale: s, $type: config.$type });
|
|
170
|
+
return Object.assign(this, { $scale: s, $type: config.$type, $sqlType: config.$type });
|
|
171
171
|
},
|
|
172
172
|
withTimezone() {
|
|
173
173
|
config.$withTimezone = true;
|
|
@@ -177,12 +177,12 @@ function createColumn(type) {
|
|
|
177
177
|
else if (config.$type === 'TIME') {
|
|
178
178
|
config.$type = 'TIMETZ';
|
|
179
179
|
}
|
|
180
|
-
return Object.assign(this, { $withTimezone: true, $type: config.$type });
|
|
180
|
+
return Object.assign(this, { $withTimezone: true, $type: config.$type, $sqlType: config.$type });
|
|
181
181
|
},
|
|
182
182
|
dimensions(d) {
|
|
183
183
|
config.$dimensions = d;
|
|
184
184
|
config.$type = `VECTOR(${d})`;
|
|
185
|
-
return Object.assign(this, { $dimensions: d, $type: config.$type });
|
|
185
|
+
return Object.assign(this, { $dimensions: d, $type: config.$type, $sqlType: config.$type });
|
|
186
186
|
},
|
|
187
187
|
comment(text) {
|
|
188
188
|
config.$comment = text;
|
|
@@ -15,7 +15,7 @@ function pgComposite(name, fields) {
|
|
|
15
15
|
const config = fieldConfig;
|
|
16
16
|
return {
|
|
17
17
|
name: fieldName,
|
|
18
|
-
type: config.$type,
|
|
18
|
+
type: config.$sqlType || (typeof config.$type === 'string' ? config.$type : 'TEXT'),
|
|
19
19
|
collation: undefined,
|
|
20
20
|
};
|
|
21
21
|
});
|
|
@@ -43,7 +43,7 @@ function generateCompositeTypeSQL(composite) {
|
|
|
43
43
|
const fieldDefs = [];
|
|
44
44
|
for (const [fieldName, fieldConfig] of Object.entries(composite.$fields)) {
|
|
45
45
|
const config = fieldConfig;
|
|
46
|
-
let fieldDef = `"${fieldName}" ${config.$type}`;
|
|
46
|
+
let fieldDef = `"${fieldName}" ${config.$sqlType || (typeof config.$type === 'string' ? config.$type : 'TEXT')}`;
|
|
47
47
|
if (config.$nullable === false) {
|
|
48
48
|
fieldDef += ' NOT NULL';
|
|
49
49
|
}
|
|
@@ -139,8 +139,8 @@ function createDomainValueExpr() {
|
|
|
139
139
|
};
|
|
140
140
|
}
|
|
141
141
|
function pgDomain(name, baseType, checks) {
|
|
142
|
-
const
|
|
143
|
-
const baseTypeStr =
|
|
142
|
+
const bt = baseType;
|
|
143
|
+
const baseTypeStr = bt.$sqlType || (typeof bt.$type === 'string' ? bt.$type : null) || 'TEXT';
|
|
144
144
|
const constraints = [];
|
|
145
145
|
let validateFn;
|
|
146
146
|
if (checks) {
|
|
@@ -163,8 +163,8 @@ function pgDomain(name, baseType, checks) {
|
|
|
163
163
|
}
|
|
164
164
|
}
|
|
165
165
|
}
|
|
166
|
-
const notNull =
|
|
167
|
-
const defaultValue =
|
|
166
|
+
const notNull = bt?.$nullable === false;
|
|
167
|
+
const defaultValue = bt?.$default;
|
|
168
168
|
const domainFn = (columnName) => {
|
|
169
169
|
const col = (0, column_builder_1.createColumnWithName)(name, columnName);
|
|
170
170
|
if (validateFn) {
|
|
@@ -8,6 +8,7 @@ function pgEnum(name, values) {
|
|
|
8
8
|
const config = function (columnName) {
|
|
9
9
|
const col = {
|
|
10
10
|
$type: name,
|
|
11
|
+
$sqlType: name,
|
|
11
12
|
$enumName: name,
|
|
12
13
|
$checkValues: values,
|
|
13
14
|
};
|
|
@@ -38,7 +39,8 @@ function pgEnum(name, values) {
|
|
|
38
39
|
array() {
|
|
39
40
|
col.$array = true;
|
|
40
41
|
col.$type = `${name}[]`;
|
|
41
|
-
|
|
42
|
+
col.$sqlType = `${name}[]`;
|
|
43
|
+
return Object.assign(this, { $array: true, $type: `${name}[]`, $sqlType: `${name}[]` });
|
|
42
44
|
},
|
|
43
45
|
$id(trackingId) {
|
|
44
46
|
col.$trackingId = trackingId;
|
|
@@ -21,7 +21,7 @@ function createTableProxy(name, columns, tableDef) {
|
|
|
21
21
|
for (const [colKey, colDef] of Object.entries(columns)) {
|
|
22
22
|
const config = colDef.$config || colDef;
|
|
23
23
|
const sqlName = config.$sqlName || config.$columnName || colKey;
|
|
24
|
-
const colType = config.$sqlType || config.$type || 'unknown';
|
|
24
|
+
const colType = config.$sqlType || (typeof config.$type === 'string' ? config.$type : undefined) || 'unknown';
|
|
25
25
|
proxy[colKey] = {
|
|
26
26
|
$table: name,
|
|
27
27
|
$column: sqlName,
|
|
@@ -116,7 +116,7 @@ function generateCreateTableSQL(def) {
|
|
|
116
116
|
function generateColumnSQL(name, config) {
|
|
117
117
|
const actualName = config.$columnName || name;
|
|
118
118
|
const parts = [pg_format_1.default.ident(actualName)];
|
|
119
|
-
let typeName = config.$type;
|
|
119
|
+
let typeName = config.$sqlType || (typeof config.$type === 'string' ? config.$type : 'TEXT');
|
|
120
120
|
if (config.$array) {
|
|
121
121
|
const dims = config.$dimensions ?? 1;
|
|
122
122
|
typeName += '[]'.repeat(dims);
|
|
@@ -76,7 +76,7 @@ function validateTable(table, tableName, features, errors, warnings, info, allow
|
|
|
76
76
|
validateTableFeatures(table, tableName, features, errors, warnings);
|
|
77
77
|
}
|
|
78
78
|
function validateColumn(column, location, features, errors, warnings, allowedCustomTypes) {
|
|
79
|
-
const colType = column.$
|
|
79
|
+
const colType = column.$sqlType || (typeof column.$type === 'string' ? column.$type : undefined) || 'unknown';
|
|
80
80
|
if (allowedCustomTypes.includes(colType.toUpperCase())) {
|
|
81
81
|
return;
|
|
82
82
|
}
|
|
@@ -17,7 +17,7 @@ function extractDefaultValue(col) {
|
|
|
17
17
|
return undefined;
|
|
18
18
|
}
|
|
19
19
|
function resolveColumnType(col) {
|
|
20
|
-
const base = col.$sqlType || col.$type || 'TEXT';
|
|
20
|
+
const base = col.$sqlType || (typeof col.$type === 'string' ? col.$type : null) || 'TEXT';
|
|
21
21
|
if (col.$length !== undefined) {
|
|
22
22
|
return `${base}(${col.$length})`;
|
|
23
23
|
}
|
|
@@ -32,7 +32,7 @@ function formatDefault(col) {
|
|
|
32
32
|
}
|
|
33
33
|
function generateColumnSQL(name, col) {
|
|
34
34
|
const parts = [quoteSQLiteIdentifier(col.$columnName || name)];
|
|
35
|
-
parts.push(col.$type || 'TEXT');
|
|
35
|
+
parts.push(col.$sqlType || (typeof col.$type === 'string' ? col.$type : null) || 'TEXT');
|
|
36
36
|
if (col.$primaryKey) {
|
|
37
37
|
parts.push('PRIMARY KEY');
|
|
38
38
|
if (col.$autoincrement) {
|
|
@@ -14,7 +14,7 @@ function sqliteTable(name, columns, options) {
|
|
|
14
14
|
for (const [colName, colConfig] of Object.entries(columns)) {
|
|
15
15
|
const col = colConfig;
|
|
16
16
|
if (col.$autoincrement) {
|
|
17
|
-
const sqlType = (col.$sqlType || col.$type || '').toUpperCase();
|
|
17
|
+
const sqlType = (col.$sqlType || (typeof col.$type === 'string' ? col.$type : '') || '').toUpperCase();
|
|
18
18
|
if (sqlType !== 'INTEGER' || !col.$primaryKey) {
|
|
19
19
|
throw new Error(`[sqliteTable] AUTOINCREMENT on column "${colName}" in table "${name}" ` +
|
|
20
20
|
`requires INTEGER PRIMARY KEY. Got type "${sqlType}", primaryKey=${col.$primaryKey}.`);
|
|
@@ -56,7 +56,8 @@ function deserializeRow(row, schema) {
|
|
|
56
56
|
const columnMap = new Map();
|
|
57
57
|
for (const [key, config] of Object.entries(schema)) {
|
|
58
58
|
const dbColumnName = config.$columnName || key;
|
|
59
|
-
|
|
59
|
+
const sqlType = config.$sqlType || (typeof config.$type === 'string' ? config.$type : 'TEXT');
|
|
60
|
+
columnMap.set(dbColumnName, { key, type: sqlType });
|
|
60
61
|
}
|
|
61
62
|
for (const [dbColumn, value] of Object.entries(row)) {
|
|
62
63
|
const mapping = columnMap.get(dbColumn);
|
|
@@ -102,7 +103,8 @@ function serializeRow(row, schema) {
|
|
|
102
103
|
for (const [key, value] of Object.entries(row)) {
|
|
103
104
|
const config = schema[key];
|
|
104
105
|
if (config) {
|
|
105
|
-
|
|
106
|
+
const sqlType = config.$sqlType || (typeof config.$type === 'string' ? config.$type : 'TEXT');
|
|
107
|
+
result[key] = serializeValue(value, sqlType);
|
|
106
108
|
}
|
|
107
109
|
else {
|
|
108
110
|
result[key] = value;
|
|
@@ -246,11 +246,21 @@ function generateColumnCode(col, useCamelCase, enumNames, domainNames, checkOver
|
|
|
246
246
|
const normalizedType = col.type.toLowerCase();
|
|
247
247
|
if (enumNames.has(normalizedType) || enumNames.has(col.type)) {
|
|
248
248
|
const enumName = `${toCamelCase(col.type)}Enum`;
|
|
249
|
-
|
|
249
|
+
if (useCamelCase && colName !== col.name) {
|
|
250
|
+
line = ` ${colName}: ${enumName}('${col.name}')`;
|
|
251
|
+
}
|
|
252
|
+
else {
|
|
253
|
+
line = ` ${colName}: ${enumName}()`;
|
|
254
|
+
}
|
|
250
255
|
}
|
|
251
256
|
else if (domainNames.has(normalizedType) || domainNames.has(col.type)) {
|
|
252
257
|
const domainName = `${toCamelCase(col.type)}Domain`;
|
|
253
|
-
|
|
258
|
+
if (useCamelCase && colName !== col.name) {
|
|
259
|
+
line = ` ${colName}: ${domainName}('${col.name}')`;
|
|
260
|
+
}
|
|
261
|
+
else {
|
|
262
|
+
line = ` ${colName}: ${domainName}()`;
|
|
263
|
+
}
|
|
254
264
|
}
|
|
255
265
|
else {
|
|
256
266
|
let typeBuilder;
|
|
@@ -667,7 +677,8 @@ function generateTableCode(table, useCamelCase, enumNames, domainNames, columnTy
|
|
|
667
677
|
function generateEnumCode(enumDef, useCamelCase) {
|
|
668
678
|
const baseName = useCamelCase ? toCamelCase(enumDef.name) : enumDef.name;
|
|
669
679
|
const enumName = `${baseName}Enum`;
|
|
670
|
-
const
|
|
680
|
+
const values = Array.isArray(enumDef.values) ? enumDef.values : typeof enumDef.values === 'string' ? enumDef.values.replace(/^\{|\}$/g, '').split(',').filter(Boolean) : [];
|
|
681
|
+
const valuesStr = values.map(v => `'${escapeString(v)}'`).join(', ');
|
|
671
682
|
const trackingId = enumDef.trackingId || generateTrackingId('e');
|
|
672
683
|
return `export const ${enumName} = pgEnum('${enumDef.name}', [${valuesStr}]).$id('${trackingId}')`;
|
|
673
684
|
}
|
|
@@ -176,7 +176,7 @@ export async function introspectCockroachDB(connection, options) {
|
|
|
176
176
|
const enums = enumsResult.rows.map(row => ({
|
|
177
177
|
name: row.enum_name,
|
|
178
178
|
schema: row.enum_schema,
|
|
179
|
-
values: row.enum_values
|
|
179
|
+
values: Array.isArray(row.enum_values) ? row.enum_values : typeof row.enum_values === 'string' ? row.enum_values.replace(/^\{|\}$/g, '').split(',').filter(Boolean) : [],
|
|
180
180
|
}));
|
|
181
181
|
onProgress?.('processing');
|
|
182
182
|
const columnsByTable = new Map();
|
|
@@ -160,7 +160,7 @@ export async function introspectDsql(connection, options) {
|
|
|
160
160
|
const enums = enumsResult.rows.map(row => ({
|
|
161
161
|
name: row.enum_name,
|
|
162
162
|
schema: row.enum_schema,
|
|
163
|
-
values: row.enum_values
|
|
163
|
+
values: Array.isArray(row.enum_values) ? row.enum_values : typeof row.enum_values === 'string' ? row.enum_values.replace(/^\{|\}$/g, '').split(',').filter(Boolean) : [],
|
|
164
164
|
}));
|
|
165
165
|
onProgress?.('processing');
|
|
166
166
|
const columnsByTable = new Map();
|
|
@@ -195,7 +195,7 @@ export async function introspectNile(connection, options) {
|
|
|
195
195
|
const enums = enumsResult.rows.map(row => ({
|
|
196
196
|
name: row.enum_name,
|
|
197
197
|
schema: row.enum_schema,
|
|
198
|
-
values: row.enum_values
|
|
198
|
+
values: Array.isArray(row.enum_values) ? row.enum_values : typeof row.enum_values === 'string' ? row.enum_values.replace(/^\{|\}$/g, '').split(',').filter(Boolean) : [],
|
|
199
199
|
}));
|
|
200
200
|
onProgress?.('processing');
|
|
201
201
|
const columnsByTable = new Map();
|
|
@@ -188,7 +188,7 @@ export async function introspectPostgres(connection, options) {
|
|
|
188
188
|
const enums = enumsResult.rows.map(row => ({
|
|
189
189
|
name: row.enum_name,
|
|
190
190
|
schema: row.enum_schema,
|
|
191
|
-
values: row.enum_values
|
|
191
|
+
values: Array.isArray(row.enum_values) ? row.enum_values : typeof row.enum_values === 'string' ? row.enum_values.replace(/^\{|\}$/g, '').split(',').filter(Boolean) : [],
|
|
192
192
|
}));
|
|
193
193
|
onProgress?.('processing');
|
|
194
194
|
const columnsByTable = new Map();
|
|
@@ -504,7 +504,7 @@ export function compositeToAST(composite) {
|
|
|
504
504
|
const config = fieldDef.$config || fieldDef;
|
|
505
505
|
attributes.push({
|
|
506
506
|
name: fieldName,
|
|
507
|
-
type: config.$type || 'text',
|
|
507
|
+
type: config.$sqlType || (typeof config.$type === 'string' ? config.$type : null) || 'text',
|
|
508
508
|
collation: config.$collation,
|
|
509
509
|
});
|
|
510
510
|
}
|
|
@@ -60,30 +60,55 @@ export class ConnectedSelectBuilder {
|
|
|
60
60
|
}
|
|
61
61
|
const tableColumns = joinedTableDef.$columns || joinedTableDef;
|
|
62
62
|
const dbToProp = new Map();
|
|
63
|
+
const propTypes = new Map();
|
|
63
64
|
for (const [propName, colDef] of Object.entries(tableColumns)) {
|
|
64
65
|
const dbColName = colDef?.$columnName ?? propName;
|
|
65
66
|
dbToProp.set(dbColName, propName);
|
|
67
|
+
const snakeCase = propName.replace(/[A-Z]/g, (letter) => `_${letter.toLowerCase()}`);
|
|
68
|
+
if (snakeCase !== propName && !dbToProp.has(snakeCase)) {
|
|
69
|
+
dbToProp.set(snakeCase, propName);
|
|
70
|
+
}
|
|
71
|
+
const sqlType = colDef?.$sqlType || (typeof colDef?.$type === 'string' ? colDef.$type : undefined);
|
|
72
|
+
if (sqlType) {
|
|
73
|
+
propTypes.set(propName, sqlType.toLowerCase());
|
|
74
|
+
}
|
|
66
75
|
}
|
|
67
76
|
if (Array.isArray(nestedData)) {
|
|
68
|
-
transformed[alias] = nestedData.map((item) => this.transformNestedObject(item, dbToProp));
|
|
77
|
+
transformed[alias] = nestedData.map((item) => this.transformNestedObject(item, dbToProp, propTypes));
|
|
69
78
|
}
|
|
70
79
|
else {
|
|
71
|
-
transformed[alias] = this.transformNestedObject(nestedData, dbToProp);
|
|
80
|
+
transformed[alias] = this.transformNestedObject(nestedData, dbToProp, propTypes);
|
|
72
81
|
}
|
|
73
82
|
}
|
|
74
83
|
return transformed;
|
|
75
84
|
});
|
|
76
85
|
}
|
|
77
|
-
transformNestedObject(obj, dbToProp) {
|
|
86
|
+
transformNestedObject(obj, dbToProp, propTypes) {
|
|
78
87
|
if (!obj || typeof obj !== 'object')
|
|
79
88
|
return obj;
|
|
80
89
|
const result = {};
|
|
81
90
|
for (const [key, value] of Object.entries(obj)) {
|
|
82
91
|
const propName = dbToProp.get(key) ?? key;
|
|
83
|
-
result[propName] = value;
|
|
92
|
+
result[propName] = propTypes ? this.coerceValue(value, propTypes.get(propName)) : value;
|
|
84
93
|
}
|
|
85
94
|
return result;
|
|
86
95
|
}
|
|
96
|
+
coerceValue(value, sqlType) {
|
|
97
|
+
if (value === null || value === undefined || !sqlType)
|
|
98
|
+
return value;
|
|
99
|
+
switch (sqlType) {
|
|
100
|
+
case 'timestamp':
|
|
101
|
+
case 'timestamptz':
|
|
102
|
+
case 'timestamp without time zone':
|
|
103
|
+
case 'timestamp with time zone':
|
|
104
|
+
return typeof value === 'string' ? new Date(value) : value;
|
|
105
|
+
case 'bigint':
|
|
106
|
+
case 'int8':
|
|
107
|
+
return typeof value === 'number' ? BigInt(value) : typeof value === 'string' ? BigInt(value) : value;
|
|
108
|
+
default:
|
|
109
|
+
return value;
|
|
110
|
+
}
|
|
111
|
+
}
|
|
87
112
|
where(callback) {
|
|
88
113
|
this.builder.where(callback);
|
|
89
114
|
return this;
|
|
@@ -38,14 +38,24 @@ export function executeTypeSafeJoin(ctx, joinType, tableOrAlias, callback) {
|
|
|
38
38
|
}
|
|
39
39
|
const selectedProps = conditionInternals.getSelectedColumns();
|
|
40
40
|
let selectColumns;
|
|
41
|
+
const toSnake = (s) => s.replace(/[A-Z]/g, l => `_${l.toLowerCase()}`);
|
|
41
42
|
if (selectedProps && selectedProps.length > 0) {
|
|
42
43
|
const rightColumns = rightTableDef?.$columns || rightTableDef;
|
|
43
44
|
selectColumns = selectedProps.map(prop => {
|
|
44
45
|
const columnDef = rightColumns?.[prop];
|
|
45
|
-
const sqlName = columnDef?.$columnName || prop;
|
|
46
|
+
const sqlName = columnDef?.$columnName || toSnake(prop);
|
|
46
47
|
return { property: prop, sqlName };
|
|
47
48
|
});
|
|
48
49
|
}
|
|
50
|
+
else if (rightTableDef) {
|
|
51
|
+
const rightColumns = rightTableDef.$columns || rightTableDef;
|
|
52
|
+
selectColumns = Object.entries(rightColumns)
|
|
53
|
+
.filter(([_, colDef]) => colDef && typeof colDef === 'object' && '$type' in colDef)
|
|
54
|
+
.map(([propName, colDef]) => ({
|
|
55
|
+
property: propName,
|
|
56
|
+
sqlName: colDef.$columnName || toSnake(propName),
|
|
57
|
+
}));
|
|
58
|
+
}
|
|
49
59
|
const joinClause = {
|
|
50
60
|
type: joinType,
|
|
51
61
|
table: rightTableName,
|
|
@@ -17,7 +17,7 @@ export function buildColumnMappings(schema, mappings, debugLog) {
|
|
|
17
17
|
const propToFields = new Map();
|
|
18
18
|
for (const [propName, colDef] of Object.entries(columns)) {
|
|
19
19
|
const dbColName = colDef?.$columnName ?? propName;
|
|
20
|
-
const colType = colDef?.$type
|
|
20
|
+
const colType = colDef?.$sqlType || (typeof colDef?.$type === 'string' ? colDef.$type : undefined) || 'TEXT';
|
|
21
21
|
propToDb.set(propName, dbColName);
|
|
22
22
|
dbToProp.set(dbColName, propName);
|
|
23
23
|
propToType.set(propName, colType);
|
|
@@ -18,8 +18,12 @@ export function buildColumnTypeMap(tableDef) {
|
|
|
18
18
|
const typeMap = new Map();
|
|
19
19
|
const columns = tableDef.$columns || tableDef;
|
|
20
20
|
for (const [key, colDef] of Object.entries(columns)) {
|
|
21
|
-
if (colDef && typeof colDef === 'object'
|
|
22
|
-
|
|
21
|
+
if (colDef && typeof colDef === 'object') {
|
|
22
|
+
const col = colDef;
|
|
23
|
+
const sqlType = col.$sqlType || (typeof col.$type === 'string' ? col.$type : undefined);
|
|
24
|
+
if (sqlType) {
|
|
25
|
+
typeMap.set(key, sqlType);
|
|
26
|
+
}
|
|
23
27
|
}
|
|
24
28
|
}
|
|
25
29
|
return typeMap;
|
|
@@ -146,7 +146,7 @@ export function createColumn(type) {
|
|
|
146
146
|
config.$length = len;
|
|
147
147
|
const baseType = config.$type.replace(/\(\d+\)/, '');
|
|
148
148
|
config.$type = `${baseType}(${len})`;
|
|
149
|
-
return Object.assign(this, { $length: len, $type: config.$type });
|
|
149
|
+
return Object.assign(this, { $length: len, $type: config.$type, $sqlType: config.$type });
|
|
150
150
|
},
|
|
151
151
|
precision(p) {
|
|
152
152
|
config.$precision = p;
|
|
@@ -154,7 +154,7 @@ export function createColumn(type) {
|
|
|
154
154
|
config.$type = config.$scale !== undefined
|
|
155
155
|
? `${base}(${p}, ${config.$scale})`
|
|
156
156
|
: `${base}(${p})`;
|
|
157
|
-
return Object.assign(this, { $precision: p, $type: config.$type });
|
|
157
|
+
return Object.assign(this, { $precision: p, $type: config.$type, $sqlType: config.$type });
|
|
158
158
|
},
|
|
159
159
|
scale(s) {
|
|
160
160
|
config.$scale = s;
|
|
@@ -162,7 +162,7 @@ export function createColumn(type) {
|
|
|
162
162
|
config.$type = config.$precision !== undefined
|
|
163
163
|
? `${base}(${config.$precision}, ${s})`
|
|
164
164
|
: `${base}(38, ${s})`;
|
|
165
|
-
return Object.assign(this, { $scale: s, $type: config.$type });
|
|
165
|
+
return Object.assign(this, { $scale: s, $type: config.$type, $sqlType: config.$type });
|
|
166
166
|
},
|
|
167
167
|
withTimezone() {
|
|
168
168
|
config.$withTimezone = true;
|
|
@@ -172,12 +172,12 @@ export function createColumn(type) {
|
|
|
172
172
|
else if (config.$type === 'TIME') {
|
|
173
173
|
config.$type = 'TIMETZ';
|
|
174
174
|
}
|
|
175
|
-
return Object.assign(this, { $withTimezone: true, $type: config.$type });
|
|
175
|
+
return Object.assign(this, { $withTimezone: true, $type: config.$type, $sqlType: config.$type });
|
|
176
176
|
},
|
|
177
177
|
dimensions(d) {
|
|
178
178
|
config.$dimensions = d;
|
|
179
179
|
config.$type = `VECTOR(${d})`;
|
|
180
|
-
return Object.assign(this, { $dimensions: d, $type: config.$type });
|
|
180
|
+
return Object.assign(this, { $dimensions: d, $type: config.$type, $sqlType: config.$type });
|
|
181
181
|
},
|
|
182
182
|
comment(text) {
|
|
183
183
|
config.$comment = text;
|
|
@@ -9,7 +9,7 @@ export function pgComposite(name, fields) {
|
|
|
9
9
|
const config = fieldConfig;
|
|
10
10
|
return {
|
|
11
11
|
name: fieldName,
|
|
12
|
-
type: config.$type,
|
|
12
|
+
type: config.$sqlType || (typeof config.$type === 'string' ? config.$type : 'TEXT'),
|
|
13
13
|
collation: undefined,
|
|
14
14
|
};
|
|
15
15
|
});
|
|
@@ -37,7 +37,7 @@ export function generateCompositeTypeSQL(composite) {
|
|
|
37
37
|
const fieldDefs = [];
|
|
38
38
|
for (const [fieldName, fieldConfig] of Object.entries(composite.$fields)) {
|
|
39
39
|
const config = fieldConfig;
|
|
40
|
-
let fieldDef = `"${fieldName}" ${config.$type}`;
|
|
40
|
+
let fieldDef = `"${fieldName}" ${config.$sqlType || (typeof config.$type === 'string' ? config.$type : 'TEXT')}`;
|
|
41
41
|
if (config.$nullable === false) {
|
|
42
42
|
fieldDef += ' NOT NULL';
|
|
43
43
|
}
|
|
@@ -135,8 +135,8 @@ function createDomainValueExpr() {
|
|
|
135
135
|
};
|
|
136
136
|
}
|
|
137
137
|
export function pgDomain(name, baseType, checks) {
|
|
138
|
-
const
|
|
139
|
-
const baseTypeStr =
|
|
138
|
+
const bt = baseType;
|
|
139
|
+
const baseTypeStr = bt.$sqlType || (typeof bt.$type === 'string' ? bt.$type : null) || 'TEXT';
|
|
140
140
|
const constraints = [];
|
|
141
141
|
let validateFn;
|
|
142
142
|
if (checks) {
|
|
@@ -159,8 +159,8 @@ export function pgDomain(name, baseType, checks) {
|
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
}
|
|
162
|
-
const notNull =
|
|
163
|
-
const defaultValue =
|
|
162
|
+
const notNull = bt?.$nullable === false;
|
|
163
|
+
const defaultValue = bt?.$default;
|
|
164
164
|
const domainFn = (columnName) => {
|
|
165
165
|
const col = createColumnWithName(name, columnName);
|
|
166
166
|
if (validateFn) {
|
|
@@ -2,6 +2,7 @@ export function pgEnum(name, values) {
|
|
|
2
2
|
const config = function (columnName) {
|
|
3
3
|
const col = {
|
|
4
4
|
$type: name,
|
|
5
|
+
$sqlType: name,
|
|
5
6
|
$enumName: name,
|
|
6
7
|
$checkValues: values,
|
|
7
8
|
};
|
|
@@ -32,7 +33,8 @@ export function pgEnum(name, values) {
|
|
|
32
33
|
array() {
|
|
33
34
|
col.$array = true;
|
|
34
35
|
col.$type = `${name}[]`;
|
|
35
|
-
|
|
36
|
+
col.$sqlType = `${name}[]`;
|
|
37
|
+
return Object.assign(this, { $array: true, $type: `${name}[]`, $sqlType: `${name}[]` });
|
|
36
38
|
},
|
|
37
39
|
$id(trackingId) {
|
|
38
40
|
col.$trackingId = trackingId;
|
|
@@ -17,7 +17,7 @@ function createTableProxy(name, columns, tableDef) {
|
|
|
17
17
|
for (const [colKey, colDef] of Object.entries(columns)) {
|
|
18
18
|
const config = colDef.$config || colDef;
|
|
19
19
|
const sqlName = config.$sqlName || config.$columnName || colKey;
|
|
20
|
-
const colType = config.$sqlType || config.$type || 'unknown';
|
|
20
|
+
const colType = config.$sqlType || (typeof config.$type === 'string' ? config.$type : undefined) || 'unknown';
|
|
21
21
|
proxy[colKey] = {
|
|
22
22
|
$table: name,
|
|
23
23
|
$column: sqlName,
|
|
@@ -105,7 +105,7 @@ export function generateCreateTableSQL(def) {
|
|
|
105
105
|
export function generateColumnSQL(name, config) {
|
|
106
106
|
const actualName = config.$columnName || name;
|
|
107
107
|
const parts = [format.ident(actualName)];
|
|
108
|
-
let typeName = config.$type;
|
|
108
|
+
let typeName = config.$sqlType || (typeof config.$type === 'string' ? config.$type : 'TEXT');
|
|
109
109
|
if (config.$array) {
|
|
110
110
|
const dims = config.$dimensions ?? 1;
|
|
111
111
|
typeName += '[]'.repeat(dims);
|
|
@@ -73,7 +73,7 @@ function validateTable(table, tableName, features, errors, warnings, info, allow
|
|
|
73
73
|
validateTableFeatures(table, tableName, features, errors, warnings);
|
|
74
74
|
}
|
|
75
75
|
function validateColumn(column, location, features, errors, warnings, allowedCustomTypes) {
|
|
76
|
-
const colType = column.$
|
|
76
|
+
const colType = column.$sqlType || (typeof column.$type === 'string' ? column.$type : undefined) || 'unknown';
|
|
77
77
|
if (allowedCustomTypes.includes(colType.toUpperCase())) {
|
|
78
78
|
return;
|
|
79
79
|
}
|
|
@@ -14,7 +14,7 @@ function extractDefaultValue(col) {
|
|
|
14
14
|
return undefined;
|
|
15
15
|
}
|
|
16
16
|
function resolveColumnType(col) {
|
|
17
|
-
const base = col.$sqlType || col.$type || 'TEXT';
|
|
17
|
+
const base = col.$sqlType || (typeof col.$type === 'string' ? col.$type : null) || 'TEXT';
|
|
18
18
|
if (col.$length !== undefined) {
|
|
19
19
|
return `${base}(${col.$length})`;
|
|
20
20
|
}
|
|
@@ -27,7 +27,7 @@ function formatDefault(col) {
|
|
|
27
27
|
}
|
|
28
28
|
function generateColumnSQL(name, col) {
|
|
29
29
|
const parts = [quoteSQLiteIdentifier(col.$columnName || name)];
|
|
30
|
-
parts.push(col.$type || 'TEXT');
|
|
30
|
+
parts.push(col.$sqlType || (typeof col.$type === 'string' ? col.$type : null) || 'TEXT');
|
|
31
31
|
if (col.$primaryKey) {
|
|
32
32
|
parts.push('PRIMARY KEY');
|
|
33
33
|
if (col.$autoincrement) {
|
|
@@ -11,7 +11,7 @@ export function sqliteTable(name, columns, options) {
|
|
|
11
11
|
for (const [colName, colConfig] of Object.entries(columns)) {
|
|
12
12
|
const col = colConfig;
|
|
13
13
|
if (col.$autoincrement) {
|
|
14
|
-
const sqlType = (col.$sqlType || col.$type || '').toUpperCase();
|
|
14
|
+
const sqlType = (col.$sqlType || (typeof col.$type === 'string' ? col.$type : '') || '').toUpperCase();
|
|
15
15
|
if (sqlType !== 'INTEGER' || !col.$primaryKey) {
|
|
16
16
|
throw new Error(`[sqliteTable] AUTOINCREMENT on column "${colName}" in table "${name}" ` +
|
|
17
17
|
`requires INTEGER PRIMARY KEY. Got type "${sqlType}", primaryKey=${col.$primaryKey}.`);
|
|
@@ -48,7 +48,8 @@ export function deserializeRow(row, schema) {
|
|
|
48
48
|
const columnMap = new Map();
|
|
49
49
|
for (const [key, config] of Object.entries(schema)) {
|
|
50
50
|
const dbColumnName = config.$columnName || key;
|
|
51
|
-
|
|
51
|
+
const sqlType = config.$sqlType || (typeof config.$type === 'string' ? config.$type : 'TEXT');
|
|
52
|
+
columnMap.set(dbColumnName, { key, type: sqlType });
|
|
52
53
|
}
|
|
53
54
|
for (const [dbColumn, value] of Object.entries(row)) {
|
|
54
55
|
const mapping = columnMap.get(dbColumn);
|
|
@@ -94,7 +95,8 @@ export function serializeRow(row, schema) {
|
|
|
94
95
|
for (const [key, value] of Object.entries(row)) {
|
|
95
96
|
const config = schema[key];
|
|
96
97
|
if (config) {
|
|
97
|
-
|
|
98
|
+
const sqlType = config.$sqlType || (typeof config.$type === 'string' ? config.$type : 'TEXT');
|
|
99
|
+
result[key] = serializeValue(value, sqlType);
|
|
98
100
|
}
|
|
99
101
|
else {
|
|
100
102
|
result[key] = value;
|
package/dist/index.d.ts
CHANGED
|
@@ -8744,6 +8744,12 @@ declare class ConnectedSelectBuilder<TSchema = any, TTable = any, TColumns exten
|
|
|
8744
8744
|
* @internal
|
|
8745
8745
|
*/
|
|
8746
8746
|
private transformNestedObject;
|
|
8747
|
+
/**
|
|
8748
|
+
* Coerce a JSON-serialized value back to its proper JS type.
|
|
8749
|
+
* row_to_json() serializes timestamps as strings and bigints as numbers.
|
|
8750
|
+
* @internal
|
|
8751
|
+
*/
|
|
8752
|
+
private coerceValue;
|
|
8747
8753
|
where(callback: (q: TypedConditionBuilder<TTable>) => TypedConditionBuilder<TTable>): this;
|
|
8748
8754
|
orderBy(column: ColumnName<TTable>, direction?: "ASC" | "DESC"): this;
|
|
8749
8755
|
/**
|