joist-core 2.3.0-next.53 → 2.3.0-next.55

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.
@@ -156,7 +156,11 @@ var PolymorphicReferenceImpl = class extends require_relations_AbstractRelationI
156
156
  if (other !== void 0 && !this.field.components.some((c) => other instanceof c.otherMetadata().cstr || typeof other === "string" && require_configure.getConstructorFromTaggedId(other) === c.otherMetadata().cstr)) require_utils.fail(`${other} cannot be set as '${this.field.fieldName}' on ${this.entity}`);
157
157
  const previousLoaded = this.loaded ?? this.maybeFindExisting();
158
158
  require_index.ensureNotDeleted(this.entity, "pending");
159
- require_fields.setField(this.entity, this.fieldName, require_Entity.isEntity(other) ? other?.idTaggedMaybe ?? other : other);
159
+ if (require_Entity.isEntity(other)) {
160
+ const otherMeta = require_EntityMetadata.getMetadata(other);
161
+ const hasComponentsWithSameBaseType = otherMeta.baseType && this.field.components.some((component) => component.otherMetadata().baseType === otherMeta.baseType && !(other instanceof component.otherMetadata().cstr));
162
+ require_fields.setField(this.entity, this.fieldName, other.isNewEntity || hasComponentsWithSameBaseType ? other : other.idTagged);
163
+ } else require_fields.setField(this.entity, this.fieldName, other);
160
164
  if (typeof other === "string") {
161
165
  this.loaded = void 0;
162
166
  this._isLoaded = false;
@@ -1 +1 @@
1
- {"version":3,"file":"PolymorphicReference.cjs","names":["lazyField","AbstractRelationImpl","getMetadata","getInstanceData","maybeGetConstructorFromReference","isCascadeDelete","isEntity","getConstructorFromTaggedId","failNoId","maybeResolveReferenceToId","failIfNewEntity","#hasBeenSet","OneToManyCollection","sameEntity","getField","RelationT","RelationU","ReferenceN"],"sources":["../../src/relations/PolymorphicReference.ts"],"sourcesContent":["import { maybeGetConstructorFromReference } from \"../configure.ts\";\nimport { type Entity, isEntity } from \"../Entity.ts\";\nimport { type IdOf, type TaggedId, sameEntity } from \"../EntityManager.ts\";\nimport { type PolymorphicFieldComponent, getMetadata } from \"../EntityMetadata.ts\";\nimport { getField, setField } from \"../fields.ts\";\nimport {\n type OneToOneReference,\n type PolymorphicField,\n type Reference,\n ensureNotDeleted,\n fail,\n getConstructorFromTaggedId,\n getInstanceData,\n maybeResolveReferenceToId,\n} from \"../index.ts\";\nimport { lazyField } from \"../newEntity.ts\";\nimport { AbstractRelationImpl, isCascadeDelete } from \"./AbstractRelationImpl.ts\";\nimport { failIfNewEntity, failNoId } from \"./ManyToOneReference.ts\";\nimport { OneToManyCollection } from \"./OneToManyCollection.ts\";\nimport { ReferenceN } from \"./ReferenceSymbols.ts\";\nimport { RelationT, RelationU } from \"./RelationSymbols.ts\";\n\nexport function hasOnePolymorphic<\n T extends Entity,\n U extends Entity,\n N extends never | undefined,\n>(): PolymorphicReference<T, U, N> {\n return lazyField((entity: T, fieldName) => {\n return new PolymorphicReferenceImpl<T, U, N>(entity, fieldName as keyof T & string);\n });\n}\n\n/** Type guard utility for determining if an entity field is a PolymorphicReference. */\nexport function isPolymorphicReference(maybeReference: any): maybeReference is PolymorphicReference<any, any, any> {\n return maybeReference instanceof PolymorphicReferenceImpl;\n}\n\n/**\n * A reference that can be assigned to multiple different entity types.\n *\n * I.e. a `Comment.parent` reference that can be an `Author` or `Book`.\n *\n * The `U` generic will be the type union of `Author | Book`.\n */\nexport interface PolymorphicReference<\n T extends Entity,\n U extends Entity,\n N extends never | undefined,\n> extends Reference<T, U, N> {\n /** Returns the id of the current assigned entity, or a runtime error if either 1) unset or 2) set to a new entity that doesn't have an `id` yet. */\n id: IdOf<U>;\n\n /** Returns the id of the current assigned entity, undefined if unset, or a runtime error if set to a new entity. */\n idIfSet: IdOf<U> | undefined;\n\n /** Returns the id of the current assigned entity, undefined if unset, or undefined if set to a new entity. */\n idMaybe: IdOf<U> | undefined;\n\n idTagged: string;\n\n /** Returns `true` if this relation is currently set (i.e. regardless of whether it's loaded, or if it is set but the assigned entity doesn't have an id saved. */\n readonly isSet: boolean;\n}\n\n/**\n * Manages a set of foreign keys from one entity to another, i.e. `Comment.parent --> Book | BookReview`.\n *\n * We keep the current `parent` / `parent.id` value in the `__orm.data` hash, where the\n * current value could be either the `comments.parent_book_id` / `comments.parent_book_review_id` id (as a tagged string)\n * from the database, or an entity `Book` / `BookReview` that the user has set.\n *\n * Note that if any of our columns (eg `comments.parent_book_review_id`) is unique, this `PolymorphicReference` will\n * essentially be half of a one-to-one relationship, but we'll keep using this reference on the \"owning\" side; the other\n * side, i.e. `BookReview.comment` will use a `OneToOneReference` to point back to us.\n */\nexport class PolymorphicReferenceImpl<T extends Entity, U extends Entity, N extends never | undefined>\n extends AbstractRelationImpl<T, U>\n implements PolymorphicReference<T, U, N>\n{\n private loaded: U | N | undefined;\n // We need a separate boolean to b/c loaded == undefined can still mean \"_isLoaded\" for nullable fks.\n private _isLoaded = false;\n private field: PolymorphicField;\n #hasBeenSet = false;\n\n constructor(\n entity: T,\n public fieldName: keyof T & string,\n ) {\n super(entity);\n this.field = getMetadata(entity).allFields[this.fieldName] as PolymorphicField;\n if (getInstanceData(entity).isOrWasNew) {\n this._isLoaded = true;\n }\n }\n\n private get currentComponent(): PolymorphicFieldComponent | N {\n const cstr = maybeGetConstructorFromReference(this.current());\n return this.field.components.find((c) => c.otherMetadata().cstr === cstr) as any;\n }\n\n private get isCascadeDelete(): boolean {\n return isCascadeDelete(this, this.fieldName);\n }\n\n async load(opts: { withDeleted?: boolean; forceReload?: boolean } = {}): Promise<U | N> {\n ensureNotDeleted(this.entity, \"pending\");\n const current = this.current();\n // Resolve the id to an entity\n if (!isEntity(current) && current !== undefined && (!this._isLoaded || opts.forceReload)) {\n this.loaded = (await this.entity.em.load(getConstructorFromTaggedId(current), current)) as any as U;\n }\n this._isLoaded = true;\n return this.filterDeleted(this.loaded!, opts);\n }\n\n set(other: U | N): void {\n this.setImpl(other);\n }\n\n get isSet(): boolean {\n return this.current() !== undefined;\n }\n\n get isLoaded(): boolean {\n return this._isLoaded;\n }\n\n /**\n * Looks for an entity in `EntityManager`, b/c we may have it in memory even if\n * our reference is not specifically loaded.\n */\n maybeFindEntity(): U | undefined {\n // Check this.loaded first b/c a new entity won't have an id yet\n const { idTaggedMaybe } = this;\n return this.loaded ?? (idTaggedMaybe !== undefined ? (this.entity.em.getEntity(idTaggedMaybe) as U) : undefined);\n }\n\n get isPreloaded(): boolean {\n return !!this.maybeFindEntity();\n }\n\n preload(): void {\n this.loaded = this.maybeFindEntity();\n this._isLoaded = true;\n }\n\n private unload(): void {\n this.loaded = undefined;\n this._isLoaded = false;\n }\n\n import(other: PolymorphicReferenceImpl<T, U, N>, findEntity: (e: U) => U): void {\n this.loaded = other.loaded ? findEntity(other.loaded) : undefined;\n this._isLoaded = true;\n }\n\n private doGet(opts?: { withDeleted?: boolean }): U | N {\n ensureNotDeleted(this.entity, \"pending\");\n // This should only be callable in the type system if we've already resolved this to an instance,\n // but, just in case we somehow got here in an unloaded state, check to see if we're already in the UoW\n if (!this._isLoaded) {\n const existing = this.maybeFindExisting();\n if (existing === undefined) {\n throw new Error(`${this.entity}.${this.fieldName} was not loaded`);\n }\n this.loaded = existing;\n this._isLoaded = true;\n }\n\n return this.filterDeleted(this.loaded!, opts);\n }\n\n get getWithDeleted(): U | N {\n return this.doGet({ withDeleted: true });\n }\n\n get get(): U | N {\n return this.doGet({ withDeleted: false });\n }\n\n get id(): IdOf<U> {\n return this.idMaybe || failNoId(this.entity, this.fieldName, this.current());\n }\n\n get idMaybe(): IdOf<U> | undefined {\n ensureNotDeleted(this.entity, \"pending\");\n return maybeResolveReferenceToId(this.current()) as IdOf<U> | undefined;\n }\n\n get idIfSet(): IdOf<U> | N | undefined {\n return this.idMaybe || failIfNewEntity(this.entity, this.fieldName, this.current());\n }\n\n get idTagged(): string {\n return this.idTaggedMaybe || failNoId(this.entity, this.fieldName, this.current());\n }\n\n get idTaggedMaybe(): string | undefined {\n ensureNotDeleted(this.entity, \"pending\");\n return maybeResolveReferenceToId(this.current());\n }\n\n get hasBeenSet() {\n return this.#hasBeenSet;\n }\n\n // private impl\n\n setFromOpts(other: U): void {\n this.setImpl(other);\n }\n\n maybeCascadeDelete(): void {\n if (this.isCascadeDelete) {\n const current = this.current({ withDeleted: true });\n if (current !== undefined && typeof current !== \"string\") {\n this.entity.em.delete(current as U);\n }\n }\n }\n\n async cleanupOnEntityDeleted(): Promise<void> {\n // if we are going to delete this relation as well, then we don't need to clean it up\n if (this.isCascadeDelete) return;\n const current = await this.load({ withDeleted: true });\n if (current !== undefined) {\n const o2m = this.getOtherRelation(current);\n if (o2m instanceof OneToManyCollection) {\n o2m.remove(this.entity, { requireLoaded: false });\n } else {\n o2m.set(undefined as any);\n }\n }\n setField(this.entity, this.fieldName, undefined);\n this.loaded = undefined as any;\n this._isLoaded = true;\n }\n\n // Internal method used by PolymorphicReference\n setImpl(other: U | N): void {\n this.#hasBeenSet = true;\n\n if (sameEntity(other, this.current({ withDeleted: true }))) {\n return;\n }\n\n if (\n other !== undefined &&\n !this.field.components.some(\n (c) =>\n other instanceof c.otherMetadata().cstr ||\n (typeof other === \"string\" && getConstructorFromTaggedId(other) === c.otherMetadata().cstr),\n )\n ) {\n fail(`${other} cannot be set as '${this.field.fieldName}' on ${this.entity}`);\n }\n\n // we may not be loaded yet, but our previous entity might already be in the UoW\n const previousLoaded = this.loaded ?? this.maybeFindExisting();\n\n ensureNotDeleted(this.entity, \"pending\");\n\n // Prefer to keep the id in our data hash, but if this is a new entity w/o an id, use the entity itself\n const changed = setField(this.entity, this.fieldName, isEntity(other) ? (other?.idTaggedMaybe ?? other) : other);\n\n if (typeof other === \"string\") {\n this.loaded = undefined;\n this._isLoaded = false;\n } else {\n this.loaded = other;\n this._isLoaded = true;\n }\n\n // If had an existing value, remove us from its collection\n if (previousLoaded) {\n const prevRelation = this.getOtherRelation(previousLoaded);\n if (prevRelation instanceof OneToManyCollection) {\n prevRelation.removeIfLoaded(this.entity);\n } else {\n prevRelation.set(undefined as any);\n }\n }\n if (other !== undefined && isEntity(other)) {\n const newRelation = this.getOtherRelation(other);\n if (newRelation instanceof OneToManyCollection) {\n newRelation.add(this.entity);\n } else {\n newRelation.set(this.entity);\n }\n }\n }\n\n // We need to keep U in data[fieldName] to handle entities without an id assigned yet.\n current(opts?: { withDeleted?: boolean }): U | TaggedId | N {\n const current = getField(this.entity, this.fieldName);\n if (current !== undefined && isEntity(current)) {\n return this.filterDeleted(current as U, opts);\n }\n return current;\n }\n\n public toString(): string {\n return `PolymorphicReference(entity: ${this.entity}, fieldName: ${\n this.fieldName\n }, otherType: ${this.currentComponent?.otherMetadata().type}, otherFieldName: ${\n this.currentComponent?.otherFieldName\n }, id: ${this.id})`;\n }\n\n private filterDeleted(entity: U | N, opts?: { withDeleted?: boolean }): U | N {\n return opts?.withDeleted === true || entity === undefined || !entity.isDeletedEntity ? entity : (undefined as N);\n }\n\n /** Returns the other relation that points back at us, i.e. we're `comment.parent_book_id` and this is `Book.comments`. */\n private getOtherRelation(other: U): OneToManyCollection<U, T> | OneToOneReference<U, T> {\n const component = this.field.components.find((c) => other instanceof c.otherMetadata().cstr) as any;\n return (other as U)[component?.otherFieldName as keyof U] as any;\n }\n\n private maybeFindExisting(): U | undefined {\n return this.idTaggedMaybe !== undefined ? (this.entity.em.getEntity(this.idTagged) as U) : undefined;\n }\n\n [RelationT]: T = null!;\n [RelationU]: U = null!;\n [ReferenceN]: N = null!;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PolymorphicReference.cjs","names":["lazyField","AbstractRelationImpl","getMetadata","getInstanceData","maybeGetConstructorFromReference","isCascadeDelete","isEntity","getConstructorFromTaggedId","failNoId","maybeResolveReferenceToId","failIfNewEntity","#hasBeenSet","OneToManyCollection","sameEntity","getField","RelationT","RelationU","ReferenceN"],"sources":["../../src/relations/PolymorphicReference.ts"],"sourcesContent":["import { maybeGetConstructorFromReference } from \"../configure.ts\";\nimport { type Entity, isEntity } from \"../Entity.ts\";\nimport { type IdOf, type TaggedId, sameEntity } from \"../EntityManager.ts\";\nimport { type PolymorphicFieldComponent, getMetadata } from \"../EntityMetadata.ts\";\nimport { getField, setField } from \"../fields.ts\";\nimport {\n type OneToOneReference,\n type PolymorphicField,\n type Reference,\n ensureNotDeleted,\n fail,\n getConstructorFromTaggedId,\n getInstanceData,\n maybeResolveReferenceToId,\n} from \"../index.ts\";\nimport { lazyField } from \"../newEntity.ts\";\nimport { AbstractRelationImpl, isCascadeDelete } from \"./AbstractRelationImpl.ts\";\nimport { failIfNewEntity, failNoId } from \"./ManyToOneReference.ts\";\nimport { OneToManyCollection } from \"./OneToManyCollection.ts\";\nimport { ReferenceN } from \"./ReferenceSymbols.ts\";\nimport { RelationT, RelationU } from \"./RelationSymbols.ts\";\n\nexport function hasOnePolymorphic<\n T extends Entity,\n U extends Entity,\n N extends never | undefined,\n>(): PolymorphicReference<T, U, N> {\n return lazyField((entity: T, fieldName) => {\n return new PolymorphicReferenceImpl<T, U, N>(entity, fieldName as keyof T & string);\n });\n}\n\n/** Type guard utility for determining if an entity field is a PolymorphicReference. */\nexport function isPolymorphicReference(maybeReference: any): maybeReference is PolymorphicReference<any, any, any> {\n return maybeReference instanceof PolymorphicReferenceImpl;\n}\n\n/**\n * A reference that can be assigned to multiple different entity types.\n *\n * I.e. a `Comment.parent` reference that can be an `Author` or `Book`.\n *\n * The `U` generic will be the type union of `Author | Book`.\n */\nexport interface PolymorphicReference<\n T extends Entity,\n U extends Entity,\n N extends never | undefined,\n> extends Reference<T, U, N> {\n /** Returns the id of the current assigned entity, or a runtime error if either 1) unset or 2) set to a new entity that doesn't have an `id` yet. */\n id: IdOf<U>;\n\n /** Returns the id of the current assigned entity, undefined if unset, or a runtime error if set to a new entity. */\n idIfSet: IdOf<U> | undefined;\n\n /** Returns the id of the current assigned entity, undefined if unset, or undefined if set to a new entity. */\n idMaybe: IdOf<U> | undefined;\n\n idTagged: string;\n\n /** Returns `true` if this relation is currently set (i.e. regardless of whether it's loaded, or if it is set but the assigned entity doesn't have an id saved. */\n readonly isSet: boolean;\n}\n\n/**\n * Manages a set of foreign keys from one entity to another, i.e. `Comment.parent --> Book | BookReview`.\n *\n * We keep the current `parent` / `parent.id` value in the `__orm.data` hash, where the\n * current value could be either the `comments.parent_book_id` / `comments.parent_book_review_id` id (as a tagged string)\n * from the database, or an entity `Book` / `BookReview` that the user has set.\n *\n * Note that if any of our columns (eg `comments.parent_book_review_id`) is unique, this `PolymorphicReference` will\n * essentially be half of a one-to-one relationship, but we'll keep using this reference on the \"owning\" side; the other\n * side, i.e. `BookReview.comment` will use a `OneToOneReference` to point back to us.\n */\nexport class PolymorphicReferenceImpl<T extends Entity, U extends Entity, N extends never | undefined>\n extends AbstractRelationImpl<T, U>\n implements PolymorphicReference<T, U, N>\n{\n private loaded: U | N | undefined;\n // We need a separate boolean to b/c loaded == undefined can still mean \"_isLoaded\" for nullable fks.\n private _isLoaded = false;\n private field: PolymorphicField;\n #hasBeenSet = false;\n\n constructor(\n entity: T,\n public fieldName: keyof T & string,\n ) {\n super(entity);\n this.field = getMetadata(entity).allFields[this.fieldName] as PolymorphicField;\n if (getInstanceData(entity).isOrWasNew) {\n this._isLoaded = true;\n }\n }\n\n private get currentComponent(): PolymorphicFieldComponent | N {\n const cstr = maybeGetConstructorFromReference(this.current());\n return this.field.components.find((c) => c.otherMetadata().cstr === cstr) as any;\n }\n\n private get isCascadeDelete(): boolean {\n return isCascadeDelete(this, this.fieldName);\n }\n\n async load(opts: { withDeleted?: boolean; forceReload?: boolean } = {}): Promise<U | N> {\n ensureNotDeleted(this.entity, \"pending\");\n const current = this.current();\n // Resolve the id to an entity\n if (!isEntity(current) && current !== undefined && (!this._isLoaded || opts.forceReload)) {\n this.loaded = (await this.entity.em.load(getConstructorFromTaggedId(current), current)) as any as U;\n }\n this._isLoaded = true;\n return this.filterDeleted(this.loaded!, opts);\n }\n\n set(other: U | N): void {\n this.setImpl(other);\n }\n\n get isSet(): boolean {\n return this.current() !== undefined;\n }\n\n get isLoaded(): boolean {\n return this._isLoaded;\n }\n\n /**\n * Looks for an entity in `EntityManager`, b/c we may have it in memory even if\n * our reference is not specifically loaded.\n */\n maybeFindEntity(): U | undefined {\n // Check this.loaded first b/c a new entity won't have an id yet\n const { idTaggedMaybe } = this;\n return this.loaded ?? (idTaggedMaybe !== undefined ? (this.entity.em.getEntity(idTaggedMaybe) as U) : undefined);\n }\n\n get isPreloaded(): boolean {\n return !!this.maybeFindEntity();\n }\n\n preload(): void {\n this.loaded = this.maybeFindEntity();\n this._isLoaded = true;\n }\n\n private unload(): void {\n this.loaded = undefined;\n this._isLoaded = false;\n }\n\n import(other: PolymorphicReferenceImpl<T, U, N>, findEntity: (e: U) => U): void {\n this.loaded = other.loaded ? findEntity(other.loaded) : undefined;\n this._isLoaded = true;\n }\n\n private doGet(opts?: { withDeleted?: boolean }): U | N {\n ensureNotDeleted(this.entity, \"pending\");\n // This should only be callable in the type system if we've already resolved this to an instance,\n // but, just in case we somehow got here in an unloaded state, check to see if we're already in the UoW\n if (!this._isLoaded) {\n const existing = this.maybeFindExisting();\n if (existing === undefined) {\n throw new Error(`${this.entity}.${this.fieldName} was not loaded`);\n }\n this.loaded = existing;\n this._isLoaded = true;\n }\n\n return this.filterDeleted(this.loaded!, opts);\n }\n\n get getWithDeleted(): U | N {\n return this.doGet({ withDeleted: true });\n }\n\n get get(): U | N {\n return this.doGet({ withDeleted: false });\n }\n\n get id(): IdOf<U> {\n return this.idMaybe || failNoId(this.entity, this.fieldName, this.current());\n }\n\n get idMaybe(): IdOf<U> | undefined {\n ensureNotDeleted(this.entity, \"pending\");\n return maybeResolveReferenceToId(this.current()) as IdOf<U> | undefined;\n }\n\n get idIfSet(): IdOf<U> | N | undefined {\n return this.idMaybe || failIfNewEntity(this.entity, this.fieldName, this.current());\n }\n\n get idTagged(): string {\n return this.idTaggedMaybe || failNoId(this.entity, this.fieldName, this.current());\n }\n\n get idTaggedMaybe(): string | undefined {\n ensureNotDeleted(this.entity, \"pending\");\n return maybeResolveReferenceToId(this.current());\n }\n\n get hasBeenSet() {\n return this.#hasBeenSet;\n }\n\n // private impl\n\n setFromOpts(other: U): void {\n this.setImpl(other);\n }\n\n maybeCascadeDelete(): void {\n if (this.isCascadeDelete) {\n const current = this.current({ withDeleted: true });\n if (current !== undefined && typeof current !== \"string\") {\n this.entity.em.delete(current as U);\n }\n }\n }\n\n async cleanupOnEntityDeleted(): Promise<void> {\n // if we are going to delete this relation as well, then we don't need to clean it up\n if (this.isCascadeDelete) return;\n const current = await this.load({ withDeleted: true });\n if (current !== undefined) {\n const o2m = this.getOtherRelation(current);\n if (o2m instanceof OneToManyCollection) {\n o2m.remove(this.entity, { requireLoaded: false });\n } else {\n o2m.set(undefined as any);\n }\n }\n setField(this.entity, this.fieldName, undefined);\n this.loaded = undefined as any;\n this._isLoaded = true;\n }\n\n // Internal method used by PolymorphicReference\n setImpl(other: U | N): void {\n this.#hasBeenSet = true;\n\n if (sameEntity(other, this.current({ withDeleted: true }))) {\n return;\n }\n\n if (\n other !== undefined &&\n !this.field.components.some(\n (c) =>\n other instanceof c.otherMetadata().cstr ||\n (typeof other === \"string\" && getConstructorFromTaggedId(other) === c.otherMetadata().cstr),\n )\n ) {\n fail(`${other} cannot be set as '${this.field.fieldName}' on ${this.entity}`);\n }\n\n // we may not be loaded yet, but our previous entity might already be in the UoW\n const previousLoaded = this.loaded ?? this.maybeFindExisting();\n\n ensureNotDeleted(this.entity, \"pending\");\n\n // Keep the entity when its tagged id cannot distinguish between sibling subtypes.\n if (isEntity(other)) {\n const otherMeta = getMetadata(other);\n const hasComponentsWithSameBaseType =\n otherMeta.baseType &&\n this.field.components.some(\n (component) =>\n component.otherMetadata().baseType === otherMeta.baseType &&\n !(other instanceof component.otherMetadata().cstr),\n );\n setField(\n this.entity,\n this.fieldName,\n other.isNewEntity || hasComponentsWithSameBaseType ? other : other.idTagged,\n );\n } else {\n setField(this.entity, this.fieldName, other);\n }\n\n if (typeof other === \"string\") {\n this.loaded = undefined;\n this._isLoaded = false;\n } else {\n this.loaded = other;\n this._isLoaded = true;\n }\n\n // If had an existing value, remove us from its collection\n if (previousLoaded) {\n const prevRelation = this.getOtherRelation(previousLoaded);\n if (prevRelation instanceof OneToManyCollection) {\n prevRelation.removeIfLoaded(this.entity);\n } else {\n prevRelation.set(undefined as any);\n }\n }\n if (other !== undefined && isEntity(other)) {\n const newRelation = this.getOtherRelation(other);\n if (newRelation instanceof OneToManyCollection) {\n newRelation.add(this.entity);\n } else {\n newRelation.set(this.entity);\n }\n }\n }\n\n // We need to keep U in data[fieldName] to handle entities without an id assigned yet.\n current(opts?: { withDeleted?: boolean }): U | TaggedId | N {\n const current = getField(this.entity, this.fieldName);\n if (current !== undefined && isEntity(current)) {\n return this.filterDeleted(current as U, opts);\n }\n return current;\n }\n\n public toString(): string {\n return `PolymorphicReference(entity: ${this.entity}, fieldName: ${\n this.fieldName\n }, otherType: ${this.currentComponent?.otherMetadata().type}, otherFieldName: ${\n this.currentComponent?.otherFieldName\n }, id: ${this.id})`;\n }\n\n private filterDeleted(entity: U | N, opts?: { withDeleted?: boolean }): U | N {\n return opts?.withDeleted === true || entity === undefined || !entity.isDeletedEntity ? entity : (undefined as N);\n }\n\n /** Returns the other relation that points back at us, i.e. we're `comment.parent_book_id` and this is `Book.comments`. */\n private getOtherRelation(other: U): OneToManyCollection<U, T> | OneToOneReference<U, T> {\n const component = this.field.components.find((c) => other instanceof c.otherMetadata().cstr) as any;\n return (other as U)[component?.otherFieldName as keyof U] as any;\n }\n\n private maybeFindExisting(): U | undefined {\n return this.idTaggedMaybe !== undefined ? (this.entity.em.getEntity(this.idTagged) as U) : undefined;\n }\n\n [RelationT]: T = null!;\n [RelationU]: U = null!;\n [ReferenceN]: N = null!;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"PolymorphicReference.d.cts","names":[],"sources":["../../src/relations/PolymorphicReference.ts"],"mappings":";;;;;;;;iBAsBgB,kBACd,UAAU,QACV,UAAU,QACV,gCACG,qBAAqB,GAAG,GAAG;;iBAOhB,uBAAuB,sBAAsB,kBAAkB;;;;;;;;UAW9D,qBACf,UAAU,QACV,UAAU,QACV,qCACQ,UAAU,GAAG,GAAG;;EAExB,IAAI,KAAK;;EAGT,SAAS,KAAK;;EAGd,SAAS,KAAK;EAEd;;WAGS;;;;;;;;;;;;;cAcE,yBAAyB,UAAU,QAAQ,UAAU,QAAQ,qCAChE,qBAAqB,GAAG,cACrB,qBAAqB,GAAG,GAAG;;EAU7B,iBAAiB;UARlB;UAEA;UACA;EAGR,YACE,QAAQ,GACD,iBAAiB;cASd;cAKA;EAIN,KAAK;IAAQ;IAAuB;MAA+B,QAAQ,IAAI;EAWrF,IAAI,OAAO,IAAI;MAIX;MAIA;;;;;EAQJ,mBAAmB;MAMf;EAIJ;UAKQ;EAKR,OAAO,OAAO,yBAAyB,GAAG,GAAG,IAAI,aAAa,GAAG,MAAM;UAK/D;MAgBJ,kBAAkB,IAAI;MAItB,OAAO,IAAI;MAIX,MAAM,KAAK;MAIX,WAAW,KAAK;MAKhB,WAAW,KAAK,KAAK;MAIrB;MAIA;MAKA;EAMJ,YAAY,OAAO;EAInB;EASM,0BAA0B;EAkBhC,QAAQ,OAAO,IAAI;EAsDnB,QAAQ;IAAS;MAA0B,IAAI,WAAW;EAQnD;UAQC;;UAKA;UAKA;GAIP,YAAY;GACZ,YAAY;GACZ,aAAa"}
1
+ {"version":3,"file":"PolymorphicReference.d.cts","names":[],"sources":["../../src/relations/PolymorphicReference.ts"],"mappings":";;;;;;;;iBAsBgB,kBACd,UAAU,QACV,UAAU,QACV,gCACG,qBAAqB,GAAG,GAAG;;iBAOhB,uBAAuB,sBAAsB,kBAAkB;;;;;;;;UAW9D,qBACf,UAAU,QACV,UAAU,QACV,qCACQ,UAAU,GAAG,GAAG;;EAExB,IAAI,KAAK;;EAGT,SAAS,KAAK;;EAGd,SAAS,KAAK;EAEd;;WAGS;;;;;;;;;;;;;cAcE,yBAAyB,UAAU,QAAQ,UAAU,QAAQ,qCAChE,qBAAqB,GAAG,cACrB,qBAAqB,GAAG,GAAG;;EAU7B,iBAAiB;UARlB;UAEA;UACA;EAGR,YACE,QAAQ,GACD,iBAAiB;cASd;cAKA;EAIN,KAAK;IAAQ;IAAuB;MAA+B,QAAQ,IAAI;EAWrF,IAAI,OAAO,IAAI;MAIX;MAIA;;;;;EAQJ,mBAAmB;MAMf;EAIJ;UAKQ;EAKR,OAAO,OAAO,yBAAyB,GAAG,GAAG,IAAI,aAAa,GAAG,MAAM;UAK/D;MAgBJ,kBAAkB,IAAI;MAItB,OAAO,IAAI;MAIX,MAAM,KAAK;MAIX,WAAW,KAAK;MAKhB,WAAW,KAAK,KAAK;MAIrB;MAIA;MAKA;EAMJ,YAAY,OAAO;EAInB;EASM,0BAA0B;EAkBhC,QAAQ,OAAO,IAAI;EAsEnB,QAAQ;IAAS;MAA0B,IAAI,WAAW;EAQnD;UAQC;;UAKA;UAKA;GAIP,YAAY;GACZ,YAAY;GACZ,aAAa"}
@@ -1 +1 @@
1
- {"version":3,"file":"PolymorphicReference.d.mts","names":[],"sources":["../../src/relations/PolymorphicReference.ts"],"mappings":";;;;;;;;iBAsBgB,kBACd,UAAU,QACV,UAAU,QACV,gCACG,qBAAqB,GAAG,GAAG;;iBAOhB,uBAAuB,sBAAsB,kBAAkB;;;;;;;;UAW9D,qBACf,UAAU,QACV,UAAU,QACV,qCACQ,UAAU,GAAG,GAAG;;EAExB,IAAI,KAAK;;EAGT,SAAS,KAAK;;EAGd,SAAS,KAAK;EAEd;;WAGS;;;;;;;;;;;;;cAcE,yBAAyB,UAAU,QAAQ,UAAU,QAAQ,qCAChE,qBAAqB,GAAG,cACrB,qBAAqB,GAAG,GAAG;;EAU7B,iBAAiB;UARlB;UAEA;UACA;EAGR,YACE,QAAQ,GACD,iBAAiB;cASd;cAKA;EAIN,KAAK;IAAQ;IAAuB;MAA+B,QAAQ,IAAI;EAWrF,IAAI,OAAO,IAAI;MAIX;MAIA;;;;;EAQJ,mBAAmB;MAMf;EAIJ;UAKQ;EAKR,OAAO,OAAO,yBAAyB,GAAG,GAAG,IAAI,aAAa,GAAG,MAAM;UAK/D;MAgBJ,kBAAkB,IAAI;MAItB,OAAO,IAAI;MAIX,MAAM,KAAK;MAIX,WAAW,KAAK;MAKhB,WAAW,KAAK,KAAK;MAIrB;MAIA;MAKA;EAMJ,YAAY,OAAO;EAInB;EASM,0BAA0B;EAkBhC,QAAQ,OAAO,IAAI;EAsDnB,QAAQ;IAAS;MAA0B,IAAI,WAAW;EAQnD;UAQC;;UAKA;UAKA;GAIP,YAAY;GACZ,YAAY;GACZ,aAAa"}
1
+ {"version":3,"file":"PolymorphicReference.d.mts","names":[],"sources":["../../src/relations/PolymorphicReference.ts"],"mappings":";;;;;;;;iBAsBgB,kBACd,UAAU,QACV,UAAU,QACV,gCACG,qBAAqB,GAAG,GAAG;;iBAOhB,uBAAuB,sBAAsB,kBAAkB;;;;;;;;UAW9D,qBACf,UAAU,QACV,UAAU,QACV,qCACQ,UAAU,GAAG,GAAG;;EAExB,IAAI,KAAK;;EAGT,SAAS,KAAK;;EAGd,SAAS,KAAK;EAEd;;WAGS;;;;;;;;;;;;;cAcE,yBAAyB,UAAU,QAAQ,UAAU,QAAQ,qCAChE,qBAAqB,GAAG,cACrB,qBAAqB,GAAG,GAAG;;EAU7B,iBAAiB;UARlB;UAEA;UACA;EAGR,YACE,QAAQ,GACD,iBAAiB;cASd;cAKA;EAIN,KAAK;IAAQ;IAAuB;MAA+B,QAAQ,IAAI;EAWrF,IAAI,OAAO,IAAI;MAIX;MAIA;;;;;EAQJ,mBAAmB;MAMf;EAIJ;UAKQ;EAKR,OAAO,OAAO,yBAAyB,GAAG,GAAG,IAAI,aAAa,GAAG,MAAM;UAK/D;MAgBJ,kBAAkB,IAAI;MAItB,OAAO,IAAI;MAIX,MAAM,KAAK;MAIX,WAAW,KAAK;MAKhB,WAAW,KAAK,KAAK;MAIrB;MAIA;MAKA;EAMJ,YAAY,OAAO;EAInB;EASM,0BAA0B;EAkBhC,QAAQ,OAAO,IAAI;EAsEnB,QAAQ;IAAS;MAA0B,IAAI,WAAW;EAQnD;UAQC;;UAKA;UAKA;GAIP,YAAY;GACZ,YAAY;GACZ,aAAa"}
@@ -155,7 +155,11 @@ var PolymorphicReferenceImpl = class extends AbstractRelationImpl {
155
155
  if (other !== void 0 && !this.field.components.some((c) => other instanceof c.otherMetadata().cstr || typeof other === "string" && getConstructorFromTaggedId(other) === c.otherMetadata().cstr)) fail(`${other} cannot be set as '${this.field.fieldName}' on ${this.entity}`);
156
156
  const previousLoaded = this.loaded ?? this.maybeFindExisting();
157
157
  ensureNotDeleted(this.entity, "pending");
158
- setField(this.entity, this.fieldName, isEntity(other) ? other?.idTaggedMaybe ?? other : other);
158
+ if (isEntity(other)) {
159
+ const otherMeta = getMetadata(other);
160
+ const hasComponentsWithSameBaseType = otherMeta.baseType && this.field.components.some((component) => component.otherMetadata().baseType === otherMeta.baseType && !(other instanceof component.otherMetadata().cstr));
161
+ setField(this.entity, this.fieldName, other.isNewEntity || hasComponentsWithSameBaseType ? other : other.idTagged);
162
+ } else setField(this.entity, this.fieldName, other);
159
163
  if (typeof other === "string") {
160
164
  this.loaded = void 0;
161
165
  this._isLoaded = false;
@@ -1 +1 @@
1
- {"version":3,"file":"PolymorphicReference.js","names":["#hasBeenSet"],"sources":["../../src/relations/PolymorphicReference.ts"],"sourcesContent":["import { maybeGetConstructorFromReference } from \"../configure.ts\";\nimport { type Entity, isEntity } from \"../Entity.ts\";\nimport { type IdOf, type TaggedId, sameEntity } from \"../EntityManager.ts\";\nimport { type PolymorphicFieldComponent, getMetadata } from \"../EntityMetadata.ts\";\nimport { getField, setField } from \"../fields.ts\";\nimport {\n type OneToOneReference,\n type PolymorphicField,\n type Reference,\n ensureNotDeleted,\n fail,\n getConstructorFromTaggedId,\n getInstanceData,\n maybeResolveReferenceToId,\n} from \"../index.ts\";\nimport { lazyField } from \"../newEntity.ts\";\nimport { AbstractRelationImpl, isCascadeDelete } from \"./AbstractRelationImpl.ts\";\nimport { failIfNewEntity, failNoId } from \"./ManyToOneReference.ts\";\nimport { OneToManyCollection } from \"./OneToManyCollection.ts\";\nimport { ReferenceN } from \"./ReferenceSymbols.ts\";\nimport { RelationT, RelationU } from \"./RelationSymbols.ts\";\n\nexport function hasOnePolymorphic<\n T extends Entity,\n U extends Entity,\n N extends never | undefined,\n>(): PolymorphicReference<T, U, N> {\n return lazyField((entity: T, fieldName) => {\n return new PolymorphicReferenceImpl<T, U, N>(entity, fieldName as keyof T & string);\n });\n}\n\n/** Type guard utility for determining if an entity field is a PolymorphicReference. */\nexport function isPolymorphicReference(maybeReference: any): maybeReference is PolymorphicReference<any, any, any> {\n return maybeReference instanceof PolymorphicReferenceImpl;\n}\n\n/**\n * A reference that can be assigned to multiple different entity types.\n *\n * I.e. a `Comment.parent` reference that can be an `Author` or `Book`.\n *\n * The `U` generic will be the type union of `Author | Book`.\n */\nexport interface PolymorphicReference<\n T extends Entity,\n U extends Entity,\n N extends never | undefined,\n> extends Reference<T, U, N> {\n /** Returns the id of the current assigned entity, or a runtime error if either 1) unset or 2) set to a new entity that doesn't have an `id` yet. */\n id: IdOf<U>;\n\n /** Returns the id of the current assigned entity, undefined if unset, or a runtime error if set to a new entity. */\n idIfSet: IdOf<U> | undefined;\n\n /** Returns the id of the current assigned entity, undefined if unset, or undefined if set to a new entity. */\n idMaybe: IdOf<U> | undefined;\n\n idTagged: string;\n\n /** Returns `true` if this relation is currently set (i.e. regardless of whether it's loaded, or if it is set but the assigned entity doesn't have an id saved. */\n readonly isSet: boolean;\n}\n\n/**\n * Manages a set of foreign keys from one entity to another, i.e. `Comment.parent --> Book | BookReview`.\n *\n * We keep the current `parent` / `parent.id` value in the `__orm.data` hash, where the\n * current value could be either the `comments.parent_book_id` / `comments.parent_book_review_id` id (as a tagged string)\n * from the database, or an entity `Book` / `BookReview` that the user has set.\n *\n * Note that if any of our columns (eg `comments.parent_book_review_id`) is unique, this `PolymorphicReference` will\n * essentially be half of a one-to-one relationship, but we'll keep using this reference on the \"owning\" side; the other\n * side, i.e. `BookReview.comment` will use a `OneToOneReference` to point back to us.\n */\nexport class PolymorphicReferenceImpl<T extends Entity, U extends Entity, N extends never | undefined>\n extends AbstractRelationImpl<T, U>\n implements PolymorphicReference<T, U, N>\n{\n private loaded: U | N | undefined;\n // We need a separate boolean to b/c loaded == undefined can still mean \"_isLoaded\" for nullable fks.\n private _isLoaded = false;\n private field: PolymorphicField;\n #hasBeenSet = false;\n\n constructor(\n entity: T,\n public fieldName: keyof T & string,\n ) {\n super(entity);\n this.field = getMetadata(entity).allFields[this.fieldName] as PolymorphicField;\n if (getInstanceData(entity).isOrWasNew) {\n this._isLoaded = true;\n }\n }\n\n private get currentComponent(): PolymorphicFieldComponent | N {\n const cstr = maybeGetConstructorFromReference(this.current());\n return this.field.components.find((c) => c.otherMetadata().cstr === cstr) as any;\n }\n\n private get isCascadeDelete(): boolean {\n return isCascadeDelete(this, this.fieldName);\n }\n\n async load(opts: { withDeleted?: boolean; forceReload?: boolean } = {}): Promise<U | N> {\n ensureNotDeleted(this.entity, \"pending\");\n const current = this.current();\n // Resolve the id to an entity\n if (!isEntity(current) && current !== undefined && (!this._isLoaded || opts.forceReload)) {\n this.loaded = (await this.entity.em.load(getConstructorFromTaggedId(current), current)) as any as U;\n }\n this._isLoaded = true;\n return this.filterDeleted(this.loaded!, opts);\n }\n\n set(other: U | N): void {\n this.setImpl(other);\n }\n\n get isSet(): boolean {\n return this.current() !== undefined;\n }\n\n get isLoaded(): boolean {\n return this._isLoaded;\n }\n\n /**\n * Looks for an entity in `EntityManager`, b/c we may have it in memory even if\n * our reference is not specifically loaded.\n */\n maybeFindEntity(): U | undefined {\n // Check this.loaded first b/c a new entity won't have an id yet\n const { idTaggedMaybe } = this;\n return this.loaded ?? (idTaggedMaybe !== undefined ? (this.entity.em.getEntity(idTaggedMaybe) as U) : undefined);\n }\n\n get isPreloaded(): boolean {\n return !!this.maybeFindEntity();\n }\n\n preload(): void {\n this.loaded = this.maybeFindEntity();\n this._isLoaded = true;\n }\n\n private unload(): void {\n this.loaded = undefined;\n this._isLoaded = false;\n }\n\n import(other: PolymorphicReferenceImpl<T, U, N>, findEntity: (e: U) => U): void {\n this.loaded = other.loaded ? findEntity(other.loaded) : undefined;\n this._isLoaded = true;\n }\n\n private doGet(opts?: { withDeleted?: boolean }): U | N {\n ensureNotDeleted(this.entity, \"pending\");\n // This should only be callable in the type system if we've already resolved this to an instance,\n // but, just in case we somehow got here in an unloaded state, check to see if we're already in the UoW\n if (!this._isLoaded) {\n const existing = this.maybeFindExisting();\n if (existing === undefined) {\n throw new Error(`${this.entity}.${this.fieldName} was not loaded`);\n }\n this.loaded = existing;\n this._isLoaded = true;\n }\n\n return this.filterDeleted(this.loaded!, opts);\n }\n\n get getWithDeleted(): U | N {\n return this.doGet({ withDeleted: true });\n }\n\n get get(): U | N {\n return this.doGet({ withDeleted: false });\n }\n\n get id(): IdOf<U> {\n return this.idMaybe || failNoId(this.entity, this.fieldName, this.current());\n }\n\n get idMaybe(): IdOf<U> | undefined {\n ensureNotDeleted(this.entity, \"pending\");\n return maybeResolveReferenceToId(this.current()) as IdOf<U> | undefined;\n }\n\n get idIfSet(): IdOf<U> | N | undefined {\n return this.idMaybe || failIfNewEntity(this.entity, this.fieldName, this.current());\n }\n\n get idTagged(): string {\n return this.idTaggedMaybe || failNoId(this.entity, this.fieldName, this.current());\n }\n\n get idTaggedMaybe(): string | undefined {\n ensureNotDeleted(this.entity, \"pending\");\n return maybeResolveReferenceToId(this.current());\n }\n\n get hasBeenSet() {\n return this.#hasBeenSet;\n }\n\n // private impl\n\n setFromOpts(other: U): void {\n this.setImpl(other);\n }\n\n maybeCascadeDelete(): void {\n if (this.isCascadeDelete) {\n const current = this.current({ withDeleted: true });\n if (current !== undefined && typeof current !== \"string\") {\n this.entity.em.delete(current as U);\n }\n }\n }\n\n async cleanupOnEntityDeleted(): Promise<void> {\n // if we are going to delete this relation as well, then we don't need to clean it up\n if (this.isCascadeDelete) return;\n const current = await this.load({ withDeleted: true });\n if (current !== undefined) {\n const o2m = this.getOtherRelation(current);\n if (o2m instanceof OneToManyCollection) {\n o2m.remove(this.entity, { requireLoaded: false });\n } else {\n o2m.set(undefined as any);\n }\n }\n setField(this.entity, this.fieldName, undefined);\n this.loaded = undefined as any;\n this._isLoaded = true;\n }\n\n // Internal method used by PolymorphicReference\n setImpl(other: U | N): void {\n this.#hasBeenSet = true;\n\n if (sameEntity(other, this.current({ withDeleted: true }))) {\n return;\n }\n\n if (\n other !== undefined &&\n !this.field.components.some(\n (c) =>\n other instanceof c.otherMetadata().cstr ||\n (typeof other === \"string\" && getConstructorFromTaggedId(other) === c.otherMetadata().cstr),\n )\n ) {\n fail(`${other} cannot be set as '${this.field.fieldName}' on ${this.entity}`);\n }\n\n // we may not be loaded yet, but our previous entity might already be in the UoW\n const previousLoaded = this.loaded ?? this.maybeFindExisting();\n\n ensureNotDeleted(this.entity, \"pending\");\n\n // Prefer to keep the id in our data hash, but if this is a new entity w/o an id, use the entity itself\n const changed = setField(this.entity, this.fieldName, isEntity(other) ? (other?.idTaggedMaybe ?? other) : other);\n\n if (typeof other === \"string\") {\n this.loaded = undefined;\n this._isLoaded = false;\n } else {\n this.loaded = other;\n this._isLoaded = true;\n }\n\n // If had an existing value, remove us from its collection\n if (previousLoaded) {\n const prevRelation = this.getOtherRelation(previousLoaded);\n if (prevRelation instanceof OneToManyCollection) {\n prevRelation.removeIfLoaded(this.entity);\n } else {\n prevRelation.set(undefined as any);\n }\n }\n if (other !== undefined && isEntity(other)) {\n const newRelation = this.getOtherRelation(other);\n if (newRelation instanceof OneToManyCollection) {\n newRelation.add(this.entity);\n } else {\n newRelation.set(this.entity);\n }\n }\n }\n\n // We need to keep U in data[fieldName] to handle entities without an id assigned yet.\n current(opts?: { withDeleted?: boolean }): U | TaggedId | N {\n const current = getField(this.entity, this.fieldName);\n if (current !== undefined && isEntity(current)) {\n return this.filterDeleted(current as U, opts);\n }\n return current;\n }\n\n public toString(): string {\n return `PolymorphicReference(entity: ${this.entity}, fieldName: ${\n this.fieldName\n }, otherType: ${this.currentComponent?.otherMetadata().type}, otherFieldName: ${\n this.currentComponent?.otherFieldName\n }, id: ${this.id})`;\n }\n\n private filterDeleted(entity: U | N, opts?: { withDeleted?: boolean }): U | N {\n return opts?.withDeleted === true || entity === undefined || !entity.isDeletedEntity ? entity : (undefined as N);\n }\n\n /** Returns the other relation that points back at us, i.e. we're `comment.parent_book_id` and this is `Book.comments`. */\n private getOtherRelation(other: U): OneToManyCollection<U, T> | OneToOneReference<U, T> {\n const component = this.field.components.find((c) => other instanceof c.otherMetadata().cstr) as any;\n return (other as U)[component?.otherFieldName as keyof U] as any;\n }\n\n private maybeFindExisting(): U | undefined {\n return this.idTaggedMaybe !== undefined ? (this.entity.em.getEntity(this.idTagged) as U) : undefined;\n }\n\n [RelationT]: T = null!;\n [RelationU]: U = null!;\n [ReferenceN]: N = null!;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"PolymorphicReference.js","names":["#hasBeenSet"],"sources":["../../src/relations/PolymorphicReference.ts"],"sourcesContent":["import { maybeGetConstructorFromReference } from \"../configure.ts\";\nimport { type Entity, isEntity } from \"../Entity.ts\";\nimport { type IdOf, type TaggedId, sameEntity } from \"../EntityManager.ts\";\nimport { type PolymorphicFieldComponent, getMetadata } from \"../EntityMetadata.ts\";\nimport { getField, setField } from \"../fields.ts\";\nimport {\n type OneToOneReference,\n type PolymorphicField,\n type Reference,\n ensureNotDeleted,\n fail,\n getConstructorFromTaggedId,\n getInstanceData,\n maybeResolveReferenceToId,\n} from \"../index.ts\";\nimport { lazyField } from \"../newEntity.ts\";\nimport { AbstractRelationImpl, isCascadeDelete } from \"./AbstractRelationImpl.ts\";\nimport { failIfNewEntity, failNoId } from \"./ManyToOneReference.ts\";\nimport { OneToManyCollection } from \"./OneToManyCollection.ts\";\nimport { ReferenceN } from \"./ReferenceSymbols.ts\";\nimport { RelationT, RelationU } from \"./RelationSymbols.ts\";\n\nexport function hasOnePolymorphic<\n T extends Entity,\n U extends Entity,\n N extends never | undefined,\n>(): PolymorphicReference<T, U, N> {\n return lazyField((entity: T, fieldName) => {\n return new PolymorphicReferenceImpl<T, U, N>(entity, fieldName as keyof T & string);\n });\n}\n\n/** Type guard utility for determining if an entity field is a PolymorphicReference. */\nexport function isPolymorphicReference(maybeReference: any): maybeReference is PolymorphicReference<any, any, any> {\n return maybeReference instanceof PolymorphicReferenceImpl;\n}\n\n/**\n * A reference that can be assigned to multiple different entity types.\n *\n * I.e. a `Comment.parent` reference that can be an `Author` or `Book`.\n *\n * The `U` generic will be the type union of `Author | Book`.\n */\nexport interface PolymorphicReference<\n T extends Entity,\n U extends Entity,\n N extends never | undefined,\n> extends Reference<T, U, N> {\n /** Returns the id of the current assigned entity, or a runtime error if either 1) unset or 2) set to a new entity that doesn't have an `id` yet. */\n id: IdOf<U>;\n\n /** Returns the id of the current assigned entity, undefined if unset, or a runtime error if set to a new entity. */\n idIfSet: IdOf<U> | undefined;\n\n /** Returns the id of the current assigned entity, undefined if unset, or undefined if set to a new entity. */\n idMaybe: IdOf<U> | undefined;\n\n idTagged: string;\n\n /** Returns `true` if this relation is currently set (i.e. regardless of whether it's loaded, or if it is set but the assigned entity doesn't have an id saved. */\n readonly isSet: boolean;\n}\n\n/**\n * Manages a set of foreign keys from one entity to another, i.e. `Comment.parent --> Book | BookReview`.\n *\n * We keep the current `parent` / `parent.id` value in the `__orm.data` hash, where the\n * current value could be either the `comments.parent_book_id` / `comments.parent_book_review_id` id (as a tagged string)\n * from the database, or an entity `Book` / `BookReview` that the user has set.\n *\n * Note that if any of our columns (eg `comments.parent_book_review_id`) is unique, this `PolymorphicReference` will\n * essentially be half of a one-to-one relationship, but we'll keep using this reference on the \"owning\" side; the other\n * side, i.e. `BookReview.comment` will use a `OneToOneReference` to point back to us.\n */\nexport class PolymorphicReferenceImpl<T extends Entity, U extends Entity, N extends never | undefined>\n extends AbstractRelationImpl<T, U>\n implements PolymorphicReference<T, U, N>\n{\n private loaded: U | N | undefined;\n // We need a separate boolean to b/c loaded == undefined can still mean \"_isLoaded\" for nullable fks.\n private _isLoaded = false;\n private field: PolymorphicField;\n #hasBeenSet = false;\n\n constructor(\n entity: T,\n public fieldName: keyof T & string,\n ) {\n super(entity);\n this.field = getMetadata(entity).allFields[this.fieldName] as PolymorphicField;\n if (getInstanceData(entity).isOrWasNew) {\n this._isLoaded = true;\n }\n }\n\n private get currentComponent(): PolymorphicFieldComponent | N {\n const cstr = maybeGetConstructorFromReference(this.current());\n return this.field.components.find((c) => c.otherMetadata().cstr === cstr) as any;\n }\n\n private get isCascadeDelete(): boolean {\n return isCascadeDelete(this, this.fieldName);\n }\n\n async load(opts: { withDeleted?: boolean; forceReload?: boolean } = {}): Promise<U | N> {\n ensureNotDeleted(this.entity, \"pending\");\n const current = this.current();\n // Resolve the id to an entity\n if (!isEntity(current) && current !== undefined && (!this._isLoaded || opts.forceReload)) {\n this.loaded = (await this.entity.em.load(getConstructorFromTaggedId(current), current)) as any as U;\n }\n this._isLoaded = true;\n return this.filterDeleted(this.loaded!, opts);\n }\n\n set(other: U | N): void {\n this.setImpl(other);\n }\n\n get isSet(): boolean {\n return this.current() !== undefined;\n }\n\n get isLoaded(): boolean {\n return this._isLoaded;\n }\n\n /**\n * Looks for an entity in `EntityManager`, b/c we may have it in memory even if\n * our reference is not specifically loaded.\n */\n maybeFindEntity(): U | undefined {\n // Check this.loaded first b/c a new entity won't have an id yet\n const { idTaggedMaybe } = this;\n return this.loaded ?? (idTaggedMaybe !== undefined ? (this.entity.em.getEntity(idTaggedMaybe) as U) : undefined);\n }\n\n get isPreloaded(): boolean {\n return !!this.maybeFindEntity();\n }\n\n preload(): void {\n this.loaded = this.maybeFindEntity();\n this._isLoaded = true;\n }\n\n private unload(): void {\n this.loaded = undefined;\n this._isLoaded = false;\n }\n\n import(other: PolymorphicReferenceImpl<T, U, N>, findEntity: (e: U) => U): void {\n this.loaded = other.loaded ? findEntity(other.loaded) : undefined;\n this._isLoaded = true;\n }\n\n private doGet(opts?: { withDeleted?: boolean }): U | N {\n ensureNotDeleted(this.entity, \"pending\");\n // This should only be callable in the type system if we've already resolved this to an instance,\n // but, just in case we somehow got here in an unloaded state, check to see if we're already in the UoW\n if (!this._isLoaded) {\n const existing = this.maybeFindExisting();\n if (existing === undefined) {\n throw new Error(`${this.entity}.${this.fieldName} was not loaded`);\n }\n this.loaded = existing;\n this._isLoaded = true;\n }\n\n return this.filterDeleted(this.loaded!, opts);\n }\n\n get getWithDeleted(): U | N {\n return this.doGet({ withDeleted: true });\n }\n\n get get(): U | N {\n return this.doGet({ withDeleted: false });\n }\n\n get id(): IdOf<U> {\n return this.idMaybe || failNoId(this.entity, this.fieldName, this.current());\n }\n\n get idMaybe(): IdOf<U> | undefined {\n ensureNotDeleted(this.entity, \"pending\");\n return maybeResolveReferenceToId(this.current()) as IdOf<U> | undefined;\n }\n\n get idIfSet(): IdOf<U> | N | undefined {\n return this.idMaybe || failIfNewEntity(this.entity, this.fieldName, this.current());\n }\n\n get idTagged(): string {\n return this.idTaggedMaybe || failNoId(this.entity, this.fieldName, this.current());\n }\n\n get idTaggedMaybe(): string | undefined {\n ensureNotDeleted(this.entity, \"pending\");\n return maybeResolveReferenceToId(this.current());\n }\n\n get hasBeenSet() {\n return this.#hasBeenSet;\n }\n\n // private impl\n\n setFromOpts(other: U): void {\n this.setImpl(other);\n }\n\n maybeCascadeDelete(): void {\n if (this.isCascadeDelete) {\n const current = this.current({ withDeleted: true });\n if (current !== undefined && typeof current !== \"string\") {\n this.entity.em.delete(current as U);\n }\n }\n }\n\n async cleanupOnEntityDeleted(): Promise<void> {\n // if we are going to delete this relation as well, then we don't need to clean it up\n if (this.isCascadeDelete) return;\n const current = await this.load({ withDeleted: true });\n if (current !== undefined) {\n const o2m = this.getOtherRelation(current);\n if (o2m instanceof OneToManyCollection) {\n o2m.remove(this.entity, { requireLoaded: false });\n } else {\n o2m.set(undefined as any);\n }\n }\n setField(this.entity, this.fieldName, undefined);\n this.loaded = undefined as any;\n this._isLoaded = true;\n }\n\n // Internal method used by PolymorphicReference\n setImpl(other: U | N): void {\n this.#hasBeenSet = true;\n\n if (sameEntity(other, this.current({ withDeleted: true }))) {\n return;\n }\n\n if (\n other !== undefined &&\n !this.field.components.some(\n (c) =>\n other instanceof c.otherMetadata().cstr ||\n (typeof other === \"string\" && getConstructorFromTaggedId(other) === c.otherMetadata().cstr),\n )\n ) {\n fail(`${other} cannot be set as '${this.field.fieldName}' on ${this.entity}`);\n }\n\n // we may not be loaded yet, but our previous entity might already be in the UoW\n const previousLoaded = this.loaded ?? this.maybeFindExisting();\n\n ensureNotDeleted(this.entity, \"pending\");\n\n // Keep the entity when its tagged id cannot distinguish between sibling subtypes.\n if (isEntity(other)) {\n const otherMeta = getMetadata(other);\n const hasComponentsWithSameBaseType =\n otherMeta.baseType &&\n this.field.components.some(\n (component) =>\n component.otherMetadata().baseType === otherMeta.baseType &&\n !(other instanceof component.otherMetadata().cstr),\n );\n setField(\n this.entity,\n this.fieldName,\n other.isNewEntity || hasComponentsWithSameBaseType ? other : other.idTagged,\n );\n } else {\n setField(this.entity, this.fieldName, other);\n }\n\n if (typeof other === \"string\") {\n this.loaded = undefined;\n this._isLoaded = false;\n } else {\n this.loaded = other;\n this._isLoaded = true;\n }\n\n // If had an existing value, remove us from its collection\n if (previousLoaded) {\n const prevRelation = this.getOtherRelation(previousLoaded);\n if (prevRelation instanceof OneToManyCollection) {\n prevRelation.removeIfLoaded(this.entity);\n } else {\n prevRelation.set(undefined as any);\n }\n }\n if (other !== undefined && isEntity(other)) {\n const newRelation = this.getOtherRelation(other);\n if (newRelation instanceof OneToManyCollection) {\n newRelation.add(this.entity);\n } else {\n newRelation.set(this.entity);\n }\n }\n }\n\n // We need to keep U in data[fieldName] to handle entities without an id assigned yet.\n current(opts?: { withDeleted?: boolean }): U | TaggedId | N {\n const current = getField(this.entity, this.fieldName);\n if (current !== undefined && isEntity(current)) {\n return this.filterDeleted(current as U, opts);\n }\n return current;\n }\n\n public toString(): string {\n return `PolymorphicReference(entity: ${this.entity}, fieldName: ${\n this.fieldName\n }, otherType: ${this.currentComponent?.otherMetadata().type}, otherFieldName: ${\n this.currentComponent?.otherFieldName\n }, id: ${this.id})`;\n }\n\n private filterDeleted(entity: U | N, opts?: { withDeleted?: boolean }): U | N {\n return opts?.withDeleted === true || entity === undefined || !entity.isDeletedEntity ? entity : (undefined as N);\n }\n\n /** Returns the other relation that points back at us, i.e. we're `comment.parent_book_id` and this is `Book.comments`. */\n private getOtherRelation(other: U): OneToManyCollection<U, T> | OneToOneReference<U, T> {\n const component = this.field.components.find((c) => other instanceof c.otherMetadata().cstr) as any;\n return (other as U)[component?.otherFieldName as keyof U] as any;\n }\n\n private maybeFindExisting(): U | undefined {\n return this.idTaggedMaybe !== undefined ? (this.entity.em.getEntity(this.idTagged) as U) : undefined;\n }\n\n [RelationT]: T = null!;\n [RelationU]: U = null!;\n [ReferenceN]: N = null!;\n}\n"],"mappings":"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"}
package/build/serde.cjs CHANGED
@@ -274,9 +274,11 @@ var PolymorphicKeySerde = class {
274
274
  isNullableArray: false,
275
275
  otherMetadata: comp.otherMetadata,
276
276
  dbValue(data) {
277
- const id = require_keys.maybeResolveReferenceToId(data[fieldName]);
278
- const cstr = id ? require_configure.getConstructorFromTaggedId(id) : void 0;
279
- return (hasMultipleComponentsWithSameBaseType ? cstr === comp.otherMetadata().cstr : cstr === require_EntityMetadata.getBaseMeta(comp.otherMetadata()).cstr) ? require_keys.keyToNumber(comp.otherMetadata(), id) : void 0;
277
+ const value = data[fieldName];
278
+ const id = require_keys.maybeResolveReferenceToId(value);
279
+ const cstr = require_Entity.isEntity(value) ? require_EntityMetadata.getMetadata(value).cstr : id ? require_configure.getConstructorFromTaggedId(id) : void 0;
280
+ const otherMeta = comp.otherMetadata();
281
+ return (hasMultipleComponentsWithSameBaseType ? cstr === otherMeta.cstr : cstr === otherMeta.cstr || cstr === require_EntityMetadata.getBaseMeta(otherMeta).cstr || otherMeta.subTypes.some((subTypeMeta) => cstr === subTypeMeta.cstr)) ? require_keys.keyToNumber(comp.otherMetadata(), id) : void 0;
280
282
  },
281
283
  mapToDb(value) {
282
284
  return require_keys.keyToNumber(comp.otherMetadata(), typeof value === "number" ? value : require_keys.maybeResolveReferenceToId(value));
@@ -1 +1 @@
1
- {"version":3,"file":"serde.cjs","names":["createRequire","plainDateMapper","plainTimeMapper","plainDateTimeMapper","getRuntimeConfig","requireTemporal","zonedDateTimeMapper","keyToTaggedId","isEntity","getMetadata","keyToNumber","maybeResolveReferenceToId","groupBy","getBaseMeta","getConstructorFromTaggedId","isDefined"],"sources":["../src/serde.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\nimport { type InsertFixup } from \"./drivers/EntityWriter.ts\";\nimport { type Field, type PolymorphicField, type SerdeField, getBaseMeta, getMetadata } from \"./EntityMetadata.ts\";\nimport {\n type Entity,\n type EntityMetadata,\n getConstructorFromTaggedId,\n isDefined,\n isEntity,\n keyToNumber,\n keyToTaggedId,\n maybeResolveReferenceToId,\n} from \"./index.ts\";\nimport { type RowData } from \"./RowData.ts\";\nimport { getRuntimeConfig } from \"./runtimeConfig.ts\";\nimport { type Temporal, requireTemporal } from \"./temporal.ts\";\nimport { plainDateMapper, plainDateTimeMapper, plainTimeMapper, zonedDateTimeMapper } from \"./temporalMappers.ts\";\nimport { groupBy } from \"./utils.ts\";\n\nconst runtimeRequire = createRequire(import.meta.url);\n\nexport function hasSerde(field: Field): field is SerdeField {\n return !!field.serde;\n}\n\n/**\n * The database/column serialization / deserialization details of a given field.\n *\n * Most implementations will have just a single column in `columns`, but some logical\n * domain fields can be mapped to multiple physical database columns, i.e. polymorphic\n * references.\n */\nexport interface FieldSerde {\n /** A single field might persist to multiple columns, i.e. polymorphic references. */\n columns: Column[];\n\n /**\n * Reads the field's column(s) from the entity's `(rowData, rowIndex)` query result and sets\n * the domain value(s) into the `__orm.data`.\n *\n * Reading via `rowData.get(rowIndex, columnName)` (instead of a materialized POJO row) lets\n * lazy results like `WireRowData` decode only the cells that are actually accessed.\n *\n * Originally used in `EntityManager.hydrate` to set db values into the entity, although\n * now we invoke it lazily in `getField` to avoid copying data until it's actually needed.\n */\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void;\n}\n\n/**\n * An interface that generalizes our Date-vs-Temporal support.\n *\n * @typeParam T - The domain type, i.e. `Date` or `Temporal.ZonedDateTime`.\n */\nexport interface TimestampSerde<T> extends FieldSerde {\n /** Given business logic that wants to \"set this value to 'now'\", converts its Date to our T. */\n mapFromNow(now: Date): T;\n /** Used for reading oplock values. */\n dbValue(data: any): any;\n}\n\n/** A specific physical column of a logical field. */\nexport interface Column {\n columnName: string;\n dbType: string;\n /** From the given `__orm.data` hash, return this columns value, i.e. for putting in `UPDATE` params. */\n dbValue(data: any, entity: Entity, tableName: string, fixups: InsertFixup[] | undefined): any;\n /**\n * Used by `fork`, `importEntity`, and `run` to create an __orm.row from an __orm.data. Should output what we would\n * expect from a db query\n */\n rowValue(data: any): any;\n /** For a given domain value, return the database value, i.e. for putting `em.find` params into a db WHERE clause. */\n mapToDb(value: any): any;\n /**\n * For converting `json_agg`-preloaded JSON values into *ResultSet* type.\n *\n * I.e. our `#orm.row` hash always wants the db-side value, as-is coming from the database driver.\n * During `getField`, we always expect the ResultSet value, b/c we lazy call\n * `setOnEntityFromRowData` to go from db-value to domain-value.\n *\n * So `mapFromJsonAgg` is for preloading that needs to go from json-value *only to db-value*.\n *\n * I.e. for types like temporal, which we keep as strings in `row`, the json-value will match\n * the db-value, so `mapFromJsonAgg` can be a noop. But (at one point...) `Date`s we store as\n * `Date`s in `row`, so then `mapFromJsonAgg` needs to convert string json-value value into a `Date`.\n */\n mapFromJsonAgg(value: any): any;\n isArray: boolean;\n /** Used by `unnest_arrays`. */\n isNullableArray: boolean;\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 FieldSerde {\n columns = [this];\n isArray: boolean = false;\n isNullableArray: boolean = false;\n\n public constructor(\n protected fieldName: string,\n public columnName: string,\n public dbType: string,\n private mapper: CustomSerde<any, any>,\n // Allow subtypes to override isArray\n isArray?: boolean,\n isNullableArray = false, // only set for nullable arrays\n ) {\n if (isArray !== undefined) this.isArray = isArray;\n this.isNullableArray = isNullableArray;\n }\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] =\n value !== undefined\n ? this.isArray\n ? value.map((value: any) => this.mapper.fromDb(value))\n : this.mapper.fromDb(value)\n : undefined;\n }\n\n dbValue(data: any): any {\n const fieldData = data[this.fieldName];\n return fieldData !== undefined\n ? this.isArray\n ? fieldData.map((value: any) => this.mapper.toDb(value))\n : this.mapper.toDb(fieldData)\n : undefined;\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any): any {\n return value === null ? value : this.mapper.toDb(value);\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 FieldSerde {\n columns = [this];\n\n constructor(\n protected fieldName: string,\n public columnName: string,\n public dbType: string,\n public isArray = false,\n public isNullableArray = false, // only set for nullable arrays\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any) {\n return this.mapToDb(data[this.fieldName]);\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value;\n }\n}\n\nexport class DateSerde extends PrimitiveSerde implements TimestampSerde<Date> {\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 `setOnEntity` (i.e.\n * `RunPlugin` mirroring writes into the test em) turn every date into a string, because our\n * `setOnEntity` assigns the row value as-is.\n */\n rowValue(data: any): any {\n return data[this.fieldName];\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(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainDateMapper, isArray, isNullableArray);\n }\n}\n\n/** Converts `TIME`s to `Temporal.PlainTime`s. */\nexport class PlainTimeSerde extends CustomSerdeAdapter {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainTimeMapper, isArray, isNullableArray);\n }\n}\n\n/** Converts `TIMESTAMP`s to `Temporal.PlainDateTime`s. */\nexport class PlainDateTimeSerde extends CustomSerdeAdapter implements TimestampSerde<Temporal.PlainDateTime> {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainDateTimeMapper, isArray, isNullableArray);\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 TimestampSerde<Temporal.ZonedDateTime> {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, zonedDateTimeMapper, isArray, isNullableArray);\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 FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n dbType = \"bigint\";\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] = value ? BigInt(value) : value;\n }\n\n dbValue(data: any) {\n return data[this.fieldName];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? 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 FieldSerde {\n dbType = \"decimal\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] = value !== undefined ? Number(value) : value;\n }\n\n dbValue(data: any) {\n return data[this.fieldName];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : Number(value);\n }\n}\n\n/** Maps physical integer keys to logical string IDs \"because GraphQL\". */\nexport class KeySerde implements FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n private meta: {\n tagName: string;\n idDbType: \"bigint\" | \"int\" | \"uuid\" | \"text\";\n };\n\n constructor(\n tagName: string,\n private fieldName: string,\n public columnName: string,\n public dbType: \"bigint\" | \"int\" | \"uuid\" | \"text\",\n ) {\n this.meta = {\n tagName,\n idDbType: dbType,\n };\n }\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = keyToTaggedId(this.meta, rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any, entity: Entity, tableName: string, fixups: InsertFixup[] | undefined) {\n const value = data[this.fieldName];\n if (\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({\n entity,\n tableName,\n column: this,\n value: keyToNumber(this.meta, maybeResolveReferenceToId(value)),\n });\n return null;\n }\n return keyToNumber(this.meta, maybeResolveReferenceToId(value));\n }\n\n rowValue(data: 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.dbValue(data, undefined!, undefined!, undefined);\n }\n\n mapToDb(value: any) {\n // Sometimes the nilIdValue will pass -1 as already a number, but usually this should be a tagged id\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 mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class PolymorphicKeySerde implements FieldSerde {\n constructor(\n private meta: () => EntityMetadata,\n private fieldName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n for (const column of this.columns) {\n const value = rowData.get(rowIndex, column.columnName);\n if (value) data[this.fieldName] ??= keyToTaggedId(column.otherMetadata(), value);\n }\n }\n\n // Lazy b/c we use PolymorphicField which we can't access in our cstr\n get columns(): Array<Column & { otherMetadata: () => EntityMetadata }> {\n const { fieldName } = this;\n\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.field.components, (comp) => getBaseMeta(comp.otherMetadata()).type).values(),\n ].some((group) => group.length > 1);\n\n return this.field.components.map((comp) => ({\n columnName: comp.columnName,\n dbType: comp.otherMetadata().idDbType,\n isArray: false,\n isNullableArray: false,\n otherMetadata: comp.otherMetadata,\n dbValue(data: any): any {\n const id = maybeResolveReferenceToId(data[fieldName]);\n const cstr = id ? getConstructorFromTaggedId(id) : undefined;\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 idAppliesToThisColumn = hasMultipleComponentsWithSameBaseType\n ? cstr === comp.otherMetadata().cstr\n : cstr === getBaseMeta(comp.otherMetadata()).cstr;\n return idAppliesToThisColumn ? keyToNumber(comp.otherMetadata(), id) : undefined;\n },\n mapToDb(value: any): any {\n return keyToNumber(comp.otherMetadata(), typeof value === \"number\" ? value : maybeResolveReferenceToId(value));\n },\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n },\n rowValue(data: any): any {\n return this.dbValue(data);\n },\n }));\n }\n\n get columnName(): string {\n throw new Error(\"Unsupported\");\n }\n\n // Lazy b/c we use PolymorphicField which we can't access in our cstr\n private get field(): PolymorphicField {\n return this.meta().fields[this.fieldName] as PolymorphicField;\n }\n}\n\nexport class EnumFieldSerde implements FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n public dbType: \"int\" | \"uuid\",\n private enumObject: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = this.enumObject.findById(rowData.get(rowIndex, this.columnName))?.code;\n }\n\n dbValue(data: any) {\n return this.enumObject.findByCode(data[this.fieldName])?.id;\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return this.enumObject.findByCode(value)?.id;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class EnumArrayFieldSerde implements FieldSerde {\n isArray = true;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n public dbType: \"int[]\" | \"uuid[]\",\n public isNullableArray: boolean,\n private enumObject: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] =\n rowData.get(rowIndex, this.columnName)?.map((id: any) => this.enumObject.findById(id).code) || [];\n }\n\n dbValue(data: any) {\n return data[this.fieldName]?.map((code: any) => this.enumObject.getByCode(code).id) || [];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return !value ? [] : value.map((code: any) => this.enumObject.getByCode(code).id);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nfunction maybeNullToUndefined(value: any): any {\n return value === null ? undefined : value;\n}\n\n/** Similar to SimpleSerde, but applies the superstruct `assert` function when reading values from the db. */\nexport class SuperstructSerde implements FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\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(\n private fieldName: string,\n public columnName: string,\n private superstruct: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n if (value) {\n this.assert(value, this.superstruct);\n }\n data[this.fieldName] = value;\n }\n\n dbValue(data: any) {\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n return data[this.fieldName];\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class JsonSerde implements FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any) {\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n const json = JSON.stringify(data[this.fieldName]);\n return isDefined(json) ? JSON.parse(json) : undefined;\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : 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 FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n private zodSchema: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n if (value) {\n data[this.fieldName] = this.zodSchema.parse(value);\n } else {\n data[this.fieldName] = value;\n }\n }\n\n dbValue(data: any) {\n // assume the data is already valid b/c it came from the entity\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n return data[this.fieldName];\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"serde.cjs","names":["createRequire","plainDateMapper","plainTimeMapper","plainDateTimeMapper","getRuntimeConfig","requireTemporal","zonedDateTimeMapper","keyToTaggedId","isEntity","getMetadata","keyToNumber","maybeResolveReferenceToId","groupBy","getBaseMeta","getConstructorFromTaggedId","isDefined"],"sources":["../src/serde.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\nimport { type InsertFixup } from \"./drivers/EntityWriter.ts\";\nimport { type Field, type PolymorphicField, type SerdeField, getBaseMeta, getMetadata } from \"./EntityMetadata.ts\";\nimport {\n type Entity,\n type EntityMetadata,\n getConstructorFromTaggedId,\n isDefined,\n isEntity,\n keyToNumber,\n keyToTaggedId,\n maybeResolveReferenceToId,\n} from \"./index.ts\";\nimport { type RowData } from \"./RowData.ts\";\nimport { getRuntimeConfig } from \"./runtimeConfig.ts\";\nimport { type Temporal, requireTemporal } from \"./temporal.ts\";\nimport { plainDateMapper, plainDateTimeMapper, plainTimeMapper, zonedDateTimeMapper } from \"./temporalMappers.ts\";\nimport { groupBy } from \"./utils.ts\";\n\nconst runtimeRequire = createRequire(import.meta.url);\n\nexport function hasSerde(field: Field): field is SerdeField {\n return !!field.serde;\n}\n\n/**\n * The database/column serialization / deserialization details of a given field.\n *\n * Most implementations will have just a single column in `columns`, but some logical\n * domain fields can be mapped to multiple physical database columns, i.e. polymorphic\n * references.\n */\nexport interface FieldSerde {\n /** A single field might persist to multiple columns, i.e. polymorphic references. */\n columns: Column[];\n\n /**\n * Reads the field's column(s) from the entity's `(rowData, rowIndex)` query result and sets\n * the domain value(s) into the `__orm.data`.\n *\n * Reading via `rowData.get(rowIndex, columnName)` (instead of a materialized POJO row) lets\n * lazy results like `WireRowData` decode only the cells that are actually accessed.\n *\n * Originally used in `EntityManager.hydrate` to set db values into the entity, although\n * now we invoke it lazily in `getField` to avoid copying data until it's actually needed.\n */\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void;\n}\n\n/**\n * An interface that generalizes our Date-vs-Temporal support.\n *\n * @typeParam T - The domain type, i.e. `Date` or `Temporal.ZonedDateTime`.\n */\nexport interface TimestampSerde<T> extends FieldSerde {\n /** Given business logic that wants to \"set this value to 'now'\", converts its Date to our T. */\n mapFromNow(now: Date): T;\n /** Used for reading oplock values. */\n dbValue(data: any): any;\n}\n\n/** A specific physical column of a logical field. */\nexport interface Column {\n columnName: string;\n dbType: string;\n /** From the given `__orm.data` hash, return this columns value, i.e. for putting in `UPDATE` params. */\n dbValue(data: any, entity: Entity, tableName: string, fixups: InsertFixup[] | undefined): any;\n /**\n * Used by `fork`, `importEntity`, and `run` to create an __orm.row from an __orm.data. Should output what we would\n * expect from a db query\n */\n rowValue(data: any): any;\n /** For a given domain value, return the database value, i.e. for putting `em.find` params into a db WHERE clause. */\n mapToDb(value: any): any;\n /**\n * For converting `json_agg`-preloaded JSON values into *ResultSet* type.\n *\n * I.e. our `#orm.row` hash always wants the db-side value, as-is coming from the database driver.\n * During `getField`, we always expect the ResultSet value, b/c we lazy call\n * `setOnEntityFromRowData` to go from db-value to domain-value.\n *\n * So `mapFromJsonAgg` is for preloading that needs to go from json-value *only to db-value*.\n *\n * I.e. for types like temporal, which we keep as strings in `row`, the json-value will match\n * the db-value, so `mapFromJsonAgg` can be a noop. But (at one point...) `Date`s we store as\n * `Date`s in `row`, so then `mapFromJsonAgg` needs to convert string json-value value into a `Date`.\n */\n mapFromJsonAgg(value: any): any;\n isArray: boolean;\n /** Used by `unnest_arrays`. */\n isNullableArray: boolean;\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 FieldSerde {\n columns = [this];\n isArray: boolean = false;\n isNullableArray: boolean = false;\n\n public constructor(\n protected fieldName: string,\n public columnName: string,\n public dbType: string,\n private mapper: CustomSerde<any, any>,\n // Allow subtypes to override isArray\n isArray?: boolean,\n isNullableArray = false, // only set for nullable arrays\n ) {\n if (isArray !== undefined) this.isArray = isArray;\n this.isNullableArray = isNullableArray;\n }\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] =\n value !== undefined\n ? this.isArray\n ? value.map((value: any) => this.mapper.fromDb(value))\n : this.mapper.fromDb(value)\n : undefined;\n }\n\n dbValue(data: any): any {\n const fieldData = data[this.fieldName];\n return fieldData !== undefined\n ? this.isArray\n ? fieldData.map((value: any) => this.mapper.toDb(value))\n : this.mapper.toDb(fieldData)\n : undefined;\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any): any {\n return value === null ? value : this.mapper.toDb(value);\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 FieldSerde {\n columns = [this];\n\n constructor(\n protected fieldName: string,\n public columnName: string,\n public dbType: string,\n public isArray = false,\n public isNullableArray = false, // only set for nullable arrays\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any) {\n return this.mapToDb(data[this.fieldName]);\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value;\n }\n}\n\nexport class DateSerde extends PrimitiveSerde implements TimestampSerde<Date> {\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 `setOnEntity` (i.e.\n * `RunPlugin` mirroring writes into the test em) turn every date into a string, because our\n * `setOnEntity` assigns the row value as-is.\n */\n rowValue(data: any): any {\n return data[this.fieldName];\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(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainDateMapper, isArray, isNullableArray);\n }\n}\n\n/** Converts `TIME`s to `Temporal.PlainTime`s. */\nexport class PlainTimeSerde extends CustomSerdeAdapter {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainTimeMapper, isArray, isNullableArray);\n }\n}\n\n/** Converts `TIMESTAMP`s to `Temporal.PlainDateTime`s. */\nexport class PlainDateTimeSerde extends CustomSerdeAdapter implements TimestampSerde<Temporal.PlainDateTime> {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainDateTimeMapper, isArray, isNullableArray);\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 TimestampSerde<Temporal.ZonedDateTime> {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, zonedDateTimeMapper, isArray, isNullableArray);\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 FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n dbType = \"bigint\";\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] = value ? BigInt(value) : value;\n }\n\n dbValue(data: any) {\n return data[this.fieldName];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? 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 FieldSerde {\n dbType = \"decimal\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] = value !== undefined ? Number(value) : value;\n }\n\n dbValue(data: any) {\n return data[this.fieldName];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : Number(value);\n }\n}\n\n/** Maps physical integer keys to logical string IDs \"because GraphQL\". */\nexport class KeySerde implements FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n private meta: {\n tagName: string;\n idDbType: \"bigint\" | \"int\" | \"uuid\" | \"text\";\n };\n\n constructor(\n tagName: string,\n private fieldName: string,\n public columnName: string,\n public dbType: \"bigint\" | \"int\" | \"uuid\" | \"text\",\n ) {\n this.meta = {\n tagName,\n idDbType: dbType,\n };\n }\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = keyToTaggedId(this.meta, rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any, entity: Entity, tableName: string, fixups: InsertFixup[] | undefined) {\n const value = data[this.fieldName];\n if (\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({\n entity,\n tableName,\n column: this,\n value: keyToNumber(this.meta, maybeResolveReferenceToId(value)),\n });\n return null;\n }\n return keyToNumber(this.meta, maybeResolveReferenceToId(value));\n }\n\n rowValue(data: 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.dbValue(data, undefined!, undefined!, undefined);\n }\n\n mapToDb(value: any) {\n // Sometimes the nilIdValue will pass -1 as already a number, but usually this should be a tagged id\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 mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class PolymorphicKeySerde implements FieldSerde {\n constructor(\n private meta: () => EntityMetadata,\n private fieldName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n for (const column of this.columns) {\n const value = rowData.get(rowIndex, column.columnName);\n if (value) data[this.fieldName] ??= keyToTaggedId(column.otherMetadata(), value);\n }\n }\n\n // Lazy b/c we use PolymorphicField which we can't access in our cstr\n get columns(): Array<Column & { otherMetadata: () => EntityMetadata }> {\n const { fieldName } = this;\n\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.field.components, (comp) => getBaseMeta(comp.otherMetadata()).type).values(),\n ].some((group) => group.length > 1);\n\n return this.field.components.map((comp) => ({\n columnName: comp.columnName,\n dbType: comp.otherMetadata().idDbType,\n isArray: false,\n isNullableArray: false,\n otherMetadata: comp.otherMetadata,\n dbValue(data: any): any {\n const value = data[fieldName];\n const id = maybeResolveReferenceToId(value);\n const cstr = isEntity(value) ? getMetadata(value).cstr : id ? getConstructorFromTaggedId(id) : undefined;\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 otherMeta = comp.otherMetadata();\n const idAppliesToThisColumn = hasMultipleComponentsWithSameBaseType\n ? cstr === otherMeta.cstr\n : cstr === otherMeta.cstr ||\n cstr === getBaseMeta(otherMeta).cstr ||\n otherMeta.subTypes.some((subTypeMeta) => cstr === subTypeMeta.cstr);\n return idAppliesToThisColumn ? keyToNumber(comp.otherMetadata(), id) : undefined;\n },\n mapToDb(value: any): any {\n return keyToNumber(comp.otherMetadata(), typeof value === \"number\" ? value : maybeResolveReferenceToId(value));\n },\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n },\n rowValue(data: any): any {\n return this.dbValue(data);\n },\n }));\n }\n\n get columnName(): string {\n throw new Error(\"Unsupported\");\n }\n\n // Lazy b/c we use PolymorphicField which we can't access in our cstr\n private get field(): PolymorphicField {\n return this.meta().fields[this.fieldName] as PolymorphicField;\n }\n}\n\nexport class EnumFieldSerde implements FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n public dbType: \"int\" | \"uuid\",\n private enumObject: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = this.enumObject.findById(rowData.get(rowIndex, this.columnName))?.code;\n }\n\n dbValue(data: any) {\n return this.enumObject.findByCode(data[this.fieldName])?.id;\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return this.enumObject.findByCode(value)?.id;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class EnumArrayFieldSerde implements FieldSerde {\n isArray = true;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n public dbType: \"int[]\" | \"uuid[]\",\n public isNullableArray: boolean,\n private enumObject: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] =\n rowData.get(rowIndex, this.columnName)?.map((id: any) => this.enumObject.findById(id).code) || [];\n }\n\n dbValue(data: any) {\n return data[this.fieldName]?.map((code: any) => this.enumObject.getByCode(code).id) || [];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return !value ? [] : value.map((code: any) => this.enumObject.getByCode(code).id);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nfunction maybeNullToUndefined(value: any): any {\n return value === null ? undefined : value;\n}\n\n/** Similar to SimpleSerde, but applies the superstruct `assert` function when reading values from the db. */\nexport class SuperstructSerde implements FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\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(\n private fieldName: string,\n public columnName: string,\n private superstruct: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n if (value) {\n this.assert(value, this.superstruct);\n }\n data[this.fieldName] = value;\n }\n\n dbValue(data: any) {\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n return data[this.fieldName];\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class JsonSerde implements FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any) {\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n const json = JSON.stringify(data[this.fieldName]);\n return isDefined(json) ? JSON.parse(json) : undefined;\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : 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 FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n private zodSchema: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n if (value) {\n data[this.fieldName] = this.zodSchema.parse(value);\n } else {\n data[this.fieldName] = value;\n }\n }\n\n dbValue(data: any) {\n // assume the data is already valid b/c it came from the entity\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n return data[this.fieldName];\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"serde.d.cts","names":[],"sources":["../src/serde.ts"],"mappings":"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"}
1
+ {"version":3,"file":"serde.d.cts","names":[],"sources":["../src/serde.ts"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"serde.d.mts","names":[],"sources":["../src/serde.ts"],"mappings":"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"}
1
+ {"version":3,"file":"serde.d.mts","names":[],"sources":["../src/serde.ts"],"mappings":"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"}
package/build/serde.js CHANGED
@@ -274,9 +274,11 @@ var PolymorphicKeySerde = class {
274
274
  isNullableArray: false,
275
275
  otherMetadata: comp.otherMetadata,
276
276
  dbValue(data) {
277
- const id = maybeResolveReferenceToId(data[fieldName]);
278
- const cstr = id ? getConstructorFromTaggedId(id) : void 0;
279
- return (hasMultipleComponentsWithSameBaseType ? cstr === comp.otherMetadata().cstr : cstr === getBaseMeta(comp.otherMetadata()).cstr) ? keyToNumber(comp.otherMetadata(), id) : void 0;
277
+ const value = data[fieldName];
278
+ const id = maybeResolveReferenceToId(value);
279
+ const cstr = isEntity(value) ? getMetadata(value).cstr : id ? getConstructorFromTaggedId(id) : void 0;
280
+ const otherMeta = comp.otherMetadata();
281
+ return (hasMultipleComponentsWithSameBaseType ? cstr === otherMeta.cstr : cstr === otherMeta.cstr || cstr === getBaseMeta(otherMeta).cstr || otherMeta.subTypes.some((subTypeMeta) => cstr === subTypeMeta.cstr)) ? keyToNumber(comp.otherMetadata(), id) : void 0;
280
282
  },
281
283
  mapToDb(value) {
282
284
  return keyToNumber(comp.otherMetadata(), typeof value === "number" ? value : maybeResolveReferenceToId(value));
@@ -1 +1 @@
1
- {"version":3,"file":"serde.js","names":[],"sources":["../src/serde.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\nimport { type InsertFixup } from \"./drivers/EntityWriter.ts\";\nimport { type Field, type PolymorphicField, type SerdeField, getBaseMeta, getMetadata } from \"./EntityMetadata.ts\";\nimport {\n type Entity,\n type EntityMetadata,\n getConstructorFromTaggedId,\n isDefined,\n isEntity,\n keyToNumber,\n keyToTaggedId,\n maybeResolveReferenceToId,\n} from \"./index.ts\";\nimport { type RowData } from \"./RowData.ts\";\nimport { getRuntimeConfig } from \"./runtimeConfig.ts\";\nimport { type Temporal, requireTemporal } from \"./temporal.ts\";\nimport { plainDateMapper, plainDateTimeMapper, plainTimeMapper, zonedDateTimeMapper } from \"./temporalMappers.ts\";\nimport { groupBy } from \"./utils.ts\";\n\nconst runtimeRequire = createRequire(import.meta.url);\n\nexport function hasSerde(field: Field): field is SerdeField {\n return !!field.serde;\n}\n\n/**\n * The database/column serialization / deserialization details of a given field.\n *\n * Most implementations will have just a single column in `columns`, but some logical\n * domain fields can be mapped to multiple physical database columns, i.e. polymorphic\n * references.\n */\nexport interface FieldSerde {\n /** A single field might persist to multiple columns, i.e. polymorphic references. */\n columns: Column[];\n\n /**\n * Reads the field's column(s) from the entity's `(rowData, rowIndex)` query result and sets\n * the domain value(s) into the `__orm.data`.\n *\n * Reading via `rowData.get(rowIndex, columnName)` (instead of a materialized POJO row) lets\n * lazy results like `WireRowData` decode only the cells that are actually accessed.\n *\n * Originally used in `EntityManager.hydrate` to set db values into the entity, although\n * now we invoke it lazily in `getField` to avoid copying data until it's actually needed.\n */\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void;\n}\n\n/**\n * An interface that generalizes our Date-vs-Temporal support.\n *\n * @typeParam T - The domain type, i.e. `Date` or `Temporal.ZonedDateTime`.\n */\nexport interface TimestampSerde<T> extends FieldSerde {\n /** Given business logic that wants to \"set this value to 'now'\", converts its Date to our T. */\n mapFromNow(now: Date): T;\n /** Used for reading oplock values. */\n dbValue(data: any): any;\n}\n\n/** A specific physical column of a logical field. */\nexport interface Column {\n columnName: string;\n dbType: string;\n /** From the given `__orm.data` hash, return this columns value, i.e. for putting in `UPDATE` params. */\n dbValue(data: any, entity: Entity, tableName: string, fixups: InsertFixup[] | undefined): any;\n /**\n * Used by `fork`, `importEntity`, and `run` to create an __orm.row from an __orm.data. Should output what we would\n * expect from a db query\n */\n rowValue(data: any): any;\n /** For a given domain value, return the database value, i.e. for putting `em.find` params into a db WHERE clause. */\n mapToDb(value: any): any;\n /**\n * For converting `json_agg`-preloaded JSON values into *ResultSet* type.\n *\n * I.e. our `#orm.row` hash always wants the db-side value, as-is coming from the database driver.\n * During `getField`, we always expect the ResultSet value, b/c we lazy call\n * `setOnEntityFromRowData` to go from db-value to domain-value.\n *\n * So `mapFromJsonAgg` is for preloading that needs to go from json-value *only to db-value*.\n *\n * I.e. for types like temporal, which we keep as strings in `row`, the json-value will match\n * the db-value, so `mapFromJsonAgg` can be a noop. But (at one point...) `Date`s we store as\n * `Date`s in `row`, so then `mapFromJsonAgg` needs to convert string json-value value into a `Date`.\n */\n mapFromJsonAgg(value: any): any;\n isArray: boolean;\n /** Used by `unnest_arrays`. */\n isNullableArray: boolean;\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 FieldSerde {\n columns = [this];\n isArray: boolean = false;\n isNullableArray: boolean = false;\n\n public constructor(\n protected fieldName: string,\n public columnName: string,\n public dbType: string,\n private mapper: CustomSerde<any, any>,\n // Allow subtypes to override isArray\n isArray?: boolean,\n isNullableArray = false, // only set for nullable arrays\n ) {\n if (isArray !== undefined) this.isArray = isArray;\n this.isNullableArray = isNullableArray;\n }\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] =\n value !== undefined\n ? this.isArray\n ? value.map((value: any) => this.mapper.fromDb(value))\n : this.mapper.fromDb(value)\n : undefined;\n }\n\n dbValue(data: any): any {\n const fieldData = data[this.fieldName];\n return fieldData !== undefined\n ? this.isArray\n ? fieldData.map((value: any) => this.mapper.toDb(value))\n : this.mapper.toDb(fieldData)\n : undefined;\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any): any {\n return value === null ? value : this.mapper.toDb(value);\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 FieldSerde {\n columns = [this];\n\n constructor(\n protected fieldName: string,\n public columnName: string,\n public dbType: string,\n public isArray = false,\n public isNullableArray = false, // only set for nullable arrays\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any) {\n return this.mapToDb(data[this.fieldName]);\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value;\n }\n}\n\nexport class DateSerde extends PrimitiveSerde implements TimestampSerde<Date> {\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 `setOnEntity` (i.e.\n * `RunPlugin` mirroring writes into the test em) turn every date into a string, because our\n * `setOnEntity` assigns the row value as-is.\n */\n rowValue(data: any): any {\n return data[this.fieldName];\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(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainDateMapper, isArray, isNullableArray);\n }\n}\n\n/** Converts `TIME`s to `Temporal.PlainTime`s. */\nexport class PlainTimeSerde extends CustomSerdeAdapter {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainTimeMapper, isArray, isNullableArray);\n }\n}\n\n/** Converts `TIMESTAMP`s to `Temporal.PlainDateTime`s. */\nexport class PlainDateTimeSerde extends CustomSerdeAdapter implements TimestampSerde<Temporal.PlainDateTime> {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainDateTimeMapper, isArray, isNullableArray);\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 TimestampSerde<Temporal.ZonedDateTime> {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, zonedDateTimeMapper, isArray, isNullableArray);\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 FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n dbType = \"bigint\";\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] = value ? BigInt(value) : value;\n }\n\n dbValue(data: any) {\n return data[this.fieldName];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? 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 FieldSerde {\n dbType = \"decimal\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] = value !== undefined ? Number(value) : value;\n }\n\n dbValue(data: any) {\n return data[this.fieldName];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : Number(value);\n }\n}\n\n/** Maps physical integer keys to logical string IDs \"because GraphQL\". */\nexport class KeySerde implements FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n private meta: {\n tagName: string;\n idDbType: \"bigint\" | \"int\" | \"uuid\" | \"text\";\n };\n\n constructor(\n tagName: string,\n private fieldName: string,\n public columnName: string,\n public dbType: \"bigint\" | \"int\" | \"uuid\" | \"text\",\n ) {\n this.meta = {\n tagName,\n idDbType: dbType,\n };\n }\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = keyToTaggedId(this.meta, rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any, entity: Entity, tableName: string, fixups: InsertFixup[] | undefined) {\n const value = data[this.fieldName];\n if (\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({\n entity,\n tableName,\n column: this,\n value: keyToNumber(this.meta, maybeResolveReferenceToId(value)),\n });\n return null;\n }\n return keyToNumber(this.meta, maybeResolveReferenceToId(value));\n }\n\n rowValue(data: 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.dbValue(data, undefined!, undefined!, undefined);\n }\n\n mapToDb(value: any) {\n // Sometimes the nilIdValue will pass -1 as already a number, but usually this should be a tagged id\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 mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class PolymorphicKeySerde implements FieldSerde {\n constructor(\n private meta: () => EntityMetadata,\n private fieldName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n for (const column of this.columns) {\n const value = rowData.get(rowIndex, column.columnName);\n if (value) data[this.fieldName] ??= keyToTaggedId(column.otherMetadata(), value);\n }\n }\n\n // Lazy b/c we use PolymorphicField which we can't access in our cstr\n get columns(): Array<Column & { otherMetadata: () => EntityMetadata }> {\n const { fieldName } = this;\n\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.field.components, (comp) => getBaseMeta(comp.otherMetadata()).type).values(),\n ].some((group) => group.length > 1);\n\n return this.field.components.map((comp) => ({\n columnName: comp.columnName,\n dbType: comp.otherMetadata().idDbType,\n isArray: false,\n isNullableArray: false,\n otherMetadata: comp.otherMetadata,\n dbValue(data: any): any {\n const id = maybeResolveReferenceToId(data[fieldName]);\n const cstr = id ? getConstructorFromTaggedId(id) : undefined;\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 idAppliesToThisColumn = hasMultipleComponentsWithSameBaseType\n ? cstr === comp.otherMetadata().cstr\n : cstr === getBaseMeta(comp.otherMetadata()).cstr;\n return idAppliesToThisColumn ? keyToNumber(comp.otherMetadata(), id) : undefined;\n },\n mapToDb(value: any): any {\n return keyToNumber(comp.otherMetadata(), typeof value === \"number\" ? value : maybeResolveReferenceToId(value));\n },\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n },\n rowValue(data: any): any {\n return this.dbValue(data);\n },\n }));\n }\n\n get columnName(): string {\n throw new Error(\"Unsupported\");\n }\n\n // Lazy b/c we use PolymorphicField which we can't access in our cstr\n private get field(): PolymorphicField {\n return this.meta().fields[this.fieldName] as PolymorphicField;\n }\n}\n\nexport class EnumFieldSerde implements FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n public dbType: \"int\" | \"uuid\",\n private enumObject: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = this.enumObject.findById(rowData.get(rowIndex, this.columnName))?.code;\n }\n\n dbValue(data: any) {\n return this.enumObject.findByCode(data[this.fieldName])?.id;\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return this.enumObject.findByCode(value)?.id;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class EnumArrayFieldSerde implements FieldSerde {\n isArray = true;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n public dbType: \"int[]\" | \"uuid[]\",\n public isNullableArray: boolean,\n private enumObject: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] =\n rowData.get(rowIndex, this.columnName)?.map((id: any) => this.enumObject.findById(id).code) || [];\n }\n\n dbValue(data: any) {\n return data[this.fieldName]?.map((code: any) => this.enumObject.getByCode(code).id) || [];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return !value ? [] : value.map((code: any) => this.enumObject.getByCode(code).id);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nfunction maybeNullToUndefined(value: any): any {\n return value === null ? undefined : value;\n}\n\n/** Similar to SimpleSerde, but applies the superstruct `assert` function when reading values from the db. */\nexport class SuperstructSerde implements FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\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(\n private fieldName: string,\n public columnName: string,\n private superstruct: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n if (value) {\n this.assert(value, this.superstruct);\n }\n data[this.fieldName] = value;\n }\n\n dbValue(data: any) {\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n return data[this.fieldName];\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class JsonSerde implements FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any) {\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n const json = JSON.stringify(data[this.fieldName]);\n return isDefined(json) ? JSON.parse(json) : undefined;\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : 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 FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n private zodSchema: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n if (value) {\n data[this.fieldName] = this.zodSchema.parse(value);\n } else {\n data[this.fieldName] = value;\n }\n }\n\n dbValue(data: any) {\n // assume the data is already valid b/c it came from the entity\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n return data[this.fieldName];\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"serde.js","names":[],"sources":["../src/serde.ts"],"sourcesContent":["import { createRequire } from \"node:module\";\n\nimport { type InsertFixup } from \"./drivers/EntityWriter.ts\";\nimport { type Field, type PolymorphicField, type SerdeField, getBaseMeta, getMetadata } from \"./EntityMetadata.ts\";\nimport {\n type Entity,\n type EntityMetadata,\n getConstructorFromTaggedId,\n isDefined,\n isEntity,\n keyToNumber,\n keyToTaggedId,\n maybeResolveReferenceToId,\n} from \"./index.ts\";\nimport { type RowData } from \"./RowData.ts\";\nimport { getRuntimeConfig } from \"./runtimeConfig.ts\";\nimport { type Temporal, requireTemporal } from \"./temporal.ts\";\nimport { plainDateMapper, plainDateTimeMapper, plainTimeMapper, zonedDateTimeMapper } from \"./temporalMappers.ts\";\nimport { groupBy } from \"./utils.ts\";\n\nconst runtimeRequire = createRequire(import.meta.url);\n\nexport function hasSerde(field: Field): field is SerdeField {\n return !!field.serde;\n}\n\n/**\n * The database/column serialization / deserialization details of a given field.\n *\n * Most implementations will have just a single column in `columns`, but some logical\n * domain fields can be mapped to multiple physical database columns, i.e. polymorphic\n * references.\n */\nexport interface FieldSerde {\n /** A single field might persist to multiple columns, i.e. polymorphic references. */\n columns: Column[];\n\n /**\n * Reads the field's column(s) from the entity's `(rowData, rowIndex)` query result and sets\n * the domain value(s) into the `__orm.data`.\n *\n * Reading via `rowData.get(rowIndex, columnName)` (instead of a materialized POJO row) lets\n * lazy results like `WireRowData` decode only the cells that are actually accessed.\n *\n * Originally used in `EntityManager.hydrate` to set db values into the entity, although\n * now we invoke it lazily in `getField` to avoid copying data until it's actually needed.\n */\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void;\n}\n\n/**\n * An interface that generalizes our Date-vs-Temporal support.\n *\n * @typeParam T - The domain type, i.e. `Date` or `Temporal.ZonedDateTime`.\n */\nexport interface TimestampSerde<T> extends FieldSerde {\n /** Given business logic that wants to \"set this value to 'now'\", converts its Date to our T. */\n mapFromNow(now: Date): T;\n /** Used for reading oplock values. */\n dbValue(data: any): any;\n}\n\n/** A specific physical column of a logical field. */\nexport interface Column {\n columnName: string;\n dbType: string;\n /** From the given `__orm.data` hash, return this columns value, i.e. for putting in `UPDATE` params. */\n dbValue(data: any, entity: Entity, tableName: string, fixups: InsertFixup[] | undefined): any;\n /**\n * Used by `fork`, `importEntity`, and `run` to create an __orm.row from an __orm.data. Should output what we would\n * expect from a db query\n */\n rowValue(data: any): any;\n /** For a given domain value, return the database value, i.e. for putting `em.find` params into a db WHERE clause. */\n mapToDb(value: any): any;\n /**\n * For converting `json_agg`-preloaded JSON values into *ResultSet* type.\n *\n * I.e. our `#orm.row` hash always wants the db-side value, as-is coming from the database driver.\n * During `getField`, we always expect the ResultSet value, b/c we lazy call\n * `setOnEntityFromRowData` to go from db-value to domain-value.\n *\n * So `mapFromJsonAgg` is for preloading that needs to go from json-value *only to db-value*.\n *\n * I.e. for types like temporal, which we keep as strings in `row`, the json-value will match\n * the db-value, so `mapFromJsonAgg` can be a noop. But (at one point...) `Date`s we store as\n * `Date`s in `row`, so then `mapFromJsonAgg` needs to convert string json-value value into a `Date`.\n */\n mapFromJsonAgg(value: any): any;\n isArray: boolean;\n /** Used by `unnest_arrays`. */\n isNullableArray: boolean;\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 FieldSerde {\n columns = [this];\n isArray: boolean = false;\n isNullableArray: boolean = false;\n\n public constructor(\n protected fieldName: string,\n public columnName: string,\n public dbType: string,\n private mapper: CustomSerde<any, any>,\n // Allow subtypes to override isArray\n isArray?: boolean,\n isNullableArray = false, // only set for nullable arrays\n ) {\n if (isArray !== undefined) this.isArray = isArray;\n this.isNullableArray = isNullableArray;\n }\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] =\n value !== undefined\n ? this.isArray\n ? value.map((value: any) => this.mapper.fromDb(value))\n : this.mapper.fromDb(value)\n : undefined;\n }\n\n dbValue(data: any): any {\n const fieldData = data[this.fieldName];\n return fieldData !== undefined\n ? this.isArray\n ? fieldData.map((value: any) => this.mapper.toDb(value))\n : this.mapper.toDb(fieldData)\n : undefined;\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any): any {\n return value === null ? value : this.mapper.toDb(value);\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 FieldSerde {\n columns = [this];\n\n constructor(\n protected fieldName: string,\n public columnName: string,\n public dbType: string,\n public isArray = false,\n public isNullableArray = false, // only set for nullable arrays\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any) {\n return this.mapToDb(data[this.fieldName]);\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value;\n }\n}\n\nexport class DateSerde extends PrimitiveSerde implements TimestampSerde<Date> {\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 `setOnEntity` (i.e.\n * `RunPlugin` mirroring writes into the test em) turn every date into a string, because our\n * `setOnEntity` assigns the row value as-is.\n */\n rowValue(data: any): any {\n return data[this.fieldName];\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(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainDateMapper, isArray, isNullableArray);\n }\n}\n\n/** Converts `TIME`s to `Temporal.PlainTime`s. */\nexport class PlainTimeSerde extends CustomSerdeAdapter {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainTimeMapper, isArray, isNullableArray);\n }\n}\n\n/** Converts `TIMESTAMP`s to `Temporal.PlainDateTime`s. */\nexport class PlainDateTimeSerde extends CustomSerdeAdapter implements TimestampSerde<Temporal.PlainDateTime> {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, plainDateTimeMapper, isArray, isNullableArray);\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 TimestampSerde<Temporal.ZonedDateTime> {\n constructor(fieldName: string, columnName: string, dbType: string, isArray = false, isNullableArray = false) {\n super(fieldName, columnName, dbType, zonedDateTimeMapper, isArray, isNullableArray);\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 FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n dbType = \"bigint\";\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] = value ? BigInt(value) : value;\n }\n\n dbValue(data: any) {\n return data[this.fieldName];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? 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 FieldSerde {\n dbType = \"decimal\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n data[this.fieldName] = value !== undefined ? Number(value) : value;\n }\n\n dbValue(data: any) {\n return data[this.fieldName];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return value;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : Number(value);\n }\n}\n\n/** Maps physical integer keys to logical string IDs \"because GraphQL\". */\nexport class KeySerde implements FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n private meta: {\n tagName: string;\n idDbType: \"bigint\" | \"int\" | \"uuid\" | \"text\";\n };\n\n constructor(\n tagName: string,\n private fieldName: string,\n public columnName: string,\n public dbType: \"bigint\" | \"int\" | \"uuid\" | \"text\",\n ) {\n this.meta = {\n tagName,\n idDbType: dbType,\n };\n }\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = keyToTaggedId(this.meta, rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any, entity: Entity, tableName: string, fixups: InsertFixup[] | undefined) {\n const value = data[this.fieldName];\n if (\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({\n entity,\n tableName,\n column: this,\n value: keyToNumber(this.meta, maybeResolveReferenceToId(value)),\n });\n return null;\n }\n return keyToNumber(this.meta, maybeResolveReferenceToId(value));\n }\n\n rowValue(data: 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.dbValue(data, undefined!, undefined!, undefined);\n }\n\n mapToDb(value: any) {\n // Sometimes the nilIdValue will pass -1 as already a number, but usually this should be a tagged id\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 mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class PolymorphicKeySerde implements FieldSerde {\n constructor(\n private meta: () => EntityMetadata,\n private fieldName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n for (const column of this.columns) {\n const value = rowData.get(rowIndex, column.columnName);\n if (value) data[this.fieldName] ??= keyToTaggedId(column.otherMetadata(), value);\n }\n }\n\n // Lazy b/c we use PolymorphicField which we can't access in our cstr\n get columns(): Array<Column & { otherMetadata: () => EntityMetadata }> {\n const { fieldName } = this;\n\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.field.components, (comp) => getBaseMeta(comp.otherMetadata()).type).values(),\n ].some((group) => group.length > 1);\n\n return this.field.components.map((comp) => ({\n columnName: comp.columnName,\n dbType: comp.otherMetadata().idDbType,\n isArray: false,\n isNullableArray: false,\n otherMetadata: comp.otherMetadata,\n dbValue(data: any): any {\n const value = data[fieldName];\n const id = maybeResolveReferenceToId(value);\n const cstr = isEntity(value) ? getMetadata(value).cstr : id ? getConstructorFromTaggedId(id) : undefined;\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 otherMeta = comp.otherMetadata();\n const idAppliesToThisColumn = hasMultipleComponentsWithSameBaseType\n ? cstr === otherMeta.cstr\n : cstr === otherMeta.cstr ||\n cstr === getBaseMeta(otherMeta).cstr ||\n otherMeta.subTypes.some((subTypeMeta) => cstr === subTypeMeta.cstr);\n return idAppliesToThisColumn ? keyToNumber(comp.otherMetadata(), id) : undefined;\n },\n mapToDb(value: any): any {\n return keyToNumber(comp.otherMetadata(), typeof value === \"number\" ? value : maybeResolveReferenceToId(value));\n },\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n },\n rowValue(data: any): any {\n return this.dbValue(data);\n },\n }));\n }\n\n get columnName(): string {\n throw new Error(\"Unsupported\");\n }\n\n // Lazy b/c we use PolymorphicField which we can't access in our cstr\n private get field(): PolymorphicField {\n return this.meta().fields[this.fieldName] as PolymorphicField;\n }\n}\n\nexport class EnumFieldSerde implements FieldSerde {\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n public dbType: \"int\" | \"uuid\",\n private enumObject: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = this.enumObject.findById(rowData.get(rowIndex, this.columnName))?.code;\n }\n\n dbValue(data: any) {\n return this.enumObject.findByCode(data[this.fieldName])?.id;\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return this.enumObject.findByCode(value)?.id;\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class EnumArrayFieldSerde implements FieldSerde {\n isArray = true;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n public dbType: \"int[]\" | \"uuid[]\",\n public isNullableArray: boolean,\n private enumObject: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] =\n rowData.get(rowIndex, this.columnName)?.map((id: any) => this.enumObject.findById(id).code) || [];\n }\n\n dbValue(data: any) {\n return data[this.fieldName]?.map((code: any) => this.enumObject.getByCode(code).id) || [];\n }\n\n rowValue(data: any): any {\n return this.dbValue(data);\n }\n\n mapToDb(value: any) {\n return !value ? [] : value.map((code: any) => this.enumObject.getByCode(code).id);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nfunction maybeNullToUndefined(value: any): any {\n return value === null ? undefined : value;\n}\n\n/** Similar to SimpleSerde, but applies the superstruct `assert` function when reading values from the db. */\nexport class SuperstructSerde implements FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\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(\n private fieldName: string,\n public columnName: string,\n private superstruct: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n if (value) {\n this.assert(value, this.superstruct);\n }\n data[this.fieldName] = value;\n }\n\n dbValue(data: any) {\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n return data[this.fieldName];\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n\nexport class JsonSerde implements FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n data[this.fieldName] = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n }\n\n dbValue(data: any) {\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n const json = JSON.stringify(data[this.fieldName]);\n return isDefined(json) ? JSON.parse(json) : undefined;\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : 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 FieldSerde {\n dbType = \"jsonb\";\n isArray = false;\n isNullableArray = false;\n columns = [this];\n\n constructor(\n private fieldName: string,\n public columnName: string,\n private zodSchema: any,\n ) {}\n\n setOnEntityFromRowData(data: any, rowData: RowData, rowIndex: number): void {\n const value = maybeNullToUndefined(rowData.get(rowIndex, this.columnName));\n if (value) {\n data[this.fieldName] = this.zodSchema.parse(value);\n } else {\n data[this.fieldName] = value;\n }\n }\n\n dbValue(data: any) {\n // assume the data is already valid b/c it came from the entity\n return JSON.stringify(data[this.fieldName]);\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 rowValue(data: any): any {\n return data[this.fieldName];\n }\n\n mapToDb(value: any) {\n return JSON.stringify(value);\n }\n\n mapFromJsonAgg(value: any): any {\n return value === null ? value : value;\n }\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "joist-core",
3
- "version": "2.3.0-next.53",
3
+ "version": "2.3.0-next.55",
4
4
  "license": "MIT",
5
5
  "type": "module",
6
6
  "repository": {
@@ -42,7 +42,7 @@
42
42
  "build"
43
43
  ],
44
44
  "peerDependencies": {
45
- "joist-utils": "2.3.0-next.53"
45
+ "joist-utils": "2.3.0-next.55"
46
46
  },
47
47
  "dependencies": {
48
48
  "ansis": "^4.3.1",