@rebasepro/server-postgres 0.19.2-canary.g201749f → 0.19.2-canary.g2cd43e9
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/index.es.js +47 -10
- package/dist/index.es.js.map +1 -1
- package/dist/services/row-pipeline.d.ts +12 -3
- package/package.json +7 -7
package/dist/index.es.js
CHANGED
|
@@ -2537,12 +2537,49 @@ function coerceDeclaredNumber(value, property) {
|
|
|
2537
2537
|
const parsed = parseFloat(value);
|
|
2538
2538
|
return isNaN(parsed) ? null : parsed;
|
|
2539
2539
|
}
|
|
2540
|
-
/**
|
|
2541
|
-
|
|
2540
|
+
/**
|
|
2541
|
+
* Serve a `date` column as the timestamp this API says it serves.
|
|
2542
|
+
*
|
|
2543
|
+
* The OpenAPI document this server publishes types a `date` property as
|
|
2544
|
+
* `string, format: date-time` — RFC 3339 — and node-postgres hands over the
|
|
2545
|
+
* Postgres literal: `"2026-08-24 01:37:57.647+02"`, with a space where the `T`
|
|
2546
|
+
* belongs and a two-digit offset. V8 parses that by accident; Safari's
|
|
2547
|
+
* `new Date()` does not have to, and the spec never promised it. A column whose
|
|
2548
|
+
* documented type only parses in some browsers is not a contract.
|
|
2549
|
+
*
|
|
2550
|
+
* A date-only column (`mode: "date"`, `format: "date"` in the spec) is already
|
|
2551
|
+
* RFC 3339 as `YYYY-MM-DD` and is left alone — widening it to a timestamp would
|
|
2552
|
+
* invent a time of day and a timezone the column does not have.
|
|
2553
|
+
*/
|
|
2554
|
+
function toRestDate(value) {
|
|
2555
|
+
if (value instanceof Date) return isNaN(value.getTime()) ? null : value.toISOString();
|
|
2556
|
+
if (value && typeof value === "object" && value.__type === "date") return value.value ?? null;
|
|
2557
|
+
if (typeof value !== "string" && typeof value !== "number") return value;
|
|
2558
|
+
if (typeof value === "string" && /^\d{4}-\d{2}-\d{2}$/.test(value)) return value;
|
|
2559
|
+
const date = new Date(value);
|
|
2560
|
+
return isNaN(date.getTime()) ? value : date.toISOString();
|
|
2561
|
+
}
|
|
2562
|
+
/**
|
|
2563
|
+
* One scalar, as REST serves it: declared numbers as numbers, declared dates as
|
|
2564
|
+
* RFC 3339, everything else exactly as the database returned it.
|
|
2565
|
+
*/
|
|
2566
|
+
function toRestScalar(value, property) {
|
|
2567
|
+
if (property?.type === "date") return toRestDate(value);
|
|
2568
|
+
return coerceDeclaredNumber(value, property);
|
|
2569
|
+
}
|
|
2570
|
+
/**
|
|
2571
|
+
* Apply {@link toRestScalar} across a row, leaving undeclared columns alone.
|
|
2572
|
+
*
|
|
2573
|
+
* Exported because the include loader attaches related rows itself, and a
|
|
2574
|
+
* target rendered differently from its parent is the shape bug this whole file
|
|
2575
|
+
* exists to prevent — a date was a string at the top level and a
|
|
2576
|
+
* `{ __type: "date" }` envelope one level down, in the same response.
|
|
2577
|
+
*/
|
|
2578
|
+
function toRestValues(row, collection) {
|
|
2542
2579
|
const properties = collection.properties;
|
|
2543
2580
|
if (!properties) return row;
|
|
2544
2581
|
const out = {};
|
|
2545
|
-
for (const [key, value] of Object.entries(row)) out[key] =
|
|
2582
|
+
for (const [key, value] of Object.entries(row)) out[key] = toRestScalar(value, properties[key]);
|
|
2546
2583
|
return out;
|
|
2547
2584
|
}
|
|
2548
2585
|
/** Render one target row in the requested style. */
|
|
@@ -2588,7 +2625,7 @@ function stripUnreadable(row, collection) {
|
|
|
2588
2625
|
return row;
|
|
2589
2626
|
}
|
|
2590
2627
|
function renderTarget(targetRow, targetCollection, style, registry) {
|
|
2591
|
-
if (style === "inline") return stripUnreadable(
|
|
2628
|
+
if (style === "inline") return stripUnreadable(toRestValues({ ...targetRow }, targetCollection), targetCollection);
|
|
2592
2629
|
const address = relationTargetAddress(targetRow, targetCollection, registry);
|
|
2593
2630
|
const path = targetCollection.slug;
|
|
2594
2631
|
return createRelationRefWithData(address, path, {
|
|
@@ -2638,9 +2675,9 @@ function toFlatRow(row, collection, registry) {
|
|
|
2638
2675
|
*
|
|
2639
2676
|
* Values are the ones the database returned, except where that contradicts the
|
|
2640
2677
|
* declared type: a `number` property is served as a number (see
|
|
2641
|
-
* {@link coerceDeclaredNumber})
|
|
2642
|
-
*
|
|
2643
|
-
*
|
|
2678
|
+
* {@link coerceDeclaredNumber}) and a `date` as RFC 3339, which is what this
|
|
2679
|
+
* server's own OpenAPI document says a date column is (see
|
|
2680
|
+
* {@link toRestDate}).
|
|
2644
2681
|
*
|
|
2645
2682
|
* Keyed by the row rather than by the relation list — a REST fetch only loads
|
|
2646
2683
|
* the relations `include` asked for, so the row is the authority on which are
|
|
@@ -2653,7 +2690,7 @@ function toRestRow(row, collection, registry) {
|
|
|
2653
2690
|
const relation = findRelation(resolvedRelations, key);
|
|
2654
2691
|
if (relation && Array.isArray(value)) flat[key] = value.map((item) => renderTarget(isJunctionRelation(relation) ? unwrapJunctionRow(item) : item, relation.target(), "inline", registry));
|
|
2655
2692
|
else if (relation && typeof value === "object" && value !== null) flat[key] = renderTarget(value, relation.target(), "inline", registry);
|
|
2656
|
-
else flat[key] =
|
|
2693
|
+
else flat[key] = toRestScalar(value, collection.properties?.[key]);
|
|
2657
2694
|
}
|
|
2658
2695
|
return stripUnreadable(flat, collection);
|
|
2659
2696
|
}
|
|
@@ -3909,7 +3946,7 @@ var FetchService = class FetchService {
|
|
|
3909
3946
|
row[key] = null;
|
|
3910
3947
|
continue;
|
|
3911
3948
|
}
|
|
3912
|
-
const [shaped] = this.shapeRelatedRows([{ ...related.values }], node, targetCollection);
|
|
3949
|
+
const [shaped] = this.shapeRelatedRows([toRestValues({ ...related.values }, targetCollection)], node, targetCollection);
|
|
3913
3950
|
row[key] = shaped;
|
|
3914
3951
|
loaded.push(shaped);
|
|
3915
3952
|
}
|
|
@@ -3917,7 +3954,7 @@ var FetchService = class FetchService {
|
|
|
3917
3954
|
const results = await this.relationService.batchFetchRelatedEntitiesMany(collectionPath, rowIds, key, relation, narrow);
|
|
3918
3955
|
for (const row of addressable) {
|
|
3919
3956
|
const related = results.get(String(addressOf(row))) ?? [];
|
|
3920
|
-
const shaped = this.shapeRelatedRows(related.map((e) => ({ ...e.values })), node, targetCollection);
|
|
3957
|
+
const shaped = this.shapeRelatedRows(related.map((e) => toRestValues({ ...e.values }, targetCollection)), node, targetCollection);
|
|
3921
3958
|
row[key] = shaped;
|
|
3922
3959
|
loaded.push(...shaped);
|
|
3923
3960
|
}
|