joist-core 2.4.0-next.45 → 2.4.0-next.46
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/build/drivers/EntityWriter.cjs.map +1 -1
- package/build/drivers/EntityWriter.d.cts +12 -0
- package/build/drivers/EntityWriter.d.cts.map +1 -1
- package/build/drivers/EntityWriter.d.mts +12 -0
- package/build/drivers/EntityWriter.d.mts.map +1 -1
- package/build/drivers/EntityWriter.js.map +1 -1
- package/build/queries/unnest.cjs +4 -5
- package/build/queries/unnest.cjs.map +1 -1
- package/build/queries/unnest.js +4 -5
- package/build/queries/unnest.js.map +1 -1
- package/build/serde/columns.cjs +3 -0
- package/build/serde/columns.cjs.map +1 -1
- package/build/serde/columns.d.cts +1 -0
- package/build/serde/columns.d.cts.map +1 -1
- package/build/serde/columns.d.mts +1 -0
- package/build/serde/columns.d.mts.map +1 -1
- package/build/serde/columns.js +3 -0
- package/build/serde/columns.js.map +1 -1
- package/build/serde/fieldSerde.cjs +3 -0
- package/build/serde/fieldSerde.cjs.map +1 -1
- package/build/serde/fieldSerde.d.cts +1 -0
- package/build/serde/fieldSerde.d.cts.map +1 -1
- package/build/serde/fieldSerde.d.mts +1 -0
- package/build/serde/fieldSerde.d.mts.map +1 -1
- package/build/serde/fieldSerde.js +3 -0
- package/build/serde/fieldSerde.js.map +1 -1
- package/build/serde/serde.cjs +25 -0
- package/build/serde/serde.cjs.map +1 -1
- package/build/serde/serde.d.cts +21 -0
- package/build/serde/serde.d.cts.map +1 -1
- package/build/serde/serde.d.mts +21 -0
- package/build/serde/serde.d.mts.map +1 -1
- package/build/serde/serde.js +25 -0
- package/build/serde/serde.js.map +1 -1
- package/build/serde/temporalMappers.cjs +8 -4
- package/build/serde/temporalMappers.cjs.map +1 -1
- package/build/serde/temporalMappers.d.cts.map +1 -1
- package/build/serde/temporalMappers.d.mts.map +1 -1
- package/build/serde/temporalMappers.js +8 -4
- package/build/serde/temporalMappers.js.map +1 -1
- package/package.json +2 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fieldSerde.js","names":[],"sources":["../../src/serde/fieldSerde.ts"],"sourcesContent":["import { getConstructorFromTaggedId } from \"src/configure.ts\";\nimport type { InsertFixup } from \"src/drivers/EntityWriter.ts\";\nimport { type Entity, isEntity } from \"src/Entity.ts\";\nimport {\n type EntityMetadata,\n type Field,\n type PolymorphicField,\n type PolymorphicFieldComponent,\n type SerdeField,\n getBaseMeta,\n getMetadata,\n} from \"src/EntityMetadata.ts\";\nimport { maybeResolveReferenceToId } from \"src/keys.ts\";\nimport type { RowData } from \"src/RowData.ts\";\nimport type { Column } from \"src/serde/columns.ts\";\nimport type { TimestampCodec } from \"src/serde/serde.ts\";\nimport { groupBy } from \"src/utils.ts\";\n\nexport function hasSerde(field: Field): field is SerdeField {\n return !!field.serde;\n}\n\n/** Entity hydration and flush bindings; a polymorphic relationship spans several physical columns. */\nexport interface FieldSerde {\n columns: FieldColumn[];\n /** Decode one domain value from accessed cells; callers own entity assignment and caching. */\n fromRow(rowData: RowData, rowIndex: number): unknown;\n}\n\nexport interface TimestampSerde<T> extends FieldSerde {\n mapFromNow(now: Date): T;\n dbValue(data: any): any;\n}\n\n/** Binds a physical column to entity data without adding a second codec or storage declaration. */\nexport class FieldColumn {\n constructor(\n readonly fieldName: string,\n readonly column: Column,\n ) {}\n get codec() {\n return this.column.codec;\n }\n get insertOptional() {\n return this.column.insertOptional;\n }\n get writable() {\n return this.column.writable;\n }\n get insert() {\n return this.column.insert;\n }\n get update() {\n return this.column.update;\n }\n get idMetadata() {\n return this.column.idMetadata;\n }\n get columnName(): string {\n return this.column.columnName;\n }\n get dbType(): string {\n return this.column.dbType;\n }\n get isArray(): boolean {\n return this.column.isArray;\n }\n get isNullableArray(): boolean {\n return this.column.isNullableArray;\n }\n get sqlNullable(): boolean {\n return this.column.sqlNullable;\n }\n get hasDefault(): boolean {\n return this.column.hasDefault;\n }\n get isGenerated(): boolean {\n return this.column.isGenerated;\n }\n get outputType() {\n return this.column.outputType;\n }\n mapToDb(value: any): any {\n return this.column.mapToDb(value);\n }\n mapToDbValue(value: unknown): unknown {\n return this.column.mapToDbValue(value);\n }\n mapFromDb(value: unknown): unknown {\n return this.column.mapFromDb(value);\n }\n mapFromJsonAgg(value: any): any {\n return this.column.mapFromJsonAgg(value);\n }\n\n /** Defers FK writes whose new target must be inserted after this entity. */\n dbValue(data: any, entity: Entity, tableName: string, fixups: InsertFixup[] | undefined): any {\n const value = data[this.fieldName];\n if (\n this.column.idMetadata &&\n fixups &&\n isEntity(value) &&\n value.isNewEntity &&\n getMetadata(value).nonDeferredFkOrder &&\n getMetadata(entity).nonDeferredFkOrder &&\n getMetadata(value).nonDeferredFkOrder! >= getMetadata(entity).nonDeferredFkOrder!\n ) {\n fixups.push({ entity, tableName, column: this, value: this.mapToDbValue(maybeResolveReferenceToId(value)) });\n return null;\n }\n return this.mapToDbValue(value);\n }\n\n /** Reconstruct the driver's row representation, which can differ from write bindings for Date and JSON. */\n rowValue(data: any): any {\n return this.column.codec.mapToRow(data[this.fieldName]);\n }\n}\n\n/** Binds one entity field to its physical column. */\nexport class SimpleFieldSerde extends FieldColumn implements FieldSerde {\n readonly columns: FieldColumn[] = [this];\n /** Decode this field's physical column without changing entity data. */\n fromRow(rowData: RowData, rowIndex: number): unknown {\n return this.column.mapFromDb(rowData.get(rowIndex, this.column.columnName));\n }\n mapFromNow(now: Date): unknown {\n return (this.column.codec as TimestampCodec<unknown>).mapFromNow(now);\n }\n}\n\n/** A polymorphic field selects exactly one component while each physical column retains a scalar ID codec. */\nexport class PolymorphicKeySerde implements FieldSerde {\n readonly columns: PolymorphicFieldColumn[];\n constructor(\n readonly fieldName: string,\n components: PolymorphicFieldComponent[],\n ) {\n this.columns = components.map((component) => new PolymorphicFieldColumn(fieldName, component, components));\n }\n /** Select the first truthy component whose decoded ID is not nullish. */\n fromRow(rowData: RowData, rowIndex: number): unknown {\n let decoded: unknown;\n for (const column of this.columns) {\n const value = rowData.get(rowIndex, column.columnName);\n if (value) {\n decoded = column.mapFromDb(value);\n if (decoded != null) return decoded;\n }\n }\n return decoded;\n }\n}\n\n/** Shares domain components between relationship traversal and entity write selection. */\nexport function polymorphicField(\n fieldName: string,\n required: boolean,\n components: PolymorphicFieldComponent[],\n): PolymorphicField {\n return {\n kind: \"poly\",\n fieldName,\n fieldIdName: `${fieldName}Id`,\n required,\n components,\n serde: new PolymorphicKeySerde(fieldName, components),\n immutable: false,\n };\n}\n\n/** A domain relationship component references storage and only overrides a specialized domain target. */\nexport class PolyComponent implements PolymorphicFieldComponent {\n constructor(\n readonly column: Column,\n readonly otherFieldName: string,\n private readonly target?: () => EntityMetadata,\n ) {}\n get columnName(): string {\n return this.column.columnName;\n }\n get otherMetadata(): () => EntityMetadata {\n return this.target ?? this.column.idMetadata!;\n }\n}\n\n/** Selects a relationship component for entity writes only; direct SQL writes use its scalar column codec. */\nclass PolymorphicFieldColumn extends FieldColumn {\n constructor(\n fieldName: string,\n private readonly component: PolymorphicFieldComponent,\n private readonly components: PolymorphicFieldComponent[],\n ) {\n super(fieldName, component.column);\n }\n get otherMetadata() {\n return this.component.otherMetadata;\n }\n\n /** Preserve exact subtype selection when multiple components share a base type. */\n mapToDbValue(value: unknown): unknown {\n const id = maybeResolveReferenceToId(value as Parameters<typeof maybeResolveReferenceToId>[0]);\n const cstr = isEntity(value) ? getMetadata(value).cstr : id ? getConstructorFromTaggedId(id) : undefined;\n // If our poly has multiple components from the same base type, i.e.\n // `parent_small_publisher_id` and `parent_large_publisher_id`, then we\n // need slightly different logic...\n const hasMultipleComponentsWithSameBaseType = [\n ...groupBy(this.components, (component) => getBaseMeta(component.otherMetadata()).type).values(),\n ].some((group) => group.length > 1);\n const otherMeta = this.otherMetadata();\n // We'll have multiple columns, i.e. [parent_author_id, parent_book_id], and each column\n // will only return a value if the `id` matches its type, i.e. `parent_author_id=a:1` will\n // return 1, but `parent_book_id` will return null.\n const applies = hasMultipleComponentsWithSameBaseType\n ? cstr === otherMeta.cstr\n : cstr === otherMeta.cstr ||\n cstr === getBaseMeta(otherMeta).cstr ||\n otherMeta.subTypes.some((subTypeMeta) => cstr === subTypeMeta.cstr);\n return applies ? this.column.mapToDbValue(id) : undefined;\n }\n // Polymorphic writes historically do not schedule non-deferred FK fixups.\n dbValue(data: any): any {\n return this.mapToDbValue(data[this.fieldName]);\n }\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"fieldSerde.js","names":[],"sources":["../../src/serde/fieldSerde.ts"],"sourcesContent":["import { getConstructorFromTaggedId } from \"src/configure.ts\";\nimport type { InsertFixup } from \"src/drivers/EntityWriter.ts\";\nimport { type Entity, isEntity } from \"src/Entity.ts\";\nimport {\n type EntityMetadata,\n type Field,\n type PolymorphicField,\n type PolymorphicFieldComponent,\n type SerdeField,\n getBaseMeta,\n getMetadata,\n} from \"src/EntityMetadata.ts\";\nimport { maybeResolveReferenceToId } from \"src/keys.ts\";\nimport type { RowData } from \"src/RowData.ts\";\nimport type { Column } from \"src/serde/columns.ts\";\nimport type { TimestampCodec } from \"src/serde/serde.ts\";\nimport { groupBy } from \"src/utils.ts\";\n\nexport function hasSerde(field: Field): field is SerdeField {\n return !!field.serde;\n}\n\n/** Entity hydration and flush bindings; a polymorphic relationship spans several physical columns. */\nexport interface FieldSerde {\n columns: FieldColumn[];\n /** Decode one domain value from accessed cells; callers own entity assignment and caching. */\n fromRow(rowData: RowData, rowIndex: number): unknown;\n}\n\nexport interface TimestampSerde<T> extends FieldSerde {\n mapFromNow(now: Date): T;\n dbValue(data: any): any;\n}\n\n/** Binds a physical column to entity data without adding a second codec or storage declaration. */\nexport class FieldColumn {\n constructor(\n readonly fieldName: string,\n readonly column: Column,\n ) {}\n get codec() {\n return this.column.codec;\n }\n get insertOptional() {\n return this.column.insertOptional;\n }\n get writable() {\n return this.column.writable;\n }\n get insert() {\n return this.column.insert;\n }\n get update() {\n return this.column.update;\n }\n get idMetadata() {\n return this.column.idMetadata;\n }\n get columnName(): string {\n return this.column.columnName;\n }\n get dbType(): string {\n return this.column.dbType;\n }\n get isArray(): boolean {\n return this.column.isArray;\n }\n get isNullableArray(): boolean {\n return this.column.isNullableArray;\n }\n get notNullMarker(): unknown {\n return this.column.notNullMarker;\n }\n get sqlNullable(): boolean {\n return this.column.sqlNullable;\n }\n get hasDefault(): boolean {\n return this.column.hasDefault;\n }\n get isGenerated(): boolean {\n return this.column.isGenerated;\n }\n get outputType() {\n return this.column.outputType;\n }\n mapToDb(value: any): any {\n return this.column.mapToDb(value);\n }\n mapToDbValue(value: unknown): unknown {\n return this.column.mapToDbValue(value);\n }\n mapFromDb(value: unknown): unknown {\n return this.column.mapFromDb(value);\n }\n mapFromJsonAgg(value: any): any {\n return this.column.mapFromJsonAgg(value);\n }\n\n /** Defers FK writes whose new target must be inserted after this entity. */\n dbValue(data: any, entity: Entity, tableName: string, fixups: InsertFixup[] | undefined): any {\n const value = data[this.fieldName];\n if (\n this.column.idMetadata &&\n fixups &&\n isEntity(value) &&\n value.isNewEntity &&\n getMetadata(value).nonDeferredFkOrder &&\n getMetadata(entity).nonDeferredFkOrder &&\n getMetadata(value).nonDeferredFkOrder! >= getMetadata(entity).nonDeferredFkOrder!\n ) {\n fixups.push({ entity, tableName, column: this, value: this.mapToDbValue(maybeResolveReferenceToId(value)) });\n return null;\n }\n return this.mapToDbValue(value);\n }\n\n /** Reconstruct the driver's row representation, which can differ from write bindings for Date and JSON. */\n rowValue(data: any): any {\n return this.column.codec.mapToRow(data[this.fieldName]);\n }\n}\n\n/** Binds one entity field to its physical column. */\nexport class SimpleFieldSerde extends FieldColumn implements FieldSerde {\n readonly columns: FieldColumn[] = [this];\n /** Decode this field's physical column without changing entity data. */\n fromRow(rowData: RowData, rowIndex: number): unknown {\n return this.column.mapFromDb(rowData.get(rowIndex, this.column.columnName));\n }\n mapFromNow(now: Date): unknown {\n return (this.column.codec as TimestampCodec<unknown>).mapFromNow(now);\n }\n}\n\n/** A polymorphic field selects exactly one component while each physical column retains a scalar ID codec. */\nexport class PolymorphicKeySerde implements FieldSerde {\n readonly columns: PolymorphicFieldColumn[];\n constructor(\n readonly fieldName: string,\n components: PolymorphicFieldComponent[],\n ) {\n this.columns = components.map((component) => new PolymorphicFieldColumn(fieldName, component, components));\n }\n /** Select the first truthy component whose decoded ID is not nullish. */\n fromRow(rowData: RowData, rowIndex: number): unknown {\n let decoded: unknown;\n for (const column of this.columns) {\n const value = rowData.get(rowIndex, column.columnName);\n if (value) {\n decoded = column.mapFromDb(value);\n if (decoded != null) return decoded;\n }\n }\n return decoded;\n }\n}\n\n/** Shares domain components between relationship traversal and entity write selection. */\nexport function polymorphicField(\n fieldName: string,\n required: boolean,\n components: PolymorphicFieldComponent[],\n): PolymorphicField {\n return {\n kind: \"poly\",\n fieldName,\n fieldIdName: `${fieldName}Id`,\n required,\n components,\n serde: new PolymorphicKeySerde(fieldName, components),\n immutable: false,\n };\n}\n\n/** A domain relationship component references storage and only overrides a specialized domain target. */\nexport class PolyComponent implements PolymorphicFieldComponent {\n constructor(\n readonly column: Column,\n readonly otherFieldName: string,\n private readonly target?: () => EntityMetadata,\n ) {}\n get columnName(): string {\n return this.column.columnName;\n }\n get otherMetadata(): () => EntityMetadata {\n return this.target ?? this.column.idMetadata!;\n }\n}\n\n/** Selects a relationship component for entity writes only; direct SQL writes use its scalar column codec. */\nclass PolymorphicFieldColumn extends FieldColumn {\n constructor(\n fieldName: string,\n private readonly component: PolymorphicFieldComponent,\n private readonly components: PolymorphicFieldComponent[],\n ) {\n super(fieldName, component.column);\n }\n get otherMetadata() {\n return this.component.otherMetadata;\n }\n\n /** Preserve exact subtype selection when multiple components share a base type. */\n mapToDbValue(value: unknown): unknown {\n const id = maybeResolveReferenceToId(value as Parameters<typeof maybeResolveReferenceToId>[0]);\n const cstr = isEntity(value) ? getMetadata(value).cstr : id ? getConstructorFromTaggedId(id) : undefined;\n // If our poly has multiple components from the same base type, i.e.\n // `parent_small_publisher_id` and `parent_large_publisher_id`, then we\n // need slightly different logic...\n const hasMultipleComponentsWithSameBaseType = [\n ...groupBy(this.components, (component) => getBaseMeta(component.otherMetadata()).type).values(),\n ].some((group) => group.length > 1);\n const otherMeta = this.otherMetadata();\n // We'll have multiple columns, i.e. [parent_author_id, parent_book_id], and each column\n // will only return a value if the `id` matches its type, i.e. `parent_author_id=a:1` will\n // return 1, but `parent_book_id` will return null.\n const applies = hasMultipleComponentsWithSameBaseType\n ? cstr === otherMeta.cstr\n : cstr === otherMeta.cstr ||\n cstr === getBaseMeta(otherMeta).cstr ||\n otherMeta.subTypes.some((subTypeMeta) => cstr === subTypeMeta.cstr);\n return applies ? this.column.mapToDbValue(id) : undefined;\n }\n // Polymorphic writes historically do not schedule non-deferred FK fixups.\n dbValue(data: any): any {\n return this.mapToDbValue(data[this.fieldName]);\n }\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n}\n"],"mappings":"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"}
|
package/build/serde/serde.cjs
CHANGED
|
@@ -16,6 +16,11 @@ var CustomSerdeAdapter = class CustomSerdeAdapter {
|
|
|
16
16
|
this.mapper = mapper;
|
|
17
17
|
if (isArray !== void 0) this.isArray = isArray;
|
|
18
18
|
}
|
|
19
|
+
/** Return the unnest null/set marker as the physical db type. */
|
|
20
|
+
get notNullMarker() {
|
|
21
|
+
const seed = this.mapper.getUnnestMarker ? this.mapper.getUnnestMarker() : this.mapper.fromDb(defaultArrayElementMarker(this.dbType));
|
|
22
|
+
return this.mapToDbValue([seed])[0];
|
|
23
|
+
}
|
|
19
24
|
/** Only known adapters share their mapper's identity and elementwise array conversion. */
|
|
20
25
|
get outputType() {
|
|
21
26
|
if (this.isArray !== this.dbType.endsWith("[]") || this.constructor !== CustomSerdeAdapter && this.constructor !== PlainDateSerde && this.constructor !== PlainTimeSerde && this.constructor !== PlainDateTimeSerde && this.constructor !== ZonedDateTimeSerde) return;
|
|
@@ -70,6 +75,11 @@ var PrimitiveSerde = class PrimitiveSerde {
|
|
|
70
75
|
this.dbType = dbType;
|
|
71
76
|
this.isArray = isArray;
|
|
72
77
|
}
|
|
78
|
+
/** Return the unnest null/set marker as the physical db type. */
|
|
79
|
+
get notNullMarker() {
|
|
80
|
+
const seed = defaultArrayElementMarker(this.dbType);
|
|
81
|
+
return this.isArray ? this.mapToDbValue([seed])[0] : this.mapToDbValue(seed);
|
|
82
|
+
}
|
|
73
83
|
/** Exact-class checks prevent an unknown subclass's overridden converters from sharing this codec. */
|
|
74
84
|
get outputType() {
|
|
75
85
|
if (this.constructor !== PrimitiveSerde) return void 0;
|
|
@@ -335,6 +345,14 @@ var EnumArrayFieldSerde = class {
|
|
|
335
345
|
this.dbType = dbType;
|
|
336
346
|
this.enumObject = enumObject;
|
|
337
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* Return the unnest null/set marker as the physical db type.
|
|
350
|
+
*
|
|
351
|
+
* The marker is removed before enum IDs are stored, so it need not identify an enum row.
|
|
352
|
+
*/
|
|
353
|
+
get notNullMarker() {
|
|
354
|
+
return defaultArrayElementMarker(this.dbType);
|
|
355
|
+
}
|
|
338
356
|
/** Physical enum arrays reject null elements, unlike scalar enum arrayAgg; leave them unknown. */
|
|
339
357
|
get outputType() {}
|
|
340
358
|
/** Resolves each enum code to its stored id, retaining the entity's empty-array default. */
|
|
@@ -492,6 +510,13 @@ var ZodSerde = class ZodSerde {
|
|
|
492
510
|
return value === null ? value : value;
|
|
493
511
|
}
|
|
494
512
|
};
|
|
513
|
+
/** Return a default unnest null/set marker as the physical db type, before codec-specific conversion. */
|
|
514
|
+
function defaultArrayElementMarker(dbType) {
|
|
515
|
+
if (dbType.startsWith("varchar") || dbType.startsWith("character") || dbType.startsWith("text")) return "";
|
|
516
|
+
else if (dbType.startsWith("int")) return 1;
|
|
517
|
+
else if (dbType.startsWith("date") || dbType.startsWith("timestamp")) return /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
|
|
518
|
+
else throw new Error("Unhandled nullable array column type " + dbType);
|
|
519
|
+
}
|
|
495
520
|
/** PostgreSQL does not enforce declared array dimensions; reject nested values rather than coercing subarrays. */
|
|
496
521
|
function assertFlatNumericArray(value) {
|
|
497
522
|
if (Array.isArray(value) && value.some(Array.isArray)) throw new Error("Native numeric arrays must be one-dimensional");
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serde.cjs","names":["createRequire","canonicalDbType","arrayOutputType","plainDateMapper","plainTimeMapper","plainDateTimeMapper","getRuntimeConfig","requireTemporal","zonedDateTimeMapper","keyToNumber","maybeResolveReferenceToId","keyToTaggedId","isDefined"],"sources":["../../src/serde/serde.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\nimport { isDefined } from \"src/EntityManager.ts\";\nimport { keyToNumber, keyToTaggedId, maybeResolveReferenceToId } from \"src/keys.ts\";\nimport { getRuntimeConfig } from \"src/runtimeConfig.ts\";\nimport { type Temporal, requireTemporal } from \"src/serde/temporal.ts\";\nimport {\n plainDateMapper,\n plainDateTimeMapper,\n plainTimeMapper,\n zonedDateTimeMapper,\n} from \"src/serde/temporalMappers.ts\";\nimport { type TypeInfo, arrayOutputType, canonicalDbType } from \"src/serde/TypeInfo.ts\";\n\nconst runtimeRequire = createRequire(import.meta.url);\n\n/** Scalar conversion only: no field names, entity hydration, or FK fixups. */\nexport interface ScalarCodec {\n dbType: string;\n isArray: boolean;\n /** Compatibility evidence for scalar conversion, absent for unknown codecs. */\n readonly outputType?: TypeInfo;\n /** Encodes a domain value for a filter, i.e. an em.find WHERE parameter. */\n mapToDb(value: any): any;\n /**\n * Encodes a domain value for an INSERT or UPDATE binding.\n *\n * Callers must handle omission, SQL NULL, and SQL expressions before encoding. JSON null and\n * codec defaults can differ from SQL NULL. Direct mutations must validate reference targets\n * and reject new or unflushed entities before encoding.\n */\n mapToDbValue?(value: unknown): unknown;\n /** Converts a driver value to its domain value, including the codec's null/default handling. */\n mapFromDb(value: unknown): unknown;\n /**\n * Converts a json_agg cell to a driver-row value, not a domain value.\n *\n * Lazy field hydration subsequently calls mapFromDb. I.e. Date codecs reconstruct a Date\n * from the JSON string, while Temporal codecs retain the driver's string representation.\n */\n mapFromJsonAgg(value: any): any;\n /** Reconstructs a driver value from a domain value, not a SQL binding. */\n mapToRow(value: any): any;\n}\n\n/** Converts the ORM clock to the timestamp's domain representation. */\nexport interface TimestampCodec<T> extends ScalarCodec {\n mapFromNow(now: Date): T;\n}\n\n/**\n * Provides a simplified, public API for mapping between db/domain values.\n *\n * Joist's internal `FieldSerde` API is admittedly a little crufty, and so this\n * API is intended to be a simpler, more user-friendly way to define custom types.\n */\nexport interface CustomSerde<DomainType, DbType> {\n toDb(value: DomainType): DbType;\n fromDb(value: DbType): DomainType;\n}\n\nexport class CustomSerdeAdapter implements ScalarCodec {\n isArray: boolean = false;\n\n constructor(\n public dbType: string,\n private mapper: CustomSerde<any, any>,\n isArray?: boolean,\n ) {\n if (isArray !== undefined) this.isArray = isArray;\n }\n\n /** Only known adapters share their mapper's identity and elementwise array conversion. */\n get outputType(): TypeInfo | undefined {\n if (\n this.isArray !== this.dbType.endsWith(\"[]\") ||\n (this.constructor !== CustomSerdeAdapter &&\n this.constructor !== PlainDateSerde &&\n this.constructor !== PlainTimeSerde &&\n this.constructor !== PlainDateTimeSerde &&\n this.constructor !== ZonedDateTimeSerde)\n ) {\n return undefined;\n }\n const dbType = canonicalDbType(this.dbType);\n // A numeric mapper may require scalar text; classic pg decodes numeric[] elements as numbers.\n const elementType = this.isArray ? dbType.slice(0, -2) : dbType;\n const outputType = { dbType: elementType, domain: this.mapper, arrayElementSafe: elementType !== \"numeric\" };\n if (!this.isArray) return outputType;\n // Physical arrays pass null elements to the mapper, unlike scalar arrayAgg; keep their domains distinct.\n return arrayOutputType(outputType) || [\"date\", \"time\", \"timestamp\", \"timestamptz\"].includes(elementType)\n ? { dbType, domain: this.mapper }\n : undefined;\n }\n\n /** Encodes each physical array element once. */\n mapToDbValue(value: unknown): unknown {\n return value !== undefined\n ? this.isArray\n ? (value as readonly unknown[]).map((element) => this.mapper.toDb(element))\n : this.mapper.toDb(value)\n : undefined;\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any): any {\n return value === null\n ? value\n : this.isArray\n ? value.map((element: unknown) => this.mapper.toDb(element))\n : this.mapper.toDb(value);\n }\n\n /** Converts a driver value with the custom mapper, including array elements. */\n mapFromDb(value: unknown): unknown {\n const dbValue = maybeNullToUndefined(value);\n return dbValue !== undefined\n ? this.isArray\n ? dbValue.map((value: unknown) => this.mapper.fromDb(value))\n : this.mapper.fromDb(dbValue)\n : undefined;\n }\n\n mapFromJsonAgg(value: any): any {\n // Assume the database JSON value matches the ResultSet value\n return value;\n // return value === null\n // ? value\n // : this.isArray\n // ? value.map((value: any) => this.mapper.fromDb(value))\n // : this.mapper.fromDb(value);\n }\n}\n\n/**\n * Supports `string`, `int`, etc., as well as `string[]`, `int[]`, etc.\n *\n * This is not generally meant for subclassing, because it assumes things like\n * `string[]`s can be mapped 1:1. See `CustomSerdeAdapter` a good base class\n * that will handle converting individual elements.\n */\nexport class PrimitiveSerde implements ScalarCodec {\n constructor(\n public dbType: string,\n public isArray = false,\n ) {}\n\n /** Exact-class checks prevent an unknown subclass's overridden converters from sharing this codec. */\n get outputType(): TypeInfo | undefined {\n if (this.constructor !== PrimitiveSerde) return undefined;\n const dbType = canonicalDbType(this.dbType);\n const elementType = dbType.endsWith(\"[]\") ? dbType.slice(0, -2) : dbType;\n if (this.isArray !== dbType.endsWith(\"[]\")) return undefined;\n const outputType = {\n dbType: elementType,\n domain: primitiveOutputDomain(elementType),\n arrayElementSafe: elementType !== \"numeric\",\n };\n return this.isArray ? arrayOutputType(outputType) : outputType;\n }\n\n /** Primitive writes share their scalar/filter conversion, including subclass overrides. */\n mapToDbValue(value: unknown): unknown {\n return this.mapToDb(value);\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n /** Keeps driver values as-is, with SQL NULL represented as an unset entity field. */\n mapFromDb(value: unknown): unknown {\n return maybeNullToUndefined(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value;\n }\n}\n\nexport class DateSerde extends PrimitiveSerde implements TimestampCodec<Date> {\n /** Date bindings use ISO strings; mapToDb does not support physical Date arrays. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === DateSerde && !this.isArray && !this.dbType.endsWith(\"[]\")\n ? { dbType: canonicalDbType(this.dbType), domain: DateSerde }\n : undefined;\n }\n\n /** Accept the caller's date as-is. */\n mapFromNow(now: Date): Date {\n return now;\n }\n\n mapFromJsonAgg(value: any): any {\n if (value === null) return value;\n return new Date(value);\n }\n\n /**\n * Returns the `Date` a driver hands back on a read, and not `mapToDb`'s ISO string.\n *\n * Otherwise callers that round-trip a row through `rowValue` and back through `fromRow` (i.e.\n * `RunPlugin` mirroring writes into the test em) turn every date into a string, because our\n * `mapFromDb` returns the row value as-is.\n */\n mapToRow(value: any): any {\n return value;\n }\n\n mapToDb(value: Date) {\n // bun.sql needs this, node-pg does it out of the box\n return value?.toISOString();\n }\n}\n\n/** Converts `DATE`s `Temporal.PlainDate`s. */\nexport class PlainDateSerde extends CustomSerdeAdapter {\n constructor(dbType: string, isArray = false) {\n super(dbType, plainDateMapper, isArray);\n }\n}\n\n/** Converts `TIME`s to `Temporal.PlainTime`s. */\nexport class PlainTimeSerde extends CustomSerdeAdapter {\n constructor(dbType: string, isArray = false) {\n super(dbType, plainTimeMapper, isArray);\n }\n}\n\n/** Converts `TIMESTAMP`s to `Temporal.PlainDateTime`s. */\nexport class PlainDateTimeSerde extends CustomSerdeAdapter implements TimestampCodec<Temporal.PlainDateTime> {\n constructor(dbType: string, isArray = false) {\n super(dbType, plainDateTimeMapper, isArray);\n }\n\n mapFromNow(now: Date): Temporal.PlainDateTime {\n const { timeZone } = getRuntimeConfig().temporal as any;\n return requireTemporal().toTemporalInstant.call(now).toZonedDateTimeISO(timeZone).toPlainDateTime();\n }\n}\n\n/** Converts `TIMESTAMP WITH TIME ZONE`s to `Temporal.ZonedDateTime`s. */\nexport class ZonedDateTimeSerde extends CustomSerdeAdapter implements TimestampCodec<Temporal.ZonedDateTime> {\n constructor(dbType: string, isArray = false) {\n super(dbType, zonedDateTimeMapper, isArray);\n }\n\n mapFromNow(now: Date): Temporal.ZonedDateTime {\n const { timeZone } = getRuntimeConfig().temporal as any;\n return requireTemporal().toTemporalInstant.call(now).toZonedDateTimeISO(timeZone);\n }\n}\n\nexport class BigIntSerde implements ScalarCodec {\n dbType: string;\n\n constructor(public isArray = false) {\n this.dbType = isArray ? \"bigint[]\" : \"bigint\";\n }\n\n /** BigInt conversion is distinct from both the driver's int8 value and Number aggregates. */\n get outputType(): TypeInfo | undefined {\n if (this.constructor !== BigIntSerde) return undefined;\n const elementType = { dbType: \"int8\", domain: BigIntSerde, arrayElementSafe: true };\n return this.isArray ? arrayOutputType(elementType) : elementType;\n }\n\n /** Drivers accept native bigint values without conversion. */\n mapToDbValue(value: unknown): unknown {\n if (this.isArray) assertFlatNumericArray(value);\n return value;\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n /** Converts the driver's bigint representation to the entity value. */\n mapFromDb(value: unknown): unknown {\n const dbValue = maybeNullToUndefined(value);\n if (this.isArray && dbValue !== undefined) {\n assertFlatNumericArray(dbValue);\n return dbValue.map((element: string | bigint | number | null) => (element === null ? null : BigInt(element)));\n }\n return dbValue ? BigInt(dbValue) : dbValue;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : this.isArray ? this.mapFromDb(value) : BigInt(value);\n }\n}\n\n/**\n * Maps `decimal(...)` database types to the JS `number`.\n *\n * Note that we assume the db values are within the range of the JS `number`;\n * we should eventually sanity check that.\n *\n * Also note that knex/pg accept `number`s as input, so we only need\n * to handle from-database -> to JS translation.\n */\nexport class DecimalToNumberSerde implements ScalarCodec {\n dbType: string;\n\n constructor(public isArray = false) {\n this.dbType = isArray ? \"numeric[]\" : \"decimal\";\n }\n\n /** Numeric aggregates use the same Number conversion and identity binding encoder. */\n get outputType(): TypeInfo | undefined {\n if (this.constructor !== DecimalToNumberSerde) return undefined;\n const elementType = { dbType: \"numeric\", domain: Number, arrayElementSafe: true };\n return this.isArray ? arrayOutputType(elementType) : elementType;\n }\n\n /** Drivers accept decimal numbers without conversion. */\n mapToDbValue(value: unknown): unknown {\n if (this.isArray) assertFlatNumericArray(value);\n return value;\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n /** Converts a driver decimal value to a JavaScript number. */\n mapFromDb(value: unknown): unknown {\n const dbValue = maybeNullToUndefined(value);\n if (this.isArray && dbValue !== undefined) {\n assertFlatNumericArray(dbValue);\n return dbValue.map((element: string | number | null) => (element === null ? null : Number(element)));\n }\n return dbValue !== undefined ? Number(dbValue) : dbValue;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : this.isArray ? this.mapFromDb(value) : Number(value);\n }\n}\n\n/** Maps physical integer keys to logical string IDs \"because GraphQL\". */\nexport class KeySerde implements ScalarCodec {\n isArray = false;\n\n private meta: {\n tagName: string;\n idDbType: \"bigint\" | \"int\" | \"uuid\" | \"text\";\n };\n\n constructor(\n tagName: string,\n public dbType: \"bigint\" | \"int\" | \"uuid\" | \"text\",\n ) {\n this.meta = {\n tagName,\n idDbType: dbType,\n };\n }\n\n /** PKs and FKs share a tag and SQL representation; the alias supplies the exact target idMeta. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === KeySerde && !this.isArray\n ? { dbType: canonicalDbType(this.dbType), domain: `key:${this.meta.tagName}`, arrayElementSafe: true }\n : undefined;\n }\n\n /** Resolves references and tagged, untagged, or numeric ids using the column's tag and storage type. */\n mapToDbValue(value: unknown): unknown {\n return keyToNumber(\n this.meta,\n typeof value === \"number\"\n ? value\n : maybeResolveReferenceToId(value as Parameters<typeof maybeResolveReferenceToId>[0]),\n );\n }\n\n mapToRow(value: any): any {\n // we don't have any fixups since we are trying to recreate what comes out of the db, so this is safe\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n // Numeric IDs are already database values; tagged string IDs still need to be resolved and untagged.\n if (value === null || typeof value === \"number\") return value;\n // We go through `maybeResolveReferenceToId` because filters like `in: [a1, a2]` pass entities directly.\n return keyToNumber(this.meta, maybeResolveReferenceToId(value));\n }\n\n /** Converts a physical primary or foreign key to a tagged id. */\n mapFromDb(value: unknown): string | undefined {\n return keyToTaggedId(this.meta, value as string | number);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class EnumFieldSerde implements ScalarCodec {\n isArray = false;\n\n constructor(\n public dbType: \"int\" | \"uuid\",\n private enumObject: any,\n ) {}\n\n /** Separate fields of the same generated enum share its code/id mapping. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === EnumFieldSerde && !this.isArray\n ? { dbType: canonicalDbType(this.dbType), domain: this.enumObject, arrayElementSafe: true }\n : undefined;\n }\n\n /** Resolves the enum code to its stored id, leaving an unknown code unset. */\n mapToDbValue(value: unknown): unknown {\n return this.enumObject.findByCode(value)?.id;\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n return this.enumObject.findByCode(value)?.id;\n }\n\n /** Converts a stored enum id to its enum code. */\n mapFromDb(value: unknown): unknown {\n return this.enumObject.findById(value)?.code;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class EnumArrayFieldSerde implements ScalarCodec {\n isArray = true;\n\n constructor(\n public dbType: \"int[]\" | \"uuid[]\",\n private enumObject: any,\n ) {}\n\n /** Physical enum arrays reject null elements, unlike scalar enum arrayAgg; leave them unknown. */\n get outputType(): undefined {\n return undefined;\n }\n\n /** Resolves each enum code to its stored id, retaining the entity's empty-array default. */\n mapToDbValue(value: unknown): unknown {\n return (value as readonly unknown[] | null | undefined)?.map((code) => this.enumObject.getByCode(code).id) || [];\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n return !value ? [] : value.map((code: any) => this.enumObject.getByCode(code).id);\n }\n\n /** Converts stored enum ids to codes, defaulting an unset entity field to an empty array. */\n mapFromDb(value: unknown): unknown[] {\n return (value as readonly unknown[] | null | undefined)?.map((id) => this.enumObject.findById(id).code) || [];\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\n/** Similar to SimpleSerde, but applies the superstruct `assert` function when reading values from the db. */\nexport class SuperstructSerde implements ScalarCodec {\n dbType = \"jsonb\";\n isArray = false;\n\n // Use a dynamic require so that downstream projects don't have to depend on superstruct\n // until they want to, i.e. we don't have superstruct in the joist-orm package.json.\n private assert = runtimeRequire(\"superstruct\").assert;\n\n constructor(private superstruct: any) {}\n\n /** JSON schemas describe a jsonb value, even when that value is a JSON array. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === SuperstructSerde && !this.isArray\n ? { dbType: canonicalDbType(this.dbType), domain: this.superstruct, arrayElementSafe: true }\n : undefined;\n }\n\n /** Serializes the domain JSON value without running the read-time schema validation. */\n mapToDbValue(value: unknown): unknown {\n return JSON.stringify(value);\n }\n\n // JSON is returned by postgres already parsed, so we should just be able to return our data directly. Unlike with\n // JsonSerde, we can assume that superstruct would have parsed any complex types in the json correctly so we don't\n // need to do a round trip through JSON.stringify.\n mapToRow(value: any): any {\n return value;\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n /** Validates a driver JSON value with the field's Superstruct schema. */\n mapFromDb(value: unknown): unknown {\n const dbValue = maybeNullToUndefined(value);\n if (dbValue) this.assert(dbValue, this.superstruct);\n return dbValue;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class JsonSerde implements ScalarCodec {\n dbType = \"jsonb\";\n isArray = false;\n\n constructor() {}\n\n /** Unvalidated JSON uses its own encoder, not a primitive or schema-specific codec. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === JsonSerde && !this.isArray\n ? { dbType: canonicalDbType(this.dbType), domain: JsonSerde, arrayElementSafe: true }\n : undefined;\n }\n\n /** Serializes the whole JSON value, including JSON arrays and custom toJSON methods. */\n mapToDbValue(value: unknown): unknown {\n return JSON.stringify(value);\n }\n\n // JSON is returned by postgres already parsed, so if we are trying to recreate then we need to stringify, then parse.\n // It's necessary to do this instead of just returning the object directly because any complex types in the json need\n // to be stringified to correctly reflect the db value.\n mapToRow(value: any): any {\n const json = JSON.stringify(value);\n return isDefined(json) ? JSON.parse(json) : undefined;\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n /** Keeps the driver's parsed JSON value, normalizing SQL NULL for entity fields. */\n mapFromDb(value: unknown): unknown {\n return maybeNullToUndefined(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\n/**\n * Maps pgvector `vector(N)` columns to `number[]`s.\n *\n * pgvector has no pg array OID, so text results are its `[1,2,3]` literal, which is also valid\n * JSON (pgvector rejects NaN/Infinity elements). Writes send the same literal, which the batch\n * `unnest(?::vector[])` casts, because node-pg would otherwise encode a JS array as `{1,2,3}`.\n */\nexport class VectorSerde implements ScalarCodec {\n dbType = \"vector\";\n isArray = false;\n\n get outputType(): TypeInfo | undefined {\n return this.constructor === VectorSerde ? { dbType: this.dbType, domain: VectorSerde } : undefined;\n }\n\n mapToDbValue(value: unknown): unknown {\n return JSON.stringify(value);\n }\n\n mapToRow(value: any): any {\n return JSON.stringify(value);\n }\n\n mapToDb(value: any) {\n return value === null ? value : JSON.stringify(value);\n }\n\n /** Parses the text literal, and passes through arrays already decoded by the binary row path. */\n mapFromDb(value: unknown): unknown {\n return typeof value === \"string\" ? JSON.parse(value) : maybeNullToUndefined(value);\n }\n\n /** `to_json(vector)` falls back to the text literal, i.e. the same value as a driver row. */\n mapFromJsonAgg(value: any): any {\n return value;\n }\n}\n\n/** Similar to SimpleSerde, but applies the zod's `parse` function when reading values from the db. */\nexport class ZodSerde implements ScalarCodec {\n dbType = \"jsonb\";\n isArray = false;\n\n constructor(private zodSchema: any) {}\n\n /** Parsing and transformations are compatible only for the same schema object. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === ZodSerde && !this.isArray\n ? { dbType: canonicalDbType(this.dbType), domain: this.zodSchema, arrayElementSafe: true }\n : undefined;\n }\n\n /** Serializes the domain JSON value without running the read-time Zod parser or transforms. */\n mapToDbValue(value: unknown): unknown {\n return JSON.stringify(value);\n }\n\n // JSON is returned by postgres already parsed, so we should just be able to return our data directly. Unlike with\n // JsonSerde, we can assume that zod would have parsed any complex types in the json correctly so we don't need to\n // do a round trip through JSON.stringify.\n mapToRow(value: any): any {\n return value;\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n /** Parses a driver JSON value with the field's Zod schema. */\n mapFromDb(value: unknown): unknown {\n const dbValue = maybeNullToUndefined(value);\n return dbValue ? this.zodSchema.parse(dbValue) : dbValue;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\n/** PostgreSQL does not enforce declared array dimensions; reject nested values rather than coercing subarrays. */\nfunction assertFlatNumericArray(value: unknown): void {\n if (Array.isArray(value) && value.some(Array.isArray)) {\n throw new Error(\"Native numeric arrays must be one-dimensional\");\n }\n}\n\n/** Only driver-native numbers agree with Number aggregates; int8/numeric identity values do not. */\nfunction primitiveOutputDomain(dbType: string): unknown {\n switch (dbType) {\n case \"int2\":\n case \"int4\":\n case \"float4\":\n case \"float8\":\n return Number;\n case \"text\":\n case \"varchar\":\n case \"bpchar\":\n return String;\n default:\n return PrimitiveSerde;\n }\n}\n\n/** Normalizes SQL NULL to an unset entity field. */\nfunction maybeNullToUndefined(value: any): any {\n return value === null ? undefined : value;\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"serde.cjs","names":["createRequire","canonicalDbType","arrayOutputType","plainDateMapper","plainTimeMapper","plainDateTimeMapper","getRuntimeConfig","requireTemporal","zonedDateTimeMapper","keyToNumber","maybeResolveReferenceToId","keyToTaggedId","isDefined"],"sources":["../../src/serde/serde.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\nimport { isDefined } from \"src/EntityManager.ts\";\nimport { keyToNumber, keyToTaggedId, maybeResolveReferenceToId } from \"src/keys.ts\";\nimport { getRuntimeConfig } from \"src/runtimeConfig.ts\";\nimport { type Temporal, requireTemporal } from \"src/serde/temporal.ts\";\nimport {\n plainDateMapper,\n plainDateTimeMapper,\n plainTimeMapper,\n zonedDateTimeMapper,\n} from \"src/serde/temporalMappers.ts\";\nimport { type TypeInfo, arrayOutputType, canonicalDbType } from \"src/serde/TypeInfo.ts\";\n\nconst runtimeRequire = createRequire(import.meta.url);\n\n/** Scalar conversion only: no field names, entity hydration, or FK fixups. */\nexport interface ScalarCodec {\n dbType: string;\n isArray: boolean;\n /** The unnest null/set marker as the physical db type; never persisted in the column. */\n readonly notNullMarker?: unknown;\n /** Compatibility evidence for scalar conversion, absent for unknown codecs. */\n readonly outputType?: TypeInfo;\n /** Encodes a domain value for a filter, i.e. an em.find WHERE parameter. */\n mapToDb(value: any): any;\n /**\n * Encodes a domain value for an INSERT or UPDATE binding.\n *\n * Callers must handle omission, SQL NULL, and SQL expressions before encoding. JSON null and\n * codec defaults can differ from SQL NULL. Direct mutations must validate reference targets\n * and reject new or unflushed entities before encoding.\n */\n mapToDbValue?(value: unknown): unknown;\n /** Converts a driver value to its domain value, including the codec's null/default handling. */\n mapFromDb(value: unknown): unknown;\n /**\n * Converts a json_agg cell to a driver-row value, not a domain value.\n *\n * Lazy field hydration subsequently calls mapFromDb. I.e. Date codecs reconstruct a Date\n * from the JSON string, while Temporal codecs retain the driver's string representation.\n */\n mapFromJsonAgg(value: any): any;\n /** Reconstructs a driver value from a domain value, not a SQL binding. */\n mapToRow(value: any): any;\n}\n\n/** Converts the ORM clock to the timestamp's domain representation. */\nexport interface TimestampCodec<T> extends ScalarCodec {\n mapFromNow(now: Date): T;\n}\n\n/**\n * Provides a simplified, public API for mapping between db/domain values.\n *\n * Joist's internal `FieldSerde` API is admittedly a little crufty, and so this\n * API is intended to be a simpler, more user-friendly way to define custom types.\n */\nexport interface CustomSerde<DomainType, DbType> {\n toDb(value: DomainType): DbType;\n fromDb(value: DbType): DomainType;\n /**\n * Return a domain value for the unnest null/set marker, before conversion to the physical db type.\n *\n * Optional to preserve legacy serdes, including scalar serdes that never need markers.\n * Without this hook, the adapter passes a default physical db value through fromDb, then converts it\n * back with the normal array writer. Temporal mappers and restricted custom domains can provide an\n * accepted domain value instead.\n */\n getUnnestMarker?(): DomainType;\n}\n\nexport class CustomSerdeAdapter implements ScalarCodec {\n isArray: boolean = false;\n\n constructor(\n public dbType: string,\n private mapper: CustomSerde<any, any>,\n isArray?: boolean,\n ) {\n if (isArray !== undefined) this.isArray = isArray;\n }\n\n /** Return the unnest null/set marker as the physical db type. */\n get notNullMarker(): unknown {\n const seed = this.mapper.getUnnestMarker\n ? this.mapper.getUnnestMarker()\n : this.mapper.fromDb(defaultArrayElementMarker(this.dbType));\n return (this.mapToDbValue([seed]) as unknown[])[0];\n }\n\n /** Only known adapters share their mapper's identity and elementwise array conversion. */\n get outputType(): TypeInfo | undefined {\n if (\n this.isArray !== this.dbType.endsWith(\"[]\") ||\n (this.constructor !== CustomSerdeAdapter &&\n this.constructor !== PlainDateSerde &&\n this.constructor !== PlainTimeSerde &&\n this.constructor !== PlainDateTimeSerde &&\n this.constructor !== ZonedDateTimeSerde)\n ) {\n return undefined;\n }\n const dbType = canonicalDbType(this.dbType);\n // A numeric mapper may require scalar text; classic pg decodes numeric[] elements as numbers.\n const elementType = this.isArray ? dbType.slice(0, -2) : dbType;\n const outputType = { dbType: elementType, domain: this.mapper, arrayElementSafe: elementType !== \"numeric\" };\n if (!this.isArray) return outputType;\n // Physical arrays pass null elements to the mapper, unlike scalar arrayAgg; keep their domains distinct.\n return arrayOutputType(outputType) || [\"date\", \"time\", \"timestamp\", \"timestamptz\"].includes(elementType)\n ? { dbType, domain: this.mapper }\n : undefined;\n }\n\n /** Encodes each physical array element once. */\n mapToDbValue(value: unknown): unknown {\n return value !== undefined\n ? this.isArray\n ? (value as readonly unknown[]).map((element) => this.mapper.toDb(element))\n : this.mapper.toDb(value)\n : undefined;\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any): any {\n return value === null\n ? value\n : this.isArray\n ? value.map((element: unknown) => this.mapper.toDb(element))\n : this.mapper.toDb(value);\n }\n\n /** Converts a driver value with the custom mapper, including array elements. */\n mapFromDb(value: unknown): unknown {\n const dbValue = maybeNullToUndefined(value);\n return dbValue !== undefined\n ? this.isArray\n ? dbValue.map((value: unknown) => this.mapper.fromDb(value))\n : this.mapper.fromDb(dbValue)\n : undefined;\n }\n\n mapFromJsonAgg(value: any): any {\n // Assume the database JSON value matches the ResultSet value\n return value;\n // return value === null\n // ? value\n // : this.isArray\n // ? value.map((value: any) => this.mapper.fromDb(value))\n // : this.mapper.fromDb(value);\n }\n}\n\n/**\n * Supports `string`, `int`, etc., as well as `string[]`, `int[]`, etc.\n *\n * This is not generally meant for subclassing, because it assumes things like\n * `string[]`s can be mapped 1:1. See `CustomSerdeAdapter` a good base class\n * that will handle converting individual elements.\n */\nexport class PrimitiveSerde implements ScalarCodec {\n constructor(\n public dbType: string,\n public isArray = false,\n ) {}\n\n /** Return the unnest null/set marker as the physical db type. */\n get notNullMarker(): unknown {\n const seed = defaultArrayElementMarker(this.dbType);\n return this.isArray ? (this.mapToDbValue([seed]) as unknown[])[0] : this.mapToDbValue(seed);\n }\n\n /** Exact-class checks prevent an unknown subclass's overridden converters from sharing this codec. */\n get outputType(): TypeInfo | undefined {\n if (this.constructor !== PrimitiveSerde) return undefined;\n const dbType = canonicalDbType(this.dbType);\n const elementType = dbType.endsWith(\"[]\") ? dbType.slice(0, -2) : dbType;\n if (this.isArray !== dbType.endsWith(\"[]\")) return undefined;\n const outputType = {\n dbType: elementType,\n domain: primitiveOutputDomain(elementType),\n arrayElementSafe: elementType !== \"numeric\",\n };\n return this.isArray ? arrayOutputType(outputType) : outputType;\n }\n\n /** Primitive writes share their scalar/filter conversion, including subclass overrides. */\n mapToDbValue(value: unknown): unknown {\n return this.mapToDb(value);\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n /** Keeps driver values as-is, with SQL NULL represented as an unset entity field. */\n mapFromDb(value: unknown): unknown {\n return maybeNullToUndefined(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value;\n }\n}\n\nexport class DateSerde extends PrimitiveSerde implements TimestampCodec<Date> {\n /** Date bindings use ISO strings; mapToDb does not support physical Date arrays. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === DateSerde && !this.isArray && !this.dbType.endsWith(\"[]\")\n ? { dbType: canonicalDbType(this.dbType), domain: DateSerde }\n : undefined;\n }\n\n /** Accept the caller's date as-is. */\n mapFromNow(now: Date): Date {\n return now;\n }\n\n mapFromJsonAgg(value: any): any {\n if (value === null) return value;\n return new Date(value);\n }\n\n /**\n * Returns the `Date` a driver hands back on a read, and not `mapToDb`'s ISO string.\n *\n * Otherwise callers that round-trip a row through `rowValue` and back through `fromRow` (i.e.\n * `RunPlugin` mirroring writes into the test em) turn every date into a string, because our\n * `mapFromDb` returns the row value as-is.\n */\n mapToRow(value: any): any {\n return value;\n }\n\n mapToDb(value: Date) {\n // bun.sql needs this, node-pg does it out of the box\n return value?.toISOString();\n }\n}\n\n/** Converts `DATE`s `Temporal.PlainDate`s. */\nexport class PlainDateSerde extends CustomSerdeAdapter {\n constructor(dbType: string, isArray = false) {\n super(dbType, plainDateMapper, isArray);\n }\n}\n\n/** Converts `TIME`s to `Temporal.PlainTime`s. */\nexport class PlainTimeSerde extends CustomSerdeAdapter {\n constructor(dbType: string, isArray = false) {\n super(dbType, plainTimeMapper, isArray);\n }\n}\n\n/** Converts `TIMESTAMP`s to `Temporal.PlainDateTime`s. */\nexport class PlainDateTimeSerde extends CustomSerdeAdapter implements TimestampCodec<Temporal.PlainDateTime> {\n constructor(dbType: string, isArray = false) {\n super(dbType, plainDateTimeMapper, isArray);\n }\n\n mapFromNow(now: Date): Temporal.PlainDateTime {\n const { timeZone } = getRuntimeConfig().temporal as any;\n return requireTemporal().toTemporalInstant.call(now).toZonedDateTimeISO(timeZone).toPlainDateTime();\n }\n}\n\n/** Converts `TIMESTAMP WITH TIME ZONE`s to `Temporal.ZonedDateTime`s. */\nexport class ZonedDateTimeSerde extends CustomSerdeAdapter implements TimestampCodec<Temporal.ZonedDateTime> {\n constructor(dbType: string, isArray = false) {\n super(dbType, zonedDateTimeMapper, isArray);\n }\n\n mapFromNow(now: Date): Temporal.ZonedDateTime {\n const { timeZone } = getRuntimeConfig().temporal as any;\n return requireTemporal().toTemporalInstant.call(now).toZonedDateTimeISO(timeZone);\n }\n}\n\nexport class BigIntSerde implements ScalarCodec {\n dbType: string;\n\n constructor(public isArray = false) {\n this.dbType = isArray ? \"bigint[]\" : \"bigint\";\n }\n\n /** BigInt conversion is distinct from both the driver's int8 value and Number aggregates. */\n get outputType(): TypeInfo | undefined {\n if (this.constructor !== BigIntSerde) return undefined;\n const elementType = { dbType: \"int8\", domain: BigIntSerde, arrayElementSafe: true };\n return this.isArray ? arrayOutputType(elementType) : elementType;\n }\n\n /** Drivers accept native bigint values without conversion. */\n mapToDbValue(value: unknown): unknown {\n if (this.isArray) assertFlatNumericArray(value);\n return value;\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n /** Converts the driver's bigint representation to the entity value. */\n mapFromDb(value: unknown): unknown {\n const dbValue = maybeNullToUndefined(value);\n if (this.isArray && dbValue !== undefined) {\n assertFlatNumericArray(dbValue);\n return dbValue.map((element: string | bigint | number | null) => (element === null ? null : BigInt(element)));\n }\n return dbValue ? BigInt(dbValue) : dbValue;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : this.isArray ? this.mapFromDb(value) : BigInt(value);\n }\n}\n\n/**\n * Maps `decimal(...)` database types to the JS `number`.\n *\n * Note that we assume the db values are within the range of the JS `number`;\n * we should eventually sanity check that.\n *\n * Also note that knex/pg accept `number`s as input, so we only need\n * to handle from-database -> to JS translation.\n */\nexport class DecimalToNumberSerde implements ScalarCodec {\n dbType: string;\n\n constructor(public isArray = false) {\n this.dbType = isArray ? \"numeric[]\" : \"decimal\";\n }\n\n /** Numeric aggregates use the same Number conversion and identity binding encoder. */\n get outputType(): TypeInfo | undefined {\n if (this.constructor !== DecimalToNumberSerde) return undefined;\n const elementType = { dbType: \"numeric\", domain: Number, arrayElementSafe: true };\n return this.isArray ? arrayOutputType(elementType) : elementType;\n }\n\n /** Drivers accept decimal numbers without conversion. */\n mapToDbValue(value: unknown): unknown {\n if (this.isArray) assertFlatNumericArray(value);\n return value;\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n /** Converts a driver decimal value to a JavaScript number. */\n mapFromDb(value: unknown): unknown {\n const dbValue = maybeNullToUndefined(value);\n if (this.isArray && dbValue !== undefined) {\n assertFlatNumericArray(dbValue);\n return dbValue.map((element: string | number | null) => (element === null ? null : Number(element)));\n }\n return dbValue !== undefined ? Number(dbValue) : dbValue;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : this.isArray ? this.mapFromDb(value) : Number(value);\n }\n}\n\n/** Maps physical integer keys to logical string IDs \"because GraphQL\". */\nexport class KeySerde implements ScalarCodec {\n isArray = false;\n\n private meta: {\n tagName: string;\n idDbType: \"bigint\" | \"int\" | \"uuid\" | \"text\";\n };\n\n constructor(\n tagName: string,\n public dbType: \"bigint\" | \"int\" | \"uuid\" | \"text\",\n ) {\n this.meta = {\n tagName,\n idDbType: dbType,\n };\n }\n\n /** PKs and FKs share a tag and SQL representation; the alias supplies the exact target idMeta. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === KeySerde && !this.isArray\n ? { dbType: canonicalDbType(this.dbType), domain: `key:${this.meta.tagName}`, arrayElementSafe: true }\n : undefined;\n }\n\n /** Resolves references and tagged, untagged, or numeric ids using the column's tag and storage type. */\n mapToDbValue(value: unknown): unknown {\n return keyToNumber(\n this.meta,\n typeof value === \"number\"\n ? value\n : maybeResolveReferenceToId(value as Parameters<typeof maybeResolveReferenceToId>[0]),\n );\n }\n\n mapToRow(value: any): any {\n // we don't have any fixups since we are trying to recreate what comes out of the db, so this is safe\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n // Numeric IDs are already database values; tagged string IDs still need to be resolved and untagged.\n if (value === null || typeof value === \"number\") return value;\n // We go through `maybeResolveReferenceToId` because filters like `in: [a1, a2]` pass entities directly.\n return keyToNumber(this.meta, maybeResolveReferenceToId(value));\n }\n\n /** Converts a physical primary or foreign key to a tagged id. */\n mapFromDb(value: unknown): string | undefined {\n return keyToTaggedId(this.meta, value as string | number);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class EnumFieldSerde implements ScalarCodec {\n isArray = false;\n\n constructor(\n public dbType: \"int\" | \"uuid\",\n private enumObject: any,\n ) {}\n\n /** Separate fields of the same generated enum share its code/id mapping. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === EnumFieldSerde && !this.isArray\n ? { dbType: canonicalDbType(this.dbType), domain: this.enumObject, arrayElementSafe: true }\n : undefined;\n }\n\n /** Resolves the enum code to its stored id, leaving an unknown code unset. */\n mapToDbValue(value: unknown): unknown {\n return this.enumObject.findByCode(value)?.id;\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n return this.enumObject.findByCode(value)?.id;\n }\n\n /** Converts a stored enum id to its enum code. */\n mapFromDb(value: unknown): unknown {\n return this.enumObject.findById(value)?.code;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class EnumArrayFieldSerde implements ScalarCodec {\n isArray = true;\n\n constructor(\n public dbType: \"int[]\" | \"uuid[]\",\n private enumObject: any,\n ) {}\n\n /**\n * Return the unnest null/set marker as the physical db type.\n *\n * The marker is removed before enum IDs are stored, so it need not identify an enum row.\n */\n get notNullMarker(): unknown {\n return defaultArrayElementMarker(this.dbType);\n }\n\n /** Physical enum arrays reject null elements, unlike scalar enum arrayAgg; leave them unknown. */\n get outputType(): undefined {\n return undefined;\n }\n\n /** Resolves each enum code to its stored id, retaining the entity's empty-array default. */\n mapToDbValue(value: unknown): unknown {\n return (value as readonly unknown[] | null | undefined)?.map((code) => this.enumObject.getByCode(code).id) || [];\n }\n\n mapToRow(value: any): any {\n return this.mapToDbValue(value);\n }\n\n mapToDb(value: any) {\n return !value ? [] : value.map((code: any) => this.enumObject.getByCode(code).id);\n }\n\n /** Converts stored enum ids to codes, defaulting an unset entity field to an empty array. */\n mapFromDb(value: unknown): unknown[] {\n return (value as readonly unknown[] | null | undefined)?.map((id) => this.enumObject.findById(id).code) || [];\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\n/** Similar to SimpleSerde, but applies the superstruct `assert` function when reading values from the db. */\nexport class SuperstructSerde implements ScalarCodec {\n dbType = \"jsonb\";\n isArray = false;\n\n // Use a dynamic require so that downstream projects don't have to depend on superstruct\n // until they want to, i.e. we don't have superstruct in the joist-orm package.json.\n private assert = runtimeRequire(\"superstruct\").assert;\n\n constructor(private superstruct: any) {}\n\n /** JSON schemas describe a jsonb value, even when that value is a JSON array. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === SuperstructSerde && !this.isArray\n ? { dbType: canonicalDbType(this.dbType), domain: this.superstruct, arrayElementSafe: true }\n : undefined;\n }\n\n /** Serializes the domain JSON value without running the read-time schema validation. */\n mapToDbValue(value: unknown): unknown {\n return JSON.stringify(value);\n }\n\n // JSON is returned by postgres already parsed, so we should just be able to return our data directly. Unlike with\n // JsonSerde, we can assume that superstruct would have parsed any complex types in the json correctly so we don't\n // need to do a round trip through JSON.stringify.\n mapToRow(value: any): any {\n return value;\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n /** Validates a driver JSON value with the field's Superstruct schema. */\n mapFromDb(value: unknown): unknown {\n const dbValue = maybeNullToUndefined(value);\n if (dbValue) this.assert(dbValue, this.superstruct);\n return dbValue;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class JsonSerde implements ScalarCodec {\n dbType = \"jsonb\";\n isArray = false;\n\n constructor() {}\n\n /** Unvalidated JSON uses its own encoder, not a primitive or schema-specific codec. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === JsonSerde && !this.isArray\n ? { dbType: canonicalDbType(this.dbType), domain: JsonSerde, arrayElementSafe: true }\n : undefined;\n }\n\n /** Serializes the whole JSON value, including JSON arrays and custom toJSON methods. */\n mapToDbValue(value: unknown): unknown {\n return JSON.stringify(value);\n }\n\n // JSON is returned by postgres already parsed, so if we are trying to recreate then we need to stringify, then parse.\n // It's necessary to do this instead of just returning the object directly because any complex types in the json need\n // to be stringified to correctly reflect the db value.\n mapToRow(value: any): any {\n const json = JSON.stringify(value);\n return isDefined(json) ? JSON.parse(json) : undefined;\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n /** Keeps the driver's parsed JSON value, normalizing SQL NULL for entity fields. */\n mapFromDb(value: unknown): unknown {\n return maybeNullToUndefined(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\n/**\n * Maps pgvector `vector(N)` columns to `number[]`s.\n *\n * pgvector has no pg array OID, so text results are its `[1,2,3]` literal, which is also valid\n * JSON (pgvector rejects NaN/Infinity elements). Writes send the same literal, which the batch\n * `unnest(?::vector[])` casts, because node-pg would otherwise encode a JS array as `{1,2,3}`.\n */\nexport class VectorSerde implements ScalarCodec {\n dbType = \"vector\";\n isArray = false;\n\n get outputType(): TypeInfo | undefined {\n return this.constructor === VectorSerde ? { dbType: this.dbType, domain: VectorSerde } : undefined;\n }\n\n mapToDbValue(value: unknown): unknown {\n return JSON.stringify(value);\n }\n\n mapToRow(value: any): any {\n return JSON.stringify(value);\n }\n\n mapToDb(value: any) {\n return value === null ? value : JSON.stringify(value);\n }\n\n /** Parses the text literal, and passes through arrays already decoded by the binary row path. */\n mapFromDb(value: unknown): unknown {\n return typeof value === \"string\" ? JSON.parse(value) : maybeNullToUndefined(value);\n }\n\n /** `to_json(vector)` falls back to the text literal, i.e. the same value as a driver row. */\n mapFromJsonAgg(value: any): any {\n return value;\n }\n}\n\n/** Similar to SimpleSerde, but applies the zod's `parse` function when reading values from the db. */\nexport class ZodSerde implements ScalarCodec {\n dbType = \"jsonb\";\n isArray = false;\n\n constructor(private zodSchema: any) {}\n\n /** Parsing and transformations are compatible only for the same schema object. */\n get outputType(): TypeInfo | undefined {\n return this.constructor === ZodSerde && !this.isArray\n ? { dbType: canonicalDbType(this.dbType), domain: this.zodSchema, arrayElementSafe: true }\n : undefined;\n }\n\n /** Serializes the domain JSON value without running the read-time Zod parser or transforms. */\n mapToDbValue(value: unknown): unknown {\n return JSON.stringify(value);\n }\n\n // JSON is returned by postgres already parsed, so we should just be able to return our data directly. Unlike with\n // JsonSerde, we can assume that zod would have parsed any complex types in the json correctly so we don't need to\n // do a round trip through JSON.stringify.\n mapToRow(value: any): any {\n return value;\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n /** Parses a driver JSON value with the field's Zod schema. */\n mapFromDb(value: unknown): unknown {\n const dbValue = maybeNullToUndefined(value);\n return dbValue ? this.zodSchema.parse(dbValue) : dbValue;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\n/** Return a default unnest null/set marker as the physical db type, before codec-specific conversion. */\nfunction defaultArrayElementMarker(dbType: string): unknown {\n if (dbType.startsWith(\"varchar\") || dbType.startsWith(\"character\") || dbType.startsWith(\"text\")) {\n return \"\";\n } else if (dbType.startsWith(\"int\")) {\n return 1;\n } else if (dbType.startsWith(\"date\") || dbType.startsWith(\"timestamp\")) {\n return new Date(\"2000-01-01T00:00:00.000Z\");\n } else {\n throw new Error(\"Unhandled nullable array column type \" + dbType);\n }\n}\n\n/** PostgreSQL does not enforce declared array dimensions; reject nested values rather than coercing subarrays. */\nfunction assertFlatNumericArray(value: unknown): void {\n if (Array.isArray(value) && value.some(Array.isArray)) {\n throw new Error(\"Native numeric arrays must be one-dimensional\");\n }\n}\n\n/** Only driver-native numbers agree with Number aggregates; int8/numeric identity values do not. */\nfunction primitiveOutputDomain(dbType: string): unknown {\n switch (dbType) {\n case \"int2\":\n case \"int4\":\n case \"float4\":\n case \"float8\":\n return Number;\n case \"text\":\n case \"varchar\":\n case \"bpchar\":\n return String;\n default:\n return PrimitiveSerde;\n }\n}\n\n/** Normalizes SQL NULL to an unset entity field. */\nfunction maybeNullToUndefined(value: any): any {\n return value === null ? undefined : value;\n}\n"],"mappings":"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"}
|
package/build/serde/serde.d.cts
CHANGED
|
@@ -5,6 +5,8 @@ import { TypeInfo } from "./TypeInfo.cjs";
|
|
|
5
5
|
export interface ScalarCodec {
|
|
6
6
|
dbType: string;
|
|
7
7
|
isArray: boolean;
|
|
8
|
+
/** The unnest null/set marker as the physical db type; never persisted in the column. */
|
|
9
|
+
readonly notNullMarker?: unknown;
|
|
8
10
|
/** Compatibility evidence for scalar conversion, absent for unknown codecs. */
|
|
9
11
|
readonly outputType?: TypeInfo;
|
|
10
12
|
/** Encodes a domain value for a filter, i.e. an em.find WHERE parameter. */
|
|
@@ -42,12 +44,23 @@ export interface TimestampCodec<T> extends ScalarCodec {
|
|
|
42
44
|
export interface CustomSerde<DomainType, DbType> {
|
|
43
45
|
toDb(value: DomainType): DbType;
|
|
44
46
|
fromDb(value: DbType): DomainType;
|
|
47
|
+
/**
|
|
48
|
+
* Return a domain value for the unnest null/set marker, before conversion to the physical db type.
|
|
49
|
+
*
|
|
50
|
+
* Optional to preserve legacy serdes, including scalar serdes that never need markers.
|
|
51
|
+
* Without this hook, the adapter passes a default physical db value through fromDb, then converts it
|
|
52
|
+
* back with the normal array writer. Temporal mappers and restricted custom domains can provide an
|
|
53
|
+
* accepted domain value instead.
|
|
54
|
+
*/
|
|
55
|
+
getUnnestMarker?(): DomainType;
|
|
45
56
|
}
|
|
46
57
|
export declare class CustomSerdeAdapter implements ScalarCodec {
|
|
47
58
|
dbType: string;
|
|
48
59
|
private mapper;
|
|
49
60
|
isArray: boolean;
|
|
50
61
|
constructor(dbType: string, mapper: CustomSerde<any, any>, isArray?: boolean);
|
|
62
|
+
/** Return the unnest null/set marker as the physical db type. */
|
|
63
|
+
get notNullMarker(): unknown;
|
|
51
64
|
/** Only known adapters share their mapper's identity and elementwise array conversion. */
|
|
52
65
|
get outputType(): TypeInfo | undefined;
|
|
53
66
|
/** Encodes each physical array element once. */
|
|
@@ -69,6 +82,8 @@ export declare class PrimitiveSerde implements ScalarCodec {
|
|
|
69
82
|
dbType: string;
|
|
70
83
|
isArray: boolean;
|
|
71
84
|
constructor(dbType: string, isArray?: boolean);
|
|
85
|
+
/** Return the unnest null/set marker as the physical db type. */
|
|
86
|
+
get notNullMarker(): unknown;
|
|
72
87
|
/** Exact-class checks prevent an unknown subclass's overridden converters from sharing this codec. */
|
|
73
88
|
get outputType(): TypeInfo | undefined;
|
|
74
89
|
/** Primitive writes share their scalar/filter conversion, including subclass overrides. */
|
|
@@ -186,6 +201,12 @@ export declare class EnumArrayFieldSerde implements ScalarCodec {
|
|
|
186
201
|
private enumObject;
|
|
187
202
|
isArray: boolean;
|
|
188
203
|
constructor(dbType: "int[]" | "uuid[]", enumObject: any);
|
|
204
|
+
/**
|
|
205
|
+
* Return the unnest null/set marker as the physical db type.
|
|
206
|
+
*
|
|
207
|
+
* The marker is removed before enum IDs are stored, so it need not identify an enum row.
|
|
208
|
+
*/
|
|
209
|
+
get notNullMarker(): unknown;
|
|
189
210
|
/** Physical enum arrays reject null elements, unlike scalar enum arrayAgg; leave them unknown. */
|
|
190
211
|
get outputType(): undefined;
|
|
191
212
|
/** Resolves each enum code to its stored id, retaining the entity's empty-array default. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serde.d.cts","names":[],"sources":["../../src/serde/serde.ts"],"mappings":";;;;iBAiBiB;EACf;EACA;;WAES,aAAa;;EAEtB,QAAQ;;;;;;;;EAQR,cAAc;;EAEd,UAAU;;;;;;;EAOV,eAAe;;EAEf,SAAS;;;iBAIM,eAAe,WAAW;EACzC,WAAW,KAAK,OAAO;;;;;;;;iBASR,YAAY,YAAY;EACvC,KAAK,OAAO,aAAa;EACzB,OAAO,OAAO,SAAS;;
|
|
1
|
+
{"version":3,"file":"serde.d.cts","names":[],"sources":["../../src/serde/serde.ts"],"mappings":";;;;iBAiBiB;EACf;EACA;;WAES;;WAEA,aAAa;;EAEtB,QAAQ;;;;;;;;EAQR,cAAc;;EAEd,UAAU;;;;;;;EAOV,eAAe;;EAEf,SAAS;;;iBAIM,eAAe,WAAW;EACzC,WAAW,KAAK,OAAO;;;;;;;;iBASR,YAAY,YAAY;EACvC,KAAK,OAAO,aAAa;EACzB,OAAO,OAAO,SAAS;;;;;;;;;EASvB,oBAAoB;;qBAGT,8BAA8B;EAIhC;UACC;EAJV;EAEA,YACS,gBACC,QAAQ,uBAChB;;MAME;;MAQA,cAAc;;EAuBlB,aAAa;EAQb,SAAS;EAIT,QAAQ;;EASR,UAAU;EASV,eAAe;;;;;;;;;qBAkBJ,0BAA0B;EAE5B;EACA;EAFT,YACS,gBACA;;MAIL;;MAMA,cAAc;;EAclB,aAAa;EAIb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EAIV,eAAe;;qBAKJ,kBAAkB,0BAA0B,eAAe;;MAElE,cAAc;;EAOlB,WAAW,KAAK,OAAO;EAIvB,eAAe;;;;;;;;EAYf,SAAS;EAIT,QAAQ,OAAO;;;qBAOJ,uBAAuB;EAClC,YAAY,gBAAgB;;;qBAMjB,uBAAuB;EAClC,YAAY,gBAAgB;;;qBAMjB,2BAA2B,8BAA8B,eAAe,SAAS;EAC5F,YAAY,gBAAgB;EAI5B,WAAW,KAAK,OAAO,SAAS;;;qBAOrB,2BAA2B,8BAA8B,eAAe,SAAS;EAC5F,YAAY,gBAAgB;EAI5B,WAAW,KAAK,OAAO,SAAS;;qBAMrB,uBAAuB;EAGf;EAFnB;EAEA,YAAmB;;MAKf,cAAc;;EAOlB,aAAa;EAKb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EASV,eAAe;;;;;;;;;;;qBAcJ,gCAAgC;EAGxB;EAFnB;EAEA,YAAmB;;MAKf,cAAc;;EAOlB,aAAa;EAKb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EASV,eAAe;;;qBAMJ,oBAAoB;EAUtB;EATT;UAEQ;EAKR,YACE,iBACO;;MASL,cAAc;;EAOlB,aAAa;EASb,SAAS;EAKT,QAAQ;;EAQR,UAAU;EAIV,eAAe;;qBAKJ,0BAA0B;EAI5B;UACC;EAJV;EAEA,YACS,wBACC;;MAIN,cAAc;;EAOlB,aAAa;EAIb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EAIV,eAAe;;qBAKJ,+BAA+B;EAIjC;UACC;EAJV;EAEA,YACS,4BACC;;;;;;MAQN;;MAKA;;EAKJ,aAAa;EAIb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EAIV,eAAe;;;qBAMJ,4BAA4B;UAQnB;EAPpB;EACA;UAIQ;EAER,YAAoB;;MAGhB,cAAc;;EAOlB,aAAa;EAOb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EAMV,eAAe;;qBAKJ,qBAAqB;EAChC;EACA;EAEA;;MAGI,cAAc;;EAOlB,aAAa;EAOb,SAAS;EAKT,QAAQ;;EAKR,UAAU;EAIV,eAAe;;;;;;;;;qBAYJ,uBAAuB;EAClC;EACA;MAEI,cAAc;EAIlB,aAAa;EAIb,SAAS;EAIT,QAAQ;;EAKR,UAAU;;EAKV,eAAe;;;qBAMJ,oBAAoB;UAIX;EAHpB;EACA;EAEA,YAAoB;;MAGhB,cAAc;;EAOlB,aAAa;EAOb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EAKV,eAAe"}
|
package/build/serde/serde.d.mts
CHANGED
|
@@ -5,6 +5,8 @@ import { TypeInfo } from "./TypeInfo.mjs";
|
|
|
5
5
|
export interface ScalarCodec {
|
|
6
6
|
dbType: string;
|
|
7
7
|
isArray: boolean;
|
|
8
|
+
/** The unnest null/set marker as the physical db type; never persisted in the column. */
|
|
9
|
+
readonly notNullMarker?: unknown;
|
|
8
10
|
/** Compatibility evidence for scalar conversion, absent for unknown codecs. */
|
|
9
11
|
readonly outputType?: TypeInfo;
|
|
10
12
|
/** Encodes a domain value for a filter, i.e. an em.find WHERE parameter. */
|
|
@@ -42,12 +44,23 @@ export interface TimestampCodec<T> extends ScalarCodec {
|
|
|
42
44
|
export interface CustomSerde<DomainType, DbType> {
|
|
43
45
|
toDb(value: DomainType): DbType;
|
|
44
46
|
fromDb(value: DbType): DomainType;
|
|
47
|
+
/**
|
|
48
|
+
* Return a domain value for the unnest null/set marker, before conversion to the physical db type.
|
|
49
|
+
*
|
|
50
|
+
* Optional to preserve legacy serdes, including scalar serdes that never need markers.
|
|
51
|
+
* Without this hook, the adapter passes a default physical db value through fromDb, then converts it
|
|
52
|
+
* back with the normal array writer. Temporal mappers and restricted custom domains can provide an
|
|
53
|
+
* accepted domain value instead.
|
|
54
|
+
*/
|
|
55
|
+
getUnnestMarker?(): DomainType;
|
|
45
56
|
}
|
|
46
57
|
export declare class CustomSerdeAdapter implements ScalarCodec {
|
|
47
58
|
dbType: string;
|
|
48
59
|
private mapper;
|
|
49
60
|
isArray: boolean;
|
|
50
61
|
constructor(dbType: string, mapper: CustomSerde<any, any>, isArray?: boolean);
|
|
62
|
+
/** Return the unnest null/set marker as the physical db type. */
|
|
63
|
+
get notNullMarker(): unknown;
|
|
51
64
|
/** Only known adapters share their mapper's identity and elementwise array conversion. */
|
|
52
65
|
get outputType(): TypeInfo | undefined;
|
|
53
66
|
/** Encodes each physical array element once. */
|
|
@@ -69,6 +82,8 @@ export declare class PrimitiveSerde implements ScalarCodec {
|
|
|
69
82
|
dbType: string;
|
|
70
83
|
isArray: boolean;
|
|
71
84
|
constructor(dbType: string, isArray?: boolean);
|
|
85
|
+
/** Return the unnest null/set marker as the physical db type. */
|
|
86
|
+
get notNullMarker(): unknown;
|
|
72
87
|
/** Exact-class checks prevent an unknown subclass's overridden converters from sharing this codec. */
|
|
73
88
|
get outputType(): TypeInfo | undefined;
|
|
74
89
|
/** Primitive writes share their scalar/filter conversion, including subclass overrides. */
|
|
@@ -186,6 +201,12 @@ export declare class EnumArrayFieldSerde implements ScalarCodec {
|
|
|
186
201
|
private enumObject;
|
|
187
202
|
isArray: boolean;
|
|
188
203
|
constructor(dbType: "int[]" | "uuid[]", enumObject: any);
|
|
204
|
+
/**
|
|
205
|
+
* Return the unnest null/set marker as the physical db type.
|
|
206
|
+
*
|
|
207
|
+
* The marker is removed before enum IDs are stored, so it need not identify an enum row.
|
|
208
|
+
*/
|
|
209
|
+
get notNullMarker(): unknown;
|
|
189
210
|
/** Physical enum arrays reject null elements, unlike scalar enum arrayAgg; leave them unknown. */
|
|
190
211
|
get outputType(): undefined;
|
|
191
212
|
/** Resolves each enum code to its stored id, retaining the entity's empty-array default. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"serde.d.mts","names":[],"sources":["../../src/serde/serde.ts"],"mappings":";;;;iBAiBiB;EACf;EACA;;WAES,aAAa;;EAEtB,QAAQ;;;;;;;;EAQR,cAAc;;EAEd,UAAU;;;;;;;EAOV,eAAe;;EAEf,SAAS;;;iBAIM,eAAe,WAAW;EACzC,WAAW,KAAK,OAAO;;;;;;;;iBASR,YAAY,YAAY;EACvC,KAAK,OAAO,aAAa;EACzB,OAAO,OAAO,SAAS;;
|
|
1
|
+
{"version":3,"file":"serde.d.mts","names":[],"sources":["../../src/serde/serde.ts"],"mappings":";;;;iBAiBiB;EACf;EACA;;WAES;;WAEA,aAAa;;EAEtB,QAAQ;;;;;;;;EAQR,cAAc;;EAEd,UAAU;;;;;;;EAOV,eAAe;;EAEf,SAAS;;;iBAIM,eAAe,WAAW;EACzC,WAAW,KAAK,OAAO;;;;;;;;iBASR,YAAY,YAAY;EACvC,KAAK,OAAO,aAAa;EACzB,OAAO,OAAO,SAAS;;;;;;;;;EASvB,oBAAoB;;qBAGT,8BAA8B;EAIhC;UACC;EAJV;EAEA,YACS,gBACC,QAAQ,uBAChB;;MAME;;MAQA,cAAc;;EAuBlB,aAAa;EAQb,SAAS;EAIT,QAAQ;;EASR,UAAU;EASV,eAAe;;;;;;;;;qBAkBJ,0BAA0B;EAE5B;EACA;EAFT,YACS,gBACA;;MAIL;;MAMA,cAAc;;EAclB,aAAa;EAIb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EAIV,eAAe;;qBAKJ,kBAAkB,0BAA0B,eAAe;;MAElE,cAAc;;EAOlB,WAAW,KAAK,OAAO;EAIvB,eAAe;;;;;;;;EAYf,SAAS;EAIT,QAAQ,OAAO;;;qBAOJ,uBAAuB;EAClC,YAAY,gBAAgB;;;qBAMjB,uBAAuB;EAClC,YAAY,gBAAgB;;;qBAMjB,2BAA2B,8BAA8B,eAAe,SAAS;EAC5F,YAAY,gBAAgB;EAI5B,WAAW,KAAK,OAAO,SAAS;;;qBAOrB,2BAA2B,8BAA8B,eAAe,SAAS;EAC5F,YAAY,gBAAgB;EAI5B,WAAW,KAAK,OAAO,SAAS;;qBAMrB,uBAAuB;EAGf;EAFnB;EAEA,YAAmB;;MAKf,cAAc;;EAOlB,aAAa;EAKb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EASV,eAAe;;;;;;;;;;;qBAcJ,gCAAgC;EAGxB;EAFnB;EAEA,YAAmB;;MAKf,cAAc;;EAOlB,aAAa;EAKb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EASV,eAAe;;;qBAMJ,oBAAoB;EAUtB;EATT;UAEQ;EAKR,YACE,iBACO;;MASL,cAAc;;EAOlB,aAAa;EASb,SAAS;EAKT,QAAQ;;EAQR,UAAU;EAIV,eAAe;;qBAKJ,0BAA0B;EAI5B;UACC;EAJV;EAEA,YACS,wBACC;;MAIN,cAAc;;EAOlB,aAAa;EAIb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EAIV,eAAe;;qBAKJ,+BAA+B;EAIjC;UACC;EAJV;EAEA,YACS,4BACC;;;;;;MAQN;;MAKA;;EAKJ,aAAa;EAIb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EAIV,eAAe;;;qBAMJ,4BAA4B;UAQnB;EAPpB;EACA;UAIQ;EAER,YAAoB;;MAGhB,cAAc;;EAOlB,aAAa;EAOb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EAMV,eAAe;;qBAKJ,qBAAqB;EAChC;EACA;EAEA;;MAGI,cAAc;;EAOlB,aAAa;EAOb,SAAS;EAKT,QAAQ;;EAKR,UAAU;EAIV,eAAe;;;;;;;;;qBAYJ,uBAAuB;EAClC;EACA;MAEI,cAAc;EAIlB,aAAa;EAIb,SAAS;EAIT,QAAQ;;EAKR,UAAU;;EAKV,eAAe;;;qBAMJ,oBAAoB;UAIX;EAHpB;EACA;EAEA,YAAoB;;MAGhB,cAAc;;EAOlB,aAAa;EAOb,SAAS;EAIT,QAAQ;;EAKR,UAAU;EAKV,eAAe"}
|
package/build/serde/serde.js
CHANGED
|
@@ -16,6 +16,11 @@ var CustomSerdeAdapter = class CustomSerdeAdapter {
|
|
|
16
16
|
this.mapper = mapper;
|
|
17
17
|
if (isArray !== void 0) this.isArray = isArray;
|
|
18
18
|
}
|
|
19
|
+
/** Return the unnest null/set marker as the physical db type. */
|
|
20
|
+
get notNullMarker() {
|
|
21
|
+
const seed = this.mapper.getUnnestMarker ? this.mapper.getUnnestMarker() : this.mapper.fromDb(defaultArrayElementMarker(this.dbType));
|
|
22
|
+
return this.mapToDbValue([seed])[0];
|
|
23
|
+
}
|
|
19
24
|
/** Only known adapters share their mapper's identity and elementwise array conversion. */
|
|
20
25
|
get outputType() {
|
|
21
26
|
if (this.isArray !== this.dbType.endsWith("[]") || this.constructor !== CustomSerdeAdapter && this.constructor !== PlainDateSerde && this.constructor !== PlainTimeSerde && this.constructor !== PlainDateTimeSerde && this.constructor !== ZonedDateTimeSerde) return;
|
|
@@ -70,6 +75,11 @@ var PrimitiveSerde = class PrimitiveSerde {
|
|
|
70
75
|
this.dbType = dbType;
|
|
71
76
|
this.isArray = isArray;
|
|
72
77
|
}
|
|
78
|
+
/** Return the unnest null/set marker as the physical db type. */
|
|
79
|
+
get notNullMarker() {
|
|
80
|
+
const seed = defaultArrayElementMarker(this.dbType);
|
|
81
|
+
return this.isArray ? this.mapToDbValue([seed])[0] : this.mapToDbValue(seed);
|
|
82
|
+
}
|
|
73
83
|
/** Exact-class checks prevent an unknown subclass's overridden converters from sharing this codec. */
|
|
74
84
|
get outputType() {
|
|
75
85
|
if (this.constructor !== PrimitiveSerde) return void 0;
|
|
@@ -335,6 +345,14 @@ var EnumArrayFieldSerde = class {
|
|
|
335
345
|
this.dbType = dbType;
|
|
336
346
|
this.enumObject = enumObject;
|
|
337
347
|
}
|
|
348
|
+
/**
|
|
349
|
+
* Return the unnest null/set marker as the physical db type.
|
|
350
|
+
*
|
|
351
|
+
* The marker is removed before enum IDs are stored, so it need not identify an enum row.
|
|
352
|
+
*/
|
|
353
|
+
get notNullMarker() {
|
|
354
|
+
return defaultArrayElementMarker(this.dbType);
|
|
355
|
+
}
|
|
338
356
|
/** Physical enum arrays reject null elements, unlike scalar enum arrayAgg; leave them unknown. */
|
|
339
357
|
get outputType() {}
|
|
340
358
|
/** Resolves each enum code to its stored id, retaining the entity's empty-array default. */
|
|
@@ -492,6 +510,13 @@ var ZodSerde = class ZodSerde {
|
|
|
492
510
|
return value === null ? value : value;
|
|
493
511
|
}
|
|
494
512
|
};
|
|
513
|
+
/** Return a default unnest null/set marker as the physical db type, before codec-specific conversion. */
|
|
514
|
+
function defaultArrayElementMarker(dbType) {
|
|
515
|
+
if (dbType.startsWith("varchar") || dbType.startsWith("character") || dbType.startsWith("text")) return "";
|
|
516
|
+
else if (dbType.startsWith("int")) return 1;
|
|
517
|
+
else if (dbType.startsWith("date") || dbType.startsWith("timestamp")) return /* @__PURE__ */ new Date("2000-01-01T00:00:00.000Z");
|
|
518
|
+
else throw new Error("Unhandled nullable array column type " + dbType);
|
|
519
|
+
}
|
|
495
520
|
/** PostgreSQL does not enforce declared array dimensions; reject nested values rather than coercing subarrays. */
|
|
496
521
|
function assertFlatNumericArray(value) {
|
|
497
522
|
if (Array.isArray(value) && value.some(Array.isArray)) throw new Error("Native numeric arrays must be one-dimensional");
|