joist-codegen 2.3.0-next.99 → 2.4.0
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 +43 -13
- package/build/EntityDbMetadata.cjs.map +1 -1
- package/build/EntityDbMetadata.d.cts +4 -2
- package/build/EntityDbMetadata.d.cts.map +1 -1
- package/build/EntityDbMetadata.d.mts +4 -2
- package/build/EntityDbMetadata.d.mts.map +1 -1
- package/build/EntityDbMetadata.js +41 -11
- package/build/EntityDbMetadata.js.map +1 -1
- package/build/generateEntitiesFile.cjs +1 -1
- package/build/generateEntitiesFile.cjs.map +1 -1
- package/build/generateEntitiesFile.d.cts +1 -1
- package/build/generateEntitiesFile.d.mts +1 -1
- package/build/generateEntitiesFile.js +1 -1
- package/build/generateEntitiesFile.js.map +1 -1
- package/build/generateEntityCodegenFile.cjs +1 -0
- 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 +1 -0
- package/build/generateEntityCodegenFile.js.map +1 -1
- package/build/generateMetadataFile.cjs +23 -17
- 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 +23 -17
- package/build/generateMetadataFile.js.map +1 -1
- package/build/index.cjs +6 -6
- package/build/index.cjs.map +1 -1
- package/build/index.d.cts.map +1 -1
- package/build/index.d.mts.map +1 -1
- package/build/index.js +7 -6
- package/build/index.js.map +1 -1
- package/build/inheritance.cjs +1 -0
- package/build/inheritance.cjs.map +1 -1
- package/build/inheritance.d.cts.map +1 -1
- package/build/inheritance.d.mts.map +1 -1
- package/build/inheritance.js +1 -0
- package/build/inheritance.js.map +1 -1
- package/build/loadMetadata.cjs +3 -3
- package/build/loadMetadata.cjs.map +1 -1
- package/build/loadMetadata.d.cts +1 -1
- package/build/loadMetadata.d.mts +1 -1
- package/build/loadMetadata.js +2 -2
- package/build/loadMetadata.js.map +1 -1
- package/build/pgMetadata.cjs +332 -0
- package/build/pgMetadata.cjs.map +1 -0
- package/build/pgMetadata.d.cts +128 -0
- package/build/pgMetadata.d.cts.map +1 -0
- package/build/pgMetadata.d.mts +128 -0
- package/build/pgMetadata.d.mts.map +1 -0
- package/build/pgMetadata.js +320 -0
- package/build/pgMetadata.js.map +1 -0
- package/build/utils.cjs +3 -1
- package/build/utils.cjs.map +1 -1
- package/build/utils.d.cts +4 -2
- package/build/utils.d.cts.map +1 -1
- package/build/utils.d.mts +4 -2
- package/build/utils.d.mts.map +1 -1
- package/build/utils.js +3 -2
- package/build/utils.js.map +1 -1
- package/package.json +12 -3
- package/skills/joist-docs/SKILL.md +1 -1
- package/skills/joist-em-basics/SKILL.md +2 -2
- package/skills/joist-em-execute/SKILL.md +35 -0
- package/skills/joist-em-find/SKILL.md +27 -0
- package/skills/joist-em-query/SKILL.md +32 -0
- package/skills/joist-reactive-hints/SKILL.md +2 -2
|
@@ -1 +1 @@
|
|
|
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","camelCase","Column","ColumnDescriptors","mapSimpleDbTypeToTypescriptType"],"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, 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 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 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"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"generateMetadataFile.cjs","names":["q","EntityMetadata","imp","SimpleFieldSerde","KeySerde","PrimitiveSerde","EnumArrayFieldSerde","EnumFieldSerde","polymorphicField","PolyComponent","camelCase","Column","ColumnDescriptors","mapSimpleDbTypeToTypescriptType","CustomSerdeAdapter","SuperstructSerde","ZodSerde","DecimalToNumberSerde","JsonSerde","BigIntSerde","PlainDateSerde","DateSerde","PlainDateTimeSerde","ZonedDateTimeSerde","PlainTimeSerde"],"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":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateMetadataFile.d.cts","names":[],"sources":["../src/generateMetadataFile.ts"],"mappings":";;;;iBAoCgB,qBAAqB,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB;;
|
|
1
|
+
{"version":3,"file":"generateMetadataFile.d.cts","names":[],"sources":["../src/generateMetadataFile.ts"],"mappings":";;;;iBAoCgB,qBAAqB,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB;;iBA8SlF,2BAA2B,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"generateMetadataFile.d.mts","names":[],"sources":["../src/generateMetadataFile.ts"],"mappings":";;;;iBAoCgB,qBAAqB,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB;;
|
|
1
|
+
{"version":3,"file":"generateMetadataFile.d.mts","names":[],"sources":["../src/generateMetadataFile.ts"],"mappings":";;;;iBAoCgB,qBAAqB,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB;;iBA8SlF,2BAA2B,QAAQ,QAAQ,QAAQ,YAAY,MAAM,mBAAmB"}
|
|
@@ -73,24 +73,9 @@ function generateFields(config, dbMeta, dbMetadata, columnRef) {
|
|
|
73
73
|
}
|
|
74
74
|
`;
|
|
75
75
|
dbMetadata.primitives.forEach((p) => {
|
|
76
|
-
const { fieldName, derived, columnType
|
|
76
|
+
const { fieldName, derived, columnType } = p;
|
|
77
77
|
const column = columnArgs(p, dbMetadata);
|
|
78
|
-
|
|
79
|
-
if (customSerde) serde = isArray ? code`new ${CustomSerdeAdapter}( "${columnType}[]", ${customSerde}, true)` : code`new ${CustomSerdeAdapter}( "${columnType}", ${customSerde})`;
|
|
80
|
-
else if (superstruct) serde = code`new ${SuperstructSerde}( ${superstruct})`;
|
|
81
|
-
else if (zodSchema) serde = code`new ${ZodSerde}( ${zodSchema})`;
|
|
82
|
-
else if (columnType === "numeric" || columnType === "decimal") serde = isArray ? code`new ${DecimalToNumberSerde}(true)` : code`new ${DecimalToNumberSerde}()`;
|
|
83
|
-
else if (columnType === "jsonb") serde = code`new ${JsonSerde}()`;
|
|
84
|
-
else if (p.rawFieldType === "bigint") serde = isArray ? code`new ${BigIntSerde}(true)` : code`new ${BigIntSerde}()`;
|
|
85
|
-
else {
|
|
86
|
-
let serdeType;
|
|
87
|
-
if (columnType === "date") serdeType = config.temporal ? PlainDateSerde : DateSerde;
|
|
88
|
-
else if (columnType === "timestamp without time zone") serdeType = config.temporal ? PlainDateTimeSerde : DateSerde;
|
|
89
|
-
else if (columnType === "timestamp with time zone") serdeType = config.temporal ? ZonedDateTimeSerde : DateSerde;
|
|
90
|
-
else if (columnType === "time without time zone") serdeType = config.temporal ? PlainTimeSerde : PrimitiveSerde;
|
|
91
|
-
else serdeType = PrimitiveSerde;
|
|
92
|
-
serde = isArray ? code`new ${serdeType}( "${columnType}[]", true)` : code`new ${serdeType}( "${columnType}")`;
|
|
93
|
-
}
|
|
78
|
+
const serde = primitiveColumnCodec(config, p);
|
|
94
79
|
const extras = columnType === "citext" ? code`citext: true,` : "";
|
|
95
80
|
fields[fieldName] = code`
|
|
96
81
|
{
|
|
@@ -278,6 +263,10 @@ function generateColumnDeclarations(config, dbMeta, meta) {
|
|
|
278
263
|
if (codec) columns[apiName] = code`new ${Column}(${q(columnName)}, ${args}, ${codec})`.asOneline();
|
|
279
264
|
return code`${meta.entity.metaName}Columns[${q(apiName)}]`;
|
|
280
265
|
});
|
|
266
|
+
for (const column of (meta.physicalMetadata ?? meta).ignoredColumns) {
|
|
267
|
+
const apiName = camelCase(column.columnName);
|
|
268
|
+
columns[apiName] = code`new ${Column}(${q(column.columnName)}, ${columnArgs(column, meta)}, ${primitiveColumnCodec(config, column)})`.asOneline();
|
|
269
|
+
}
|
|
281
270
|
return code`const ${meta.entity.metaName}Columns = ${columns} satisfies ${ColumnDescriptors};`;
|
|
282
271
|
}
|
|
283
272
|
/** Emits a direct reference to a descriptor by its SQL API name. */
|
|
@@ -301,6 +290,23 @@ function maybeSanitize(config, f) {
|
|
|
301
290
|
function isString(config, columnType) {
|
|
302
291
|
return mapSimpleDbTypeToTypescriptType(config, columnType) === "string";
|
|
303
292
|
}
|
|
293
|
+
/** Uses domain codecs for modeled fields and the same native conversions for unmodeled columns. */
|
|
294
|
+
function primitiveColumnCodec(config, column) {
|
|
295
|
+
const { columnType, customSerde, superstruct, zodSchema, isArray } = column;
|
|
296
|
+
if (customSerde) return isArray ? code`new ${CustomSerdeAdapter}( "${columnType}[]", ${customSerde}, true)` : code`new ${CustomSerdeAdapter}( "${columnType}", ${customSerde})`;
|
|
297
|
+
if (superstruct) return code`new ${SuperstructSerde}( ${superstruct})`;
|
|
298
|
+
if (zodSchema) return code`new ${ZodSerde}( ${zodSchema})`;
|
|
299
|
+
if (columnType === "numeric" || columnType === "decimal") return isArray ? code`new ${DecimalToNumberSerde}(true)` : code`new ${DecimalToNumberSerde}()`;
|
|
300
|
+
if (columnType === "jsonb") return code`new ${JsonSerde}()`;
|
|
301
|
+
if (column.rawFieldType === "bigint") return isArray ? code`new ${BigIntSerde}(true)` : code`new ${BigIntSerde}()`;
|
|
302
|
+
let serdeType;
|
|
303
|
+
if (columnType === "date") serdeType = config.temporal ? PlainDateSerde : DateSerde;
|
|
304
|
+
else if (columnType === "timestamp without time zone") serdeType = config.temporal ? PlainDateTimeSerde : DateSerde;
|
|
305
|
+
else if (columnType === "timestamp with time zone") serdeType = config.temporal ? ZonedDateTimeSerde : DateSerde;
|
|
306
|
+
else if (columnType === "time without time zone") serdeType = config.temporal ? PlainTimeSerde : PrimitiveSerde;
|
|
307
|
+
else serdeType = PrimitiveSerde;
|
|
308
|
+
return isArray ? code`new ${serdeType}( "${columnType}[]", true)` : code`new ${serdeType}( "${columnType}")`;
|
|
309
|
+
}
|
|
304
310
|
//#endregion
|
|
305
311
|
export { generateColumnDeclarations, generateMetadataFile };
|
|
306
312
|
|
|
@@ -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, 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 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 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"],"mappings":"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"}
|
|
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":"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"}
|
package/build/index.cjs
CHANGED
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
|
|
3
3
|
const require_runtime = require("./_virtual/_rolldown/runtime.cjs");
|
|
4
4
|
const require_codemods_index = require("./codemods/index.cjs");
|
|
5
|
+
const require_pgMetadata = require("./pgMetadata.cjs");
|
|
5
6
|
const require_utils = require("./utils.cjs");
|
|
6
7
|
const require_inheritance = require("./inheritance.cjs");
|
|
7
8
|
const require_logger = require("./logger.cjs");
|
|
@@ -15,15 +16,14 @@ const require_scanEntityFiles = require("./scanEntityFiles.cjs");
|
|
|
15
16
|
const require_loadMetadata = require("./loadMetadata.cjs");
|
|
16
17
|
const require_EntityDbMetadata = require("./EntityDbMetadata.cjs");
|
|
17
18
|
let joist_utils = require("joist-utils");
|
|
18
|
-
let pg_structure = require("pg-structure");
|
|
19
|
-
pg_structure = require_runtime.__toESM(pg_structure, 1);
|
|
20
19
|
let ts_poet = require("ts-poet");
|
|
21
20
|
let pg = require("pg");
|
|
21
|
+
let node_fs = require("node:fs");
|
|
22
22
|
let node_process = require("node:process");
|
|
23
23
|
node_process = require_runtime.__toESM(node_process, 1);
|
|
24
24
|
//#region src/index.ts
|
|
25
|
-
const { default: pgStructure } = pg_structure.default;
|
|
26
25
|
async function joistCodegen() {
|
|
26
|
+
if ((0, node_fs.existsSync)(".env")) node_process.default.loadEnvFile();
|
|
27
27
|
const config = await require_config.loadConfig();
|
|
28
28
|
maybeSetDatabaseUrl(config);
|
|
29
29
|
if (!node_process.default.env.DATABASE_URL && !node_process.default.env.DB_USER) {
|
|
@@ -86,13 +86,13 @@ async function maybeGenerateFlushFunctions(config, client, pgConfig, db) {
|
|
|
86
86
|
}
|
|
87
87
|
}
|
|
88
88
|
async function loadSchemaMetadata(config, client) {
|
|
89
|
-
const db = await
|
|
89
|
+
const db = await require_pgMetadata.loadPgMetadata(client);
|
|
90
90
|
const enums = await require_loadMetadata.loadEnumMetadata(db, client, config);
|
|
91
91
|
const pgEnums = await require_loadMetadata.loadPgEnumMetadata(db, client, config);
|
|
92
|
-
const entities = db.tables.filter((t) => require_utils.isEntityTable(config, t)).
|
|
92
|
+
const entities = db.tables.filter((t) => require_utils.isEntityTable(config, t)).sort((a, b) => require_utils.tableToEntityName(config, a).localeCompare(require_utils.tableToEntityName(config, b))).map((table) => new require_EntityDbMetadata.EntityDbMetadata(config, table, enums));
|
|
93
93
|
const totalTables = db.tables.length;
|
|
94
94
|
const joinTables = db.tables.filter((t) => require_utils.isJoinTable(config, t)).map((t) => t.name);
|
|
95
|
-
const otherTables = db.tables.filter((t) => !require_utils.isEntityTable(config, t) && !require_utils.isEnumTable(config, t) && !require_utils.isJoinTable(config, t)).map((t) => t.name);
|
|
95
|
+
const otherTables = db.tables.filter((t) => require_utils.shouldIncludeSchema(config, t) && !require_utils.isEntityTable(config, t) && !require_utils.isEnumTable(config, t) && !require_utils.isJoinTable(config, t)).map((t) => t.name);
|
|
96
96
|
return {
|
|
97
97
|
entities,
|
|
98
98
|
entitiesByName: Object.fromEntries(entities.map((e) => [e.name, e])),
|
package/build/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.cjs","names":["pgStructureModule","loadConfig","process","newPgConnectionConfig","Client","scanEntityFiles","maybeSetForeignKeyOrdering","maybeRunTransforms","installSkills","writeConfig","generateFiles","saveFiles","createFlushFunction","loadEnumMetadata","loadPgEnumMetadata","isEntityTable","EntityDbMetadata","isJoinTable","isEnumTable","loggerMaxWarningLevelHit","LOG_LEVELS"],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport process from \"node:process\";\n\nimport { type ConnectionConfig, newPgConnectionConfig } from \"joist-utils\";\nimport { Client } from \"pg\";\nimport pgStructureModule from \"pg-structure\";\nimport { saveFiles } from \"ts-poet\";\n\nimport { assignTags } from \"./assignTags.ts\";\nimport { maybeRunTransforms } from \"./codemods/index.ts\";\nimport { type Config, loadConfig, stripStiPlaceholders, warnInvalidConfigEntries, writeConfig } from \"./config.ts\";\nimport {\n type DbMetadata,\n EntityDbMetadata,\n failIfOverlappingFieldNames,\n resolveNameConflicts,\n} from \"./EntityDbMetadata.ts\";\nimport { maybeSetForeignKeyOrdering } from \"./foreignKeyOrdering.ts\";\nimport { generateFiles } from \"./generate.ts\";\nimport { createFlushFunction } from \"./generateFlushFunction.ts\";\nimport { applyInheritanceUpdates } from \"./inheritance.ts\";\nimport { installSkills } from \"./installSkills.ts\";\nimport { loadEnumMetadata, loadPgEnumMetadata } from \"./loadMetadata.ts\";\nimport { LOG_LEVELS, loggerMaxWarningLevelHit } from \"./logger.ts\";\nimport { scanEntityFiles } from \"./scanEntityFiles.ts\";\nimport { isEntityTable, isEnumTable, isJoinTable, mapSimpleDbTypeToTypescriptType } from \"./utils.ts\";\n\nconst { default: pgStructure } = pgStructureModule;\n\nexport {\n type DbMetadata,\n type EnumField,\n makeEntity,\n type ManyToManyField,\n type ManyToOneField,\n type OneToManyField,\n type OneToOneField,\n type PolymorphicField,\n type PrimitiveField,\n type PrimitiveTypescriptType,\n} from \"./EntityDbMetadata.ts\";\nexport type { EnumMetadata, EnumRow, EnumTableData, PgEnumData, PgEnumMetadata } from \"./loadMetadata.ts\";\nexport { dateCode, plainDateCode, plainDateTimeCode, zonedDateTimeCode } from \"./utils.ts\";\nexport { type Config, EntityDbMetadata, mapSimpleDbTypeToTypescriptType };\n\nexport async function joistCodegen() {\n const config = await loadConfig();\n\n maybeSetDatabaseUrl(config);\n if (!process.env.DATABASE_URL && !process.env.DB_USER) {\n console.log(`Database connection information not found, please set either:`);\n console.log(` - the DATABASE_URL env variable (i.e. using .env and dotenv), or`);\n console.log(` - the databaseUrl key in joist-config.json`);\n return;\n }\n const pgConfig = newPgConnectionConfig();\n\n const client = new Client(pgConfig);\n await client.connect();\n\n const dbMetadata = await loadSchemaMetadata(config, client);\n const { entities, enums, totalTables } = dbMetadata;\n console.log(\n `Found ${totalTables} total tables, ${entities.length} entity tables, ${Object.entries(enums).length} enum tables`,\n );\n console.log(\"\");\n\n // Look for STI tables to synthesize separate metas\n applyInheritanceUpdates(config, dbMetadata);\n\n // Now that all entities (incl. STI subtypes) are known, fix up any colliding codegen'd type names\n resolveNameConflicts(config, dbMetadata);\n\n // Assign any new tags and write them back to the config file\n assignTags(config, dbMetadata);\n validateTagDelimiter(config, entities);\n\n // Scan `*.ts` files after we've expanded `Task` -> `TaskOld.ts`\n await scanEntityFiles(config, dbMetadata);\n\n // If we're not using deferred FKs, determine our DAG insert order\n await maybeSetForeignKeyOrdering(config, dbMetadata.entities);\n\n // Generate the flush function for tests\n await maybeGenerateFlushFunctions(config, client, pgConfig, dbMetadata);\n\n await client.end();\n\n // Apply any codemods to the user's codebase, if we have them\n await maybeRunTransforms(config);\n\n // Do some warnings\n for (const entity of entities) failIfOverlappingFieldNames(entity);\n warnInvalidConfigEntries(config, dbMetadata);\n\n // Finally actually generate the files (even if we found a fatal error)\n await generateAndSaveFiles(config, dbMetadata);\n\n // Install our bundled Agent Skills so coding agents can find them, unless explicitly disabled\n if (config.skills !== false) await installSkills();\n\n stripStiPlaceholders(config, entities);\n await writeConfig(config);\n}\n\n/** Uses entities and enums from the `db` schema and saves them into our entities directory. */\nexport async function generateAndSaveFiles(config: Config, dbMeta: DbMetadata): Promise<void> {\n const files = await generateFiles(config, dbMeta);\n const esmExt = config.esm ? (config.allowImportingTsExtensions ? \"ts\" : \"js\") : \"\";\n await saveFiles({\n toolName: \"joist-codegen\",\n directory: config.entitiesDirectory,\n files,\n toStringOpts: { importExtensions: esmExt || false },\n });\n}\n\nasync function maybeGenerateFlushFunctions(config: Config, client: Client, pgConfig: ConnectionConfig, db: DbMetadata) {\n // In graphql-service we have our own custom flush function, so allow skipping this\n if (config.createFlushFunction !== false) {\n // Look for multiple test databases\n if (Array.isArray(config.createFlushFunction)) {\n console.log(\"Creating flush_database functions\");\n await Promise.all(\n config.createFlushFunction.map(async (dbName) => {\n const client = new Client({ ...pgConfig, database: dbName });\n await client.connect();\n await createFlushFunction(client, db);\n await client.end();\n }),\n );\n } else {\n console.log(\"Creating flush_database function\");\n await createFlushFunction(client, db);\n }\n }\n}\n\nasync function loadSchemaMetadata(config: Config, client: Client): Promise<DbMetadata> {\n // Here we load all schemas, to avoid pg-structure failing on cross-schema foreign keys\n // like our cyanaudit triggers (https://github.com/ozum/pg-structure/issues/85), and then\n // later filter them non-public schema tables out.\n const db = await pgStructure(client);\n const enums = await loadEnumMetadata(db, client, config);\n const pgEnums = await loadPgEnumMetadata(db, client, config);\n const entities = db.tables\n .filter((t) => isEntityTable(config, t))\n .sortBy(\"name\")\n .map((table) => new EntityDbMetadata(config, table, enums));\n const totalTables = db.tables.length;\n const joinTables = db.tables.filter((t) => isJoinTable(config, t)).map((t) => t.name);\n const otherTables = db.tables\n .filter((t) => !isEntityTable(config, t) && !isEnumTable(config, t) && !isJoinTable(config, t))\n .map((t) => t.name);\n const entitiesByName = Object.fromEntries(entities.map((e) => [e.name, e]));\n return { entities, entitiesByName, enums, pgEnums, totalTables, joinTables, otherTables };\n}\n\nfunction maybeSetDatabaseUrl(config: Config): void {\n if (!process.env.DATABASE_URL && config.databaseUrl) {\n process.env.DATABASE_URL = config.databaseUrl;\n }\n}\n\nexport function maybeSetExitCode(): void {\n if (\n !process.argv.includes(\"--always-exit-code-zero\") &&\n // strict mode + warnings or greater\n ((process.argv.includes(\"--strict\") && loggerMaxWarningLevelHit >= LOG_LEVELS.warn) ||\n // otherwise errors or greater\n loggerMaxWarningLevelHit >= LOG_LEVELS.error)\n ) {\n process.exitCode = 1;\n }\n}\n\n/** Validates that tags can be parsed unambiguously with the configured delimiter. */\nfunction validateTagDelimiter(config: Config, entities: EntityDbMetadata[]): void {\n const tagDelimiter = config.tagDelimiter ?? \":\";\n for (const entity of entities) {\n if (tagDelimiter !== \"\" && `${entity.tagName}${tagDelimiter}`.indexOf(tagDelimiter) !== entity.tagName.length) {\n throw new Error(\n `Tagged id delimiter '${tagDelimiter}' cannot occur in or overlap tag '${entity.tagName}' for ${entity.name}`,\n );\n } else if (tagDelimiter === \"\" && !/^[a-z]+$/i.test(entity.tagName)) {\n throw new Error(`Delimiterless ids require an alphabetic tag, got '${entity.tagName}' for ${entity.name}`);\n } else if (\n tagDelimiter === \"\" &&\n entity.primaryKey.columnType !== \"int\" &&\n entity.primaryKey.columnType !== \"bigint\"\n ) {\n throw new Error(\n `Delimiterless ids require an int or bigint primary key, got '${entity.primaryKey.columnType}' for ${entity.name}`,\n );\n }\n }\n}\n\nif (typeof module !== \"undefined\" && require.main === module) {\n joistCodegen()\n .then(() => maybeSetExitCode())\n .catch((err) => {\n console.error(err);\n process.exit(1);\n });\n}\n"],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;AA4BA,MAAM,EAAE,SAAS,gBAAgBA,aAAAA;AAkBjC,eAAsB,eAAe;CACnC,MAAM,SAAS,MAAMC,eAAAA,WAAW;CAEhC,oBAAoB,MAAM;CAC1B,IAAI,CAACC,aAAAA,QAAQ,IAAI,gBAAgB,CAACA,aAAAA,QAAQ,IAAI,SAAS;EACrD,QAAQ,IAAI,+DAA+D;EAC3E,QAAQ,IAAI,oEAAoE;EAChF,QAAQ,IAAI,8CAA8C;EAC1D;CACF;CACA,MAAM,YAAA,GAAWC,YAAAA,sBAAAA,CAAsB;CAEvC,MAAM,SAAS,IAAIC,GAAAA,OAAO,QAAQ;CAClC,MAAM,OAAO,QAAQ;CAErB,MAAM,aAAa,MAAM,mBAAmB,QAAQ,MAAM;CAC1D,MAAM,EAAE,UAAU,OAAO,gBAAgB;CACzC,QAAQ,IACN,SAAS,YAAY,iBAAiB,SAAS,OAAO,kBAAkB,OAAO,QAAQ,KAAK,CAAC,CAAC,OAAO,aACvG;CACA,QAAQ,IAAI,EAAE;CAGd,oBAAA,wBAAwB,QAAQ,UAAU;CAG1C,yBAAA,qBAAqB,QAAQ,UAAU;CAGvC,mBAAA,WAAW,QAAQ,UAAU;CAC7B,qBAAqB,QAAQ,QAAQ;CAGrC,MAAMC,wBAAAA,gBAAgB,QAAQ,UAAU;CAGxC,MAAMC,2BAAAA,2BAA2B,QAAQ,WAAW,QAAQ;CAG5D,MAAM,4BAA4B,QAAQ,QAAQ,UAAU,UAAU;CAEtE,MAAM,OAAO,IAAI;CAGjB,MAAMC,uBAAAA,mBAAmB,MAAM;CAG/B,KAAK,MAAM,UAAU,UAAU,yBAAA,4BAA4B,MAAM;CACjE,eAAA,yBAAyB,QAAQ,UAAU;CAG3C,MAAM,qBAAqB,QAAQ,UAAU;CAG7C,IAAI,OAAO,WAAW,OAAO,MAAMC,sBAAAA,cAAc;CAEjD,eAAA,qBAAqB,QAAQ,QAAQ;CACrC,MAAMC,eAAAA,YAAY,MAAM;AAC1B;;AAGA,eAAsB,qBAAqB,QAAgB,QAAmC;CAC5F,MAAM,QAAQ,MAAMC,iBAAAA,cAAc,QAAQ,MAAM;CAChD,MAAM,SAAS,OAAO,MAAO,OAAO,6BAA6B,OAAO,OAAQ;CAChF,OAAA,GAAMC,QAAAA,UAAAA,CAAU;EACd,UAAU;EACV,WAAW,OAAO;EAClB;EACA,cAAc,EAAE,kBAAkB,UAAU,MAAM;CACpD,CAAC;AACH;AAEA,eAAe,4BAA4B,QAAgB,QAAgB,UAA4B,IAAgB;CAErH,IAAI,OAAO,wBAAwB,OAAO;EAExC,IAAI,MAAM,QAAQ,OAAO,mBAAmB,GAAG;GAC7C,QAAQ,IAAI,mCAAmC;GAC/C,MAAM,QAAQ,IACZ,OAAO,oBAAoB,IAAI,OAAO,WAAW;IAC/C,MAAM,SAAS,IAAIP,GAAAA,OAAO;KAAE,GAAG;KAAU,UAAU;IAAO,CAAC;IAC3D,MAAM,OAAO,QAAQ;IACrB,MAAMQ,8BAAAA,oBAAoB,QAAQ,EAAE;IACpC,MAAM,OAAO,IAAI;GACnB,CAAC,CACH;EACF,OAAO;GACL,QAAQ,IAAI,kCAAkC;GAC9C,MAAMA,8BAAAA,oBAAoB,QAAQ,EAAE;EACtC;CACF;AACF;AAEA,eAAe,mBAAmB,QAAgB,QAAqC;CAIrF,MAAM,KAAK,MAAM,YAAY,MAAM;CACnC,MAAM,QAAQ,MAAMC,qBAAAA,iBAAiB,IAAI,QAAQ,MAAM;CACvD,MAAM,UAAU,MAAMC,qBAAAA,mBAAmB,IAAI,QAAQ,MAAM;CAC3D,MAAM,WAAW,GAAG,OACjB,QAAQ,MAAMC,cAAAA,cAAc,QAAQ,CAAC,CAAC,CAAC,CACvC,OAAO,MAAM,CAAC,CACd,KAAK,UAAU,IAAIC,yBAAAA,iBAAiB,QAAQ,OAAO,KAAK,CAAC;CAC5D,MAAM,cAAc,GAAG,OAAO;CAC9B,MAAM,aAAa,GAAG,OAAO,QAAQ,MAAMC,cAAAA,YAAY,QAAQ,CAAC,CAAC,CAAC,CAAC,KAAK,MAAM,EAAE,IAAI;CACpF,MAAM,cAAc,GAAG,OACpB,QAAQ,MAAM,CAACF,cAAAA,cAAc,QAAQ,CAAC,KAAK,CAACG,cAAAA,YAAY,QAAQ,CAAC,KAAK,CAACD,cAAAA,YAAY,QAAQ,CAAC,CAAC,CAAC,CAC9F,KAAK,MAAM,EAAE,IAAI;CAEpB,OAAO;EAAE;EAAU,gBADI,OAAO,YAAY,SAAS,KAAK,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC,CACzC;EAAG;EAAO;EAAS;EAAa;EAAY;CAAY;AAC1F;AAEA,SAAS,oBAAoB,QAAsB;CACjD,IAAI,CAACf,aAAAA,QAAQ,IAAI,gBAAgB,OAAO,aACtC,aAAA,QAAQ,IAAI,eAAe,OAAO;AAEtC;AAEA,SAAgB,mBAAyB;CACvC,IACE,CAACA,aAAAA,QAAQ,KAAK,SAAS,yBAAyB,MAE9CA,aAAAA,QAAQ,KAAK,SAAS,UAAU,KAAKiB,eAAAA,4BAA4BC,eAAAA,WAAW,QAE5ED,eAAAA,4BAA4BC,eAAAA,WAAW,QAEzC,aAAA,QAAA,WAAmB;AAEvB;;AAGA,SAAS,qBAAqB,QAAgB,UAAoC;CAChF,MAAM,eAAe,OAAO,gBAAgB;CAC5C,KAAK,MAAM,UAAU,UACnB,IAAI,iBAAiB,MAAM,GAAG,OAAO,UAAU,eAAe,QAAQ,YAAY,MAAM,OAAO,QAAQ,QACrG,MAAM,IAAI,MACR,wBAAwB,aAAa,oCAAoC,OAAO,QAAQ,QAAQ,OAAO,MACzG;MACK,IAAI,iBAAiB,MAAM,CAAC,YAAY,KAAK,OAAO,OAAO,GAChE,MAAM,IAAI,MAAM,qDAAqD,OAAO,QAAQ,QAAQ,OAAO,MAAM;MACpG,IACL,iBAAiB,MACjB,OAAO,WAAW,eAAe,SACjC,OAAO,WAAW,eAAe,UAEjC,MAAM,IAAI,MACR,gEAAgE,OAAO,WAAW,WAAW,QAAQ,OAAO,MAC9G;AAGN;AAEA,IAAI,OAAO,WAAW,eAAe,QAAQ,SAAS,QACpD,aAAa,CAAC,CACX,WAAW,iBAAiB,CAAC,CAAC,CAC9B,OAAO,QAAQ;CACd,QAAQ,MAAM,GAAG;CACjB,aAAA,QAAQ,KAAK,CAAC;AAChB,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.cjs","names":["existsSync","loadConfig","process","newPgConnectionConfig","Client","scanEntityFiles","maybeSetForeignKeyOrdering","maybeRunTransforms","installSkills","writeConfig","generateFiles","saveFiles","createFlushFunction","loadPgMetadata","loadEnumMetadata","loadPgEnumMetadata","isEntityTable","tableToEntityName","EntityDbMetadata","isJoinTable","shouldIncludeSchema","isEnumTable","loggerMaxWarningLevelHit","LOG_LEVELS"],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { existsSync } from \"node:fs\";\nimport process from \"node:process\";\n\nimport { type ConnectionConfig, newPgConnectionConfig } from \"joist-utils\";\nimport { Client } from \"pg\";\nimport { saveFiles } from \"ts-poet\";\n\nimport { assignTags } from \"./assignTags.ts\";\nimport { maybeRunTransforms } from \"./codemods/index.ts\";\nimport { type Config, loadConfig, stripStiPlaceholders, warnInvalidConfigEntries, writeConfig } from \"./config.ts\";\nimport {\n type DbMetadata,\n EntityDbMetadata,\n failIfOverlappingFieldNames,\n resolveNameConflicts,\n} from \"./EntityDbMetadata.ts\";\nimport { maybeSetForeignKeyOrdering } from \"./foreignKeyOrdering.ts\";\nimport { generateFiles } from \"./generate.ts\";\nimport { createFlushFunction } from \"./generateFlushFunction.ts\";\nimport { applyInheritanceUpdates } from \"./inheritance.ts\";\nimport { installSkills } from \"./installSkills.ts\";\nimport { loadEnumMetadata, loadPgEnumMetadata } from \"./loadMetadata.ts\";\nimport { LOG_LEVELS, loggerMaxWarningLevelHit } from \"./logger.ts\";\nimport { loadPgMetadata } from \"./pgMetadata.ts\";\nimport { scanEntityFiles } from \"./scanEntityFiles.ts\";\nimport {\n isEntityTable,\n isEnumTable,\n isJoinTable,\n mapSimpleDbTypeToTypescriptType,\n shouldIncludeSchema,\n tableToEntityName,\n} from \"./utils.ts\";\n\nexport {\n type DbMetadata,\n type EnumField,\n makeEntity,\n type ManyToManyField,\n type ManyToOneField,\n type OneToManyField,\n type OneToOneField,\n type PolymorphicField,\n type PrimitiveField,\n type PrimitiveTypescriptType,\n} from \"./EntityDbMetadata.ts\";\nexport type { EnumMetadata, EnumRow, EnumTableData, PgEnumData, PgEnumMetadata } from \"./loadMetadata.ts\";\nexport { dateCode, plainDateCode, plainDateTimeCode, zonedDateTimeCode } from \"./utils.ts\";\nexport { type Config, EntityDbMetadata, mapSimpleDbTypeToTypescriptType };\n\nexport async function joistCodegen() {\n // pg-structure used to load .env on import; keep that behavior for fixtures and apps\n // that provide DATABASE_URL in a local .env without a separate dotenv bootstrap.\n if (existsSync(\".env\")) process.loadEnvFile();\n const config = await loadConfig();\n\n maybeSetDatabaseUrl(config);\n if (!process.env.DATABASE_URL && !process.env.DB_USER) {\n console.log(`Database connection information not found, please set either:`);\n console.log(` - the DATABASE_URL env variable (i.e. using .env and dotenv), or`);\n console.log(` - the databaseUrl key in joist-config.json`);\n return;\n }\n const pgConfig = newPgConnectionConfig();\n\n const client = new Client(pgConfig);\n await client.connect();\n\n const dbMetadata = await loadSchemaMetadata(config, client);\n const { entities, enums, totalTables } = dbMetadata;\n console.log(\n `Found ${totalTables} total tables, ${entities.length} entity tables, ${Object.entries(enums).length} enum tables`,\n );\n console.log(\"\");\n\n // Look for STI tables to synthesize separate metas\n applyInheritanceUpdates(config, dbMetadata);\n\n // Now that all entities (incl. STI subtypes) are known, fix up any colliding codegen'd type names\n resolveNameConflicts(config, dbMetadata);\n\n // Assign any new tags and write them back to the config file\n assignTags(config, dbMetadata);\n validateTagDelimiter(config, entities);\n\n // Scan `*.ts` files after we've expanded `Task` -> `TaskOld.ts`\n await scanEntityFiles(config, dbMetadata);\n\n // If we're not using deferred FKs, determine our DAG insert order\n await maybeSetForeignKeyOrdering(config, dbMetadata.entities);\n\n // Generate the flush function for tests\n await maybeGenerateFlushFunctions(config, client, pgConfig, dbMetadata);\n\n await client.end();\n\n // Apply any codemods to the user's codebase, if we have them\n await maybeRunTransforms(config);\n\n // Do some warnings\n for (const entity of entities) failIfOverlappingFieldNames(entity);\n warnInvalidConfigEntries(config, dbMetadata);\n\n // Finally actually generate the files (even if we found a fatal error)\n await generateAndSaveFiles(config, dbMetadata);\n\n // Install our bundled Agent Skills so coding agents can find them, unless explicitly disabled\n if (config.skills !== false) await installSkills();\n\n stripStiPlaceholders(config, entities);\n await writeConfig(config);\n}\n\n/** Uses entities and enums from the `db` schema and saves them into our entities directory. */\nexport async function generateAndSaveFiles(config: Config, dbMeta: DbMetadata): Promise<void> {\n const files = await generateFiles(config, dbMeta);\n const esmExt = config.esm ? (config.allowImportingTsExtensions ? \"ts\" : \"js\") : \"\";\n await saveFiles({\n toolName: \"joist-codegen\",\n directory: config.entitiesDirectory,\n files,\n toStringOpts: { importExtensions: esmExt || false },\n });\n}\n\nasync function maybeGenerateFlushFunctions(config: Config, client: Client, pgConfig: ConnectionConfig, db: DbMetadata) {\n // In graphql-service we have our own custom flush function, so allow skipping this\n if (config.createFlushFunction !== false) {\n // Look for multiple test databases\n if (Array.isArray(config.createFlushFunction)) {\n console.log(\"Creating flush_database functions\");\n await Promise.all(\n config.createFlushFunction.map(async (dbName) => {\n const client = new Client({ ...pgConfig, database: dbName });\n await client.connect();\n await createFlushFunction(client, db);\n await client.end();\n }),\n );\n } else {\n console.log(\"Creating flush_database function\");\n await createFlushFunction(client, db);\n }\n }\n}\n\nasync function loadSchemaMetadata(config: Config, client: Client): Promise<DbMetadata> {\n // Load all user schemas so cross-schema foreign keys can be resolved. Codegen filters\n // non-public tables below; trigger functions in other schemas do not affect entities.\n const db = await loadPgMetadata(client);\n const enums = await loadEnumMetadata(db, client, config);\n const pgEnums = await loadPgEnumMetadata(db, client, config);\n // The order also controls generated exports; sorting physical table names puts book_reviews\n // before books and changes initialization order for entity modules with circular imports.\n const entities = db.tables\n .filter((t) => isEntityTable(config, t))\n .sort((a, b) => tableToEntityName(config, a).localeCompare(tableToEntityName(config, b)))\n .map((table) => new EntityDbMetadata(config, table, enums));\n const totalTables = db.tables.length;\n const joinTables = db.tables.filter((t) => isJoinTable(config, t)).map((t) => t.name);\n const otherTables = db.tables\n .filter(\n (t) =>\n shouldIncludeSchema(config, t) &&\n !isEntityTable(config, t) &&\n !isEnumTable(config, t) &&\n !isJoinTable(config, t),\n )\n .map((t) => t.name);\n const entitiesByName = Object.fromEntries(entities.map((e) => [e.name, e]));\n return { entities, entitiesByName, enums, pgEnums, totalTables, joinTables, otherTables };\n}\n\nfunction maybeSetDatabaseUrl(config: Config): void {\n if (!process.env.DATABASE_URL && config.databaseUrl) {\n process.env.DATABASE_URL = config.databaseUrl;\n }\n}\n\nexport function maybeSetExitCode(): void {\n if (\n !process.argv.includes(\"--always-exit-code-zero\") &&\n // strict mode + warnings or greater\n ((process.argv.includes(\"--strict\") && loggerMaxWarningLevelHit >= LOG_LEVELS.warn) ||\n // otherwise errors or greater\n loggerMaxWarningLevelHit >= LOG_LEVELS.error)\n ) {\n process.exitCode = 1;\n }\n}\n\n/** Validates that tags can be parsed unambiguously with the configured delimiter. */\nfunction validateTagDelimiter(config: Config, entities: EntityDbMetadata[]): void {\n const tagDelimiter = config.tagDelimiter ?? \":\";\n for (const entity of entities) {\n if (tagDelimiter !== \"\" && `${entity.tagName}${tagDelimiter}`.indexOf(tagDelimiter) !== entity.tagName.length) {\n throw new Error(\n `Tagged id delimiter '${tagDelimiter}' cannot occur in or overlap tag '${entity.tagName}' for ${entity.name}`,\n );\n } else if (tagDelimiter === \"\" && !/^[a-z]+$/i.test(entity.tagName)) {\n throw new Error(`Delimiterless ids require an alphabetic tag, got '${entity.tagName}' for ${entity.name}`);\n } else if (\n tagDelimiter === \"\" &&\n entity.primaryKey.columnType !== \"int\" &&\n entity.primaryKey.columnType !== \"bigint\"\n ) {\n throw new Error(\n `Delimiterless ids require an int or bigint primary key, got '${entity.primaryKey.columnType}' for ${entity.name}`,\n );\n }\n }\n}\n\nif (typeof module !== \"undefined\" && require.main === module) {\n joistCodegen()\n .then(() => maybeSetExitCode())\n .catch((err) => {\n console.error(err);\n process.exit(1);\n });\n}\n"],"mappings":"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"}
|
package/build/index.d.cts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.cts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;iBAoDsB,gBAAY;;iBAgEZ,qBAAqB,QAAQ,QAAQ,QAAQ,aAAa;iBAiEhE"}
|
package/build/index.d.mts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;
|
|
1
|
+
{"version":3,"file":"index.d.mts","names":[],"sources":["../src/index.ts"],"mappings":";;;;;iBAoDsB,gBAAY;;iBAgEZ,qBAAqB,QAAQ,QAAQ,QAAQ,aAAa;iBAiEhE"}
|
package/build/index.js
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
import { __require } from "./_virtual/_rolldown/runtime.js";
|
|
3
3
|
import { maybeRunTransforms } from "./codemods/index.js";
|
|
4
|
-
import {
|
|
4
|
+
import { loadPgMetadata } from "./pgMetadata.js";
|
|
5
|
+
import { dateCode, isEntityTable, isEnumTable, isJoinTable, mapSimpleDbTypeToTypescriptType, plainDateCode, plainDateTimeCode, shouldIncludeSchema, tableToEntityName, zonedDateTimeCode } from "./utils.js";
|
|
5
6
|
import { applyInheritanceUpdates } from "./inheritance.js";
|
|
6
7
|
import { LOG_LEVELS, loggerMaxWarningLevelHit } from "./logger.js";
|
|
7
8
|
import { loadConfig, stripStiPlaceholders, warnInvalidConfigEntries, writeConfig } from "./config.js";
|
|
@@ -14,13 +15,13 @@ import { scanEntityFiles } from "./scanEntityFiles.js";
|
|
|
14
15
|
import { loadEnumMetadata, loadPgEnumMetadata } from "./loadMetadata.js";
|
|
15
16
|
import { EntityDbMetadata, failIfOverlappingFieldNames, makeEntity, resolveNameConflicts } from "./EntityDbMetadata.js";
|
|
16
17
|
import { newPgConnectionConfig } from "joist-utils";
|
|
17
|
-
import pgStructureModule from "pg-structure";
|
|
18
18
|
import { saveFiles } from "ts-poet";
|
|
19
19
|
import { Client } from "pg";
|
|
20
|
+
import { existsSync } from "node:fs";
|
|
20
21
|
import process from "node:process";
|
|
21
22
|
//#region src/index.ts
|
|
22
|
-
const { default: pgStructure } = pgStructureModule;
|
|
23
23
|
async function joistCodegen() {
|
|
24
|
+
if (existsSync(".env")) process.loadEnvFile();
|
|
24
25
|
const config = await loadConfig();
|
|
25
26
|
maybeSetDatabaseUrl(config);
|
|
26
27
|
if (!process.env.DATABASE_URL && !process.env.DB_USER) {
|
|
@@ -83,13 +84,13 @@ async function maybeGenerateFlushFunctions(config, client, pgConfig, db) {
|
|
|
83
84
|
}
|
|
84
85
|
}
|
|
85
86
|
async function loadSchemaMetadata(config, client) {
|
|
86
|
-
const db = await
|
|
87
|
+
const db = await loadPgMetadata(client);
|
|
87
88
|
const enums = await loadEnumMetadata(db, client, config);
|
|
88
89
|
const pgEnums = await loadPgEnumMetadata(db, client, config);
|
|
89
|
-
const entities = db.tables.filter((t) => isEntityTable(config, t)).
|
|
90
|
+
const entities = db.tables.filter((t) => isEntityTable(config, t)).sort((a, b) => tableToEntityName(config, a).localeCompare(tableToEntityName(config, b))).map((table) => new EntityDbMetadata(config, table, enums));
|
|
90
91
|
const totalTables = db.tables.length;
|
|
91
92
|
const joinTables = db.tables.filter((t) => isJoinTable(config, t)).map((t) => t.name);
|
|
92
|
-
const otherTables = db.tables.filter((t) => !isEntityTable(config, t) && !isEnumTable(config, t) && !isJoinTable(config, t)).map((t) => t.name);
|
|
93
|
+
const otherTables = db.tables.filter((t) => shouldIncludeSchema(config, t) && !isEntityTable(config, t) && !isEnumTable(config, t) && !isJoinTable(config, t)).map((t) => t.name);
|
|
93
94
|
return {
|
|
94
95
|
entities,
|
|
95
96
|
entitiesByName: Object.fromEntries(entities.map((e) => [e.name, e])),
|
package/build/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport process from \"node:process\";\n\nimport { type ConnectionConfig, newPgConnectionConfig } from \"joist-utils\";\nimport { Client } from \"pg\";\nimport pgStructureModule from \"pg-structure\";\nimport { saveFiles } from \"ts-poet\";\n\nimport { assignTags } from \"./assignTags.ts\";\nimport { maybeRunTransforms } from \"./codemods/index.ts\";\nimport { type Config, loadConfig, stripStiPlaceholders, warnInvalidConfigEntries, writeConfig } from \"./config.ts\";\nimport {\n type DbMetadata,\n EntityDbMetadata,\n failIfOverlappingFieldNames,\n resolveNameConflicts,\n} from \"./EntityDbMetadata.ts\";\nimport { maybeSetForeignKeyOrdering } from \"./foreignKeyOrdering.ts\";\nimport { generateFiles } from \"./generate.ts\";\nimport { createFlushFunction } from \"./generateFlushFunction.ts\";\nimport { applyInheritanceUpdates } from \"./inheritance.ts\";\nimport { installSkills } from \"./installSkills.ts\";\nimport { loadEnumMetadata, loadPgEnumMetadata } from \"./loadMetadata.ts\";\nimport { LOG_LEVELS, loggerMaxWarningLevelHit } from \"./logger.ts\";\nimport { scanEntityFiles } from \"./scanEntityFiles.ts\";\nimport { isEntityTable, isEnumTable, isJoinTable, mapSimpleDbTypeToTypescriptType } from \"./utils.ts\";\n\nconst { default: pgStructure } = pgStructureModule;\n\nexport {\n type DbMetadata,\n type EnumField,\n makeEntity,\n type ManyToManyField,\n type ManyToOneField,\n type OneToManyField,\n type OneToOneField,\n type PolymorphicField,\n type PrimitiveField,\n type PrimitiveTypescriptType,\n} from \"./EntityDbMetadata.ts\";\nexport type { EnumMetadata, EnumRow, EnumTableData, PgEnumData, PgEnumMetadata } from \"./loadMetadata.ts\";\nexport { dateCode, plainDateCode, plainDateTimeCode, zonedDateTimeCode } from \"./utils.ts\";\nexport { type Config, EntityDbMetadata, mapSimpleDbTypeToTypescriptType };\n\nexport async function joistCodegen() {\n const config = await loadConfig();\n\n maybeSetDatabaseUrl(config);\n if (!process.env.DATABASE_URL && !process.env.DB_USER) {\n console.log(`Database connection information not found, please set either:`);\n console.log(` - the DATABASE_URL env variable (i.e. using .env and dotenv), or`);\n console.log(` - the databaseUrl key in joist-config.json`);\n return;\n }\n const pgConfig = newPgConnectionConfig();\n\n const client = new Client(pgConfig);\n await client.connect();\n\n const dbMetadata = await loadSchemaMetadata(config, client);\n const { entities, enums, totalTables } = dbMetadata;\n console.log(\n `Found ${totalTables} total tables, ${entities.length} entity tables, ${Object.entries(enums).length} enum tables`,\n );\n console.log(\"\");\n\n // Look for STI tables to synthesize separate metas\n applyInheritanceUpdates(config, dbMetadata);\n\n // Now that all entities (incl. STI subtypes) are known, fix up any colliding codegen'd type names\n resolveNameConflicts(config, dbMetadata);\n\n // Assign any new tags and write them back to the config file\n assignTags(config, dbMetadata);\n validateTagDelimiter(config, entities);\n\n // Scan `*.ts` files after we've expanded `Task` -> `TaskOld.ts`\n await scanEntityFiles(config, dbMetadata);\n\n // If we're not using deferred FKs, determine our DAG insert order\n await maybeSetForeignKeyOrdering(config, dbMetadata.entities);\n\n // Generate the flush function for tests\n await maybeGenerateFlushFunctions(config, client, pgConfig, dbMetadata);\n\n await client.end();\n\n // Apply any codemods to the user's codebase, if we have them\n await maybeRunTransforms(config);\n\n // Do some warnings\n for (const entity of entities) failIfOverlappingFieldNames(entity);\n warnInvalidConfigEntries(config, dbMetadata);\n\n // Finally actually generate the files (even if we found a fatal error)\n await generateAndSaveFiles(config, dbMetadata);\n\n // Install our bundled Agent Skills so coding agents can find them, unless explicitly disabled\n if (config.skills !== false) await installSkills();\n\n stripStiPlaceholders(config, entities);\n await writeConfig(config);\n}\n\n/** Uses entities and enums from the `db` schema and saves them into our entities directory. */\nexport async function generateAndSaveFiles(config: Config, dbMeta: DbMetadata): Promise<void> {\n const files = await generateFiles(config, dbMeta);\n const esmExt = config.esm ? (config.allowImportingTsExtensions ? \"ts\" : \"js\") : \"\";\n await saveFiles({\n toolName: \"joist-codegen\",\n directory: config.entitiesDirectory,\n files,\n toStringOpts: { importExtensions: esmExt || false },\n });\n}\n\nasync function maybeGenerateFlushFunctions(config: Config, client: Client, pgConfig: ConnectionConfig, db: DbMetadata) {\n // In graphql-service we have our own custom flush function, so allow skipping this\n if (config.createFlushFunction !== false) {\n // Look for multiple test databases\n if (Array.isArray(config.createFlushFunction)) {\n console.log(\"Creating flush_database functions\");\n await Promise.all(\n config.createFlushFunction.map(async (dbName) => {\n const client = new Client({ ...pgConfig, database: dbName });\n await client.connect();\n await createFlushFunction(client, db);\n await client.end();\n }),\n );\n } else {\n console.log(\"Creating flush_database function\");\n await createFlushFunction(client, db);\n }\n }\n}\n\nasync function loadSchemaMetadata(config: Config, client: Client): Promise<DbMetadata> {\n // Here we load all schemas, to avoid pg-structure failing on cross-schema foreign keys\n // like our cyanaudit triggers (https://github.com/ozum/pg-structure/issues/85), and then\n // later filter them non-public schema tables out.\n const db = await pgStructure(client);\n const enums = await loadEnumMetadata(db, client, config);\n const pgEnums = await loadPgEnumMetadata(db, client, config);\n const entities = db.tables\n .filter((t) => isEntityTable(config, t))\n .sortBy(\"name\")\n .map((table) => new EntityDbMetadata(config, table, enums));\n const totalTables = db.tables.length;\n const joinTables = db.tables.filter((t) => isJoinTable(config, t)).map((t) => t.name);\n const otherTables = db.tables\n .filter((t) => !isEntityTable(config, t) && !isEnumTable(config, t) && !isJoinTable(config, t))\n .map((t) => t.name);\n const entitiesByName = Object.fromEntries(entities.map((e) => [e.name, e]));\n return { entities, entitiesByName, enums, pgEnums, totalTables, joinTables, otherTables };\n}\n\nfunction maybeSetDatabaseUrl(config: Config): void {\n if (!process.env.DATABASE_URL && config.databaseUrl) {\n process.env.DATABASE_URL = config.databaseUrl;\n }\n}\n\nexport function maybeSetExitCode(): void {\n if (\n !process.argv.includes(\"--always-exit-code-zero\") &&\n // strict mode + warnings or greater\n ((process.argv.includes(\"--strict\") && loggerMaxWarningLevelHit >= LOG_LEVELS.warn) ||\n // otherwise errors or greater\n loggerMaxWarningLevelHit >= LOG_LEVELS.error)\n ) {\n process.exitCode = 1;\n }\n}\n\n/** Validates that tags can be parsed unambiguously with the configured delimiter. */\nfunction validateTagDelimiter(config: Config, entities: EntityDbMetadata[]): void {\n const tagDelimiter = config.tagDelimiter ?? \":\";\n for (const entity of entities) {\n if (tagDelimiter !== \"\" && `${entity.tagName}${tagDelimiter}`.indexOf(tagDelimiter) !== entity.tagName.length) {\n throw new Error(\n `Tagged id delimiter '${tagDelimiter}' cannot occur in or overlap tag '${entity.tagName}' for ${entity.name}`,\n );\n } else if (tagDelimiter === \"\" && !/^[a-z]+$/i.test(entity.tagName)) {\n throw new Error(`Delimiterless ids require an alphabetic tag, got '${entity.tagName}' for ${entity.name}`);\n } else if (\n tagDelimiter === \"\" &&\n entity.primaryKey.columnType !== \"int\" &&\n entity.primaryKey.columnType !== \"bigint\"\n ) {\n throw new Error(\n `Delimiterless ids require an int or bigint primary key, got '${entity.primaryKey.columnType}' for ${entity.name}`,\n );\n }\n }\n}\n\nif (typeof module !== \"undefined\" && require.main === module) {\n joistCodegen()\n .then(() => maybeSetExitCode())\n .catch((err) => {\n console.error(err);\n process.exit(1);\n });\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","names":[],"sources":["../src/index.ts"],"sourcesContent":["#!/usr/bin/env node\n\nimport { existsSync } from \"node:fs\";\nimport process from \"node:process\";\n\nimport { type ConnectionConfig, newPgConnectionConfig } from \"joist-utils\";\nimport { Client } from \"pg\";\nimport { saveFiles } from \"ts-poet\";\n\nimport { assignTags } from \"./assignTags.ts\";\nimport { maybeRunTransforms } from \"./codemods/index.ts\";\nimport { type Config, loadConfig, stripStiPlaceholders, warnInvalidConfigEntries, writeConfig } from \"./config.ts\";\nimport {\n type DbMetadata,\n EntityDbMetadata,\n failIfOverlappingFieldNames,\n resolveNameConflicts,\n} from \"./EntityDbMetadata.ts\";\nimport { maybeSetForeignKeyOrdering } from \"./foreignKeyOrdering.ts\";\nimport { generateFiles } from \"./generate.ts\";\nimport { createFlushFunction } from \"./generateFlushFunction.ts\";\nimport { applyInheritanceUpdates } from \"./inheritance.ts\";\nimport { installSkills } from \"./installSkills.ts\";\nimport { loadEnumMetadata, loadPgEnumMetadata } from \"./loadMetadata.ts\";\nimport { LOG_LEVELS, loggerMaxWarningLevelHit } from \"./logger.ts\";\nimport { loadPgMetadata } from \"./pgMetadata.ts\";\nimport { scanEntityFiles } from \"./scanEntityFiles.ts\";\nimport {\n isEntityTable,\n isEnumTable,\n isJoinTable,\n mapSimpleDbTypeToTypescriptType,\n shouldIncludeSchema,\n tableToEntityName,\n} from \"./utils.ts\";\n\nexport {\n type DbMetadata,\n type EnumField,\n makeEntity,\n type ManyToManyField,\n type ManyToOneField,\n type OneToManyField,\n type OneToOneField,\n type PolymorphicField,\n type PrimitiveField,\n type PrimitiveTypescriptType,\n} from \"./EntityDbMetadata.ts\";\nexport type { EnumMetadata, EnumRow, EnumTableData, PgEnumData, PgEnumMetadata } from \"./loadMetadata.ts\";\nexport { dateCode, plainDateCode, plainDateTimeCode, zonedDateTimeCode } from \"./utils.ts\";\nexport { type Config, EntityDbMetadata, mapSimpleDbTypeToTypescriptType };\n\nexport async function joistCodegen() {\n // pg-structure used to load .env on import; keep that behavior for fixtures and apps\n // that provide DATABASE_URL in a local .env without a separate dotenv bootstrap.\n if (existsSync(\".env\")) process.loadEnvFile();\n const config = await loadConfig();\n\n maybeSetDatabaseUrl(config);\n if (!process.env.DATABASE_URL && !process.env.DB_USER) {\n console.log(`Database connection information not found, please set either:`);\n console.log(` - the DATABASE_URL env variable (i.e. using .env and dotenv), or`);\n console.log(` - the databaseUrl key in joist-config.json`);\n return;\n }\n const pgConfig = newPgConnectionConfig();\n\n const client = new Client(pgConfig);\n await client.connect();\n\n const dbMetadata = await loadSchemaMetadata(config, client);\n const { entities, enums, totalTables } = dbMetadata;\n console.log(\n `Found ${totalTables} total tables, ${entities.length} entity tables, ${Object.entries(enums).length} enum tables`,\n );\n console.log(\"\");\n\n // Look for STI tables to synthesize separate metas\n applyInheritanceUpdates(config, dbMetadata);\n\n // Now that all entities (incl. STI subtypes) are known, fix up any colliding codegen'd type names\n resolveNameConflicts(config, dbMetadata);\n\n // Assign any new tags and write them back to the config file\n assignTags(config, dbMetadata);\n validateTagDelimiter(config, entities);\n\n // Scan `*.ts` files after we've expanded `Task` -> `TaskOld.ts`\n await scanEntityFiles(config, dbMetadata);\n\n // If we're not using deferred FKs, determine our DAG insert order\n await maybeSetForeignKeyOrdering(config, dbMetadata.entities);\n\n // Generate the flush function for tests\n await maybeGenerateFlushFunctions(config, client, pgConfig, dbMetadata);\n\n await client.end();\n\n // Apply any codemods to the user's codebase, if we have them\n await maybeRunTransforms(config);\n\n // Do some warnings\n for (const entity of entities) failIfOverlappingFieldNames(entity);\n warnInvalidConfigEntries(config, dbMetadata);\n\n // Finally actually generate the files (even if we found a fatal error)\n await generateAndSaveFiles(config, dbMetadata);\n\n // Install our bundled Agent Skills so coding agents can find them, unless explicitly disabled\n if (config.skills !== false) await installSkills();\n\n stripStiPlaceholders(config, entities);\n await writeConfig(config);\n}\n\n/** Uses entities and enums from the `db` schema and saves them into our entities directory. */\nexport async function generateAndSaveFiles(config: Config, dbMeta: DbMetadata): Promise<void> {\n const files = await generateFiles(config, dbMeta);\n const esmExt = config.esm ? (config.allowImportingTsExtensions ? \"ts\" : \"js\") : \"\";\n await saveFiles({\n toolName: \"joist-codegen\",\n directory: config.entitiesDirectory,\n files,\n toStringOpts: { importExtensions: esmExt || false },\n });\n}\n\nasync function maybeGenerateFlushFunctions(config: Config, client: Client, pgConfig: ConnectionConfig, db: DbMetadata) {\n // In graphql-service we have our own custom flush function, so allow skipping this\n if (config.createFlushFunction !== false) {\n // Look for multiple test databases\n if (Array.isArray(config.createFlushFunction)) {\n console.log(\"Creating flush_database functions\");\n await Promise.all(\n config.createFlushFunction.map(async (dbName) => {\n const client = new Client({ ...pgConfig, database: dbName });\n await client.connect();\n await createFlushFunction(client, db);\n await client.end();\n }),\n );\n } else {\n console.log(\"Creating flush_database function\");\n await createFlushFunction(client, db);\n }\n }\n}\n\nasync function loadSchemaMetadata(config: Config, client: Client): Promise<DbMetadata> {\n // Load all user schemas so cross-schema foreign keys can be resolved. Codegen filters\n // non-public tables below; trigger functions in other schemas do not affect entities.\n const db = await loadPgMetadata(client);\n const enums = await loadEnumMetadata(db, client, config);\n const pgEnums = await loadPgEnumMetadata(db, client, config);\n // The order also controls generated exports; sorting physical table names puts book_reviews\n // before books and changes initialization order for entity modules with circular imports.\n const entities = db.tables\n .filter((t) => isEntityTable(config, t))\n .sort((a, b) => tableToEntityName(config, a).localeCompare(tableToEntityName(config, b)))\n .map((table) => new EntityDbMetadata(config, table, enums));\n const totalTables = db.tables.length;\n const joinTables = db.tables.filter((t) => isJoinTable(config, t)).map((t) => t.name);\n const otherTables = db.tables\n .filter(\n (t) =>\n shouldIncludeSchema(config, t) &&\n !isEntityTable(config, t) &&\n !isEnumTable(config, t) &&\n !isJoinTable(config, t),\n )\n .map((t) => t.name);\n const entitiesByName = Object.fromEntries(entities.map((e) => [e.name, e]));\n return { entities, entitiesByName, enums, pgEnums, totalTables, joinTables, otherTables };\n}\n\nfunction maybeSetDatabaseUrl(config: Config): void {\n if (!process.env.DATABASE_URL && config.databaseUrl) {\n process.env.DATABASE_URL = config.databaseUrl;\n }\n}\n\nexport function maybeSetExitCode(): void {\n if (\n !process.argv.includes(\"--always-exit-code-zero\") &&\n // strict mode + warnings or greater\n ((process.argv.includes(\"--strict\") && loggerMaxWarningLevelHit >= LOG_LEVELS.warn) ||\n // otherwise errors or greater\n loggerMaxWarningLevelHit >= LOG_LEVELS.error)\n ) {\n process.exitCode = 1;\n }\n}\n\n/** Validates that tags can be parsed unambiguously with the configured delimiter. */\nfunction validateTagDelimiter(config: Config, entities: EntityDbMetadata[]): void {\n const tagDelimiter = config.tagDelimiter ?? \":\";\n for (const entity of entities) {\n if (tagDelimiter !== \"\" && `${entity.tagName}${tagDelimiter}`.indexOf(tagDelimiter) !== entity.tagName.length) {\n throw new Error(\n `Tagged id delimiter '${tagDelimiter}' cannot occur in or overlap tag '${entity.tagName}' for ${entity.name}`,\n );\n } else if (tagDelimiter === \"\" && !/^[a-z]+$/i.test(entity.tagName)) {\n throw new Error(`Delimiterless ids require an alphabetic tag, got '${entity.tagName}' for ${entity.name}`);\n } else if (\n tagDelimiter === \"\" &&\n entity.primaryKey.columnType !== \"int\" &&\n entity.primaryKey.columnType !== \"bigint\"\n ) {\n throw new Error(\n `Delimiterless ids require an int or bigint primary key, got '${entity.primaryKey.columnType}' for ${entity.name}`,\n );\n }\n }\n}\n\nif (typeof module !== \"undefined\" && require.main === module) {\n joistCodegen()\n .then(() => maybeSetExitCode())\n .catch((err) => {\n console.error(err);\n process.exit(1);\n });\n}\n"],"mappings":"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"}
|
package/build/inheritance.cjs
CHANGED
|
@@ -139,6 +139,7 @@ function expandSingleTableInheritance(config, entitiesByName, entities) {
|
|
|
139
139
|
entity: require_EntityDbMetadata.makeEntity(subTypeName),
|
|
140
140
|
tableName: entity.tableName,
|
|
141
141
|
physicalMetadata: entity.physicalMetadata,
|
|
142
|
+
ignoredColumns: entity.ignoredColumns,
|
|
142
143
|
primaryKey: entity.primaryKey,
|
|
143
144
|
primitives: entity.primitives.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),
|
|
144
145
|
enums: entity.enums.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),
|