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.
Files changed (36) hide show
  1. package/dist/database/postgres-client.d.ts.map +1 -1
  2. package/dist/database/postgres-client.js +25 -0
  3. package/dist/database/postgres-client.js.map +1 -1
  4. package/dist/entity/db-context.d.ts.map +1 -1
  5. package/dist/entity/db-context.js +1 -0
  6. package/dist/entity/db-context.js.map +1 -1
  7. package/dist/entity/model-config.d.ts +31 -0
  8. package/dist/entity/model-config.d.ts.map +1 -1
  9. package/dist/entity/model-config.js +40 -0
  10. package/dist/entity/model-config.js.map +1 -1
  11. package/dist/migration/db-schema-manager.d.ts +33 -0
  12. package/dist/migration/db-schema-manager.d.ts.map +1 -1
  13. package/dist/migration/db-schema-manager.js +72 -0
  14. package/dist/migration/db-schema-manager.js.map +1 -1
  15. package/dist/migration/dbsetting-sql.d.ts +66 -0
  16. package/dist/migration/dbsetting-sql.d.ts.map +1 -0
  17. package/dist/migration/dbsetting-sql.js +109 -0
  18. package/dist/migration/dbsetting-sql.js.map +1 -0
  19. package/dist/migration/migration-scaffold.d.ts.map +1 -1
  20. package/dist/migration/migration-scaffold.js +10 -0
  21. package/dist/migration/migration-scaffold.js.map +1 -1
  22. package/dist/query/future-query.d.ts +10 -2
  23. package/dist/query/future-query.d.ts.map +1 -1
  24. package/dist/query/future-query.js.map +1 -1
  25. package/dist/query/query-batch.d.ts.map +1 -1
  26. package/dist/query/query-batch.js +21 -8
  27. package/dist/query/query-batch.js.map +1 -1
  28. package/dist/query/query-builder.d.ts +22 -2
  29. package/dist/query/query-builder.d.ts.map +1 -1
  30. package/dist/query/query-builder.js +122 -49
  31. package/dist/query/query-builder.js.map +1 -1
  32. package/dist/query/union-builder.d.ts +12 -0
  33. package/dist/query/union-builder.d.ts.map +1 -1
  34. package/dist/query/union-builder.js +36 -0
  35. package/dist/query/union-builder.js.map +1 -1
  36. 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
- buildJsonRowReviver(selection) {
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' || !('__fieldName' in value)) {
1508
+ if (!value || typeof value !== 'object' || Array.isArray(value)) {
1484
1509
  continue;
1485
1510
  }
1486
- const config = this.resolveFieldColumnConfig(value);
1487
- if (!config) {
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
- if (config.type === 'timestamp' || config.type === 'timestamptz') {
1491
- revivals.push({ key, revive: (v) => (typeof v === 'string' ? new Date(v) : v) });
1492
- }
1493
- else if (config.type === 'date') {
1494
- revivals.push({
1495
- key,
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
- if (revivals.length === 0) {
1518
- return undefined;
1519
- }
1520
- return (row) => {
1521
- for (const { key, revive } of revivals) {
1522
- const value = row[key];
1523
- if (value !== null && value !== undefined) {
1524
- row[key] = revive(value);
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