joist-codegen 2.3.0-next.64 → 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.
Files changed (43) hide show
  1. package/build/EntityDbMetadata.cjs +6 -0
  2. package/build/EntityDbMetadata.cjs.map +1 -1
  3. package/build/EntityDbMetadata.d.cts +2 -0
  4. package/build/EntityDbMetadata.d.cts.map +1 -1
  5. package/build/EntityDbMetadata.d.mts +2 -0
  6. package/build/EntityDbMetadata.d.mts.map +1 -1
  7. package/build/EntityDbMetadata.js +6 -0
  8. package/build/EntityDbMetadata.js.map +1 -1
  9. package/build/generate.cjs +1 -0
  10. package/build/generate.cjs.map +1 -1
  11. package/build/generate.js +2 -1
  12. package/build/generate.js.map +1 -1
  13. package/build/generateEntityCodegenFile.cjs +13 -10
  14. package/build/generateEntityCodegenFile.cjs.map +1 -1
  15. package/build/generateEntityCodegenFile.d.cts.map +1 -1
  16. package/build/generateEntityCodegenFile.d.mts.map +1 -1
  17. package/build/generateEntityCodegenFile.js +13 -10
  18. package/build/generateEntityCodegenFile.js.map +1 -1
  19. package/build/generateMetadataFile.cjs +58 -44
  20. package/build/generateMetadataFile.cjs.map +1 -1
  21. package/build/generateMetadataFile.d.cts +3 -1
  22. package/build/generateMetadataFile.d.cts.map +1 -1
  23. package/build/generateMetadataFile.d.mts +3 -1
  24. package/build/generateMetadataFile.d.mts.map +1 -1
  25. package/build/generateMetadataFile.js +59 -46
  26. package/build/generateMetadataFile.js.map +1 -1
  27. package/build/inheritance.cjs +28 -0
  28. package/build/inheritance.cjs.map +1 -1
  29. package/build/inheritance.d.cts +1 -0
  30. package/build/inheritance.d.cts.map +1 -1
  31. package/build/inheritance.d.mts +1 -0
  32. package/build/inheritance.d.mts.map +1 -1
  33. package/build/inheritance.js +28 -0
  34. package/build/inheritance.js.map +1 -1
  35. package/build/symbols.cjs +10 -0
  36. package/build/symbols.cjs.map +1 -1
  37. package/build/symbols.d.cts +6 -1
  38. package/build/symbols.d.cts.map +1 -1
  39. package/build/symbols.d.mts +6 -1
  40. package/build/symbols.d.mts.map +1 -1
  41. package/build/symbols.js +6 -1
  42. package/build/symbols.js.map +1 -1
  43. package/package.json +2 -2
@@ -7,7 +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);
10
+ const fields = generateFields(config, dbMeta, meta, (name) => columnReference(dbMeta, meta, name));
11
11
  Object.values(fields).forEach((code) => code.asOneline());
12
12
  const maybeBaseType = meta.baseClassName ? `"${meta.baseClassName}"` : void 0;
13
13
  const maybeInheritanceType = meta.inheritanceType ? `inheritanceType: "${meta.inheritanceType}",` : "";
@@ -35,16 +35,7 @@ function generateMetadataFile(config, dbMeta, meta) {
35
35
  tableName: "${meta.tableName}",
36
36
  supportsEmExecute: ${!meta.inheritanceType && meta.supportsEmExecute === true},
37
37
  fields: ${fields},
38
- columns: ${Object.fromEntries([
39
- ["id", { fieldName: "id" }],
40
- ...[
41
- ...meta.primitives,
42
- ...meta.enums,
43
- ...meta.pgEnums,
44
- ...meta.manyToOnes
45
- ].map((field) => [field.columnName, { fieldName: field.fieldName }]),
46
- ...meta.polymorphics.flatMap((field) => field.components.map((component) => [component.columnName, { fieldName: field.fieldName }]))
47
- ])},
38
+ columns: ${columnOwner(dbMeta, meta, "id").entity.metaName}Columns,
48
39
  allFields: {},
49
40
  orderBy: ${require_utils.q(config.entities[meta.name]?.orderBy)},
50
41
  timestampFields: ${maybeTimestampConfig},
@@ -68,7 +59,8 @@ function getUniqueBy(config, meta) {
68
59
  return true;
69
60
  });
70
61
  }
71
- function generateFields(config, dbMetadata) {
62
+ /** Emits fields that bind the already-declared physical columns. */
63
+ function generateFields(config, dbMeta, dbMetadata, columnRef) {
72
64
  const fields = {};
73
65
  fields["id"] = ts_poet.code`
74
66
  {
@@ -76,20 +68,20 @@ function generateFields(config, dbMetadata) {
76
68
  fieldName: "id",
77
69
  fieldIdName: undefined,
78
70
  required: true,
79
- 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}`))}),
80
72
  immutable: true,
81
73
  }
82
74
  `;
83
75
  dbMetadata.primitives.forEach((p) => {
84
76
  const { fieldName, derived, columnName, columnType, superstruct, zodSchema, customSerde, isArray } = p;
85
- const column = columnOptions(p);
77
+ const column = columnArgs(p, dbMetadata);
86
78
  let serde;
87
- 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})`;
88
- else if (superstruct) serde = ts_poet.code`new ${require_symbols.SuperstructSerde}("${fieldName}", "${columnName}", ${superstruct}, ${column})`;
89
- else if (zodSchema) serde = ts_poet.code`new ${require_symbols.ZodSerde}("${fieldName}", "${columnName}", ${zodSchema}, ${column})`;
90
- 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})`;
91
- else if (columnType === "jsonb") serde = ts_poet.code`new ${require_symbols.JsonSerde}("${fieldName}", "${columnName}", ${column})`;
92
- 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}()`;
93
85
  else {
94
86
  let serdeType;
95
87
  if (columnType === "date") serdeType = config.temporal ? require_symbols.PlainDateSerde : require_symbols.DateSerde;
@@ -97,7 +89,7 @@ function generateFields(config, dbMetadata) {
97
89
  else if (columnType === "timestamp with time zone") serdeType = config.temporal ? require_symbols.ZonedDateTimeSerde : require_symbols.DateSerde;
98
90
  else if (columnType === "time without time zone") serdeType = config.temporal ? require_symbols.PlainTimeSerde : require_symbols.PrimitiveSerde;
99
91
  else serdeType = require_symbols.PrimitiveSerde;
100
- 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}")`;
101
93
  }
102
94
  const extras = columnType === "citext" ? ts_poet.code`citext: true,` : "";
103
95
  fields[fieldName] = ts_poet.code`
@@ -109,7 +101,7 @@ function generateFields(config, dbMetadata) {
109
101
  required: ${!derived && p.notNull},
110
102
  protected: ${p.protected},
111
103
  type: ${typeof p.rawFieldType === "string" ? `"${p.rawFieldType}"` : p.rawFieldType},
112
- serde: ${serde},
104
+ serde: new ${require_symbols.SimpleFieldSerde}("${fieldName}", ${columnRef(columnName, serde, column)}),
113
105
  immutable: false,
114
106
  ${p.lazy ? ts_poet.code`lazy: true,` : ""}
115
107
  ${extras}
@@ -128,7 +120,7 @@ function generateFields(config, dbMetadata) {
128
120
  required: ${notNull},
129
121
  protected: false,
130
122
  type: "string",
131
- 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))}),
132
124
  immutable: false,
133
125
  ${maybeDefault(p)}
134
126
  }`;
@@ -137,7 +129,6 @@ function generateFields(config, dbMetadata) {
137
129
  const { fieldName, enumDetailType, notNull, isArray, columnName, columnType, derived } = field;
138
130
  const serdeType = isArray ? require_symbols.EnumArrayFieldSerde : require_symbols.EnumFieldSerde;
139
131
  const columnTypeWithArray = `${columnType}${isArray ? "[]" : ""}`;
140
- const maybeIsNullable = isArray ? `, ${!notNull}` : "";
141
132
  fields[fieldName] = ts_poet.code`
142
133
  {
143
134
  kind: "enum",
@@ -146,7 +137,7 @@ function generateFields(config, dbMetadata) {
146
137
  required: ${notNull},
147
138
  derived: ${!derived ? false : `"${derived}"`},
148
139
  enumDetailType: ${enumDetailType},
149
- 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))}),
150
141
  immutable: false,
151
142
  ${maybeDefault(field)}
152
143
  }
@@ -155,6 +146,7 @@ function generateFields(config, dbMetadata) {
155
146
  dbMetadata.manyToOnes.forEach((m2o) => {
156
147
  const { fieldName, columnName, notNull, otherEntity, otherFieldName, derived, dbType } = m2o;
157
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}`;
158
150
  fields[fieldName] = ts_poet.code`
159
151
  {
160
152
  kind: "m2o",
@@ -162,9 +154,9 @@ function generateFields(config, dbMetadata) {
162
154
  fieldIdName: "${fieldName}Id",
163
155
  derived: ${!derived ? false : `"${derived}"`},
164
156
  required: ${notNull},
165
- otherMetadata: () => ${otherEntity.metaName},
157
+ otherMetadata: ${otherMetadata},
166
158
  otherFieldName: "${otherFieldName}",
167
- 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}`))}),
168
160
  immutable: false,
169
161
  ${maybeDefault(m2o)}
170
162
  }
@@ -260,28 +252,49 @@ function generateFields(config, dbMetadata) {
260
252
  });
261
253
  dbMetadata.polymorphics.forEach((p) => {
262
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}`));
263
256
  fields[fieldName] = ts_poet.code`
264
- {
265
- kind: "poly",
266
- fieldName: "${fieldName}",
267
- fieldIdName: "${fieldName}Id",
268
- required: ${notNull},
269
- components: [${components.map(({ otherFieldName, otherEntity, columnName }) => ts_poet.code`
270
- {
271
- otherMetadata: () => ${otherEntity.metaName},
272
- otherFieldName: "${otherFieldName}",
273
- columnName: "${columnName}",
274
- },`)}],
275
- serde: new ${require_symbols.PolymorphicKeySerde}(() => ${dbMetadata.entity.metaName}, "${fieldName}"),
276
- immutable: false,
277
- }
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
+ })}])
278
262
  `;
279
263
  });
280
264
  return fields;
281
265
  }
282
- /** Emits constructor options using codegen's existing column facts. */
283
- function columnOptions(column) {
284
- 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)}]`;
285
298
  }
286
299
  function maybeDefault(f) {
287
300
  return f.hasConfigDefault ? ts_poet.code`default: "config",` : f.columnDefault != null ? ts_poet.code`default: "schema",` : "";
@@ -301,6 +314,7 @@ function isString(config, columnType) {
301
314
  return require_utils.mapSimpleDbTypeToTypescriptType(config, columnType) === "string";
302
315
  }
303
316
  //#endregion
317
+ exports.generateColumnDeclarations = generateColumnDeclarations;
304
318
  exports.generateMetadataFile = generateMetadataFile;
305
319
 
306
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\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: ${Object.fromEntries([\n [\"id\", { fieldName: \"id\" }],\n ...[...meta.primitives, ...meta.enums, ...meta.pgEnums, ...meta.manyToOnes].map((field) => [\n field.columnName,\n { fieldName: field.fieldName },\n ]),\n ...meta.polymorphics.flatMap((field) =>\n field.components.map((component) => [component.columnName, { fieldName: field.fieldName }]),\n ),\n ])},\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\nfunction generateFields(config: Config, dbMetadata: EntityDbMetadata): 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}\"),\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,12 +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);
9
+ const fields = generateFields(config, dbMeta, meta, (name) => columnReference(dbMeta, meta, name));
10
10
  Object.values(fields).forEach((code) => code.asOneline());
11
11
  const maybeBaseType = meta.baseClassName ? `"${meta.baseClassName}"` : void 0;
12
12
  const maybeInheritanceType = meta.inheritanceType ? `inheritanceType: "${meta.inheritanceType}",` : "";
@@ -34,16 +34,7 @@ function generateMetadataFile(config, dbMeta, meta) {
34
34
  tableName: "${meta.tableName}",
35
35
  supportsEmExecute: ${!meta.inheritanceType && meta.supportsEmExecute === true},
36
36
  fields: ${fields},
37
- columns: ${Object.fromEntries([
38
- ["id", { fieldName: "id" }],
39
- ...[
40
- ...meta.primitives,
41
- ...meta.enums,
42
- ...meta.pgEnums,
43
- ...meta.manyToOnes
44
- ].map((field) => [field.columnName, { fieldName: field.fieldName }]),
45
- ...meta.polymorphics.flatMap((field) => field.components.map((component) => [component.columnName, { fieldName: field.fieldName }]))
46
- ])},
37
+ columns: ${columnOwner(dbMeta, meta, "id").entity.metaName}Columns,
47
38
  allFields: {},
48
39
  orderBy: ${q(config.entities[meta.name]?.orderBy)},
49
40
  timestampFields: ${maybeTimestampConfig},
@@ -67,7 +58,8 @@ function getUniqueBy(config, meta) {
67
58
  return true;
68
59
  });
69
60
  }
70
- function generateFields(config, dbMetadata) {
61
+ /** Emits fields that bind the already-declared physical columns. */
62
+ function generateFields(config, dbMeta, dbMetadata, columnRef) {
71
63
  const fields = {};
72
64
  fields["id"] = code`
73
65
  {
@@ -75,20 +67,20 @@ function generateFields(config, dbMetadata) {
75
67
  fieldName: "id",
76
68
  fieldIdName: undefined,
77
69
  required: true,
78
- 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}`))}),
79
71
  immutable: true,
80
72
  }
81
73
  `;
82
74
  dbMetadata.primitives.forEach((p) => {
83
75
  const { fieldName, derived, columnName, columnType, superstruct, zodSchema, customSerde, isArray } = p;
84
- const column = columnOptions(p);
76
+ const column = columnArgs(p, dbMetadata);
85
77
  let serde;
86
- 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})`;
87
- else if (superstruct) serde = code`new ${SuperstructSerde}("${fieldName}", "${columnName}", ${superstruct}, ${column})`;
88
- else if (zodSchema) serde = code`new ${ZodSerde}("${fieldName}", "${columnName}", ${zodSchema}, ${column})`;
89
- 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})`;
90
- else if (columnType === "jsonb") serde = code`new ${JsonSerde}("${fieldName}", "${columnName}", ${column})`;
91
- 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}()`;
92
84
  else {
93
85
  let serdeType;
94
86
  if (columnType === "date") serdeType = config.temporal ? PlainDateSerde : DateSerde;
@@ -96,7 +88,7 @@ function generateFields(config, dbMetadata) {
96
88
  else if (columnType === "timestamp with time zone") serdeType = config.temporal ? ZonedDateTimeSerde : DateSerde;
97
89
  else if (columnType === "time without time zone") serdeType = config.temporal ? PlainTimeSerde : PrimitiveSerde;
98
90
  else serdeType = PrimitiveSerde;
99
- 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}")`;
100
92
  }
101
93
  const extras = columnType === "citext" ? code`citext: true,` : "";
102
94
  fields[fieldName] = code`
@@ -108,7 +100,7 @@ function generateFields(config, dbMetadata) {
108
100
  required: ${!derived && p.notNull},
109
101
  protected: ${p.protected},
110
102
  type: ${typeof p.rawFieldType === "string" ? `"${p.rawFieldType}"` : p.rawFieldType},
111
- serde: ${serde},
103
+ serde: new ${SimpleFieldSerde}("${fieldName}", ${columnRef(columnName, serde, column)}),
112
104
  immutable: false,
113
105
  ${p.lazy ? code`lazy: true,` : ""}
114
106
  ${extras}
@@ -127,7 +119,7 @@ function generateFields(config, dbMetadata) {
127
119
  required: ${notNull},
128
120
  protected: false,
129
121
  type: "string",
130
- serde: new ${PrimitiveSerde}("${fieldName}", "${columnName}", "${dbType}", false, false, ${columnOptions(p)}),
122
+ serde: new ${SimpleFieldSerde}("${fieldName}", ${columnRef(columnName, code`new ${PrimitiveSerde}("${dbType}")`, columnArgs(p, dbMetadata))}),
131
123
  immutable: false,
132
124
  ${maybeDefault(p)}
133
125
  }`;
@@ -136,7 +128,6 @@ function generateFields(config, dbMetadata) {
136
128
  const { fieldName, enumDetailType, notNull, isArray, columnName, columnType, derived } = field;
137
129
  const serdeType = isArray ? EnumArrayFieldSerde : EnumFieldSerde;
138
130
  const columnTypeWithArray = `${columnType}${isArray ? "[]" : ""}`;
139
- const maybeIsNullable = isArray ? `, ${!notNull}` : "";
140
131
  fields[fieldName] = code`
141
132
  {
142
133
  kind: "enum",
@@ -145,7 +136,7 @@ function generateFields(config, dbMetadata) {
145
136
  required: ${notNull},
146
137
  derived: ${!derived ? false : `"${derived}"`},
147
138
  enumDetailType: ${enumDetailType},
148
- 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))}),
149
140
  immutable: false,
150
141
  ${maybeDefault(field)}
151
142
  }
@@ -154,6 +145,7 @@ function generateFields(config, dbMetadata) {
154
145
  dbMetadata.manyToOnes.forEach((m2o) => {
155
146
  const { fieldName, columnName, notNull, otherEntity, otherFieldName, derived, dbType } = m2o;
156
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}`;
157
149
  fields[fieldName] = code`
158
150
  {
159
151
  kind: "m2o",
@@ -161,9 +153,9 @@ function generateFields(config, dbMetadata) {
161
153
  fieldIdName: "${fieldName}Id",
162
154
  derived: ${!derived ? false : `"${derived}"`},
163
155
  required: ${notNull},
164
- otherMetadata: () => ${otherEntity.metaName},
156
+ otherMetadata: ${otherMetadata},
165
157
  otherFieldName: "${otherFieldName}",
166
- 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}`))}),
167
159
  immutable: false,
168
160
  ${maybeDefault(m2o)}
169
161
  }
@@ -259,28 +251,49 @@ function generateFields(config, dbMetadata) {
259
251
  });
260
252
  dbMetadata.polymorphics.forEach((p) => {
261
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}`));
262
255
  fields[fieldName] = code`
263
- {
264
- kind: "poly",
265
- fieldName: "${fieldName}",
266
- fieldIdName: "${fieldName}Id",
267
- required: ${notNull},
268
- components: [${components.map(({ otherFieldName, otherEntity, columnName }) => code`
269
- {
270
- otherMetadata: () => ${otherEntity.metaName},
271
- otherFieldName: "${otherFieldName}",
272
- columnName: "${columnName}",
273
- },`)}],
274
- serde: new ${PolymorphicKeySerde}(() => ${dbMetadata.entity.metaName}, "${fieldName}"),
275
- immutable: false,
276
- }
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
+ })}])
277
261
  `;
278
262
  });
279
263
  return fields;
280
264
  }
281
- /** Emits constructor options using codegen's existing column facts. */
282
- function columnOptions(column) {
283
- 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)}]`;
284
297
  }
285
298
  function maybeDefault(f) {
286
299
  return f.hasConfigDefault ? code`default: "config",` : f.columnDefault != null ? code`default: "schema",` : "";
@@ -300,6 +313,6 @@ function isString(config, columnType) {
300
313
  return mapSimpleDbTypeToTypescriptType(config, columnType) === "string";
301
314
  }
302
315
  //#endregion
303
- export { generateMetadataFile };
316
+ export { generateColumnDeclarations, generateMetadataFile };
304
317
 
305
318
  //# sourceMappingURL=generateMetadataFile.js.map