joist-codegen 2.4.0-next.2 → 2.4.0-next.21
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/build/EntityDbMetadata.cjs +5 -3
- package/build/EntityDbMetadata.cjs.map +1 -1
- package/build/EntityDbMetadata.d.cts +2 -0
- package/build/EntityDbMetadata.d.cts.map +1 -1
- package/build/EntityDbMetadata.d.mts +2 -0
- package/build/EntityDbMetadata.d.mts.map +1 -1
- package/build/EntityDbMetadata.js +5 -3
- package/build/EntityDbMetadata.js.map +1 -1
- package/build/config.cjs +1 -1
- package/build/config.cjs.map +1 -1
- package/build/config.js +1 -1
- package/build/config.js.map +1 -1
- package/build/generateEntityCodegenFile.cjs +5 -3
- package/build/generateEntityCodegenFile.cjs.map +1 -1
- package/build/generateEntityCodegenFile.d.cts.map +1 -1
- package/build/generateEntityCodegenFile.d.mts.map +1 -1
- package/build/generateEntityCodegenFile.js +5 -3
- package/build/generateEntityCodegenFile.js.map +1 -1
- package/build/generateMetadataFile.cjs +2 -1
- package/build/generateMetadataFile.cjs.map +1 -1
- package/build/generateMetadataFile.d.cts.map +1 -1
- package/build/generateMetadataFile.d.mts.map +1 -1
- package/build/generateMetadataFile.js +2 -1
- package/build/generateMetadataFile.js.map +1 -1
- package/build/scanEntityFiles.cjs +6 -1
- package/build/scanEntityFiles.cjs.map +1 -1
- package/build/scanEntityFiles.d.cts +1 -1
- package/build/scanEntityFiles.d.cts.map +1 -1
- package/build/scanEntityFiles.d.mts +1 -1
- package/build/scanEntityFiles.d.mts.map +1 -1
- package/build/scanEntityFiles.js +6 -1
- package/build/scanEntityFiles.js.map +1 -1
- package/package.json +2 -2
|
@@ -111,7 +111,7 @@ function generateFields(config, dbMeta, dbMetadata, columnRef) {
|
|
|
111
111
|
}`;
|
|
112
112
|
});
|
|
113
113
|
dbMetadata.enums.forEach((field) => {
|
|
114
|
-
const { fieldName, enumDetailType, notNull, isArray, columnType, derived } = field;
|
|
114
|
+
const { fieldName, enumDetailType, enumType, notNull, isArray, columnType, derived } = field;
|
|
115
115
|
const serdeType = isArray ? EnumArrayFieldSerde : EnumFieldSerde;
|
|
116
116
|
const columnTypeWithArray = `${columnType}${isArray ? "[]" : ""}`;
|
|
117
117
|
fields[fieldName] = code`
|
|
@@ -122,6 +122,7 @@ function generateFields(config, dbMeta, dbMetadata, columnRef) {
|
|
|
122
122
|
required: ${notNull},
|
|
123
123
|
derived: ${!derived ? false : `"${derived}"`},
|
|
124
124
|
enumDetailType: ${enumDetailType},
|
|
125
|
+
enumType: ${enumType},
|
|
125
126
|
serde: new ${SimpleFieldSerde}("${fieldName}", ${columnRef(field, code`new ${serdeType}("${columnTypeWithArray}", ${enumDetailType})`, columnArgs(field, dbMetadata))}),
|
|
126
127
|
immutable: false,
|
|
127
128
|
${maybeDefault(field)}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateMetadataFile.js","names":[],"sources":["../src/generateMetadataFile.ts"],"sourcesContent":["import { camelCase } from \"change-case\";\nimport { 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 } = p;\n const column = columnArgs(p, dbMetadata);\n const serde = primitiveColumnCodec(config, p);\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 by their SQL API names 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 columnName = column.columnName;\n const apiName = camelCase(columnName);\n if (codec) columns[apiName] = code`new ${Column}(${q(columnName)}, ${args}, ${codec})`.asOneline();\n return code`${meta.entity.metaName}Columns[${q(apiName)}]`;\n });\n for (const column of (meta.physicalMetadata ?? meta).ignoredColumns) {\n const apiName = camelCase(column.columnName);\n columns[apiName] =\n code`new ${Column}(${q(column.columnName)}, ${columnArgs(column, meta)}, ${primitiveColumnCodec(config, column)})`.asOneline();\n }\n return code`const ${meta.entity.metaName}Columns = ${columns} satisfies ${ColumnDescriptors};`;\n}\n\n/** Emits a direct reference to a descriptor by its SQL API name. */\nfunction columnReference(column: Pick<PrimitiveField, \"columnName\" | \"columnOwner\">): Code {\n return code`${column.columnOwner.metaName}Columns[${q(camelCase(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\n/** Uses domain codecs for modeled fields and the same native conversions for unmodeled columns. */\nfunction primitiveColumnCodec(config: Config, column: PrimitiveField): Code {\n const { columnType, customSerde, superstruct, zodSchema, isArray } = column;\n if (customSerde) {\n return isArray\n ? code`new ${CustomSerdeAdapter}( \"${columnType}[]\", ${customSerde}, true)`\n : code`new ${CustomSerdeAdapter}( \"${columnType}\", ${customSerde})`;\n }\n if (superstruct) return code`new ${SuperstructSerde}( ${superstruct})`;\n if (zodSchema) return code`new ${ZodSerde}( ${zodSchema})`;\n if (columnType === \"numeric\" || columnType === \"decimal\") {\n return isArray ? code`new ${DecimalToNumberSerde}(true)` : code`new ${DecimalToNumberSerde}()`;\n }\n if (columnType === \"jsonb\") return code`new ${JsonSerde}()`;\n if (column.rawFieldType === \"bigint\") {\n return isArray ? code`new ${BigIntSerde}(true)` : code`new ${BigIntSerde}()`;\n }\n\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 return isArray ? code`new ${serdeType}( \"${columnType}[]\", true)` : code`new ${serdeType}( \"${columnType}\")`;\n}\n"],"mappings":";;;;;;;AAoCA,SAAgB,qBAAqB,QAAgB,QAAoB,MAA8B;CACrG,MAAM,EAAE,QAAQ,WAAW,WAAW,cAAc;CAEpD,MAAM,SAAS,eAAe,QAAQ,QAAQ,MAAM,eAAe;CAEnE,OAAO,OAAO,MAAM,CAAC,CAAC,SAAS,SAAS,KAAK,UAAU,CAAC;CAExD,MAAM,gBAAgB,KAAK,gBAAgB,IAAI,KAAK,cAAc,KAAK,KAAA;CAEvE,MAAM,uBAAuB,KAAK,kBAAkB,qBAAqB,KAAK,gBAAgB,MAAM;CACpG,MAAM,iBAAiB,KAAK,wBAAwB,2BAA2B,KAAK,sBAAsB,MAAM;CAChH,MAAM,gBAAgB,KAAK,wBAAwB,0BAA0B,KAAK,sBAAsB,KAAK;CAC7G,MAAM,mBAAmB,KAAK,WAAW,gBAAgB,KAAK,SAAS,KAAK;CAG5E,MAAM,uBAAuB,KAAK,gBAC9B,IAAI,cACJ,IAAI;;mBAES,EAAE,WAAW,SAAS,EAAE;mBACxB,EAAE,WAAW,SAAS,EAAE;mBACxB,EAAE,WAAW,SAAS,EAAE;;;CAGzC,MAAM,sBAAsB,KAAK,uBAAuB,IAAI,uBAAuB,KAAK,mBAAmB,KAAK;CAChH,MAAM,WAAW,YAAY,QAAQ,IAAI;CACzC,MAAM,gBAAgB,SAAS,SAAS,IAAI,IAAI,aAAa,KAAK,UAAU,QAAQ,EAAE,KAAK,IAAI;CAE/F,OAAO,IAAI;mBACM,OAAO,SAAS,IAAI,eAAe,GAAG,OAAO,KAAK;cACvD,OAAO,oBAAoB;eAC1B,OAAO,KAAK;kBACT,cAAc,IAAI,qBAAqB,GAAG,eAAe,GAAG,cAAc,GAAG,iBAAiB;iBAC/F,OAAO,UAAU,gBAAgB;mBAC/B,KAAK,WAAW,WAAW;kBAC5B,KAAK,QAAQ;oBACX,KAAK,UAAU;2BACR,CAAC,KAAK,mBAAmB,KAAK,sBAAsB,KAAK;gBACpE,OAAO;iBACN,KAAK,WAAW,YAAY,SAAS;;iBAErC,EAAE,OAAO,SAAS,KAAK,KAAK,EAAE,OAAO,EAAE;yBAC/B,qBAAqB;gBAC9B,OAAO,YAAY;iBAClB,IAAI,MAAM,OAAO,KAAK,eAAe,EAAE;;sBAElC,oBAAoB,GAAG,cAAc;;;OAGpD,OAAO,oBAAoB,sBAAsB,OAAO,SAAS;;AAExE;;AAGA,SAAS,YAAY,QAAgB,MAAoC;CACvE,MAAM,WAAW,OAAO,SAAS,KAAK,KAAK,EAAE,YAAY,CAAC;CAC1D,MAAM,uBAAO,IAAI,IAAY;CAC7B,OAAO,CAAC,GAAG,UAAU,GAAI,KAAK,qBAAqB,CAAC,CAAE,CAAC,CAAC,QAAQ,WAAW;EACzE,MAAM,MAAM,OAAO,KAAK,IAAQ;EAChC,IAAI,KAAK,IAAI,GAAG,GAAG,OAAO;EAC1B,KAAK,IAAI,GAAG;EACZ,OAAO;CACT,CAAC;AACH;;AAGA,SAAS,eACP,QACA,QACA,YACA,WACsB;CACtB,MAAM,SAA+B,CAAC;CAEtC,OAAO,QAAQ,IAAI;;;;;;mBAMF,iBAAiB,SAAS,UAAU,WAAW,YAAY,IAAI,OAAO,SAAS,IAAI,WAAW,QAAQ,MAAM,WAAW,WAAW,WAAW,KAAK,WAAW,WAAW,YAAY,YAAY,IAAI,SAAS,WAAW,OAAO,UAAU,CAAC,EAAE;;;;CAK7P,WAAW,WAAW,SAAS,MAAM;EACnC,MAAM,EAAE,WAAW,SAAS,eAAe;EAC3C,MAAM,SAAS,WAAW,GAAG,UAAU;EACvC,MAAM,QAAQ,qBAAqB,QAAQ,CAAC;EAC5C,MAAM,SAAS,eAAe,WAAW,IAAI,kBAAkB;EAC/D,OAAO,aAAa,IAAI;;;sBAGN,UAAU;;mBAEb,CAAC,UAAU,QAAQ,IAAI,QAAQ,GAAG;oBACjC,CAAC,WAAW,EAAE,QAAQ;qBACrB,EAAE,UAAU;gBACjB,OAAO,EAAE,iBAAiB,WAAW,IAAI,EAAE,aAAa,KAAK,EAAE,aAAa;qBACvE,iBAAiB,IAAI,UAAU,KAAK,UAAU,GAAG,OAAO,MAAM,EAAE;;UAE3E,EAAE,OAAO,IAAI,gBAAgB,GAAG;UAChC,OAAO;UACP,aAAa,CAAC,EAAE;UAChB,cAAc,QAAQ,CAAC,EAAE;;CAEjC,CAAC;CAGD,WAAW,QAAQ,SAAS,MAAM;EAChC,MAAM,EAAE,WAAW,SAAS,WAAW;EACvC,OAAO,aAAa,IAAI;;;sBAGN,UAAU;;;oBAGZ,QAAQ;;;qBAGP,iBAAiB,IAAI,UAAU,KAAK,UAAU,GAAG,IAAI,OAAO,eAAe,IAAI,OAAO,KAAK,WAAW,GAAG,UAAU,CAAC,EAAE;;UAEjI,aAAa,CAAC,EAAE;;CAExB,CAAC;CAED,WAAW,MAAM,SAAS,UAAU;EAClC,MAAM,EAAE,WAAW,gBAAgB,SAAS,SAAS,YAAY,YAAY;EAC7E,MAAM,YAAY,UAAU,sBAAsB;EAClD,MAAM,sBAAsB,GAAG,aAAa,UAAU,OAAO;EAC7D,OAAO,aAAa,IAAI;;;sBAGN,UAAU;;oBAEZ,QAAQ;mBACT,CAAC,UAAU,QAAQ,IAAI,QAAQ,GAAG;0BAC3B,eAAe;qBACpB,iBAAiB,IAAI,UAAU,KAAK,UAAU,OAAO,IAAI,OAAO,UAAU,IAAI,oBAAoB,KAAK,eAAe,IAAI,WAAW,OAAO,UAAU,CAAC,EAAE;;UAEpK,aAAa,KAAK,EAAE;;;CAG5B,CAAC;CAED,WAAW,WAAW,SAAS,QAAQ;EACrC,MAAM,EAAE,WAAW,YAAY,SAAS,aAAa,gBAAgB,SAAS,WAAW;EACzF,MAAM,eAAe,OAAO,SAAS,YAAY,KAAK,CAAC;EAIvD,MAAM,iBAHY,WAAW,oBAAoB,WAAA,CAAY,WAAW,MACrE,UAAU,MAAM,eAAe,UAGzB,CAAC,EAAE,YAAY,SAAS,YAAY,OACvC,IAAI,GAAG,UAAU,GAAG,EAAE,gBACtB,IAAI,SAAS,YAAY;EAC/B,OAAO,aAAa,IAAI;;;sBAGN,UAAU;wBACR,UAAU;mBACf,CAAC,UAAU,QAAQ,IAAI,QAAQ,GAAG;oBACjC,QAAQ;yBACH,cAAc;2BACZ,eAAe;qBACrB,iBAAiB,IAAI,UAAU,KAAK,UAAU,KAAK,IAAI,OAAO,SAAS,IAAI,aAAa,MAAM,OAAO,KAAK,WAAW,KAAK,YAAY,IAAI,SAAS,YAAY,UAAU,CAAC,EAAE;;UAEvL,aAAa,GAAG,EAAE;;;CAG1B,CAAC;CAED,WAAW,WAAW,SAAS,QAAQ;EACrC,MAAM,EAAE,WAAW,cAAc,aAAa,gBAAgB,oBAAoB;EAClF,OAAO,aAAa,IAAI;;;sBAGN,UAAU;wBACR,aAAa;;+BAEN,YAAY,SAAS;2BACzB,eAAe;4BACd,gBAAgB;;;UAGlC,aAAa,GAAG,EAAE;UAClB,iBAAiB,GAAG,EAAE;;;CAG9B,CAAC;CAED,WAAW,gBAAgB,SAAS,QAAQ;EAC1C,MAAM,EAAE,WAAW,cAAc,aAAa,gBAAgB,oBAAoB;EAClF,OAAO,aAAa,IAAI;;;sBAGN,UAAU;wBACR,aAAa;;+BAEN,YAAY,SAAS;2BACzB,eAAe;4BACd,gBAAgB;;;;;CAK1C,CAAC;CAED,WAAW,YAAY,SAAS,QAAQ;EACtC,MAAM,EAAE,WAAW,cAAc,aAAa,gBAAgB,YAAY;EAC1E,OAAO,aAAa,IAAI;;;sBAGN,UAAU;wBACR,aAAa;;mBAElB,YAAY,UAAU,YAAY,YAAY,cAAc,gBAAgB,QAAQ;+BACxE,YAAY,SAAS;2BACzB,eAAe;;;0BAGhB,IAAI,cAAc;yBACnB,IAAI,WAAW,MAAM,IAAI,gBAAgB;0BACxC,IAAI,eAAe;UACnC,iBAAiB,GAAG,EAAE;;;CAG9B,CAAC;CAED,WAAW,gBAAgB,SAAS,QAAQ;EAC1C,MAAM,EAAE,WAAW,mBAAmB;EACtC,OAAO,aAAa,IAAI;;;sBAGN,UAAU;;;;0BAIN,eAAe;;;0BAGf,IAAI,cAAc;yBACnB,IAAI,WAAW,MAAM,IAAI,gBAAgB;0BACxC,IAAI,eAAe;;;CAG3C,CAAC;CAED,WAAW,UAAU,SAAS,QAAQ;EACpC,MAAM,EAAE,WAAW,aAAa,gBAAgB,oBAAoB;EACpE,OAAO,aAAa,IAAI;;;sBAGN,UAAU;wBACR,UAAU;;+BAEH,YAAY,SAAS;2BACzB,eAAe;4BACd,gBAAgB;;;;;CAK1C,CAAC;CAED,WAAW,aAAa,SAAS,MAAM;EACrC,MAAM,EAAE,WAAW,SAAS,eAAe;EAC3C,WAAW,SAAS,cAClB,UACE,WACA,IAAI,OAAO,SAAS,IAAI,OAAO,SAAS,UAAU,YAAY,KAAK,CAAC,IAAI,MAAM,OAAO,eAAe,UAAU,YAAY,KAAK,CAAC,WAAW,WAAW,KACtJ,IAAI,2CAA2C,UAAU,YAAY,UACvE,CACF;EACA,OAAO,aAAa,IAAI;QACpB,iBAAiB,IAAI,UAAU,KAAK,QAAQ,KAAK,WAAW,KAAK,cAAc;GAC/E,MAAM,QAAQ,OAAO,eAAe,UAAU,YAAY;GAI1D,MAAM,UAHY,MAAM,oBAAoB,MAAA,CAAO,aAChD,SAAS,UAAU,MAAM,UAAU,CAAC,CACpC,MAAM,MAAM,EAAE,eAAe,UAAU,UAEjC,CAAC,CAAC,YAAY,SAAS,UAAU,YAAY,OAChD,KACA,IAAI,WAAW,UAAU,YAAY;GAC3C,OAAO,IAAI,OAAO,cAAc,GAAG,UAAU,SAAS,EAAE,IAAI,EAAE,UAAU,cAAc,IAAI,OAAO;EACnG,CAAC,EAAE;;CAEP,CAAC;CAED,OAAO;AACT;;AAGA,SAAS,WACP,QACA,MACA,YACM;CACN,MAAM,iBAAiB,WAAW,KAAK,aAAa,WAAW,KAAK;CACpE,OAAO,IAAI,GAAG,CAAC,OAAO,cAAc,IAAI,OAAO,iBAAiB,QAAQ,CAAC,OAAO,gBAAgB,IAAI,OAAO,gBAAgB,IAAI,eAAe,UAAU,cAAc;AACxK;;AAGA,SAAgB,2BAA2B,QAAgB,QAAoB,MAA8B;CAC3G,IAAI,KAAK,oBAAoB,SAAS,KAAK,eAAe,OAAO,IAAI;CACrE,MAAM,UAAgC,CAAC;CACvC,eAAe,QAAQ,QAAQ,KAAK,oBAAoB,OAAO,QAAQ,OAAO,SAAS;EACrF,MAAM,aAAa,OAAO;EAC1B,MAAM,UAAU,UAAU,UAAU;EACpC,IAAI,OAAO,QAAQ,WAAW,IAAI,OAAO,OAAO,GAAG,EAAE,UAAU,EAAE,IAAI,KAAK,IAAI,MAAM,GAAG,UAAU;EACjG,OAAO,IAAI,GAAG,KAAK,OAAO,SAAS,UAAU,EAAE,OAAO,EAAE;CAC1D,CAAC;CACD,KAAK,MAAM,WAAW,KAAK,oBAAoB,KAAA,CAAM,gBAAgB;EACnE,MAAM,UAAU,UAAU,OAAO,UAAU;EAC3C,QAAQ,WACN,IAAI,OAAO,OAAO,GAAG,EAAE,OAAO,UAAU,EAAE,IAAI,WAAW,QAAQ,IAAI,EAAE,IAAI,qBAAqB,QAAQ,MAAM,EAAE,GAAG,UAAU;CACjI;CACA,OAAO,IAAI,SAAS,KAAK,OAAO,SAAS,YAAY,QAAQ,aAAa,kBAAkB;AAC9F;;AAGA,SAAS,gBAAgB,QAAkE;CACzF,OAAO,IAAI,GAAG,OAAO,YAAY,SAAS,UAAU,EAAE,UAAU,OAAO,UAAU,CAAC,EAAE;AACtF;AAEA,SAAS,aAAa,GAA+F;CACnH,OAAO,EAAE,mBAAmB,IAAI,uBAAuB,EAAE,iBAAiB,OAAO,IAAI,uBAAuB;AAC9G;AAEA,SAAS,aAAa,GAA8B;CAClD,OAAO,EAAE,UAAU,IAAI,sBAAsB,EAAE,QAAQ,MAAM,iBAAiB,EAAE,QAAQ,UAAU,QAAQ;AAC5G;;AAGA,SAAS,iBAAiB,GAAkE;CAC1F,OAAO,EAAE,cAAc,IAAI,iBAAiB,EAAE,YAAY,MAAM;AAClE;;AAGA,SAAS,cACP,QACA,GACW;CAEX,OAAO,SAAS,QAAQ,EAAE,UAAU,MAAM,EAAE,kBAAkB,QAAQ,EAAE,WAAW,EAAE,eACjF,IAAI,qBACJ;AACN;AAEA,SAAS,SAAS,QAAgB,YAAyC;CACzE,OAAO,gCAAgC,QAAQ,UAAU,MAAM;AACjE;;AAGA,SAAS,qBAAqB,QAAgB,QAA8B;CAC1E,MAAM,EAAE,YAAY,aAAa,aAAa,WAAW,YAAY;CACrE,IAAI,aACF,OAAO,UACH,IAAI,OAAO,mBAAmB,KAAK,WAAW,OAAO,YAAY,WACjE,IAAI,OAAO,mBAAmB,KAAK,WAAW,KAAK,YAAY;CAErE,IAAI,aAAa,OAAO,IAAI,OAAO,iBAAiB,IAAI,YAAY;CACpE,IAAI,WAAW,OAAO,IAAI,OAAO,SAAS,IAAI,UAAU;CACxD,IAAI,eAAe,aAAa,eAAe,WAC7C,OAAO,UAAU,IAAI,OAAO,qBAAqB,UAAU,IAAI,OAAO,qBAAqB;CAE7F,IAAI,eAAe,SAAS,OAAO,IAAI,OAAO,UAAU;CACxD,IAAI,OAAO,iBAAiB,UAC1B,OAAO,UAAU,IAAI,OAAO,YAAY,UAAU,IAAI,OAAO,YAAY;CAG3E,IAAI;CACJ,IAAI,eAAe,QACjB,YAAY,OAAO,WAAW,iBAAiB;MAC1C,IAAI,eAAe,+BACxB,YAAY,OAAO,WAAW,qBAAqB;MAC9C,IAAI,eAAe,4BACxB,YAAY,OAAO,WAAW,qBAAqB;MAC9C,IAAI,eAAe,0BACxB,YAAY,OAAO,WAAW,iBAAiB;MAE/C,YAAY;CAEd,OAAO,UAAU,IAAI,OAAO,UAAU,KAAK,WAAW,cAAc,IAAI,OAAO,UAAU,KAAK,WAAW;AAC3G"}
|
|
1
|
+
{"version":3,"file":"generateMetadataFile.js","names":[],"sources":["../src/generateMetadataFile.ts"],"sourcesContent":["import { camelCase } from \"change-case\";\nimport { 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 } = p;\n const column = columnArgs(p, dbMetadata);\n const serde = primitiveColumnCodec(config, p);\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, enumType, 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 enumType: ${enumType},\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 by their SQL API names 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 columnName = column.columnName;\n const apiName = camelCase(columnName);\n if (codec) columns[apiName] = code`new ${Column}(${q(columnName)}, ${args}, ${codec})`.asOneline();\n return code`${meta.entity.metaName}Columns[${q(apiName)}]`;\n });\n for (const column of (meta.physicalMetadata ?? meta).ignoredColumns) {\n const apiName = camelCase(column.columnName);\n columns[apiName] =\n code`new ${Column}(${q(column.columnName)}, ${columnArgs(column, meta)}, ${primitiveColumnCodec(config, column)})`.asOneline();\n }\n return code`const ${meta.entity.metaName}Columns = ${columns} satisfies ${ColumnDescriptors};`;\n}\n\n/** Emits a direct reference to a descriptor by its SQL API name. */\nfunction columnReference(column: Pick<PrimitiveField, \"columnName\" | \"columnOwner\">): Code {\n return code`${column.columnOwner.metaName}Columns[${q(camelCase(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\n/** Uses domain codecs for modeled fields and the same native conversions for unmodeled columns. */\nfunction primitiveColumnCodec(config: Config, column: PrimitiveField): Code {\n const { columnType, customSerde, superstruct, zodSchema, isArray } = column;\n if (customSerde) {\n return isArray\n ? code`new ${CustomSerdeAdapter}( \"${columnType}[]\", ${customSerde}, true)`\n : code`new ${CustomSerdeAdapter}( \"${columnType}\", ${customSerde})`;\n }\n if (superstruct) return code`new ${SuperstructSerde}( ${superstruct})`;\n if (zodSchema) return code`new ${ZodSerde}( ${zodSchema})`;\n if (columnType === \"numeric\" || columnType === \"decimal\") {\n return isArray ? code`new ${DecimalToNumberSerde}(true)` : code`new ${DecimalToNumberSerde}()`;\n }\n if (columnType === \"jsonb\") return code`new ${JsonSerde}()`;\n if (column.rawFieldType === \"bigint\") {\n return isArray ? code`new ${BigIntSerde}(true)` : code`new ${BigIntSerde}()`;\n }\n\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 return isArray ? code`new ${serdeType}( \"${columnType}[]\", true)` : code`new ${serdeType}( \"${columnType}\")`;\n}\n"],"mappings":"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"}
|
|
@@ -5,7 +5,8 @@ let path = require("path");
|
|
|
5
5
|
let fs_promises = require("fs/promises");
|
|
6
6
|
//#region src/scanEntityFiles.ts
|
|
7
7
|
const regex = /config\.setDefault\([\s\n]*["'](\w+)["']/g;
|
|
8
|
-
|
|
8
|
+
const transitionsRegex = /config\.(?:transitions|guardTransition|onTransition)\(\s*(?:(?:["'][^"']*["']|\w+)\s*,\s*(?=["']))?["'](\w+)["']/g;
|
|
9
|
+
/** Scans the entity files themselves for usage hints (like `setDefault` or `transitions` calls) to drive our codegen output. */
|
|
9
10
|
async function scanEntityFiles(config, dbMeta) {
|
|
10
11
|
await Promise.all(dbMeta.entities.map(async (entity) => {
|
|
11
12
|
try {
|
|
@@ -15,6 +16,10 @@ async function scanEntityFiles(config, dbMeta) {
|
|
|
15
16
|
const field = defaultableFields.find((f) => f.fieldName === match[1]);
|
|
16
17
|
if (field) field.hasConfigDefault = true;
|
|
17
18
|
}
|
|
19
|
+
for (const match of tsCode.matchAll(transitionsRegex)) {
|
|
20
|
+
const field = defaultableFields.find((f) => f.fieldName === match[1]);
|
|
21
|
+
if (field?.kind === "enum") field.hasTransitions = true;
|
|
22
|
+
}
|
|
18
23
|
} catch (e) {}
|
|
19
24
|
}));
|
|
20
25
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanEntityFiles.cjs","names":["readFile","join"],"sources":["../src/scanEntityFiles.ts"],"sourcesContent":["import { readFile } from \"fs/promises\";\nimport { join } from \"path\";\n\nimport { type Config } from \"./config.ts\";\nimport {\n type DbMetadata,\n type EntityDbMetadata,\n type EnumField,\n type ManyToOneField,\n type PgEnumField,\n type PolymorphicField,\n type PrimitiveField,\n} from \"./EntityDbMetadata.ts\";\n\n// Erg, we need a regex in case the fieldName arg is wrapped onto a new line... :-/\nconst regex = /config\\.setDefault\\([\\s\\n]*[\"'](\\w+)[\"']/g;\n\n/** Scans the entity files themselves for usage hints (like `setDefault` calls) to drive our codegen output. */\nexport async function scanEntityFiles(config: Config, dbMeta: DbMetadata): Promise<void> {\n await Promise.all(\n dbMeta.entities.map(async (entity) => {\n try {\n // load the entity.ts file (as a promise with fs/promises)\n const tsCode = (await readFile(join(config.entitiesDirectory, `${entity.name}.ts`))).toString();\n const defaultableFields = recursiveDefaultableFields(dbMeta, entity);\n for (const match of tsCode.matchAll(regex)) {\n const field = defaultableFields.find((f) => f.fieldName === match[1]);\n if (field) {\n field.hasConfigDefault = true;\n }\n }\n } catch (e) {\n // Ignore file not existing yet\n }\n }),\n );\n}\n\n/**\n * Traverse the entity inheritance tree to find all fields that can have defaults set on them.\n *\n * I.e. a column defined in a base CTI table like `publishers.foo_bar` having a `config.setDefault` in\n * `SmallPublisher` and/or `LargePublisher`, or the same scenario for an STI table like `tasks.foo_bar`\n * with `TaskNew` and/or `TaskOld`.\n *\n * NOTE: I suspect here could be some edge cases here that will need to be ironed out, but should work\n * for simple inheritance structures. In particular, there may be unexpected side effects if a base\n * class field has a default set in one subtype, but not another.\n */\nfunction recursiveDefaultableFields(\n dbMeta: DbMetadata,\n entity: EntityDbMetadata | undefined,\n): Array<PrimitiveField | EnumField | PgEnumField | ManyToOneField | PolymorphicField> {\n if (!entity) return [];\n return [\n ...entity.primitives,\n ...entity.enums,\n ...entity.pgEnums,\n ...entity.manyToOnes,\n ...entity.polymorphics,\n ...(entity.baseClassName ? recursiveDefaultableFields(dbMeta, dbMeta.entitiesByName[entity.baseClassName]) : []),\n ];\n}\n"],"mappings":";;;;;;AAeA,MAAM,QAAQ;;
|
|
1
|
+
{"version":3,"file":"scanEntityFiles.cjs","names":["readFile","join"],"sources":["../src/scanEntityFiles.ts"],"sourcesContent":["import { readFile } from \"fs/promises\";\nimport { join } from \"path\";\n\nimport { type Config } from \"./config.ts\";\nimport {\n type DbMetadata,\n type EntityDbMetadata,\n type EnumField,\n type ManyToOneField,\n type PgEnumField,\n type PolymorphicField,\n type PrimitiveField,\n} from \"./EntityDbMetadata.ts\";\n\n// Erg, we need a regex in case the fieldName arg is wrapped onto a new line... :-/\nconst regex = /config\\.setDefault\\([\\s\\n]*[\"'](\\w+)[\"']/g;\n// Any transition method marks the field; onTransition may have a name before the field argument.\nconst transitionsRegex =\n /config\\.(?:transitions|guardTransition|onTransition)\\(\\s*(?:(?:[\"'][^\"']*[\"']|\\w+)\\s*,\\s*(?=[\"']))?[\"'](\\w+)[\"']/g;\n\n/** Scans the entity files themselves for usage hints (like `setDefault` or `transitions` calls) to drive our codegen output. */\nexport async function scanEntityFiles(config: Config, dbMeta: DbMetadata): Promise<void> {\n await Promise.all(\n dbMeta.entities.map(async (entity) => {\n try {\n // load the entity.ts file (as a promise with fs/promises)\n const tsCode = (await readFile(join(config.entitiesDirectory, `${entity.name}.ts`))).toString();\n const defaultableFields = recursiveDefaultableFields(dbMeta, entity);\n for (const match of tsCode.matchAll(regex)) {\n const field = defaultableFields.find((f) => f.fieldName === match[1]);\n if (field) {\n field.hasConfigDefault = true;\n }\n }\n // Transition fields get `withStatus` factory opts and accessor names, i.e. `Draft`\n for (const match of tsCode.matchAll(transitionsRegex)) {\n const field = defaultableFields.find((f) => f.fieldName === match[1]);\n if (field?.kind === \"enum\") {\n field.hasTransitions = true;\n }\n }\n } catch (e) {\n // Ignore file not existing yet\n }\n }),\n );\n}\n\n/**\n * Traverse the entity inheritance tree to find all fields that can have defaults set on them.\n *\n * I.e. a column defined in a base CTI table like `publishers.foo_bar` having a `config.setDefault` in\n * `SmallPublisher` and/or `LargePublisher`, or the same scenario for an STI table like `tasks.foo_bar`\n * with `TaskNew` and/or `TaskOld`.\n *\n * NOTE: I suspect here could be some edge cases here that will need to be ironed out, but should work\n * for simple inheritance structures. In particular, there may be unexpected side effects if a base\n * class field has a default set in one subtype, but not another.\n */\nfunction recursiveDefaultableFields(\n dbMeta: DbMetadata,\n entity: EntityDbMetadata | undefined,\n): Array<PrimitiveField | EnumField | PgEnumField | ManyToOneField | PolymorphicField> {\n if (!entity) return [];\n return [\n ...entity.primitives,\n ...entity.enums,\n ...entity.pgEnums,\n ...entity.manyToOnes,\n ...entity.polymorphics,\n ...(entity.baseClassName ? recursiveDefaultableFields(dbMeta, dbMeta.entitiesByName[entity.baseClassName]) : []),\n ];\n}\n"],"mappings":";;;;;;AAeA,MAAM,QAAQ;AAEd,MAAM,mBACJ;;AAGF,eAAsB,gBAAgB,QAAgB,QAAmC;CACvF,MAAM,QAAQ,IACZ,OAAO,SAAS,IAAI,OAAO,WAAW;EACpC,IAAI;GAEF,MAAM,UAAU,OAAA,GAAMA,YAAAA,SAAAA,EAAAA,GAASC,KAAAA,KAAAA,CAAK,OAAO,mBAAmB,GAAG,OAAO,KAAK,IAAI,CAAC,EAAA,CAAG,SAAS;GAC9F,MAAM,oBAAoB,2BAA2B,QAAQ,MAAM;GACnE,KAAK,MAAM,SAAS,OAAO,SAAS,KAAK,GAAG;IAC1C,MAAM,QAAQ,kBAAkB,MAAM,MAAM,EAAE,cAAc,MAAM,EAAE;IACpE,IAAI,OACF,MAAM,mBAAmB;GAE7B;GAEA,KAAK,MAAM,SAAS,OAAO,SAAS,gBAAgB,GAAG;IACrD,MAAM,QAAQ,kBAAkB,MAAM,MAAM,EAAE,cAAc,MAAM,EAAE;IACpE,IAAI,OAAO,SAAS,QAClB,MAAM,iBAAiB;GAE3B;EACF,SAAS,GAAG,CAEZ;CACF,CAAC,CACH;AACF;;;;;;;;;;;;AAaA,SAAS,2BACP,QACA,QACqF;CACrF,IAAI,CAAC,QAAQ,OAAO,CAAC;CACrB,OAAO;EACL,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAI,OAAO,gBAAgB,2BAA2B,QAAQ,OAAO,eAAe,OAAO,cAAc,IAAI,CAAC;CAChH;AACF"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Config } from "./config.cjs";
|
|
2
2
|
import { DbMetadata } from "./EntityDbMetadata.cjs";
|
|
3
3
|
//#region src/scanEntityFiles.d.ts
|
|
4
|
-
/** Scans the entity files themselves for usage hints (like `setDefault` calls) to drive our codegen output. */
|
|
4
|
+
/** Scans the entity files themselves for usage hints (like `setDefault` or `transitions` calls) to drive our codegen output. */
|
|
5
5
|
declare function scanEntityFiles(config: Config, dbMeta: DbMetadata): Promise<void>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { scanEntityFiles };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanEntityFiles.d.cts","names":[],"sources":["../src/scanEntityFiles.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"scanEntityFiles.d.cts","names":[],"sources":["../src/scanEntityFiles.ts"],"mappings":";;;;iBAqBsB,gBAAgB,QAAQ,QAAQ,QAAQ,aAAa"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Config } from "./config.mjs";
|
|
2
2
|
import { DbMetadata } from "./EntityDbMetadata.mjs";
|
|
3
3
|
//#region src/scanEntityFiles.d.ts
|
|
4
|
-
/** Scans the entity files themselves for usage hints (like `setDefault` calls) to drive our codegen output. */
|
|
4
|
+
/** Scans the entity files themselves for usage hints (like `setDefault` or `transitions` calls) to drive our codegen output. */
|
|
5
5
|
declare function scanEntityFiles(config: Config, dbMeta: DbMetadata): Promise<void>;
|
|
6
6
|
//#endregion
|
|
7
7
|
export { scanEntityFiles };
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanEntityFiles.d.mts","names":[],"sources":["../src/scanEntityFiles.ts"],"mappings":";;;;
|
|
1
|
+
{"version":3,"file":"scanEntityFiles.d.mts","names":[],"sources":["../src/scanEntityFiles.ts"],"mappings":";;;;iBAqBsB,gBAAgB,QAAQ,QAAQ,QAAQ,aAAa"}
|
package/build/scanEntityFiles.js
CHANGED
|
@@ -4,7 +4,8 @@ import { join } from "path";
|
|
|
4
4
|
import { readFile } from "fs/promises";
|
|
5
5
|
//#region src/scanEntityFiles.ts
|
|
6
6
|
const regex = /config\.setDefault\([\s\n]*["'](\w+)["']/g;
|
|
7
|
-
|
|
7
|
+
const transitionsRegex = /config\.(?:transitions|guardTransition|onTransition)\(\s*(?:(?:["'][^"']*["']|\w+)\s*,\s*(?=["']))?["'](\w+)["']/g;
|
|
8
|
+
/** Scans the entity files themselves for usage hints (like `setDefault` or `transitions` calls) to drive our codegen output. */
|
|
8
9
|
async function scanEntityFiles(config, dbMeta) {
|
|
9
10
|
await Promise.all(dbMeta.entities.map(async (entity) => {
|
|
10
11
|
try {
|
|
@@ -14,6 +15,10 @@ async function scanEntityFiles(config, dbMeta) {
|
|
|
14
15
|
const field = defaultableFields.find((f) => f.fieldName === match[1]);
|
|
15
16
|
if (field) field.hasConfigDefault = true;
|
|
16
17
|
}
|
|
18
|
+
for (const match of tsCode.matchAll(transitionsRegex)) {
|
|
19
|
+
const field = defaultableFields.find((f) => f.fieldName === match[1]);
|
|
20
|
+
if (field?.kind === "enum") field.hasTransitions = true;
|
|
21
|
+
}
|
|
17
22
|
} catch (e) {}
|
|
18
23
|
}));
|
|
19
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"scanEntityFiles.js","names":[],"sources":["../src/scanEntityFiles.ts"],"sourcesContent":["import { readFile } from \"fs/promises\";\nimport { join } from \"path\";\n\nimport { type Config } from \"./config.ts\";\nimport {\n type DbMetadata,\n type EntityDbMetadata,\n type EnumField,\n type ManyToOneField,\n type PgEnumField,\n type PolymorphicField,\n type PrimitiveField,\n} from \"./EntityDbMetadata.ts\";\n\n// Erg, we need a regex in case the fieldName arg is wrapped onto a new line... :-/\nconst regex = /config\\.setDefault\\([\\s\\n]*[\"'](\\w+)[\"']/g;\n\n/** Scans the entity files themselves for usage hints (like `setDefault` calls) to drive our codegen output. */\nexport async function scanEntityFiles(config: Config, dbMeta: DbMetadata): Promise<void> {\n await Promise.all(\n dbMeta.entities.map(async (entity) => {\n try {\n // load the entity.ts file (as a promise with fs/promises)\n const tsCode = (await readFile(join(config.entitiesDirectory, `${entity.name}.ts`))).toString();\n const defaultableFields = recursiveDefaultableFields(dbMeta, entity);\n for (const match of tsCode.matchAll(regex)) {\n const field = defaultableFields.find((f) => f.fieldName === match[1]);\n if (field) {\n field.hasConfigDefault = true;\n }\n }\n } catch (e) {\n // Ignore file not existing yet\n }\n }),\n );\n}\n\n/**\n * Traverse the entity inheritance tree to find all fields that can have defaults set on them.\n *\n * I.e. a column defined in a base CTI table like `publishers.foo_bar` having a `config.setDefault` in\n * `SmallPublisher` and/or `LargePublisher`, or the same scenario for an STI table like `tasks.foo_bar`\n * with `TaskNew` and/or `TaskOld`.\n *\n * NOTE: I suspect here could be some edge cases here that will need to be ironed out, but should work\n * for simple inheritance structures. In particular, there may be unexpected side effects if a base\n * class field has a default set in one subtype, but not another.\n */\nfunction recursiveDefaultableFields(\n dbMeta: DbMetadata,\n entity: EntityDbMetadata | undefined,\n): Array<PrimitiveField | EnumField | PgEnumField | ManyToOneField | PolymorphicField> {\n if (!entity) return [];\n return [\n ...entity.primitives,\n ...entity.enums,\n ...entity.pgEnums,\n ...entity.manyToOnes,\n ...entity.polymorphics,\n ...(entity.baseClassName ? recursiveDefaultableFields(dbMeta, dbMeta.entitiesByName[entity.baseClassName]) : []),\n ];\n}\n"],"mappings":";;;;;AAeA,MAAM,QAAQ;;
|
|
1
|
+
{"version":3,"file":"scanEntityFiles.js","names":[],"sources":["../src/scanEntityFiles.ts"],"sourcesContent":["import { readFile } from \"fs/promises\";\nimport { join } from \"path\";\n\nimport { type Config } from \"./config.ts\";\nimport {\n type DbMetadata,\n type EntityDbMetadata,\n type EnumField,\n type ManyToOneField,\n type PgEnumField,\n type PolymorphicField,\n type PrimitiveField,\n} from \"./EntityDbMetadata.ts\";\n\n// Erg, we need a regex in case the fieldName arg is wrapped onto a new line... :-/\nconst regex = /config\\.setDefault\\([\\s\\n]*[\"'](\\w+)[\"']/g;\n// Any transition method marks the field; onTransition may have a name before the field argument.\nconst transitionsRegex =\n /config\\.(?:transitions|guardTransition|onTransition)\\(\\s*(?:(?:[\"'][^\"']*[\"']|\\w+)\\s*,\\s*(?=[\"']))?[\"'](\\w+)[\"']/g;\n\n/** Scans the entity files themselves for usage hints (like `setDefault` or `transitions` calls) to drive our codegen output. */\nexport async function scanEntityFiles(config: Config, dbMeta: DbMetadata): Promise<void> {\n await Promise.all(\n dbMeta.entities.map(async (entity) => {\n try {\n // load the entity.ts file (as a promise with fs/promises)\n const tsCode = (await readFile(join(config.entitiesDirectory, `${entity.name}.ts`))).toString();\n const defaultableFields = recursiveDefaultableFields(dbMeta, entity);\n for (const match of tsCode.matchAll(regex)) {\n const field = defaultableFields.find((f) => f.fieldName === match[1]);\n if (field) {\n field.hasConfigDefault = true;\n }\n }\n // Transition fields get `withStatus` factory opts and accessor names, i.e. `Draft`\n for (const match of tsCode.matchAll(transitionsRegex)) {\n const field = defaultableFields.find((f) => f.fieldName === match[1]);\n if (field?.kind === \"enum\") {\n field.hasTransitions = true;\n }\n }\n } catch (e) {\n // Ignore file not existing yet\n }\n }),\n );\n}\n\n/**\n * Traverse the entity inheritance tree to find all fields that can have defaults set on them.\n *\n * I.e. a column defined in a base CTI table like `publishers.foo_bar` having a `config.setDefault` in\n * `SmallPublisher` and/or `LargePublisher`, or the same scenario for an STI table like `tasks.foo_bar`\n * with `TaskNew` and/or `TaskOld`.\n *\n * NOTE: I suspect here could be some edge cases here that will need to be ironed out, but should work\n * for simple inheritance structures. In particular, there may be unexpected side effects if a base\n * class field has a default set in one subtype, but not another.\n */\nfunction recursiveDefaultableFields(\n dbMeta: DbMetadata,\n entity: EntityDbMetadata | undefined,\n): Array<PrimitiveField | EnumField | PgEnumField | ManyToOneField | PolymorphicField> {\n if (!entity) return [];\n return [\n ...entity.primitives,\n ...entity.enums,\n ...entity.pgEnums,\n ...entity.manyToOnes,\n ...entity.polymorphics,\n ...(entity.baseClassName ? recursiveDefaultableFields(dbMeta, dbMeta.entitiesByName[entity.baseClassName]) : []),\n ];\n}\n"],"mappings":";;;;;AAeA,MAAM,QAAQ;AAEd,MAAM,mBACJ;;AAGF,eAAsB,gBAAgB,QAAgB,QAAmC;CACvF,MAAM,QAAQ,IACZ,OAAO,SAAS,IAAI,OAAO,WAAW;EACpC,IAAI;GAEF,MAAM,UAAU,MAAM,SAAS,KAAK,OAAO,mBAAmB,GAAG,OAAO,KAAK,IAAI,CAAC,EAAA,CAAG,SAAS;GAC9F,MAAM,oBAAoB,2BAA2B,QAAQ,MAAM;GACnE,KAAK,MAAM,SAAS,OAAO,SAAS,KAAK,GAAG;IAC1C,MAAM,QAAQ,kBAAkB,MAAM,MAAM,EAAE,cAAc,MAAM,EAAE;IACpE,IAAI,OACF,MAAM,mBAAmB;GAE7B;GAEA,KAAK,MAAM,SAAS,OAAO,SAAS,gBAAgB,GAAG;IACrD,MAAM,QAAQ,kBAAkB,MAAM,MAAM,EAAE,cAAc,MAAM,EAAE;IACpE,IAAI,OAAO,SAAS,QAClB,MAAM,iBAAiB;GAE3B;EACF,SAAS,GAAG,CAEZ;CACF,CAAC,CACH;AACF;;;;;;;;;;;;AAaA,SAAS,2BACP,QACA,QACqF;CACrF,IAAI,CAAC,QAAQ,OAAO,CAAC;CACrB,OAAO;EACL,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAG,OAAO;EACV,GAAI,OAAO,gBAAgB,2BAA2B,QAAQ,OAAO,eAAe,OAAO,cAAc,IAAI,CAAC;CAChH;AACF"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "joist-codegen",
|
|
3
|
-
"version": "2.4.0-next.
|
|
3
|
+
"version": "2.4.0-next.21",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"skills"
|
|
49
49
|
],
|
|
50
50
|
"peerDependencies": {
|
|
51
|
-
"joist-utils": "2.4.0-next.
|
|
51
|
+
"joist-utils": "2.4.0-next.21",
|
|
52
52
|
"knex": "^3.1.0",
|
|
53
53
|
"pg": "^8.23.0"
|
|
54
54
|
},
|