linkgress-orm 0.1.18 → 0.1.20
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/database/database-client.interface.d.ts +29 -0
- package/dist/database/database-client.interface.d.ts.map +1 -1
- package/dist/database/database-client.interface.js +45 -1
- package/dist/database/database-client.interface.js.map +1 -1
- package/dist/database/pg-client.d.ts +5 -0
- package/dist/database/pg-client.d.ts.map +1 -1
- package/dist/database/pg-client.js +27 -0
- package/dist/database/pg-client.js.map +1 -1
- package/dist/database/postgres-client.d.ts +6 -0
- package/dist/database/postgres-client.d.ts.map +1 -1
- package/dist/database/postgres-client.js +17 -0
- package/dist/database/postgres-client.js.map +1 -1
- package/dist/entity/db-column.d.ts +17 -0
- package/dist/entity/db-column.d.ts.map +1 -1
- package/dist/entity/db-column.js.map +1 -1
- package/dist/entity/db-context.d.ts +56 -6
- package/dist/entity/db-context.d.ts.map +1 -1
- package/dist/entity/db-context.js +180 -74
- package/dist/entity/db-context.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js.map +1 -1
- package/dist/query/collection-strategy.interface.d.ts +12 -0
- package/dist/query/collection-strategy.interface.d.ts.map +1 -1
- package/dist/query/query-builder.d.ts +15 -2
- package/dist/query/query-builder.d.ts.map +1 -1
- package/dist/query/query-builder.js +179 -48
- package/dist/query/query-builder.js.map +1 -1
- package/dist/query/sql-utils.d.ts +2 -0
- package/dist/query/sql-utils.d.ts.map +1 -1
- package/dist/query/sql-utils.js +24 -7
- package/dist/query/sql-utils.js.map +1 -1
- package/dist/query/strategies/temptable-collection-strategy.d.ts.map +1 -1
- package/dist/query/strategies/temptable-collection-strategy.js +4 -3
- package/dist/query/strategies/temptable-collection-strategy.js.map +1 -1
- package/package.json +2 -3
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
"use strict";
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.DatabaseContext = exports.DbEntityTable = exports.EntityInsertBuilder = exports.DataContext = exports.TableAccessor = exports.InsertBuilder = exports.QueryExecutor = exports.TimeTracer = void 0;
|
|
4
|
+
const database_client_interface_1 = require("../database/database-client.interface");
|
|
4
5
|
const entity_base_1 = require("./entity-base");
|
|
5
6
|
const model_config_1 = require("./model-config");
|
|
6
7
|
const query_builder_1 = require("../query/query-builder");
|
|
@@ -528,15 +529,21 @@ class TableAccessor {
|
|
|
528
529
|
const column = this.schema.columns[key];
|
|
529
530
|
if (column) {
|
|
530
531
|
const config = column.build();
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
placeholders.push(`$${paramIndex++}`);
|
|
532
|
+
// Skip auto-increment columns
|
|
533
|
+
if (config.autoIncrement) {
|
|
534
|
+
continue;
|
|
535
|
+
}
|
|
536
|
+
// Skip columns with undefined values if they have a default - let the DB use the default
|
|
537
|
+
if (value === undefined && (config.default !== undefined || config.identity)) {
|
|
538
|
+
continue;
|
|
539
539
|
}
|
|
540
|
+
columns.push(`"${config.name}"`);
|
|
541
|
+
// Apply toDriver mapper if present
|
|
542
|
+
const mappedValue = config.mapper
|
|
543
|
+
? config.mapper.toDriver(value)
|
|
544
|
+
: value;
|
|
545
|
+
values.push(mappedValue);
|
|
546
|
+
placeholders.push(`$${paramIndex++}`);
|
|
540
547
|
}
|
|
541
548
|
}
|
|
542
549
|
const returningColumns = (0, sql_utils_1.buildReturningColumnList)(this.schema);
|
|
@@ -792,13 +799,18 @@ class DataContext {
|
|
|
792
799
|
}
|
|
793
800
|
/**
|
|
794
801
|
* Get table accessor by name
|
|
802
|
+
* When in a transaction, creates a fresh accessor with the transactional client
|
|
795
803
|
*/
|
|
796
804
|
getTable(name) {
|
|
797
|
-
const
|
|
798
|
-
if (!
|
|
805
|
+
const cachedAccessor = this.tableAccessors.get(name);
|
|
806
|
+
if (!cachedAccessor) {
|
|
799
807
|
throw new Error(`Table ${String(name)} not found in schema`);
|
|
800
808
|
}
|
|
801
|
-
|
|
809
|
+
// If in a transaction, create a new accessor with the current (transactional) client
|
|
810
|
+
if (this.client.isInTransaction()) {
|
|
811
|
+
return new TableAccessor(cachedAccessor.tableBuilder, this.client, this.schemaRegistry, this.executor, this.queryOptions?.collectionStrategy);
|
|
812
|
+
}
|
|
813
|
+
return cachedAccessor;
|
|
802
814
|
}
|
|
803
815
|
/**
|
|
804
816
|
* Execute raw SQL query with optional type parameter for results
|
|
@@ -821,22 +833,25 @@ class DataContext {
|
|
|
821
833
|
}
|
|
822
834
|
/**
|
|
823
835
|
* Execute in transaction
|
|
836
|
+
* Uses the database client's native transaction support for proper handling
|
|
837
|
+
* across different drivers (pg uses BEGIN/COMMIT, postgres uses sql.begin())
|
|
824
838
|
*/
|
|
825
839
|
async transaction(fn) {
|
|
826
|
-
|
|
827
|
-
|
|
828
|
-
|
|
829
|
-
|
|
830
|
-
|
|
831
|
-
|
|
832
|
-
|
|
833
|
-
|
|
834
|
-
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
+
// Store the original client
|
|
841
|
+
const originalClient = this.client;
|
|
842
|
+
return await this.client.transaction(async (queryFn) => {
|
|
843
|
+
// Create a transactional client that routes all queries through the transaction
|
|
844
|
+
const txClient = new database_client_interface_1.TransactionalClient(queryFn, originalClient);
|
|
845
|
+
// Temporarily swap the client to use the transactional one
|
|
846
|
+
this.client = txClient;
|
|
847
|
+
try {
|
|
848
|
+
return await fn(this);
|
|
849
|
+
}
|
|
850
|
+
finally {
|
|
851
|
+
// Restore the original client
|
|
852
|
+
this.client = originalClient;
|
|
853
|
+
}
|
|
854
|
+
});
|
|
840
855
|
}
|
|
841
856
|
/**
|
|
842
857
|
* Get schema manager for create/drop operations and automatic migrations
|
|
@@ -977,6 +992,36 @@ class DbEntityTable {
|
|
|
977
992
|
}
|
|
978
993
|
return columns;
|
|
979
994
|
}
|
|
995
|
+
/**
|
|
996
|
+
* Get an array of all column property names (keys) for this entity.
|
|
997
|
+
* Returns a strongly typed array where each element is a valid column key of TEntity.
|
|
998
|
+
*
|
|
999
|
+
* This is a convenience method equivalent to `getColumns().map(c => c.propertyName)`
|
|
1000
|
+
* but with better type inference.
|
|
1001
|
+
*
|
|
1002
|
+
* @returns Array of column property names typed as ExtractDbColumnKeys<TEntity>
|
|
1003
|
+
*
|
|
1004
|
+
* @example
|
|
1005
|
+
* ```typescript
|
|
1006
|
+
* // Get all column keys
|
|
1007
|
+
* const keys = db.users.getColumnKeys();
|
|
1008
|
+
* // Type: ExtractDbColumnKeys<User>[] which is ('id' | 'username' | 'email' | ...)[]
|
|
1009
|
+
*
|
|
1010
|
+
* // Use for dynamic property access
|
|
1011
|
+
* const user = await db.users.findOne(u => eq(u.id, 1));
|
|
1012
|
+
* for (const key of db.users.getColumnKeys()) {
|
|
1013
|
+
* console.log(`${key}: ${user[key]}`); // TypeScript knows key is valid
|
|
1014
|
+
* }
|
|
1015
|
+
*
|
|
1016
|
+
* // Use for building dynamic queries
|
|
1017
|
+
* const columnKeys = db.users.getColumnKeys();
|
|
1018
|
+
* // columnKeys[0] is typed as 'id' | 'username' | 'email' | ...
|
|
1019
|
+
* ```
|
|
1020
|
+
*/
|
|
1021
|
+
getColumnKeys() {
|
|
1022
|
+
const schema = this._getSchema();
|
|
1023
|
+
return Object.keys(schema.columns);
|
|
1024
|
+
}
|
|
980
1025
|
/**
|
|
981
1026
|
* Get an object containing all entity properties as DbColumn references.
|
|
982
1027
|
* Useful for building dynamic queries or accessing column metadata.
|
|
@@ -1225,21 +1270,20 @@ class DbEntityTable {
|
|
|
1225
1270
|
*/
|
|
1226
1271
|
where(condition) {
|
|
1227
1272
|
const schema = this._getSchema();
|
|
1228
|
-
// Create a selector that selects all columns
|
|
1273
|
+
// Create a selector that selects all columns only (not navigation properties)
|
|
1229
1274
|
const allColumnsSelector = (e) => {
|
|
1230
1275
|
const result = {};
|
|
1231
1276
|
// Copy all column properties
|
|
1232
1277
|
for (const colName of Object.keys(schema.columns)) {
|
|
1233
1278
|
result[colName] = e[colName];
|
|
1234
1279
|
}
|
|
1235
|
-
// Add navigation properties as enumerable getters
|
|
1236
|
-
//
|
|
1237
|
-
//
|
|
1238
|
-
// When the selection is analyzed, the builder is detected and handled appropriately
|
|
1280
|
+
// Add navigation properties as non-enumerable getters
|
|
1281
|
+
// This allows chained selectors like .select(u => ({ posts: u.posts!.where(...) }))
|
|
1282
|
+
// but they won't be included in the default query output
|
|
1239
1283
|
for (const relName of Object.keys(schema.relations)) {
|
|
1240
1284
|
Object.defineProperty(result, relName, {
|
|
1241
1285
|
get: () => e[relName],
|
|
1242
|
-
enumerable:
|
|
1286
|
+
enumerable: false, // Non-enumerable so it's NOT included in default selection
|
|
1243
1287
|
configurable: true,
|
|
1244
1288
|
});
|
|
1245
1289
|
}
|
|
@@ -1255,21 +1299,20 @@ class DbEntityTable {
|
|
|
1255
1299
|
*/
|
|
1256
1300
|
with(...ctes) {
|
|
1257
1301
|
const schema = this._getSchema();
|
|
1258
|
-
// Create a selector that selects all columns
|
|
1302
|
+
// Create a selector that selects all columns only (not navigation properties)
|
|
1259
1303
|
const allColumnsSelector = (e) => {
|
|
1260
1304
|
const result = {};
|
|
1261
1305
|
// Copy all column properties
|
|
1262
1306
|
for (const colName of Object.keys(schema.columns)) {
|
|
1263
1307
|
result[colName] = e[colName];
|
|
1264
1308
|
}
|
|
1265
|
-
// Add navigation properties as enumerable getters
|
|
1266
|
-
//
|
|
1267
|
-
//
|
|
1268
|
-
// When the selection is analyzed, the builder is detected and handled appropriately
|
|
1309
|
+
// Add navigation properties as non-enumerable getters
|
|
1310
|
+
// This allows chained selectors like .select(u => ({ posts: u.posts!.where(...) }))
|
|
1311
|
+
// but they won't be included in the default query output
|
|
1269
1312
|
for (const relName of Object.keys(schema.relations)) {
|
|
1270
1313
|
Object.defineProperty(result, relName, {
|
|
1271
1314
|
get: () => e[relName],
|
|
1272
|
-
enumerable:
|
|
1315
|
+
enumerable: false, // Non-enumerable so it's NOT included in default selection
|
|
1273
1316
|
configurable: true,
|
|
1274
1317
|
});
|
|
1275
1318
|
}
|
|
@@ -1411,20 +1454,37 @@ class DbEntityTable {
|
|
|
1411
1454
|
const executor = this._getExecutor();
|
|
1412
1455
|
const client = this._getClient();
|
|
1413
1456
|
const qualifiedTableName = this._getQualifiedTableName();
|
|
1414
|
-
// Get columns from
|
|
1415
|
-
const referenceItem = data[0];
|
|
1457
|
+
// Get columns from all rows - a column is included if ANY row has a non-undefined value for it
|
|
1416
1458
|
const columnConfigs = [];
|
|
1417
1459
|
for (const [propName, colBuilder] of Object.entries(schema.columns)) {
|
|
1418
|
-
|
|
1419
|
-
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1423
|
-
|
|
1424
|
-
|
|
1425
|
-
|
|
1460
|
+
const config = colBuilder.build();
|
|
1461
|
+
// Skip auto-increment columns (unless overriding)
|
|
1462
|
+
if (config.autoIncrement && !overridingSystemValue) {
|
|
1463
|
+
continue;
|
|
1464
|
+
}
|
|
1465
|
+
// Check if any row has a defined (non-undefined) value for this column
|
|
1466
|
+
const hasDefinedValue = data.some(record => {
|
|
1467
|
+
const value = record[propName];
|
|
1468
|
+
return value !== undefined;
|
|
1469
|
+
});
|
|
1470
|
+
// If column has a default and ALL rows have undefined, skip it (let DB use default)
|
|
1471
|
+
// Otherwise, include it if at least one row has a defined value
|
|
1472
|
+
if (!hasDefinedValue) {
|
|
1473
|
+
// All rows have undefined - if there's a default, skip the column
|
|
1474
|
+
if (config.default !== undefined || config.identity) {
|
|
1475
|
+
continue;
|
|
1476
|
+
}
|
|
1477
|
+
// No default, but column is present with undefined in data - include it (will become NULL)
|
|
1478
|
+
const isPresentInAnyRow = data.some(record => propName in record);
|
|
1479
|
+
if (!isPresentInAnyRow) {
|
|
1480
|
+
continue;
|
|
1426
1481
|
}
|
|
1427
1482
|
}
|
|
1483
|
+
columnConfigs.push({
|
|
1484
|
+
propName,
|
|
1485
|
+
dbName: config.name,
|
|
1486
|
+
mapper: config.mapper,
|
|
1487
|
+
});
|
|
1428
1488
|
}
|
|
1429
1489
|
// Build VALUES clauses
|
|
1430
1490
|
const valuesClauses = [];
|
|
@@ -1461,7 +1521,7 @@ class DbEntityTable {
|
|
|
1461
1521
|
if (!returningClause) {
|
|
1462
1522
|
return undefined;
|
|
1463
1523
|
}
|
|
1464
|
-
return this.mapReturningResults(result.rows,
|
|
1524
|
+
return this.mapReturningResults(result.rows, returningClause.aliasToProperty);
|
|
1465
1525
|
}
|
|
1466
1526
|
/**
|
|
1467
1527
|
* Upsert with advanced configuration
|
|
@@ -1669,7 +1729,7 @@ class DbEntityTable {
|
|
|
1669
1729
|
if (!returningClause) {
|
|
1670
1730
|
return undefined;
|
|
1671
1731
|
}
|
|
1672
|
-
return this.mapReturningResults(result.rows,
|
|
1732
|
+
return this.mapReturningResults(result.rows, returningClause.aliasToProperty);
|
|
1673
1733
|
}
|
|
1674
1734
|
/**
|
|
1675
1735
|
* Map database column names back to property names
|
|
@@ -1752,8 +1812,10 @@ class DbEntityTable {
|
|
|
1752
1812
|
throw new Error('No valid columns to update');
|
|
1753
1813
|
}
|
|
1754
1814
|
// No WHERE clause - updates all records
|
|
1755
|
-
// Build RETURNING clause
|
|
1756
|
-
const returningClause =
|
|
1815
|
+
// Build RETURNING clause (not needed for count-only)
|
|
1816
|
+
const returningClause = returning !== 'count'
|
|
1817
|
+
? table.buildReturningClause(returning)
|
|
1818
|
+
: undefined;
|
|
1757
1819
|
const qualifiedTableName = table._getQualifiedTableName();
|
|
1758
1820
|
let sql = `UPDATE ${qualifiedTableName} SET ${setClauses.join(', ')}`;
|
|
1759
1821
|
if (returningClause) {
|
|
@@ -1762,15 +1824,26 @@ class DbEntityTable {
|
|
|
1762
1824
|
const result = executor
|
|
1763
1825
|
? await executor.query(sql, values)
|
|
1764
1826
|
: await client.query(sql, values);
|
|
1827
|
+
// Return affected count
|
|
1828
|
+
if (returning === 'count') {
|
|
1829
|
+
return result.rowCount ?? 0;
|
|
1830
|
+
}
|
|
1765
1831
|
if (!returningClause) {
|
|
1766
1832
|
return undefined;
|
|
1767
1833
|
}
|
|
1768
|
-
return table.mapReturningResults(result.rows,
|
|
1834
|
+
return table.mapReturningResults(result.rows, returningClause.aliasToProperty);
|
|
1769
1835
|
};
|
|
1770
1836
|
return {
|
|
1771
1837
|
then(onfulfilled, onrejected) {
|
|
1772
1838
|
return executeUpdate(undefined).then(onfulfilled, onrejected);
|
|
1773
1839
|
},
|
|
1840
|
+
affectedCount() {
|
|
1841
|
+
return {
|
|
1842
|
+
then(onfulfilled, onrejected) {
|
|
1843
|
+
return executeUpdate('count').then(onfulfilled, onrejected);
|
|
1844
|
+
}
|
|
1845
|
+
};
|
|
1846
|
+
},
|
|
1774
1847
|
returning(selector) {
|
|
1775
1848
|
const returningConfig = selector ?? true;
|
|
1776
1849
|
return {
|
|
@@ -1971,7 +2044,7 @@ WHERE ${whereClause}`.trim();
|
|
|
1971
2044
|
if (!returningClause) {
|
|
1972
2045
|
return undefined;
|
|
1973
2046
|
}
|
|
1974
|
-
return this.mapReturningResults(result.rows,
|
|
2047
|
+
return this.mapReturningResults(result.rows, returningClause.aliasToProperty);
|
|
1975
2048
|
}
|
|
1976
2049
|
/**
|
|
1977
2050
|
* Delete all records from the table
|
|
@@ -1991,11 +2064,14 @@ WHERE ${whereClause}`.trim();
|
|
|
1991
2064
|
const baseSql = `DELETE FROM ${qualifiedTableName}`;
|
|
1992
2065
|
const table = this;
|
|
1993
2066
|
const executeDelete = async (returningConfig) => {
|
|
1994
|
-
if (!returningConfig) {
|
|
2067
|
+
if (!returningConfig || returningConfig === 'count') {
|
|
1995
2068
|
const sql = baseSql;
|
|
1996
2069
|
const result = executor
|
|
1997
2070
|
? await executor.query(sql, [])
|
|
1998
2071
|
: await client.query(sql, []);
|
|
2072
|
+
if (returningConfig === 'count') {
|
|
2073
|
+
return result.rowCount ?? 0;
|
|
2074
|
+
}
|
|
1999
2075
|
return;
|
|
2000
2076
|
}
|
|
2001
2077
|
// Build RETURNING clause
|
|
@@ -2005,13 +2081,20 @@ WHERE ${whereClause}`.trim();
|
|
|
2005
2081
|
? await executor.query(sql, [])
|
|
2006
2082
|
: await client.query(sql, []);
|
|
2007
2083
|
if (returningClause && result.rows) {
|
|
2008
|
-
return table.mapReturningResults(result.rows,
|
|
2084
|
+
return table.mapReturningResults(result.rows, returningClause.aliasToProperty);
|
|
2009
2085
|
}
|
|
2010
2086
|
};
|
|
2011
2087
|
const fluent = {
|
|
2012
2088
|
then: (resolve, reject) => {
|
|
2013
2089
|
return executeDelete().then(resolve, reject);
|
|
2014
2090
|
},
|
|
2091
|
+
affectedCount: () => {
|
|
2092
|
+
return {
|
|
2093
|
+
then: (resolve, reject) => {
|
|
2094
|
+
return executeDelete('count').then(resolve, reject);
|
|
2095
|
+
}
|
|
2096
|
+
};
|
|
2097
|
+
},
|
|
2015
2098
|
returning: ((selector) => {
|
|
2016
2099
|
const returningConfig = selector ?? true;
|
|
2017
2100
|
return {
|
|
@@ -2090,14 +2173,20 @@ WHERE ${whereClause}`.trim();
|
|
|
2090
2173
|
if (typeof selection === 'object' && selection !== null) {
|
|
2091
2174
|
const columns = [];
|
|
2092
2175
|
const sqlParts = [];
|
|
2176
|
+
const aliasToProperty = new Map();
|
|
2093
2177
|
for (const [alias, field] of Object.entries(selection)) {
|
|
2094
2178
|
if (field && typeof field === 'object' && '__dbColumnName' in field) {
|
|
2095
2179
|
const dbName = field.__dbColumnName;
|
|
2180
|
+
const propName = field.__fieldName; // Property name on entity
|
|
2096
2181
|
columns.push(alias);
|
|
2097
2182
|
sqlParts.push(`${prefix}"${dbName}" AS "${alias}"`);
|
|
2183
|
+
// Track alias -> property name mapping for mapper lookup
|
|
2184
|
+
if (propName) {
|
|
2185
|
+
aliasToProperty.set(alias, propName);
|
|
2186
|
+
}
|
|
2098
2187
|
}
|
|
2099
2188
|
}
|
|
2100
|
-
return { sql: sqlParts.join(', '), columns };
|
|
2189
|
+
return { sql: sqlParts.join(', '), columns, aliasToProperty };
|
|
2101
2190
|
}
|
|
2102
2191
|
// Single field selection
|
|
2103
2192
|
if (selection && typeof selection === 'object' && '__dbColumnName' in selection) {
|
|
@@ -2107,33 +2196,50 @@ WHERE ${whereClause}`.trim();
|
|
|
2107
2196
|
return null;
|
|
2108
2197
|
}
|
|
2109
2198
|
/**
|
|
2110
|
-
* Map row results
|
|
2199
|
+
* Map row results applying custom mappers
|
|
2111
2200
|
* @internal
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2201
|
+
* @param rows - Raw database rows
|
|
2202
|
+
* @param aliasToProperty - Optional mapping from result aliases to entity property names.
|
|
2203
|
+
* If undefined, assumes full entity mapping (db column names -> property names)
|
|
2204
|
+
*/
|
|
2205
|
+
mapReturningResults(rows, aliasToProperty) {
|
|
2206
|
+
// If no alias mapping provided, use full entity mapping
|
|
2207
|
+
// This handles the `returning === true` case where we want proper db column -> property name mapping
|
|
2208
|
+
if (!aliasToProperty || aliasToProperty.size === 0) {
|
|
2116
2209
|
return this.mapResultsToEntities(rows);
|
|
2117
2210
|
}
|
|
2118
|
-
// For selector functions, rows are already in the correct shape
|
|
2119
|
-
// Just apply any type mappers needed
|
|
2120
2211
|
const schema = this._getSchema();
|
|
2121
2212
|
return rows.map(row => {
|
|
2122
2213
|
const mapped = {};
|
|
2123
2214
|
for (const [key, value] of Object.entries(row)) {
|
|
2124
|
-
//
|
|
2125
|
-
const
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
2130
|
-
|
|
2131
|
-
|
|
2132
|
-
|
|
2133
|
-
|
|
2215
|
+
// Check if this key is an alias that maps to a property name
|
|
2216
|
+
const propName = aliasToProperty.get(key);
|
|
2217
|
+
if (propName) {
|
|
2218
|
+
// Found via alias mapping - use the property name to look up the column
|
|
2219
|
+
const colBuilder = schema.columns[propName];
|
|
2220
|
+
if (colBuilder) {
|
|
2221
|
+
const config = colBuilder.build();
|
|
2222
|
+
// Apply fromDriver mapper if present
|
|
2223
|
+
mapped[key] = config.mapper ? config.mapper.fromDriver(value) : value;
|
|
2224
|
+
}
|
|
2225
|
+
else {
|
|
2226
|
+
mapped[key] = value;
|
|
2227
|
+
}
|
|
2134
2228
|
}
|
|
2135
2229
|
else {
|
|
2136
|
-
|
|
2230
|
+
// Try to find column by direct property name or db column name match
|
|
2231
|
+
const colEntry = Object.entries(schema.columns).find(([pName, col]) => {
|
|
2232
|
+
const config = col.build();
|
|
2233
|
+
return pName === key || config.name === key;
|
|
2234
|
+
});
|
|
2235
|
+
if (colEntry) {
|
|
2236
|
+
const config = colEntry[1].build();
|
|
2237
|
+
// Apply fromDriver mapper if present
|
|
2238
|
+
mapped[key] = config.mapper ? config.mapper.fromDriver(value) : value;
|
|
2239
|
+
}
|
|
2240
|
+
else {
|
|
2241
|
+
mapped[key] = value;
|
|
2242
|
+
}
|
|
2137
2243
|
}
|
|
2138
2244
|
}
|
|
2139
2245
|
return mapped;
|