joist-codegen 2.3.0-next.81 → 2.3.0-next.83
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/config.cjs +2 -2
- package/build/config.cjs.map +1 -1
- package/build/config.d.cts +6 -6
- package/build/config.d.mts +6 -6
- package/build/config.js +2 -2
- package/build/config.js.map +1 -1
- package/build/inheritance.cjs +35 -19
- 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 +35 -19
- package/build/inheritance.js.map +1 -1
- package/package.json +2 -2
package/build/config.cjs
CHANGED
|
@@ -22,7 +22,7 @@ const fieldConfig = zod.z.object({
|
|
|
22
22
|
type: zod.z.optional(zod.z.string()),
|
|
23
23
|
serde: zod.z.optional(zod.z.string()),
|
|
24
24
|
stiDiscriminator: zod.z.optional(zod.z.record(zod.z.string(), zod.z.string())),
|
|
25
|
-
stiType: zod.z.optional(zod.z.string()),
|
|
25
|
+
stiType: zod.z.optional(zod.z.union([zod.z.string(), zod.z.array(zod.z.string())])),
|
|
26
26
|
notNull: zod.z.optional(zod.z.boolean()),
|
|
27
27
|
hasDefault: zod.z.optional(zod.z.boolean()),
|
|
28
28
|
lazy: zod.z.optional(zod.z.boolean())
|
|
@@ -39,7 +39,7 @@ const relationConfig = zod.z.object({
|
|
|
39
39
|
* this specific o2m/m2m always return soft-deleted entities from `.get`/`.load`.
|
|
40
40
|
*/
|
|
41
41
|
softDeletes: zod.z.optional(zod.z.union([zod.z.literal("include"), zod.z.literal("exclude")])),
|
|
42
|
-
stiType: zod.z.optional(zod.z.string()),
|
|
42
|
+
stiType: zod.z.optional(zod.z.union([zod.z.string(), zod.z.array(zod.z.string())])),
|
|
43
43
|
/**
|
|
44
44
|
* Allow specializing a base type relation (SmallPublisher.group: SmallPublisherGroup).
|
|
45
45
|
*
|
package/build/config.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.cjs","names":["createFromBuffer","readFileSync","getPath","z","groupBy","getStiEntities","trueIfResolved","getLatestCodemodVersion","sortKeys","parse","join","existsSync","dirname"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, promises as fs, readFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\nimport { createFromBuffer } from \"@dprint/formatter\";\nimport { getPath } from \"@dprint/json\";\nimport { groupBy } from \"joist-utils\";\nimport { type ParseError, parse } from \"jsonc-parser\";\nimport { z } from \"zod\";\n\nimport { getLatestCodemodVersion } from \"./codemods/index.ts\";\nimport { type DbMetadata, type Entity, type EntityDbMetadata } from \"./EntityDbMetadata.ts\";\nimport { getStiEntities } from \"./inheritance.ts\";\nimport { logger } from \"./logger.ts\";\nimport { fail, sortKeys, trueIfResolved } from \"./utils.ts\";\n\nconst jsonFormatter = createFromBuffer(readFileSync(getPath()));\n\nconst fieldConfig = z\n .object({\n // For getters & ReactiveFields\n derived: z.optional(z.union([z.literal(\"sync\"), z.literal(\"async\")])),\n protected: z.optional(z.boolean()),\n ignore: z.optional(z.boolean()),\n superstruct: z.optional(z.string()),\n zodSchema: z.optional(z.string()),\n type: z.optional(z.string()),\n serde: z.optional(z.string()),\n stiDiscriminator: z.optional(z.record(z.string(), z.string())),\n stiType: z.optional(z.string()),\n // Allow subclasses to mark fields as required\n notNull: z.optional(z.boolean()),\n // Allow overriding scanEntities default detection for fields with defaults added by helpers\n hasDefault: z.optional(z.boolean()),\n // Exclude a (large jsonb/text) column from the default SELECT and expose it as a lazy-loaded LazyField\n lazy: z.optional(z.boolean()),\n })\n .strict();\n\nexport type FieldConfig = z.infer<typeof fieldConfig>;\n\nconst relationConfig = z\n .object({\n // For ReactiveReferences\n derived: z.optional(z.literal(\"async\")),\n polymorphic: z.optional(z.union([z.literal(\"notNull\"), z.literal(true)])),\n large: z.optional(z.boolean()),\n orderBy: z.optional(z.string()),\n /**\n * Controls whether this collection's `.get`/`.load` hide soft-deleted entities.\n *\n * Defaults to `\"exclude\"` (soft-deleted entities are hidden); set to `\"include\"` to have\n * this specific o2m/m2m always return soft-deleted entities from `.get`/`.load`.\n */\n softDeletes: z.optional(z.union([z.literal(\"include\"), z.literal(\"exclude\")])),\n // Allow pushing m2o/m2m/o2o relations in a base type (Task) down to a subtype (TaskOld)\n stiType: z.optional(z.string()),\n /**\n * Allow specializing a base type relation (SmallPublisher.group: SmallPublisherGroup).\n *\n * Self-referential FKs also support `subType: \"self\"` that means each subtype will point\n * at its own subtype.\n */\n subType: z.optional(z.string()),\n /** Allow skipping self-referential fields getting a `...Recursive` relation. */\n skipRecursiveRelations: z.optional(z.boolean()),\n // Allow marking m2o FKs as required on subclasses\n notNull: z.optional(z.boolean()),\n // Allow overriding scanEntities default detection for fields with defaults added by helpers\n hasDefault: z.optional(z.boolean()),\n })\n .strict();\n\nexport type RelationConfig = z.infer<typeof relationConfig>;\n\nconst uniqueByConfig = z\n .union([z.string(), z.array(z.string()), z.array(z.array(z.string()))])\n .transform(normalizeUniqueByConfig);\n\nconst entityConfig = z\n .object({\n tag: z.string(),\n tableName: z.optional(z.string()),\n fields: z.optional(z.record(z.string(), fieldConfig)),\n relations: z.optional(z.record(z.string(), relationConfig)),\n /** Whether this entity should be abstract, e.g. for inheritance a subtype must be instantiated instead of this type. */\n abstract: z.optional(z.boolean()),\n orderBy: z.optional(z.string()),\n uniqueBy: z.optional(uniqueByConfig),\n })\n .strict();\n\nexport type EntityConfig = z.infer<typeof entityConfig>;\n\nconst timestampConfig = z\n .object({\n /** The names to check for this timestamp, i.e. `created_at` `created`, etc. */\n names: z.array(z.string()),\n /** Whether this timestamp column is required to consider a table an entity, defaults to `false`. */\n required: z.optional(z.boolean()),\n })\n .strict();\n\nexport type TimestampConfig = z.infer<typeof timestampConfig>;\n\nexport const config = z\n .object({\n /** The _build-time_ database URL for reading database metadata. */\n databaseUrl: z.optional(z.string()),\n /** Your application's request-level `Context` type. */\n contextType: z.optional(z.string()),\n /** Your application's database client's `Transaction` type. */\n transactionType: z.optional(z.string()),\n /**\n * Allows the user to specify the `updated_at` / `created_at` column names to look up, and if they're optional.\n *\n * We default to looking for `updated_at`, `updatedAt`, `created_at`, `createdAt`, and optional to true,\n * e.g. tables are not required to have both timestamp columns to be considered entities.\n *\n * These defaults are the most lenient, to facilitate running Joist against an existing schema and\n * seeing all of your entities, regardless of your previous conventions.\n */\n timestampColumns: z.optional(\n z.object({\n createdAt: z.optional(timestampConfig),\n updatedAt: z.optional(timestampConfig),\n deletedAt: z.optional(timestampConfig),\n }),\n ),\n /**\n * Allows the user to have codegen output `Temporal` types instead of the base JS `Date`\n *\n * Additionally, allows for specifying the default time zone for `Temporal` types when converting dates to/from\n * the database.\n */\n temporal: z.optional(z.union([z.boolean(), z.object({ timeZone: z.string() })])),\n /**\n * By default, we create a `flush_database` function for fast testing.\n *\n * However, if you don't want to use this, or you have your own bespoke function like we do\n * that is more application-aware, then you can disable Joist's out-of-the-box one.\n *\n * If you have more than one test database, you can set `createFlushFunction` to the array\n * of test database names, i.e. `mydb_test_1`, `mydb_test_2`, etc.\n */\n createFlushFunction: z.optional(z.union([z.boolean(), z.array(z.string())])),\n entitiesDirectory: z.string().default(\"./src/entities\"),\n codegenPlugins: z.optional(z.array(z.string())),\n entities: z.record(z.string(), entityConfig).default({}),\n ignoredTables: z.optional(z.array(z.string())),\n /** The type of entity `id` fields; defaults to `tagged-string`. */\n idType: z.optional(z.union([z.literal(\"tagged-string\"), z.literal(\"untagged-string\"), z.literal(\"number\")])),\n /** The separator between entity tags and ids; defaults to `:`, and `\"\"` disables the separator. */\n tagDelimiter: z.optional(z.string()),\n /** How we should support non-deferred foreign keys. */\n nonDeferredForeignKeys: z.optional(z.union([z.literal(\"error\"), z.literal(\"warn\"), z.literal(\"ignore\")])),\n /** Enables esm output. */\n esm: z.optional(z.boolean()),\n /** Controls the style of GraphQL pagination scaffolding. */\n paginationStyle: z.optional(z.union([z.literal(\"cursor\"), z.literal(\"limit\")])).default(\"cursor\"),\n /** Enables documentation syncing between .md files and JSDocs. */\n docs: z.optional(z.boolean()),\n /** Installs Joist's bundled Agent Skills into `.claude/skills` and `.agents/skills`; on by default, set `false` to disable. */\n skills: z.optional(z.boolean()),\n /** Output a metadata-docs.ts file with entity/field documentation available at runtime. */\n outputDocs: z.optional(z.boolean()),\n /** Auto-set by probing the project's `tsconfig.json` file. */\n allowImportingTsExtensions: z.optional(z.boolean()),\n /** The latest Joist codemod counter that has been applied to this project. */\n codemodVersion: z.number().int().min(0).default(0),\n\n /** A list of postgres schemas to use for finding tables */\n schemas: z.optional(z.array(z.string())),\n })\n .strict();\n\nexport type Config = z.infer<typeof config> & {\n // We don't persist this, and instead just use it as a cache\n __tableToEntityName?: Record<string, string>;\n};\n\nexport const ormMaintainedFields = [\"createdAt\", \"updatedAt\"];\n\n/** Ensure the user doesn't have any typos in their config. */\nexport function warnInvalidConfigEntries(config: Config, db: DbMetadata): void {\n const entitiesByName = groupBy(db.entities, (e) => e.name);\n for (const [entityName, entityConfig] of Object.entries(config.entities)) {\n const entities = entitiesByName[entityName];\n if (!entities) {\n logger.warn(`Found config for non-existent entity ${entityName}`);\n continue;\n }\n // We don't have keyBy...\n const [entity] = entities;\n\n // Check fields\n const fields = [...entity.primitives, ...entity.enums];\n for (const [name, config] of Object.entries(entityConfig.fields || {})) {\n if (config.ignore) continue;\n let field = fields.find((f) => f.fieldName === name);\n // STI types might be in the base type\n if (!field && entity.stiDiscriminatorField) {\n const stiEntities = getStiEntities(db.entities).get(entity.name)?.subTypes;\n field = stiEntities?.flatMap((st) => [...st.primitives, ...st.enums]).find((f) => f.fieldName === name);\n }\n if (!field) logger.warn(`Found config for non-existent field ${entityName}.${name}`);\n }\n\n // Check relations\n const relations = [\n ...entity.manyToOnes,\n ...entity.oneToManys,\n ...entity.manyToManys,\n ...entity.manyToManyEnums,\n ...entity.oneToOnes,\n ...entity.largeOneToManys,\n ...entity.largeManyToManys,\n ...entity.polymorphics,\n ];\n for (const [name, _] of Object.entries(entityConfig.relations || {})) {\n let relation = relations.find((r) => r.fieldName === name);\n // STI types might be in the subtypes\n if (!relation && entity.stiDiscriminatorField) {\n const stiEntities = getStiEntities(db.entities).get(entity.name)?.subTypes;\n relation = stiEntities\n ?.flatMap((entity) => [\n ...entity.manyToOnes,\n ...entity.oneToManys,\n ...entity.manyToManys,\n ...entity.oneToOnes,\n ...entity.largeOneToManys,\n ...entity.largeManyToManys,\n ...entity.polymorphics,\n ])\n ?.find((f) => f.fieldName === name);\n }\n // CTI subtype specializations (i.e. SmallPublisher.group: SmallPublisherGroup) need to look in the base type\n if (!relation && entity.baseType) {\n const baseType = entity.baseType;\n relation = [\n ...baseType.manyToOnes,\n ...baseType.oneToManys,\n ...baseType.manyToManys,\n ...baseType.oneToOnes,\n ...baseType.largeOneToManys,\n ...baseType.largeManyToManys,\n ...baseType.polymorphics,\n ].find((f) => f.fieldName === name);\n }\n\n if (!relation) logger.warn(`Found config for non-existent relation ${entityName}.${name}`);\n }\n\n const uniqueFields = [\n ...entity.primitives,\n ...entity.enums,\n ...entity.pgEnums,\n ...entity.manyToOnes,\n ...entity.polymorphics,\n ];\n for (const uniqueBy of entityConfig.uniqueBy || []) {\n for (const name of uniqueBy) {\n const field = uniqueFields.find((f) => f.fieldName === name);\n if (!field) {\n logger.warn(`Found uniqueBy for non-existent or non-queryable field ${entityName}.${name}`);\n } else if (field.kind === \"primitive\" && (field.derived || field.isArray || field.customSerde)) {\n logger.warn(`Found uniqueBy for unsupported primitive field ${entityName}.${name}`);\n } else if (field.kind === \"enum\" && (field.derived || field.isArray)) {\n logger.warn(`Found uniqueBy for unsupported enum field ${entityName}.${name}`);\n }\n }\n }\n }\n}\n\nexport function isGetterField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.derived === \"sync\";\n}\n\nexport function isReactiveField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.derived === \"async\";\n}\n\nexport function isReactiveReference(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.derived === \"async\";\n}\n\n/** Returns true if this m2m relation is configured as a ReactiveManyToMany (derived: async). */\nexport function isReactiveManyToMany(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.derived === \"async\";\n}\n\nexport function isProtected(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.protected === true;\n}\n\n/** Whether a column should be excluded from the default SELECT and exposed as a lazy-loaded `LazyField`. */\nexport function isLazyField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.lazy === true;\n}\n\nexport function serdeConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.serde;\n}\n\nexport function superstructConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.superstruct;\n}\n\nexport function zodSchemaConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.zodSchema;\n}\n\nexport function fieldTypeConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.type;\n}\n\nexport function isLargeCollection(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.large === true;\n}\n\n/** Whether a collection should include (or exclude) soft-deleted entities from `.get`/`.load`. */\nexport function softDeletesConfig(\n config: Config,\n entity: Entity,\n fieldName: string,\n): \"include\" | \"exclude\" | undefined {\n return config.entities[entity.name]?.relations?.[fieldName]?.softDeletes;\n}\n\nexport function isFieldIgnored(\n config: Config,\n entity: Entity,\n fieldName: string,\n notNull: boolean = false,\n hasDefault: boolean = false,\n): boolean {\n const ignore = config.entities[entity.name]?.fields?.[fieldName]?.ignore === true;\n if (ignore && notNull && !hasDefault) {\n fail(\n `notNull field ${entity.name}.${fieldName} cannot be ignored. Alter the column to be optional or have a default value prior to ignoring it.`,\n );\n }\n return ignore;\n}\n\nexport function isFieldHasDefault(config: Config, entity: Entity, fieldName: string): boolean {\n const entityConfig = config.entities[entity.name] ?? {};\n const fieldConfig = entityConfig.fields?.[fieldName] ?? entityConfig.relations?.[fieldName] ?? {};\n return fieldConfig.hasDefault === true;\n}\n\nconst configPath = \"./joist-config.json\";\n\nexport async function loadConfig(): Promise<Config> {\n const exists = await trueIfResolved(fs.access(configPath));\n if (exists) {\n const content = await fs.readFile(configPath);\n const result = config.safeParse(stripLegacyConfigKeys(JSON.parse(content.toString())));\n if (!result.success) {\n throw new Error(\n `Invalid joist-config.json: ${result.error.issues\n .map((ze) => `${ze.path.map(String).join(\"/\")} ${ze.message}`)\n .join(\"\\n\")}`,\n );\n }\n result.data.allowImportingTsExtensions ??= projectIsUsingEsmWithImports();\n return result.data;\n }\n // Brand-new projects should not be prompted to run historical codemods.\n const initial = config.parse({ codemodVersion: getLatestCodemodVersion() });\n initial.allowImportingTsExtensions ??= projectIsUsingEsmWithImports();\n return initial;\n}\n\n/**\n * Writes the potentially-updated config entry back to `joist-config.json`.\n *\n * We format the output with prettier so it should both a) look nice and b) be deterministic,\n * such that no changes to the config show up as noops to the scm.\n */\nexport async function writeConfig(config: Config): Promise<void> {\n const sorted: Partial<Config> = sortKeys(config);\n delete sorted.__tableToEntityName;\n delete sorted.allowImportingTsExtensions;\n if (sorted.paginationStyle === \"cursor\") {\n delete sorted.paginationStyle;\n }\n const input = JSON.stringify(sorted);\n const content = jsonFormatter.formatText({ filePath: \"test.json\", fileText: input });\n await fs.writeFile(configPath, content);\n}\n\nexport function stripStiPlaceholders(config: Config, entities: EntityDbMetadata[]): void {\n // Defacto (with today's setup) the config of STI entities lives on the base entity,\n // so don't write confusing subtype-specific entries into the config file.\n // ...hopefully we don't have any code accidentally looking for the STI config...\n for (const entity of entities) {\n if (entity.inheritanceType === \"sti\" && entity.stiDiscriminatorValue) {\n delete config.entities[entity.name];\n }\n }\n}\n\n/** Applies defaults to the timestamp config. */\nexport function getTimestampConfig(config: Config): {\n updatedAtConf: Required<TimestampConfig>;\n createdAtConf: Required<TimestampConfig>;\n deletedAtConf: Required<TimestampConfig>;\n} {\n return {\n createdAtConf: {\n names: [\"created_at\", \"createdAt\"],\n required: false,\n ...config?.timestampColumns?.createdAt,\n },\n updatedAtConf: {\n names: [\"updated_at\", \"updatedAt\"],\n required: false,\n ...config?.timestampColumns?.updatedAt,\n },\n deletedAtConf: {\n names: [\"deleted_at\", \"deletedAt\"],\n required: false,\n ...config?.timestampColumns?.deletedAt,\n },\n };\n}\n\nfunction projectIsUsingEsmWithImports(): boolean {\n // Attempt to find the project's tsconfig.json in the current directory or up the directory hierarchy\n const configPath = findTsConfigFile(process.cwd());\n if (!configPath) {\n return false;\n }\n try {\n // Use jsonc-parser to parse the tsconfig.json file (not the old tsc readConfigFile which was\n // dropped in TypeScript 7), allowing for comments and trailing commas.\n const errors: ParseError[] = [];\n const parsed: unknown = parse(readFileSync(configPath, \"utf8\"), errors, { allowTrailingComma: true });\n if (errors.length > 0 || typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) return false;\n const compilerOptions = (parsed as Record<string, unknown>).compilerOptions;\n return (\n typeof compilerOptions === \"object\" &&\n compilerOptions !== null &&\n !Array.isArray(compilerOptions) &&\n (compilerOptions as Record<string, unknown>).allowImportingTsExtensions === true\n );\n } catch {\n return false;\n }\n}\n\n/** Normalizes `uniqueBy` config sugar into runtime identity candidates. */\nfunction normalizeUniqueByConfig(uniqueBy: string | string[] | string[][]): string[][] {\n if (typeof uniqueBy === \"string\") return [[uniqueBy]];\n if (uniqueBy.every((field) => typeof field === \"string\")) return [uniqueBy];\n return uniqueBy;\n}\n\nfunction stripLegacyConfigKeys(raw: unknown): unknown {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n return raw;\n }\n // Accept old configs so the deprecated key disappears on the next write.\n const parsed = { ...(raw as Record<string, unknown>) };\n delete parsed.version;\n return parsed;\n}\n\n/** Finds the nearest `tsconfig.json` in `directory` or one of its ancestors. */\nfunction findTsConfigFile(directory: string): string | undefined {\n while (true) {\n const fileName = join(directory, \"tsconfig.json\");\n if (existsSync(fileName)) return fileName;\n const parent = dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n"],"mappings":";;;;;;;;;;;;;;AAeA,MAAM,iBAAA,GAAgBA,kBAAAA,iBAAAA,EAAAA,GAAiBC,GAAAA,aAAAA,EAAAA,GAAaC,aAAAA,QAAAA,CAAQ,CAAC,CAAC;AAE9D,MAAM,cAAcC,IAAAA,EACjB,OAAO;CAEN,SAASA,IAAAA,EAAE,SAASA,IAAAA,EAAE,MAAM,CAACA,IAAAA,EAAE,QAAQ,MAAM,GAAGA,IAAAA,EAAE,QAAQ,OAAO,CAAC,CAAC,CAAC;CACpE,WAAWA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;CACjC,QAAQA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;CAC9B,aAAaA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;CAClC,WAAWA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;CAChC,MAAMA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;CAC3B,OAAOA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;CAC5B,kBAAkBA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAOA,IAAAA,EAAE,OAAO,GAAGA,IAAAA,EAAE,OAAO,CAAC,CAAC;CAC7D,SAASA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;CAE9B,SAASA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;CAE/B,YAAYA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;CAElC,MAAMA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;AAC9B,CAAC,CAAC,CACD,OAAO;AAIV,MAAM,iBAAiBA,IAAAA,EACpB,OAAO;CAEN,SAASA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,OAAO,CAAC;CACtC,aAAaA,IAAAA,EAAE,SAASA,IAAAA,EAAE,MAAM,CAACA,IAAAA,EAAE,QAAQ,SAAS,GAAGA,IAAAA,EAAE,QAAQ,IAAI,CAAC,CAAC,CAAC;CACxE,OAAOA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;CAC7B,SAASA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;;;;;;;CAO9B,aAAaA,IAAAA,EAAE,SAASA,IAAAA,EAAE,MAAM,CAACA,IAAAA,EAAE,QAAQ,SAAS,GAAGA,IAAAA,EAAE,QAAQ,SAAS,CAAC,CAAC,CAAC;CAE7E,SAASA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;;;;;;;CAO9B,SAASA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;;CAE9B,wBAAwBA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;CAE9C,SAASA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;CAE/B,YAAYA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;AACpC,CAAC,CAAC,CACD,OAAO;AAIV,MAAM,iBAAiBA,IAAAA,EACpB,MAAM;CAACA,IAAAA,EAAE,OAAO;CAAGA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC;CAAGA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC,CAAC;AAAC,CAAC,CAAC,CACtE,UAAU,uBAAuB;AAEpC,MAAM,eAAeA,IAAAA,EAClB,OAAO;CACN,KAAKA,IAAAA,EAAE,OAAO;CACd,WAAWA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;CAChC,QAAQA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAOA,IAAAA,EAAE,OAAO,GAAG,WAAW,CAAC;CACpD,WAAWA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAOA,IAAAA,EAAE,OAAO,GAAG,cAAc,CAAC;;CAE1D,UAAUA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;CAChC,SAASA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;CAC9B,UAAUA,IAAAA,EAAE,SAAS,cAAc;AACrC,CAAC,CAAC,CACD,OAAO;AAIV,MAAM,kBAAkBA,IAAAA,EACrB,OAAO;;CAEN,OAAOA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC;;CAEzB,UAAUA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;AAClC,CAAC,CAAC,CACD,OAAO;AAIV,MAAa,SAASA,IAAAA,EACnB,OAAO;;CAEN,aAAaA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;;CAElC,aAAaA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;;CAElC,iBAAiBA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;;;;;;;;;;CAUtC,kBAAkBA,IAAAA,EAAE,SAClBA,IAAAA,EAAE,OAAO;EACP,WAAWA,IAAAA,EAAE,SAAS,eAAe;EACrC,WAAWA,IAAAA,EAAE,SAAS,eAAe;EACrC,WAAWA,IAAAA,EAAE,SAAS,eAAe;CACvC,CAAC,CACH;;;;;;;CAOA,UAAUA,IAAAA,EAAE,SAASA,IAAAA,EAAE,MAAM,CAACA,IAAAA,EAAE,QAAQ,GAAGA,IAAAA,EAAE,OAAO,EAAE,UAAUA,IAAAA,EAAE,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC;;;;;;;;;;CAU/E,qBAAqBA,IAAAA,EAAE,SAASA,IAAAA,EAAE,MAAM,CAACA,IAAAA,EAAE,QAAQ,GAAGA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;CAC3E,mBAAmBA,IAAAA,EAAE,OAAO,CAAC,CAAC,QAAQ,gBAAgB;CACtD,gBAAgBA,IAAAA,EAAE,SAASA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC,CAAC;CAC9C,UAAUA,IAAAA,EAAE,OAAOA,IAAAA,EAAE,OAAO,GAAG,YAAY,CAAC,CAAC,QAAQ,CAAC,CAAC;CACvD,eAAeA,IAAAA,EAAE,SAASA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC,CAAC;;CAE7C,QAAQA,IAAAA,EAAE,SAASA,IAAAA,EAAE,MAAM;EAACA,IAAAA,EAAE,QAAQ,eAAe;EAAGA,IAAAA,EAAE,QAAQ,iBAAiB;EAAGA,IAAAA,EAAE,QAAQ,QAAQ;CAAC,CAAC,CAAC;;CAE3G,cAAcA,IAAAA,EAAE,SAASA,IAAAA,EAAE,OAAO,CAAC;;CAEnC,wBAAwBA,IAAAA,EAAE,SAASA,IAAAA,EAAE,MAAM;EAACA,IAAAA,EAAE,QAAQ,OAAO;EAAGA,IAAAA,EAAE,QAAQ,MAAM;EAAGA,IAAAA,EAAE,QAAQ,QAAQ;CAAC,CAAC,CAAC;;CAExG,KAAKA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;;CAE3B,iBAAiBA,IAAAA,EAAE,SAASA,IAAAA,EAAE,MAAM,CAACA,IAAAA,EAAE,QAAQ,QAAQ,GAAGA,IAAAA,EAAE,QAAQ,OAAO,CAAC,CAAC,CAAC,CAAC,CAAC,QAAQ,QAAQ;;CAEhG,MAAMA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;;CAE5B,QAAQA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;;CAE9B,YAAYA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;;CAElC,4BAA4BA,IAAAA,EAAE,SAASA,IAAAA,EAAE,QAAQ,CAAC;;CAElD,gBAAgBA,IAAAA,EAAE,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,QAAQ,CAAC;;CAGjD,SAASA,IAAAA,EAAE,SAASA,IAAAA,EAAE,MAAMA,IAAAA,EAAE,OAAO,CAAC,CAAC;AACzC,CAAC,CAAC,CACD,OAAO;AAOV,MAAa,sBAAsB,CAAC,aAAa,WAAW;;AAG5D,SAAgB,yBAAyB,QAAgB,IAAsB;CAC7E,MAAM,kBAAA,GAAiBC,YAAAA,QAAAA,CAAQ,GAAG,WAAW,MAAM,EAAE,IAAI;CACzD,KAAK,MAAM,CAAC,YAAY,iBAAiB,OAAO,QAAQ,OAAO,QAAQ,GAAG;EACxE,MAAM,WAAW,eAAe;EAChC,IAAI,CAAC,UAAU;GACb,eAAA,OAAO,KAAK,wCAAwC,YAAY;GAChE;EACF;EAEA,MAAM,CAAC,UAAU;EAGjB,MAAM,SAAS,CAAC,GAAG,OAAO,YAAY,GAAG,OAAO,KAAK;EACrD,KAAK,MAAM,CAAC,MAAM,WAAW,OAAO,QAAQ,aAAa,UAAU,CAAC,CAAC,GAAG;GACtE,IAAI,OAAO,QAAQ;GACnB,IAAI,QAAQ,OAAO,MAAM,MAAM,EAAE,cAAc,IAAI;GAEnD,IAAI,CAAC,SAAS,OAAO,uBAEnB,SADoBC,oBAAAA,eAAe,GAAG,QAAQ,CAAC,CAAC,IAAI,OAAO,IAAI,CAAC,EAAE,SAAA,EAC7C,SAAS,OAAO,CAAC,GAAG,GAAG,YAAY,GAAG,GAAG,KAAK,CAAC,CAAC,CAAC,MAAM,MAAM,EAAE,cAAc,IAAI;GAExG,IAAI,CAAC,OAAO,eAAA,OAAO,KAAK,uCAAuC,WAAW,GAAG,MAAM;EACrF;EAGA,MAAM,YAAY;GAChB,GAAG,OAAO;GACV,GAAG,OAAO;GACV,GAAG,OAAO;GACV,GAAG,OAAO;GACV,GAAG,OAAO;GACV,GAAG,OAAO;GACV,GAAG,OAAO;GACV,GAAG,OAAO;EACZ;EACA,KAAK,MAAM,CAAC,MAAM,MAAM,OAAO,QAAQ,aAAa,aAAa,CAAC,CAAC,GAAG;GACpE,IAAI,WAAW,UAAU,MAAM,MAAM,EAAE,cAAc,IAAI;GAEzD,IAAI,CAAC,YAAY,OAAO,uBAEtB,YADoBA,oBAAAA,eAAe,GAAG,QAAQ,CAAC,CAAC,IAAI,OAAO,IAAI,CAAC,EAAE,SAAA,EAE9D,SAAS,WAAW;IACpB,GAAG,OAAO;IACV,GAAG,OAAO;IACV,GAAG,OAAO;IACV,GAAG,OAAO;IACV,GAAG,OAAO;IACV,GAAG,OAAO;IACV,GAAG,OAAO;GACZ,CAAC,CAAC,EACA,MAAM,MAAM,EAAE,cAAc,IAAI;GAGtC,IAAI,CAAC,YAAY,OAAO,UAAU;IAChC,MAAM,WAAW,OAAO;IACxB,WAAW;KACT,GAAG,SAAS;KACZ,GAAG,SAAS;KACZ,GAAG,SAAS;KACZ,GAAG,SAAS;KACZ,GAAG,SAAS;KACZ,GAAG,SAAS;KACZ,GAAG,SAAS;IACd,CAAC,CAAC,MAAM,MAAM,EAAE,cAAc,IAAI;GACpC;GAEA,IAAI,CAAC,UAAU,eAAA,OAAO,KAAK,0CAA0C,WAAW,GAAG,MAAM;EAC3F;EAEA,MAAM,eAAe;GACnB,GAAG,OAAO;GACV,GAAG,OAAO;GACV,GAAG,OAAO;GACV,GAAG,OAAO;GACV,GAAG,OAAO;EACZ;EACA,KAAK,MAAM,YAAY,aAAa,YAAY,CAAC,GAC/C,KAAK,MAAM,QAAQ,UAAU;GAC3B,MAAM,QAAQ,aAAa,MAAM,MAAM,EAAE,cAAc,IAAI;GAC3D,IAAI,CAAC,OACH,eAAA,OAAO,KAAK,0DAA0D,WAAW,GAAG,MAAM;QACrF,IAAI,MAAM,SAAS,gBAAgB,MAAM,WAAW,MAAM,WAAW,MAAM,cAChF,eAAA,OAAO,KAAK,kDAAkD,WAAW,GAAG,MAAM;QAC7E,IAAI,MAAM,SAAS,WAAW,MAAM,WAAW,MAAM,UAC1D,eAAA,OAAO,KAAK,6CAA6C,WAAW,GAAG,MAAM;EAEjF;CAEJ;AACF;AAEA,SAAgB,cAAc,QAAgB,QAAgB,WAA4B;CACxF,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,SAAS,UAAU,EAAE,YAAY;AACxE;AAEA,SAAgB,gBAAgB,QAAgB,QAAgB,WAA4B;CAC1F,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,SAAS,UAAU,EAAE,YAAY;AACxE;AAEA,SAAgB,oBAAoB,QAAgB,QAAgB,WAA4B;CAC9F,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,YAAY,UAAU,EAAE,YAAY;AAC3E;;AAGA,SAAgB,qBAAqB,QAAgB,QAAgB,WAA4B;CAC/F,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,YAAY,UAAU,EAAE,YAAY;AAC3E;AAEA,SAAgB,YAAY,QAAgB,QAAgB,WAA4B;CACtF,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,SAAS,UAAU,EAAE,cAAc;AAC1E;;AAGA,SAAgB,YAAY,QAAgB,QAAgB,WAA4B;CACtF,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,SAAS,UAAU,EAAE,SAAS;AACrE;AAEA,SAAgB,YAAY,QAAgB,QAAgB,WAAuC;CACjG,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,SAAS,UAAU,EAAE;AAC5D;AAEA,SAAgB,kBAAkB,QAAgB,QAAgB,WAAuC;CACvG,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,SAAS,UAAU,EAAE;AAC5D;AAEA,SAAgB,gBAAgB,QAAgB,QAAgB,WAAuC;CACrG,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,SAAS,UAAU,EAAE;AAC5D;AAEA,SAAgB,gBAAgB,QAAgB,QAAgB,WAAuC;CACrG,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,SAAS,UAAU,EAAE;AAC5D;AAEA,SAAgB,kBAAkB,QAAgB,QAAgB,WAA4B;CAC5F,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,YAAY,UAAU,EAAE,UAAU;AACzE;;AAGA,SAAgB,kBACd,QACA,QACA,WACmC;CACnC,OAAO,OAAO,SAAS,OAAO,KAAK,EAAE,YAAY,UAAU,EAAE;AAC/D;AAEA,SAAgB,eACd,QACA,QACA,WACA,UAAmB,OACnB,aAAsB,OACb;CACT,MAAM,SAAS,OAAO,SAAS,OAAO,KAAK,EAAE,SAAS,UAAU,EAAE,WAAW;CAC7E,IAAI,UAAU,WAAW,CAAC,YACxB,cAAA,KACE,iBAAiB,OAAO,KAAK,GAAG,UAAU,kGAC5C;CAEF,OAAO;AACT;AAEA,SAAgB,kBAAkB,QAAgB,QAAgB,WAA4B;CAC5F,MAAM,eAAe,OAAO,SAAS,OAAO,SAAS,CAAC;CAEtD,QADoB,aAAa,SAAS,cAAc,aAAa,YAAY,cAAc,CAAC,EAAA,CAC7E,eAAe;AACpC;AAEA,MAAM,aAAa;AAEnB,eAAsB,aAA8B;CAElD,IAAI,MADiBC,cAAAA,eAAe,GAAA,SAAG,OAAO,UAAU,CAAC,GAC7C;EACV,MAAM,UAAU,MAAM,GAAA,SAAG,SAAS,UAAU;EAC5C,MAAM,SAAS,OAAO,UAAU,sBAAsB,KAAK,MAAM,QAAQ,SAAS,CAAC,CAAC,CAAC;EACrF,IAAI,CAAC,OAAO,SACV,MAAM,IAAI,MACR,8BAA8B,OAAO,MAAM,OACxC,KAAK,OAAO,GAAG,GAAG,KAAK,IAAI,MAAM,CAAC,CAAC,KAAK,GAAG,EAAE,GAAG,GAAG,SAAS,CAAC,CAC7D,KAAK,IAAI,GACd;EAEF,OAAO,KAAK,+BAA+B,6BAA6B;EACxE,OAAO,OAAO;CAChB;CAEA,MAAM,UAAU,OAAO,MAAM,EAAE,gBAAgBC,uBAAAA,wBAAwB,EAAE,CAAC;CAC1E,QAAQ,+BAA+B,6BAA6B;CACpE,OAAO;AACT;;;;;;;AAQA,eAAsB,YAAY,QAA+B;CAC/D,MAAM,SAA0BC,cAAAA,SAAS,MAAM;CAC/C,OAAO,OAAO;CACd,OAAO,OAAO;CACd,IAAI,OAAO,oBAAoB,UAC7B,OAAO,OAAO;CAEhB,MAAM,QAAQ,KAAK,UAAU,MAAM;CACnC,MAAM,UAAU,cAAc,WAAW;EAAE,UAAU;EAAa,UAAU;CAAM,CAAC;CACnF,MAAM,GAAA,SAAG,UAAU,YAAY,OAAO;AACxC;AAEA,SAAgB,qBAAqB,QAAgB,UAAoC;CAIvF,KAAK,MAAM,UAAU,UACnB,IAAI,OAAO,oBAAoB,SAAS,OAAO,uBAC7C,OAAO,OAAO,SAAS,OAAO;AAGpC;;AAGA,SAAgB,mBAAmB,QAIjC;CACA,OAAO;EACL,eAAe;GACb,OAAO,CAAC,cAAc,WAAW;GACjC,UAAU;GACV,GAAG,QAAQ,kBAAkB;EAC/B;EACA,eAAe;GACb,OAAO,CAAC,cAAc,WAAW;GACjC,UAAU;GACV,GAAG,QAAQ,kBAAkB;EAC/B;EACA,eAAe;GACb,OAAO,CAAC,cAAc,WAAW;GACjC,UAAU;GACV,GAAG,QAAQ,kBAAkB;EAC/B;CACF;AACF;AAEA,SAAS,+BAAwC;CAE/C,MAAM,aAAa,iBAAiB,QAAQ,IAAI,CAAC;CACjD,IAAI,CAAC,YACH,OAAO;CAET,IAAI;EAGF,MAAM,SAAuB,CAAC;EAC9B,MAAM,UAAA,GAAkBC,aAAAA,MAAAA,EAAAA,GAAMR,GAAAA,aAAAA,CAAa,YAAY,MAAM,GAAG,QAAQ,EAAE,oBAAoB,KAAK,CAAC;EACpG,IAAI,OAAO,SAAS,KAAK,OAAO,WAAW,YAAY,WAAW,QAAQ,MAAM,QAAQ,MAAM,GAAG,OAAO;EACxG,MAAM,kBAAmB,OAAmC;EAC5D,OACE,OAAO,oBAAoB,YAC3B,oBAAoB,QACpB,CAAC,MAAM,QAAQ,eAAe,KAC7B,gBAA4C,+BAA+B;CAEhF,QAAQ;EACN,OAAO;CACT;AACF;;AAGA,SAAS,wBAAwB,UAAsD;CACrF,IAAI,OAAO,aAAa,UAAU,OAAO,CAAC,CAAC,QAAQ,CAAC;CACpD,IAAI,SAAS,OAAO,UAAU,OAAO,UAAU,QAAQ,GAAG,OAAO,CAAC,QAAQ;CAC1E,OAAO;AACT;AAEA,SAAS,sBAAsB,KAAuB;CACpD,IAAI,CAAC,OAAO,OAAO,QAAQ,YAAY,MAAM,QAAQ,GAAG,GACtD,OAAO;CAGT,MAAM,SAAS,EAAE,GAAI,IAAgC;CACrD,OAAO,OAAO;CACd,OAAO;AACT;;AAGA,SAAS,iBAAiB,WAAuC;CAC/D,OAAO,MAAM;EACX,MAAM,YAAA,GAAWS,KAAAA,KAAAA,CAAK,WAAW,eAAe;EAChD,KAAA,GAAIC,GAAAA,WAAAA,CAAW,QAAQ,GAAG,OAAO;EACjC,MAAM,UAAA,GAASC,KAAAA,QAAAA,CAAQ,SAAS;EAChC,IAAI,WAAW,WAAW,OAAO,KAAA;EACjC,YAAY;CACd;AACF"}
|
|
1
|
+
{"version":3,"file":"config.cjs","names":["createFromBuffer","readFileSync","getPath","z","groupBy","getStiEntities","trueIfResolved","getLatestCodemodVersion","sortKeys","parse","join","existsSync","dirname"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, promises as fs, readFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\nimport { createFromBuffer } from \"@dprint/formatter\";\nimport { getPath } from \"@dprint/json\";\nimport { groupBy } from \"joist-utils\";\nimport { type ParseError, parse } from \"jsonc-parser\";\nimport { z } from \"zod\";\n\nimport { getLatestCodemodVersion } from \"./codemods/index.ts\";\nimport { type DbMetadata, type Entity, type EntityDbMetadata } from \"./EntityDbMetadata.ts\";\nimport { getStiEntities } from \"./inheritance.ts\";\nimport { logger } from \"./logger.ts\";\nimport { fail, sortKeys, trueIfResolved } from \"./utils.ts\";\n\nconst jsonFormatter = createFromBuffer(readFileSync(getPath()));\n\nconst fieldConfig = z\n .object({\n // For getters & ReactiveFields\n derived: z.optional(z.union([z.literal(\"sync\"), z.literal(\"async\")])),\n protected: z.optional(z.boolean()),\n ignore: z.optional(z.boolean()),\n superstruct: z.optional(z.string()),\n zodSchema: z.optional(z.string()),\n type: z.optional(z.string()),\n serde: z.optional(z.string()),\n stiDiscriminator: z.optional(z.record(z.string(), z.string())),\n stiType: z.optional(z.union([z.string(), z.array(z.string())])),\n // Allow subclasses to mark fields as required\n notNull: z.optional(z.boolean()),\n // Allow overriding scanEntities default detection for fields with defaults added by helpers\n hasDefault: z.optional(z.boolean()),\n // Exclude a (large jsonb/text) column from the default SELECT and expose it as a lazy-loaded LazyField\n lazy: z.optional(z.boolean()),\n })\n .strict();\n\nexport type FieldConfig = z.infer<typeof fieldConfig>;\n\nconst relationConfig = z\n .object({\n // For ReactiveReferences\n derived: z.optional(z.literal(\"async\")),\n polymorphic: z.optional(z.union([z.literal(\"notNull\"), z.literal(true)])),\n large: z.optional(z.boolean()),\n orderBy: z.optional(z.string()),\n /**\n * Controls whether this collection's `.get`/`.load` hide soft-deleted entities.\n *\n * Defaults to `\"exclude\"` (soft-deleted entities are hidden); set to `\"include\"` to have\n * this specific o2m/m2m always return soft-deleted entities from `.get`/`.load`.\n */\n softDeletes: z.optional(z.union([z.literal(\"include\"), z.literal(\"exclude\")])),\n // Allow pushing m2o/m2m/o2o relations in a base type (Task) down to a subtype (TaskOld)\n stiType: z.optional(z.union([z.string(), z.array(z.string())])),\n /**\n * Allow specializing a base type relation (SmallPublisher.group: SmallPublisherGroup).\n *\n * Self-referential FKs also support `subType: \"self\"` that means each subtype will point\n * at its own subtype.\n */\n subType: z.optional(z.string()),\n /** Allow skipping self-referential fields getting a `...Recursive` relation. */\n skipRecursiveRelations: z.optional(z.boolean()),\n // Allow marking m2o FKs as required on subclasses\n notNull: z.optional(z.boolean()),\n // Allow overriding scanEntities default detection for fields with defaults added by helpers\n hasDefault: z.optional(z.boolean()),\n })\n .strict();\n\nexport type RelationConfig = z.infer<typeof relationConfig>;\n\nconst uniqueByConfig = z\n .union([z.string(), z.array(z.string()), z.array(z.array(z.string()))])\n .transform(normalizeUniqueByConfig);\n\nconst entityConfig = z\n .object({\n tag: z.string(),\n tableName: z.optional(z.string()),\n fields: z.optional(z.record(z.string(), fieldConfig)),\n relations: z.optional(z.record(z.string(), relationConfig)),\n /** Whether this entity should be abstract, e.g. for inheritance a subtype must be instantiated instead of this type. */\n abstract: z.optional(z.boolean()),\n orderBy: z.optional(z.string()),\n uniqueBy: z.optional(uniqueByConfig),\n })\n .strict();\n\nexport type EntityConfig = z.infer<typeof entityConfig>;\n\nconst timestampConfig = z\n .object({\n /** The names to check for this timestamp, i.e. `created_at` `created`, etc. */\n names: z.array(z.string()),\n /** Whether this timestamp column is required to consider a table an entity, defaults to `false`. */\n required: z.optional(z.boolean()),\n })\n .strict();\n\nexport type TimestampConfig = z.infer<typeof timestampConfig>;\n\nexport const config = z\n .object({\n /** The _build-time_ database URL for reading database metadata. */\n databaseUrl: z.optional(z.string()),\n /** Your application's request-level `Context` type. */\n contextType: z.optional(z.string()),\n /** Your application's database client's `Transaction` type. */\n transactionType: z.optional(z.string()),\n /**\n * Allows the user to specify the `updated_at` / `created_at` column names to look up, and if they're optional.\n *\n * We default to looking for `updated_at`, `updatedAt`, `created_at`, `createdAt`, and optional to true,\n * e.g. tables are not required to have both timestamp columns to be considered entities.\n *\n * These defaults are the most lenient, to facilitate running Joist against an existing schema and\n * seeing all of your entities, regardless of your previous conventions.\n */\n timestampColumns: z.optional(\n z.object({\n createdAt: z.optional(timestampConfig),\n updatedAt: z.optional(timestampConfig),\n deletedAt: z.optional(timestampConfig),\n }),\n ),\n /**\n * Allows the user to have codegen output `Temporal` types instead of the base JS `Date`\n *\n * Additionally, allows for specifying the default time zone for `Temporal` types when converting dates to/from\n * the database.\n */\n temporal: z.optional(z.union([z.boolean(), z.object({ timeZone: z.string() })])),\n /**\n * By default, we create a `flush_database` function for fast testing.\n *\n * However, if you don't want to use this, or you have your own bespoke function like we do\n * that is more application-aware, then you can disable Joist's out-of-the-box one.\n *\n * If you have more than one test database, you can set `createFlushFunction` to the array\n * of test database names, i.e. `mydb_test_1`, `mydb_test_2`, etc.\n */\n createFlushFunction: z.optional(z.union([z.boolean(), z.array(z.string())])),\n entitiesDirectory: z.string().default(\"./src/entities\"),\n codegenPlugins: z.optional(z.array(z.string())),\n entities: z.record(z.string(), entityConfig).default({}),\n ignoredTables: z.optional(z.array(z.string())),\n /** The type of entity `id` fields; defaults to `tagged-string`. */\n idType: z.optional(z.union([z.literal(\"tagged-string\"), z.literal(\"untagged-string\"), z.literal(\"number\")])),\n /** The separator between entity tags and ids; defaults to `:`, and `\"\"` disables the separator. */\n tagDelimiter: z.optional(z.string()),\n /** How we should support non-deferred foreign keys. */\n nonDeferredForeignKeys: z.optional(z.union([z.literal(\"error\"), z.literal(\"warn\"), z.literal(\"ignore\")])),\n /** Enables esm output. */\n esm: z.optional(z.boolean()),\n /** Controls the style of GraphQL pagination scaffolding. */\n paginationStyle: z.optional(z.union([z.literal(\"cursor\"), z.literal(\"limit\")])).default(\"cursor\"),\n /** Enables documentation syncing between .md files and JSDocs. */\n docs: z.optional(z.boolean()),\n /** Installs Joist's bundled Agent Skills into `.claude/skills` and `.agents/skills`; on by default, set `false` to disable. */\n skills: z.optional(z.boolean()),\n /** Output a metadata-docs.ts file with entity/field documentation available at runtime. */\n outputDocs: z.optional(z.boolean()),\n /** Auto-set by probing the project's `tsconfig.json` file. */\n allowImportingTsExtensions: z.optional(z.boolean()),\n /** The latest Joist codemod counter that has been applied to this project. */\n codemodVersion: z.number().int().min(0).default(0),\n\n /** A list of postgres schemas to use for finding tables */\n schemas: z.optional(z.array(z.string())),\n })\n .strict();\n\nexport type Config = z.infer<typeof config> & {\n // We don't persist this, and instead just use it as a cache\n __tableToEntityName?: Record<string, string>;\n};\n\nexport const ormMaintainedFields = [\"createdAt\", \"updatedAt\"];\n\n/** Ensure the user doesn't have any typos in their config. */\nexport function warnInvalidConfigEntries(config: Config, db: DbMetadata): void {\n const entitiesByName = groupBy(db.entities, (e) => e.name);\n for (const [entityName, entityConfig] of Object.entries(config.entities)) {\n const entities = entitiesByName[entityName];\n if (!entities) {\n logger.warn(`Found config for non-existent entity ${entityName}`);\n continue;\n }\n // We don't have keyBy...\n const [entity] = entities;\n\n // Check fields\n const fields = [...entity.primitives, ...entity.enums];\n for (const [name, config] of Object.entries(entityConfig.fields || {})) {\n if (config.ignore) continue;\n let field = fields.find((f) => f.fieldName === name);\n // STI types might be in the base type\n if (!field && entity.stiDiscriminatorField) {\n const stiEntities = getStiEntities(db.entities).get(entity.name)?.subTypes;\n field = stiEntities?.flatMap((st) => [...st.primitives, ...st.enums]).find((f) => f.fieldName === name);\n }\n if (!field) logger.warn(`Found config for non-existent field ${entityName}.${name}`);\n }\n\n // Check relations\n const relations = [\n ...entity.manyToOnes,\n ...entity.oneToManys,\n ...entity.manyToManys,\n ...entity.manyToManyEnums,\n ...entity.oneToOnes,\n ...entity.largeOneToManys,\n ...entity.largeManyToManys,\n ...entity.polymorphics,\n ];\n for (const [name, _] of Object.entries(entityConfig.relations || {})) {\n let relation = relations.find((r) => r.fieldName === name);\n // STI types might be in the subtypes\n if (!relation && entity.stiDiscriminatorField) {\n const stiEntities = getStiEntities(db.entities).get(entity.name)?.subTypes;\n relation = stiEntities\n ?.flatMap((entity) => [\n ...entity.manyToOnes,\n ...entity.oneToManys,\n ...entity.manyToManys,\n ...entity.oneToOnes,\n ...entity.largeOneToManys,\n ...entity.largeManyToManys,\n ...entity.polymorphics,\n ])\n ?.find((f) => f.fieldName === name);\n }\n // CTI subtype specializations (i.e. SmallPublisher.group: SmallPublisherGroup) need to look in the base type\n if (!relation && entity.baseType) {\n const baseType = entity.baseType;\n relation = [\n ...baseType.manyToOnes,\n ...baseType.oneToManys,\n ...baseType.manyToManys,\n ...baseType.oneToOnes,\n ...baseType.largeOneToManys,\n ...baseType.largeManyToManys,\n ...baseType.polymorphics,\n ].find((f) => f.fieldName === name);\n }\n\n if (!relation) logger.warn(`Found config for non-existent relation ${entityName}.${name}`);\n }\n\n const uniqueFields = [\n ...entity.primitives,\n ...entity.enums,\n ...entity.pgEnums,\n ...entity.manyToOnes,\n ...entity.polymorphics,\n ];\n for (const uniqueBy of entityConfig.uniqueBy || []) {\n for (const name of uniqueBy) {\n const field = uniqueFields.find((f) => f.fieldName === name);\n if (!field) {\n logger.warn(`Found uniqueBy for non-existent or non-queryable field ${entityName}.${name}`);\n } else if (field.kind === \"primitive\" && (field.derived || field.isArray || field.customSerde)) {\n logger.warn(`Found uniqueBy for unsupported primitive field ${entityName}.${name}`);\n } else if (field.kind === \"enum\" && (field.derived || field.isArray)) {\n logger.warn(`Found uniqueBy for unsupported enum field ${entityName}.${name}`);\n }\n }\n }\n }\n}\n\nexport function isGetterField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.derived === \"sync\";\n}\n\nexport function isReactiveField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.derived === \"async\";\n}\n\nexport function isReactiveReference(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.derived === \"async\";\n}\n\n/** Returns true if this m2m relation is configured as a ReactiveManyToMany (derived: async). */\nexport function isReactiveManyToMany(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.derived === \"async\";\n}\n\nexport function isProtected(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.protected === true;\n}\n\n/** Whether a column should be excluded from the default SELECT and exposed as a lazy-loaded `LazyField`. */\nexport function isLazyField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.lazy === true;\n}\n\nexport function serdeConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.serde;\n}\n\nexport function superstructConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.superstruct;\n}\n\nexport function zodSchemaConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.zodSchema;\n}\n\nexport function fieldTypeConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.type;\n}\n\nexport function isLargeCollection(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.large === true;\n}\n\n/** Whether a collection should include (or exclude) soft-deleted entities from `.get`/`.load`. */\nexport function softDeletesConfig(\n config: Config,\n entity: Entity,\n fieldName: string,\n): \"include\" | \"exclude\" | undefined {\n return config.entities[entity.name]?.relations?.[fieldName]?.softDeletes;\n}\n\nexport function isFieldIgnored(\n config: Config,\n entity: Entity,\n fieldName: string,\n notNull: boolean = false,\n hasDefault: boolean = false,\n): boolean {\n const ignore = config.entities[entity.name]?.fields?.[fieldName]?.ignore === true;\n if (ignore && notNull && !hasDefault) {\n fail(\n `notNull field ${entity.name}.${fieldName} cannot be ignored. Alter the column to be optional or have a default value prior to ignoring it.`,\n );\n }\n return ignore;\n}\n\nexport function isFieldHasDefault(config: Config, entity: Entity, fieldName: string): boolean {\n const entityConfig = config.entities[entity.name] ?? {};\n const fieldConfig = entityConfig.fields?.[fieldName] ?? entityConfig.relations?.[fieldName] ?? {};\n return fieldConfig.hasDefault === true;\n}\n\nconst configPath = \"./joist-config.json\";\n\nexport async function loadConfig(): Promise<Config> {\n const exists = await trueIfResolved(fs.access(configPath));\n if (exists) {\n const content = await fs.readFile(configPath);\n const result = config.safeParse(stripLegacyConfigKeys(JSON.parse(content.toString())));\n if (!result.success) {\n throw new Error(\n `Invalid joist-config.json: ${result.error.issues\n .map((ze) => `${ze.path.map(String).join(\"/\")} ${ze.message}`)\n .join(\"\\n\")}`,\n );\n }\n result.data.allowImportingTsExtensions ??= projectIsUsingEsmWithImports();\n return result.data;\n }\n // Brand-new projects should not be prompted to run historical codemods.\n const initial = config.parse({ codemodVersion: getLatestCodemodVersion() });\n initial.allowImportingTsExtensions ??= projectIsUsingEsmWithImports();\n return initial;\n}\n\n/**\n * Writes the potentially-updated config entry back to `joist-config.json`.\n *\n * We format the output with prettier so it should both a) look nice and b) be deterministic,\n * such that no changes to the config show up as noops to the scm.\n */\nexport async function writeConfig(config: Config): Promise<void> {\n const sorted: Partial<Config> = sortKeys(config);\n delete sorted.__tableToEntityName;\n delete sorted.allowImportingTsExtensions;\n if (sorted.paginationStyle === \"cursor\") {\n delete sorted.paginationStyle;\n }\n const input = JSON.stringify(sorted);\n const content = jsonFormatter.formatText({ filePath: \"test.json\", fileText: input });\n await fs.writeFile(configPath, content);\n}\n\nexport function stripStiPlaceholders(config: Config, entities: EntityDbMetadata[]): void {\n // Defacto (with today's setup) the config of STI entities lives on the base entity,\n // so don't write confusing subtype-specific entries into the config file.\n // ...hopefully we don't have any code accidentally looking for the STI config...\n for (const entity of entities) {\n if (entity.inheritanceType === \"sti\" && entity.stiDiscriminatorValue) {\n delete config.entities[entity.name];\n }\n }\n}\n\n/** Applies defaults to the timestamp config. */\nexport function getTimestampConfig(config: Config): {\n updatedAtConf: Required<TimestampConfig>;\n createdAtConf: Required<TimestampConfig>;\n deletedAtConf: Required<TimestampConfig>;\n} {\n return {\n createdAtConf: {\n names: [\"created_at\", \"createdAt\"],\n required: false,\n ...config?.timestampColumns?.createdAt,\n },\n updatedAtConf: {\n names: [\"updated_at\", \"updatedAt\"],\n required: false,\n ...config?.timestampColumns?.updatedAt,\n },\n deletedAtConf: {\n names: [\"deleted_at\", \"deletedAt\"],\n required: false,\n ...config?.timestampColumns?.deletedAt,\n },\n };\n}\n\nfunction projectIsUsingEsmWithImports(): boolean {\n // Attempt to find the project's tsconfig.json in the current directory or up the directory hierarchy\n const configPath = findTsConfigFile(process.cwd());\n if (!configPath) {\n return false;\n }\n try {\n // Use jsonc-parser to parse the tsconfig.json file (not the old tsc readConfigFile which was\n // dropped in TypeScript 7), allowing for comments and trailing commas.\n const errors: ParseError[] = [];\n const parsed: unknown = parse(readFileSync(configPath, \"utf8\"), errors, { allowTrailingComma: true });\n if (errors.length > 0 || typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) return false;\n const compilerOptions = (parsed as Record<string, unknown>).compilerOptions;\n return (\n typeof compilerOptions === \"object\" &&\n compilerOptions !== null &&\n !Array.isArray(compilerOptions) &&\n (compilerOptions as Record<string, unknown>).allowImportingTsExtensions === true\n );\n } catch {\n return false;\n }\n}\n\n/** Normalizes `uniqueBy` config sugar into runtime identity candidates. */\nfunction normalizeUniqueByConfig(uniqueBy: string | string[] | string[][]): string[][] {\n if (typeof uniqueBy === \"string\") return [[uniqueBy]];\n if (uniqueBy.every((field) => typeof field === \"string\")) return [uniqueBy];\n return uniqueBy;\n}\n\nfunction stripLegacyConfigKeys(raw: unknown): unknown {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n return raw;\n }\n // Accept old configs so the deprecated key disappears on the next write.\n const parsed = { ...(raw as Record<string, unknown>) };\n delete parsed.version;\n return parsed;\n}\n\n/** Finds the nearest `tsconfig.json` in `directory` or one of its ancestors. */\nfunction findTsConfigFile(directory: string): string | undefined {\n while (true) {\n const fileName = join(directory, \"tsconfig.json\");\n if (existsSync(fileName)) return fileName;\n const parent = dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n"],"mappings":"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"}
|
package/build/config.d.cts
CHANGED
|
@@ -10,7 +10,7 @@ declare const fieldConfig: z.ZodObject<{
|
|
|
10
10
|
type: z.ZodOptional<z.ZodString>;
|
|
11
11
|
serde: z.ZodOptional<z.ZodString>;
|
|
12
12
|
stiDiscriminator: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
13
|
-
stiType: z.ZodOptional<z.ZodString
|
|
13
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
14
14
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
|
15
15
|
hasDefault: z.ZodOptional<z.ZodBoolean>;
|
|
16
16
|
lazy: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -22,7 +22,7 @@ declare const relationConfig: z.ZodObject<{
|
|
|
22
22
|
large: z.ZodOptional<z.ZodBoolean>;
|
|
23
23
|
orderBy: z.ZodOptional<z.ZodString>;
|
|
24
24
|
softDeletes: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"include">, z.ZodLiteral<"exclude">]>>;
|
|
25
|
-
stiType: z.ZodOptional<z.ZodString
|
|
25
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
26
26
|
subType: z.ZodOptional<z.ZodString>;
|
|
27
27
|
skipRecursiveRelations: z.ZodOptional<z.ZodBoolean>;
|
|
28
28
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -41,7 +41,7 @@ declare const entityConfig: z.ZodObject<{
|
|
|
41
41
|
type: z.ZodOptional<z.ZodString>;
|
|
42
42
|
serde: z.ZodOptional<z.ZodString>;
|
|
43
43
|
stiDiscriminator: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
44
|
-
stiType: z.ZodOptional<z.ZodString
|
|
44
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
45
45
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
|
46
46
|
hasDefault: z.ZodOptional<z.ZodBoolean>;
|
|
47
47
|
lazy: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -52,7 +52,7 @@ declare const entityConfig: z.ZodObject<{
|
|
|
52
52
|
large: z.ZodOptional<z.ZodBoolean>;
|
|
53
53
|
orderBy: z.ZodOptional<z.ZodString>;
|
|
54
54
|
softDeletes: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"include">, z.ZodLiteral<"exclude">]>>;
|
|
55
|
-
stiType: z.ZodOptional<z.ZodString
|
|
55
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
56
56
|
subType: z.ZodOptional<z.ZodString>;
|
|
57
57
|
skipRecursiveRelations: z.ZodOptional<z.ZodBoolean>;
|
|
58
58
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -104,7 +104,7 @@ declare const config: z.ZodObject<{
|
|
|
104
104
|
type: z.ZodOptional<z.ZodString>;
|
|
105
105
|
serde: z.ZodOptional<z.ZodString>;
|
|
106
106
|
stiDiscriminator: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
107
|
-
stiType: z.ZodOptional<z.ZodString
|
|
107
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
108
108
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
|
109
109
|
hasDefault: z.ZodOptional<z.ZodBoolean>;
|
|
110
110
|
lazy: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -115,7 +115,7 @@ declare const config: z.ZodObject<{
|
|
|
115
115
|
large: z.ZodOptional<z.ZodBoolean>;
|
|
116
116
|
orderBy: z.ZodOptional<z.ZodString>;
|
|
117
117
|
softDeletes: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"include">, z.ZodLiteral<"exclude">]>>;
|
|
118
|
-
stiType: z.ZodOptional<z.ZodString
|
|
118
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
119
119
|
subType: z.ZodOptional<z.ZodString>;
|
|
120
120
|
skipRecursiveRelations: z.ZodOptional<z.ZodBoolean>;
|
|
121
121
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
package/build/config.d.mts
CHANGED
|
@@ -10,7 +10,7 @@ declare const fieldConfig: z.ZodObject<{
|
|
|
10
10
|
type: z.ZodOptional<z.ZodString>;
|
|
11
11
|
serde: z.ZodOptional<z.ZodString>;
|
|
12
12
|
stiDiscriminator: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
13
|
-
stiType: z.ZodOptional<z.ZodString
|
|
13
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
14
14
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
|
15
15
|
hasDefault: z.ZodOptional<z.ZodBoolean>;
|
|
16
16
|
lazy: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -22,7 +22,7 @@ declare const relationConfig: z.ZodObject<{
|
|
|
22
22
|
large: z.ZodOptional<z.ZodBoolean>;
|
|
23
23
|
orderBy: z.ZodOptional<z.ZodString>;
|
|
24
24
|
softDeletes: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"include">, z.ZodLiteral<"exclude">]>>;
|
|
25
|
-
stiType: z.ZodOptional<z.ZodString
|
|
25
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
26
26
|
subType: z.ZodOptional<z.ZodString>;
|
|
27
27
|
skipRecursiveRelations: z.ZodOptional<z.ZodBoolean>;
|
|
28
28
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -41,7 +41,7 @@ declare const entityConfig: z.ZodObject<{
|
|
|
41
41
|
type: z.ZodOptional<z.ZodString>;
|
|
42
42
|
serde: z.ZodOptional<z.ZodString>;
|
|
43
43
|
stiDiscriminator: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
44
|
-
stiType: z.ZodOptional<z.ZodString
|
|
44
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
45
45
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
|
46
46
|
hasDefault: z.ZodOptional<z.ZodBoolean>;
|
|
47
47
|
lazy: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -52,7 +52,7 @@ declare const entityConfig: z.ZodObject<{
|
|
|
52
52
|
large: z.ZodOptional<z.ZodBoolean>;
|
|
53
53
|
orderBy: z.ZodOptional<z.ZodString>;
|
|
54
54
|
softDeletes: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"include">, z.ZodLiteral<"exclude">]>>;
|
|
55
|
-
stiType: z.ZodOptional<z.ZodString
|
|
55
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
56
56
|
subType: z.ZodOptional<z.ZodString>;
|
|
57
57
|
skipRecursiveRelations: z.ZodOptional<z.ZodBoolean>;
|
|
58
58
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -104,7 +104,7 @@ declare const config: z.ZodObject<{
|
|
|
104
104
|
type: z.ZodOptional<z.ZodString>;
|
|
105
105
|
serde: z.ZodOptional<z.ZodString>;
|
|
106
106
|
stiDiscriminator: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodString>>;
|
|
107
|
-
stiType: z.ZodOptional<z.ZodString
|
|
107
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
108
108
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
|
109
109
|
hasDefault: z.ZodOptional<z.ZodBoolean>;
|
|
110
110
|
lazy: z.ZodOptional<z.ZodBoolean>;
|
|
@@ -115,7 +115,7 @@ declare const config: z.ZodObject<{
|
|
|
115
115
|
large: z.ZodOptional<z.ZodBoolean>;
|
|
116
116
|
orderBy: z.ZodOptional<z.ZodString>;
|
|
117
117
|
softDeletes: z.ZodOptional<z.ZodUnion<readonly [z.ZodLiteral<"include">, z.ZodLiteral<"exclude">]>>;
|
|
118
|
-
stiType: z.ZodOptional<z.ZodString
|
|
118
|
+
stiType: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodArray<z.ZodString>]>>;
|
|
119
119
|
subType: z.ZodOptional<z.ZodString>;
|
|
120
120
|
skipRecursiveRelations: z.ZodOptional<z.ZodBoolean>;
|
|
121
121
|
notNull: z.ZodOptional<z.ZodBoolean>;
|
package/build/config.js
CHANGED
|
@@ -21,7 +21,7 @@ const fieldConfig = z.object({
|
|
|
21
21
|
type: z.optional(z.string()),
|
|
22
22
|
serde: z.optional(z.string()),
|
|
23
23
|
stiDiscriminator: z.optional(z.record(z.string(), z.string())),
|
|
24
|
-
stiType: z.optional(z.string()),
|
|
24
|
+
stiType: z.optional(z.union([z.string(), z.array(z.string())])),
|
|
25
25
|
notNull: z.optional(z.boolean()),
|
|
26
26
|
hasDefault: z.optional(z.boolean()),
|
|
27
27
|
lazy: z.optional(z.boolean())
|
|
@@ -38,7 +38,7 @@ const relationConfig = z.object({
|
|
|
38
38
|
* this specific o2m/m2m always return soft-deleted entities from `.get`/`.load`.
|
|
39
39
|
*/
|
|
40
40
|
softDeletes: z.optional(z.union([z.literal("include"), z.literal("exclude")])),
|
|
41
|
-
stiType: z.optional(z.string()),
|
|
41
|
+
stiType: z.optional(z.union([z.string(), z.array(z.string())])),
|
|
42
42
|
/**
|
|
43
43
|
* Allow specializing a base type relation (SmallPublisher.group: SmallPublisherGroup).
|
|
44
44
|
*
|
package/build/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","names":["fs"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, promises as fs, readFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\nimport { createFromBuffer } from \"@dprint/formatter\";\nimport { getPath } from \"@dprint/json\";\nimport { groupBy } from \"joist-utils\";\nimport { type ParseError, parse } from \"jsonc-parser\";\nimport { z } from \"zod\";\n\nimport { getLatestCodemodVersion } from \"./codemods/index.ts\";\nimport { type DbMetadata, type Entity, type EntityDbMetadata } from \"./EntityDbMetadata.ts\";\nimport { getStiEntities } from \"./inheritance.ts\";\nimport { logger } from \"./logger.ts\";\nimport { fail, sortKeys, trueIfResolved } from \"./utils.ts\";\n\nconst jsonFormatter = createFromBuffer(readFileSync(getPath()));\n\nconst fieldConfig = z\n .object({\n // For getters & ReactiveFields\n derived: z.optional(z.union([z.literal(\"sync\"), z.literal(\"async\")])),\n protected: z.optional(z.boolean()),\n ignore: z.optional(z.boolean()),\n superstruct: z.optional(z.string()),\n zodSchema: z.optional(z.string()),\n type: z.optional(z.string()),\n serde: z.optional(z.string()),\n stiDiscriminator: z.optional(z.record(z.string(), z.string())),\n stiType: z.optional(z.string()),\n // Allow subclasses to mark fields as required\n notNull: z.optional(z.boolean()),\n // Allow overriding scanEntities default detection for fields with defaults added by helpers\n hasDefault: z.optional(z.boolean()),\n // Exclude a (large jsonb/text) column from the default SELECT and expose it as a lazy-loaded LazyField\n lazy: z.optional(z.boolean()),\n })\n .strict();\n\nexport type FieldConfig = z.infer<typeof fieldConfig>;\n\nconst relationConfig = z\n .object({\n // For ReactiveReferences\n derived: z.optional(z.literal(\"async\")),\n polymorphic: z.optional(z.union([z.literal(\"notNull\"), z.literal(true)])),\n large: z.optional(z.boolean()),\n orderBy: z.optional(z.string()),\n /**\n * Controls whether this collection's `.get`/`.load` hide soft-deleted entities.\n *\n * Defaults to `\"exclude\"` (soft-deleted entities are hidden); set to `\"include\"` to have\n * this specific o2m/m2m always return soft-deleted entities from `.get`/`.load`.\n */\n softDeletes: z.optional(z.union([z.literal(\"include\"), z.literal(\"exclude\")])),\n // Allow pushing m2o/m2m/o2o relations in a base type (Task) down to a subtype (TaskOld)\n stiType: z.optional(z.string()),\n /**\n * Allow specializing a base type relation (SmallPublisher.group: SmallPublisherGroup).\n *\n * Self-referential FKs also support `subType: \"self\"` that means each subtype will point\n * at its own subtype.\n */\n subType: z.optional(z.string()),\n /** Allow skipping self-referential fields getting a `...Recursive` relation. */\n skipRecursiveRelations: z.optional(z.boolean()),\n // Allow marking m2o FKs as required on subclasses\n notNull: z.optional(z.boolean()),\n // Allow overriding scanEntities default detection for fields with defaults added by helpers\n hasDefault: z.optional(z.boolean()),\n })\n .strict();\n\nexport type RelationConfig = z.infer<typeof relationConfig>;\n\nconst uniqueByConfig = z\n .union([z.string(), z.array(z.string()), z.array(z.array(z.string()))])\n .transform(normalizeUniqueByConfig);\n\nconst entityConfig = z\n .object({\n tag: z.string(),\n tableName: z.optional(z.string()),\n fields: z.optional(z.record(z.string(), fieldConfig)),\n relations: z.optional(z.record(z.string(), relationConfig)),\n /** Whether this entity should be abstract, e.g. for inheritance a subtype must be instantiated instead of this type. */\n abstract: z.optional(z.boolean()),\n orderBy: z.optional(z.string()),\n uniqueBy: z.optional(uniqueByConfig),\n })\n .strict();\n\nexport type EntityConfig = z.infer<typeof entityConfig>;\n\nconst timestampConfig = z\n .object({\n /** The names to check for this timestamp, i.e. `created_at` `created`, etc. */\n names: z.array(z.string()),\n /** Whether this timestamp column is required to consider a table an entity, defaults to `false`. */\n required: z.optional(z.boolean()),\n })\n .strict();\n\nexport type TimestampConfig = z.infer<typeof timestampConfig>;\n\nexport const config = z\n .object({\n /** The _build-time_ database URL for reading database metadata. */\n databaseUrl: z.optional(z.string()),\n /** Your application's request-level `Context` type. */\n contextType: z.optional(z.string()),\n /** Your application's database client's `Transaction` type. */\n transactionType: z.optional(z.string()),\n /**\n * Allows the user to specify the `updated_at` / `created_at` column names to look up, and if they're optional.\n *\n * We default to looking for `updated_at`, `updatedAt`, `created_at`, `createdAt`, and optional to true,\n * e.g. tables are not required to have both timestamp columns to be considered entities.\n *\n * These defaults are the most lenient, to facilitate running Joist against an existing schema and\n * seeing all of your entities, regardless of your previous conventions.\n */\n timestampColumns: z.optional(\n z.object({\n createdAt: z.optional(timestampConfig),\n updatedAt: z.optional(timestampConfig),\n deletedAt: z.optional(timestampConfig),\n }),\n ),\n /**\n * Allows the user to have codegen output `Temporal` types instead of the base JS `Date`\n *\n * Additionally, allows for specifying the default time zone for `Temporal` types when converting dates to/from\n * the database.\n */\n temporal: z.optional(z.union([z.boolean(), z.object({ timeZone: z.string() })])),\n /**\n * By default, we create a `flush_database` function for fast testing.\n *\n * However, if you don't want to use this, or you have your own bespoke function like we do\n * that is more application-aware, then you can disable Joist's out-of-the-box one.\n *\n * If you have more than one test database, you can set `createFlushFunction` to the array\n * of test database names, i.e. `mydb_test_1`, `mydb_test_2`, etc.\n */\n createFlushFunction: z.optional(z.union([z.boolean(), z.array(z.string())])),\n entitiesDirectory: z.string().default(\"./src/entities\"),\n codegenPlugins: z.optional(z.array(z.string())),\n entities: z.record(z.string(), entityConfig).default({}),\n ignoredTables: z.optional(z.array(z.string())),\n /** The type of entity `id` fields; defaults to `tagged-string`. */\n idType: z.optional(z.union([z.literal(\"tagged-string\"), z.literal(\"untagged-string\"), z.literal(\"number\")])),\n /** The separator between entity tags and ids; defaults to `:`, and `\"\"` disables the separator. */\n tagDelimiter: z.optional(z.string()),\n /** How we should support non-deferred foreign keys. */\n nonDeferredForeignKeys: z.optional(z.union([z.literal(\"error\"), z.literal(\"warn\"), z.literal(\"ignore\")])),\n /** Enables esm output. */\n esm: z.optional(z.boolean()),\n /** Controls the style of GraphQL pagination scaffolding. */\n paginationStyle: z.optional(z.union([z.literal(\"cursor\"), z.literal(\"limit\")])).default(\"cursor\"),\n /** Enables documentation syncing between .md files and JSDocs. */\n docs: z.optional(z.boolean()),\n /** Installs Joist's bundled Agent Skills into `.claude/skills` and `.agents/skills`; on by default, set `false` to disable. */\n skills: z.optional(z.boolean()),\n /** Output a metadata-docs.ts file with entity/field documentation available at runtime. */\n outputDocs: z.optional(z.boolean()),\n /** Auto-set by probing the project's `tsconfig.json` file. */\n allowImportingTsExtensions: z.optional(z.boolean()),\n /** The latest Joist codemod counter that has been applied to this project. */\n codemodVersion: z.number().int().min(0).default(0),\n\n /** A list of postgres schemas to use for finding tables */\n schemas: z.optional(z.array(z.string())),\n })\n .strict();\n\nexport type Config = z.infer<typeof config> & {\n // We don't persist this, and instead just use it as a cache\n __tableToEntityName?: Record<string, string>;\n};\n\nexport const ormMaintainedFields = [\"createdAt\", \"updatedAt\"];\n\n/** Ensure the user doesn't have any typos in their config. */\nexport function warnInvalidConfigEntries(config: Config, db: DbMetadata): void {\n const entitiesByName = groupBy(db.entities, (e) => e.name);\n for (const [entityName, entityConfig] of Object.entries(config.entities)) {\n const entities = entitiesByName[entityName];\n if (!entities) {\n logger.warn(`Found config for non-existent entity ${entityName}`);\n continue;\n }\n // We don't have keyBy...\n const [entity] = entities;\n\n // Check fields\n const fields = [...entity.primitives, ...entity.enums];\n for (const [name, config] of Object.entries(entityConfig.fields || {})) {\n if (config.ignore) continue;\n let field = fields.find((f) => f.fieldName === name);\n // STI types might be in the base type\n if (!field && entity.stiDiscriminatorField) {\n const stiEntities = getStiEntities(db.entities).get(entity.name)?.subTypes;\n field = stiEntities?.flatMap((st) => [...st.primitives, ...st.enums]).find((f) => f.fieldName === name);\n }\n if (!field) logger.warn(`Found config for non-existent field ${entityName}.${name}`);\n }\n\n // Check relations\n const relations = [\n ...entity.manyToOnes,\n ...entity.oneToManys,\n ...entity.manyToManys,\n ...entity.manyToManyEnums,\n ...entity.oneToOnes,\n ...entity.largeOneToManys,\n ...entity.largeManyToManys,\n ...entity.polymorphics,\n ];\n for (const [name, _] of Object.entries(entityConfig.relations || {})) {\n let relation = relations.find((r) => r.fieldName === name);\n // STI types might be in the subtypes\n if (!relation && entity.stiDiscriminatorField) {\n const stiEntities = getStiEntities(db.entities).get(entity.name)?.subTypes;\n relation = stiEntities\n ?.flatMap((entity) => [\n ...entity.manyToOnes,\n ...entity.oneToManys,\n ...entity.manyToManys,\n ...entity.oneToOnes,\n ...entity.largeOneToManys,\n ...entity.largeManyToManys,\n ...entity.polymorphics,\n ])\n ?.find((f) => f.fieldName === name);\n }\n // CTI subtype specializations (i.e. SmallPublisher.group: SmallPublisherGroup) need to look in the base type\n if (!relation && entity.baseType) {\n const baseType = entity.baseType;\n relation = [\n ...baseType.manyToOnes,\n ...baseType.oneToManys,\n ...baseType.manyToManys,\n ...baseType.oneToOnes,\n ...baseType.largeOneToManys,\n ...baseType.largeManyToManys,\n ...baseType.polymorphics,\n ].find((f) => f.fieldName === name);\n }\n\n if (!relation) logger.warn(`Found config for non-existent relation ${entityName}.${name}`);\n }\n\n const uniqueFields = [\n ...entity.primitives,\n ...entity.enums,\n ...entity.pgEnums,\n ...entity.manyToOnes,\n ...entity.polymorphics,\n ];\n for (const uniqueBy of entityConfig.uniqueBy || []) {\n for (const name of uniqueBy) {\n const field = uniqueFields.find((f) => f.fieldName === name);\n if (!field) {\n logger.warn(`Found uniqueBy for non-existent or non-queryable field ${entityName}.${name}`);\n } else if (field.kind === \"primitive\" && (field.derived || field.isArray || field.customSerde)) {\n logger.warn(`Found uniqueBy for unsupported primitive field ${entityName}.${name}`);\n } else if (field.kind === \"enum\" && (field.derived || field.isArray)) {\n logger.warn(`Found uniqueBy for unsupported enum field ${entityName}.${name}`);\n }\n }\n }\n }\n}\n\nexport function isGetterField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.derived === \"sync\";\n}\n\nexport function isReactiveField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.derived === \"async\";\n}\n\nexport function isReactiveReference(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.derived === \"async\";\n}\n\n/** Returns true if this m2m relation is configured as a ReactiveManyToMany (derived: async). */\nexport function isReactiveManyToMany(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.derived === \"async\";\n}\n\nexport function isProtected(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.protected === true;\n}\n\n/** Whether a column should be excluded from the default SELECT and exposed as a lazy-loaded `LazyField`. */\nexport function isLazyField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.lazy === true;\n}\n\nexport function serdeConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.serde;\n}\n\nexport function superstructConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.superstruct;\n}\n\nexport function zodSchemaConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.zodSchema;\n}\n\nexport function fieldTypeConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.type;\n}\n\nexport function isLargeCollection(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.large === true;\n}\n\n/** Whether a collection should include (or exclude) soft-deleted entities from `.get`/`.load`. */\nexport function softDeletesConfig(\n config: Config,\n entity: Entity,\n fieldName: string,\n): \"include\" | \"exclude\" | undefined {\n return config.entities[entity.name]?.relations?.[fieldName]?.softDeletes;\n}\n\nexport function isFieldIgnored(\n config: Config,\n entity: Entity,\n fieldName: string,\n notNull: boolean = false,\n hasDefault: boolean = false,\n): boolean {\n const ignore = config.entities[entity.name]?.fields?.[fieldName]?.ignore === true;\n if (ignore && notNull && !hasDefault) {\n fail(\n `notNull field ${entity.name}.${fieldName} cannot be ignored. Alter the column to be optional or have a default value prior to ignoring it.`,\n );\n }\n return ignore;\n}\n\nexport function isFieldHasDefault(config: Config, entity: Entity, fieldName: string): boolean {\n const entityConfig = config.entities[entity.name] ?? {};\n const fieldConfig = entityConfig.fields?.[fieldName] ?? entityConfig.relations?.[fieldName] ?? {};\n return fieldConfig.hasDefault === true;\n}\n\nconst configPath = \"./joist-config.json\";\n\nexport async function loadConfig(): Promise<Config> {\n const exists = await trueIfResolved(fs.access(configPath));\n if (exists) {\n const content = await fs.readFile(configPath);\n const result = config.safeParse(stripLegacyConfigKeys(JSON.parse(content.toString())));\n if (!result.success) {\n throw new Error(\n `Invalid joist-config.json: ${result.error.issues\n .map((ze) => `${ze.path.map(String).join(\"/\")} ${ze.message}`)\n .join(\"\\n\")}`,\n );\n }\n result.data.allowImportingTsExtensions ??= projectIsUsingEsmWithImports();\n return result.data;\n }\n // Brand-new projects should not be prompted to run historical codemods.\n const initial = config.parse({ codemodVersion: getLatestCodemodVersion() });\n initial.allowImportingTsExtensions ??= projectIsUsingEsmWithImports();\n return initial;\n}\n\n/**\n * Writes the potentially-updated config entry back to `joist-config.json`.\n *\n * We format the output with prettier so it should both a) look nice and b) be deterministic,\n * such that no changes to the config show up as noops to the scm.\n */\nexport async function writeConfig(config: Config): Promise<void> {\n const sorted: Partial<Config> = sortKeys(config);\n delete sorted.__tableToEntityName;\n delete sorted.allowImportingTsExtensions;\n if (sorted.paginationStyle === \"cursor\") {\n delete sorted.paginationStyle;\n }\n const input = JSON.stringify(sorted);\n const content = jsonFormatter.formatText({ filePath: \"test.json\", fileText: input });\n await fs.writeFile(configPath, content);\n}\n\nexport function stripStiPlaceholders(config: Config, entities: EntityDbMetadata[]): void {\n // Defacto (with today's setup) the config of STI entities lives on the base entity,\n // so don't write confusing subtype-specific entries into the config file.\n // ...hopefully we don't have any code accidentally looking for the STI config...\n for (const entity of entities) {\n if (entity.inheritanceType === \"sti\" && entity.stiDiscriminatorValue) {\n delete config.entities[entity.name];\n }\n }\n}\n\n/** Applies defaults to the timestamp config. */\nexport function getTimestampConfig(config: Config): {\n updatedAtConf: Required<TimestampConfig>;\n createdAtConf: Required<TimestampConfig>;\n deletedAtConf: Required<TimestampConfig>;\n} {\n return {\n createdAtConf: {\n names: [\"created_at\", \"createdAt\"],\n required: false,\n ...config?.timestampColumns?.createdAt,\n },\n updatedAtConf: {\n names: [\"updated_at\", \"updatedAt\"],\n required: false,\n ...config?.timestampColumns?.updatedAt,\n },\n deletedAtConf: {\n names: [\"deleted_at\", \"deletedAt\"],\n required: false,\n ...config?.timestampColumns?.deletedAt,\n },\n };\n}\n\nfunction projectIsUsingEsmWithImports(): boolean {\n // Attempt to find the project's tsconfig.json in the current directory or up the directory hierarchy\n const configPath = findTsConfigFile(process.cwd());\n if (!configPath) {\n return false;\n }\n try {\n // Use jsonc-parser to parse the tsconfig.json file (not the old tsc readConfigFile which was\n // dropped in TypeScript 7), allowing for comments and trailing commas.\n const errors: ParseError[] = [];\n const parsed: unknown = parse(readFileSync(configPath, \"utf8\"), errors, { allowTrailingComma: true });\n if (errors.length > 0 || typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) return false;\n const compilerOptions = (parsed as Record<string, unknown>).compilerOptions;\n return (\n typeof compilerOptions === \"object\" &&\n compilerOptions !== null &&\n !Array.isArray(compilerOptions) &&\n (compilerOptions as Record<string, unknown>).allowImportingTsExtensions === true\n );\n } catch {\n return false;\n }\n}\n\n/** Normalizes `uniqueBy` config sugar into runtime identity candidates. */\nfunction normalizeUniqueByConfig(uniqueBy: string | string[] | string[][]): string[][] {\n if (typeof uniqueBy === \"string\") return [[uniqueBy]];\n if (uniqueBy.every((field) => typeof field === \"string\")) return [uniqueBy];\n return uniqueBy;\n}\n\nfunction stripLegacyConfigKeys(raw: unknown): unknown {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n return raw;\n }\n // Accept old configs so the deprecated key disappears on the next write.\n const parsed = { ...(raw as Record<string, unknown>) };\n delete parsed.version;\n return parsed;\n}\n\n/** Finds the nearest `tsconfig.json` in `directory` or one of its ancestors. */\nfunction findTsConfigFile(directory: string): string | undefined {\n while (true) {\n const fileName = join(directory, \"tsconfig.json\");\n if (existsSync(fileName)) return fileName;\n const parent = dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"config.js","names":["fs"],"sources":["../src/config.ts"],"sourcesContent":["import { existsSync, promises as fs, readFileSync } from \"fs\";\nimport { dirname, join } from \"path\";\n\nimport { createFromBuffer } from \"@dprint/formatter\";\nimport { getPath } from \"@dprint/json\";\nimport { groupBy } from \"joist-utils\";\nimport { type ParseError, parse } from \"jsonc-parser\";\nimport { z } from \"zod\";\n\nimport { getLatestCodemodVersion } from \"./codemods/index.ts\";\nimport { type DbMetadata, type Entity, type EntityDbMetadata } from \"./EntityDbMetadata.ts\";\nimport { getStiEntities } from \"./inheritance.ts\";\nimport { logger } from \"./logger.ts\";\nimport { fail, sortKeys, trueIfResolved } from \"./utils.ts\";\n\nconst jsonFormatter = createFromBuffer(readFileSync(getPath()));\n\nconst fieldConfig = z\n .object({\n // For getters & ReactiveFields\n derived: z.optional(z.union([z.literal(\"sync\"), z.literal(\"async\")])),\n protected: z.optional(z.boolean()),\n ignore: z.optional(z.boolean()),\n superstruct: z.optional(z.string()),\n zodSchema: z.optional(z.string()),\n type: z.optional(z.string()),\n serde: z.optional(z.string()),\n stiDiscriminator: z.optional(z.record(z.string(), z.string())),\n stiType: z.optional(z.union([z.string(), z.array(z.string())])),\n // Allow subclasses to mark fields as required\n notNull: z.optional(z.boolean()),\n // Allow overriding scanEntities default detection for fields with defaults added by helpers\n hasDefault: z.optional(z.boolean()),\n // Exclude a (large jsonb/text) column from the default SELECT and expose it as a lazy-loaded LazyField\n lazy: z.optional(z.boolean()),\n })\n .strict();\n\nexport type FieldConfig = z.infer<typeof fieldConfig>;\n\nconst relationConfig = z\n .object({\n // For ReactiveReferences\n derived: z.optional(z.literal(\"async\")),\n polymorphic: z.optional(z.union([z.literal(\"notNull\"), z.literal(true)])),\n large: z.optional(z.boolean()),\n orderBy: z.optional(z.string()),\n /**\n * Controls whether this collection's `.get`/`.load` hide soft-deleted entities.\n *\n * Defaults to `\"exclude\"` (soft-deleted entities are hidden); set to `\"include\"` to have\n * this specific o2m/m2m always return soft-deleted entities from `.get`/`.load`.\n */\n softDeletes: z.optional(z.union([z.literal(\"include\"), z.literal(\"exclude\")])),\n // Allow pushing m2o/m2m/o2o relations in a base type (Task) down to a subtype (TaskOld)\n stiType: z.optional(z.union([z.string(), z.array(z.string())])),\n /**\n * Allow specializing a base type relation (SmallPublisher.group: SmallPublisherGroup).\n *\n * Self-referential FKs also support `subType: \"self\"` that means each subtype will point\n * at its own subtype.\n */\n subType: z.optional(z.string()),\n /** Allow skipping self-referential fields getting a `...Recursive` relation. */\n skipRecursiveRelations: z.optional(z.boolean()),\n // Allow marking m2o FKs as required on subclasses\n notNull: z.optional(z.boolean()),\n // Allow overriding scanEntities default detection for fields with defaults added by helpers\n hasDefault: z.optional(z.boolean()),\n })\n .strict();\n\nexport type RelationConfig = z.infer<typeof relationConfig>;\n\nconst uniqueByConfig = z\n .union([z.string(), z.array(z.string()), z.array(z.array(z.string()))])\n .transform(normalizeUniqueByConfig);\n\nconst entityConfig = z\n .object({\n tag: z.string(),\n tableName: z.optional(z.string()),\n fields: z.optional(z.record(z.string(), fieldConfig)),\n relations: z.optional(z.record(z.string(), relationConfig)),\n /** Whether this entity should be abstract, e.g. for inheritance a subtype must be instantiated instead of this type. */\n abstract: z.optional(z.boolean()),\n orderBy: z.optional(z.string()),\n uniqueBy: z.optional(uniqueByConfig),\n })\n .strict();\n\nexport type EntityConfig = z.infer<typeof entityConfig>;\n\nconst timestampConfig = z\n .object({\n /** The names to check for this timestamp, i.e. `created_at` `created`, etc. */\n names: z.array(z.string()),\n /** Whether this timestamp column is required to consider a table an entity, defaults to `false`. */\n required: z.optional(z.boolean()),\n })\n .strict();\n\nexport type TimestampConfig = z.infer<typeof timestampConfig>;\n\nexport const config = z\n .object({\n /** The _build-time_ database URL for reading database metadata. */\n databaseUrl: z.optional(z.string()),\n /** Your application's request-level `Context` type. */\n contextType: z.optional(z.string()),\n /** Your application's database client's `Transaction` type. */\n transactionType: z.optional(z.string()),\n /**\n * Allows the user to specify the `updated_at` / `created_at` column names to look up, and if they're optional.\n *\n * We default to looking for `updated_at`, `updatedAt`, `created_at`, `createdAt`, and optional to true,\n * e.g. tables are not required to have both timestamp columns to be considered entities.\n *\n * These defaults are the most lenient, to facilitate running Joist against an existing schema and\n * seeing all of your entities, regardless of your previous conventions.\n */\n timestampColumns: z.optional(\n z.object({\n createdAt: z.optional(timestampConfig),\n updatedAt: z.optional(timestampConfig),\n deletedAt: z.optional(timestampConfig),\n }),\n ),\n /**\n * Allows the user to have codegen output `Temporal` types instead of the base JS `Date`\n *\n * Additionally, allows for specifying the default time zone for `Temporal` types when converting dates to/from\n * the database.\n */\n temporal: z.optional(z.union([z.boolean(), z.object({ timeZone: z.string() })])),\n /**\n * By default, we create a `flush_database` function for fast testing.\n *\n * However, if you don't want to use this, or you have your own bespoke function like we do\n * that is more application-aware, then you can disable Joist's out-of-the-box one.\n *\n * If you have more than one test database, you can set `createFlushFunction` to the array\n * of test database names, i.e. `mydb_test_1`, `mydb_test_2`, etc.\n */\n createFlushFunction: z.optional(z.union([z.boolean(), z.array(z.string())])),\n entitiesDirectory: z.string().default(\"./src/entities\"),\n codegenPlugins: z.optional(z.array(z.string())),\n entities: z.record(z.string(), entityConfig).default({}),\n ignoredTables: z.optional(z.array(z.string())),\n /** The type of entity `id` fields; defaults to `tagged-string`. */\n idType: z.optional(z.union([z.literal(\"tagged-string\"), z.literal(\"untagged-string\"), z.literal(\"number\")])),\n /** The separator between entity tags and ids; defaults to `:`, and `\"\"` disables the separator. */\n tagDelimiter: z.optional(z.string()),\n /** How we should support non-deferred foreign keys. */\n nonDeferredForeignKeys: z.optional(z.union([z.literal(\"error\"), z.literal(\"warn\"), z.literal(\"ignore\")])),\n /** Enables esm output. */\n esm: z.optional(z.boolean()),\n /** Controls the style of GraphQL pagination scaffolding. */\n paginationStyle: z.optional(z.union([z.literal(\"cursor\"), z.literal(\"limit\")])).default(\"cursor\"),\n /** Enables documentation syncing between .md files and JSDocs. */\n docs: z.optional(z.boolean()),\n /** Installs Joist's bundled Agent Skills into `.claude/skills` and `.agents/skills`; on by default, set `false` to disable. */\n skills: z.optional(z.boolean()),\n /** Output a metadata-docs.ts file with entity/field documentation available at runtime. */\n outputDocs: z.optional(z.boolean()),\n /** Auto-set by probing the project's `tsconfig.json` file. */\n allowImportingTsExtensions: z.optional(z.boolean()),\n /** The latest Joist codemod counter that has been applied to this project. */\n codemodVersion: z.number().int().min(0).default(0),\n\n /** A list of postgres schemas to use for finding tables */\n schemas: z.optional(z.array(z.string())),\n })\n .strict();\n\nexport type Config = z.infer<typeof config> & {\n // We don't persist this, and instead just use it as a cache\n __tableToEntityName?: Record<string, string>;\n};\n\nexport const ormMaintainedFields = [\"createdAt\", \"updatedAt\"];\n\n/** Ensure the user doesn't have any typos in their config. */\nexport function warnInvalidConfigEntries(config: Config, db: DbMetadata): void {\n const entitiesByName = groupBy(db.entities, (e) => e.name);\n for (const [entityName, entityConfig] of Object.entries(config.entities)) {\n const entities = entitiesByName[entityName];\n if (!entities) {\n logger.warn(`Found config for non-existent entity ${entityName}`);\n continue;\n }\n // We don't have keyBy...\n const [entity] = entities;\n\n // Check fields\n const fields = [...entity.primitives, ...entity.enums];\n for (const [name, config] of Object.entries(entityConfig.fields || {})) {\n if (config.ignore) continue;\n let field = fields.find((f) => f.fieldName === name);\n // STI types might be in the base type\n if (!field && entity.stiDiscriminatorField) {\n const stiEntities = getStiEntities(db.entities).get(entity.name)?.subTypes;\n field = stiEntities?.flatMap((st) => [...st.primitives, ...st.enums]).find((f) => f.fieldName === name);\n }\n if (!field) logger.warn(`Found config for non-existent field ${entityName}.${name}`);\n }\n\n // Check relations\n const relations = [\n ...entity.manyToOnes,\n ...entity.oneToManys,\n ...entity.manyToManys,\n ...entity.manyToManyEnums,\n ...entity.oneToOnes,\n ...entity.largeOneToManys,\n ...entity.largeManyToManys,\n ...entity.polymorphics,\n ];\n for (const [name, _] of Object.entries(entityConfig.relations || {})) {\n let relation = relations.find((r) => r.fieldName === name);\n // STI types might be in the subtypes\n if (!relation && entity.stiDiscriminatorField) {\n const stiEntities = getStiEntities(db.entities).get(entity.name)?.subTypes;\n relation = stiEntities\n ?.flatMap((entity) => [\n ...entity.manyToOnes,\n ...entity.oneToManys,\n ...entity.manyToManys,\n ...entity.oneToOnes,\n ...entity.largeOneToManys,\n ...entity.largeManyToManys,\n ...entity.polymorphics,\n ])\n ?.find((f) => f.fieldName === name);\n }\n // CTI subtype specializations (i.e. SmallPublisher.group: SmallPublisherGroup) need to look in the base type\n if (!relation && entity.baseType) {\n const baseType = entity.baseType;\n relation = [\n ...baseType.manyToOnes,\n ...baseType.oneToManys,\n ...baseType.manyToManys,\n ...baseType.oneToOnes,\n ...baseType.largeOneToManys,\n ...baseType.largeManyToManys,\n ...baseType.polymorphics,\n ].find((f) => f.fieldName === name);\n }\n\n if (!relation) logger.warn(`Found config for non-existent relation ${entityName}.${name}`);\n }\n\n const uniqueFields = [\n ...entity.primitives,\n ...entity.enums,\n ...entity.pgEnums,\n ...entity.manyToOnes,\n ...entity.polymorphics,\n ];\n for (const uniqueBy of entityConfig.uniqueBy || []) {\n for (const name of uniqueBy) {\n const field = uniqueFields.find((f) => f.fieldName === name);\n if (!field) {\n logger.warn(`Found uniqueBy for non-existent or non-queryable field ${entityName}.${name}`);\n } else if (field.kind === \"primitive\" && (field.derived || field.isArray || field.customSerde)) {\n logger.warn(`Found uniqueBy for unsupported primitive field ${entityName}.${name}`);\n } else if (field.kind === \"enum\" && (field.derived || field.isArray)) {\n logger.warn(`Found uniqueBy for unsupported enum field ${entityName}.${name}`);\n }\n }\n }\n }\n}\n\nexport function isGetterField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.derived === \"sync\";\n}\n\nexport function isReactiveField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.derived === \"async\";\n}\n\nexport function isReactiveReference(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.derived === \"async\";\n}\n\n/** Returns true if this m2m relation is configured as a ReactiveManyToMany (derived: async). */\nexport function isReactiveManyToMany(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.derived === \"async\";\n}\n\nexport function isProtected(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.protected === true;\n}\n\n/** Whether a column should be excluded from the default SELECT and exposed as a lazy-loaded `LazyField`. */\nexport function isLazyField(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.fields?.[fieldName]?.lazy === true;\n}\n\nexport function serdeConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.serde;\n}\n\nexport function superstructConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.superstruct;\n}\n\nexport function zodSchemaConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.zodSchema;\n}\n\nexport function fieldTypeConfig(config: Config, entity: Entity, fieldName: string): string | undefined {\n return config.entities[entity.name]?.fields?.[fieldName]?.type;\n}\n\nexport function isLargeCollection(config: Config, entity: Entity, fieldName: string): boolean {\n return config.entities[entity.name]?.relations?.[fieldName]?.large === true;\n}\n\n/** Whether a collection should include (or exclude) soft-deleted entities from `.get`/`.load`. */\nexport function softDeletesConfig(\n config: Config,\n entity: Entity,\n fieldName: string,\n): \"include\" | \"exclude\" | undefined {\n return config.entities[entity.name]?.relations?.[fieldName]?.softDeletes;\n}\n\nexport function isFieldIgnored(\n config: Config,\n entity: Entity,\n fieldName: string,\n notNull: boolean = false,\n hasDefault: boolean = false,\n): boolean {\n const ignore = config.entities[entity.name]?.fields?.[fieldName]?.ignore === true;\n if (ignore && notNull && !hasDefault) {\n fail(\n `notNull field ${entity.name}.${fieldName} cannot be ignored. Alter the column to be optional or have a default value prior to ignoring it.`,\n );\n }\n return ignore;\n}\n\nexport function isFieldHasDefault(config: Config, entity: Entity, fieldName: string): boolean {\n const entityConfig = config.entities[entity.name] ?? {};\n const fieldConfig = entityConfig.fields?.[fieldName] ?? entityConfig.relations?.[fieldName] ?? {};\n return fieldConfig.hasDefault === true;\n}\n\nconst configPath = \"./joist-config.json\";\n\nexport async function loadConfig(): Promise<Config> {\n const exists = await trueIfResolved(fs.access(configPath));\n if (exists) {\n const content = await fs.readFile(configPath);\n const result = config.safeParse(stripLegacyConfigKeys(JSON.parse(content.toString())));\n if (!result.success) {\n throw new Error(\n `Invalid joist-config.json: ${result.error.issues\n .map((ze) => `${ze.path.map(String).join(\"/\")} ${ze.message}`)\n .join(\"\\n\")}`,\n );\n }\n result.data.allowImportingTsExtensions ??= projectIsUsingEsmWithImports();\n return result.data;\n }\n // Brand-new projects should not be prompted to run historical codemods.\n const initial = config.parse({ codemodVersion: getLatestCodemodVersion() });\n initial.allowImportingTsExtensions ??= projectIsUsingEsmWithImports();\n return initial;\n}\n\n/**\n * Writes the potentially-updated config entry back to `joist-config.json`.\n *\n * We format the output with prettier so it should both a) look nice and b) be deterministic,\n * such that no changes to the config show up as noops to the scm.\n */\nexport async function writeConfig(config: Config): Promise<void> {\n const sorted: Partial<Config> = sortKeys(config);\n delete sorted.__tableToEntityName;\n delete sorted.allowImportingTsExtensions;\n if (sorted.paginationStyle === \"cursor\") {\n delete sorted.paginationStyle;\n }\n const input = JSON.stringify(sorted);\n const content = jsonFormatter.formatText({ filePath: \"test.json\", fileText: input });\n await fs.writeFile(configPath, content);\n}\n\nexport function stripStiPlaceholders(config: Config, entities: EntityDbMetadata[]): void {\n // Defacto (with today's setup) the config of STI entities lives on the base entity,\n // so don't write confusing subtype-specific entries into the config file.\n // ...hopefully we don't have any code accidentally looking for the STI config...\n for (const entity of entities) {\n if (entity.inheritanceType === \"sti\" && entity.stiDiscriminatorValue) {\n delete config.entities[entity.name];\n }\n }\n}\n\n/** Applies defaults to the timestamp config. */\nexport function getTimestampConfig(config: Config): {\n updatedAtConf: Required<TimestampConfig>;\n createdAtConf: Required<TimestampConfig>;\n deletedAtConf: Required<TimestampConfig>;\n} {\n return {\n createdAtConf: {\n names: [\"created_at\", \"createdAt\"],\n required: false,\n ...config?.timestampColumns?.createdAt,\n },\n updatedAtConf: {\n names: [\"updated_at\", \"updatedAt\"],\n required: false,\n ...config?.timestampColumns?.updatedAt,\n },\n deletedAtConf: {\n names: [\"deleted_at\", \"deletedAt\"],\n required: false,\n ...config?.timestampColumns?.deletedAt,\n },\n };\n}\n\nfunction projectIsUsingEsmWithImports(): boolean {\n // Attempt to find the project's tsconfig.json in the current directory or up the directory hierarchy\n const configPath = findTsConfigFile(process.cwd());\n if (!configPath) {\n return false;\n }\n try {\n // Use jsonc-parser to parse the tsconfig.json file (not the old tsc readConfigFile which was\n // dropped in TypeScript 7), allowing for comments and trailing commas.\n const errors: ParseError[] = [];\n const parsed: unknown = parse(readFileSync(configPath, \"utf8\"), errors, { allowTrailingComma: true });\n if (errors.length > 0 || typeof parsed !== \"object\" || parsed === null || Array.isArray(parsed)) return false;\n const compilerOptions = (parsed as Record<string, unknown>).compilerOptions;\n return (\n typeof compilerOptions === \"object\" &&\n compilerOptions !== null &&\n !Array.isArray(compilerOptions) &&\n (compilerOptions as Record<string, unknown>).allowImportingTsExtensions === true\n );\n } catch {\n return false;\n }\n}\n\n/** Normalizes `uniqueBy` config sugar into runtime identity candidates. */\nfunction normalizeUniqueByConfig(uniqueBy: string | string[] | string[][]): string[][] {\n if (typeof uniqueBy === \"string\") return [[uniqueBy]];\n if (uniqueBy.every((field) => typeof field === \"string\")) return [uniqueBy];\n return uniqueBy;\n}\n\nfunction stripLegacyConfigKeys(raw: unknown): unknown {\n if (!raw || typeof raw !== \"object\" || Array.isArray(raw)) {\n return raw;\n }\n // Accept old configs so the deprecated key disappears on the next write.\n const parsed = { ...(raw as Record<string, unknown>) };\n delete parsed.version;\n return parsed;\n}\n\n/** Finds the nearest `tsconfig.json` in `directory` or one of its ancestors. */\nfunction findTsConfigFile(directory: string): string | undefined {\n while (true) {\n const fileName = join(directory, \"tsconfig.json\");\n if (existsSync(fileName)) return fileName;\n const parent = dirname(directory);\n if (parent === directory) return undefined;\n directory = parent;\n }\n}\n"],"mappings":"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"}
|
package/build/inheritance.cjs
CHANGED
|
@@ -114,11 +114,21 @@ function expandSingleTableInheritance(config, entitiesByName, entities) {
|
|
|
114
114
|
const availableCodes = subTypes.map(([code]) => code);
|
|
115
115
|
const availableNames = subTypes.map(([, name]) => name);
|
|
116
116
|
const available = [...availableCodes, ...availableNames];
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
117
|
+
for (const [name, f] of allFields) for (const stiType of stiTypesOf(f)) if (!available.includes(stiType)) require_utils.fail(`${name}.stiType '${stiType}' is invalid, expected one of ${available.join(", ")}`);
|
|
118
|
+
const requiredFieldNames = new Set([
|
|
119
|
+
...entity.primitives,
|
|
120
|
+
...entity.enums,
|
|
121
|
+
...entity.pgEnums,
|
|
122
|
+
...entity.manyToOnes
|
|
123
|
+
].filter((f) => f.notNull && f.columnDefault === null && !("columnGenerated" in f && f.columnGenerated)).map((f) => f.fieldName));
|
|
124
|
+
for (const [name, f] of allFields) {
|
|
125
|
+
const stiTypes = stiTypesOf(f);
|
|
126
|
+
const claimsEverySubtype = subTypes.every(([code, name]) => stiTypes.some((t) => t === code || t === name));
|
|
127
|
+
if (stiTypes.length > 0 && !claimsEverySubtype && requiredFieldNames.has(name)) require_utils.fail(`${entity.name}.${name} is notNull with no database default, so it cannot be pushed down to ${stiTypes.map((t) => `'${t}'`).join(", ")} -- the other subtypes would have no value to insert. Either give the column a default, make it nullable (stiType will still make it required on those subtypes), or leave the field on ${entity.name}.`);
|
|
128
|
+
}
|
|
129
|
+
const claimedFieldNames = new Set(allFields.filter(([, f]) => stiTypesOf(f).length > 0).map(([name]) => name));
|
|
120
130
|
for (const [enumCode, subTypeName] of subTypes) {
|
|
121
|
-
const subTypeFields = allFields.filter(([, f]) => f.
|
|
131
|
+
const subTypeFields = allFields.filter(([, f]) => stiTypesOf(f).some((t) => t === subTypeName || t === enumCode));
|
|
122
132
|
const subTypeFieldNames = subTypeFields.map(([name]) => name);
|
|
123
133
|
function maybeRequired(field) {
|
|
124
134
|
if ((subTypeFields.find(([name]) => name === field.fieldName)?.[1]).notNull) field.notNull = true;
|
|
@@ -159,21 +169,22 @@ function expandSingleTableInheritance(config, entitiesByName, entities) {
|
|
|
159
169
|
return this.manyToManys.filter((r) => !r.isDeferredAndDeferrable);
|
|
160
170
|
}
|
|
161
171
|
};
|
|
162
|
-
entity.primitives = entity.primitives.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
163
|
-
entity.enums = entity.enums.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
164
|
-
entity.pgEnums = entity.pgEnums.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
165
|
-
entity.manyToOnes = entity.manyToOnes.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
166
|
-
entity.oneToManys = entity.oneToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
167
|
-
entity.largeOneToManys = entity.largeOneToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
168
|
-
entity.oneToOnes = entity.oneToOnes.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
169
|
-
entity.manyToManys = entity.manyToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
170
|
-
entity.largeManyToManys = entity.largeManyToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
171
|
-
entity.manyToManyEnums = entity.manyToManyEnums.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
172
|
-
entity.polymorphics = entity.polymorphics.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
173
172
|
entity.subTypes.push(subEntity);
|
|
174
173
|
entities.push(subEntity);
|
|
175
174
|
entitiesByName[subEntity.name] = subEntity;
|
|
176
175
|
}
|
|
176
|
+
const keep = (f) => !claimedFieldNames.has(f.fieldName);
|
|
177
|
+
entity.primitives = entity.primitives.filter(keep);
|
|
178
|
+
entity.enums = entity.enums.filter(keep);
|
|
179
|
+
entity.pgEnums = entity.pgEnums.filter(keep);
|
|
180
|
+
entity.manyToOnes = entity.manyToOnes.filter(keep);
|
|
181
|
+
entity.oneToManys = entity.oneToManys.filter(keep);
|
|
182
|
+
entity.largeOneToManys = entity.largeOneToManys.filter(keep);
|
|
183
|
+
entity.oneToOnes = entity.oneToOnes.filter(keep);
|
|
184
|
+
entity.manyToManys = entity.manyToManys.filter(keep);
|
|
185
|
+
entity.largeManyToManys = entity.largeManyToManys.filter(keep);
|
|
186
|
+
entity.manyToManyEnums = entity.manyToManyEnums.filter(keep);
|
|
187
|
+
entity.polymorphics = entity.polymorphics.filter(keep);
|
|
177
188
|
}
|
|
178
189
|
}
|
|
179
190
|
}
|
|
@@ -203,8 +214,8 @@ function rewriteSingleTableForeignKeys(config, entities) {
|
|
|
203
214
|
for (const m2o of entity.manyToOnes) {
|
|
204
215
|
const target = stiEntities.get(m2o.otherEntity.name);
|
|
205
216
|
const base = target?.base.entity.name;
|
|
206
|
-
const stiType = base
|
|
207
|
-
if (target && stiType) {
|
|
217
|
+
const [stiType, ...others] = stiTypesOf(base ? config.entities[base]?.relations?.[m2o.otherFieldName] : void 0);
|
|
218
|
+
if (target && stiType && others.length === 0) {
|
|
208
219
|
const { subTypes } = target;
|
|
209
220
|
m2o.otherEntity = (subTypes.find((s) => s.name === stiType) ?? require_utils.fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)).entity;
|
|
210
221
|
}
|
|
@@ -212,8 +223,8 @@ function rewriteSingleTableForeignKeys(config, entities) {
|
|
|
212
223
|
for (const poly of entity.polymorphics) for (const comp of poly.components) {
|
|
213
224
|
const target = stiEntities.get(comp.otherEntity.name);
|
|
214
225
|
const base = target?.base.entity.name;
|
|
215
|
-
const stiType = base
|
|
216
|
-
if (target && stiType) {
|
|
226
|
+
const [stiType, ...others] = stiTypesOf(base ? config.entities[base]?.relations?.[comp.otherFieldName] : void 0);
|
|
227
|
+
if (target && stiType && others.length === 0) {
|
|
217
228
|
const { subTypes } = target;
|
|
218
229
|
comp.otherEntity = (subTypes.find((s) => s.name === stiType) ?? require_utils.fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)).entity;
|
|
219
230
|
}
|
|
@@ -234,6 +245,11 @@ function rewriteSingleTableForeignKeys(config, entities) {
|
|
|
234
245
|
}
|
|
235
246
|
}
|
|
236
247
|
}
|
|
248
|
+
/** Normalizes a field/relation's `stiType`, which may name one subtype or several, to an array. */
|
|
249
|
+
function stiTypesOf(config) {
|
|
250
|
+
const stiType = config?.stiType;
|
|
251
|
+
return stiType === void 0 ? [] : typeof stiType === "string" ? [stiType] : stiType;
|
|
252
|
+
}
|
|
237
253
|
//#endregion
|
|
238
254
|
exports.applyInheritanceUpdates = applyInheritanceUpdates;
|
|
239
255
|
exports.getStiEntities = getStiEntities;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inheritance.cjs","names":["makeEntity","fail"],"sources":["../src/inheritance.ts"],"sourcesContent":["import { type Config } from \"./config.ts\";\nimport {\n type DbMetadata,\n type EntityDbMetadata,\n type ManyToManyField,\n type ManyToOneField,\n type PolymorphicFieldComponent,\n canonicalizeOtherEntities,\n makeEntity,\n} from \"./EntityDbMetadata.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** Preserves physical storage metadata, then applies domain inheritance specialization. */\nexport function applyInheritanceUpdates(config: Config, db: DbMetadata): void {\n const { entities, entitiesByName } = db;\n // Preserve storage domains before STI moves fields or rewrites relationship targets.\n for (const meta of entities) {\n meta.physicalMetadata = {\n ...meta,\n name: meta.name,\n primitives: meta.primitives.map((field) => ({ ...field })),\n enums: meta.enums.map((field) => ({ ...field })),\n pgEnums: meta.pgEnums.map((field) => ({ ...field })),\n manyToOnes: meta.manyToOnes.map((field) => ({ ...field })),\n oneToManys: meta.oneToManys.map((field) => ({ ...field })),\n largeOneToManys: meta.largeOneToManys.map((field) => ({ ...field })),\n oneToOnes: meta.oneToOnes.map((field) => ({ ...field })),\n manyToManys: meta.manyToManys.map((field) => ({ ...field })),\n largeManyToManys: meta.largeManyToManys.map((field) => ({ ...field })),\n polymorphics: meta.polymorphics.map((field) => ({\n ...field,\n components: field.components.map((component) => ({ ...component })),\n })),\n nonDeferredFks: meta.nonDeferredFks,\n nonDeferredManyToManyFks: meta.nonDeferredManyToManyFks,\n };\n for (const timestamp of [\"createdAt\", \"updatedAt\", \"deletedAt\"] as const) {\n meta.physicalMetadata[timestamp] = meta.physicalMetadata.primitives.find(\n (field) => field.fieldName === meta[timestamp]?.fieldName,\n );\n }\n }\n setClassTableInheritance(entities, entitiesByName);\n expandSingleTableInheritance(config, entitiesByName, entities);\n rewriteSingleTableForeignKeys(config, entities);\n setupSubTypeSpecialization(config, entities);\n // Now that all relations (incl. specialized ones) exist, collapse the duplicate `otherEntity` objects\n canonicalizeOtherEntities(db);\n}\n\n/**\n * Looks for subtypes specializing a FK of their base type, and give them a specialized m2o.\n *\n * I.e. `SmallPublishers.group: SmallPublisherGroup`.\n *\n * This means the `publishers.group_id` FK will actually be in the `EntityDbMetadata` twice,\n * once for the base and once for the child, which is unusual, but gets the types generated\n * that we want, and then we fixup/dedupe them at runtime in `configure.ts` when creating\n * `meta.allFields`.\n */\nfunction setupSubTypeSpecialization(config: Config, entities: EntityDbMetadata[]): void {\n for (const entity of entities) {\n if (entity.baseType) {\n const entityConfig = config.entities[entity.name];\n const baseConfig = config.entities[entity.baseType.name];\n // Look through the base's m2os & o2ms, looking for a config specialization\n for (const rel of [...entity.baseType.manyToOnes, ...entity.baseType.oneToManys]) {\n const { notNull } = entityConfig?.relations?.[rel.fieldName] ?? {};\n const subType =\n entityConfig?.relations?.[rel.fieldName]?.subType ??\n baseConfig?.relations?.[rel.fieldName]?.subType ??\n // Probe the otherFieldName for a `subType: \"self\"` on self-referential relations in STI tables\n baseConfig?.relations?.[rel.otherFieldName]?.subType ??\n // if we are only marking the relation as required and not specifying a subtype, then use the original type\n (notNull ? rel.otherEntity.name : undefined);\n\n if (!subType) {\n // continue...\n } else if (subType === \"self\" && rel.kind === \"m2o\") {\n // Specialize `TaskNew.copiedFrom: TaskNew` & `TaskOld.copiedFrom: TaskOld`\n entity.manyToOnes.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(entity.name) });\n } else if (subType === \"self\" && rel.kind === \"o2m\") {\n // Specialize `TaskNew.copiedTo: TaskNew[]` & `TaskOld.copiedTo: TaskOld[]`\n entity.oneToManys.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(entity.name) });\n } else if (rel.kind === \"m2o\") {\n // Specialize `SmallPublisher.group: SmallPublisherGroup`\n entity.manyToOnes.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(subType) });\n } else if (rel.kind === \"o2m\") {\n // Specialize `SmallPublisherGroup.publishers: SmallPublisher`\n entity.oneToManys.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(subType) });\n }\n }\n\n // Look through the base's primitives looking for a config specialization\n for (const field of entity.baseType?.primitives ?? []) {\n // the only specialization a primitive can have is nullability\n const { notNull } = entityConfig?.fields?.[field.fieldName] ?? {};\n if (notNull) {\n entity.primitives.push({ ...field, notNull });\n }\n }\n }\n }\n}\n\n/**\n * Ensure CTI base types have their inheritanceType set.\n *\n * (We automatically set `inheritanceType` for STI tables when we see their config\n * setup, see `expandSingleTableInheritance`.)\n */\nfunction setClassTableInheritance(\n entities: EntityDbMetadata[],\n entitiesByName: Record<string, EntityDbMetadata>,\n): void {\n const ctiBaseNames: string[] = [];\n for (const entity of entities) {\n if (entity.baseClassName) {\n ctiBaseNames.push(entity.baseClassName);\n const base = entitiesByName[entity.baseClassName];\n entity.baseType = base;\n base.subTypes.push(entity);\n }\n }\n for (const entity of entities) {\n if (ctiBaseNames.includes(entity.name)) entity.inheritanceType = \"cti\";\n }\n}\n\n/** Expands STI tables into multiple entities, so they get separate `SubTypeCodegen.ts` & `SubType.ts` files. */\nfunction expandSingleTableInheritance(\n config: Config,\n entitiesByName: Record<string, EntityDbMetadata>,\n entities: EntityDbMetadata[],\n): void {\n for (const entity of entities) {\n const [fieldName, stiField] =\n Object.entries(config.entities[entity.name]?.fields || {}).find(([, f]) => !!f.stiDiscriminator) ?? [];\n if (fieldName && stiField && stiField.stiDiscriminator) {\n entity.inheritanceType = \"sti\";\n\n // Ensure we have an enum field so that we can bake the STI discriminators into the metadata.ts file\n const enumField =\n entity.enums.find((e) => e.fieldName === fieldName) ??\n fail(`No enum column found for ${entity.name}.${fieldName}, which is required to use singleTableInheritance`);\n entity.stiDiscriminatorField = enumField.fieldName;\n\n // Find the available discriminators/subtypes, i.e. NEW => NewTask, OLD => OldTask, etc.\n const subTypes = Object.entries(stiField.stiDiscriminator);\n\n const allFields = [\n ...Object.entries(config.entities[entity.name]?.fields ?? {}),\n ...Object.entries(config.entities[entity.name]?.relations ?? {}),\n ];\n\n // Make sure there aren't any typos in `stiType`s\n const availableCodes = subTypes.map(([code]) => code);\n const availableNames = subTypes.map(([, name]) => name);\n const available = [...availableCodes, ...availableNames];\n allFields.filter(([name, f]) => {\n if (f.stiType && !available.includes(f.stiType)) {\n fail(`${name}.stiType '${f.stiType}' is invalid, expected one of ${available.join(\", \")}`);\n }\n });\n\n // Now split each subType out into its out entity\n for (const [enumCode, subTypeName] of subTypes) {\n // Find all the base entity's fields that belong to us\n const subTypeFields = allFields.filter(([, f]) => f.stiType === subTypeName || f.stiType === enumCode);\n const subTypeFieldNames = subTypeFields.map(([name]) => name);\n\n // Make fields as required\n function maybeRequired<T extends { notNull: boolean; fieldName: string }>(field: T): T {\n const config = subTypeFields.find(([name]) => name === field.fieldName)?.[1]!;\n if (config.notNull) field.notNull = true;\n return field;\n }\n\n // Synthesize an entity for this STI sub-entity\n const subEntity: EntityDbMetadata = {\n name: subTypeName,\n entity: makeEntity(subTypeName),\n tableName: entity.tableName,\n physicalMetadata: entity.physicalMetadata,\n primaryKey: entity.primaryKey,\n primitives: entity.primitives.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n enums: entity.enums.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n pgEnums: entity.pgEnums.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n manyToOnes: entity.manyToOnes.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n oneToManys: entity.oneToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n largeOneToManys: entity.largeOneToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n oneToOnes: entity.oneToOnes.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n manyToManys: entity.manyToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n largeManyToManys: entity.largeManyToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n manyToManyEnums: entity.manyToManyEnums.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n polymorphics: entity.polymorphics.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n tagName: entity.tagName,\n createdAt: undefined,\n updatedAt: undefined,\n deletedAt: undefined,\n baseClassName: entity.name,\n baseType: entity,\n subTypes: [],\n inheritanceType: \"sti\",\n stiDiscriminatorValue: (\n enumField.enumRows.find((r) => r.code === enumCode) ??\n fail(`No enum row found for ${entity.name}.${fieldName}.${enumCode}`)\n ).id,\n abstract: false,\n nonDeferredFkOrder: entity.nonDeferredFkOrder,\n get nonDeferredFks(): Array<ManyToOneField | PolymorphicFieldComponent> {\n return [\n ...this.manyToOnes.filter((r) => !r.isDeferredAndDeferrable),\n ...this.polymorphics.flatMap((p) => p.components).filter((c) => !c.isDeferredAndDeferrable),\n ];\n },\n get nonDeferredManyToManyFks(): Array<ManyToManyField> {\n return this.manyToManys.filter((r) => !r.isDeferredAndDeferrable);\n },\n };\n\n // Now strip all the subclass fields from the base class\n entity.primitives = entity.primitives.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.enums = entity.enums.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.pgEnums = entity.pgEnums.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.manyToOnes = entity.manyToOnes.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.oneToManys = entity.oneToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.largeOneToManys = entity.largeOneToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.oneToOnes = entity.oneToOnes.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.manyToManys = entity.manyToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.largeManyToManys = entity.largeManyToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.manyToManyEnums = entity.manyToManyEnums.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.polymorphics = entity.polymorphics.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.subTypes.push(subEntity);\n\n entities.push(subEntity);\n entitiesByName[subEntity.name] = subEntity;\n }\n }\n }\n}\n\ntype StiEntityMap = Map<string, { base: EntityDbMetadata; subTypes: EntityDbMetadata[] }>;\nlet stiEntities: StiEntityMap;\n\nexport function getStiEntities(entities: EntityDbMetadata[]): StiEntityMap {\n if (stiEntities) return stiEntities;\n stiEntities = new Map();\n for (const entity of entities) {\n if (entity.inheritanceType === \"sti\" && entity.stiDiscriminatorField) {\n const base = entity;\n const subTypes = entities.filter((s) => s.baseClassName === entity.name && s !== entity);\n stiEntities.set(entity.name, { base, subTypes });\n // Allow looking up by subType name\n for (const subType of subTypes) {\n stiEntities.set(subType.name, { base, subTypes: [] });\n }\n }\n }\n return stiEntities;\n}\n\n/** Finds FKs pointing to the base table and, if configured, rewrites them to point to the sub-tables. */\nfunction rewriteSingleTableForeignKeys(config: Config, entities: EntityDbMetadata[]): void {\n // See if we even have any STI tables\n const stiEntities = getStiEntities(entities);\n if (stiEntities.size === 0) return;\n // Scan for other entities/relations that point to the STI table\n for (const entity of entities) {\n // m2os -- Look for `entity.task_id` FKs pointing at `Task` and, if configured, rewrite them to point at `TaskOld`\n for (const m2o of entity.manyToOnes) {\n const target = stiEntities.get(m2o.otherEntity.name);\n const base = target?.base.entity.name;\n // See if the user has pushed `Task.entities` down to a subtype\n const stiType = base && config.entities[base]?.relations?.[m2o.otherFieldName]?.stiType;\n if (target && stiType) {\n const { subTypes } = target;\n m2o.otherEntity = (\n subTypes.find((s) => s.name === stiType) ??\n fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)\n ).entity;\n }\n }\n // polys -- Look for `entity.parent_task_id` FKs pointing at `Task` and, if configured, rewrite them to point at `TaskOld`\n for (const poly of entity.polymorphics) {\n for (const comp of poly.components) {\n const target = stiEntities.get(comp.otherEntity.name);\n const base = target?.base.entity.name;\n // See if the user has pushed `Task.entities` down to a subtype\n const stiType = base && config.entities[base]?.relations?.[comp.otherFieldName]?.stiType;\n if (target && stiType) {\n const { subTypes } = target;\n comp.otherEntity = (\n subTypes.find((s) => s.name === stiType) ??\n fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)\n ).entity;\n }\n }\n }\n // o2ms -- Look for `entity.tasks` collections loading `task.entity_id`, but entity has been pushed down to `TaskOld`\n for (const o2m of entity.oneToManys) {\n const target = stiEntities.get(o2m.otherEntity.name);\n if (target && target.base.inheritanceType === \"sti\") {\n // Ensure the incoming FK is not in the base type, and find the 1st subtype (eventually N subtypes?)\n const otherField = target.subTypes.find(\n (st) =>\n !target.base.manyToOnes.some((m) => m.fieldName === o2m.otherFieldName) &&\n st.manyToOnes.some((m) => m.fieldName === o2m.otherFieldName),\n );\n if (otherField) {\n o2m.otherEntity = otherField.entity;\n }\n }\n }\n // m2ms -- Look for `entity.tasks` collections loading m2m rows, but `entity` has been pushed down to `TaskOld`\n for (const m2m of entity.manyToManys) {\n const target = stiEntities.get(m2m.otherEntity.name);\n if (target && target.base.inheritanceType === \"sti\") {\n // Ensure the incoming FK is not in the base type, and find the 1st subtype (eventually N subtypes?)\n const otherField = target.subTypes.find(\n (st) =>\n !target.base.manyToManys.some((m) => m.fieldName === m2m.otherFieldName) &&\n st.manyToManys.some((m) => m.fieldName === m2m.otherFieldName),\n );\n if (otherField) {\n m2m.otherEntity = otherField.entity;\n }\n }\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"inheritance.cjs","names":["makeEntity","fail"],"sources":["../src/inheritance.ts"],"sourcesContent":["import { type Config } from \"./config.ts\";\nimport {\n type DbMetadata,\n type EntityDbMetadata,\n type ManyToManyField,\n type ManyToOneField,\n type PolymorphicFieldComponent,\n canonicalizeOtherEntities,\n makeEntity,\n} from \"./EntityDbMetadata.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** Preserves physical storage metadata, then applies domain inheritance specialization. */\nexport function applyInheritanceUpdates(config: Config, db: DbMetadata): void {\n const { entities, entitiesByName } = db;\n // Preserve storage domains before STI moves fields or rewrites relationship targets.\n for (const meta of entities) {\n meta.physicalMetadata = {\n ...meta,\n name: meta.name,\n primitives: meta.primitives.map((field) => ({ ...field })),\n enums: meta.enums.map((field) => ({ ...field })),\n pgEnums: meta.pgEnums.map((field) => ({ ...field })),\n manyToOnes: meta.manyToOnes.map((field) => ({ ...field })),\n oneToManys: meta.oneToManys.map((field) => ({ ...field })),\n largeOneToManys: meta.largeOneToManys.map((field) => ({ ...field })),\n oneToOnes: meta.oneToOnes.map((field) => ({ ...field })),\n manyToManys: meta.manyToManys.map((field) => ({ ...field })),\n largeManyToManys: meta.largeManyToManys.map((field) => ({ ...field })),\n polymorphics: meta.polymorphics.map((field) => ({\n ...field,\n components: field.components.map((component) => ({ ...component })),\n })),\n nonDeferredFks: meta.nonDeferredFks,\n nonDeferredManyToManyFks: meta.nonDeferredManyToManyFks,\n };\n for (const timestamp of [\"createdAt\", \"updatedAt\", \"deletedAt\"] as const) {\n meta.physicalMetadata[timestamp] = meta.physicalMetadata.primitives.find(\n (field) => field.fieldName === meta[timestamp]?.fieldName,\n );\n }\n }\n setClassTableInheritance(entities, entitiesByName);\n expandSingleTableInheritance(config, entitiesByName, entities);\n rewriteSingleTableForeignKeys(config, entities);\n setupSubTypeSpecialization(config, entities);\n // Now that all relations (incl. specialized ones) exist, collapse the duplicate `otherEntity` objects\n canonicalizeOtherEntities(db);\n}\n\n/**\n * Looks for subtypes specializing a FK of their base type, and give them a specialized m2o.\n *\n * I.e. `SmallPublishers.group: SmallPublisherGroup`.\n *\n * This means the `publishers.group_id` FK will actually be in the `EntityDbMetadata` twice,\n * once for the base and once for the child, which is unusual, but gets the types generated\n * that we want, and then we fixup/dedupe them at runtime in `configure.ts` when creating\n * `meta.allFields`.\n */\nfunction setupSubTypeSpecialization(config: Config, entities: EntityDbMetadata[]): void {\n for (const entity of entities) {\n if (entity.baseType) {\n const entityConfig = config.entities[entity.name];\n const baseConfig = config.entities[entity.baseType.name];\n // Look through the base's m2os & o2ms, looking for a config specialization\n for (const rel of [...entity.baseType.manyToOnes, ...entity.baseType.oneToManys]) {\n const { notNull } = entityConfig?.relations?.[rel.fieldName] ?? {};\n const subType =\n entityConfig?.relations?.[rel.fieldName]?.subType ??\n baseConfig?.relations?.[rel.fieldName]?.subType ??\n // Probe the otherFieldName for a `subType: \"self\"` on self-referential relations in STI tables\n baseConfig?.relations?.[rel.otherFieldName]?.subType ??\n // if we are only marking the relation as required and not specifying a subtype, then use the original type\n (notNull ? rel.otherEntity.name : undefined);\n\n if (!subType) {\n // continue...\n } else if (subType === \"self\" && rel.kind === \"m2o\") {\n // Specialize `TaskNew.copiedFrom: TaskNew` & `TaskOld.copiedFrom: TaskOld`\n entity.manyToOnes.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(entity.name) });\n } else if (subType === \"self\" && rel.kind === \"o2m\") {\n // Specialize `TaskNew.copiedTo: TaskNew[]` & `TaskOld.copiedTo: TaskOld[]`\n entity.oneToManys.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(entity.name) });\n } else if (rel.kind === \"m2o\") {\n // Specialize `SmallPublisher.group: SmallPublisherGroup`\n entity.manyToOnes.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(subType) });\n } else if (rel.kind === \"o2m\") {\n // Specialize `SmallPublisherGroup.publishers: SmallPublisher`\n entity.oneToManys.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(subType) });\n }\n }\n\n // Look through the base's primitives looking for a config specialization\n for (const field of entity.baseType?.primitives ?? []) {\n // the only specialization a primitive can have is nullability\n const { notNull } = entityConfig?.fields?.[field.fieldName] ?? {};\n if (notNull) {\n entity.primitives.push({ ...field, notNull });\n }\n }\n }\n }\n}\n\n/**\n * Ensure CTI base types have their inheritanceType set.\n *\n * (We automatically set `inheritanceType` for STI tables when we see their config\n * setup, see `expandSingleTableInheritance`.)\n */\nfunction setClassTableInheritance(\n entities: EntityDbMetadata[],\n entitiesByName: Record<string, EntityDbMetadata>,\n): void {\n const ctiBaseNames: string[] = [];\n for (const entity of entities) {\n if (entity.baseClassName) {\n ctiBaseNames.push(entity.baseClassName);\n const base = entitiesByName[entity.baseClassName];\n entity.baseType = base;\n base.subTypes.push(entity);\n }\n }\n for (const entity of entities) {\n if (ctiBaseNames.includes(entity.name)) entity.inheritanceType = \"cti\";\n }\n}\n\n/** Expands STI tables into multiple entities, so they get separate `SubTypeCodegen.ts` & `SubType.ts` files. */\nfunction expandSingleTableInheritance(\n config: Config,\n entitiesByName: Record<string, EntityDbMetadata>,\n entities: EntityDbMetadata[],\n): void {\n for (const entity of entities) {\n const [fieldName, stiField] =\n Object.entries(config.entities[entity.name]?.fields || {}).find(([, f]) => !!f.stiDiscriminator) ?? [];\n if (fieldName && stiField && stiField.stiDiscriminator) {\n entity.inheritanceType = \"sti\";\n\n // Ensure we have an enum field so that we can bake the STI discriminators into the metadata.ts file\n const enumField =\n entity.enums.find((e) => e.fieldName === fieldName) ??\n fail(`No enum column found for ${entity.name}.${fieldName}, which is required to use singleTableInheritance`);\n entity.stiDiscriminatorField = enumField.fieldName;\n\n // Find the available discriminators/subtypes, i.e. NEW => NewTask, OLD => OldTask, etc.\n const subTypes = Object.entries(stiField.stiDiscriminator);\n\n const allFields = [\n ...Object.entries(config.entities[entity.name]?.fields ?? {}),\n ...Object.entries(config.entities[entity.name]?.relations ?? {}),\n ];\n\n // Make sure there aren't any typos in `stiType`s\n const availableCodes = subTypes.map(([code]) => code);\n const availableNames = subTypes.map(([, name]) => name);\n const available = [...availableCodes, ...availableNames];\n for (const [name, f] of allFields) {\n for (const stiType of stiTypesOf(f)) {\n if (!available.includes(stiType)) {\n fail(`${name}.stiType '${stiType}' is invalid, expected one of ${available.join(\", \")}`);\n }\n }\n }\n\n // A `notNull` column with no database default cannot be pushed down to a subtype: the other\n // subtypes omit it from their INSERT (see `addInserts`), and the database has nothing to fall back\n // on. A `notNull` column *with* a default is fine -- the other subtypes simply get the default.\n const requiredFieldNames = new Set(\n [...entity.primitives, ...entity.enums, ...entity.pgEnums, ...entity.manyToOnes]\n .filter((f) => f.notNull && f.columnDefault === null && !(\"columnGenerated\" in f && f.columnGenerated))\n .map((f) => f.fieldName),\n );\n for (const [name, f] of allFields) {\n const stiTypes = stiTypesOf(f);\n // Claiming every subtype leaves no one without a value, so it's equivalent to staying on the base\n const claimsEverySubtype = subTypes.every(([code, name]) => stiTypes.some((t) => t === code || t === name));\n if (stiTypes.length > 0 && !claimsEverySubtype && requiredFieldNames.has(name)) {\n fail(\n `${entity.name}.${name} is notNull with no database default, so it cannot be pushed down to` +\n ` ${stiTypes.map((t) => `'${t}'`).join(\", \")} -- the other subtypes would have no value to` +\n ` insert. Either give the column a default, make it nullable (stiType will still make it` +\n ` required on those subtypes), or leave the field on ${entity.name}.`,\n );\n }\n }\n\n // Names claimed by any subtype; stripped from the base after the loop, not during it, so that a\n // field claimed by two subtypes is still on the base when the second iteration looks for it.\n const claimedFieldNames = new Set(allFields.filter(([, f]) => stiTypesOf(f).length > 0).map(([name]) => name));\n\n // Now split each subType out into its out entity\n for (const [enumCode, subTypeName] of subTypes) {\n // Find all the base entity's fields that belong to us\n const subTypeFields = allFields.filter(([, f]) =>\n stiTypesOf(f).some((t) => t === subTypeName || t === enumCode),\n );\n const subTypeFieldNames = subTypeFields.map(([name]) => name);\n\n // Make fields as required\n function maybeRequired<T extends { notNull: boolean; fieldName: string }>(field: T): T {\n const config = subTypeFields.find(([name]) => name === field.fieldName)?.[1]!;\n if (config.notNull) field.notNull = true;\n return field;\n }\n\n // Synthesize an entity for this STI sub-entity\n const subEntity: EntityDbMetadata = {\n name: subTypeName,\n entity: makeEntity(subTypeName),\n tableName: entity.tableName,\n physicalMetadata: entity.physicalMetadata,\n primaryKey: entity.primaryKey,\n primitives: entity.primitives.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n enums: entity.enums.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n pgEnums: entity.pgEnums.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n manyToOnes: entity.manyToOnes.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n oneToManys: entity.oneToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n largeOneToManys: entity.largeOneToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n oneToOnes: entity.oneToOnes.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n manyToManys: entity.manyToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n largeManyToManys: entity.largeManyToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n manyToManyEnums: entity.manyToManyEnums.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n polymorphics: entity.polymorphics.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n tagName: entity.tagName,\n createdAt: undefined,\n updatedAt: undefined,\n deletedAt: undefined,\n baseClassName: entity.name,\n baseType: entity,\n subTypes: [],\n inheritanceType: \"sti\",\n stiDiscriminatorValue: (\n enumField.enumRows.find((r) => r.code === enumCode) ??\n fail(`No enum row found for ${entity.name}.${fieldName}.${enumCode}`)\n ).id,\n abstract: false,\n nonDeferredFkOrder: entity.nonDeferredFkOrder,\n get nonDeferredFks(): Array<ManyToOneField | PolymorphicFieldComponent> {\n return [\n ...this.manyToOnes.filter((r) => !r.isDeferredAndDeferrable),\n ...this.polymorphics.flatMap((p) => p.components).filter((c) => !c.isDeferredAndDeferrable),\n ];\n },\n get nonDeferredManyToManyFks(): Array<ManyToManyField> {\n return this.manyToManys.filter((r) => !r.isDeferredAndDeferrable);\n },\n };\n\n entity.subTypes.push(subEntity);\n\n entities.push(subEntity);\n entitiesByName[subEntity.name] = subEntity;\n }\n\n // Now strip the subclass fields from the base class\n const keep = <T extends { fieldName: string }>(f: T) => !claimedFieldNames.has(f.fieldName);\n entity.primitives = entity.primitives.filter(keep);\n entity.enums = entity.enums.filter(keep);\n entity.pgEnums = entity.pgEnums.filter(keep);\n entity.manyToOnes = entity.manyToOnes.filter(keep);\n entity.oneToManys = entity.oneToManys.filter(keep);\n entity.largeOneToManys = entity.largeOneToManys.filter(keep);\n entity.oneToOnes = entity.oneToOnes.filter(keep);\n entity.manyToManys = entity.manyToManys.filter(keep);\n entity.largeManyToManys = entity.largeManyToManys.filter(keep);\n entity.manyToManyEnums = entity.manyToManyEnums.filter(keep);\n entity.polymorphics = entity.polymorphics.filter(keep);\n }\n }\n}\n\ntype StiEntityMap = Map<string, { base: EntityDbMetadata; subTypes: EntityDbMetadata[] }>;\nlet stiEntities: StiEntityMap;\n\nexport function getStiEntities(entities: EntityDbMetadata[]): StiEntityMap {\n if (stiEntities) return stiEntities;\n stiEntities = new Map();\n for (const entity of entities) {\n if (entity.inheritanceType === \"sti\" && entity.stiDiscriminatorField) {\n const base = entity;\n const subTypes = entities.filter((s) => s.baseClassName === entity.name && s !== entity);\n stiEntities.set(entity.name, { base, subTypes });\n // Allow looking up by subType name\n for (const subType of subTypes) {\n stiEntities.set(subType.name, { base, subTypes: [] });\n }\n }\n }\n return stiEntities;\n}\n\n/** Finds FKs pointing to the base table and, if configured, rewrites them to point to the sub-tables. */\nfunction rewriteSingleTableForeignKeys(config: Config, entities: EntityDbMetadata[]): void {\n // See if we even have any STI tables\n const stiEntities = getStiEntities(entities);\n if (stiEntities.size === 0) return;\n // Scan for other entities/relations that point to the STI table\n for (const entity of entities) {\n // m2os -- Look for `entity.task_id` FKs pointing at `Task` and, if configured, rewrite them to point at `TaskOld`\n for (const m2o of entity.manyToOnes) {\n const target = stiEntities.get(m2o.otherEntity.name);\n const base = target?.base.entity.name;\n // See if the user has pushed `Task.entities` down to a subtype\n // Only a lone subtype can retype the FK; naming several means the FK can point at any of them,\n // which is just the base type, so leave it alone.\n const [stiType, ...others] = stiTypesOf(\n base ? config.entities[base]?.relations?.[m2o.otherFieldName] : undefined,\n );\n if (target && stiType && others.length === 0) {\n const { subTypes } = target;\n m2o.otherEntity = (\n subTypes.find((s) => s.name === stiType) ??\n fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)\n ).entity;\n }\n }\n // polys -- Look for `entity.parent_task_id` FKs pointing at `Task` and, if configured, rewrite them to point at `TaskOld`\n for (const poly of entity.polymorphics) {\n for (const comp of poly.components) {\n const target = stiEntities.get(comp.otherEntity.name);\n const base = target?.base.entity.name;\n // See if the user has pushed `Task.entities` down to a subtype\n const [stiType, ...others] = stiTypesOf(\n base ? config.entities[base]?.relations?.[comp.otherFieldName] : undefined,\n );\n if (target && stiType && others.length === 0) {\n const { subTypes } = target;\n comp.otherEntity = (\n subTypes.find((s) => s.name === stiType) ??\n fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)\n ).entity;\n }\n }\n }\n // o2ms -- Look for `entity.tasks` collections loading `task.entity_id`, but entity has been pushed down to `TaskOld`\n for (const o2m of entity.oneToManys) {\n const target = stiEntities.get(o2m.otherEntity.name);\n if (target && target.base.inheritanceType === \"sti\") {\n // Ensure the incoming FK is not in the base type, and find the 1st subtype (eventually N subtypes?)\n const otherField = target.subTypes.find(\n (st) =>\n !target.base.manyToOnes.some((m) => m.fieldName === o2m.otherFieldName) &&\n st.manyToOnes.some((m) => m.fieldName === o2m.otherFieldName),\n );\n if (otherField) {\n o2m.otherEntity = otherField.entity;\n }\n }\n }\n // m2ms -- Look for `entity.tasks` collections loading m2m rows, but `entity` has been pushed down to `TaskOld`\n for (const m2m of entity.manyToManys) {\n const target = stiEntities.get(m2m.otherEntity.name);\n if (target && target.base.inheritanceType === \"sti\") {\n // Ensure the incoming FK is not in the base type, and find the 1st subtype (eventually N subtypes?)\n const otherField = target.subTypes.find(\n (st) =>\n !target.base.manyToManys.some((m) => m.fieldName === m2m.otherFieldName) &&\n st.manyToManys.some((m) => m.fieldName === m2m.otherFieldName),\n );\n if (otherField) {\n m2m.otherEntity = otherField.entity;\n }\n }\n }\n }\n}\n\n/** Normalizes a field/relation's `stiType`, which may name one subtype or several, to an array. */\nfunction stiTypesOf(config: { stiType?: string | string[] } | undefined): string[] {\n const stiType = config?.stiType;\n return stiType === undefined ? [] : typeof stiType === \"string\" ? [stiType] : stiType;\n}\n"],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inheritance.d.cts","names":[],"sources":["../src/inheritance.ts"],"mappings":";;;;iBAagB,wBAAwB,QAAQ,QAAQ,IAAI;
|
|
1
|
+
{"version":3,"file":"inheritance.d.cts","names":[],"sources":["../src/inheritance.ts"],"mappings":";;;;iBAagB,wBAAwB,QAAQ,QAAQ,IAAI;KAqQvD,eAAe;EAAc,MAAM;EAAkB,UAAU;;iBAGpD,eAAe,UAAU,qBAAqB"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inheritance.d.mts","names":[],"sources":["../src/inheritance.ts"],"mappings":";;;;iBAagB,wBAAwB,QAAQ,QAAQ,IAAI;
|
|
1
|
+
{"version":3,"file":"inheritance.d.mts","names":[],"sources":["../src/inheritance.ts"],"mappings":";;;;iBAagB,wBAAwB,QAAQ,QAAQ,IAAI;KAqQvD,eAAe;EAAc,MAAM;EAAkB,UAAU;;iBAGpD,eAAe,UAAU,qBAAqB"}
|
package/build/inheritance.js
CHANGED
|
@@ -113,11 +113,21 @@ function expandSingleTableInheritance(config, entitiesByName, entities) {
|
|
|
113
113
|
const availableCodes = subTypes.map(([code]) => code);
|
|
114
114
|
const availableNames = subTypes.map(([, name]) => name);
|
|
115
115
|
const available = [...availableCodes, ...availableNames];
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
for (const [name, f] of allFields) for (const stiType of stiTypesOf(f)) if (!available.includes(stiType)) fail(`${name}.stiType '${stiType}' is invalid, expected one of ${available.join(", ")}`);
|
|
117
|
+
const requiredFieldNames = new Set([
|
|
118
|
+
...entity.primitives,
|
|
119
|
+
...entity.enums,
|
|
120
|
+
...entity.pgEnums,
|
|
121
|
+
...entity.manyToOnes
|
|
122
|
+
].filter((f) => f.notNull && f.columnDefault === null && !("columnGenerated" in f && f.columnGenerated)).map((f) => f.fieldName));
|
|
123
|
+
for (const [name, f] of allFields) {
|
|
124
|
+
const stiTypes = stiTypesOf(f);
|
|
125
|
+
const claimsEverySubtype = subTypes.every(([code, name]) => stiTypes.some((t) => t === code || t === name));
|
|
126
|
+
if (stiTypes.length > 0 && !claimsEverySubtype && requiredFieldNames.has(name)) fail(`${entity.name}.${name} is notNull with no database default, so it cannot be pushed down to ${stiTypes.map((t) => `'${t}'`).join(", ")} -- the other subtypes would have no value to insert. Either give the column a default, make it nullable (stiType will still make it required on those subtypes), or leave the field on ${entity.name}.`);
|
|
127
|
+
}
|
|
128
|
+
const claimedFieldNames = new Set(allFields.filter(([, f]) => stiTypesOf(f).length > 0).map(([name]) => name));
|
|
119
129
|
for (const [enumCode, subTypeName] of subTypes) {
|
|
120
|
-
const subTypeFields = allFields.filter(([, f]) => f.
|
|
130
|
+
const subTypeFields = allFields.filter(([, f]) => stiTypesOf(f).some((t) => t === subTypeName || t === enumCode));
|
|
121
131
|
const subTypeFieldNames = subTypeFields.map(([name]) => name);
|
|
122
132
|
function maybeRequired(field) {
|
|
123
133
|
if ((subTypeFields.find(([name]) => name === field.fieldName)?.[1]).notNull) field.notNull = true;
|
|
@@ -158,21 +168,22 @@ function expandSingleTableInheritance(config, entitiesByName, entities) {
|
|
|
158
168
|
return this.manyToManys.filter((r) => !r.isDeferredAndDeferrable);
|
|
159
169
|
}
|
|
160
170
|
};
|
|
161
|
-
entity.primitives = entity.primitives.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
162
|
-
entity.enums = entity.enums.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
163
|
-
entity.pgEnums = entity.pgEnums.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
164
|
-
entity.manyToOnes = entity.manyToOnes.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
165
|
-
entity.oneToManys = entity.oneToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
166
|
-
entity.largeOneToManys = entity.largeOneToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
167
|
-
entity.oneToOnes = entity.oneToOnes.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
168
|
-
entity.manyToManys = entity.manyToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
169
|
-
entity.largeManyToManys = entity.largeManyToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
170
|
-
entity.manyToManyEnums = entity.manyToManyEnums.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
171
|
-
entity.polymorphics = entity.polymorphics.filter((f) => !subTypeFieldNames.includes(f.fieldName));
|
|
172
171
|
entity.subTypes.push(subEntity);
|
|
173
172
|
entities.push(subEntity);
|
|
174
173
|
entitiesByName[subEntity.name] = subEntity;
|
|
175
174
|
}
|
|
175
|
+
const keep = (f) => !claimedFieldNames.has(f.fieldName);
|
|
176
|
+
entity.primitives = entity.primitives.filter(keep);
|
|
177
|
+
entity.enums = entity.enums.filter(keep);
|
|
178
|
+
entity.pgEnums = entity.pgEnums.filter(keep);
|
|
179
|
+
entity.manyToOnes = entity.manyToOnes.filter(keep);
|
|
180
|
+
entity.oneToManys = entity.oneToManys.filter(keep);
|
|
181
|
+
entity.largeOneToManys = entity.largeOneToManys.filter(keep);
|
|
182
|
+
entity.oneToOnes = entity.oneToOnes.filter(keep);
|
|
183
|
+
entity.manyToManys = entity.manyToManys.filter(keep);
|
|
184
|
+
entity.largeManyToManys = entity.largeManyToManys.filter(keep);
|
|
185
|
+
entity.manyToManyEnums = entity.manyToManyEnums.filter(keep);
|
|
186
|
+
entity.polymorphics = entity.polymorphics.filter(keep);
|
|
176
187
|
}
|
|
177
188
|
}
|
|
178
189
|
}
|
|
@@ -202,8 +213,8 @@ function rewriteSingleTableForeignKeys(config, entities) {
|
|
|
202
213
|
for (const m2o of entity.manyToOnes) {
|
|
203
214
|
const target = stiEntities.get(m2o.otherEntity.name);
|
|
204
215
|
const base = target?.base.entity.name;
|
|
205
|
-
const stiType = base
|
|
206
|
-
if (target && stiType) {
|
|
216
|
+
const [stiType, ...others] = stiTypesOf(base ? config.entities[base]?.relations?.[m2o.otherFieldName] : void 0);
|
|
217
|
+
if (target && stiType && others.length === 0) {
|
|
207
218
|
const { subTypes } = target;
|
|
208
219
|
m2o.otherEntity = (subTypes.find((s) => s.name === stiType) ?? fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)).entity;
|
|
209
220
|
}
|
|
@@ -211,8 +222,8 @@ function rewriteSingleTableForeignKeys(config, entities) {
|
|
|
211
222
|
for (const poly of entity.polymorphics) for (const comp of poly.components) {
|
|
212
223
|
const target = stiEntities.get(comp.otherEntity.name);
|
|
213
224
|
const base = target?.base.entity.name;
|
|
214
|
-
const stiType = base
|
|
215
|
-
if (target && stiType) {
|
|
225
|
+
const [stiType, ...others] = stiTypesOf(base ? config.entities[base]?.relations?.[comp.otherFieldName] : void 0);
|
|
226
|
+
if (target && stiType && others.length === 0) {
|
|
216
227
|
const { subTypes } = target;
|
|
217
228
|
comp.otherEntity = (subTypes.find((s) => s.name === stiType) ?? fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)).entity;
|
|
218
229
|
}
|
|
@@ -233,6 +244,11 @@ function rewriteSingleTableForeignKeys(config, entities) {
|
|
|
233
244
|
}
|
|
234
245
|
}
|
|
235
246
|
}
|
|
247
|
+
/** Normalizes a field/relation's `stiType`, which may name one subtype or several, to an array. */
|
|
248
|
+
function stiTypesOf(config) {
|
|
249
|
+
const stiType = config?.stiType;
|
|
250
|
+
return stiType === void 0 ? [] : typeof stiType === "string" ? [stiType] : stiType;
|
|
251
|
+
}
|
|
236
252
|
//#endregion
|
|
237
253
|
export { applyInheritanceUpdates, getStiEntities };
|
|
238
254
|
|
package/build/inheritance.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"inheritance.js","names":[],"sources":["../src/inheritance.ts"],"sourcesContent":["import { type Config } from \"./config.ts\";\nimport {\n type DbMetadata,\n type EntityDbMetadata,\n type ManyToManyField,\n type ManyToOneField,\n type PolymorphicFieldComponent,\n canonicalizeOtherEntities,\n makeEntity,\n} from \"./EntityDbMetadata.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** Preserves physical storage metadata, then applies domain inheritance specialization. */\nexport function applyInheritanceUpdates(config: Config, db: DbMetadata): void {\n const { entities, entitiesByName } = db;\n // Preserve storage domains before STI moves fields or rewrites relationship targets.\n for (const meta of entities) {\n meta.physicalMetadata = {\n ...meta,\n name: meta.name,\n primitives: meta.primitives.map((field) => ({ ...field })),\n enums: meta.enums.map((field) => ({ ...field })),\n pgEnums: meta.pgEnums.map((field) => ({ ...field })),\n manyToOnes: meta.manyToOnes.map((field) => ({ ...field })),\n oneToManys: meta.oneToManys.map((field) => ({ ...field })),\n largeOneToManys: meta.largeOneToManys.map((field) => ({ ...field })),\n oneToOnes: meta.oneToOnes.map((field) => ({ ...field })),\n manyToManys: meta.manyToManys.map((field) => ({ ...field })),\n largeManyToManys: meta.largeManyToManys.map((field) => ({ ...field })),\n polymorphics: meta.polymorphics.map((field) => ({\n ...field,\n components: field.components.map((component) => ({ ...component })),\n })),\n nonDeferredFks: meta.nonDeferredFks,\n nonDeferredManyToManyFks: meta.nonDeferredManyToManyFks,\n };\n for (const timestamp of [\"createdAt\", \"updatedAt\", \"deletedAt\"] as const) {\n meta.physicalMetadata[timestamp] = meta.physicalMetadata.primitives.find(\n (field) => field.fieldName === meta[timestamp]?.fieldName,\n );\n }\n }\n setClassTableInheritance(entities, entitiesByName);\n expandSingleTableInheritance(config, entitiesByName, entities);\n rewriteSingleTableForeignKeys(config, entities);\n setupSubTypeSpecialization(config, entities);\n // Now that all relations (incl. specialized ones) exist, collapse the duplicate `otherEntity` objects\n canonicalizeOtherEntities(db);\n}\n\n/**\n * Looks for subtypes specializing a FK of their base type, and give them a specialized m2o.\n *\n * I.e. `SmallPublishers.group: SmallPublisherGroup`.\n *\n * This means the `publishers.group_id` FK will actually be in the `EntityDbMetadata` twice,\n * once for the base and once for the child, which is unusual, but gets the types generated\n * that we want, and then we fixup/dedupe them at runtime in `configure.ts` when creating\n * `meta.allFields`.\n */\nfunction setupSubTypeSpecialization(config: Config, entities: EntityDbMetadata[]): void {\n for (const entity of entities) {\n if (entity.baseType) {\n const entityConfig = config.entities[entity.name];\n const baseConfig = config.entities[entity.baseType.name];\n // Look through the base's m2os & o2ms, looking for a config specialization\n for (const rel of [...entity.baseType.manyToOnes, ...entity.baseType.oneToManys]) {\n const { notNull } = entityConfig?.relations?.[rel.fieldName] ?? {};\n const subType =\n entityConfig?.relations?.[rel.fieldName]?.subType ??\n baseConfig?.relations?.[rel.fieldName]?.subType ??\n // Probe the otherFieldName for a `subType: \"self\"` on self-referential relations in STI tables\n baseConfig?.relations?.[rel.otherFieldName]?.subType ??\n // if we are only marking the relation as required and not specifying a subtype, then use the original type\n (notNull ? rel.otherEntity.name : undefined);\n\n if (!subType) {\n // continue...\n } else if (subType === \"self\" && rel.kind === \"m2o\") {\n // Specialize `TaskNew.copiedFrom: TaskNew` & `TaskOld.copiedFrom: TaskOld`\n entity.manyToOnes.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(entity.name) });\n } else if (subType === \"self\" && rel.kind === \"o2m\") {\n // Specialize `TaskNew.copiedTo: TaskNew[]` & `TaskOld.copiedTo: TaskOld[]`\n entity.oneToManys.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(entity.name) });\n } else if (rel.kind === \"m2o\") {\n // Specialize `SmallPublisher.group: SmallPublisherGroup`\n entity.manyToOnes.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(subType) });\n } else if (rel.kind === \"o2m\") {\n // Specialize `SmallPublisherGroup.publishers: SmallPublisher`\n entity.oneToManys.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(subType) });\n }\n }\n\n // Look through the base's primitives looking for a config specialization\n for (const field of entity.baseType?.primitives ?? []) {\n // the only specialization a primitive can have is nullability\n const { notNull } = entityConfig?.fields?.[field.fieldName] ?? {};\n if (notNull) {\n entity.primitives.push({ ...field, notNull });\n }\n }\n }\n }\n}\n\n/**\n * Ensure CTI base types have their inheritanceType set.\n *\n * (We automatically set `inheritanceType` for STI tables when we see their config\n * setup, see `expandSingleTableInheritance`.)\n */\nfunction setClassTableInheritance(\n entities: EntityDbMetadata[],\n entitiesByName: Record<string, EntityDbMetadata>,\n): void {\n const ctiBaseNames: string[] = [];\n for (const entity of entities) {\n if (entity.baseClassName) {\n ctiBaseNames.push(entity.baseClassName);\n const base = entitiesByName[entity.baseClassName];\n entity.baseType = base;\n base.subTypes.push(entity);\n }\n }\n for (const entity of entities) {\n if (ctiBaseNames.includes(entity.name)) entity.inheritanceType = \"cti\";\n }\n}\n\n/** Expands STI tables into multiple entities, so they get separate `SubTypeCodegen.ts` & `SubType.ts` files. */\nfunction expandSingleTableInheritance(\n config: Config,\n entitiesByName: Record<string, EntityDbMetadata>,\n entities: EntityDbMetadata[],\n): void {\n for (const entity of entities) {\n const [fieldName, stiField] =\n Object.entries(config.entities[entity.name]?.fields || {}).find(([, f]) => !!f.stiDiscriminator) ?? [];\n if (fieldName && stiField && stiField.stiDiscriminator) {\n entity.inheritanceType = \"sti\";\n\n // Ensure we have an enum field so that we can bake the STI discriminators into the metadata.ts file\n const enumField =\n entity.enums.find((e) => e.fieldName === fieldName) ??\n fail(`No enum column found for ${entity.name}.${fieldName}, which is required to use singleTableInheritance`);\n entity.stiDiscriminatorField = enumField.fieldName;\n\n // Find the available discriminators/subtypes, i.e. NEW => NewTask, OLD => OldTask, etc.\n const subTypes = Object.entries(stiField.stiDiscriminator);\n\n const allFields = [\n ...Object.entries(config.entities[entity.name]?.fields ?? {}),\n ...Object.entries(config.entities[entity.name]?.relations ?? {}),\n ];\n\n // Make sure there aren't any typos in `stiType`s\n const availableCodes = subTypes.map(([code]) => code);\n const availableNames = subTypes.map(([, name]) => name);\n const available = [...availableCodes, ...availableNames];\n allFields.filter(([name, f]) => {\n if (f.stiType && !available.includes(f.stiType)) {\n fail(`${name}.stiType '${f.stiType}' is invalid, expected one of ${available.join(\", \")}`);\n }\n });\n\n // Now split each subType out into its out entity\n for (const [enumCode, subTypeName] of subTypes) {\n // Find all the base entity's fields that belong to us\n const subTypeFields = allFields.filter(([, f]) => f.stiType === subTypeName || f.stiType === enumCode);\n const subTypeFieldNames = subTypeFields.map(([name]) => name);\n\n // Make fields as required\n function maybeRequired<T extends { notNull: boolean; fieldName: string }>(field: T): T {\n const config = subTypeFields.find(([name]) => name === field.fieldName)?.[1]!;\n if (config.notNull) field.notNull = true;\n return field;\n }\n\n // Synthesize an entity for this STI sub-entity\n const subEntity: EntityDbMetadata = {\n name: subTypeName,\n entity: makeEntity(subTypeName),\n tableName: entity.tableName,\n physicalMetadata: entity.physicalMetadata,\n primaryKey: entity.primaryKey,\n primitives: entity.primitives.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n enums: entity.enums.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n pgEnums: entity.pgEnums.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n manyToOnes: entity.manyToOnes.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n oneToManys: entity.oneToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n largeOneToManys: entity.largeOneToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n oneToOnes: entity.oneToOnes.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n manyToManys: entity.manyToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n largeManyToManys: entity.largeManyToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n manyToManyEnums: entity.manyToManyEnums.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n polymorphics: entity.polymorphics.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n tagName: entity.tagName,\n createdAt: undefined,\n updatedAt: undefined,\n deletedAt: undefined,\n baseClassName: entity.name,\n baseType: entity,\n subTypes: [],\n inheritanceType: \"sti\",\n stiDiscriminatorValue: (\n enumField.enumRows.find((r) => r.code === enumCode) ??\n fail(`No enum row found for ${entity.name}.${fieldName}.${enumCode}`)\n ).id,\n abstract: false,\n nonDeferredFkOrder: entity.nonDeferredFkOrder,\n get nonDeferredFks(): Array<ManyToOneField | PolymorphicFieldComponent> {\n return [\n ...this.manyToOnes.filter((r) => !r.isDeferredAndDeferrable),\n ...this.polymorphics.flatMap((p) => p.components).filter((c) => !c.isDeferredAndDeferrable),\n ];\n },\n get nonDeferredManyToManyFks(): Array<ManyToManyField> {\n return this.manyToManys.filter((r) => !r.isDeferredAndDeferrable);\n },\n };\n\n // Now strip all the subclass fields from the base class\n entity.primitives = entity.primitives.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.enums = entity.enums.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.pgEnums = entity.pgEnums.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.manyToOnes = entity.manyToOnes.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.oneToManys = entity.oneToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.largeOneToManys = entity.largeOneToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.oneToOnes = entity.oneToOnes.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.manyToManys = entity.manyToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.largeManyToManys = entity.largeManyToManys.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.manyToManyEnums = entity.manyToManyEnums.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.polymorphics = entity.polymorphics.filter((f) => !subTypeFieldNames.includes(f.fieldName));\n entity.subTypes.push(subEntity);\n\n entities.push(subEntity);\n entitiesByName[subEntity.name] = subEntity;\n }\n }\n }\n}\n\ntype StiEntityMap = Map<string, { base: EntityDbMetadata; subTypes: EntityDbMetadata[] }>;\nlet stiEntities: StiEntityMap;\n\nexport function getStiEntities(entities: EntityDbMetadata[]): StiEntityMap {\n if (stiEntities) return stiEntities;\n stiEntities = new Map();\n for (const entity of entities) {\n if (entity.inheritanceType === \"sti\" && entity.stiDiscriminatorField) {\n const base = entity;\n const subTypes = entities.filter((s) => s.baseClassName === entity.name && s !== entity);\n stiEntities.set(entity.name, { base, subTypes });\n // Allow looking up by subType name\n for (const subType of subTypes) {\n stiEntities.set(subType.name, { base, subTypes: [] });\n }\n }\n }\n return stiEntities;\n}\n\n/** Finds FKs pointing to the base table and, if configured, rewrites them to point to the sub-tables. */\nfunction rewriteSingleTableForeignKeys(config: Config, entities: EntityDbMetadata[]): void {\n // See if we even have any STI tables\n const stiEntities = getStiEntities(entities);\n if (stiEntities.size === 0) return;\n // Scan for other entities/relations that point to the STI table\n for (const entity of entities) {\n // m2os -- Look for `entity.task_id` FKs pointing at `Task` and, if configured, rewrite them to point at `TaskOld`\n for (const m2o of entity.manyToOnes) {\n const target = stiEntities.get(m2o.otherEntity.name);\n const base = target?.base.entity.name;\n // See if the user has pushed `Task.entities` down to a subtype\n const stiType = base && config.entities[base]?.relations?.[m2o.otherFieldName]?.stiType;\n if (target && stiType) {\n const { subTypes } = target;\n m2o.otherEntity = (\n subTypes.find((s) => s.name === stiType) ??\n fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)\n ).entity;\n }\n }\n // polys -- Look for `entity.parent_task_id` FKs pointing at `Task` and, if configured, rewrite them to point at `TaskOld`\n for (const poly of entity.polymorphics) {\n for (const comp of poly.components) {\n const target = stiEntities.get(comp.otherEntity.name);\n const base = target?.base.entity.name;\n // See if the user has pushed `Task.entities` down to a subtype\n const stiType = base && config.entities[base]?.relations?.[comp.otherFieldName]?.stiType;\n if (target && stiType) {\n const { subTypes } = target;\n comp.otherEntity = (\n subTypes.find((s) => s.name === stiType) ??\n fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)\n ).entity;\n }\n }\n }\n // o2ms -- Look for `entity.tasks` collections loading `task.entity_id`, but entity has been pushed down to `TaskOld`\n for (const o2m of entity.oneToManys) {\n const target = stiEntities.get(o2m.otherEntity.name);\n if (target && target.base.inheritanceType === \"sti\") {\n // Ensure the incoming FK is not in the base type, and find the 1st subtype (eventually N subtypes?)\n const otherField = target.subTypes.find(\n (st) =>\n !target.base.manyToOnes.some((m) => m.fieldName === o2m.otherFieldName) &&\n st.manyToOnes.some((m) => m.fieldName === o2m.otherFieldName),\n );\n if (otherField) {\n o2m.otherEntity = otherField.entity;\n }\n }\n }\n // m2ms -- Look for `entity.tasks` collections loading m2m rows, but `entity` has been pushed down to `TaskOld`\n for (const m2m of entity.manyToManys) {\n const target = stiEntities.get(m2m.otherEntity.name);\n if (target && target.base.inheritanceType === \"sti\") {\n // Ensure the incoming FK is not in the base type, and find the 1st subtype (eventually N subtypes?)\n const otherField = target.subTypes.find(\n (st) =>\n !target.base.manyToManys.some((m) => m.fieldName === m2m.otherFieldName) &&\n st.manyToManys.some((m) => m.fieldName === m2m.otherFieldName),\n );\n if (otherField) {\n m2m.otherEntity = otherField.entity;\n }\n }\n }\n }\n}\n"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"inheritance.js","names":[],"sources":["../src/inheritance.ts"],"sourcesContent":["import { type Config } from \"./config.ts\";\nimport {\n type DbMetadata,\n type EntityDbMetadata,\n type ManyToManyField,\n type ManyToOneField,\n type PolymorphicFieldComponent,\n canonicalizeOtherEntities,\n makeEntity,\n} from \"./EntityDbMetadata.ts\";\nimport { fail } from \"./utils.ts\";\n\n/** Preserves physical storage metadata, then applies domain inheritance specialization. */\nexport function applyInheritanceUpdates(config: Config, db: DbMetadata): void {\n const { entities, entitiesByName } = db;\n // Preserve storage domains before STI moves fields or rewrites relationship targets.\n for (const meta of entities) {\n meta.physicalMetadata = {\n ...meta,\n name: meta.name,\n primitives: meta.primitives.map((field) => ({ ...field })),\n enums: meta.enums.map((field) => ({ ...field })),\n pgEnums: meta.pgEnums.map((field) => ({ ...field })),\n manyToOnes: meta.manyToOnes.map((field) => ({ ...field })),\n oneToManys: meta.oneToManys.map((field) => ({ ...field })),\n largeOneToManys: meta.largeOneToManys.map((field) => ({ ...field })),\n oneToOnes: meta.oneToOnes.map((field) => ({ ...field })),\n manyToManys: meta.manyToManys.map((field) => ({ ...field })),\n largeManyToManys: meta.largeManyToManys.map((field) => ({ ...field })),\n polymorphics: meta.polymorphics.map((field) => ({\n ...field,\n components: field.components.map((component) => ({ ...component })),\n })),\n nonDeferredFks: meta.nonDeferredFks,\n nonDeferredManyToManyFks: meta.nonDeferredManyToManyFks,\n };\n for (const timestamp of [\"createdAt\", \"updatedAt\", \"deletedAt\"] as const) {\n meta.physicalMetadata[timestamp] = meta.physicalMetadata.primitives.find(\n (field) => field.fieldName === meta[timestamp]?.fieldName,\n );\n }\n }\n setClassTableInheritance(entities, entitiesByName);\n expandSingleTableInheritance(config, entitiesByName, entities);\n rewriteSingleTableForeignKeys(config, entities);\n setupSubTypeSpecialization(config, entities);\n // Now that all relations (incl. specialized ones) exist, collapse the duplicate `otherEntity` objects\n canonicalizeOtherEntities(db);\n}\n\n/**\n * Looks for subtypes specializing a FK of their base type, and give them a specialized m2o.\n *\n * I.e. `SmallPublishers.group: SmallPublisherGroup`.\n *\n * This means the `publishers.group_id` FK will actually be in the `EntityDbMetadata` twice,\n * once for the base and once for the child, which is unusual, but gets the types generated\n * that we want, and then we fixup/dedupe them at runtime in `configure.ts` when creating\n * `meta.allFields`.\n */\nfunction setupSubTypeSpecialization(config: Config, entities: EntityDbMetadata[]): void {\n for (const entity of entities) {\n if (entity.baseType) {\n const entityConfig = config.entities[entity.name];\n const baseConfig = config.entities[entity.baseType.name];\n // Look through the base's m2os & o2ms, looking for a config specialization\n for (const rel of [...entity.baseType.manyToOnes, ...entity.baseType.oneToManys]) {\n const { notNull } = entityConfig?.relations?.[rel.fieldName] ?? {};\n const subType =\n entityConfig?.relations?.[rel.fieldName]?.subType ??\n baseConfig?.relations?.[rel.fieldName]?.subType ??\n // Probe the otherFieldName for a `subType: \"self\"` on self-referential relations in STI tables\n baseConfig?.relations?.[rel.otherFieldName]?.subType ??\n // if we are only marking the relation as required and not specifying a subtype, then use the original type\n (notNull ? rel.otherEntity.name : undefined);\n\n if (!subType) {\n // continue...\n } else if (subType === \"self\" && rel.kind === \"m2o\") {\n // Specialize `TaskNew.copiedFrom: TaskNew` & `TaskOld.copiedFrom: TaskOld`\n entity.manyToOnes.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(entity.name) });\n } else if (subType === \"self\" && rel.kind === \"o2m\") {\n // Specialize `TaskNew.copiedTo: TaskNew[]` & `TaskOld.copiedTo: TaskOld[]`\n entity.oneToManys.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(entity.name) });\n } else if (rel.kind === \"m2o\") {\n // Specialize `SmallPublisher.group: SmallPublisherGroup`\n entity.manyToOnes.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(subType) });\n } else if (rel.kind === \"o2m\") {\n // Specialize `SmallPublisherGroup.publishers: SmallPublisher`\n entity.oneToManys.push({ ...rel, ...(notNull ? { notNull } : {}), otherEntity: makeEntity(subType) });\n }\n }\n\n // Look through the base's primitives looking for a config specialization\n for (const field of entity.baseType?.primitives ?? []) {\n // the only specialization a primitive can have is nullability\n const { notNull } = entityConfig?.fields?.[field.fieldName] ?? {};\n if (notNull) {\n entity.primitives.push({ ...field, notNull });\n }\n }\n }\n }\n}\n\n/**\n * Ensure CTI base types have their inheritanceType set.\n *\n * (We automatically set `inheritanceType` for STI tables when we see their config\n * setup, see `expandSingleTableInheritance`.)\n */\nfunction setClassTableInheritance(\n entities: EntityDbMetadata[],\n entitiesByName: Record<string, EntityDbMetadata>,\n): void {\n const ctiBaseNames: string[] = [];\n for (const entity of entities) {\n if (entity.baseClassName) {\n ctiBaseNames.push(entity.baseClassName);\n const base = entitiesByName[entity.baseClassName];\n entity.baseType = base;\n base.subTypes.push(entity);\n }\n }\n for (const entity of entities) {\n if (ctiBaseNames.includes(entity.name)) entity.inheritanceType = \"cti\";\n }\n}\n\n/** Expands STI tables into multiple entities, so they get separate `SubTypeCodegen.ts` & `SubType.ts` files. */\nfunction expandSingleTableInheritance(\n config: Config,\n entitiesByName: Record<string, EntityDbMetadata>,\n entities: EntityDbMetadata[],\n): void {\n for (const entity of entities) {\n const [fieldName, stiField] =\n Object.entries(config.entities[entity.name]?.fields || {}).find(([, f]) => !!f.stiDiscriminator) ?? [];\n if (fieldName && stiField && stiField.stiDiscriminator) {\n entity.inheritanceType = \"sti\";\n\n // Ensure we have an enum field so that we can bake the STI discriminators into the metadata.ts file\n const enumField =\n entity.enums.find((e) => e.fieldName === fieldName) ??\n fail(`No enum column found for ${entity.name}.${fieldName}, which is required to use singleTableInheritance`);\n entity.stiDiscriminatorField = enumField.fieldName;\n\n // Find the available discriminators/subtypes, i.e. NEW => NewTask, OLD => OldTask, etc.\n const subTypes = Object.entries(stiField.stiDiscriminator);\n\n const allFields = [\n ...Object.entries(config.entities[entity.name]?.fields ?? {}),\n ...Object.entries(config.entities[entity.name]?.relations ?? {}),\n ];\n\n // Make sure there aren't any typos in `stiType`s\n const availableCodes = subTypes.map(([code]) => code);\n const availableNames = subTypes.map(([, name]) => name);\n const available = [...availableCodes, ...availableNames];\n for (const [name, f] of allFields) {\n for (const stiType of stiTypesOf(f)) {\n if (!available.includes(stiType)) {\n fail(`${name}.stiType '${stiType}' is invalid, expected one of ${available.join(\", \")}`);\n }\n }\n }\n\n // A `notNull` column with no database default cannot be pushed down to a subtype: the other\n // subtypes omit it from their INSERT (see `addInserts`), and the database has nothing to fall back\n // on. A `notNull` column *with* a default is fine -- the other subtypes simply get the default.\n const requiredFieldNames = new Set(\n [...entity.primitives, ...entity.enums, ...entity.pgEnums, ...entity.manyToOnes]\n .filter((f) => f.notNull && f.columnDefault === null && !(\"columnGenerated\" in f && f.columnGenerated))\n .map((f) => f.fieldName),\n );\n for (const [name, f] of allFields) {\n const stiTypes = stiTypesOf(f);\n // Claiming every subtype leaves no one without a value, so it's equivalent to staying on the base\n const claimsEverySubtype = subTypes.every(([code, name]) => stiTypes.some((t) => t === code || t === name));\n if (stiTypes.length > 0 && !claimsEverySubtype && requiredFieldNames.has(name)) {\n fail(\n `${entity.name}.${name} is notNull with no database default, so it cannot be pushed down to` +\n ` ${stiTypes.map((t) => `'${t}'`).join(\", \")} -- the other subtypes would have no value to` +\n ` insert. Either give the column a default, make it nullable (stiType will still make it` +\n ` required on those subtypes), or leave the field on ${entity.name}.`,\n );\n }\n }\n\n // Names claimed by any subtype; stripped from the base after the loop, not during it, so that a\n // field claimed by two subtypes is still on the base when the second iteration looks for it.\n const claimedFieldNames = new Set(allFields.filter(([, f]) => stiTypesOf(f).length > 0).map(([name]) => name));\n\n // Now split each subType out into its out entity\n for (const [enumCode, subTypeName] of subTypes) {\n // Find all the base entity's fields that belong to us\n const subTypeFields = allFields.filter(([, f]) =>\n stiTypesOf(f).some((t) => t === subTypeName || t === enumCode),\n );\n const subTypeFieldNames = subTypeFields.map(([name]) => name);\n\n // Make fields as required\n function maybeRequired<T extends { notNull: boolean; fieldName: string }>(field: T): T {\n const config = subTypeFields.find(([name]) => name === field.fieldName)?.[1]!;\n if (config.notNull) field.notNull = true;\n return field;\n }\n\n // Synthesize an entity for this STI sub-entity\n const subEntity: EntityDbMetadata = {\n name: subTypeName,\n entity: makeEntity(subTypeName),\n tableName: entity.tableName,\n physicalMetadata: entity.physicalMetadata,\n primaryKey: entity.primaryKey,\n primitives: entity.primitives.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n enums: entity.enums.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n pgEnums: entity.pgEnums.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n manyToOnes: entity.manyToOnes.filter((f) => subTypeFieldNames.includes(f.fieldName)).map(maybeRequired),\n oneToManys: entity.oneToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n largeOneToManys: entity.largeOneToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n oneToOnes: entity.oneToOnes.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n manyToManys: entity.manyToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n largeManyToManys: entity.largeManyToManys.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n manyToManyEnums: entity.manyToManyEnums.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n polymorphics: entity.polymorphics.filter((f) => subTypeFieldNames.includes(f.fieldName)),\n tagName: entity.tagName,\n createdAt: undefined,\n updatedAt: undefined,\n deletedAt: undefined,\n baseClassName: entity.name,\n baseType: entity,\n subTypes: [],\n inheritanceType: \"sti\",\n stiDiscriminatorValue: (\n enumField.enumRows.find((r) => r.code === enumCode) ??\n fail(`No enum row found for ${entity.name}.${fieldName}.${enumCode}`)\n ).id,\n abstract: false,\n nonDeferredFkOrder: entity.nonDeferredFkOrder,\n get nonDeferredFks(): Array<ManyToOneField | PolymorphicFieldComponent> {\n return [\n ...this.manyToOnes.filter((r) => !r.isDeferredAndDeferrable),\n ...this.polymorphics.flatMap((p) => p.components).filter((c) => !c.isDeferredAndDeferrable),\n ];\n },\n get nonDeferredManyToManyFks(): Array<ManyToManyField> {\n return this.manyToManys.filter((r) => !r.isDeferredAndDeferrable);\n },\n };\n\n entity.subTypes.push(subEntity);\n\n entities.push(subEntity);\n entitiesByName[subEntity.name] = subEntity;\n }\n\n // Now strip the subclass fields from the base class\n const keep = <T extends { fieldName: string }>(f: T) => !claimedFieldNames.has(f.fieldName);\n entity.primitives = entity.primitives.filter(keep);\n entity.enums = entity.enums.filter(keep);\n entity.pgEnums = entity.pgEnums.filter(keep);\n entity.manyToOnes = entity.manyToOnes.filter(keep);\n entity.oneToManys = entity.oneToManys.filter(keep);\n entity.largeOneToManys = entity.largeOneToManys.filter(keep);\n entity.oneToOnes = entity.oneToOnes.filter(keep);\n entity.manyToManys = entity.manyToManys.filter(keep);\n entity.largeManyToManys = entity.largeManyToManys.filter(keep);\n entity.manyToManyEnums = entity.manyToManyEnums.filter(keep);\n entity.polymorphics = entity.polymorphics.filter(keep);\n }\n }\n}\n\ntype StiEntityMap = Map<string, { base: EntityDbMetadata; subTypes: EntityDbMetadata[] }>;\nlet stiEntities: StiEntityMap;\n\nexport function getStiEntities(entities: EntityDbMetadata[]): StiEntityMap {\n if (stiEntities) return stiEntities;\n stiEntities = new Map();\n for (const entity of entities) {\n if (entity.inheritanceType === \"sti\" && entity.stiDiscriminatorField) {\n const base = entity;\n const subTypes = entities.filter((s) => s.baseClassName === entity.name && s !== entity);\n stiEntities.set(entity.name, { base, subTypes });\n // Allow looking up by subType name\n for (const subType of subTypes) {\n stiEntities.set(subType.name, { base, subTypes: [] });\n }\n }\n }\n return stiEntities;\n}\n\n/** Finds FKs pointing to the base table and, if configured, rewrites them to point to the sub-tables. */\nfunction rewriteSingleTableForeignKeys(config: Config, entities: EntityDbMetadata[]): void {\n // See if we even have any STI tables\n const stiEntities = getStiEntities(entities);\n if (stiEntities.size === 0) return;\n // Scan for other entities/relations that point to the STI table\n for (const entity of entities) {\n // m2os -- Look for `entity.task_id` FKs pointing at `Task` and, if configured, rewrite them to point at `TaskOld`\n for (const m2o of entity.manyToOnes) {\n const target = stiEntities.get(m2o.otherEntity.name);\n const base = target?.base.entity.name;\n // See if the user has pushed `Task.entities` down to a subtype\n // Only a lone subtype can retype the FK; naming several means the FK can point at any of them,\n // which is just the base type, so leave it alone.\n const [stiType, ...others] = stiTypesOf(\n base ? config.entities[base]?.relations?.[m2o.otherFieldName] : undefined,\n );\n if (target && stiType && others.length === 0) {\n const { subTypes } = target;\n m2o.otherEntity = (\n subTypes.find((s) => s.name === stiType) ??\n fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)\n ).entity;\n }\n }\n // polys -- Look for `entity.parent_task_id` FKs pointing at `Task` and, if configured, rewrite them to point at `TaskOld`\n for (const poly of entity.polymorphics) {\n for (const comp of poly.components) {\n const target = stiEntities.get(comp.otherEntity.name);\n const base = target?.base.entity.name;\n // See if the user has pushed `Task.entities` down to a subtype\n const [stiType, ...others] = stiTypesOf(\n base ? config.entities[base]?.relations?.[comp.otherFieldName] : undefined,\n );\n if (target && stiType && others.length === 0) {\n const { subTypes } = target;\n comp.otherEntity = (\n subTypes.find((s) => s.name === stiType) ??\n fail(`Could not find STI type '${stiType}' in ${subTypes.map((s) => s.name)}`)\n ).entity;\n }\n }\n }\n // o2ms -- Look for `entity.tasks` collections loading `task.entity_id`, but entity has been pushed down to `TaskOld`\n for (const o2m of entity.oneToManys) {\n const target = stiEntities.get(o2m.otherEntity.name);\n if (target && target.base.inheritanceType === \"sti\") {\n // Ensure the incoming FK is not in the base type, and find the 1st subtype (eventually N subtypes?)\n const otherField = target.subTypes.find(\n (st) =>\n !target.base.manyToOnes.some((m) => m.fieldName === o2m.otherFieldName) &&\n st.manyToOnes.some((m) => m.fieldName === o2m.otherFieldName),\n );\n if (otherField) {\n o2m.otherEntity = otherField.entity;\n }\n }\n }\n // m2ms -- Look for `entity.tasks` collections loading m2m rows, but `entity` has been pushed down to `TaskOld`\n for (const m2m of entity.manyToManys) {\n const target = stiEntities.get(m2m.otherEntity.name);\n if (target && target.base.inheritanceType === \"sti\") {\n // Ensure the incoming FK is not in the base type, and find the 1st subtype (eventually N subtypes?)\n const otherField = target.subTypes.find(\n (st) =>\n !target.base.manyToManys.some((m) => m.fieldName === m2m.otherFieldName) &&\n st.manyToManys.some((m) => m.fieldName === m2m.otherFieldName),\n );\n if (otherField) {\n m2m.otherEntity = otherField.entity;\n }\n }\n }\n }\n}\n\n/** Normalizes a field/relation's `stiType`, which may name one subtype or several, to an array. */\nfunction stiTypesOf(config: { stiType?: string | string[] } | undefined): string[] {\n const stiType = config?.stiType;\n return stiType === undefined ? [] : typeof stiType === \"string\" ? [stiType] : stiType;\n}\n"],"mappings":"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"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "joist-codegen",
|
|
3
|
-
"version": "2.3.0-next.
|
|
3
|
+
"version": "2.3.0-next.83",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -38,7 +38,7 @@
|
|
|
38
38
|
"skills"
|
|
39
39
|
],
|
|
40
40
|
"peerDependencies": {
|
|
41
|
-
"joist-utils": "2.3.0-next.
|
|
41
|
+
"joist-utils": "2.3.0-next.83",
|
|
42
42
|
"knex": "^3.1.0",
|
|
43
43
|
"pg": "^8.23.0"
|
|
44
44
|
},
|