linkgress-orm 0.4.49 → 0.4.52
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/postgres-client.d.ts.map +1 -1
- package/dist/database/postgres-client.js +25 -0
- package/dist/database/postgres-client.js.map +1 -1
- package/dist/entity/db-context.d.ts.map +1 -1
- package/dist/entity/db-context.js +1 -0
- package/dist/entity/db-context.js.map +1 -1
- package/dist/entity/model-config.d.ts +31 -0
- package/dist/entity/model-config.d.ts.map +1 -1
- package/dist/entity/model-config.js +40 -0
- package/dist/entity/model-config.js.map +1 -1
- package/dist/migration/db-schema-manager.d.ts +33 -0
- package/dist/migration/db-schema-manager.d.ts.map +1 -1
- package/dist/migration/db-schema-manager.js +72 -0
- package/dist/migration/db-schema-manager.js.map +1 -1
- package/dist/migration/dbsetting-sql.d.ts +66 -0
- package/dist/migration/dbsetting-sql.d.ts.map +1 -0
- package/dist/migration/dbsetting-sql.js +109 -0
- package/dist/migration/dbsetting-sql.js.map +1 -0
- package/dist/migration/migration-scaffold.d.ts.map +1 -1
- package/dist/migration/migration-scaffold.js +10 -0
- package/dist/migration/migration-scaffold.js.map +1 -1
- package/dist/query/future-query.d.ts +10 -2
- package/dist/query/future-query.d.ts.map +1 -1
- package/dist/query/future-query.js.map +1 -1
- package/dist/query/query-batch.d.ts.map +1 -1
- package/dist/query/query-batch.js +21 -8
- package/dist/query/query-batch.js.map +1 -1
- package/dist/query/query-builder.d.ts +22 -2
- package/dist/query/query-builder.d.ts.map +1 -1
- package/dist/query/query-builder.js +122 -49
- package/dist/query/query-builder.js.map +1 -1
- package/dist/query/union-builder.d.ts +12 -0
- package/dist/query/union-builder.d.ts.map +1 -1
- package/dist/query/union-builder.js +36 -0
- package/dist/query/union-builder.js.map +1 -1
- package/package.json +80 -80
|
@@ -1380,10 +1380,7 @@ class SelectQueryBuilder {
|
|
|
1380
1380
|
return this.transformResults(processedRows, selectionResult);
|
|
1381
1381
|
};
|
|
1382
1382
|
const future = new future_query_1.FutureQuery(sql, params, transformFn, this.client, this.executor);
|
|
1383
|
-
future._batchMeta =
|
|
1384
|
-
hasNestedPaths: nestedPaths.size > 0,
|
|
1385
|
-
reviveJsonRow: this.buildJsonRowReviver(selectionResult),
|
|
1386
|
-
};
|
|
1383
|
+
future._batchMeta = this.buildBatchMeta(selectionResult, nestedPaths.size > 0);
|
|
1387
1384
|
return future;
|
|
1388
1385
|
}
|
|
1389
1386
|
/**
|
|
@@ -1431,10 +1428,7 @@ class SelectQueryBuilder {
|
|
|
1431
1428
|
return this.transformResults(processedRows, selectionResult);
|
|
1432
1429
|
};
|
|
1433
1430
|
const future = new future_query_1.FutureSingleQuery(sql, params, transformFn, this.client, this.executor);
|
|
1434
|
-
future._batchMeta =
|
|
1435
|
-
hasNestedPaths: nestedPaths.size > 0,
|
|
1436
|
-
reviveJsonRow: this.buildJsonRowReviver(selectionResult),
|
|
1437
|
-
};
|
|
1431
|
+
future._batchMeta = this.buildBatchMeta(selectionResult, nestedPaths.size > 0);
|
|
1438
1432
|
return future;
|
|
1439
1433
|
}
|
|
1440
1434
|
/**
|
|
@@ -1476,56 +1470,135 @@ class SelectQueryBuilder {
|
|
|
1476
1470
|
* Returns undefined when no selected column needs revival.
|
|
1477
1471
|
* @internal
|
|
1478
1472
|
*/
|
|
1479
|
-
|
|
1473
|
+
buildBatchMeta(selection, hasNestedPaths) {
|
|
1480
1474
|
const revivals = [];
|
|
1475
|
+
const textColumns = [];
|
|
1476
|
+
this.collectJsonRowRevivals(selection, undefined, revivals, textColumns);
|
|
1477
|
+
const reviveJsonRow = revivals.length === 0
|
|
1478
|
+
? undefined
|
|
1479
|
+
: (row) => {
|
|
1480
|
+
for (const { key, revive } of revivals) {
|
|
1481
|
+
const value = row[key];
|
|
1482
|
+
if (value !== null && value !== undefined) {
|
|
1483
|
+
row[key] = revive(value);
|
|
1484
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
return row;
|
|
1487
|
+
};
|
|
1488
|
+
return {
|
|
1489
|
+
hasNestedPaths,
|
|
1490
|
+
reviveJsonRow,
|
|
1491
|
+
textColumns: textColumns.length > 0 ? textColumns : undefined,
|
|
1492
|
+
};
|
|
1493
|
+
}
|
|
1494
|
+
/**
|
|
1495
|
+
* Walk a selection — including nested-object projections — collecting revival
|
|
1496
|
+
* entries keyed by the FLAT column alias each leaf is delivered under: top-level
|
|
1497
|
+
* keys as-is, nested leaves under the `__nested__<path>__<leaf>` path-encoded
|
|
1498
|
+
* alias that tryBuildFlatNestedSelect emits (revival runs BEFORE nested
|
|
1499
|
+
* reconstruction, so it must target the flat row shape). Only plain object
|
|
1500
|
+
* literals are recursed into; collections, SqlFragments and subquery builders
|
|
1501
|
+
* are skipped — they are delivered as json under standalone execution too, so
|
|
1502
|
+
* they need no revival.
|
|
1503
|
+
* @internal
|
|
1504
|
+
*/
|
|
1505
|
+
collectJsonRowRevivals(selection, pathPrefix, revivals, textColumns) {
|
|
1481
1506
|
for (const key in selection) {
|
|
1482
1507
|
const value = selection[key];
|
|
1483
|
-
if (!value || typeof value !== 'object' ||
|
|
1508
|
+
if (!value || typeof value !== 'object' || Array.isArray(value)) {
|
|
1484
1509
|
continue;
|
|
1485
1510
|
}
|
|
1486
|
-
|
|
1487
|
-
|
|
1511
|
+
if ('__fieldName' in value) {
|
|
1512
|
+
const config = this.resolveFieldColumnConfig(value);
|
|
1513
|
+
if (!config) {
|
|
1514
|
+
continue;
|
|
1515
|
+
}
|
|
1516
|
+
const flatKey = pathPrefix ? `${pathPrefix}__${key}` : key;
|
|
1517
|
+
// A custom fromDriver mapper is the column's type authority: it was
|
|
1518
|
+
// written against the driver's RAW output (apps like gopass configure
|
|
1519
|
+
// timestamp parser passthrough, so their mappers expect the
|
|
1520
|
+
// text-protocol string). For mapper columns, revival reconstructs that
|
|
1521
|
+
// text form — json's ISO 'T' separator back to the driver's space, a
|
|
1522
|
+
// timestamptz's ':00' offset minutes collapsed to the driver's short
|
|
1523
|
+
// form — and never hands the mapper a Date it does not expect.
|
|
1524
|
+
const hasMapper = config.mapper != null;
|
|
1525
|
+
if (config.type === 'timestamp') {
|
|
1526
|
+
revivals.push(hasMapper
|
|
1527
|
+
? { key: flatKey, revive: (v) => (typeof v === 'string' ? v.replace('T', ' ') : v) }
|
|
1528
|
+
: { key: flatKey, revive: (v) => (typeof v === 'string' ? new Date(v) : v) });
|
|
1529
|
+
}
|
|
1530
|
+
else if (config.type === 'timestamptz') {
|
|
1531
|
+
revivals.push(hasMapper
|
|
1532
|
+
? { key: flatKey, revive: (v) => (typeof v === 'string' ? v.replace('T', ' ').replace(/([+-]\d{2}):00$/, '$1') : v) }
|
|
1533
|
+
: { key: flatKey, revive: (v) => (typeof v === 'string' ? new Date(v) : v) });
|
|
1534
|
+
}
|
|
1535
|
+
else if (config.type === 'date') {
|
|
1536
|
+
if (hasMapper) {
|
|
1537
|
+
// json 'YYYY-MM-DD' IS the driver text form — the mapper gets it as-is.
|
|
1538
|
+
continue;
|
|
1539
|
+
}
|
|
1540
|
+
revivals.push({
|
|
1541
|
+
key: flatKey,
|
|
1542
|
+
revive: (v) => {
|
|
1543
|
+
if (typeof v !== 'string') {
|
|
1544
|
+
return v;
|
|
1545
|
+
}
|
|
1546
|
+
// Mirror the drivers' date parsing: local midnight, not UTC
|
|
1547
|
+
const [year, month, day] = v.split('-').map(Number);
|
|
1548
|
+
return new Date(year, month - 1, day);
|
|
1549
|
+
},
|
|
1550
|
+
});
|
|
1551
|
+
}
|
|
1552
|
+
else if (config.type === 'decimal' || config.type === 'numeric' || config.type === 'bigint') {
|
|
1553
|
+
// Values of these types can exceed float53 precision, and JSON.parse
|
|
1554
|
+
// silently collapses arbitrary-precision JSON numerals to floats —
|
|
1555
|
+
// unrecoverable here. The batch therefore casts them ::text
|
|
1556
|
+
// server-side (see the envelope in query-batch.ts); these fallback
|
|
1557
|
+
// revivals only normalize a NUMBER that slipped through (older
|
|
1558
|
+
// metadata without textColumns) and no-op on the cast strings.
|
|
1559
|
+
textColumns.push(flatKey);
|
|
1560
|
+
const scale = config.scale;
|
|
1561
|
+
revivals.push({
|
|
1562
|
+
key: flatKey,
|
|
1563
|
+
revive: (v) => (typeof v === 'number' ? (scale != null && config.type !== 'bigint' ? v.toFixed(scale) : String(v)) : v),
|
|
1564
|
+
});
|
|
1565
|
+
}
|
|
1566
|
+
else if (config.type === 'bytea') {
|
|
1567
|
+
// Driver delivery is a byte buffer; row_to_json emits the '\x…' hex text.
|
|
1568
|
+
revivals.push({
|
|
1569
|
+
key: flatKey,
|
|
1570
|
+
revive: (v) => {
|
|
1571
|
+
if (typeof v !== 'string' || !v.startsWith('\\x')) {
|
|
1572
|
+
return v;
|
|
1573
|
+
}
|
|
1574
|
+
const hex = v.slice(2);
|
|
1575
|
+
const bufferCtor = globalThis.Buffer;
|
|
1576
|
+
return bufferCtor
|
|
1577
|
+
? bufferCtor.from(hex, 'hex')
|
|
1578
|
+
: Uint8Array.from(hex.match(/../g)?.map((pair) => parseInt(pair, 16)) ?? []);
|
|
1579
|
+
},
|
|
1580
|
+
});
|
|
1581
|
+
}
|
|
1488
1582
|
continue;
|
|
1489
1583
|
}
|
|
1490
|
-
|
|
1491
|
-
|
|
1492
|
-
|
|
1493
|
-
|
|
1494
|
-
|
|
1495
|
-
|
|
1496
|
-
revive: (v) => {
|
|
1497
|
-
if (typeof v !== 'string') {
|
|
1498
|
-
return v;
|
|
1499
|
-
}
|
|
1500
|
-
// Mirror the drivers' date parsing: local midnight, not UTC
|
|
1501
|
-
const [year, month, day] = v.split('-').map(Number);
|
|
1502
|
-
return new Date(year, month - 1, day);
|
|
1503
|
-
},
|
|
1504
|
-
});
|
|
1505
|
-
}
|
|
1506
|
-
else if (config.type === 'decimal' || config.type === 'numeric') {
|
|
1507
|
-
const scale = config.scale;
|
|
1508
|
-
revivals.push({
|
|
1509
|
-
key,
|
|
1510
|
-
revive: (v) => (typeof v === 'number' ? (scale != null ? v.toFixed(scale) : String(v)) : v),
|
|
1511
|
-
});
|
|
1512
|
-
}
|
|
1513
|
-
else if (config.type === 'bigint') {
|
|
1514
|
-
revivals.push({ key, revive: (v) => (typeof v === 'number' ? String(v) : v) });
|
|
1584
|
+
// Recurse only into plain object literals — the nested-object projections
|
|
1585
|
+
// tryBuildFlatNestedSelect flattens. Class instances (collections, SqlFragment,
|
|
1586
|
+
// Subquery) and collection-result markers must not be walked.
|
|
1587
|
+
const proto = Object.getPrototypeOf(value);
|
|
1588
|
+
if ((proto === Object.prototype || proto === null) && !('__collectionResult' in value)) {
|
|
1589
|
+
this.collectJsonRowRevivals(value, pathPrefix ? `${pathPrefix}__${key}` : `__nested__${key}`, revivals, textColumns);
|
|
1515
1590
|
}
|
|
1516
1591
|
}
|
|
1517
|
-
|
|
1518
|
-
|
|
1519
|
-
|
|
1520
|
-
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
return row;
|
|
1528
|
-
};
|
|
1592
|
+
}
|
|
1593
|
+
/**
|
|
1594
|
+
* Union-leg hook: builds the full batch metadata (reviver + text-cast column
|
|
1595
|
+
* aliases) for a previously consumed union selection so
|
|
1596
|
+
* UnionQueryBuilder.future() can attach it. Same mechanics as the standalone
|
|
1597
|
+
* future factories.
|
|
1598
|
+
* @internal
|
|
1599
|
+
*/
|
|
1600
|
+
_buildUnionBatchMeta(selectionResult, hasNestedPaths) {
|
|
1601
|
+
return this.buildBatchMeta(selectionResult, hasNestedPaths);
|
|
1529
1602
|
}
|
|
1530
1603
|
/**
|
|
1531
1604
|
* Resolve the declared column config for a selected FieldRef: base table
|