relq 1.0.81 → 1.0.83
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/core/helpers/ConnectedInsertBuilder.cjs +4 -1
- package/dist/cjs/core/helpers/ConnectedSelectBuilder.cjs +52 -4
- package/dist/cjs/core/helpers/ConnectedUpdateBuilder.cjs +4 -1
- package/dist/cjs/core/helpers/select-joins.cjs +2 -0
- package/dist/cjs/insert/insert-builder.cjs +13 -18
- package/dist/cjs/update/update-builder.cjs +4 -5
- package/dist/esm/core/helpers/ConnectedInsertBuilder.js +4 -1
- package/dist/esm/core/helpers/ConnectedSelectBuilder.js +52 -4
- package/dist/esm/core/helpers/ConnectedUpdateBuilder.js +4 -1
- package/dist/esm/core/helpers/select-joins.js +2 -0
- package/dist/esm/insert/insert-builder.js +13 -18
- package/dist/esm/update/update-builder.js +4 -5
- package/dist/index.d.ts +15 -2
- package/package.json +1 -1
|
@@ -36,10 +36,13 @@ class ConnectedInsertBuilder {
|
|
|
36
36
|
});
|
|
37
37
|
this.builder.setColumnTypeResolver((column) => {
|
|
38
38
|
const columnDef = tableColumns[column];
|
|
39
|
-
if (!columnDef
|
|
39
|
+
if (!columnDef) {
|
|
40
40
|
return undefined;
|
|
41
41
|
}
|
|
42
42
|
const type = columnDef.$type;
|
|
43
|
+
if (typeof type !== 'string') {
|
|
44
|
+
return undefined;
|
|
45
|
+
}
|
|
43
46
|
const isArray = columnDef.$array === true;
|
|
44
47
|
const baseType = type.replace(/\[\]$/, '').toLowerCase();
|
|
45
48
|
return { type: baseType, isArray };
|
|
@@ -41,6 +41,52 @@ class ConnectedSelectBuilder {
|
|
|
41
41
|
return column;
|
|
42
42
|
});
|
|
43
43
|
}
|
|
44
|
+
transformJoinResults(rows) {
|
|
45
|
+
const joins = this.builder.getStructuredJoins();
|
|
46
|
+
if (joins.length === 0) {
|
|
47
|
+
return rows;
|
|
48
|
+
}
|
|
49
|
+
const internal = this.relq[methods_1.INTERNAL];
|
|
50
|
+
return rows.map(row => {
|
|
51
|
+
if (!row || typeof row !== 'object')
|
|
52
|
+
return row;
|
|
53
|
+
const transformed = { ...row };
|
|
54
|
+
for (const join of joins) {
|
|
55
|
+
const alias = join.alias;
|
|
56
|
+
const nestedData = transformed[alias];
|
|
57
|
+
if (nestedData === null || nestedData === undefined) {
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const joinedTableDef = internal.getTableDef(join.schemaKey || alias) || internal.getTableDef(join.table);
|
|
61
|
+
if (!joinedTableDef) {
|
|
62
|
+
continue;
|
|
63
|
+
}
|
|
64
|
+
const tableColumns = joinedTableDef.$columns || joinedTableDef;
|
|
65
|
+
const dbToProp = new Map();
|
|
66
|
+
for (const [propName, colDef] of Object.entries(tableColumns)) {
|
|
67
|
+
const dbColName = colDef?.$columnName ?? propName;
|
|
68
|
+
dbToProp.set(dbColName, propName);
|
|
69
|
+
}
|
|
70
|
+
if (Array.isArray(nestedData)) {
|
|
71
|
+
transformed[alias] = nestedData.map((item) => this.transformNestedObject(item, dbToProp));
|
|
72
|
+
}
|
|
73
|
+
else {
|
|
74
|
+
transformed[alias] = this.transformNestedObject(nestedData, dbToProp);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
return transformed;
|
|
78
|
+
});
|
|
79
|
+
}
|
|
80
|
+
transformNestedObject(obj, dbToProp) {
|
|
81
|
+
if (!obj || typeof obj !== 'object')
|
|
82
|
+
return obj;
|
|
83
|
+
const result = {};
|
|
84
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
85
|
+
const propName = dbToProp.get(key) ?? key;
|
|
86
|
+
result[propName] = value;
|
|
87
|
+
}
|
|
88
|
+
return result;
|
|
89
|
+
}
|
|
44
90
|
where(callback) {
|
|
45
91
|
this.builder.where(callback);
|
|
46
92
|
return this;
|
|
@@ -158,19 +204,21 @@ class ConnectedSelectBuilder {
|
|
|
158
204
|
async all(withMetadata, _asRequired) {
|
|
159
205
|
const sql = this.builder.toString();
|
|
160
206
|
const result = await this.relq[methods_1.INTERNAL].executeSelect(sql, this.tableName);
|
|
207
|
+
const transformedData = this.transformJoinResults(result.data);
|
|
161
208
|
if (withMetadata) {
|
|
162
|
-
return result;
|
|
209
|
+
return { data: transformedData, metadata: result.metadata };
|
|
163
210
|
}
|
|
164
|
-
return
|
|
211
|
+
return transformedData;
|
|
165
212
|
}
|
|
166
213
|
async get(withMetadata, _asRequired) {
|
|
167
214
|
this.builder.limit(1);
|
|
168
215
|
const sql = this.builder.toString();
|
|
169
216
|
const result = await this.relq[methods_1.INTERNAL].executeSelectOne(sql, this.tableName);
|
|
217
|
+
const transformedData = result.data ? this.transformJoinResults([result.data])[0] : null;
|
|
170
218
|
if (withMetadata) {
|
|
171
|
-
return result;
|
|
219
|
+
return { data: transformedData, metadata: result.metadata };
|
|
172
220
|
}
|
|
173
|
-
return
|
|
221
|
+
return transformedData;
|
|
174
222
|
}
|
|
175
223
|
async value(column) {
|
|
176
224
|
this.builder.limit(1);
|
|
@@ -35,10 +35,13 @@ class ConnectedUpdateBuilder {
|
|
|
35
35
|
});
|
|
36
36
|
this.builder.setColumnTypeResolver((column) => {
|
|
37
37
|
const columnDef = tableColumns[column];
|
|
38
|
-
if (!columnDef
|
|
38
|
+
if (!columnDef) {
|
|
39
39
|
return undefined;
|
|
40
40
|
}
|
|
41
41
|
const type = columnDef.$type;
|
|
42
|
+
if (typeof type !== 'string') {
|
|
43
|
+
return undefined;
|
|
44
|
+
}
|
|
42
45
|
const isArray = columnDef.$array === true;
|
|
43
46
|
const baseType = type.replace(/\[\]$/, '').toLowerCase();
|
|
44
47
|
return { type: baseType, isArray };
|
|
@@ -54,6 +54,7 @@ function executeTypeSafeJoin(ctx, joinType, tableOrAlias, callback) {
|
|
|
54
54
|
type: joinType,
|
|
55
55
|
table: rightTableName,
|
|
56
56
|
alias: rightAlias,
|
|
57
|
+
schemaKey: rightTableKey,
|
|
57
58
|
onClause: conditionInternals.toSQL() || undefined,
|
|
58
59
|
usingColumns: conditionInternals.getUsingColumns() || undefined,
|
|
59
60
|
selectColumns
|
|
@@ -89,6 +90,7 @@ function executeTypeSafeJoinMany(ctx, joinType, tableOrAlias, callback) {
|
|
|
89
90
|
type: lateralJoinType,
|
|
90
91
|
table: rightTableName,
|
|
91
92
|
alias: rightAlias,
|
|
93
|
+
schemaKey: rightTableKey,
|
|
92
94
|
lateralSubquery: lateralSQL
|
|
93
95
|
};
|
|
94
96
|
ctx.builder.addStructuredJoin(joinClause);
|
|
@@ -184,34 +184,29 @@ class InsertBuilder {
|
|
|
184
184
|
const placeholderTypes = [];
|
|
185
185
|
for (const colName of originalColumns) {
|
|
186
186
|
const value = row[colName];
|
|
187
|
-
if (Array.isArray(value)) {
|
|
187
|
+
if (Array.isArray(value) || (value !== null && typeof value === 'object' && !(value instanceof Date))) {
|
|
188
188
|
const typeInfo = this.columnTypeResolver?.(colName);
|
|
189
189
|
if (typeInfo) {
|
|
190
|
-
if (
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
190
|
+
if (Array.isArray(value)) {
|
|
191
|
+
if (typeInfo.isArray) {
|
|
192
|
+
processedValues.push(this.formatPostgresArray(value, typeInfo.type));
|
|
193
|
+
}
|
|
194
|
+
else if (typeInfo.type === 'jsonb' || typeInfo.type === 'json') {
|
|
195
|
+
processedValues.push(this.formatJsonbValue(value));
|
|
196
|
+
}
|
|
197
|
+
else {
|
|
198
|
+
processedValues.push(this.formatJsonbValue(value));
|
|
199
|
+
}
|
|
195
200
|
}
|
|
196
201
|
else {
|
|
197
|
-
processedValues.push(this.
|
|
202
|
+
processedValues.push(this.formatJsonbValue(value));
|
|
198
203
|
}
|
|
199
204
|
}
|
|
200
205
|
else {
|
|
201
|
-
|
|
202
|
-
if (hasObjects) {
|
|
203
|
-
processedValues.push(this.formatJsonbValue(value));
|
|
204
|
-
}
|
|
205
|
-
else {
|
|
206
|
-
processedValues.push(this.formatPostgresArray(value));
|
|
207
|
-
}
|
|
206
|
+
processedValues.push(this.formatJsonbValue(value));
|
|
208
207
|
}
|
|
209
208
|
placeholderTypes.push('%s');
|
|
210
209
|
}
|
|
211
|
-
else if (value !== null && typeof value === 'object' && !(value instanceof Date)) {
|
|
212
|
-
processedValues.push(this.formatJsonbValue(value));
|
|
213
|
-
placeholderTypes.push('%s');
|
|
214
|
-
}
|
|
215
210
|
else {
|
|
216
211
|
processedValues.push(value);
|
|
217
212
|
placeholderTypes.push('%L');
|
|
@@ -172,12 +172,11 @@ class UpdateBuilder {
|
|
|
172
172
|
else if (typeInfo.type === 'jsonb' || typeInfo.type === 'json') {
|
|
173
173
|
return this.formatJsonbValue(value);
|
|
174
174
|
}
|
|
175
|
+
else {
|
|
176
|
+
return this.formatJsonbValue(value);
|
|
177
|
+
}
|
|
175
178
|
}
|
|
176
|
-
|
|
177
|
-
if (hasObjects) {
|
|
178
|
-
return this.formatJsonbValue(value);
|
|
179
|
-
}
|
|
180
|
-
return this.formatPostgresArray(value);
|
|
179
|
+
return this.formatJsonbValue(value);
|
|
181
180
|
}
|
|
182
181
|
toString() {
|
|
183
182
|
const processedPairs = Object.entries(this.updateData).map(([col, val]) => {
|
|
@@ -33,10 +33,13 @@ export class ConnectedInsertBuilder {
|
|
|
33
33
|
});
|
|
34
34
|
this.builder.setColumnTypeResolver((column) => {
|
|
35
35
|
const columnDef = tableColumns[column];
|
|
36
|
-
if (!columnDef
|
|
36
|
+
if (!columnDef) {
|
|
37
37
|
return undefined;
|
|
38
38
|
}
|
|
39
39
|
const type = columnDef.$type;
|
|
40
|
+
if (typeof type !== 'string') {
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
40
43
|
const isArray = columnDef.$array === true;
|
|
41
44
|
const baseType = type.replace(/\[\]$/, '').toLowerCase();
|
|
42
45
|
return { type: baseType, isArray };
|
|
@@ -38,6 +38,52 @@ export class ConnectedSelectBuilder {
|
|
|
38
38
|
return column;
|
|
39
39
|
});
|
|
40
40
|
}
|
|
41
|
+
transformJoinResults(rows) {
|
|
42
|
+
const joins = this.builder.getStructuredJoins();
|
|
43
|
+
if (joins.length === 0) {
|
|
44
|
+
return rows;
|
|
45
|
+
}
|
|
46
|
+
const internal = this.relq[INTERNAL];
|
|
47
|
+
return rows.map(row => {
|
|
48
|
+
if (!row || typeof row !== 'object')
|
|
49
|
+
return row;
|
|
50
|
+
const transformed = { ...row };
|
|
51
|
+
for (const join of joins) {
|
|
52
|
+
const alias = join.alias;
|
|
53
|
+
const nestedData = transformed[alias];
|
|
54
|
+
if (nestedData === null || nestedData === undefined) {
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
const joinedTableDef = internal.getTableDef(join.schemaKey || alias) || internal.getTableDef(join.table);
|
|
58
|
+
if (!joinedTableDef) {
|
|
59
|
+
continue;
|
|
60
|
+
}
|
|
61
|
+
const tableColumns = joinedTableDef.$columns || joinedTableDef;
|
|
62
|
+
const dbToProp = new Map();
|
|
63
|
+
for (const [propName, colDef] of Object.entries(tableColumns)) {
|
|
64
|
+
const dbColName = colDef?.$columnName ?? propName;
|
|
65
|
+
dbToProp.set(dbColName, propName);
|
|
66
|
+
}
|
|
67
|
+
if (Array.isArray(nestedData)) {
|
|
68
|
+
transformed[alias] = nestedData.map((item) => this.transformNestedObject(item, dbToProp));
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
transformed[alias] = this.transformNestedObject(nestedData, dbToProp);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
return transformed;
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
transformNestedObject(obj, dbToProp) {
|
|
78
|
+
if (!obj || typeof obj !== 'object')
|
|
79
|
+
return obj;
|
|
80
|
+
const result = {};
|
|
81
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
82
|
+
const propName = dbToProp.get(key) ?? key;
|
|
83
|
+
result[propName] = value;
|
|
84
|
+
}
|
|
85
|
+
return result;
|
|
86
|
+
}
|
|
41
87
|
where(callback) {
|
|
42
88
|
this.builder.where(callback);
|
|
43
89
|
return this;
|
|
@@ -155,19 +201,21 @@ export class ConnectedSelectBuilder {
|
|
|
155
201
|
async all(withMetadata, _asRequired) {
|
|
156
202
|
const sql = this.builder.toString();
|
|
157
203
|
const result = await this.relq[INTERNAL].executeSelect(sql, this.tableName);
|
|
204
|
+
const transformedData = this.transformJoinResults(result.data);
|
|
158
205
|
if (withMetadata) {
|
|
159
|
-
return result;
|
|
206
|
+
return { data: transformedData, metadata: result.metadata };
|
|
160
207
|
}
|
|
161
|
-
return
|
|
208
|
+
return transformedData;
|
|
162
209
|
}
|
|
163
210
|
async get(withMetadata, _asRequired) {
|
|
164
211
|
this.builder.limit(1);
|
|
165
212
|
const sql = this.builder.toString();
|
|
166
213
|
const result = await this.relq[INTERNAL].executeSelectOne(sql, this.tableName);
|
|
214
|
+
const transformedData = result.data ? this.transformJoinResults([result.data])[0] : null;
|
|
167
215
|
if (withMetadata) {
|
|
168
|
-
return result;
|
|
216
|
+
return { data: transformedData, metadata: result.metadata };
|
|
169
217
|
}
|
|
170
|
-
return
|
|
218
|
+
return transformedData;
|
|
171
219
|
}
|
|
172
220
|
async value(column) {
|
|
173
221
|
this.builder.limit(1);
|
|
@@ -32,10 +32,13 @@ export class ConnectedUpdateBuilder {
|
|
|
32
32
|
});
|
|
33
33
|
this.builder.setColumnTypeResolver((column) => {
|
|
34
34
|
const columnDef = tableColumns[column];
|
|
35
|
-
if (!columnDef
|
|
35
|
+
if (!columnDef) {
|
|
36
36
|
return undefined;
|
|
37
37
|
}
|
|
38
38
|
const type = columnDef.$type;
|
|
39
|
+
if (typeof type !== 'string') {
|
|
40
|
+
return undefined;
|
|
41
|
+
}
|
|
39
42
|
const isArray = columnDef.$array === true;
|
|
40
43
|
const baseType = type.replace(/\[\]$/, '').toLowerCase();
|
|
41
44
|
return { type: baseType, isArray };
|
|
@@ -50,6 +50,7 @@ export function executeTypeSafeJoin(ctx, joinType, tableOrAlias, callback) {
|
|
|
50
50
|
type: joinType,
|
|
51
51
|
table: rightTableName,
|
|
52
52
|
alias: rightAlias,
|
|
53
|
+
schemaKey: rightTableKey,
|
|
53
54
|
onClause: conditionInternals.toSQL() || undefined,
|
|
54
55
|
usingColumns: conditionInternals.getUsingColumns() || undefined,
|
|
55
56
|
selectColumns
|
|
@@ -85,6 +86,7 @@ export function executeTypeSafeJoinMany(ctx, joinType, tableOrAlias, callback) {
|
|
|
85
86
|
type: lateralJoinType,
|
|
86
87
|
table: rightTableName,
|
|
87
88
|
alias: rightAlias,
|
|
89
|
+
schemaKey: rightTableKey,
|
|
88
90
|
lateralSubquery: lateralSQL
|
|
89
91
|
};
|
|
90
92
|
ctx.builder.addStructuredJoin(joinClause);
|
|
@@ -178,34 +178,29 @@ export class InsertBuilder {
|
|
|
178
178
|
const placeholderTypes = [];
|
|
179
179
|
for (const colName of originalColumns) {
|
|
180
180
|
const value = row[colName];
|
|
181
|
-
if (Array.isArray(value)) {
|
|
181
|
+
if (Array.isArray(value) || (value !== null && typeof value === 'object' && !(value instanceof Date))) {
|
|
182
182
|
const typeInfo = this.columnTypeResolver?.(colName);
|
|
183
183
|
if (typeInfo) {
|
|
184
|
-
if (
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
184
|
+
if (Array.isArray(value)) {
|
|
185
|
+
if (typeInfo.isArray) {
|
|
186
|
+
processedValues.push(this.formatPostgresArray(value, typeInfo.type));
|
|
187
|
+
}
|
|
188
|
+
else if (typeInfo.type === 'jsonb' || typeInfo.type === 'json') {
|
|
189
|
+
processedValues.push(this.formatJsonbValue(value));
|
|
190
|
+
}
|
|
191
|
+
else {
|
|
192
|
+
processedValues.push(this.formatJsonbValue(value));
|
|
193
|
+
}
|
|
189
194
|
}
|
|
190
195
|
else {
|
|
191
|
-
processedValues.push(this.
|
|
196
|
+
processedValues.push(this.formatJsonbValue(value));
|
|
192
197
|
}
|
|
193
198
|
}
|
|
194
199
|
else {
|
|
195
|
-
|
|
196
|
-
if (hasObjects) {
|
|
197
|
-
processedValues.push(this.formatJsonbValue(value));
|
|
198
|
-
}
|
|
199
|
-
else {
|
|
200
|
-
processedValues.push(this.formatPostgresArray(value));
|
|
201
|
-
}
|
|
200
|
+
processedValues.push(this.formatJsonbValue(value));
|
|
202
201
|
}
|
|
203
202
|
placeholderTypes.push('%s');
|
|
204
203
|
}
|
|
205
|
-
else if (value !== null && typeof value === 'object' && !(value instanceof Date)) {
|
|
206
|
-
processedValues.push(this.formatJsonbValue(value));
|
|
207
|
-
placeholderTypes.push('%s');
|
|
208
|
-
}
|
|
209
204
|
else {
|
|
210
205
|
processedValues.push(value);
|
|
211
206
|
placeholderTypes.push('%L');
|
|
@@ -166,12 +166,11 @@ export class UpdateBuilder {
|
|
|
166
166
|
else if (typeInfo.type === 'jsonb' || typeInfo.type === 'json') {
|
|
167
167
|
return this.formatJsonbValue(value);
|
|
168
168
|
}
|
|
169
|
+
else {
|
|
170
|
+
return this.formatJsonbValue(value);
|
|
171
|
+
}
|
|
169
172
|
}
|
|
170
|
-
|
|
171
|
-
if (hasObjects) {
|
|
172
|
-
return this.formatJsonbValue(value);
|
|
173
|
-
}
|
|
174
|
-
return this.formatPostgresArray(value);
|
|
173
|
+
return this.formatJsonbValue(value);
|
|
175
174
|
}
|
|
176
175
|
toString() {
|
|
177
176
|
const processedPairs = Object.entries(this.updateData).map(([col, val]) => {
|
package/dist/index.d.ts
CHANGED
|
@@ -2037,6 +2037,8 @@ export interface JoinClause {
|
|
|
2037
2037
|
table: string;
|
|
2038
2038
|
/** Alias for the table (may be same as table) */
|
|
2039
2039
|
alias: string;
|
|
2040
|
+
/** Schema key (for looking up table definition) - may differ from table/alias */
|
|
2041
|
+
schemaKey?: string;
|
|
2040
2042
|
/** ON clause SQL (without "ON" keyword) */
|
|
2041
2043
|
onClause?: string;
|
|
2042
2044
|
/** USING columns (alternative to ON) */
|
|
@@ -2501,8 +2503,8 @@ export declare class UpdateBuilder {
|
|
|
2501
2503
|
*/
|
|
2502
2504
|
private formatJsonbValue;
|
|
2503
2505
|
/**
|
|
2504
|
-
* Format an array value using schema type info
|
|
2505
|
-
*
|
|
2506
|
+
* Format an array value using schema type info.
|
|
2507
|
+
* Schema is required for proper handling - defaults to JSONB if no schema.
|
|
2506
2508
|
*/
|
|
2507
2509
|
private formatArrayValueWithType;
|
|
2508
2510
|
toString(): string;
|
|
@@ -8731,6 +8733,17 @@ declare class ConnectedSelectBuilder<TSchema = any, TTable = any, TColumns exten
|
|
|
8731
8733
|
* @internal
|
|
8732
8734
|
*/
|
|
8733
8735
|
private setupColumnResolver;
|
|
8736
|
+
/**
|
|
8737
|
+
* Transform nested join results from DB column names to schema property names.
|
|
8738
|
+
* Uses schema metadata to resolve column names for each joined table.
|
|
8739
|
+
* @internal
|
|
8740
|
+
*/
|
|
8741
|
+
private transformJoinResults;
|
|
8742
|
+
/**
|
|
8743
|
+
* Transform a single nested object using the column mapping.
|
|
8744
|
+
* @internal
|
|
8745
|
+
*/
|
|
8746
|
+
private transformNestedObject;
|
|
8734
8747
|
where(callback: (q: TypedConditionBuilder<TTable>) => TypedConditionBuilder<TTable>): this;
|
|
8735
8748
|
orderBy(column: ColumnName<TTable>, direction?: "ASC" | "DESC"): this;
|
|
8736
8749
|
/**
|