joist-codegen 2.3.0-next.65 → 2.3.0-next.66

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.
@@ -7,21 +7,7 @@ let ts_poet = require("ts-poet");
7
7
  //#region src/generateMetadataFile.ts
8
8
  function generateMetadataFile(config, dbMeta, meta) {
9
9
  const { entity, createdAt, updatedAt, deletedAt } = meta;
10
- const fields = generateFields(config, meta);
11
- const physical = meta.physicalMetadata ?? meta;
12
- const sharedTable = meta.inheritanceType === "sti" && meta.baseClassName;
13
- const storageFields = generateFields(config, physical, true);
14
- const physicalFields = Object.fromEntries(Object.entries(storageFields).map(([name, field]) => [name, fields[name]?.toString() === field.toString() ? ts_poet.code`${entity.metaName}.fields[${require_utils.q(name)}]` : field]));
15
- const columns = Object.fromEntries([
16
- ["id", "id"],
17
- ...[
18
- ...physical.primitives,
19
- ...physical.enums,
20
- ...physical.pgEnums,
21
- ...physical.manyToOnes
22
- ].map((field) => [field.columnName, field.fieldName]),
23
- ...physical.polymorphics.flatMap((field) => field.components.map((component) => [component.columnName, field.fieldName]))
24
- ]);
10
+ const fields = generateFields(config, dbMeta, meta, (name) => columnReference(dbMeta, meta, name));
25
11
  Object.values(fields).forEach((code) => code.asOneline());
26
12
  const maybeBaseType = meta.baseClassName ? `"${meta.baseClassName}"` : void 0;
27
13
  const maybeInheritanceType = meta.inheritanceType ? `inheritanceType: "${meta.inheritanceType}",` : "";
@@ -49,7 +35,7 @@ function generateMetadataFile(config, dbMeta, meta) {
49
35
  tableName: "${meta.tableName}",
50
36
  supportsEmExecute: ${!meta.inheritanceType && meta.supportsEmExecute === true},
51
37
  fields: ${fields},
52
- columns: {},
38
+ columns: ${columnOwner(dbMeta, meta, "id").entity.metaName}Columns,
53
39
  allFields: {},
54
40
  orderBy: ${require_utils.q(config.entities[meta.name]?.orderBy)},
55
41
  timestampFields: ${maybeTimestampConfig},
@@ -59,14 +45,6 @@ function generateMetadataFile(config, dbMeta, meta) {
59
45
  subTypes: [], ${maybeInsertionOrder} ${maybeUniqueBy}
60
46
  };
61
47
 
62
- ${sharedTable ? "" : ts_poet.code`
63
- ${Object.entries(columns).map(([columnName, fieldName]) => {
64
- const firstColumn = Object.keys(columns).find((name) => columns[name] === fieldName);
65
- const field = firstColumn === columnName ? physicalFields[fieldName] : ts_poet.code`${entity.metaName}.columns[${require_utils.q(firstColumn)}].field`;
66
- return ts_poet.code`${entity.metaName}.columns[${require_utils.q(columnName)}] = { fieldName: ${require_utils.q(fieldName)}, field: ${field} };`;
67
- })}
68
- `}
69
-
70
48
  (${entity.typeForMetadataFile} as any).metadata = ${entity.metaName};
71
49
  `;
72
50
  }
@@ -81,8 +59,8 @@ function getUniqueBy(config, meta) {
81
59
  return true;
82
60
  });
83
61
  }
84
- /** Emits field descriptors; physical polymorphic serdes resolve the original storage components. */
85
- function generateFields(config, dbMetadata, physical = false) {
62
+ /** Emits fields that bind the already-declared physical columns. */
63
+ function generateFields(config, dbMeta, dbMetadata, columnRef) {
86
64
  const fields = {};
87
65
  fields["id"] = ts_poet.code`
88
66
  {
@@ -90,20 +68,20 @@ function generateFields(config, dbMetadata, physical = false) {
90
68
  fieldName: "id",
91
69
  fieldIdName: undefined,
92
70
  required: true,
93
- serde: new ${require_symbols.KeySerde}("${dbMetadata.tagName}", "id", "id", "${dbMetadata.primaryKey.columnType}", ${columnOptions(dbMetadata.primaryKey)}),
71
+ serde: new ${require_symbols.SimpleFieldSerde}("id", ${columnRef("id", ts_poet.code`new ${require_symbols.KeySerde}("${dbMetadata.tagName}", "${dbMetadata.primaryKey.columnType}")`, columnArgs(dbMetadata.primaryKey, dbMetadata, ts_poet.code`() => ${dbMetadata.entity.metaName}`))}),
94
72
  immutable: true,
95
73
  }
96
74
  `;
97
75
  dbMetadata.primitives.forEach((p) => {
98
76
  const { fieldName, derived, columnName, columnType, superstruct, zodSchema, customSerde, isArray } = p;
99
- const column = columnOptions(p);
77
+ const column = columnArgs(p, dbMetadata);
100
78
  let serde;
101
- if (customSerde) serde = isArray ? ts_poet.code`new ${require_symbols.CustomSerdeAdapter}("${fieldName}", "${columnName}", "${columnType}[]", ${customSerde}, true, ${!p.notNull}, ${column})` : ts_poet.code`new ${require_symbols.CustomSerdeAdapter}("${fieldName}", "${columnName}", "${columnType}", ${customSerde}, false, false, ${column})`;
102
- else if (superstruct) serde = ts_poet.code`new ${require_symbols.SuperstructSerde}("${fieldName}", "${columnName}", ${superstruct}, ${column})`;
103
- else if (zodSchema) serde = ts_poet.code`new ${require_symbols.ZodSerde}("${fieldName}", "${columnName}", ${zodSchema}, ${column})`;
104
- else if (columnType === "numeric" || columnType === "decimal") serde = isArray ? ts_poet.code`new ${require_symbols.DecimalToNumberSerde}("${fieldName}", "${columnName}", true, ${!p.notNull}, ${column})` : ts_poet.code`new ${require_symbols.DecimalToNumberSerde}("${fieldName}", "${columnName}", false, false, ${column})`;
105
- else if (columnType === "jsonb") serde = ts_poet.code`new ${require_symbols.JsonSerde}("${fieldName}", "${columnName}", ${column})`;
106
- else if (p.rawFieldType === "bigint") serde = isArray ? ts_poet.code`new ${require_symbols.BigIntSerde}("${fieldName}", "${columnName}", true, ${!p.notNull}, ${column})` : ts_poet.code`new ${require_symbols.BigIntSerde}("${fieldName}", "${columnName}", false, false, ${column})`;
79
+ if (customSerde) serde = isArray ? ts_poet.code`new ${require_symbols.CustomSerdeAdapter}( "${columnType}[]", ${customSerde}, true)` : ts_poet.code`new ${require_symbols.CustomSerdeAdapter}( "${columnType}", ${customSerde})`;
80
+ else if (superstruct) serde = ts_poet.code`new ${require_symbols.SuperstructSerde}( ${superstruct})`;
81
+ else if (zodSchema) serde = ts_poet.code`new ${require_symbols.ZodSerde}( ${zodSchema})`;
82
+ else if (columnType === "numeric" || columnType === "decimal") serde = isArray ? ts_poet.code`new ${require_symbols.DecimalToNumberSerde}(true)` : ts_poet.code`new ${require_symbols.DecimalToNumberSerde}()`;
83
+ else if (columnType === "jsonb") serde = ts_poet.code`new ${require_symbols.JsonSerde}()`;
84
+ else if (p.rawFieldType === "bigint") serde = isArray ? ts_poet.code`new ${require_symbols.BigIntSerde}(true)` : ts_poet.code`new ${require_symbols.BigIntSerde}()`;
107
85
  else {
108
86
  let serdeType;
109
87
  if (columnType === "date") serdeType = config.temporal ? require_symbols.PlainDateSerde : require_symbols.DateSerde;
@@ -111,7 +89,7 @@ function generateFields(config, dbMetadata, physical = false) {
111
89
  else if (columnType === "timestamp with time zone") serdeType = config.temporal ? require_symbols.ZonedDateTimeSerde : require_symbols.DateSerde;
112
90
  else if (columnType === "time without time zone") serdeType = config.temporal ? require_symbols.PlainTimeSerde : require_symbols.PrimitiveSerde;
113
91
  else serdeType = require_symbols.PrimitiveSerde;
114
- serde = isArray ? ts_poet.code`new ${serdeType}("${fieldName}", "${columnName}", "${columnType}[]", true, ${!p.notNull}, ${column})` : ts_poet.code`new ${serdeType}("${fieldName}", "${columnName}", "${columnType}", false, false, ${column})`;
92
+ serde = isArray ? ts_poet.code`new ${serdeType}( "${columnType}[]", true)` : ts_poet.code`new ${serdeType}( "${columnType}")`;
115
93
  }
116
94
  const extras = columnType === "citext" ? ts_poet.code`citext: true,` : "";
117
95
  fields[fieldName] = ts_poet.code`
@@ -123,7 +101,7 @@ function generateFields(config, dbMetadata, physical = false) {
123
101
  required: ${!derived && p.notNull},
124
102
  protected: ${p.protected},
125
103
  type: ${typeof p.rawFieldType === "string" ? `"${p.rawFieldType}"` : p.rawFieldType},
126
- serde: ${serde},
104
+ serde: new ${require_symbols.SimpleFieldSerde}("${fieldName}", ${columnRef(columnName, serde, column)}),
127
105
  immutable: false,
128
106
  ${p.lazy ? ts_poet.code`lazy: true,` : ""}
129
107
  ${extras}
@@ -142,7 +120,7 @@ function generateFields(config, dbMetadata, physical = false) {
142
120
  required: ${notNull},
143
121
  protected: false,
144
122
  type: "string",
145
- serde: new ${require_symbols.PrimitiveSerde}("${fieldName}", "${columnName}", "${dbType}", false, false, ${columnOptions(p)}),
123
+ serde: new ${require_symbols.SimpleFieldSerde}("${fieldName}", ${columnRef(columnName, ts_poet.code`new ${require_symbols.PrimitiveSerde}("${dbType}")`, columnArgs(p, dbMetadata))}),
146
124
  immutable: false,
147
125
  ${maybeDefault(p)}
148
126
  }`;
@@ -151,7 +129,6 @@ function generateFields(config, dbMetadata, physical = false) {
151
129
  const { fieldName, enumDetailType, notNull, isArray, columnName, columnType, derived } = field;
152
130
  const serdeType = isArray ? require_symbols.EnumArrayFieldSerde : require_symbols.EnumFieldSerde;
153
131
  const columnTypeWithArray = `${columnType}${isArray ? "[]" : ""}`;
154
- const maybeIsNullable = isArray ? `, ${!notNull}` : "";
155
132
  fields[fieldName] = ts_poet.code`
156
133
  {
157
134
  kind: "enum",
@@ -160,7 +137,7 @@ function generateFields(config, dbMetadata, physical = false) {
160
137
  required: ${notNull},
161
138
  derived: ${!derived ? false : `"${derived}"`},
162
139
  enumDetailType: ${enumDetailType},
163
- serde: new ${serdeType}("${fieldName}", "${columnName}", "${columnTypeWithArray}"${maybeIsNullable}, ${enumDetailType}, ${columnOptions(field)}),
140
+ serde: new ${require_symbols.SimpleFieldSerde}("${fieldName}", ${columnRef(columnName, ts_poet.code`new ${serdeType}("${columnTypeWithArray}", ${enumDetailType})`, columnArgs(field, dbMetadata))}),
164
141
  immutable: false,
165
142
  ${maybeDefault(field)}
166
143
  }
@@ -169,6 +146,7 @@ function generateFields(config, dbMetadata, physical = false) {
169
146
  dbMetadata.manyToOnes.forEach((m2o) => {
170
147
  const { fieldName, columnName, notNull, otherEntity, otherFieldName, derived, dbType } = m2o;
171
148
  const otherTagName = config.entities[otherEntity.name].tag;
149
+ const otherMetadata = (dbMetadata.physicalMetadata ?? dbMetadata).manyToOnes.find((field) => field.columnName === columnName)?.otherEntity.name === otherEntity.name ? ts_poet.code`${columnRef(columnName)}.idMetadata!` : ts_poet.code`() => ${otherEntity.metaName}`;
172
150
  fields[fieldName] = ts_poet.code`
173
151
  {
174
152
  kind: "m2o",
@@ -176,9 +154,9 @@ function generateFields(config, dbMetadata, physical = false) {
176
154
  fieldIdName: "${fieldName}Id",
177
155
  derived: ${!derived ? false : `"${derived}"`},
178
156
  required: ${notNull},
179
- otherMetadata: () => ${otherEntity.metaName},
157
+ otherMetadata: ${otherMetadata},
180
158
  otherFieldName: "${otherFieldName}",
181
- serde: new ${require_symbols.KeySerde}("${otherTagName}", "${fieldName}", "${columnName}", "${dbType}", ${columnOptions(m2o)}),
159
+ serde: new ${require_symbols.SimpleFieldSerde}("${fieldName}", ${columnRef(columnName, ts_poet.code`new ${require_symbols.KeySerde}("${otherTagName}", "${dbType}")`, columnArgs(m2o, dbMetadata, ts_poet.code`() => ${otherEntity.metaName}`))}),
182
160
  immutable: false,
183
161
  ${maybeDefault(m2o)}
184
162
  }
@@ -274,28 +252,49 @@ function generateFields(config, dbMetadata, physical = false) {
274
252
  });
275
253
  dbMetadata.polymorphics.forEach((p) => {
276
254
  const { fieldName, notNull, components } = p;
255
+ components.forEach((component) => columnRef(component.columnName, ts_poet.code`new ${require_symbols.KeySerde}("${config.entities[component.otherEntity.name].tag}", "${dbMeta.entitiesByName[component.otherEntity.name].primaryKey.columnType}")`, ts_poet.code`true, false, false, false, false, () => ${component.otherEntity.metaName}`));
277
256
  fields[fieldName] = ts_poet.code`
278
- {
279
- kind: "poly",
280
- fieldName: "${fieldName}",
281
- fieldIdName: "${fieldName}Id",
282
- required: ${notNull},
283
- components: [${components.map(({ otherFieldName, otherEntity, columnName }) => ts_poet.code`
284
- {
285
- otherMetadata: () => ${otherEntity.metaName},
286
- otherFieldName: "${otherFieldName}",
287
- columnName: "${columnName}",
288
- },`)}],
289
- serde: new ${require_symbols.PolymorphicKeySerde}(() => ${dbMetadata.entity.metaName}, "${fieldName}"${physical ? ts_poet.code`, ${require_utils.q(components[0].columnName)}` : ""}),
290
- immutable: false,
291
- }
257
+ ${require_symbols.polymorphicField}("${fieldName}", ${notNull}, [${components.map((component) => {
258
+ const owner = columnOwner(dbMeta, dbMetadata, component.columnName);
259
+ const target = (owner.physicalMetadata ?? owner).polymorphics.flatMap((field) => field.components).find((c) => c.columnName === component.columnName).otherEntity.name === component.otherEntity.name ? "" : ts_poet.code`, () => ${component.otherEntity.metaName}`;
260
+ return ts_poet.code`new ${require_symbols.PolyComponent}(${columnRef(component.columnName)}, ${require_utils.q(component.otherFieldName)}${target}),`;
261
+ })}])
292
262
  `;
293
263
  });
294
264
  return fields;
295
265
  }
296
- /** Emits constructor options using codegen's existing column facts. */
297
- function columnOptions(column) {
298
- return ts_poet.code`{ sqlNullable: ${!column.columnNotNull}, hasDefault: ${column.columnDefault != null && !column.columnGenerated}, isGenerated: ${column.columnGenerated} }`;
266
+ /** Emits constructor arguments using codegen's existing column facts. */
267
+ function columnArgs(column, meta, idMetadata) {
268
+ const insertOptional = column === meta.createdAt || column === meta.updatedAt;
269
+ return ts_poet.code`${!column.columnNotNull}, ${column.columnDefault != null && !column.columnGenerated}, ${column.columnGenerated}, ${insertOptional}, true, ${idMetadata ?? "undefined"}`;
270
+ }
271
+ /** Declares all physical codecs before any domain metadata; ID targets remain lazy. */
272
+ function generateColumnDeclarations(config, dbMeta, meta) {
273
+ if (meta.inheritanceType === "sti" && meta.baseClassName) return ts_poet.code``;
274
+ const columns = {};
275
+ generateFields(config, dbMeta, meta.physicalMetadata ?? meta, (name, codec, args) => {
276
+ if (codec) columns[name] = ts_poet.code`new ${require_symbols.Column}(${require_utils.q(name)}, ${args}, ${codec})`.asOneline();
277
+ return ts_poet.code`${meta.entity.metaName}Columns[${require_utils.q(name)}]`;
278
+ });
279
+ return ts_poet.code`const ${meta.entity.metaName}Columns = ${columns} satisfies ${require_symbols.ColumnDescriptors};`;
280
+ }
281
+ /** Locates a column's physical table without copying inherited columns into subtype tables. */
282
+ function columnOwner(dbMeta, meta, name) {
283
+ if (meta.inheritanceType === "sti" && meta.baseClassName) return columnOwner(dbMeta, dbMeta.entitiesByName[meta.baseClassName], name);
284
+ const physical = meta.physicalMetadata ?? meta;
285
+ if (name === "id" || [
286
+ ...physical.primitives,
287
+ ...physical.enums,
288
+ ...physical.pgEnums,
289
+ ...physical.manyToOnes,
290
+ ...physical.polymorphics.flatMap((field) => field.components)
291
+ ].some((field) => field.columnName === name)) return meta;
292
+ if (meta.baseClassName) return columnOwner(dbMeta, dbMeta.entitiesByName[meta.baseClassName], name);
293
+ throw new Error(`No physical column ${meta.name}.${name}`);
294
+ }
295
+ /** Emits a direct reference to the single physical descriptor. */
296
+ function columnReference(dbMeta, meta, name) {
297
+ return ts_poet.code`${columnOwner(dbMeta, meta, name).entity.metaName}Columns[${require_utils.q(name)}]`;
299
298
  }
300
299
  function maybeDefault(f) {
301
300
  return f.hasConfigDefault ? ts_poet.code`default: "config",` : f.columnDefault != null ? ts_poet.code`default: "schema",` : "";
@@ -315,6 +314,7 @@ function isString(config, columnType) {
315
314
  return require_utils.mapSimpleDbTypeToTypescriptType(config, columnType) === "string";
316
315
  }
317
316
  //#endregion
317
+ exports.generateColumnDeclarations = generateColumnDeclarations;
318
318
  exports.generateMetadataFile = generateMetadataFile;
319
319
 
320
320
  //# sourceMappingURL=generateMetadataFile.cjs.map
@@ -1 +1 @@
1
- {"version":3,"file":"generateMetadataFile.cjs","names":["q","EntityMetadata","imp","KeySerde","CustomSerdeAdapter","SuperstructSerde","ZodSerde","DecimalToNumberSerde","JsonSerde","BigIntSerde","PlainDateSerde","DateSerde","PlainDateTimeSerde","ZonedDateTimeSerde","PlainTimeSerde","PrimitiveSerde","EnumArrayFieldSerde","EnumFieldSerde","PolymorphicKeySerde","mapSimpleDbTypeToTypescriptType"],"sources":["../src/generateMetadataFile.ts"],"sourcesContent":["import { type Code, type Import, code, imp } from \"ts-poet\";\n\nimport { type Config } from \"./config.ts\";\nimport {\n type DatabaseColumnType,\n type DbMetadata,\n type EntityDbMetadata,\n type OneToManyField,\n type PrimitiveField,\n} from \"./EntityDbMetadata.ts\";\nimport {\n BigIntSerde,\n CustomSerdeAdapter,\n DateSerde,\n DecimalToNumberSerde,\n EntityMetadata,\n EnumArrayFieldSerde,\n EnumFieldSerde,\n JsonSerde,\n KeySerde,\n PlainDateSerde,\n PlainDateTimeSerde,\n PlainTimeSerde,\n PolymorphicKeySerde,\n PrimitiveSerde,\n SuperstructSerde,\n ZodSerde,\n ZonedDateTimeSerde,\n} from \"./symbols.ts\";\nimport { mapSimpleDbTypeToTypescriptType, q } from \"./utils.ts\";\n\nexport function generateMetadataFile(config: Config, dbMeta: DbMetadata, meta: EntityDbMetadata): Code {\n const { entity, createdAt, updatedAt, deletedAt } = meta;\n\n const fields = generateFields(config, meta);\n const physical = meta.physicalMetadata ?? meta;\n const sharedTable = meta.inheritanceType === \"sti\" && meta.baseClassName;\n const storageFields = generateFields(config, physical, true);\n // Reuse unchanged descriptors; only moved or specialized fields need separate storage metadata.\n const physicalFields = Object.fromEntries(\n Object.entries(storageFields).map(([name, field]) => [\n name,\n fields[name]?.toString() === field.toString() ? code`${entity.metaName}.fields[${q(name)}]` : field,\n ]),\n );\n const columns = Object.fromEntries<string>([\n [\"id\", \"id\"],\n ...[...physical.primitives, ...physical.enums, ...physical.pgEnums, ...physical.manyToOnes].map(\n (field) => [field.columnName, field.fieldName] as const,\n ),\n ...physical.polymorphics.flatMap((field) =>\n field.components.map((component) => [component.columnName, field.fieldName] as const),\n ),\n ]);\n\n Object.values(fields).forEach((code) => code.asOneline());\n\n const maybeBaseType = meta.baseClassName ? `\"${meta.baseClassName}\"` : undefined;\n // We want to put inheritanceType: sti/cti onto base classes as well\n const maybeInheritanceType = meta.inheritanceType ? `inheritanceType: \"${meta.inheritanceType}\",` : \"\";\n const maybeStiColumn = meta.stiDiscriminatorField ? `stiDiscriminatorField: \"${meta.stiDiscriminatorField}\",` : \"\";\n const maybeStiValue = meta.stiDiscriminatorValue ? `stiDiscriminatorValue: ${meta.stiDiscriminatorValue},` : \"\";\n const maybeCtiAbstract = meta.abstract ? `ctiAbstract: ${meta.abstract},` : \"\";\n // Force subtype `timestampFields` to be `undefined` to ensure all runtime code is reading from the baseMeta values.\n // Force subtype `timestampFields` to be `undefined` to ensure all runtime code is reading from the baseMeta values.\n const maybeTimestampConfig = meta.baseClassName\n ? code`undefined`\n : code`\n {\n createdAt: ${q(createdAt?.fieldName)},\n updatedAt: ${q(updatedAt?.fieldName)},\n deletedAt: ${q(deletedAt?.fieldName)},\n }\n `;\n const maybeInsertionOrder = meta.nonDeferredFkOrder !== 0 ? `nonDeferredFkOrder: ${meta.nonDeferredFkOrder},` : ``;\n const uniqueBy = getUniqueBy(config, meta);\n const maybeUniqueBy = uniqueBy.length > 0 ? code`uniqueBy: ${JSON.stringify(uniqueBy)},` : code``;\n\n return code`\n export const ${entity.metaName}: ${EntityMetadata}<${entity.name}> = {\n cstr: ${entity.typeForMetadataFile},\n type: \"${entity.name}\",\n baseType: ${maybeBaseType}, ${maybeInheritanceType} ${maybeStiColumn} ${maybeStiValue} ${maybeCtiAbstract}\n idType: \"${config.idType ?? \"tagged-string\"}\",\n idDbType: \"${meta.primaryKey.columnType}\",\n tagName: \"${meta.tagName}\",\n tableName: \"${meta.tableName}\",\n supportsEmExecute: ${!meta.inheritanceType && meta.supportsEmExecute === true},\n fields: ${fields},\n columns: {},\n allFields: {},\n orderBy: ${q(config.entities[meta.name]?.orderBy)},\n timestampFields: ${maybeTimestampConfig},\n config: ${entity.configConst},\n factory: ${imp(`new${entity.name}@./entities.ts`)},\n baseTypes: [],\n subTypes: [], ${maybeInsertionOrder} ${maybeUniqueBy}\n };\n\n ${\n sharedTable\n ? \"\"\n : code`\n ${Object.entries(columns).map(([columnName, fieldName]) => {\n const firstColumn = Object.keys(columns).find((name) => columns[name] === fieldName)!;\n const field =\n firstColumn === columnName\n ? physicalFields[fieldName]\n : code`${entity.metaName}.columns[${q(firstColumn)}].field`;\n return code`${entity.metaName}.columns[${q(columnName)}] = { fieldName: ${q(fieldName)}, field: ${field} };`;\n })}\n `\n }\n\n (${entity.typeForMetadataFile} as any).metadata = ${entity.metaName};\n `;\n}\n\n/** Returns configured identities plus conservative database-backed unique identities. */\nfunction getUniqueBy(config: Config, meta: EntityDbMetadata): string[][] {\n const uniqueBy = config.entities[meta.name]?.uniqueBy ?? [];\n const seen = new Set<string>();\n return [...uniqueBy, ...(meta.uniqueConstraints ?? [])].filter((fields) => {\n const key = fields.join(\"\\u0000\");\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** Emits field descriptors; physical polymorphic serdes resolve the original storage components. */\nfunction generateFields(config: Config, dbMetadata: EntityDbMetadata, physical = false): Record<string, Code> {\n const fields: Record<string, Code> = {};\n\n fields[\"id\"] = code`\n {\n kind: \"primaryKey\",\n fieldName: \"id\",\n fieldIdName: undefined,\n required: true,\n serde: new ${KeySerde}(\"${dbMetadata.tagName}\", \"id\", \"id\", \"${dbMetadata.primaryKey.columnType}\", ${columnOptions(dbMetadata.primaryKey)}),\n immutable: true,\n }\n `;\n\n dbMetadata.primitives.forEach((p) => {\n const { fieldName, derived, columnName, columnType, superstruct, zodSchema, customSerde, isArray } = p;\n const column = columnOptions(p);\n let serde: Code;\n if (customSerde) {\n serde = isArray\n ? code`new ${CustomSerdeAdapter}(\"${fieldName}\", \"${columnName}\", \"${columnType}[]\", ${customSerde}, true, ${!p.notNull}, ${column})`\n : code`new ${CustomSerdeAdapter}(\"${fieldName}\", \"${columnName}\", \"${columnType}\", ${customSerde}, false, false, ${column})`;\n } else if (superstruct) {\n serde = code`new ${SuperstructSerde}(\"${fieldName}\", \"${columnName}\", ${superstruct}, ${column})`;\n } else if (zodSchema) {\n serde = code`new ${ZodSerde}(\"${fieldName}\", \"${columnName}\", ${zodSchema}, ${column})`;\n } else if (columnType === \"numeric\" || columnType === \"decimal\") {\n serde = isArray\n ? code`new ${DecimalToNumberSerde}(\"${fieldName}\", \"${columnName}\", true, ${!p.notNull}, ${column})`\n : code`new ${DecimalToNumberSerde}(\"${fieldName}\", \"${columnName}\", false, false, ${column})`;\n } else if (columnType === \"jsonb\") {\n serde = code`new ${JsonSerde}(\"${fieldName}\", \"${columnName}\", ${column})`;\n } else if (p.rawFieldType === \"bigint\") {\n serde = isArray\n ? code`new ${BigIntSerde}(\"${fieldName}\", \"${columnName}\", true, ${!p.notNull}, ${column})`\n : code`new ${BigIntSerde}(\"${fieldName}\", \"${columnName}\", false, false, ${column})`;\n } else {\n let serdeType: Import;\n if (columnType === \"date\") {\n serdeType = config.temporal ? PlainDateSerde : DateSerde;\n } else if (columnType === \"timestamp without time zone\") {\n serdeType = config.temporal ? PlainDateTimeSerde : DateSerde;\n } else if (columnType === \"timestamp with time zone\") {\n serdeType = config.temporal ? ZonedDateTimeSerde : DateSerde;\n } else if (columnType === \"time without time zone\") {\n serdeType = config.temporal ? PlainTimeSerde : PrimitiveSerde;\n } else {\n serdeType = PrimitiveSerde;\n }\n serde = isArray\n ? code`new ${serdeType}(\"${fieldName}\", \"${columnName}\", \"${columnType}[]\", true, ${!p.notNull}, ${column})`\n : code`new ${serdeType}(\"${fieldName}\", \"${columnName}\", \"${columnType}\", false, false, ${column})`;\n }\n const extras = columnType === \"citext\" ? code`citext: true,` : \"\";\n fields[fieldName] = code`\n {\n kind: \"primitive\",\n fieldName: \"${fieldName}\",\n fieldIdName: undefined,\n derived: ${!derived ? false : `\"${derived}\"`},\n required: ${!derived && p.notNull},\n protected: ${p.protected},\n type: ${typeof p.rawFieldType === \"string\" ? `\"${p.rawFieldType}\"` : p.rawFieldType},\n serde: ${serde},\n immutable: false,\n ${p.lazy ? code`lazy: true,` : \"\"}\n ${extras}\n ${maybeDefault(p)}\n ${maybeSanitize(config, p)}\n }`;\n });\n\n // Treat native enums as primitives\n dbMetadata.pgEnums.forEach((p) => {\n const { columnName, fieldName, notNull, dbType } = p;\n fields[fieldName] = code`\n {\n kind: \"primitive\",\n fieldName: \"${fieldName}\",\n fieldIdName: undefined,\n derived: false,\n required: ${notNull},\n protected: false,\n type: \"string\",\n serde: new ${PrimitiveSerde}(\"${fieldName}\", \"${columnName}\", \"${dbType}\", false, false, ${columnOptions(p)}),\n immutable: false,\n ${maybeDefault(p)}\n }`;\n });\n\n dbMetadata.enums.forEach((field) => {\n const { fieldName, enumDetailType, notNull, isArray, columnName, columnType, derived } = field;\n const serdeType = isArray ? EnumArrayFieldSerde : EnumFieldSerde;\n const columnTypeWithArray = `${columnType}${isArray ? \"[]\" : \"\"}`;\n const maybeIsNullable = isArray ? `, ${!notNull}` : \"\";\n fields[fieldName] = code`\n {\n kind: \"enum\",\n fieldName: \"${fieldName}\",\n fieldIdName: undefined,\n required: ${notNull},\n derived: ${!derived ? false : `\"${derived}\"`},\n enumDetailType: ${enumDetailType},\n serde: new ${serdeType}(\"${fieldName}\", \"${columnName}\", \"${columnTypeWithArray}\"${maybeIsNullable}, ${enumDetailType}, ${columnOptions(field)}),\n immutable: false,\n ${maybeDefault(field)}\n }\n `;\n });\n\n dbMetadata.manyToOnes.forEach((m2o) => {\n const { fieldName, columnName, notNull, otherEntity, otherFieldName, derived, dbType } = m2o;\n const otherTagName = config.entities[otherEntity.name].tag;\n fields[fieldName] = code`\n {\n kind: \"m2o\",\n fieldName: \"${fieldName}\",\n fieldIdName: \"${fieldName}Id\",\n derived: ${!derived ? false : `\"${derived}\"`},\n required: ${notNull},\n otherMetadata: () => ${otherEntity.metaName},\n otherFieldName: \"${otherFieldName}\",\n serde: new ${KeySerde}(\"${otherTagName}\", \"${fieldName}\", \"${columnName}\", \"${dbType}\", ${columnOptions(m2o)}),\n immutable: false,\n ${maybeDefault(m2o)}\n }\n `;\n });\n\n dbMetadata.oneToManys.forEach((o2m) => {\n const { fieldName, singularName, otherEntity, otherFieldName, otherColumnName } = o2m;\n fields[fieldName] = code`\n {\n kind: \"o2m\",\n fieldName: \"${fieldName}\",\n fieldIdName: \"${singularName}Ids\",\n required: false,\n otherMetadata: () => ${otherEntity.metaName},\n otherFieldName: \"${otherFieldName}\",\n otherColumnName: \"${otherColumnName}\",\n serde: undefined,\n immutable: false,\n ${maybeOrderBy(o2m)}\n ${maybeSoftDeletes(o2m)}\n }\n `;\n });\n\n dbMetadata.largeOneToManys.forEach((o2m) => {\n const { fieldName, singularName, otherEntity, otherFieldName, otherColumnName } = o2m;\n fields[fieldName] = code`\n {\n kind: \"lo2m\",\n fieldName: \"${fieldName}\",\n fieldIdName: \"${singularName}Ids\",\n required: false,\n otherMetadata: () => ${otherEntity.metaName},\n otherFieldName: \"${otherFieldName}\",\n otherColumnName: \"${otherColumnName}\",\n serde: undefined,\n immutable: false,\n }\n `;\n });\n\n dbMetadata.manyToManys.forEach((m2m) => {\n const { fieldName, singularName, otherEntity, otherFieldName, derived } = m2m;\n fields[fieldName] = code`\n {\n kind: \"m2m\",\n fieldName: \"${fieldName}\",\n fieldIdName: \"${singularName}Ids\",\n required: false,\n derived: ${derived === \"async\" ? `\"async\"` : derived === \"otherSide\" ? `\"otherSide\"` : \"false\"},\n otherMetadata: () => ${otherEntity.metaName},\n otherFieldName: \"${otherFieldName}\",\n serde: undefined,\n immutable: false,\n joinTableName: \"${m2m.joinTableName}\",\n columnNames: [\"${m2m.columnName}\", \"${m2m.otherColumnName}\"],\n hasJoinTableId: ${m2m.hasJoinTableId},\n ${maybeSoftDeletes(m2m)}\n }\n `;\n });\n\n dbMetadata.manyToManyEnums.forEach((m2m) => {\n const { fieldName, enumDetailType } = m2m;\n fields[fieldName] = code`\n {\n kind: \"m2mEnum\",\n fieldName: \"${fieldName}\",\n fieldIdName: undefined,\n required: false,\n derived: false,\n enumDetailType: ${enumDetailType},\n serde: undefined,\n immutable: false,\n joinTableName: \"${m2m.joinTableName}\",\n columnNames: [\"${m2m.columnName}\", \"${m2m.otherColumnName}\"],\n hasJoinTableId: ${m2m.hasJoinTableId},\n }\n `;\n });\n\n dbMetadata.oneToOnes.forEach((o2o) => {\n const { fieldName, otherEntity, otherFieldName, otherColumnName } = o2o;\n fields[fieldName] = code`\n {\n kind: \"o2o\",\n fieldName: \"${fieldName}\",\n fieldIdName: \"${fieldName}Id\",\n required: false,\n otherMetadata: () => ${otherEntity.metaName},\n otherFieldName: \"${otherFieldName}\",\n otherColumnName: \"${otherColumnName}\",\n serde: undefined,\n immutable: false,\n }\n `;\n });\n\n dbMetadata.polymorphics.forEach((p) => {\n const { fieldName, notNull, components } = p;\n fields[fieldName] = code`\n {\n kind: \"poly\",\n fieldName: \"${fieldName}\",\n fieldIdName: \"${fieldName}Id\",\n required: ${notNull},\n components: [${components.map(\n ({ otherFieldName, otherEntity, columnName }) => code`\n {\n otherMetadata: () => ${otherEntity.metaName},\n otherFieldName: \"${otherFieldName}\",\n columnName: \"${columnName}\",\n },`,\n )}],\n serde: new ${PolymorphicKeySerde}(() => ${dbMetadata.entity.metaName}, \"${fieldName}\"${physical ? code`, ${q(components[0].columnName)}` : \"\"}),\n immutable: false,\n }\n `;\n });\n\n return fields;\n}\n\n/** Emits constructor options using codegen's existing column facts. */\nfunction columnOptions(\n column: Pick<PrimitiveField, \"columnNotNull\" | \"columnGenerated\"> & Partial<Pick<PrimitiveField, \"columnDefault\">>,\n): Code {\n return code`{ sqlNullable: ${!column.columnNotNull}, hasDefault: ${column.columnDefault != null && !column.columnGenerated}, isGenerated: ${column.columnGenerated} }`;\n}\n\nfunction maybeDefault(f: { hasConfigDefault: boolean; columnDefault?: number | boolean | string | null }): Code | \"\" {\n return f.hasConfigDefault ? code`default: \"config\",` : f.columnDefault != null ? code`default: \"schema\",` : \"\";\n}\n\nfunction maybeOrderBy(f: OneToManyField): Code | \"\" {\n return f.orderBy ? code`orderBy: { field: \"${f.orderBy.field}\", direction: \"${f.orderBy.direction}\" },` : \"\";\n}\n\n/** Emits the `softDeletes` config, i.e. `softDeletes: \"include\",`, for relations that opt out of hiding soft-deletes. */\nfunction maybeSoftDeletes(f: { softDeletes: \"include\" | \"exclude\" | undefined }): Code | \"\" {\n return f.softDeletes ? code`softDeletes: \"${f.softDeletes}\",` : \"\";\n}\n\n/** We sanitize/cleanStringValue all varchars, unless opted out by the column default/arrays/custom serdes. */\nfunction maybeSanitize(\n config: Config,\n f: { columnType: DatabaseColumnType; columnDefault?: any; isArray: boolean; customSerde: any },\n): Code | \"\" {\n // Only strings need to maybe turn off their cleanStringValue sanitization, if the default=\"\" or its an array\n return isString(config, f.columnType) && (f.columnDefault === \"''\" || f.isArray || f.customSerde)\n ? code`sanitize: false,`\n : \"\";\n}\n\nfunction isString(config: Config, columnType: DatabaseColumnType): boolean {\n return mapSimpleDbTypeToTypescriptType(config, columnType) === \"string\";\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"generateMetadataFile.cjs","names":["q","EntityMetadata","imp","SimpleFieldSerde","KeySerde","CustomSerdeAdapter","SuperstructSerde","ZodSerde","DecimalToNumberSerde","JsonSerde","BigIntSerde","PlainDateSerde","DateSerde","PlainDateTimeSerde","ZonedDateTimeSerde","PlainTimeSerde","PrimitiveSerde","EnumArrayFieldSerde","EnumFieldSerde","polymorphicField","PolyComponent","Column","ColumnDescriptors","mapSimpleDbTypeToTypescriptType"],"sources":["../src/generateMetadataFile.ts"],"sourcesContent":["import { type Code, type Import, code, imp } from \"ts-poet\";\n\nimport { type Config } from \"./config.ts\";\nimport {\n type DatabaseColumnType,\n type DbMetadata,\n type EntityDbMetadata,\n type OneToManyField,\n type PrimitiveField,\n} from \"./EntityDbMetadata.ts\";\nimport {\n BigIntSerde,\n Column,\n ColumnDescriptors,\n CustomSerdeAdapter,\n DateSerde,\n DecimalToNumberSerde,\n EntityMetadata,\n EnumArrayFieldSerde,\n EnumFieldSerde,\n JsonSerde,\n KeySerde,\n PlainDateSerde,\n PlainDateTimeSerde,\n PlainTimeSerde,\n PolyComponent,\n PrimitiveSerde,\n SimpleFieldSerde,\n SuperstructSerde,\n ZodSerde,\n ZonedDateTimeSerde,\n polymorphicField,\n} from \"./symbols.ts\";\nimport { mapSimpleDbTypeToTypescriptType, q } from \"./utils.ts\";\n\nexport function generateMetadataFile(config: Config, dbMeta: DbMetadata, meta: EntityDbMetadata): Code {\n const { entity, createdAt, updatedAt, deletedAt } = meta;\n\n const fields = generateFields(config, dbMeta, meta, (name) => columnReference(dbMeta, meta, name));\n\n Object.values(fields).forEach((code) => code.asOneline());\n\n const maybeBaseType = meta.baseClassName ? `\"${meta.baseClassName}\"` : undefined;\n // We want to put inheritanceType: sti/cti onto base classes as well\n const maybeInheritanceType = meta.inheritanceType ? `inheritanceType: \"${meta.inheritanceType}\",` : \"\";\n const maybeStiColumn = meta.stiDiscriminatorField ? `stiDiscriminatorField: \"${meta.stiDiscriminatorField}\",` : \"\";\n const maybeStiValue = meta.stiDiscriminatorValue ? `stiDiscriminatorValue: ${meta.stiDiscriminatorValue},` : \"\";\n const maybeCtiAbstract = meta.abstract ? `ctiAbstract: ${meta.abstract},` : \"\";\n // Force subtype `timestampFields` to be `undefined` to ensure all runtime code is reading from the baseMeta values.\n // Force subtype `timestampFields` to be `undefined` to ensure all runtime code is reading from the baseMeta values.\n const maybeTimestampConfig = meta.baseClassName\n ? code`undefined`\n : code`\n {\n createdAt: ${q(createdAt?.fieldName)},\n updatedAt: ${q(updatedAt?.fieldName)},\n deletedAt: ${q(deletedAt?.fieldName)},\n }\n `;\n const maybeInsertionOrder = meta.nonDeferredFkOrder !== 0 ? `nonDeferredFkOrder: ${meta.nonDeferredFkOrder},` : ``;\n const uniqueBy = getUniqueBy(config, meta);\n const maybeUniqueBy = uniqueBy.length > 0 ? code`uniqueBy: ${JSON.stringify(uniqueBy)},` : code``;\n\n return code`\n export const ${entity.metaName}: ${EntityMetadata}<${entity.name}> = {\n cstr: ${entity.typeForMetadataFile},\n type: \"${entity.name}\",\n baseType: ${maybeBaseType}, ${maybeInheritanceType} ${maybeStiColumn} ${maybeStiValue} ${maybeCtiAbstract}\n idType: \"${config.idType ?? \"tagged-string\"}\",\n idDbType: \"${meta.primaryKey.columnType}\",\n tagName: \"${meta.tagName}\",\n tableName: \"${meta.tableName}\",\n supportsEmExecute: ${!meta.inheritanceType && meta.supportsEmExecute === true},\n fields: ${fields},\n columns: ${columnOwner(dbMeta, meta, \"id\").entity.metaName}Columns,\n allFields: {},\n orderBy: ${q(config.entities[meta.name]?.orderBy)},\n timestampFields: ${maybeTimestampConfig},\n config: ${entity.configConst},\n factory: ${imp(`new${entity.name}@./entities.ts`)},\n baseTypes: [],\n subTypes: [], ${maybeInsertionOrder} ${maybeUniqueBy}\n };\n\n (${entity.typeForMetadataFile} as any).metadata = ${entity.metaName};\n `;\n}\n\n/** Returns configured identities plus conservative database-backed unique identities. */\nfunction getUniqueBy(config: Config, meta: EntityDbMetadata): string[][] {\n const uniqueBy = config.entities[meta.name]?.uniqueBy ?? [];\n const seen = new Set<string>();\n return [...uniqueBy, ...(meta.uniqueConstraints ?? [])].filter((fields) => {\n const key = fields.join(\"\\u0000\");\n if (seen.has(key)) return false;\n seen.add(key);\n return true;\n });\n}\n\n/** Emits fields that bind the already-declared physical columns. */\nfunction generateFields(\n config: Config,\n dbMeta: DbMetadata,\n dbMetadata: EntityDbMetadata,\n columnRef: (name: string, codec?: Code, args?: Code) => Code,\n): Record<string, Code> {\n const fields: Record<string, Code> = {};\n\n fields[\"id\"] = code`\n {\n kind: \"primaryKey\",\n fieldName: \"id\",\n fieldIdName: undefined,\n required: true,\n serde: new ${SimpleFieldSerde}(\"id\", ${columnRef(\"id\", code`new ${KeySerde}(\"${dbMetadata.tagName}\", \"${dbMetadata.primaryKey.columnType}\")`, columnArgs(dbMetadata.primaryKey, dbMetadata, code`() => ${dbMetadata.entity.metaName}`))}),\n immutable: true,\n }\n `;\n\n dbMetadata.primitives.forEach((p) => {\n const { fieldName, derived, columnName, columnType, superstruct, zodSchema, customSerde, isArray } = p;\n const column = columnArgs(p, dbMetadata);\n let serde: Code;\n if (customSerde) {\n serde = isArray\n ? code`new ${CustomSerdeAdapter}( \"${columnType}[]\", ${customSerde}, true)`\n : code`new ${CustomSerdeAdapter}( \"${columnType}\", ${customSerde})`;\n } else if (superstruct) {\n serde = code`new ${SuperstructSerde}( ${superstruct})`;\n } else if (zodSchema) {\n serde = code`new ${ZodSerde}( ${zodSchema})`;\n } else if (columnType === \"numeric\" || columnType === \"decimal\") {\n serde = isArray ? code`new ${DecimalToNumberSerde}(true)` : code`new ${DecimalToNumberSerde}()`;\n } else if (columnType === \"jsonb\") {\n serde = code`new ${JsonSerde}()`;\n } else if (p.rawFieldType === \"bigint\") {\n serde = isArray ? code`new ${BigIntSerde}(true)` : code`new ${BigIntSerde}()`;\n } else {\n let serdeType: Import;\n if (columnType === \"date\") {\n serdeType = config.temporal ? PlainDateSerde : DateSerde;\n } else if (columnType === \"timestamp without time zone\") {\n serdeType = config.temporal ? PlainDateTimeSerde : DateSerde;\n } else if (columnType === \"timestamp with time zone\") {\n serdeType = config.temporal ? ZonedDateTimeSerde : DateSerde;\n } else if (columnType === \"time without time zone\") {\n serdeType = config.temporal ? PlainTimeSerde : PrimitiveSerde;\n } else {\n serdeType = PrimitiveSerde;\n }\n serde = isArray ? code`new ${serdeType}( \"${columnType}[]\", true)` : code`new ${serdeType}( \"${columnType}\")`;\n }\n const extras = columnType === \"citext\" ? code`citext: true,` : \"\";\n fields[fieldName] = code`\n {\n kind: \"primitive\",\n fieldName: \"${fieldName}\",\n fieldIdName: undefined,\n derived: ${!derived ? false : `\"${derived}\"`},\n required: ${!derived && p.notNull},\n protected: ${p.protected},\n type: ${typeof p.rawFieldType === \"string\" ? `\"${p.rawFieldType}\"` : p.rawFieldType},\n serde: new ${SimpleFieldSerde}(\"${fieldName}\", ${columnRef(columnName, serde, column)}),\n immutable: false,\n ${p.lazy ? code`lazy: true,` : \"\"}\n ${extras}\n ${maybeDefault(p)}\n ${maybeSanitize(config, p)}\n }`;\n });\n\n // Treat native enums as primitives\n dbMetadata.pgEnums.forEach((p) => {\n const { columnName, fieldName, notNull, dbType } = p;\n fields[fieldName] = code`\n {\n kind: \"primitive\",\n fieldName: \"${fieldName}\",\n fieldIdName: undefined,\n derived: false,\n required: ${notNull},\n protected: false,\n type: \"string\",\n serde: new ${SimpleFieldSerde}(\"${fieldName}\", ${columnRef(columnName, code`new ${PrimitiveSerde}(\"${dbType}\")`, columnArgs(p, dbMetadata))}),\n immutable: false,\n ${maybeDefault(p)}\n }`;\n });\n\n dbMetadata.enums.forEach((field) => {\n const { fieldName, enumDetailType, notNull, isArray, columnName, columnType, derived } = field;\n const serdeType = isArray ? EnumArrayFieldSerde : EnumFieldSerde;\n const columnTypeWithArray = `${columnType}${isArray ? \"[]\" : \"\"}`;\n fields[fieldName] = code`\n {\n kind: \"enum\",\n fieldName: \"${fieldName}\",\n fieldIdName: undefined,\n required: ${notNull},\n derived: ${!derived ? false : `\"${derived}\"`},\n enumDetailType: ${enumDetailType},\n serde: new ${SimpleFieldSerde}(\"${fieldName}\", ${columnRef(columnName, code`new ${serdeType}(\"${columnTypeWithArray}\", ${enumDetailType})`, columnArgs(field, dbMetadata))}),\n immutable: false,\n ${maybeDefault(field)}\n }\n `;\n });\n\n dbMetadata.manyToOnes.forEach((m2o) => {\n const { fieldName, columnName, notNull, otherEntity, otherFieldName, derived, dbType } = m2o;\n const otherTagName = config.entities[otherEntity.name].tag;\n const physical = (dbMetadata.physicalMetadata ?? dbMetadata).manyToOnes.find(\n (field) => field.columnName === columnName,\n );\n const otherMetadata =\n physical?.otherEntity.name === otherEntity.name\n ? code`${columnRef(columnName)}.idMetadata!`\n : code`() => ${otherEntity.metaName}`;\n fields[fieldName] = code`\n {\n kind: \"m2o\",\n fieldName: \"${fieldName}\",\n fieldIdName: \"${fieldName}Id\",\n derived: ${!derived ? false : `\"${derived}\"`},\n required: ${notNull},\n otherMetadata: ${otherMetadata},\n otherFieldName: \"${otherFieldName}\",\n serde: new ${SimpleFieldSerde}(\"${fieldName}\", ${columnRef(columnName, code`new ${KeySerde}(\"${otherTagName}\", \"${dbType}\")`, columnArgs(m2o, dbMetadata, code`() => ${otherEntity.metaName}`))}),\n immutable: false,\n ${maybeDefault(m2o)}\n }\n `;\n });\n\n dbMetadata.oneToManys.forEach((o2m) => {\n const { fieldName, singularName, otherEntity, otherFieldName, otherColumnName } = o2m;\n fields[fieldName] = code`\n {\n kind: \"o2m\",\n fieldName: \"${fieldName}\",\n fieldIdName: \"${singularName}Ids\",\n required: false,\n otherMetadata: () => ${otherEntity.metaName},\n otherFieldName: \"${otherFieldName}\",\n otherColumnName: \"${otherColumnName}\",\n serde: undefined,\n immutable: false,\n ${maybeOrderBy(o2m)}\n ${maybeSoftDeletes(o2m)}\n }\n `;\n });\n\n dbMetadata.largeOneToManys.forEach((o2m) => {\n const { fieldName, singularName, otherEntity, otherFieldName, otherColumnName } = o2m;\n fields[fieldName] = code`\n {\n kind: \"lo2m\",\n fieldName: \"${fieldName}\",\n fieldIdName: \"${singularName}Ids\",\n required: false,\n otherMetadata: () => ${otherEntity.metaName},\n otherFieldName: \"${otherFieldName}\",\n otherColumnName: \"${otherColumnName}\",\n serde: undefined,\n immutable: false,\n }\n `;\n });\n\n dbMetadata.manyToManys.forEach((m2m) => {\n const { fieldName, singularName, otherEntity, otherFieldName, derived } = m2m;\n fields[fieldName] = code`\n {\n kind: \"m2m\",\n fieldName: \"${fieldName}\",\n fieldIdName: \"${singularName}Ids\",\n required: false,\n derived: ${derived === \"async\" ? `\"async\"` : derived === \"otherSide\" ? `\"otherSide\"` : \"false\"},\n otherMetadata: () => ${otherEntity.metaName},\n otherFieldName: \"${otherFieldName}\",\n serde: undefined,\n immutable: false,\n joinTableName: \"${m2m.joinTableName}\",\n columnNames: [\"${m2m.columnName}\", \"${m2m.otherColumnName}\"],\n hasJoinTableId: ${m2m.hasJoinTableId},\n ${maybeSoftDeletes(m2m)}\n }\n `;\n });\n\n dbMetadata.manyToManyEnums.forEach((m2m) => {\n const { fieldName, enumDetailType } = m2m;\n fields[fieldName] = code`\n {\n kind: \"m2mEnum\",\n fieldName: \"${fieldName}\",\n fieldIdName: undefined,\n required: false,\n derived: false,\n enumDetailType: ${enumDetailType},\n serde: undefined,\n immutable: false,\n joinTableName: \"${m2m.joinTableName}\",\n columnNames: [\"${m2m.columnName}\", \"${m2m.otherColumnName}\"],\n hasJoinTableId: ${m2m.hasJoinTableId},\n }\n `;\n });\n\n dbMetadata.oneToOnes.forEach((o2o) => {\n const { fieldName, otherEntity, otherFieldName, otherColumnName } = o2o;\n fields[fieldName] = code`\n {\n kind: \"o2o\",\n fieldName: \"${fieldName}\",\n fieldIdName: \"${fieldName}Id\",\n required: false,\n otherMetadata: () => ${otherEntity.metaName},\n otherFieldName: \"${otherFieldName}\",\n otherColumnName: \"${otherColumnName}\",\n serde: undefined,\n immutable: false,\n }\n `;\n });\n\n dbMetadata.polymorphics.forEach((p) => {\n const { fieldName, notNull, components } = p;\n components.forEach((component) =>\n columnRef(\n component.columnName,\n code`new ${KeySerde}(\"${config.entities[component.otherEntity.name].tag}\", \"${dbMeta.entitiesByName[component.otherEntity.name].primaryKey.columnType}\")`,\n code`true, false, false, false, false, () => ${component.otherEntity.metaName}`,\n ),\n );\n fields[fieldName] = code`\n ${polymorphicField}(\"${fieldName}\", ${notNull}, [${components.map((component) => {\n const owner = columnOwner(dbMeta, dbMetadata, component.columnName);\n const physical = (owner.physicalMetadata ?? owner).polymorphics\n .flatMap((field) => field.components)\n .find((c) => c.columnName === component.columnName)!;\n const target =\n physical.otherEntity.name === component.otherEntity.name\n ? \"\"\n : code`, () => ${component.otherEntity.metaName}`;\n return code`new ${PolyComponent}(${columnRef(component.columnName)}, ${q(component.otherFieldName)}${target}),`;\n })}])\n `;\n });\n\n return fields;\n}\n\n/** Emits constructor arguments using codegen's existing column facts. */\nfunction columnArgs(\n column: Pick<PrimitiveField, \"columnNotNull\" | \"columnGenerated\"> & Partial<Pick<PrimitiveField, \"columnDefault\">>,\n meta: EntityDbMetadata,\n idMetadata?: Code,\n): Code {\n const insertOptional = column === meta.createdAt || column === meta.updatedAt;\n return code`${!column.columnNotNull}, ${column.columnDefault != null && !column.columnGenerated}, ${column.columnGenerated}, ${insertOptional}, true, ${idMetadata ?? \"undefined\"}`;\n}\n\n/** Declares all physical codecs before any domain metadata; ID targets remain lazy. */\nexport function generateColumnDeclarations(config: Config, dbMeta: DbMetadata, meta: EntityDbMetadata): Code {\n if (meta.inheritanceType === \"sti\" && meta.baseClassName) return code``;\n const columns: Record<string, Code> = {};\n generateFields(config, dbMeta, meta.physicalMetadata ?? meta, (name, codec, args) => {\n if (codec) columns[name] = code`new ${Column}(${q(name)}, ${args}, ${codec})`.asOneline();\n return code`${meta.entity.metaName}Columns[${q(name)}]`;\n });\n return code`const ${meta.entity.metaName}Columns = ${columns} satisfies ${ColumnDescriptors};`;\n}\n\n/** Locates a column's physical table without copying inherited columns into subtype tables. */\nfunction columnOwner(dbMeta: DbMetadata, meta: EntityDbMetadata, name: string): EntityDbMetadata {\n if (meta.inheritanceType === \"sti\" && meta.baseClassName) {\n return columnOwner(dbMeta, dbMeta.entitiesByName[meta.baseClassName], name);\n }\n const physical = meta.physicalMetadata ?? meta;\n if (\n name === \"id\" ||\n [\n ...physical.primitives,\n ...physical.enums,\n ...physical.pgEnums,\n ...physical.manyToOnes,\n ...physical.polymorphics.flatMap((field) => field.components),\n ].some((field) => field.columnName === name)\n )\n return meta;\n if (meta.baseClassName) return columnOwner(dbMeta, dbMeta.entitiesByName[meta.baseClassName], name);\n throw new Error(`No physical column ${meta.name}.${name}`);\n}\n\n/** Emits a direct reference to the single physical descriptor. */\nfunction columnReference(dbMeta: DbMetadata, meta: EntityDbMetadata, name: string): Code {\n return code`${columnOwner(dbMeta, meta, name).entity.metaName}Columns[${q(name)}]`;\n}\n\nfunction maybeDefault(f: { hasConfigDefault: boolean; columnDefault?: number | boolean | string | null }): Code | \"\" {\n return f.hasConfigDefault ? code`default: \"config\",` : f.columnDefault != null ? code`default: \"schema\",` : \"\";\n}\n\nfunction maybeOrderBy(f: OneToManyField): Code | \"\" {\n return f.orderBy ? code`orderBy: { field: \"${f.orderBy.field}\", direction: \"${f.orderBy.direction}\" },` : \"\";\n}\n\n/** Emits the `softDeletes` config, i.e. `softDeletes: \"include\",`, for relations that opt out of hiding soft-deletes. */\nfunction maybeSoftDeletes(f: { softDeletes: \"include\" | \"exclude\" | undefined }): Code | \"\" {\n return f.softDeletes ? code`softDeletes: \"${f.softDeletes}\",` : \"\";\n}\n\n/** We sanitize/cleanStringValue all varchars, unless opted out by the column default/arrays/custom serdes. */\nfunction maybeSanitize(\n config: Config,\n f: { columnType: DatabaseColumnType; columnDefault?: any; isArray: boolean; customSerde: any },\n): Code | \"\" {\n // Only strings need to maybe turn off their cleanStringValue sanitization, if the default=\"\" or its an array\n return isString(config, f.columnType) && (f.columnDefault === \"''\" || f.isArray || f.customSerde)\n ? code`sanitize: false,`\n : \"\";\n}\n\nfunction isString(config: Config, columnType: DatabaseColumnType): boolean {\n return mapSimpleDbTypeToTypescriptType(config, columnType) === \"string\";\n}\n"],"mappings":"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"}
@@ -3,6 +3,8 @@ import { DbMetadata, EntityDbMetadata } from "./EntityDbMetadata.cjs";
3
3
  import { Code } from "ts-poet";
4
4
  //#region src/generateMetadataFile.d.ts
5
5
  declare function generateMetadataFile(config: Config, dbMeta: DbMetadata, meta: EntityDbMetadata): Code;
6
+ /** Declares all physical codecs before any domain metadata; ID targets remain lazy. */
7
+ declare function generateColumnDeclarations(config: Config, dbMeta: DbMetadata, meta: EntityDbMetadata): Code;
6
8
  //#endregion
7
- export { generateMetadataFile };
9
+ export { generateColumnDeclarations, generateMetadataFile };
8
10
  //# sourceMappingURL=generateMetadataFile.d.cts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generateMetadataFile.d.cts","names":[],"sources":["../src/generateMetadataFile.ts"],"mappings":";;;;iBA+BgB,qBAAqB,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB"}
1
+ {"version":3,"file":"generateMetadataFile.d.cts","names":[],"sources":["../src/generateMetadataFile.ts"],"mappings":";;;;iBAmCgB,qBAAqB,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB;;iBA2UlF,2BAA2B,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB"}
@@ -3,6 +3,8 @@ import { DbMetadata, EntityDbMetadata } from "./EntityDbMetadata.mjs";
3
3
  import { Code } from "ts-poet";
4
4
  //#region src/generateMetadataFile.d.ts
5
5
  declare function generateMetadataFile(config: Config, dbMeta: DbMetadata, meta: EntityDbMetadata): Code;
6
+ /** Declares all physical codecs before any domain metadata; ID targets remain lazy. */
7
+ declare function generateColumnDeclarations(config: Config, dbMeta: DbMetadata, meta: EntityDbMetadata): Code;
6
8
  //#endregion
7
- export { generateMetadataFile };
9
+ export { generateColumnDeclarations, generateMetadataFile };
8
10
  //# sourceMappingURL=generateMetadataFile.d.mts.map
@@ -1 +1 @@
1
- {"version":3,"file":"generateMetadataFile.d.mts","names":[],"sources":["../src/generateMetadataFile.ts"],"mappings":";;;;iBA+BgB,qBAAqB,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB"}
1
+ {"version":3,"file":"generateMetadataFile.d.mts","names":[],"sources":["../src/generateMetadataFile.ts"],"mappings":";;;;iBAmCgB,qBAAqB,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB;;iBA2UlF,2BAA2B,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB"}
@@ -1,26 +1,12 @@
1
1
  import { mapSimpleDbTypeToTypescriptType, q } from "./utils.js";
2
2
  import "./config.js";
3
- import { BigIntSerde, CustomSerdeAdapter, DateSerde, DecimalToNumberSerde, EntityMetadata, EnumArrayFieldSerde, EnumFieldSerde, JsonSerde, KeySerde, PlainDateSerde, PlainDateTimeSerde, PlainTimeSerde, PolymorphicKeySerde, PrimitiveSerde, SuperstructSerde, ZodSerde, ZonedDateTimeSerde } from "./symbols.js";
3
+ import { BigIntSerde, Column, ColumnDescriptors, CustomSerdeAdapter, DateSerde, DecimalToNumberSerde, EntityMetadata, EnumArrayFieldSerde, EnumFieldSerde, JsonSerde, KeySerde, PlainDateSerde, PlainDateTimeSerde, PlainTimeSerde, PolyComponent, PrimitiveSerde, SimpleFieldSerde, SuperstructSerde, ZodSerde, ZonedDateTimeSerde, polymorphicField } from "./symbols.js";
4
4
  import "./EntityDbMetadata.js";
5
5
  import { code, imp } from "ts-poet";
6
6
  //#region src/generateMetadataFile.ts
7
7
  function generateMetadataFile(config, dbMeta, meta) {
8
8
  const { entity, createdAt, updatedAt, deletedAt } = meta;
9
- const fields = generateFields(config, meta);
10
- const physical = meta.physicalMetadata ?? meta;
11
- const sharedTable = meta.inheritanceType === "sti" && meta.baseClassName;
12
- const storageFields = generateFields(config, physical, true);
13
- const physicalFields = Object.fromEntries(Object.entries(storageFields).map(([name, field]) => [name, fields[name]?.toString() === field.toString() ? code`${entity.metaName}.fields[${q(name)}]` : field]));
14
- const columns = Object.fromEntries([
15
- ["id", "id"],
16
- ...[
17
- ...physical.primitives,
18
- ...physical.enums,
19
- ...physical.pgEnums,
20
- ...physical.manyToOnes
21
- ].map((field) => [field.columnName, field.fieldName]),
22
- ...physical.polymorphics.flatMap((field) => field.components.map((component) => [component.columnName, field.fieldName]))
23
- ]);
9
+ const fields = generateFields(config, dbMeta, meta, (name) => columnReference(dbMeta, meta, name));
24
10
  Object.values(fields).forEach((code) => code.asOneline());
25
11
  const maybeBaseType = meta.baseClassName ? `"${meta.baseClassName}"` : void 0;
26
12
  const maybeInheritanceType = meta.inheritanceType ? `inheritanceType: "${meta.inheritanceType}",` : "";
@@ -48,7 +34,7 @@ function generateMetadataFile(config, dbMeta, meta) {
48
34
  tableName: "${meta.tableName}",
49
35
  supportsEmExecute: ${!meta.inheritanceType && meta.supportsEmExecute === true},
50
36
  fields: ${fields},
51
- columns: {},
37
+ columns: ${columnOwner(dbMeta, meta, "id").entity.metaName}Columns,
52
38
  allFields: {},
53
39
  orderBy: ${q(config.entities[meta.name]?.orderBy)},
54
40
  timestampFields: ${maybeTimestampConfig},
@@ -58,14 +44,6 @@ function generateMetadataFile(config, dbMeta, meta) {
58
44
  subTypes: [], ${maybeInsertionOrder} ${maybeUniqueBy}
59
45
  };
60
46
 
61
- ${sharedTable ? "" : code`
62
- ${Object.entries(columns).map(([columnName, fieldName]) => {
63
- const firstColumn = Object.keys(columns).find((name) => columns[name] === fieldName);
64
- const field = firstColumn === columnName ? physicalFields[fieldName] : code`${entity.metaName}.columns[${q(firstColumn)}].field`;
65
- return code`${entity.metaName}.columns[${q(columnName)}] = { fieldName: ${q(fieldName)}, field: ${field} };`;
66
- })}
67
- `}
68
-
69
47
  (${entity.typeForMetadataFile} as any).metadata = ${entity.metaName};
70
48
  `;
71
49
  }
@@ -80,8 +58,8 @@ function getUniqueBy(config, meta) {
80
58
  return true;
81
59
  });
82
60
  }
83
- /** Emits field descriptors; physical polymorphic serdes resolve the original storage components. */
84
- function generateFields(config, dbMetadata, physical = false) {
61
+ /** Emits fields that bind the already-declared physical columns. */
62
+ function generateFields(config, dbMeta, dbMetadata, columnRef) {
85
63
  const fields = {};
86
64
  fields["id"] = code`
87
65
  {
@@ -89,20 +67,20 @@ function generateFields(config, dbMetadata, physical = false) {
89
67
  fieldName: "id",
90
68
  fieldIdName: undefined,
91
69
  required: true,
92
- serde: new ${KeySerde}("${dbMetadata.tagName}", "id", "id", "${dbMetadata.primaryKey.columnType}", ${columnOptions(dbMetadata.primaryKey)}),
70
+ serde: new ${SimpleFieldSerde}("id", ${columnRef("id", code`new ${KeySerde}("${dbMetadata.tagName}", "${dbMetadata.primaryKey.columnType}")`, columnArgs(dbMetadata.primaryKey, dbMetadata, code`() => ${dbMetadata.entity.metaName}`))}),
93
71
  immutable: true,
94
72
  }
95
73
  `;
96
74
  dbMetadata.primitives.forEach((p) => {
97
75
  const { fieldName, derived, columnName, columnType, superstruct, zodSchema, customSerde, isArray } = p;
98
- const column = columnOptions(p);
76
+ const column = columnArgs(p, dbMetadata);
99
77
  let serde;
100
- if (customSerde) serde = isArray ? code`new ${CustomSerdeAdapter}("${fieldName}", "${columnName}", "${columnType}[]", ${customSerde}, true, ${!p.notNull}, ${column})` : code`new ${CustomSerdeAdapter}("${fieldName}", "${columnName}", "${columnType}", ${customSerde}, false, false, ${column})`;
101
- else if (superstruct) serde = code`new ${SuperstructSerde}("${fieldName}", "${columnName}", ${superstruct}, ${column})`;
102
- else if (zodSchema) serde = code`new ${ZodSerde}("${fieldName}", "${columnName}", ${zodSchema}, ${column})`;
103
- else if (columnType === "numeric" || columnType === "decimal") serde = isArray ? code`new ${DecimalToNumberSerde}("${fieldName}", "${columnName}", true, ${!p.notNull}, ${column})` : code`new ${DecimalToNumberSerde}("${fieldName}", "${columnName}", false, false, ${column})`;
104
- else if (columnType === "jsonb") serde = code`new ${JsonSerde}("${fieldName}", "${columnName}", ${column})`;
105
- else if (p.rawFieldType === "bigint") serde = isArray ? code`new ${BigIntSerde}("${fieldName}", "${columnName}", true, ${!p.notNull}, ${column})` : code`new ${BigIntSerde}("${fieldName}", "${columnName}", false, false, ${column})`;
78
+ if (customSerde) serde = isArray ? code`new ${CustomSerdeAdapter}( "${columnType}[]", ${customSerde}, true)` : code`new ${CustomSerdeAdapter}( "${columnType}", ${customSerde})`;
79
+ else if (superstruct) serde = code`new ${SuperstructSerde}( ${superstruct})`;
80
+ else if (zodSchema) serde = code`new ${ZodSerde}( ${zodSchema})`;
81
+ else if (columnType === "numeric" || columnType === "decimal") serde = isArray ? code`new ${DecimalToNumberSerde}(true)` : code`new ${DecimalToNumberSerde}()`;
82
+ else if (columnType === "jsonb") serde = code`new ${JsonSerde}()`;
83
+ else if (p.rawFieldType === "bigint") serde = isArray ? code`new ${BigIntSerde}(true)` : code`new ${BigIntSerde}()`;
106
84
  else {
107
85
  let serdeType;
108
86
  if (columnType === "date") serdeType = config.temporal ? PlainDateSerde : DateSerde;
@@ -110,7 +88,7 @@ function generateFields(config, dbMetadata, physical = false) {
110
88
  else if (columnType === "timestamp with time zone") serdeType = config.temporal ? ZonedDateTimeSerde : DateSerde;
111
89
  else if (columnType === "time without time zone") serdeType = config.temporal ? PlainTimeSerde : PrimitiveSerde;
112
90
  else serdeType = PrimitiveSerde;
113
- serde = isArray ? code`new ${serdeType}("${fieldName}", "${columnName}", "${columnType}[]", true, ${!p.notNull}, ${column})` : code`new ${serdeType}("${fieldName}", "${columnName}", "${columnType}", false, false, ${column})`;
91
+ serde = isArray ? code`new ${serdeType}( "${columnType}[]", true)` : code`new ${serdeType}( "${columnType}")`;
114
92
  }
115
93
  const extras = columnType === "citext" ? code`citext: true,` : "";
116
94
  fields[fieldName] = code`
@@ -122,7 +100,7 @@ function generateFields(config, dbMetadata, physical = false) {
122
100
  required: ${!derived && p.notNull},
123
101
  protected: ${p.protected},
124
102
  type: ${typeof p.rawFieldType === "string" ? `"${p.rawFieldType}"` : p.rawFieldType},
125
- serde: ${serde},
103
+ serde: new ${SimpleFieldSerde}("${fieldName}", ${columnRef(columnName, serde, column)}),
126
104
  immutable: false,
127
105
  ${p.lazy ? code`lazy: true,` : ""}
128
106
  ${extras}
@@ -141,7 +119,7 @@ function generateFields(config, dbMetadata, physical = false) {
141
119
  required: ${notNull},
142
120
  protected: false,
143
121
  type: "string",
144
- serde: new ${PrimitiveSerde}("${fieldName}", "${columnName}", "${dbType}", false, false, ${columnOptions(p)}),
122
+ serde: new ${SimpleFieldSerde}("${fieldName}", ${columnRef(columnName, code`new ${PrimitiveSerde}("${dbType}")`, columnArgs(p, dbMetadata))}),
145
123
  immutable: false,
146
124
  ${maybeDefault(p)}
147
125
  }`;
@@ -150,7 +128,6 @@ function generateFields(config, dbMetadata, physical = false) {
150
128
  const { fieldName, enumDetailType, notNull, isArray, columnName, columnType, derived } = field;
151
129
  const serdeType = isArray ? EnumArrayFieldSerde : EnumFieldSerde;
152
130
  const columnTypeWithArray = `${columnType}${isArray ? "[]" : ""}`;
153
- const maybeIsNullable = isArray ? `, ${!notNull}` : "";
154
131
  fields[fieldName] = code`
155
132
  {
156
133
  kind: "enum",
@@ -159,7 +136,7 @@ function generateFields(config, dbMetadata, physical = false) {
159
136
  required: ${notNull},
160
137
  derived: ${!derived ? false : `"${derived}"`},
161
138
  enumDetailType: ${enumDetailType},
162
- serde: new ${serdeType}("${fieldName}", "${columnName}", "${columnTypeWithArray}"${maybeIsNullable}, ${enumDetailType}, ${columnOptions(field)}),
139
+ serde: new ${SimpleFieldSerde}("${fieldName}", ${columnRef(columnName, code`new ${serdeType}("${columnTypeWithArray}", ${enumDetailType})`, columnArgs(field, dbMetadata))}),
163
140
  immutable: false,
164
141
  ${maybeDefault(field)}
165
142
  }
@@ -168,6 +145,7 @@ function generateFields(config, dbMetadata, physical = false) {
168
145
  dbMetadata.manyToOnes.forEach((m2o) => {
169
146
  const { fieldName, columnName, notNull, otherEntity, otherFieldName, derived, dbType } = m2o;
170
147
  const otherTagName = config.entities[otherEntity.name].tag;
148
+ const otherMetadata = (dbMetadata.physicalMetadata ?? dbMetadata).manyToOnes.find((field) => field.columnName === columnName)?.otherEntity.name === otherEntity.name ? code`${columnRef(columnName)}.idMetadata!` : code`() => ${otherEntity.metaName}`;
171
149
  fields[fieldName] = code`
172
150
  {
173
151
  kind: "m2o",
@@ -175,9 +153,9 @@ function generateFields(config, dbMetadata, physical = false) {
175
153
  fieldIdName: "${fieldName}Id",
176
154
  derived: ${!derived ? false : `"${derived}"`},
177
155
  required: ${notNull},
178
- otherMetadata: () => ${otherEntity.metaName},
156
+ otherMetadata: ${otherMetadata},
179
157
  otherFieldName: "${otherFieldName}",
180
- serde: new ${KeySerde}("${otherTagName}", "${fieldName}", "${columnName}", "${dbType}", ${columnOptions(m2o)}),
158
+ serde: new ${SimpleFieldSerde}("${fieldName}", ${columnRef(columnName, code`new ${KeySerde}("${otherTagName}", "${dbType}")`, columnArgs(m2o, dbMetadata, code`() => ${otherEntity.metaName}`))}),
181
159
  immutable: false,
182
160
  ${maybeDefault(m2o)}
183
161
  }
@@ -273,28 +251,49 @@ function generateFields(config, dbMetadata, physical = false) {
273
251
  });
274
252
  dbMetadata.polymorphics.forEach((p) => {
275
253
  const { fieldName, notNull, components } = p;
254
+ components.forEach((component) => columnRef(component.columnName, code`new ${KeySerde}("${config.entities[component.otherEntity.name].tag}", "${dbMeta.entitiesByName[component.otherEntity.name].primaryKey.columnType}")`, code`true, false, false, false, false, () => ${component.otherEntity.metaName}`));
276
255
  fields[fieldName] = code`
277
- {
278
- kind: "poly",
279
- fieldName: "${fieldName}",
280
- fieldIdName: "${fieldName}Id",
281
- required: ${notNull},
282
- components: [${components.map(({ otherFieldName, otherEntity, columnName }) => code`
283
- {
284
- otherMetadata: () => ${otherEntity.metaName},
285
- otherFieldName: "${otherFieldName}",
286
- columnName: "${columnName}",
287
- },`)}],
288
- serde: new ${PolymorphicKeySerde}(() => ${dbMetadata.entity.metaName}, "${fieldName}"${physical ? code`, ${q(components[0].columnName)}` : ""}),
289
- immutable: false,
290
- }
256
+ ${polymorphicField}("${fieldName}", ${notNull}, [${components.map((component) => {
257
+ const owner = columnOwner(dbMeta, dbMetadata, component.columnName);
258
+ const target = (owner.physicalMetadata ?? owner).polymorphics.flatMap((field) => field.components).find((c) => c.columnName === component.columnName).otherEntity.name === component.otherEntity.name ? "" : code`, () => ${component.otherEntity.metaName}`;
259
+ return code`new ${PolyComponent}(${columnRef(component.columnName)}, ${q(component.otherFieldName)}${target}),`;
260
+ })}])
291
261
  `;
292
262
  });
293
263
  return fields;
294
264
  }
295
- /** Emits constructor options using codegen's existing column facts. */
296
- function columnOptions(column) {
297
- return code`{ sqlNullable: ${!column.columnNotNull}, hasDefault: ${column.columnDefault != null && !column.columnGenerated}, isGenerated: ${column.columnGenerated} }`;
265
+ /** Emits constructor arguments using codegen's existing column facts. */
266
+ function columnArgs(column, meta, idMetadata) {
267
+ const insertOptional = column === meta.createdAt || column === meta.updatedAt;
268
+ return code`${!column.columnNotNull}, ${column.columnDefault != null && !column.columnGenerated}, ${column.columnGenerated}, ${insertOptional}, true, ${idMetadata ?? "undefined"}`;
269
+ }
270
+ /** Declares all physical codecs before any domain metadata; ID targets remain lazy. */
271
+ function generateColumnDeclarations(config, dbMeta, meta) {
272
+ if (meta.inheritanceType === "sti" && meta.baseClassName) return code``;
273
+ const columns = {};
274
+ generateFields(config, dbMeta, meta.physicalMetadata ?? meta, (name, codec, args) => {
275
+ if (codec) columns[name] = code`new ${Column}(${q(name)}, ${args}, ${codec})`.asOneline();
276
+ return code`${meta.entity.metaName}Columns[${q(name)}]`;
277
+ });
278
+ return code`const ${meta.entity.metaName}Columns = ${columns} satisfies ${ColumnDescriptors};`;
279
+ }
280
+ /** Locates a column's physical table without copying inherited columns into subtype tables. */
281
+ function columnOwner(dbMeta, meta, name) {
282
+ if (meta.inheritanceType === "sti" && meta.baseClassName) return columnOwner(dbMeta, dbMeta.entitiesByName[meta.baseClassName], name);
283
+ const physical = meta.physicalMetadata ?? meta;
284
+ if (name === "id" || [
285
+ ...physical.primitives,
286
+ ...physical.enums,
287
+ ...physical.pgEnums,
288
+ ...physical.manyToOnes,
289
+ ...physical.polymorphics.flatMap((field) => field.components)
290
+ ].some((field) => field.columnName === name)) return meta;
291
+ if (meta.baseClassName) return columnOwner(dbMeta, dbMeta.entitiesByName[meta.baseClassName], name);
292
+ throw new Error(`No physical column ${meta.name}.${name}`);
293
+ }
294
+ /** Emits a direct reference to the single physical descriptor. */
295
+ function columnReference(dbMeta, meta, name) {
296
+ return code`${columnOwner(dbMeta, meta, name).entity.metaName}Columns[${q(name)}]`;
298
297
  }
299
298
  function maybeDefault(f) {
300
299
  return f.hasConfigDefault ? code`default: "config",` : f.columnDefault != null ? code`default: "schema",` : "";
@@ -314,6 +313,6 @@ function isString(config, columnType) {
314
313
  return mapSimpleDbTypeToTypescriptType(config, columnType) === "string";
315
314
  }
316
315
  //#endregion
317
- export { generateMetadataFile };
316
+ export { generateColumnDeclarations, generateMetadataFile };
318
317
 
319
318
  //# sourceMappingURL=generateMetadataFile.js.map