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

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 (35) hide show
  1. package/build/EntityDbMetadata.cjs +6 -0
  2. package/build/EntityDbMetadata.cjs.map +1 -1
  3. package/build/EntityDbMetadata.d.cts +11 -0
  4. package/build/EntityDbMetadata.d.cts.map +1 -1
  5. package/build/EntityDbMetadata.d.mts +11 -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 +7 -8
  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 +7 -8
  18. package/build/generateEntityCodegenFile.js.map +1 -1
  19. package/build/generateMetadataFile.cjs +48 -61
  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 +49 -63
  26. package/build/generateMetadataFile.js.map +1 -1
  27. package/build/symbols.cjs +10 -0
  28. package/build/symbols.cjs.map +1 -1
  29. package/build/symbols.d.cts +6 -1
  30. package/build/symbols.d.cts.map +1 -1
  31. package/build/symbols.d.mts +6 -1
  32. package/build/symbols.d.mts.map +1 -1
  33. package/build/symbols.js +6 -1
  34. package/build/symbols.js.map +1 -1
  35. package/package.json +2 -2
@@ -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, columnReference);
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: ${meta.primaryKey.columnOwner.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(dbMetadata.primaryKey, 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
- const { fieldName, derived, columnName, columnType, superstruct, zodSchema, customSerde, isArray } = p;
99
- const column = columnOptions(p);
76
+ const { fieldName, derived, columnType, superstruct, zodSchema, customSerde, isArray } = 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(p, serde, column)}),
127
105
  immutable: false,
128
106
  ${p.lazy ? ts_poet.code`lazy: true,` : ""}
129
107
  ${extras}
@@ -132,7 +110,7 @@ function generateFields(config, dbMetadata, physical = false) {
132
110
  }`;
133
111
  });
134
112
  dbMetadata.pgEnums.forEach((p) => {
135
- const { columnName, fieldName, notNull, dbType } = p;
113
+ const { fieldName, notNull, dbType } = p;
136
114
  fields[fieldName] = ts_poet.code`
137
115
  {
138
116
  kind: "primitive",
@@ -142,16 +120,15 @@ 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(p, ts_poet.code`new ${require_symbols.PrimitiveSerde}("${dbType}")`, columnArgs(p, dbMetadata))}),
146
124
  immutable: false,
147
125
  ${maybeDefault(p)}
148
126
  }`;
149
127
  });
150
128
  dbMetadata.enums.forEach((field) => {
151
- const { fieldName, enumDetailType, notNull, isArray, columnName, columnType, derived } = field;
129
+ const { fieldName, enumDetailType, notNull, isArray, 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(field, 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(m2o)}.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(m2o, 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,36 @@ 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, 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 = dbMeta.entitiesByName[component.columnOwner.name];
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)}, ${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, (column, codec, args) => {
276
+ const name = column.columnName;
277
+ if (codec) columns[name] = ts_poet.code`new ${require_symbols.Column}(${require_utils.q(name)}, ${args}, ${codec})`.asOneline();
278
+ return ts_poet.code`${meta.entity.metaName}Columns[${require_utils.q(name)}]`;
279
+ });
280
+ return ts_poet.code`const ${meta.entity.metaName}Columns = ${columns} satisfies ${require_symbols.ColumnDescriptors};`;
281
+ }
282
+ /** Emits a direct reference to the single physical descriptor. */
283
+ function columnReference(column) {
284
+ return ts_poet.code`${column.columnOwner.metaName}Columns[${require_utils.q(column.columnName)}]`;
299
285
  }
300
286
  function maybeDefault(f) {
301
287
  return f.hasConfigDefault ? ts_poet.code`default: "config",` : f.columnDefault != null ? ts_poet.code`default: "schema",` : "";
@@ -315,6 +301,7 @@ function isString(config, columnType) {
315
301
  return require_utils.mapSimpleDbTypeToTypescriptType(config, columnType) === "string";
316
302
  }
317
303
  //#endregion
304
+ exports.generateColumnDeclarations = generateColumnDeclarations;
318
305
  exports.generateMetadataFile = generateMetadataFile;
319
306
 
320
307
  //# 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, columnReference);\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: ${meta.primaryKey.columnOwner.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: (column: Pick<PrimitiveField, \"columnName\" | \"columnOwner\">, 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(dbMetadata.primaryKey, 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, 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(p, 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 { 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(p, 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, 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(field, 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(m2o)}.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(m2o, 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,\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 = dbMeta.entitiesByName[component.columnOwner.name];\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)}, ${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, (column, codec, args) => {\n const name = column.columnName;\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/** Emits a direct reference to the single physical descriptor. */\nfunction columnReference(column: Pick<PrimitiveField, \"columnName\" | \"columnOwner\">): Code {\n return code`${column.columnOwner.metaName}Columns[${q(column.columnName)}]`;\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, columnReference);
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: ${meta.primaryKey.columnOwner.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(dbMetadata.primaryKey, 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
- const { fieldName, derived, columnName, columnType, superstruct, zodSchema, customSerde, isArray } = p;
98
- const column = columnOptions(p);
75
+ const { fieldName, derived, columnType, superstruct, zodSchema, customSerde, isArray } = 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(p, serde, column)}),
126
104
  immutable: false,
127
105
  ${p.lazy ? code`lazy: true,` : ""}
128
106
  ${extras}
@@ -131,7 +109,7 @@ function generateFields(config, dbMetadata, physical = false) {
131
109
  }`;
132
110
  });
133
111
  dbMetadata.pgEnums.forEach((p) => {
134
- const { columnName, fieldName, notNull, dbType } = p;
112
+ const { fieldName, notNull, dbType } = p;
135
113
  fields[fieldName] = code`
136
114
  {
137
115
  kind: "primitive",
@@ -141,16 +119,15 @@ 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(p, code`new ${PrimitiveSerde}("${dbType}")`, columnArgs(p, dbMetadata))}),
145
123
  immutable: false,
146
124
  ${maybeDefault(p)}
147
125
  }`;
148
126
  });
149
127
  dbMetadata.enums.forEach((field) => {
150
- const { fieldName, enumDetailType, notNull, isArray, columnName, columnType, derived } = field;
128
+ const { fieldName, enumDetailType, notNull, isArray, 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(field, 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(m2o)}.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(m2o, code`new ${KeySerde}("${otherTagName}", "${dbType}")`, columnArgs(m2o, dbMetadata, code`() => ${otherEntity.metaName}`))}),
181
159
  immutable: false,
182
160
  ${maybeDefault(m2o)}
183
161
  }
@@ -273,28 +251,36 @@ 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, 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 = dbMeta.entitiesByName[component.columnOwner.name];
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)}, ${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, (column, codec, args) => {
275
+ const name = column.columnName;
276
+ if (codec) columns[name] = code`new ${Column}(${q(name)}, ${args}, ${codec})`.asOneline();
277
+ return code`${meta.entity.metaName}Columns[${q(name)}]`;
278
+ });
279
+ return code`const ${meta.entity.metaName}Columns = ${columns} satisfies ${ColumnDescriptors};`;
280
+ }
281
+ /** Emits a direct reference to the single physical descriptor. */
282
+ function columnReference(column) {
283
+ return code`${column.columnOwner.metaName}Columns[${q(column.columnName)}]`;
298
284
  }
299
285
  function maybeDefault(f) {
300
286
  return f.hasConfigDefault ? code`default: "config",` : f.columnDefault != null ? code`default: "schema",` : "";
@@ -314,6 +300,6 @@ function isString(config, columnType) {
314
300
  return mapSimpleDbTypeToTypescriptType(config, columnType) === "string";
315
301
  }
316
302
  //#endregion
317
- export { generateMetadataFile };
303
+ export { generateColumnDeclarations, generateMetadataFile };
318
304
 
319
305
  //# sourceMappingURL=generateMetadataFile.js.map