joist-core 2.4.0-next.2 → 2.4.0-next.21

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (153) hide show
  1. package/build/EntityManager.cjs +25 -11
  2. package/build/EntityManager.cjs.map +1 -1
  3. package/build/EntityManager.d.cts +11 -4
  4. package/build/EntityManager.d.cts.map +1 -1
  5. package/build/EntityManager.d.mts +11 -4
  6. package/build/EntityManager.d.mts.map +1 -1
  7. package/build/EntityManager.js +25 -13
  8. package/build/EntityManager.js.map +1 -1
  9. package/build/EntityMetadata.cjs +0 -1
  10. package/build/EntityMetadata.cjs.map +1 -1
  11. package/build/EntityMetadata.d.cts +8 -4
  12. package/build/EntityMetadata.d.cts.map +1 -1
  13. package/build/EntityMetadata.d.mts +8 -4
  14. package/build/EntityMetadata.d.mts.map +1 -1
  15. package/build/EntityMetadata.js +0 -1
  16. package/build/EntityMetadata.js.map +1 -1
  17. package/build/IndexManager.cjs +23 -5
  18. package/build/IndexManager.cjs.map +1 -1
  19. package/build/IndexManager.d.cts.map +1 -1
  20. package/build/IndexManager.d.mts.map +1 -1
  21. package/build/IndexManager.js +23 -5
  22. package/build/IndexManager.js.map +1 -1
  23. package/build/batchloaders/populateBatchLoader.cjs +2 -2
  24. package/build/batchloaders/populateBatchLoader.js +2 -2
  25. package/build/batchloaders/recursiveChildrenBatchLoader.cjs +1 -1
  26. package/build/batchloaders/recursiveChildrenBatchLoader.js +1 -1
  27. package/build/batchloaders/recursiveM2mBatchLoader.cjs +1 -1
  28. package/build/batchloaders/recursiveM2mBatchLoader.js +1 -1
  29. package/build/batchloaders/recursiveParentsBatchLoader.cjs +1 -1
  30. package/build/batchloaders/recursiveParentsBatchLoader.js +1 -1
  31. package/build/config.cjs +74 -1
  32. package/build/config.cjs.map +1 -1
  33. package/build/config.d.cts +83 -2
  34. package/build/config.d.cts.map +1 -1
  35. package/build/config.d.mts +83 -2
  36. package/build/config.d.mts.map +1 -1
  37. package/build/config.js +74 -1
  38. package/build/config.js.map +1 -1
  39. package/build/configure.cjs +6 -2
  40. package/build/configure.cjs.map +1 -1
  41. package/build/configure.d.cts.map +1 -1
  42. package/build/configure.d.mts.map +1 -1
  43. package/build/configure.js +6 -2
  44. package/build/configure.js.map +1 -1
  45. package/build/dataloaders/findDataLoader.cjs +1 -1
  46. package/build/dataloaders/findDataLoader.js +1 -1
  47. package/build/dataloaders/findOrCreateDataLoader.cjs +6 -2
  48. package/build/dataloaders/findOrCreateDataLoader.cjs.map +1 -1
  49. package/build/dataloaders/findOrCreateDataLoader.d.cts.map +1 -1
  50. package/build/dataloaders/findOrCreateDataLoader.d.mts.map +1 -1
  51. package/build/dataloaders/findOrCreateDataLoader.js +7 -3
  52. package/build/dataloaders/findOrCreateDataLoader.js.map +1 -1
  53. package/build/dataloaders/findPaginatedDataLoader.cjs +1 -1
  54. package/build/dataloaders/findPaginatedDataLoader.js +1 -1
  55. package/build/defaults.cjs +2 -2
  56. package/build/defaults.js +2 -2
  57. package/build/fields.cjs +1 -0
  58. package/build/fields.cjs.map +1 -1
  59. package/build/fields.d.cts.map +1 -1
  60. package/build/fields.d.mts.map +1 -1
  61. package/build/fields.js +1 -0
  62. package/build/fields.js.map +1 -1
  63. package/build/index.cjs +13 -8
  64. package/build/index.cjs.map +1 -1
  65. package/build/index.d.cts +4 -3
  66. package/build/index.d.cts.map +1 -1
  67. package/build/index.d.mts +4 -3
  68. package/build/index.d.mts.map +1 -1
  69. package/build/index.js +13 -10
  70. package/build/index.js.map +1 -1
  71. package/build/json.cjs +3 -3
  72. package/build/json.js +3 -3
  73. package/build/loading/loadHints.cjs +1 -1
  74. package/build/loading/loadHints.js +1 -1
  75. package/build/loading/withLoaded.cjs +2 -2
  76. package/build/loading/withLoaded.js +2 -2
  77. package/build/newTestInstance.cjs +1 -0
  78. package/build/newTestInstance.cjs.map +1 -1
  79. package/build/newTestInstance.d.cts.map +1 -1
  80. package/build/newTestInstance.d.mts.map +1 -1
  81. package/build/newTestInstance.js +1 -0
  82. package/build/newTestInstance.js.map +1 -1
  83. package/build/preloading/partitionHint.cjs +1 -1
  84. package/build/preloading/partitionHint.js +1 -1
  85. package/build/queries/sql/execute.cjs +68 -89
  86. package/build/queries/sql/execute.cjs.map +1 -1
  87. package/build/queries/sql/execute.d.cts +35 -18
  88. package/build/queries/sql/execute.d.cts.map +1 -1
  89. package/build/queries/sql/execute.d.mts +35 -18
  90. package/build/queries/sql/execute.d.mts.map +1 -1
  91. package/build/queries/sql/execute.js +70 -91
  92. package/build/queries/sql/execute.js.map +1 -1
  93. package/build/queries/sql/query.cjs +77 -30
  94. package/build/queries/sql/query.cjs.map +1 -1
  95. package/build/queries/sql/query.d.cts +64 -21
  96. package/build/queries/sql/query.d.cts.map +1 -1
  97. package/build/queries/sql/query.d.mts +64 -21
  98. package/build/queries/sql/query.d.mts.map +1 -1
  99. package/build/queries/sql/query.js +75 -30
  100. package/build/queries/sql/query.js.map +1 -1
  101. package/build/reactivity/ReactionsManager.cjs +168 -2
  102. package/build/reactivity/ReactionsManager.cjs.map +1 -1
  103. package/build/reactivity/ReactionsManager.d.cts +54 -1
  104. package/build/reactivity/ReactionsManager.d.cts.map +1 -1
  105. package/build/reactivity/ReactionsManager.d.mts +54 -1
  106. package/build/reactivity/ReactionsManager.d.mts.map +1 -1
  107. package/build/reactivity/ReactionsManager.js +169 -3
  108. package/build/reactivity/ReactionsManager.js.map +1 -1
  109. package/build/reactivity/reactiveHints.cjs +3 -3
  110. package/build/reactivity/reactiveHints.cjs.map +1 -1
  111. package/build/reactivity/reactiveHints.d.cts.map +1 -1
  112. package/build/reactivity/reactiveHints.d.mts.map +1 -1
  113. package/build/reactivity/reactiveHints.js +3 -3
  114. package/build/reactivity/reactiveHints.js.map +1 -1
  115. package/build/relations/AsyncReactiveField.cjs +3 -3
  116. package/build/relations/AsyncReactiveField.js +3 -3
  117. package/build/relations/LazyField.cjs +14 -0
  118. package/build/relations/LazyField.cjs.map +1 -1
  119. package/build/relations/LazyField.d.cts +6 -0
  120. package/build/relations/LazyField.d.cts.map +1 -1
  121. package/build/relations/LazyField.d.mts +6 -0
  122. package/build/relations/LazyField.d.mts.map +1 -1
  123. package/build/relations/LazyField.js +14 -0
  124. package/build/relations/LazyField.js.map +1 -1
  125. package/build/relations/ReactiveField.cjs +2 -2
  126. package/build/relations/ReactiveField.js +2 -2
  127. package/build/relations/ReactiveManyToMany.cjs +1 -1
  128. package/build/relations/ReactiveManyToMany.js +1 -1
  129. package/build/relations/ReactiveReference.cjs +1 -1
  130. package/build/relations/ReactiveReference.js +1 -1
  131. package/build/relations/RecursiveCollection.cjs +3 -3
  132. package/build/relations/RecursiveCollection.js +3 -3
  133. package/build/relations/hasProperty.cjs +2 -2
  134. package/build/relations/hasProperty.js +2 -2
  135. package/build/relations/index.cjs +5 -5
  136. package/build/relations/index.js +5 -5
  137. package/build/resurrection.cjs +11 -1
  138. package/build/resurrection.cjs.map +1 -1
  139. package/build/resurrection.d.cts +4 -1
  140. package/build/resurrection.d.cts.map +1 -1
  141. package/build/resurrection.d.mts +4 -1
  142. package/build/resurrection.d.mts.map +1 -1
  143. package/build/resurrection.js +11 -2
  144. package/build/resurrection.js.map +1 -1
  145. package/build/transitions.cjs +89 -0
  146. package/build/transitions.cjs.map +1 -0
  147. package/build/transitions.d.cts +110 -0
  148. package/build/transitions.d.cts.map +1 -0
  149. package/build/transitions.d.mts +110 -0
  150. package/build/transitions.d.mts.map +1 -0
  151. package/build/transitions.js +84 -0
  152. package/build/transitions.js.map +1 -0
  153. package/package.json +2 -2
@@ -1 +1 @@
1
- {"version":3,"file":"configure.cjs","names":["getBaseAndSelfMetas","getBaseSelfAndSubMetas","fail","tagFromId","maybeResolveReferenceToId","maybeGetRuntimeConfig","isCannotBeUpdatedRule","AsyncDefault","reverseReactiveHint","getProperties","AsyncReactiveFieldImpl","SimpleFieldSerde"],"sources":["../src/configure.ts"],"sourcesContent":["import { type Reactable, setAfterMetadataLocked, setBooted } from \"src/config.ts\";\nimport { AsyncDefault } from \"src/defaults.ts\";\nimport { type Entity } from \"src/Entity.ts\";\nimport { type MaybeAbstractEntityConstructor, type TaggedId } from \"src/EntityManager.ts\";\nimport {\n type EntityMetadata,\n type EnumField,\n type ManyToOneField,\n type OneToManyField,\n getBaseAndSelfMetas,\n getBaseSelfAndSubMetas,\n getMetadata,\n} from \"src/EntityMetadata.ts\";\nimport { getProperties } from \"src/getProperties.ts\";\nimport { maybeResolveReferenceToId, setTaggedIdDelimiter, tagFromId } from \"src/keys.ts\";\nimport { reverseReactiveHint } from \"src/reactivity/reactiveHints.ts\";\nimport { AsyncReactiveFieldImpl } from \"src/relations/AsyncReactiveField.ts\";\nimport { type ReactiveManyToManyImpl, type ReactiveReferenceImpl, type Reference } from \"src/relations/index.ts\";\nimport { type ReactiveFieldImpl } from \"src/relations/ReactiveField.ts\";\nimport { isCannotBeUpdatedRule } from \"src/rules.ts\";\nimport { maybeGetRuntimeConfig } from \"src/runtimeConfig.ts\";\nimport { SimpleFieldSerde } from \"src/serde/fieldSerde.ts\";\nimport { defineLazyGetter, fail } from \"src/utils.ts\";\n\nconst tagToConstructorMap = new Map<string, MaybeAbstractEntityConstructor<any>>();\nconst tableToMetaMap = new Map<string, EntityMetadata>();\nconst typeToMetaMap = new Map<string, EntityMetadata>();\n\nlet previousBootError: any;\n\n/** Performs our boot-time initialization, i.e. hooking up reactivity. */\nexport function configureMetadata(metas: EntityMetadata[]): void {\n // Add explicit \"did we already fail\" check b/c if a transformer like tsx gets a runtime error from\n // here, it can potentially suppress it, move on to another file, which will naively re-invoke\n // `configureMetadata` again, and fail with a very confusing \"Duplicate tag\" error\n if (previousBootError) {\n throw previousBootError;\n }\n try {\n populateConstructorMaps(metas);\n hookUpBaseTypeAndSubTypes(metas);\n installMetadataGetters(metas);\n sortMetasByBaseType(metas);\n setImmutableFields(metas);\n populatePolyComponentFields(metas);\n fireAfterMetadatas(metas);\n // Callers can make `config` calls during `afterMetadata` callbacks, but after that\n // we don't allow any more config changes.\n setBooted();\n // Do these after `fireAfterMetadatas`, in case afterMetadata callbacks added more defaults/rules\n copyAsyncDefaults(metas);\n reverseIndexReactivity(metas);\n installReactiveMetadataGetters(metas);\n copyRunBeforeBooksToBaseType(metas);\n } catch (e) {\n previousBootError = e;\n throw e;\n }\n}\n\n/** Installs lazy lookup getters for metadata-derived caches. */\nfunction installMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n defineLazyGetter(meta, \"subTypesByType\", function buildSubTypesByType() {\n return new Map(meta.subTypes.map((st) => [st.type, st]));\n });\n defineLazyGetter(meta, \"subTypesByStiValue\", function buildSubTypesByStiValue() {\n return new Map(meta.subTypes.map((st) => [st.stiDiscriminatorValue, st]));\n });\n defineLazyGetter(meta, \"stiDiscriminatorColumnName\", function buildStiDiscriminatorColumnName() {\n const field = meta.fields[meta.stiDiscriminatorField!];\n if (field === undefined) throw new Error(`${meta.type} does not have an STI discriminator field`);\n if (field.kind !== \"enum\") throw new Error(\"Discriminator field must be an enum\");\n return (field as EnumField).serde.columns[0].columnName;\n });\n defineLazyGetter(meta, \"lazyFieldNames\", function buildLazyFieldNames() {\n return new Set(\n Object.values(meta.fields)\n .filter((f) => f.kind === \"primitive\" && f.lazy)\n .map((f) => f.fieldName),\n );\n });\n defineLazyGetter(meta, \"hasLazyColumns\", function buildHasLazyColumns() {\n return meta.lazyFieldNames!.size > 0;\n });\n defineLazyGetter(meta, \"syncDerivedFields\", function buildSyncDerivedFields() {\n return Object.values(meta.allFields)\n .filter((f) => (f.kind === \"primitive\" || f.kind === \"enum\") && f.derived === \"sync\")\n .map((f) => f.fieldName);\n });\n }\n}\n\n/** Installs lazy getters for reactivity caches after reactivity has been reverse-indexed. */\nfunction installReactiveMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n defineLazyGetter(meta, \"reactables\", function buildReactables() {\n return getBaseAndSelfMetas(meta)\n .flatMap((m) => m.config.__data.reactables)\n .filter((r) => !r.isReadOnly);\n });\n defineLazyGetter(meta, \"reactablesByField\", function buildReactablesByField() {\n return indexReactablesByField(meta.reactables!);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnly\", function buildReactablesIncludingReadOnly() {\n return getBaseAndSelfMetas(meta).flatMap((m) => m.config.__data.reactables);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnlyByField\", function buildReactablesIncludingReadOnlyByField() {\n return indexReactablesByField(meta.reactablesIncludingReadOnly!);\n });\n defineLazyGetter(meta, \"reactiveRules\", function buildReactiveRules() {\n // We use \"AndSub\" because `reactiveRules` is called with `todo.metadata`, which is always\n // the root type, but ofc we don't want to skip subtype rules.\n //\n // I had considered filtering this list with `rr.fields.length > 0`, but even rules with 100%\n // immutable fields (so all read-only, and so not \"reactive\") need to run on initial entity creation.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveRules);\n });\n defineLazyGetter(meta, \"reactiveCommitRules\", function buildReactiveCommitRules() {\n // Same \"AndSub\" reasoning as `reactiveRules`, just for the post-flush/pre-commit commit rules.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveCommitRules);\n });\n defineLazyGetter(meta, \"hasCommitRules\", function buildHasCommitRules() {\n // True if flushing an entity of this type could trigger commit-rule work, so `em.flush` can\n // skip the whole commit-rule pass otherwise. We need *both* checks because hinted and\n // non-hinted commit rules are stored in different places:\n //\n // 1. Hinted commit rules are reverse-indexed onto their *trigger* entity's `reactiveCommitRules`,\n // which is often a *different* entity than the one the rule is declared on. I.e. a rule\n // `config.addCommitRule({ books: \"title\" }, fn)` declared on `Author` lands on\n // `Book.reactiveCommitRules`, so flushing a Book must run it even though `Book`'s own\n // `config.__data.commitRules` is empty — hence checking `reactiveCommitRules`, not `commitRules`.\n //\n // 2. Non-hinted commit rules are *not* reverse-indexed at all; they run on every insert/update of\n // the entity they're declared on (via `validateSimpleRules`). I.e. `config.addCommitRule(fn)` on\n // `Author` only ever shows up in `Author.config.__data.commitRules` with `hint === undefined`,\n // so `reactiveCommitRules` would miss it. (We filter to `hint === undefined` because hinted\n // rules are already covered by check #1.)\n return (\n meta.reactiveCommitRules!.length > 0 ||\n getBaseSelfAndSubMetas(meta).some((m) => m.config.__data.commitRules.some((r) => r.hint === undefined))\n );\n });\n }\n}\n\n// Sort metas in place by inheritance hierarchy so that the base type comes before subtypes\nfunction sortMetasByBaseType(metas: EntityMetadata[]): void {\n metas.sort(compareMetasByBaseType);\n}\n\n// Compare metas by inheritance hierarchy so that the base type sorts before subtypes\nfunction compareMetasByBaseType(a: EntityMetadata, b: EntityMetadata): number {\n if (a.baseTypes.length > 0 && b.baseTypes.length === 0) return 1;\n if (a.baseTypes.length === 0 && b.baseTypes.length > 0) return -1;\n if (a.baseTypes.some((baseType) => baseType === b)) return 1;\n if (b.baseTypes.some((baseType) => baseType === a)) return -1;\n return a.type.localeCompare(b.type);\n}\n\nfunction fireAfterMetadatas(metas: EntityMetadata[]): void {\n setAfterMetadataLocked();\n for (const meta of metas) {\n for (const fn of meta.config.__data.afterMetadataCallbacks) fn(meta);\n }\n}\n\nexport function resetConstructorMap(): void {\n tagToConstructorMap.clear();\n setTaggedIdDelimiter(\":\");\n}\n\nexport function getConstructorFromTag(tag: string): MaybeAbstractEntityConstructor<any> {\n return tagToConstructorMap.get(tag) ?? fail(`Unknown tag: \"${tag}\" `);\n}\n\nexport function getConstructorFromTaggedId(id: TaggedId): MaybeAbstractEntityConstructor<any> {\n return getConstructorFromTag(tagFromId(id));\n}\n\nexport function getMetadataForTable(tableName: string): EntityMetadata {\n return tableToMetaMap.get(tableName) ?? fail(`Unknown table ${tableName}`);\n}\n\nexport function getMetadataForType(typeName: string): EntityMetadata {\n return typeToMetaMap.get(typeName) ?? fail(`Unknown type ${typeName}`);\n}\n\n/** Returns metadata for `typeName`, if `configureMetadata` has populated the type map. */\nexport function maybeGetMetadataForType<T extends Entity = Entity>(typeName: string): EntityMetadata<T> | undefined {\n return typeToMetaMap.get(typeName) as EntityMetadata<T> | undefined;\n}\n\nexport function maybeGetConstructorFromReference(\n value: string | Entity | Reference<any, any, any> | undefined,\n): MaybeAbstractEntityConstructor<any> | undefined {\n const id = maybeResolveReferenceToId(value);\n return id ? getConstructorFromTaggedId(id) : undefined;\n}\n\nfunction populateConstructorMaps(metas: EntityMetadata[]): void {\n const runtimeConfig = maybeGetRuntimeConfig();\n const tagDelimiter = runtimeConfig && Object.hasOwn(runtimeConfig, \"tagDelimiter\") ? runtimeConfig.tagDelimiter : \":\";\n setTaggedIdDelimiter(tagDelimiter);\n\n for (const meta of metas) {\n // Add each (root) constructor into our tag -> constructor map for future lookups\n if (!meta.baseType) {\n const existing = tagToConstructorMap.get(meta.tagName);\n if (existing) throw new Error(`Duplicate tag '${meta.tagName}' for ${meta.type} and ${existing.name}`);\n tagToConstructorMap.set(meta.tagName, meta.cstr);\n }\n // Same for tables, but include subclass tables\n tableToMetaMap.set(meta.tableName, meta);\n typeToMetaMap.set(meta.type, meta);\n }\n}\n\n// Do a first pass to flag immutable fields (which we'll use in reverseReactiveHint)\nfunction setImmutableFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Scan rules for cannotBeUpdated so that we can set `field.immutable`\n for (const rule of meta.config.__data.rules) {\n if (isCannotBeUpdatedRule(rule.fn) && rule.fn.immutable) {\n // Usually the field will exist directly in meta.fields\n const selfField = meta.fields[rule.fn.field];\n // Or it might have come in from a base type in meta.allFields\n const baseField = meta.allFields[rule.fn.field];\n // Either way, at least one should exist\n if (!selfField && !baseField) {\n throw new Error(`Missing field '${meta.type}.${rule.fn.field}' for cannotBeUpdated at ${rule.name}`);\n }\n if (selfField) selfField.immutable = true;\n if (baseField) baseField.immutable = true;\n }\n }\n }\n}\n\n// Setup subTypes/baseTypes\nfunction hookUpBaseTypeAndSubTypes(metas: EntityMetadata[]): void {\n const metaByName = metas.reduce(\n (acc, m) => {\n acc[m.type] = m;\n return acc;\n },\n {} as Record<string, EntityMetadata>,\n );\n for (const m of metas) {\n // This is basically m.fields.mapValues to assign the primary alias\n m.allFields = Object.fromEntries(\n Object.entries(m.fields).map(([name, field]) => [name, { ...field, aliasSuffix: \"\" }]),\n );\n // Only supporting one level of inheritance for now, ideally would loop `while current !== null`\n if (m.baseType) {\n const b = metaByName[m.baseType];\n if (m.inheritanceType === \"sti\") {\n m.columns = b.columns;\n }\n m.baseTypes.push(b);\n b.subTypes.push(m);\n // Add all the base's fields to our allFields, with the base's aliasSuffix, so that in\n // `WHERE` clauses for `small_publishers`, we'll have joined in `publishers` with an\n // alias + this alias suffix, so can `WHERE` on `${alias}_b0.name = 'foo'` and get\n // to the correct table.\n //\n // Note that we don't need to do this for subtypes, because `em.find` queries aren't\n // allowed to `WHERE` against columns in their subtypes. Maybe someday we can support\n // that like the GraphQL `...on SmallPublisher` syntax, like conditional/subtype-specific\n // clauses.\n Object.entries(b.fields).forEach(([name, field]) => {\n // We use `b0` because that is what addTablePerClassJoinsAndClassTag uses to join in the base table\n const aliasSuffix = b.inheritanceType === \"cti\" ? \"_b0\" : \"\";\n if (name in m.allFields && name !== \"id\") {\n // If the base field (i.e. group) is already in `m.allFields`, it's from a CTI subtype specializing\n // a base field (i.e. `SmallPublisher.group`), in which case we don't really want it inserted/updated\n // in the `small_publishers` table itself, so we'll delete it from `m.fields`, *but* leave it in\n // m.allFields, with appropriate/overridden `otherEntity: SmallPublisherGroup` config so that it\n // can be used to reverse validation rules/RFs.\n delete m.fields[name];\n m.allFields[name].aliasSuffix = aliasSuffix;\n m.allFields[name].specialized = true;\n } else {\n m.allFields[name] = { ...field, aliasSuffix };\n }\n });\n }\n }\n // Now that base/sub links are complete, cache the hot-path meta arrays that\n // `getBaseAndSelfMetas`/`getBaseSelfAndSubMetas` would otherwise re-allocate per call.\n for (const m of metas) {\n m.baseSelfMetas = [...m.baseTypes, m];\n m.baseSelfAndSubMetas = [...m.baseTypes, m, ...m.subTypes];\n }\n}\n\n/** Copy/pastes base AsyncDefaults onto subtypes, so that subtypes can have their own default dependencies. */\nfunction copyAsyncDefaults(metas: EntityMetadata[]): void {\n for (const m of metas) {\n for (const b of m.baseTypes) {\n // Clone in the base asyncDefaults, unless we override our own\n for (const [fieldName, df] of Object.entries(b.config.__data.asyncDefaults)) {\n if (!m.config.__data.asyncDefaults[fieldName]) {\n // Given our subtype its own instance, because we might have different default dependencies.\n // I.e. from a sample domain model, something like:\n // - The base `PlanVersion.type` default depends on `{ identity: \"type\" }`\n // - The base `Plan.type` has no default itself\n // - The sub `SpecialPlanVersion` inherits type, and specializes `SPV.identity: SP`\n // - The sub `SpecialPlan.type` does have a default\n //\n // So we need to eval `PlanVersion.type` separately from `SpecialPlanVersion.type`, even\n // though they come from the same `config.setDefault` call/lambda in `PlanVersion.ts`.\n m.config.__data.asyncDefaults[fieldName] = new AsyncDefault(df.fieldName, df.fieldHint, df.fn);\n }\n }\n }\n }\n}\n\n// Now hook up our reactivity\nfunction reverseIndexReactivity(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Look for reactive validation rules to reverse\n for (const { name, hint, fn } of meta.config.__data.rules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-re-validate\n // the original rule's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Same reverse-indexing as `rules` above, but for `commitRules` -> `reactiveCommitRules`.\n for (const { name, hint, fn } of meta.config.__data.commitRules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveCommitRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Look for reactions to reverse\n for (const { name, hint, fn, runOnce } of meta.config.__data.reactions) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-rerun\n // the original reaction's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: \"reaction\",\n source: entity,\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name,\n fields,\n path,\n fn,\n runOnce,\n });\n }\n }\n\n // Look for ReactiveFields, ReactiveReferences, & ReactiveManyToManys to reverse\n const reactiveRelations = Object.values(meta.allFields).filter(\n (f) =>\n f.kind === \"primitive\" ||\n (f.kind === \"m2o\" && f.derived === \"async\") ||\n (f.kind === \"enum\" && f.derived === \"async\") ||\n (f.kind === \"m2m\" && f.derived === \"async\"),\n );\n for (const field of reactiveRelations) {\n const ap = (getProperties(meta) as any)[field.fieldName] as\n | ReactiveFieldImpl<any, any, any>\n | AsyncReactiveFieldImpl<any, any, any, any>\n | ReactiveReferenceImpl<any, any, any, any>\n | ReactiveManyToManyImpl<any, any, any>\n | undefined;\n // We might have an async property configured in joist-config.json that has not yet\n // been made a `hasReactiveField` in the entity file, so avoid continuing\n // if we don't actually have a property/loadHint available.\n if (ap?.reactiveHint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, ap.reactiveHint);\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: ap instanceof AsyncReactiveFieldImpl ? \"query\" : \"populate\",\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name: field.fieldName,\n path,\n fields,\n runOnce: false,\n });\n }\n }\n }\n }\n}\n\n/**\n * In addition to the canonical `meta.allFields`, we populate a `meta.polyComponentFields` to\n * disaggregates the poly's components into individual fields so that `em.find` / `parseFindQuery`\n * can support component-specific find queries.\n */\nfunction populatePolyComponentFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n for (const [key, field] of Object.entries(meta.allFields)) {\n if (field.kind === \"poly\") {\n meta.polyComponentFields ??= {};\n for (const comp of field.components) {\n const fieldName = `${key}${comp.otherMetadata().type}`;\n // Synthesize a m2o component that won't be used for any actual read/write serde,\n // but just to help `parseFindQuery` build `WHERE` clauses.\n meta.polyComponentFields[fieldName] = {\n kind: \"m2o\",\n fieldName,\n fieldIdName: `${fieldName}Id`,\n required: false,\n immutable: false,\n derived: false,\n serde: new SimpleFieldSerde(fieldName, comp.column),\n otherMetadata: comp.otherMetadata,\n otherFieldName: comp.otherFieldName,\n aliasSuffix: field.aliasSuffix,\n } satisfies ManyToOneField & { aliasSuffix: string };\n }\n } else if (field.kind === \"m2o\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n // a subtype specific sub-field (i.e. `publisherLargePublishers`) cannot be required (which turns into\n // an `inner join`), even if its parent is, since it won't always be present (i.e. the pointed-at publisher\n // might be a small publisher).\n required: false,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies ManyToOneField & { aliasSuffix: string };\n });\n } else if (field.kind === \"o2m\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies OneToManyField & { aliasSuffix: string };\n });\n }\n }\n }\n}\n\nfunction copyRunBeforeBooksToBaseType(meta: EntityMetadata[]): void {\n for (const m of meta) {\n for (const b of m.baseTypes) {\n b.config.__data.runHooksBefore.push(...m.config.__data.runHooksBefore);\n }\n }\n}\n\n/** Indexes reactables once so field setters don't scan every reactable's fields. */\nfunction indexReactablesByField(reactables: readonly Reactable[]): Map<string, Reactable[]> {\n const byField = new Map<string, Reactable[]>();\n for (const reactable of reactables) {\n for (const field of reactable.fields) {\n let fields = byField.get(field);\n if (fields === undefined) {\n fields = [];\n byField.set(field, fields);\n }\n if (!fields.includes(reactable)) fields.push(reactable);\n }\n }\n return byField;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"configure.cjs","names":["buildFieldTransitions","getBaseAndSelfMetas","getBaseSelfAndSubMetas","fail","tagFromId","maybeResolveReferenceToId","maybeGetRuntimeConfig","isCannotBeUpdatedRule","AsyncDefault","reverseReactiveHint","getProperties","AsyncReactiveFieldImpl","SimpleFieldSerde"],"sources":["../src/configure.ts"],"sourcesContent":["import { type Reactable, setAfterMetadataLocked, setBooted } from \"src/config.ts\";\nimport { AsyncDefault } from \"src/defaults.ts\";\nimport { type Entity } from \"src/Entity.ts\";\nimport { type MaybeAbstractEntityConstructor, type TaggedId } from \"src/EntityManager.ts\";\nimport {\n type EntityMetadata,\n type EnumField,\n type ManyToOneField,\n type OneToManyField,\n getBaseAndSelfMetas,\n getBaseSelfAndSubMetas,\n getMetadata,\n} from \"src/EntityMetadata.ts\";\nimport { getProperties } from \"src/getProperties.ts\";\nimport { maybeResolveReferenceToId, setTaggedIdDelimiter, tagFromId } from \"src/keys.ts\";\nimport { reverseReactiveHint } from \"src/reactivity/reactiveHints.ts\";\nimport { AsyncReactiveFieldImpl } from \"src/relations/AsyncReactiveField.ts\";\nimport { type ReactiveManyToManyImpl, type ReactiveReferenceImpl, type Reference } from \"src/relations/index.ts\";\nimport { type ReactiveFieldImpl } from \"src/relations/ReactiveField.ts\";\nimport { isCannotBeUpdatedRule } from \"src/rules.ts\";\nimport { maybeGetRuntimeConfig } from \"src/runtimeConfig.ts\";\nimport { SimpleFieldSerde } from \"src/serde/fieldSerde.ts\";\nimport { buildFieldTransitions } from \"src/transitions.ts\";\nimport { defineLazyGetter, fail } from \"src/utils.ts\";\n\nconst tagToConstructorMap = new Map<string, MaybeAbstractEntityConstructor<any>>();\nconst tableToMetaMap = new Map<string, EntityMetadata>();\nconst typeToMetaMap = new Map<string, EntityMetadata>();\n\nlet previousBootError: any;\n\n/** Performs our boot-time initialization, i.e. hooking up reactivity. */\nexport function configureMetadata(metas: EntityMetadata[]): void {\n // Add explicit \"did we already fail\" check b/c if a transformer like tsx gets a runtime error from\n // here, it can potentially suppress it, move on to another file, which will naively re-invoke\n // `configureMetadata` again, and fail with a very confusing \"Duplicate tag\" error\n if (previousBootError) {\n throw previousBootError;\n }\n try {\n populateConstructorMaps(metas);\n hookUpBaseTypeAndSubTypes(metas);\n installMetadataGetters(metas);\n sortMetasByBaseType(metas);\n setImmutableFields(metas);\n populatePolyComponentFields(metas);\n fireAfterMetadatas(metas);\n // Callers can make `config` calls during `afterMetadata` callbacks, but after that\n // we don't allow any more config changes.\n setBooted();\n // Do these after `fireAfterMetadatas`, in case afterMetadata callbacks added more defaults/rules\n copyAsyncDefaults(metas);\n reverseIndexReactivity(metas);\n installReactiveMetadataGetters(metas);\n copyRunBeforeBooksToBaseType(metas);\n } catch (e) {\n previousBootError = e;\n throw e;\n }\n}\n\n/** Installs lazy lookup getters for metadata-derived caches. */\nfunction installMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n defineLazyGetter(meta, \"subTypesByType\", function buildSubTypesByType() {\n return new Map(meta.subTypes.map((st) => [st.type, st]));\n });\n defineLazyGetter(meta, \"subTypesByStiValue\", function buildSubTypesByStiValue() {\n return new Map(meta.subTypes.map((st) => [st.stiDiscriminatorValue, st]));\n });\n defineLazyGetter(meta, \"stiDiscriminatorColumnName\", function buildStiDiscriminatorColumnName() {\n const field = meta.fields[meta.stiDiscriminatorField!];\n if (field === undefined) throw new Error(`${meta.type} does not have an STI discriminator field`);\n if (field.kind !== \"enum\") throw new Error(\"Discriminator field must be an enum\");\n return (field as EnumField).serde.columns[0].columnName;\n });\n defineLazyGetter(meta, \"lazyFieldNames\", function buildLazyFieldNames() {\n return new Set(\n Object.values(meta.fields)\n .filter((f) => f.kind === \"primitive\" && f.lazy)\n .map((f) => f.fieldName),\n );\n });\n defineLazyGetter(meta, \"hasLazyColumns\", function buildHasLazyColumns() {\n return meta.lazyFieldNames!.size > 0;\n });\n defineLazyGetter(meta, \"syncDerivedFields\", function buildSyncDerivedFields() {\n return Object.values(meta.allFields)\n .filter((f) => (f.kind === \"primitive\" || f.kind === \"enum\") && f.derived === \"sync\")\n .map((f) => f.fieldName);\n });\n }\n}\n\n/** Installs lazy getters for reactivity caches after reactivity has been reverse-indexed. */\nfunction installReactiveMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Config-dependent getters are installed after afterMetadata callbacks finish adding config.\n defineLazyGetter(meta, \"transitions\", function buildTransitions() {\n return buildFieldTransitions(meta);\n });\n defineLazyGetter(meta, \"reactables\", function buildReactables() {\n return getBaseAndSelfMetas(meta)\n .flatMap((m) => m.config.__data.reactables)\n .filter((r) => !r.isReadOnly);\n });\n defineLazyGetter(meta, \"reactablesByField\", function buildReactablesByField() {\n return indexReactablesByField(meta.reactables!);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnly\", function buildReactablesIncludingReadOnly() {\n return getBaseAndSelfMetas(meta).flatMap((m) => m.config.__data.reactables);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnlyByField\", function buildReactablesIncludingReadOnlyByField() {\n return indexReactablesByField(meta.reactablesIncludingReadOnly!);\n });\n defineLazyGetter(meta, \"reactiveRules\", function buildReactiveRules() {\n // We use \"AndSub\" because `reactiveRules` is called with `todo.metadata`, which is always\n // the root type, but ofc we don't want to skip subtype rules.\n //\n // I had considered filtering this list with `rr.fields.length > 0`, but even rules with 100%\n // immutable fields (so all read-only, and so not \"reactive\") need to run on initial entity creation.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveRules);\n });\n defineLazyGetter(meta, \"reactiveCommitRules\", function buildReactiveCommitRules() {\n // Same \"AndSub\" reasoning as `reactiveRules`, just for the post-flush/pre-commit commit rules.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveCommitRules);\n });\n defineLazyGetter(meta, \"hasCommitRules\", function buildHasCommitRules() {\n // True if flushing an entity of this type could trigger commit-rule work, so `em.flush` can\n // skip the whole commit-rule pass otherwise. We need *both* checks because hinted and\n // non-hinted commit rules are stored in different places:\n //\n // 1. Hinted commit rules are reverse-indexed onto their *trigger* entity's `reactiveCommitRules`,\n // which is often a *different* entity than the one the rule is declared on. I.e. a rule\n // `config.addCommitRule({ books: \"title\" }, fn)` declared on `Author` lands on\n // `Book.reactiveCommitRules`, so flushing a Book must run it even though `Book`'s own\n // `config.__data.commitRules` is empty — hence checking `reactiveCommitRules`, not `commitRules`.\n //\n // 2. Non-hinted commit rules are *not* reverse-indexed at all; they run on every insert/update of\n // the entity they're declared on (via `validateSimpleRules`). I.e. `config.addCommitRule(fn)` on\n // `Author` only ever shows up in `Author.config.__data.commitRules` with `hint === undefined`,\n // so `reactiveCommitRules` would miss it. (We filter to `hint === undefined` because hinted\n // rules are already covered by check #1.)\n return (\n meta.reactiveCommitRules!.length > 0 ||\n getBaseSelfAndSubMetas(meta).some((m) => m.config.__data.commitRules.some((r) => r.hint === undefined))\n );\n });\n }\n}\n\n// Sort metas in place by inheritance hierarchy so that the base type comes before subtypes\nfunction sortMetasByBaseType(metas: EntityMetadata[]): void {\n metas.sort(compareMetasByBaseType);\n}\n\n// Compare metas by inheritance hierarchy so that the base type sorts before subtypes\nfunction compareMetasByBaseType(a: EntityMetadata, b: EntityMetadata): number {\n if (a.baseTypes.length > 0 && b.baseTypes.length === 0) return 1;\n if (a.baseTypes.length === 0 && b.baseTypes.length > 0) return -1;\n if (a.baseTypes.some((baseType) => baseType === b)) return 1;\n if (b.baseTypes.some((baseType) => baseType === a)) return -1;\n return a.type.localeCompare(b.type);\n}\n\nfunction fireAfterMetadatas(metas: EntityMetadata[]): void {\n setAfterMetadataLocked();\n for (const meta of metas) {\n for (const fn of meta.config.__data.afterMetadataCallbacks) fn(meta);\n }\n}\n\nexport function resetConstructorMap(): void {\n tagToConstructorMap.clear();\n setTaggedIdDelimiter(\":\");\n}\n\nexport function getConstructorFromTag(tag: string): MaybeAbstractEntityConstructor<any> {\n return tagToConstructorMap.get(tag) ?? fail(`Unknown tag: \"${tag}\" `);\n}\n\nexport function getConstructorFromTaggedId(id: TaggedId): MaybeAbstractEntityConstructor<any> {\n return getConstructorFromTag(tagFromId(id));\n}\n\nexport function getMetadataForTable(tableName: string): EntityMetadata {\n return tableToMetaMap.get(tableName) ?? fail(`Unknown table ${tableName}`);\n}\n\nexport function getMetadataForType(typeName: string): EntityMetadata {\n return typeToMetaMap.get(typeName) ?? fail(`Unknown type ${typeName}`);\n}\n\n/** Returns metadata for `typeName`, if `configureMetadata` has populated the type map. */\nexport function maybeGetMetadataForType<T extends Entity = Entity>(typeName: string): EntityMetadata<T> | undefined {\n return typeToMetaMap.get(typeName) as EntityMetadata<T> | undefined;\n}\n\nexport function maybeGetConstructorFromReference(\n value: string | Entity | Reference<any, any, any> | undefined,\n): MaybeAbstractEntityConstructor<any> | undefined {\n const id = maybeResolveReferenceToId(value);\n return id ? getConstructorFromTaggedId(id) : undefined;\n}\n\nfunction populateConstructorMaps(metas: EntityMetadata[]): void {\n const runtimeConfig = maybeGetRuntimeConfig();\n const tagDelimiter = runtimeConfig && Object.hasOwn(runtimeConfig, \"tagDelimiter\") ? runtimeConfig.tagDelimiter : \":\";\n setTaggedIdDelimiter(tagDelimiter);\n\n for (const meta of metas) {\n // Add each (root) constructor into our tag -> constructor map for future lookups\n if (!meta.baseType) {\n const existing = tagToConstructorMap.get(meta.tagName);\n if (existing) throw new Error(`Duplicate tag '${meta.tagName}' for ${meta.type} and ${existing.name}`);\n tagToConstructorMap.set(meta.tagName, meta.cstr);\n }\n // Same for tables, but include subclass tables\n tableToMetaMap.set(meta.tableName, meta);\n typeToMetaMap.set(meta.type, meta);\n }\n}\n\n// Do a first pass to flag immutable fields (which we'll use in reverseReactiveHint)\nfunction setImmutableFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Scan rules for cannotBeUpdated so that we can set `field.immutable`\n for (const rule of meta.config.__data.rules) {\n if (isCannotBeUpdatedRule(rule.fn) && rule.fn.immutable) {\n // Usually the field will exist directly in meta.fields\n const selfField = meta.fields[rule.fn.field];\n // Or it might have come in from a base type in meta.allFields\n const baseField = meta.allFields[rule.fn.field];\n // Either way, at least one should exist\n if (!selfField && !baseField) {\n throw new Error(`Missing field '${meta.type}.${rule.fn.field}' for cannotBeUpdated at ${rule.name}`);\n }\n if (selfField) selfField.immutable = true;\n if (baseField) baseField.immutable = true;\n }\n }\n }\n}\n\n// Setup subTypes/baseTypes\nfunction hookUpBaseTypeAndSubTypes(metas: EntityMetadata[]): void {\n const metaByName = metas.reduce(\n (acc, m) => {\n acc[m.type] = m;\n return acc;\n },\n {} as Record<string, EntityMetadata>,\n );\n for (const m of metas) {\n // This is basically m.fields.mapValues to assign the primary alias\n m.allFields = Object.fromEntries(\n Object.entries(m.fields).map(([name, field]) => [name, { ...field, aliasSuffix: \"\" }]),\n );\n // Only supporting one level of inheritance for now, ideally would loop `while current !== null`\n if (m.baseType) {\n const b = metaByName[m.baseType];\n if (m.inheritanceType === \"sti\") {\n m.columns = b.columns;\n }\n m.baseTypes.push(b);\n b.subTypes.push(m);\n // Add all the base's fields to our allFields, with the base's aliasSuffix, so that in\n // `WHERE` clauses for `small_publishers`, we'll have joined in `publishers` with an\n // alias + this alias suffix, so can `WHERE` on `${alias}_b0.name = 'foo'` and get\n // to the correct table.\n //\n // Note that we don't need to do this for subtypes, because `em.find` queries aren't\n // allowed to `WHERE` against columns in their subtypes. Maybe someday we can support\n // that like the GraphQL `...on SmallPublisher` syntax, like conditional/subtype-specific\n // clauses.\n Object.entries(b.fields).forEach(([name, field]) => {\n // We use `b0` because that is what addTablePerClassJoinsAndClassTag uses to join in the base table\n const aliasSuffix = b.inheritanceType === \"cti\" ? \"_b0\" : \"\";\n if (name in m.allFields && name !== \"id\") {\n // If the base field (i.e. group) is already in `m.allFields`, it's from a CTI subtype specializing\n // a base field (i.e. `SmallPublisher.group`), in which case we don't really want it inserted/updated\n // in the `small_publishers` table itself, so we'll delete it from `m.fields`, *but* leave it in\n // m.allFields, with appropriate/overridden `otherEntity: SmallPublisherGroup` config so that it\n // can be used to reverse validation rules/RFs.\n delete m.fields[name];\n m.allFields[name].aliasSuffix = aliasSuffix;\n m.allFields[name].specialized = true;\n } else {\n m.allFields[name] = { ...field, aliasSuffix };\n }\n });\n }\n }\n // Now that base/sub links are complete, cache the hot-path meta arrays that\n // `getBaseAndSelfMetas`/`getBaseSelfAndSubMetas` would otherwise re-allocate per call.\n for (const m of metas) {\n m.baseSelfMetas = [...m.baseTypes, m];\n m.baseSelfAndSubMetas = [...m.baseTypes, m, ...m.subTypes];\n }\n}\n\n/** Copy/pastes base AsyncDefaults onto subtypes, so that subtypes can have their own default dependencies. */\nfunction copyAsyncDefaults(metas: EntityMetadata[]): void {\n for (const m of metas) {\n for (const b of m.baseTypes) {\n // Clone in the base asyncDefaults, unless we override our own\n for (const [fieldName, df] of Object.entries(b.config.__data.asyncDefaults)) {\n if (!m.config.__data.asyncDefaults[fieldName]) {\n // Given our subtype its own instance, because we might have different default dependencies.\n // I.e. from a sample domain model, something like:\n // - The base `PlanVersion.type` default depends on `{ identity: \"type\" }`\n // - The base `Plan.type` has no default itself\n // - The sub `SpecialPlanVersion` inherits type, and specializes `SPV.identity: SP`\n // - The sub `SpecialPlan.type` does have a default\n //\n // So we need to eval `PlanVersion.type` separately from `SpecialPlanVersion.type`, even\n // though they come from the same `config.setDefault` call/lambda in `PlanVersion.ts`.\n m.config.__data.asyncDefaults[fieldName] = new AsyncDefault(df.fieldName, df.fieldHint, df.fn);\n }\n }\n }\n }\n}\n\n// Now hook up our reactivity\nfunction reverseIndexReactivity(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Look for reactive validation rules to reverse\n for (const { name, hint, fn } of meta.config.__data.rules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-re-validate\n // the original rule's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Same reverse-indexing as `rules` above, but for `commitRules` -> `reactiveCommitRules`.\n for (const { name, hint, fn } of meta.config.__data.commitRules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveCommitRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Look for reactions to reverse\n for (const { name, hint, fn, runOnce } of meta.config.__data.reactions) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-rerun\n // the original reaction's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: \"reaction\",\n source: entity,\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name,\n fields,\n path,\n fn,\n runOnce,\n });\n }\n }\n\n // Look for ReactiveFields, ReactiveReferences, & ReactiveManyToManys to reverse\n const reactiveRelations = Object.values(meta.allFields).filter(\n (f) =>\n f.kind === \"primitive\" ||\n (f.kind === \"m2o\" && f.derived === \"async\") ||\n (f.kind === \"enum\" && f.derived === \"async\") ||\n (f.kind === \"m2m\" && f.derived === \"async\"),\n );\n for (const field of reactiveRelations) {\n const ap = (getProperties(meta) as any)[field.fieldName] as\n | ReactiveFieldImpl<any, any, any>\n | AsyncReactiveFieldImpl<any, any, any, any>\n | ReactiveReferenceImpl<any, any, any, any>\n | ReactiveManyToManyImpl<any, any, any>\n | undefined;\n // We might have an async property configured in joist-config.json that has not yet\n // been made a `hasReactiveField` in the entity file, so avoid continuing\n // if we don't actually have a property/loadHint available.\n if (ap?.reactiveHint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, ap.reactiveHint);\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: ap instanceof AsyncReactiveFieldImpl ? \"query\" : \"populate\",\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name: field.fieldName,\n path,\n fields,\n runOnce: false,\n });\n }\n }\n }\n }\n}\n\n/**\n * In addition to the canonical `meta.allFields`, we populate a `meta.polyComponentFields` to\n * disaggregates the poly's components into individual fields so that `em.find` / `parseFindQuery`\n * can support component-specific find queries.\n */\nfunction populatePolyComponentFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n for (const [key, field] of Object.entries(meta.allFields)) {\n if (field.kind === \"poly\") {\n meta.polyComponentFields ??= {};\n for (const comp of field.components) {\n const fieldName = `${key}${comp.otherMetadata().type}`;\n // Synthesize a m2o component that won't be used for any actual read/write serde,\n // but just to help `parseFindQuery` build `WHERE` clauses.\n meta.polyComponentFields[fieldName] = {\n kind: \"m2o\",\n fieldName,\n fieldIdName: `${fieldName}Id`,\n required: false,\n immutable: false,\n derived: false,\n serde: new SimpleFieldSerde(fieldName, comp.column),\n otherMetadata: comp.otherMetadata,\n otherFieldName: comp.otherFieldName,\n aliasSuffix: field.aliasSuffix,\n } satisfies ManyToOneField & { aliasSuffix: string };\n }\n } else if (field.kind === \"m2o\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n // a subtype specific sub-field (i.e. `publisherLargePublishers`) cannot be required (which turns into\n // an `inner join`), even if its parent is, since it won't always be present (i.e. the pointed-at publisher\n // might be a small publisher).\n required: false,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies ManyToOneField & { aliasSuffix: string };\n });\n } else if (field.kind === \"o2m\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies OneToManyField & { aliasSuffix: string };\n });\n }\n }\n }\n}\n\nfunction copyRunBeforeBooksToBaseType(meta: EntityMetadata[]): void {\n for (const m of meta) {\n for (const b of m.baseTypes) {\n b.config.__data.runHooksBefore.push(...m.config.__data.runHooksBefore);\n }\n }\n}\n\n/** Indexes reactables once so field setters don't scan every reactable's fields. */\nfunction indexReactablesByField(reactables: readonly Reactable[]): Map<string, Reactable[]> {\n const byField = new Map<string, Reactable[]>();\n for (const reactable of reactables) {\n for (const field of reactable.fields) {\n let fields = byField.get(field);\n if (fields === undefined) {\n fields = [];\n byField.set(field, fields);\n }\n if (!fields.includes(reactable)) fields.push(reactable);\n }\n }\n return byField;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"configure.d.cts","names":[],"sources":["../src/configure.ts"],"mappings":";;;;;;;iBA+BgB,kBAAkB,OAAO;iBAwIzB;iBAKA,sBAAsB,cAAc;iBAIpC,2BAA2B,IAAI,WAAW;iBAI1C,oBAAoB,oBAAoB;iBAIxC,mBAAmB,mBAAmB;;iBAKtC,wBAAwB,UAAU,SAAS,QAAQ,mBAAmB,eAAe;iBAIrF,iCACd,gBAAgB,SAAS,uCACxB"}
1
+ {"version":3,"file":"configure.d.cts","names":[],"sources":["../src/configure.ts"],"mappings":";;;;;;;iBAgCgB,kBAAkB,OAAO;iBA4IzB;iBAKA,sBAAsB,cAAc;iBAIpC,2BAA2B,IAAI,WAAW;iBAI1C,oBAAoB,oBAAoB;iBAIxC,mBAAmB,mBAAmB;;iBAKtC,wBAAwB,UAAU,SAAS,QAAQ,mBAAmB,eAAe;iBAIrF,iCACd,gBAAgB,SAAS,uCACxB"}
@@ -1 +1 @@
1
- {"version":3,"file":"configure.d.mts","names":[],"sources":["../src/configure.ts"],"mappings":";;;;;;;iBA+BgB,kBAAkB,OAAO;iBAwIzB;iBAKA,sBAAsB,cAAc;iBAIpC,2BAA2B,IAAI,WAAW;iBAI1C,oBAAoB,oBAAoB;iBAIxC,mBAAmB,mBAAmB;;iBAKtC,wBAAwB,UAAU,SAAS,QAAQ,mBAAmB,eAAe;iBAIrF,iCACd,gBAAgB,SAAS,uCACxB"}
1
+ {"version":3,"file":"configure.d.mts","names":[],"sources":["../src/configure.ts"],"mappings":";;;;;;;iBAgCgB,kBAAkB,OAAO;iBA4IzB;iBAKA,sBAAsB,cAAc;iBAIpC,2BAA2B,IAAI,WAAW;iBAI1C,oBAAoB,oBAAoB;iBAIxC,mBAAmB,mBAAmB;;iBAKtC,wBAAwB,UAAU,SAAS,QAAQ,mBAAmB,eAAe;iBAIrF,iCACd,gBAAgB,SAAS,uCACxB"}
@@ -1,14 +1,15 @@
1
- import { reverseReactiveHint } from "./reactivity/reactiveHints.js";
2
1
  import { maybeResolveReferenceToId, setTaggedIdDelimiter, tagFromId } from "./keys.js";
3
2
  import "./relations/ReactiveField.js";
4
3
  import { AsyncReactiveFieldImpl } from "./relations/AsyncReactiveField.js";
5
4
  import "./relations/index.js";
6
5
  import { defineLazyGetter, fail } from "./utils.js";
7
6
  import { getProperties } from "./getProperties.js";
7
+ import { reverseReactiveHint } from "./reactivity/reactiveHints.js";
8
8
  import { isCannotBeUpdatedRule } from "./rules.js";
9
+ import { buildFieldTransitions } from "./transitions.js";
10
+ import { setAfterMetadataLocked, setBooted } from "./config.js";
9
11
  import { maybeGetRuntimeConfig } from "./runtimeConfig.js";
10
12
  import { SimpleFieldSerde } from "./serde/fieldSerde.js";
11
- import { setAfterMetadataLocked, setBooted } from "./config.js";
12
13
  import { getBaseAndSelfMetas, getBaseSelfAndSubMetas, getMetadata } from "./EntityMetadata.js";
13
14
  import { AsyncDefault } from "./defaults.js";
14
15
  import "./EntityManager.js";
@@ -68,6 +69,9 @@ function installMetadataGetters(metas) {
68
69
  /** Installs lazy getters for reactivity caches after reactivity has been reverse-indexed. */
69
70
  function installReactiveMetadataGetters(metas) {
70
71
  for (const meta of metas) {
72
+ defineLazyGetter(meta, "transitions", function buildTransitions() {
73
+ return buildFieldTransitions(meta);
74
+ });
71
75
  defineLazyGetter(meta, "reactables", function buildReactables() {
72
76
  return getBaseAndSelfMetas(meta).flatMap((m) => m.config.__data.reactables).filter((r) => !r.isReadOnly);
73
77
  });
@@ -1 +1 @@
1
- {"version":3,"file":"configure.js","names":[],"sources":["../src/configure.ts"],"sourcesContent":["import { type Reactable, setAfterMetadataLocked, setBooted } from \"src/config.ts\";\nimport { AsyncDefault } from \"src/defaults.ts\";\nimport { type Entity } from \"src/Entity.ts\";\nimport { type MaybeAbstractEntityConstructor, type TaggedId } from \"src/EntityManager.ts\";\nimport {\n type EntityMetadata,\n type EnumField,\n type ManyToOneField,\n type OneToManyField,\n getBaseAndSelfMetas,\n getBaseSelfAndSubMetas,\n getMetadata,\n} from \"src/EntityMetadata.ts\";\nimport { getProperties } from \"src/getProperties.ts\";\nimport { maybeResolveReferenceToId, setTaggedIdDelimiter, tagFromId } from \"src/keys.ts\";\nimport { reverseReactiveHint } from \"src/reactivity/reactiveHints.ts\";\nimport { AsyncReactiveFieldImpl } from \"src/relations/AsyncReactiveField.ts\";\nimport { type ReactiveManyToManyImpl, type ReactiveReferenceImpl, type Reference } from \"src/relations/index.ts\";\nimport { type ReactiveFieldImpl } from \"src/relations/ReactiveField.ts\";\nimport { isCannotBeUpdatedRule } from \"src/rules.ts\";\nimport { maybeGetRuntimeConfig } from \"src/runtimeConfig.ts\";\nimport { SimpleFieldSerde } from \"src/serde/fieldSerde.ts\";\nimport { defineLazyGetter, fail } from \"src/utils.ts\";\n\nconst tagToConstructorMap = new Map<string, MaybeAbstractEntityConstructor<any>>();\nconst tableToMetaMap = new Map<string, EntityMetadata>();\nconst typeToMetaMap = new Map<string, EntityMetadata>();\n\nlet previousBootError: any;\n\n/** Performs our boot-time initialization, i.e. hooking up reactivity. */\nexport function configureMetadata(metas: EntityMetadata[]): void {\n // Add explicit \"did we already fail\" check b/c if a transformer like tsx gets a runtime error from\n // here, it can potentially suppress it, move on to another file, which will naively re-invoke\n // `configureMetadata` again, and fail with a very confusing \"Duplicate tag\" error\n if (previousBootError) {\n throw previousBootError;\n }\n try {\n populateConstructorMaps(metas);\n hookUpBaseTypeAndSubTypes(metas);\n installMetadataGetters(metas);\n sortMetasByBaseType(metas);\n setImmutableFields(metas);\n populatePolyComponentFields(metas);\n fireAfterMetadatas(metas);\n // Callers can make `config` calls during `afterMetadata` callbacks, but after that\n // we don't allow any more config changes.\n setBooted();\n // Do these after `fireAfterMetadatas`, in case afterMetadata callbacks added more defaults/rules\n copyAsyncDefaults(metas);\n reverseIndexReactivity(metas);\n installReactiveMetadataGetters(metas);\n copyRunBeforeBooksToBaseType(metas);\n } catch (e) {\n previousBootError = e;\n throw e;\n }\n}\n\n/** Installs lazy lookup getters for metadata-derived caches. */\nfunction installMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n defineLazyGetter(meta, \"subTypesByType\", function buildSubTypesByType() {\n return new Map(meta.subTypes.map((st) => [st.type, st]));\n });\n defineLazyGetter(meta, \"subTypesByStiValue\", function buildSubTypesByStiValue() {\n return new Map(meta.subTypes.map((st) => [st.stiDiscriminatorValue, st]));\n });\n defineLazyGetter(meta, \"stiDiscriminatorColumnName\", function buildStiDiscriminatorColumnName() {\n const field = meta.fields[meta.stiDiscriminatorField!];\n if (field === undefined) throw new Error(`${meta.type} does not have an STI discriminator field`);\n if (field.kind !== \"enum\") throw new Error(\"Discriminator field must be an enum\");\n return (field as EnumField).serde.columns[0].columnName;\n });\n defineLazyGetter(meta, \"lazyFieldNames\", function buildLazyFieldNames() {\n return new Set(\n Object.values(meta.fields)\n .filter((f) => f.kind === \"primitive\" && f.lazy)\n .map((f) => f.fieldName),\n );\n });\n defineLazyGetter(meta, \"hasLazyColumns\", function buildHasLazyColumns() {\n return meta.lazyFieldNames!.size > 0;\n });\n defineLazyGetter(meta, \"syncDerivedFields\", function buildSyncDerivedFields() {\n return Object.values(meta.allFields)\n .filter((f) => (f.kind === \"primitive\" || f.kind === \"enum\") && f.derived === \"sync\")\n .map((f) => f.fieldName);\n });\n }\n}\n\n/** Installs lazy getters for reactivity caches after reactivity has been reverse-indexed. */\nfunction installReactiveMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n defineLazyGetter(meta, \"reactables\", function buildReactables() {\n return getBaseAndSelfMetas(meta)\n .flatMap((m) => m.config.__data.reactables)\n .filter((r) => !r.isReadOnly);\n });\n defineLazyGetter(meta, \"reactablesByField\", function buildReactablesByField() {\n return indexReactablesByField(meta.reactables!);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnly\", function buildReactablesIncludingReadOnly() {\n return getBaseAndSelfMetas(meta).flatMap((m) => m.config.__data.reactables);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnlyByField\", function buildReactablesIncludingReadOnlyByField() {\n return indexReactablesByField(meta.reactablesIncludingReadOnly!);\n });\n defineLazyGetter(meta, \"reactiveRules\", function buildReactiveRules() {\n // We use \"AndSub\" because `reactiveRules` is called with `todo.metadata`, which is always\n // the root type, but ofc we don't want to skip subtype rules.\n //\n // I had considered filtering this list with `rr.fields.length > 0`, but even rules with 100%\n // immutable fields (so all read-only, and so not \"reactive\") need to run on initial entity creation.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveRules);\n });\n defineLazyGetter(meta, \"reactiveCommitRules\", function buildReactiveCommitRules() {\n // Same \"AndSub\" reasoning as `reactiveRules`, just for the post-flush/pre-commit commit rules.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveCommitRules);\n });\n defineLazyGetter(meta, \"hasCommitRules\", function buildHasCommitRules() {\n // True if flushing an entity of this type could trigger commit-rule work, so `em.flush` can\n // skip the whole commit-rule pass otherwise. We need *both* checks because hinted and\n // non-hinted commit rules are stored in different places:\n //\n // 1. Hinted commit rules are reverse-indexed onto their *trigger* entity's `reactiveCommitRules`,\n // which is often a *different* entity than the one the rule is declared on. I.e. a rule\n // `config.addCommitRule({ books: \"title\" }, fn)` declared on `Author` lands on\n // `Book.reactiveCommitRules`, so flushing a Book must run it even though `Book`'s own\n // `config.__data.commitRules` is empty — hence checking `reactiveCommitRules`, not `commitRules`.\n //\n // 2. Non-hinted commit rules are *not* reverse-indexed at all; they run on every insert/update of\n // the entity they're declared on (via `validateSimpleRules`). I.e. `config.addCommitRule(fn)` on\n // `Author` only ever shows up in `Author.config.__data.commitRules` with `hint === undefined`,\n // so `reactiveCommitRules` would miss it. (We filter to `hint === undefined` because hinted\n // rules are already covered by check #1.)\n return (\n meta.reactiveCommitRules!.length > 0 ||\n getBaseSelfAndSubMetas(meta).some((m) => m.config.__data.commitRules.some((r) => r.hint === undefined))\n );\n });\n }\n}\n\n// Sort metas in place by inheritance hierarchy so that the base type comes before subtypes\nfunction sortMetasByBaseType(metas: EntityMetadata[]): void {\n metas.sort(compareMetasByBaseType);\n}\n\n// Compare metas by inheritance hierarchy so that the base type sorts before subtypes\nfunction compareMetasByBaseType(a: EntityMetadata, b: EntityMetadata): number {\n if (a.baseTypes.length > 0 && b.baseTypes.length === 0) return 1;\n if (a.baseTypes.length === 0 && b.baseTypes.length > 0) return -1;\n if (a.baseTypes.some((baseType) => baseType === b)) return 1;\n if (b.baseTypes.some((baseType) => baseType === a)) return -1;\n return a.type.localeCompare(b.type);\n}\n\nfunction fireAfterMetadatas(metas: EntityMetadata[]): void {\n setAfterMetadataLocked();\n for (const meta of metas) {\n for (const fn of meta.config.__data.afterMetadataCallbacks) fn(meta);\n }\n}\n\nexport function resetConstructorMap(): void {\n tagToConstructorMap.clear();\n setTaggedIdDelimiter(\":\");\n}\n\nexport function getConstructorFromTag(tag: string): MaybeAbstractEntityConstructor<any> {\n return tagToConstructorMap.get(tag) ?? fail(`Unknown tag: \"${tag}\" `);\n}\n\nexport function getConstructorFromTaggedId(id: TaggedId): MaybeAbstractEntityConstructor<any> {\n return getConstructorFromTag(tagFromId(id));\n}\n\nexport function getMetadataForTable(tableName: string): EntityMetadata {\n return tableToMetaMap.get(tableName) ?? fail(`Unknown table ${tableName}`);\n}\n\nexport function getMetadataForType(typeName: string): EntityMetadata {\n return typeToMetaMap.get(typeName) ?? fail(`Unknown type ${typeName}`);\n}\n\n/** Returns metadata for `typeName`, if `configureMetadata` has populated the type map. */\nexport function maybeGetMetadataForType<T extends Entity = Entity>(typeName: string): EntityMetadata<T> | undefined {\n return typeToMetaMap.get(typeName) as EntityMetadata<T> | undefined;\n}\n\nexport function maybeGetConstructorFromReference(\n value: string | Entity | Reference<any, any, any> | undefined,\n): MaybeAbstractEntityConstructor<any> | undefined {\n const id = maybeResolveReferenceToId(value);\n return id ? getConstructorFromTaggedId(id) : undefined;\n}\n\nfunction populateConstructorMaps(metas: EntityMetadata[]): void {\n const runtimeConfig = maybeGetRuntimeConfig();\n const tagDelimiter = runtimeConfig && Object.hasOwn(runtimeConfig, \"tagDelimiter\") ? runtimeConfig.tagDelimiter : \":\";\n setTaggedIdDelimiter(tagDelimiter);\n\n for (const meta of metas) {\n // Add each (root) constructor into our tag -> constructor map for future lookups\n if (!meta.baseType) {\n const existing = tagToConstructorMap.get(meta.tagName);\n if (existing) throw new Error(`Duplicate tag '${meta.tagName}' for ${meta.type} and ${existing.name}`);\n tagToConstructorMap.set(meta.tagName, meta.cstr);\n }\n // Same for tables, but include subclass tables\n tableToMetaMap.set(meta.tableName, meta);\n typeToMetaMap.set(meta.type, meta);\n }\n}\n\n// Do a first pass to flag immutable fields (which we'll use in reverseReactiveHint)\nfunction setImmutableFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Scan rules for cannotBeUpdated so that we can set `field.immutable`\n for (const rule of meta.config.__data.rules) {\n if (isCannotBeUpdatedRule(rule.fn) && rule.fn.immutable) {\n // Usually the field will exist directly in meta.fields\n const selfField = meta.fields[rule.fn.field];\n // Or it might have come in from a base type in meta.allFields\n const baseField = meta.allFields[rule.fn.field];\n // Either way, at least one should exist\n if (!selfField && !baseField) {\n throw new Error(`Missing field '${meta.type}.${rule.fn.field}' for cannotBeUpdated at ${rule.name}`);\n }\n if (selfField) selfField.immutable = true;\n if (baseField) baseField.immutable = true;\n }\n }\n }\n}\n\n// Setup subTypes/baseTypes\nfunction hookUpBaseTypeAndSubTypes(metas: EntityMetadata[]): void {\n const metaByName = metas.reduce(\n (acc, m) => {\n acc[m.type] = m;\n return acc;\n },\n {} as Record<string, EntityMetadata>,\n );\n for (const m of metas) {\n // This is basically m.fields.mapValues to assign the primary alias\n m.allFields = Object.fromEntries(\n Object.entries(m.fields).map(([name, field]) => [name, { ...field, aliasSuffix: \"\" }]),\n );\n // Only supporting one level of inheritance for now, ideally would loop `while current !== null`\n if (m.baseType) {\n const b = metaByName[m.baseType];\n if (m.inheritanceType === \"sti\") {\n m.columns = b.columns;\n }\n m.baseTypes.push(b);\n b.subTypes.push(m);\n // Add all the base's fields to our allFields, with the base's aliasSuffix, so that in\n // `WHERE` clauses for `small_publishers`, we'll have joined in `publishers` with an\n // alias + this alias suffix, so can `WHERE` on `${alias}_b0.name = 'foo'` and get\n // to the correct table.\n //\n // Note that we don't need to do this for subtypes, because `em.find` queries aren't\n // allowed to `WHERE` against columns in their subtypes. Maybe someday we can support\n // that like the GraphQL `...on SmallPublisher` syntax, like conditional/subtype-specific\n // clauses.\n Object.entries(b.fields).forEach(([name, field]) => {\n // We use `b0` because that is what addTablePerClassJoinsAndClassTag uses to join in the base table\n const aliasSuffix = b.inheritanceType === \"cti\" ? \"_b0\" : \"\";\n if (name in m.allFields && name !== \"id\") {\n // If the base field (i.e. group) is already in `m.allFields`, it's from a CTI subtype specializing\n // a base field (i.e. `SmallPublisher.group`), in which case we don't really want it inserted/updated\n // in the `small_publishers` table itself, so we'll delete it from `m.fields`, *but* leave it in\n // m.allFields, with appropriate/overridden `otherEntity: SmallPublisherGroup` config so that it\n // can be used to reverse validation rules/RFs.\n delete m.fields[name];\n m.allFields[name].aliasSuffix = aliasSuffix;\n m.allFields[name].specialized = true;\n } else {\n m.allFields[name] = { ...field, aliasSuffix };\n }\n });\n }\n }\n // Now that base/sub links are complete, cache the hot-path meta arrays that\n // `getBaseAndSelfMetas`/`getBaseSelfAndSubMetas` would otherwise re-allocate per call.\n for (const m of metas) {\n m.baseSelfMetas = [...m.baseTypes, m];\n m.baseSelfAndSubMetas = [...m.baseTypes, m, ...m.subTypes];\n }\n}\n\n/** Copy/pastes base AsyncDefaults onto subtypes, so that subtypes can have their own default dependencies. */\nfunction copyAsyncDefaults(metas: EntityMetadata[]): void {\n for (const m of metas) {\n for (const b of m.baseTypes) {\n // Clone in the base asyncDefaults, unless we override our own\n for (const [fieldName, df] of Object.entries(b.config.__data.asyncDefaults)) {\n if (!m.config.__data.asyncDefaults[fieldName]) {\n // Given our subtype its own instance, because we might have different default dependencies.\n // I.e. from a sample domain model, something like:\n // - The base `PlanVersion.type` default depends on `{ identity: \"type\" }`\n // - The base `Plan.type` has no default itself\n // - The sub `SpecialPlanVersion` inherits type, and specializes `SPV.identity: SP`\n // - The sub `SpecialPlan.type` does have a default\n //\n // So we need to eval `PlanVersion.type` separately from `SpecialPlanVersion.type`, even\n // though they come from the same `config.setDefault` call/lambda in `PlanVersion.ts`.\n m.config.__data.asyncDefaults[fieldName] = new AsyncDefault(df.fieldName, df.fieldHint, df.fn);\n }\n }\n }\n }\n}\n\n// Now hook up our reactivity\nfunction reverseIndexReactivity(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Look for reactive validation rules to reverse\n for (const { name, hint, fn } of meta.config.__data.rules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-re-validate\n // the original rule's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Same reverse-indexing as `rules` above, but for `commitRules` -> `reactiveCommitRules`.\n for (const { name, hint, fn } of meta.config.__data.commitRules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveCommitRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Look for reactions to reverse\n for (const { name, hint, fn, runOnce } of meta.config.__data.reactions) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-rerun\n // the original reaction's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: \"reaction\",\n source: entity,\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name,\n fields,\n path,\n fn,\n runOnce,\n });\n }\n }\n\n // Look for ReactiveFields, ReactiveReferences, & ReactiveManyToManys to reverse\n const reactiveRelations = Object.values(meta.allFields).filter(\n (f) =>\n f.kind === \"primitive\" ||\n (f.kind === \"m2o\" && f.derived === \"async\") ||\n (f.kind === \"enum\" && f.derived === \"async\") ||\n (f.kind === \"m2m\" && f.derived === \"async\"),\n );\n for (const field of reactiveRelations) {\n const ap = (getProperties(meta) as any)[field.fieldName] as\n | ReactiveFieldImpl<any, any, any>\n | AsyncReactiveFieldImpl<any, any, any, any>\n | ReactiveReferenceImpl<any, any, any, any>\n | ReactiveManyToManyImpl<any, any, any>\n | undefined;\n // We might have an async property configured in joist-config.json that has not yet\n // been made a `hasReactiveField` in the entity file, so avoid continuing\n // if we don't actually have a property/loadHint available.\n if (ap?.reactiveHint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, ap.reactiveHint);\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: ap instanceof AsyncReactiveFieldImpl ? \"query\" : \"populate\",\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name: field.fieldName,\n path,\n fields,\n runOnce: false,\n });\n }\n }\n }\n }\n}\n\n/**\n * In addition to the canonical `meta.allFields`, we populate a `meta.polyComponentFields` to\n * disaggregates the poly's components into individual fields so that `em.find` / `parseFindQuery`\n * can support component-specific find queries.\n */\nfunction populatePolyComponentFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n for (const [key, field] of Object.entries(meta.allFields)) {\n if (field.kind === \"poly\") {\n meta.polyComponentFields ??= {};\n for (const comp of field.components) {\n const fieldName = `${key}${comp.otherMetadata().type}`;\n // Synthesize a m2o component that won't be used for any actual read/write serde,\n // but just to help `parseFindQuery` build `WHERE` clauses.\n meta.polyComponentFields[fieldName] = {\n kind: \"m2o\",\n fieldName,\n fieldIdName: `${fieldName}Id`,\n required: false,\n immutable: false,\n derived: false,\n serde: new SimpleFieldSerde(fieldName, comp.column),\n otherMetadata: comp.otherMetadata,\n otherFieldName: comp.otherFieldName,\n aliasSuffix: field.aliasSuffix,\n } satisfies ManyToOneField & { aliasSuffix: string };\n }\n } else if (field.kind === \"m2o\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n // a subtype specific sub-field (i.e. `publisherLargePublishers`) cannot be required (which turns into\n // an `inner join`), even if its parent is, since it won't always be present (i.e. the pointed-at publisher\n // might be a small publisher).\n required: false,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies ManyToOneField & { aliasSuffix: string };\n });\n } else if (field.kind === \"o2m\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies OneToManyField & { aliasSuffix: string };\n });\n }\n }\n }\n}\n\nfunction copyRunBeforeBooksToBaseType(meta: EntityMetadata[]): void {\n for (const m of meta) {\n for (const b of m.baseTypes) {\n b.config.__data.runHooksBefore.push(...m.config.__data.runHooksBefore);\n }\n }\n}\n\n/** Indexes reactables once so field setters don't scan every reactable's fields. */\nfunction indexReactablesByField(reactables: readonly Reactable[]): Map<string, Reactable[]> {\n const byField = new Map<string, Reactable[]>();\n for (const reactable of reactables) {\n for (const field of reactable.fields) {\n let fields = byField.get(field);\n if (fields === undefined) {\n fields = [];\n byField.set(field, fields);\n }\n if (!fields.includes(reactable)) fields.push(reactable);\n }\n }\n return byField;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"configure.js","names":[],"sources":["../src/configure.ts"],"sourcesContent":["import { type Reactable, setAfterMetadataLocked, setBooted } from \"src/config.ts\";\nimport { AsyncDefault } from \"src/defaults.ts\";\nimport { type Entity } from \"src/Entity.ts\";\nimport { type MaybeAbstractEntityConstructor, type TaggedId } from \"src/EntityManager.ts\";\nimport {\n type EntityMetadata,\n type EnumField,\n type ManyToOneField,\n type OneToManyField,\n getBaseAndSelfMetas,\n getBaseSelfAndSubMetas,\n getMetadata,\n} from \"src/EntityMetadata.ts\";\nimport { getProperties } from \"src/getProperties.ts\";\nimport { maybeResolveReferenceToId, setTaggedIdDelimiter, tagFromId } from \"src/keys.ts\";\nimport { reverseReactiveHint } from \"src/reactivity/reactiveHints.ts\";\nimport { AsyncReactiveFieldImpl } from \"src/relations/AsyncReactiveField.ts\";\nimport { type ReactiveManyToManyImpl, type ReactiveReferenceImpl, type Reference } from \"src/relations/index.ts\";\nimport { type ReactiveFieldImpl } from \"src/relations/ReactiveField.ts\";\nimport { isCannotBeUpdatedRule } from \"src/rules.ts\";\nimport { maybeGetRuntimeConfig } from \"src/runtimeConfig.ts\";\nimport { SimpleFieldSerde } from \"src/serde/fieldSerde.ts\";\nimport { buildFieldTransitions } from \"src/transitions.ts\";\nimport { defineLazyGetter, fail } from \"src/utils.ts\";\n\nconst tagToConstructorMap = new Map<string, MaybeAbstractEntityConstructor<any>>();\nconst tableToMetaMap = new Map<string, EntityMetadata>();\nconst typeToMetaMap = new Map<string, EntityMetadata>();\n\nlet previousBootError: any;\n\n/** Performs our boot-time initialization, i.e. hooking up reactivity. */\nexport function configureMetadata(metas: EntityMetadata[]): void {\n // Add explicit \"did we already fail\" check b/c if a transformer like tsx gets a runtime error from\n // here, it can potentially suppress it, move on to another file, which will naively re-invoke\n // `configureMetadata` again, and fail with a very confusing \"Duplicate tag\" error\n if (previousBootError) {\n throw previousBootError;\n }\n try {\n populateConstructorMaps(metas);\n hookUpBaseTypeAndSubTypes(metas);\n installMetadataGetters(metas);\n sortMetasByBaseType(metas);\n setImmutableFields(metas);\n populatePolyComponentFields(metas);\n fireAfterMetadatas(metas);\n // Callers can make `config` calls during `afterMetadata` callbacks, but after that\n // we don't allow any more config changes.\n setBooted();\n // Do these after `fireAfterMetadatas`, in case afterMetadata callbacks added more defaults/rules\n copyAsyncDefaults(metas);\n reverseIndexReactivity(metas);\n installReactiveMetadataGetters(metas);\n copyRunBeforeBooksToBaseType(metas);\n } catch (e) {\n previousBootError = e;\n throw e;\n }\n}\n\n/** Installs lazy lookup getters for metadata-derived caches. */\nfunction installMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n defineLazyGetter(meta, \"subTypesByType\", function buildSubTypesByType() {\n return new Map(meta.subTypes.map((st) => [st.type, st]));\n });\n defineLazyGetter(meta, \"subTypesByStiValue\", function buildSubTypesByStiValue() {\n return new Map(meta.subTypes.map((st) => [st.stiDiscriminatorValue, st]));\n });\n defineLazyGetter(meta, \"stiDiscriminatorColumnName\", function buildStiDiscriminatorColumnName() {\n const field = meta.fields[meta.stiDiscriminatorField!];\n if (field === undefined) throw new Error(`${meta.type} does not have an STI discriminator field`);\n if (field.kind !== \"enum\") throw new Error(\"Discriminator field must be an enum\");\n return (field as EnumField).serde.columns[0].columnName;\n });\n defineLazyGetter(meta, \"lazyFieldNames\", function buildLazyFieldNames() {\n return new Set(\n Object.values(meta.fields)\n .filter((f) => f.kind === \"primitive\" && f.lazy)\n .map((f) => f.fieldName),\n );\n });\n defineLazyGetter(meta, \"hasLazyColumns\", function buildHasLazyColumns() {\n return meta.lazyFieldNames!.size > 0;\n });\n defineLazyGetter(meta, \"syncDerivedFields\", function buildSyncDerivedFields() {\n return Object.values(meta.allFields)\n .filter((f) => (f.kind === \"primitive\" || f.kind === \"enum\") && f.derived === \"sync\")\n .map((f) => f.fieldName);\n });\n }\n}\n\n/** Installs lazy getters for reactivity caches after reactivity has been reverse-indexed. */\nfunction installReactiveMetadataGetters(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Config-dependent getters are installed after afterMetadata callbacks finish adding config.\n defineLazyGetter(meta, \"transitions\", function buildTransitions() {\n return buildFieldTransitions(meta);\n });\n defineLazyGetter(meta, \"reactables\", function buildReactables() {\n return getBaseAndSelfMetas(meta)\n .flatMap((m) => m.config.__data.reactables)\n .filter((r) => !r.isReadOnly);\n });\n defineLazyGetter(meta, \"reactablesByField\", function buildReactablesByField() {\n return indexReactablesByField(meta.reactables!);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnly\", function buildReactablesIncludingReadOnly() {\n return getBaseAndSelfMetas(meta).flatMap((m) => m.config.__data.reactables);\n });\n defineLazyGetter(meta, \"reactablesIncludingReadOnlyByField\", function buildReactablesIncludingReadOnlyByField() {\n return indexReactablesByField(meta.reactablesIncludingReadOnly!);\n });\n defineLazyGetter(meta, \"reactiveRules\", function buildReactiveRules() {\n // We use \"AndSub\" because `reactiveRules` is called with `todo.metadata`, which is always\n // the root type, but ofc we don't want to skip subtype rules.\n //\n // I had considered filtering this list with `rr.fields.length > 0`, but even rules with 100%\n // immutable fields (so all read-only, and so not \"reactive\") need to run on initial entity creation.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveRules);\n });\n defineLazyGetter(meta, \"reactiveCommitRules\", function buildReactiveCommitRules() {\n // Same \"AndSub\" reasoning as `reactiveRules`, just for the post-flush/pre-commit commit rules.\n return getBaseSelfAndSubMetas(meta).flatMap((m) => m.config.__data.reactiveCommitRules);\n });\n defineLazyGetter(meta, \"hasCommitRules\", function buildHasCommitRules() {\n // True if flushing an entity of this type could trigger commit-rule work, so `em.flush` can\n // skip the whole commit-rule pass otherwise. We need *both* checks because hinted and\n // non-hinted commit rules are stored in different places:\n //\n // 1. Hinted commit rules are reverse-indexed onto their *trigger* entity's `reactiveCommitRules`,\n // which is often a *different* entity than the one the rule is declared on. I.e. a rule\n // `config.addCommitRule({ books: \"title\" }, fn)` declared on `Author` lands on\n // `Book.reactiveCommitRules`, so flushing a Book must run it even though `Book`'s own\n // `config.__data.commitRules` is empty — hence checking `reactiveCommitRules`, not `commitRules`.\n //\n // 2. Non-hinted commit rules are *not* reverse-indexed at all; they run on every insert/update of\n // the entity they're declared on (via `validateSimpleRules`). I.e. `config.addCommitRule(fn)` on\n // `Author` only ever shows up in `Author.config.__data.commitRules` with `hint === undefined`,\n // so `reactiveCommitRules` would miss it. (We filter to `hint === undefined` because hinted\n // rules are already covered by check #1.)\n return (\n meta.reactiveCommitRules!.length > 0 ||\n getBaseSelfAndSubMetas(meta).some((m) => m.config.__data.commitRules.some((r) => r.hint === undefined))\n );\n });\n }\n}\n\n// Sort metas in place by inheritance hierarchy so that the base type comes before subtypes\nfunction sortMetasByBaseType(metas: EntityMetadata[]): void {\n metas.sort(compareMetasByBaseType);\n}\n\n// Compare metas by inheritance hierarchy so that the base type sorts before subtypes\nfunction compareMetasByBaseType(a: EntityMetadata, b: EntityMetadata): number {\n if (a.baseTypes.length > 0 && b.baseTypes.length === 0) return 1;\n if (a.baseTypes.length === 0 && b.baseTypes.length > 0) return -1;\n if (a.baseTypes.some((baseType) => baseType === b)) return 1;\n if (b.baseTypes.some((baseType) => baseType === a)) return -1;\n return a.type.localeCompare(b.type);\n}\n\nfunction fireAfterMetadatas(metas: EntityMetadata[]): void {\n setAfterMetadataLocked();\n for (const meta of metas) {\n for (const fn of meta.config.__data.afterMetadataCallbacks) fn(meta);\n }\n}\n\nexport function resetConstructorMap(): void {\n tagToConstructorMap.clear();\n setTaggedIdDelimiter(\":\");\n}\n\nexport function getConstructorFromTag(tag: string): MaybeAbstractEntityConstructor<any> {\n return tagToConstructorMap.get(tag) ?? fail(`Unknown tag: \"${tag}\" `);\n}\n\nexport function getConstructorFromTaggedId(id: TaggedId): MaybeAbstractEntityConstructor<any> {\n return getConstructorFromTag(tagFromId(id));\n}\n\nexport function getMetadataForTable(tableName: string): EntityMetadata {\n return tableToMetaMap.get(tableName) ?? fail(`Unknown table ${tableName}`);\n}\n\nexport function getMetadataForType(typeName: string): EntityMetadata {\n return typeToMetaMap.get(typeName) ?? fail(`Unknown type ${typeName}`);\n}\n\n/** Returns metadata for `typeName`, if `configureMetadata` has populated the type map. */\nexport function maybeGetMetadataForType<T extends Entity = Entity>(typeName: string): EntityMetadata<T> | undefined {\n return typeToMetaMap.get(typeName) as EntityMetadata<T> | undefined;\n}\n\nexport function maybeGetConstructorFromReference(\n value: string | Entity | Reference<any, any, any> | undefined,\n): MaybeAbstractEntityConstructor<any> | undefined {\n const id = maybeResolveReferenceToId(value);\n return id ? getConstructorFromTaggedId(id) : undefined;\n}\n\nfunction populateConstructorMaps(metas: EntityMetadata[]): void {\n const runtimeConfig = maybeGetRuntimeConfig();\n const tagDelimiter = runtimeConfig && Object.hasOwn(runtimeConfig, \"tagDelimiter\") ? runtimeConfig.tagDelimiter : \":\";\n setTaggedIdDelimiter(tagDelimiter);\n\n for (const meta of metas) {\n // Add each (root) constructor into our tag -> constructor map for future lookups\n if (!meta.baseType) {\n const existing = tagToConstructorMap.get(meta.tagName);\n if (existing) throw new Error(`Duplicate tag '${meta.tagName}' for ${meta.type} and ${existing.name}`);\n tagToConstructorMap.set(meta.tagName, meta.cstr);\n }\n // Same for tables, but include subclass tables\n tableToMetaMap.set(meta.tableName, meta);\n typeToMetaMap.set(meta.type, meta);\n }\n}\n\n// Do a first pass to flag immutable fields (which we'll use in reverseReactiveHint)\nfunction setImmutableFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Scan rules for cannotBeUpdated so that we can set `field.immutable`\n for (const rule of meta.config.__data.rules) {\n if (isCannotBeUpdatedRule(rule.fn) && rule.fn.immutable) {\n // Usually the field will exist directly in meta.fields\n const selfField = meta.fields[rule.fn.field];\n // Or it might have come in from a base type in meta.allFields\n const baseField = meta.allFields[rule.fn.field];\n // Either way, at least one should exist\n if (!selfField && !baseField) {\n throw new Error(`Missing field '${meta.type}.${rule.fn.field}' for cannotBeUpdated at ${rule.name}`);\n }\n if (selfField) selfField.immutable = true;\n if (baseField) baseField.immutable = true;\n }\n }\n }\n}\n\n// Setup subTypes/baseTypes\nfunction hookUpBaseTypeAndSubTypes(metas: EntityMetadata[]): void {\n const metaByName = metas.reduce(\n (acc, m) => {\n acc[m.type] = m;\n return acc;\n },\n {} as Record<string, EntityMetadata>,\n );\n for (const m of metas) {\n // This is basically m.fields.mapValues to assign the primary alias\n m.allFields = Object.fromEntries(\n Object.entries(m.fields).map(([name, field]) => [name, { ...field, aliasSuffix: \"\" }]),\n );\n // Only supporting one level of inheritance for now, ideally would loop `while current !== null`\n if (m.baseType) {\n const b = metaByName[m.baseType];\n if (m.inheritanceType === \"sti\") {\n m.columns = b.columns;\n }\n m.baseTypes.push(b);\n b.subTypes.push(m);\n // Add all the base's fields to our allFields, with the base's aliasSuffix, so that in\n // `WHERE` clauses for `small_publishers`, we'll have joined in `publishers` with an\n // alias + this alias suffix, so can `WHERE` on `${alias}_b0.name = 'foo'` and get\n // to the correct table.\n //\n // Note that we don't need to do this for subtypes, because `em.find` queries aren't\n // allowed to `WHERE` against columns in their subtypes. Maybe someday we can support\n // that like the GraphQL `...on SmallPublisher` syntax, like conditional/subtype-specific\n // clauses.\n Object.entries(b.fields).forEach(([name, field]) => {\n // We use `b0` because that is what addTablePerClassJoinsAndClassTag uses to join in the base table\n const aliasSuffix = b.inheritanceType === \"cti\" ? \"_b0\" : \"\";\n if (name in m.allFields && name !== \"id\") {\n // If the base field (i.e. group) is already in `m.allFields`, it's from a CTI subtype specializing\n // a base field (i.e. `SmallPublisher.group`), in which case we don't really want it inserted/updated\n // in the `small_publishers` table itself, so we'll delete it from `m.fields`, *but* leave it in\n // m.allFields, with appropriate/overridden `otherEntity: SmallPublisherGroup` config so that it\n // can be used to reverse validation rules/RFs.\n delete m.fields[name];\n m.allFields[name].aliasSuffix = aliasSuffix;\n m.allFields[name].specialized = true;\n } else {\n m.allFields[name] = { ...field, aliasSuffix };\n }\n });\n }\n }\n // Now that base/sub links are complete, cache the hot-path meta arrays that\n // `getBaseAndSelfMetas`/`getBaseSelfAndSubMetas` would otherwise re-allocate per call.\n for (const m of metas) {\n m.baseSelfMetas = [...m.baseTypes, m];\n m.baseSelfAndSubMetas = [...m.baseTypes, m, ...m.subTypes];\n }\n}\n\n/** Copy/pastes base AsyncDefaults onto subtypes, so that subtypes can have their own default dependencies. */\nfunction copyAsyncDefaults(metas: EntityMetadata[]): void {\n for (const m of metas) {\n for (const b of m.baseTypes) {\n // Clone in the base asyncDefaults, unless we override our own\n for (const [fieldName, df] of Object.entries(b.config.__data.asyncDefaults)) {\n if (!m.config.__data.asyncDefaults[fieldName]) {\n // Given our subtype its own instance, because we might have different default dependencies.\n // I.e. from a sample domain model, something like:\n // - The base `PlanVersion.type` default depends on `{ identity: \"type\" }`\n // - The base `Plan.type` has no default itself\n // - The sub `SpecialPlanVersion` inherits type, and specializes `SPV.identity: SP`\n // - The sub `SpecialPlan.type` does have a default\n //\n // So we need to eval `PlanVersion.type` separately from `SpecialPlanVersion.type`, even\n // though they come from the same `config.setDefault` call/lambda in `PlanVersion.ts`.\n m.config.__data.asyncDefaults[fieldName] = new AsyncDefault(df.fieldName, df.fieldHint, df.fn);\n }\n }\n }\n }\n}\n\n// Now hook up our reactivity\nfunction reverseIndexReactivity(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n // Look for reactive validation rules to reverse\n for (const { name, hint, fn } of meta.config.__data.rules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-re-validate\n // the original rule's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Same reverse-indexing as `rules` above, but for `commitRules` -> `reactiveCommitRules`.\n for (const { name, hint, fn } of meta.config.__data.commitRules) {\n if (hint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n for (const { kind, entity, path, fields } of reversals) {\n if (kind === \"update\") {\n getMetadata(entity).config.__data.reactiveCommitRules.push({\n source: entity,\n cstr: meta.cstr,\n name,\n fields,\n path,\n fn,\n });\n }\n }\n }\n }\n\n // Look for reactions to reverse\n for (const { name, hint, fn, runOnce } of meta.config.__data.reactions) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, hint);\n // For each reversal, tell its config about the reverse hint to force-rerun\n // the original reaction's instance any time it changes.\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: \"reaction\",\n source: entity,\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name,\n fields,\n path,\n fn,\n runOnce,\n });\n }\n }\n\n // Look for ReactiveFields, ReactiveReferences, & ReactiveManyToManys to reverse\n const reactiveRelations = Object.values(meta.allFields).filter(\n (f) =>\n f.kind === \"primitive\" ||\n (f.kind === \"m2o\" && f.derived === \"async\") ||\n (f.kind === \"enum\" && f.derived === \"async\") ||\n (f.kind === \"m2m\" && f.derived === \"async\"),\n );\n for (const field of reactiveRelations) {\n const ap = (getProperties(meta) as any)[field.fieldName] as\n | ReactiveFieldImpl<any, any, any>\n | AsyncReactiveFieldImpl<any, any, any, any>\n | ReactiveReferenceImpl<any, any, any, any>\n | ReactiveManyToManyImpl<any, any, any>\n | undefined;\n // We might have an async property configured in joist-config.json that has not yet\n // been made a `hasReactiveField` in the entity file, so avoid continuing\n // if we don't actually have a property/loadHint available.\n if (ap?.reactiveHint) {\n const reversals = reverseReactiveHint(meta.cstr, meta.cstr, ap.reactiveHint);\n for (const { kind, entity, path, fields } of reversals) {\n getMetadata(entity).config.__data.reactables.push({\n kind: ap instanceof AsyncReactiveFieldImpl ? \"query\" : \"populate\",\n cstr: meta.cstr,\n isReadOnly: kind === \"read-only\",\n name: field.fieldName,\n path,\n fields,\n runOnce: false,\n });\n }\n }\n }\n }\n}\n\n/**\n * In addition to the canonical `meta.allFields`, we populate a `meta.polyComponentFields` to\n * disaggregates the poly's components into individual fields so that `em.find` / `parseFindQuery`\n * can support component-specific find queries.\n */\nfunction populatePolyComponentFields(metas: EntityMetadata[]): void {\n for (const meta of metas) {\n for (const [key, field] of Object.entries(meta.allFields)) {\n if (field.kind === \"poly\") {\n meta.polyComponentFields ??= {};\n for (const comp of field.components) {\n const fieldName = `${key}${comp.otherMetadata().type}`;\n // Synthesize a m2o component that won't be used for any actual read/write serde,\n // but just to help `parseFindQuery` build `WHERE` clauses.\n meta.polyComponentFields[fieldName] = {\n kind: \"m2o\",\n fieldName,\n fieldIdName: `${fieldName}Id`,\n required: false,\n immutable: false,\n derived: false,\n serde: new SimpleFieldSerde(fieldName, comp.column),\n otherMetadata: comp.otherMetadata,\n otherFieldName: comp.otherFieldName,\n aliasSuffix: field.aliasSuffix,\n } satisfies ManyToOneField & { aliasSuffix: string };\n }\n } else if (field.kind === \"m2o\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n // a subtype specific sub-field (i.e. `publisherLargePublishers`) cannot be required (which turns into\n // an `inner join`), even if its parent is, since it won't always be present (i.e. the pointed-at publisher\n // might be a small publisher).\n required: false,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies ManyToOneField & { aliasSuffix: string };\n });\n } else if (field.kind === \"o2m\") {\n field.otherMetadata().subTypes.forEach((st) => {\n const fieldName = `${key}${st.type}`;\n meta.polyComponentFields ??= {};\n meta.polyComponentFields[fieldName] = {\n ...field,\n fieldName,\n fieldIdName: `${fieldName}Id`,\n otherMetadata: () => st,\n } satisfies OneToManyField & { aliasSuffix: string };\n });\n }\n }\n }\n}\n\nfunction copyRunBeforeBooksToBaseType(meta: EntityMetadata[]): void {\n for (const m of meta) {\n for (const b of m.baseTypes) {\n b.config.__data.runHooksBefore.push(...m.config.__data.runHooksBefore);\n }\n }\n}\n\n/** Indexes reactables once so field setters don't scan every reactable's fields. */\nfunction indexReactablesByField(reactables: readonly Reactable[]): Map<string, Reactable[]> {\n const byField = new Map<string, Reactable[]>();\n for (const reactable of reactables) {\n for (const field of reactable.fields) {\n let fields = byField.get(field);\n if (fields === undefined) {\n fields = [];\n byField.set(field, fields);\n }\n if (!fields.includes(reactable)) fields.push(reactable);\n }\n }\n return byField;\n}\n"],"mappings":";;;;;;;;;;;;;;;;;AAyBA,MAAM,sCAAsB,IAAI,IAAiD;AACjF,MAAM,iCAAiB,IAAI,IAA4B;AACvD,MAAM,gCAAgB,IAAI,IAA4B;AAEtD,IAAI;;AAGJ,SAAgB,kBAAkB,OAA+B;CAI/D,IAAI,mBACF,MAAM;CAER,IAAI;EACF,wBAAwB,KAAK;EAC7B,0BAA0B,KAAK;EAC/B,uBAAuB,KAAK;EAC5B,oBAAoB,KAAK;EACzB,mBAAmB,KAAK;EACxB,4BAA4B,KAAK;EACjC,mBAAmB,KAAK;EAGxB,UAAU;EAEV,kBAAkB,KAAK;EACvB,uBAAuB,KAAK;EAC5B,+BAA+B,KAAK;EACpC,6BAA6B,KAAK;CACpC,SAAS,GAAG;EACV,oBAAoB;EACpB,MAAM;CACR;AACF;;AAGA,SAAS,uBAAuB,OAA+B;CAC7D,KAAK,MAAM,QAAQ,OAAO;EACxB,iBAAiB,MAAM,kBAAkB,SAAS,sBAAsB;GACtE,OAAO,IAAI,IAAI,KAAK,SAAS,KAAK,OAAO,CAAC,GAAG,MAAM,EAAE,CAAC,CAAC;EACzD,CAAC;EACD,iBAAiB,MAAM,sBAAsB,SAAS,0BAA0B;GAC9E,OAAO,IAAI,IAAI,KAAK,SAAS,KAAK,OAAO,CAAC,GAAG,uBAAuB,EAAE,CAAC,CAAC;EAC1E,CAAC;EACD,iBAAiB,MAAM,8BAA8B,SAAS,kCAAkC;GAC9F,MAAM,QAAQ,KAAK,OAAO,KAAK;GAC/B,IAAI,UAAU,KAAA,GAAW,MAAM,IAAI,MAAM,GAAG,KAAK,KAAK,0CAA0C;GAChG,IAAI,MAAM,SAAS,QAAQ,MAAM,IAAI,MAAM,qCAAqC;GAChF,OAAQ,MAAoB,MAAM,QAAQ,EAAE,CAAC;EAC/C,CAAC;EACD,iBAAiB,MAAM,kBAAkB,SAAS,sBAAsB;GACtE,OAAO,IAAI,IACT,OAAO,OAAO,KAAK,MAAM,CAAC,CACvB,QAAQ,MAAM,EAAE,SAAS,eAAe,EAAE,IAAI,CAAC,CAC/C,KAAK,MAAM,EAAE,SAAS,CAC3B;EACF,CAAC;EACD,iBAAiB,MAAM,kBAAkB,SAAS,sBAAsB;GACtE,OAAO,KAAK,eAAgB,OAAO;EACrC,CAAC;EACD,iBAAiB,MAAM,qBAAqB,SAAS,yBAAyB;GAC5E,OAAO,OAAO,OAAO,KAAK,SAAS,CAAC,CACjC,QAAQ,OAAO,EAAE,SAAS,eAAe,EAAE,SAAS,WAAW,EAAE,YAAY,MAAM,CAAC,CACpF,KAAK,MAAM,EAAE,SAAS;EAC3B,CAAC;CACH;AACF;;AAGA,SAAS,+BAA+B,OAA+B;CACrE,KAAK,MAAM,QAAQ,OAAO;EAExB,iBAAiB,MAAM,eAAe,SAAS,mBAAmB;GAChE,OAAO,sBAAsB,IAAI;EACnC,CAAC;EACD,iBAAiB,MAAM,cAAc,SAAS,kBAAkB;GAC9D,OAAO,oBAAoB,IAAI,CAAC,CAC7B,SAAS,MAAM,EAAE,OAAO,OAAO,UAAU,CAAC,CAC1C,QAAQ,MAAM,CAAC,EAAE,UAAU;EAChC,CAAC;EACD,iBAAiB,MAAM,qBAAqB,SAAS,yBAAyB;GAC5E,OAAO,uBAAuB,KAAK,UAAW;EAChD,CAAC;EACD,iBAAiB,MAAM,+BAA+B,SAAS,mCAAmC;GAChG,OAAO,oBAAoB,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,OAAO,UAAU;EAC5E,CAAC;EACD,iBAAiB,MAAM,sCAAsC,SAAS,0CAA0C;GAC9G,OAAO,uBAAuB,KAAK,2BAA4B;EACjE,CAAC;EACD,iBAAiB,MAAM,iBAAiB,SAAS,qBAAqB;GAMpE,OAAO,uBAAuB,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,OAAO,aAAa;EAClF,CAAC;EACD,iBAAiB,MAAM,uBAAuB,SAAS,2BAA2B;GAEhF,OAAO,uBAAuB,IAAI,CAAC,CAAC,SAAS,MAAM,EAAE,OAAO,OAAO,mBAAmB;EACxF,CAAC;EACD,iBAAiB,MAAM,kBAAkB,SAAS,sBAAsB;GAgBtE,OACE,KAAK,oBAAqB,SAAS,KACnC,uBAAuB,IAAI,CAAC,CAAC,MAAM,MAAM,EAAE,OAAO,OAAO,YAAY,MAAM,MAAM,EAAE,SAAS,KAAA,CAAS,CAAC;EAE1G,CAAC;CACH;AACF;AAGA,SAAS,oBAAoB,OAA+B;CAC1D,MAAM,KAAK,sBAAsB;AACnC;AAGA,SAAS,uBAAuB,GAAmB,GAA2B;CAC5E,IAAI,EAAE,UAAU,SAAS,KAAK,EAAE,UAAU,WAAW,GAAG,OAAO;CAC/D,IAAI,EAAE,UAAU,WAAW,KAAK,EAAE,UAAU,SAAS,GAAG,OAAO;CAC/D,IAAI,EAAE,UAAU,MAAM,aAAa,aAAa,CAAC,GAAG,OAAO;CAC3D,IAAI,EAAE,UAAU,MAAM,aAAa,aAAa,CAAC,GAAG,OAAO;CAC3D,OAAO,EAAE,KAAK,cAAc,EAAE,IAAI;AACpC;AAEA,SAAS,mBAAmB,OAA+B;CACzD,uBAAuB;CACvB,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,MAAM,KAAK,OAAO,OAAO,wBAAwB,GAAG,IAAI;AAEvE;AAEA,SAAgB,sBAA4B;CAC1C,oBAAoB,MAAM;CAC1B,qBAAqB,GAAG;AAC1B;AAEA,SAAgB,sBAAsB,KAAkD;CACtF,OAAO,oBAAoB,IAAI,GAAG,KAAK,KAAK,iBAAiB,IAAI,GAAG;AACtE;AAEA,SAAgB,2BAA2B,IAAmD;CAC5F,OAAO,sBAAsB,UAAU,EAAE,CAAC;AAC5C;AAEA,SAAgB,oBAAoB,WAAmC;CACrE,OAAO,eAAe,IAAI,SAAS,KAAK,KAAK,iBAAiB,WAAW;AAC3E;AAEA,SAAgB,mBAAmB,UAAkC;CACnE,OAAO,cAAc,IAAI,QAAQ,KAAK,KAAK,gBAAgB,UAAU;AACvE;;AAGA,SAAgB,wBAAmD,UAAiD;CAClH,OAAO,cAAc,IAAI,QAAQ;AACnC;AAEA,SAAgB,iCACd,OACiD;CACjD,MAAM,KAAK,0BAA0B,KAAK;CAC1C,OAAO,KAAK,2BAA2B,EAAE,IAAI,KAAA;AAC/C;AAEA,SAAS,wBAAwB,OAA+B;CAC9D,MAAM,gBAAgB,sBAAsB;CAC5C,MAAM,eAAe,iBAAiB,OAAO,OAAO,eAAe,cAAc,IAAI,cAAc,eAAe;CAClH,qBAAqB,YAAY;CAEjC,KAAK,MAAM,QAAQ,OAAO;EAExB,IAAI,CAAC,KAAK,UAAU;GAClB,MAAM,WAAW,oBAAoB,IAAI,KAAK,OAAO;GACrD,IAAI,UAAU,MAAM,IAAI,MAAM,kBAAkB,KAAK,QAAQ,QAAQ,KAAK,KAAK,OAAO,SAAS,MAAM;GACrG,oBAAoB,IAAI,KAAK,SAAS,KAAK,IAAI;EACjD;EAEA,eAAe,IAAI,KAAK,WAAW,IAAI;EACvC,cAAc,IAAI,KAAK,MAAM,IAAI;CACnC;AACF;AAGA,SAAS,mBAAmB,OAA+B;CACzD,KAAK,MAAM,QAAQ,OAEjB,KAAK,MAAM,QAAQ,KAAK,OAAO,OAAO,OACpC,IAAI,sBAAsB,KAAK,EAAE,KAAK,KAAK,GAAG,WAAW;EAEvD,MAAM,YAAY,KAAK,OAAO,KAAK,GAAG;EAEtC,MAAM,YAAY,KAAK,UAAU,KAAK,GAAG;EAEzC,IAAI,CAAC,aAAa,CAAC,WACjB,MAAM,IAAI,MAAM,kBAAkB,KAAK,KAAK,GAAG,KAAK,GAAG,MAAM,2BAA2B,KAAK,MAAM;EAErG,IAAI,WAAW,UAAU,YAAY;EACrC,IAAI,WAAW,UAAU,YAAY;CACvC;AAGN;AAGA,SAAS,0BAA0B,OAA+B;CAChE,MAAM,aAAa,MAAM,QACtB,KAAK,MAAM;EACV,IAAI,EAAE,QAAQ;EACd,OAAO;CACT,GACA,CAAC,CACH;CACA,KAAK,MAAM,KAAK,OAAO;EAErB,EAAE,YAAY,OAAO,YACnB,OAAO,QAAQ,EAAE,MAAM,CAAC,CAAC,KAAK,CAAC,MAAM,WAAW,CAAC,MAAM;GAAE,GAAG;GAAO,aAAa;EAAG,CAAC,CAAC,CACvF;EAEA,IAAI,EAAE,UAAU;GACd,MAAM,IAAI,WAAW,EAAE;GACvB,IAAI,EAAE,oBAAoB,OACxB,EAAE,UAAU,EAAE;GAEhB,EAAE,UAAU,KAAK,CAAC;GAClB,EAAE,SAAS,KAAK,CAAC;GAUjB,OAAO,QAAQ,EAAE,MAAM,CAAC,CAAC,SAAS,CAAC,MAAM,WAAW;IAElD,MAAM,cAAc,EAAE,oBAAoB,QAAQ,QAAQ;IAC1D,IAAI,QAAQ,EAAE,aAAa,SAAS,MAAM;KAMxC,OAAO,EAAE,OAAO;KAChB,EAAE,UAAU,KAAK,CAAC,cAAc;KAChC,EAAE,UAAU,KAAK,CAAC,cAAc;IAClC,OACE,EAAE,UAAU,QAAQ;KAAE,GAAG;KAAO;IAAY;GAEhD,CAAC;EACH;CACF;CAGA,KAAK,MAAM,KAAK,OAAO;EACrB,EAAE,gBAAgB,CAAC,GAAG,EAAE,WAAW,CAAC;EACpC,EAAE,sBAAsB;GAAC,GAAG,EAAE;GAAW;GAAG,GAAG,EAAE;EAAQ;CAC3D;AACF;;AAGA,SAAS,kBAAkB,OAA+B;CACxD,KAAK,MAAM,KAAK,OACd,KAAK,MAAM,KAAK,EAAE,WAEhB,KAAK,MAAM,CAAC,WAAW,OAAO,OAAO,QAAQ,EAAE,OAAO,OAAO,aAAa,GACxE,IAAI,CAAC,EAAE,OAAO,OAAO,cAAc,YAUjC,EAAE,OAAO,OAAO,cAAc,aAAa,IAAI,aAAa,GAAG,WAAW,GAAG,WAAW,GAAG,EAAE;AAKvG;AAGA,SAAS,uBAAuB,OAA+B;CAC7D,KAAK,MAAM,QAAQ,OAAO;EAExB,KAAK,MAAM,EAAE,MAAM,MAAM,QAAQ,KAAK,OAAO,OAAO,OAClD,IAAI,MAAM;GACR,MAAM,YAAY,oBAAoB,KAAK,MAAM,KAAK,MAAM,IAAI;GAGhE,KAAK,MAAM,EAAE,MAAM,QAAQ,MAAM,YAAY,WAC3C,IAAI,SAAS,UACX,YAAY,MAAM,CAAC,CAAC,OAAO,OAAO,cAAc,KAAK;IACnD,QAAQ;IACR,MAAM,KAAK;IACX;IACA;IACA;IACA;GACF,CAAC;EAGP;EAIF,KAAK,MAAM,EAAE,MAAM,MAAM,QAAQ,KAAK,OAAO,OAAO,aAClD,IAAI,MAAM;GACR,MAAM,YAAY,oBAAoB,KAAK,MAAM,KAAK,MAAM,IAAI;GAChE,KAAK,MAAM,EAAE,MAAM,QAAQ,MAAM,YAAY,WAC3C,IAAI,SAAS,UACX,YAAY,MAAM,CAAC,CAAC,OAAO,OAAO,oBAAoB,KAAK;IACzD,QAAQ;IACR,MAAM,KAAK;IACX;IACA;IACA;IACA;GACF,CAAC;EAGP;EAIF,KAAK,MAAM,EAAE,MAAM,MAAM,IAAI,aAAa,KAAK,OAAO,OAAO,WAAW;GACtE,MAAM,YAAY,oBAAoB,KAAK,MAAM,KAAK,MAAM,IAAI;GAGhE,KAAK,MAAM,EAAE,MAAM,QAAQ,MAAM,YAAY,WAC3C,YAAY,MAAM,CAAC,CAAC,OAAO,OAAO,WAAW,KAAK;IAChD,MAAM;IACN,QAAQ;IACR,MAAM,KAAK;IACX,YAAY,SAAS;IACrB;IACA;IACA;IACA;IACA;GACF,CAAC;EAEL;EAGA,MAAM,oBAAoB,OAAO,OAAO,KAAK,SAAS,CAAC,CAAC,QACrD,MACC,EAAE,SAAS,eACV,EAAE,SAAS,SAAS,EAAE,YAAY,WAClC,EAAE,SAAS,UAAU,EAAE,YAAY,WACnC,EAAE,SAAS,SAAS,EAAE,YAAY,OACvC;EACA,KAAK,MAAM,SAAS,mBAAmB;GACrC,MAAM,KAAM,cAAc,IAAI,CAAC,CAAS,MAAM;GAS9C,IAAI,IAAI,cAAc;IACpB,MAAM,YAAY,oBAAoB,KAAK,MAAM,KAAK,MAAM,GAAG,YAAY;IAC3E,KAAK,MAAM,EAAE,MAAM,QAAQ,MAAM,YAAY,WAC3C,YAAY,MAAM,CAAC,CAAC,OAAO,OAAO,WAAW,KAAK;KAChD,MAAM,cAAc,yBAAyB,UAAU;KACvD,MAAM,KAAK;KACX,YAAY,SAAS;KACrB,MAAM,MAAM;KACZ;KACA;KACA,SAAS;IACX,CAAC;GAEL;EACF;CACF;AACF;;;;;;AAOA,SAAS,4BAA4B,OAA+B;CAClE,KAAK,MAAM,QAAQ,OACjB,KAAK,MAAM,CAAC,KAAK,UAAU,OAAO,QAAQ,KAAK,SAAS,GACtD,IAAI,MAAM,SAAS,QAAQ;EACzB,KAAK,wBAAwB,CAAC;EAC9B,KAAK,MAAM,QAAQ,MAAM,YAAY;GACnC,MAAM,YAAY,GAAG,MAAM,KAAK,cAAc,CAAC,CAAC;GAGhD,KAAK,oBAAoB,aAAa;IACpC,MAAM;IACN;IACA,aAAa,GAAG,UAAU;IAC1B,UAAU;IACV,WAAW;IACX,SAAS;IACT,OAAO,IAAI,iBAAiB,WAAW,KAAK,MAAM;IAClD,eAAe,KAAK;IACpB,gBAAgB,KAAK;IACrB,aAAa,MAAM;GACrB;EACF;CACF,OAAO,IAAI,MAAM,SAAS,OACxB,MAAM,cAAc,CAAC,CAAC,SAAS,SAAS,OAAO;EAC7C,MAAM,YAAY,GAAG,MAAM,GAAG;EAC9B,KAAK,wBAAwB,CAAC;EAC9B,KAAK,oBAAoB,aAAa;GACpC,GAAG;GAIH,UAAU;GACV;GACA,aAAa,GAAG,UAAU;GAC1B,qBAAqB;EACvB;CACF,CAAC;MACI,IAAI,MAAM,SAAS,OACxB,MAAM,cAAc,CAAC,CAAC,SAAS,SAAS,OAAO;EAC7C,MAAM,YAAY,GAAG,MAAM,GAAG;EAC9B,KAAK,wBAAwB,CAAC;EAC9B,KAAK,oBAAoB,aAAa;GACpC,GAAG;GACH;GACA,aAAa,GAAG,UAAU;GAC1B,qBAAqB;EACvB;CACF,CAAC;AAIT;AAEA,SAAS,6BAA6B,MAA8B;CAClE,KAAK,MAAM,KAAK,MACd,KAAK,MAAM,KAAK,EAAE,WAChB,EAAE,OAAO,OAAO,eAAe,KAAK,GAAG,EAAE,OAAO,OAAO,cAAc;AAG3E;;AAGA,SAAS,uBAAuB,YAA4D;CAC1F,MAAM,0BAAU,IAAI,IAAyB;CAC7C,KAAK,MAAM,aAAa,YACtB,KAAK,MAAM,SAAS,UAAU,QAAQ;EACpC,IAAI,SAAS,QAAQ,IAAI,KAAK;EAC9B,IAAI,WAAW,KAAA,GAAW;GACxB,SAAS,CAAC;GACV,QAAQ,IAAI,OAAO,MAAM;EAC3B;EACA,IAAI,CAAC,OAAO,SAAS,SAAS,GAAG,OAAO,KAAK,SAAS;CACxD;CAEF,OAAO;AACT"}
@@ -1,10 +1,10 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_normalizeHints = require("../normalizeHints.cjs");
3
2
  const require_fields = require("../fields.cjs");
4
3
  const require_queries_sql_keywords = require("../queries/sql/keywords.cjs");
5
4
  const require_queries_find_QueryVisitor = require("../queries/find/QueryVisitor.cjs");
6
5
  const require_queries_find_QueryParser = require("../queries/find/QueryParser.cjs");
7
6
  const require_utils = require("../utils.cjs");
7
+ const require_normalizeHints = require("../normalizeHints.cjs");
8
8
  const require_EntityMetadata = require("../EntityMetadata.cjs");
9
9
  const require_queries_find_EntityGraphQLFilter = require("../queries/find/EntityGraphQLFilter.cjs");
10
10
  const require_dataloaders_fastWhereFilterHash = require("./fastWhereFilterHash.cjs");
@@ -1,9 +1,9 @@
1
- import { hintKey } from "../normalizeHints.js";
2
1
  import { equal, equalArrays } from "../fields.js";
3
2
  import { kqDot } from "../queries/sql/keywords.js";
4
3
  import { isQueryProvablyEmpty, visitConditions } from "../queries/find/QueryVisitor.js";
5
4
  import { getTables, parseAlias, parseFindQuery } from "../queries/find/QueryParser.js";
6
5
  import { assertNever, fail } from "../utils.js";
6
+ import { hintKey } from "../normalizeHints.js";
7
7
  import { getMetadata } from "../EntityMetadata.js";
8
8
  import { opToFn } from "../queries/find/EntityGraphQLFilter.js";
9
9
  import { fastWhereFilterHash } from "./fastWhereFilterHash.js";
@@ -1,4 +1,5 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
+ const require_fields = require("../fields.cjs");
2
3
  const require_relations_Reference = require("../relations/Reference.cjs");
3
4
  require("../relations/index.cjs");
4
5
  const require_utils = require("../utils.cjs");
@@ -38,7 +39,7 @@ function findOrCreateDataLoader(em, type, where, softDeletes) {
38
39
  if (upsert) entity.set(upsert);
39
40
  return keys.map(() => entity);
40
41
  }
41
- const entities = await em.find(type, Object.fromEntries(Object.entries(where).map(([k, v]) => [k, v === void 0 ? null : v])), { softDeletes: "include" });
42
+ const entities = await em.find(type, require_resurrection.newWhereEqual(meta, where), { softDeletes: "include" });
42
43
  let entity;
43
44
  if (entities.length > 1) throw new require_EntityManager.TooManyError(`Found more than one existing ${type.name} with ${whereAsString(where)}`);
44
45
  else if (entities.length === 1) {
@@ -61,7 +62,10 @@ function entityMatches(entity, opts) {
61
62
  switch (field.kind) {
62
63
  case "primaryKey":
63
64
  case "enum": return entity[fn] === value;
64
- case "primitive": if (field.citext) return compareCaseInsensitive(entity[fn], value);
65
+ case "primitive": if (meta.columns[fieldName]?.isArray) {
66
+ const current = entity[fn];
67
+ return Array.isArray(current) && Array.isArray(value) ? require_fields.equalArrays(current, value) : current === value;
68
+ } else if (field.citext) return compareCaseInsensitive(entity[fn], value);
65
69
  else return entity[fn] === value;
66
70
  case "m2o":
67
71
  case "poly":
@@ -1 +1 @@
1
- {"version":3,"file":"findOrCreateDataLoader.cjs","names":["getMetadata","whereFilterHash","fail","TooManyError","isEntity","isLoadedReference","sameEntity","cleanStringValue"],"sources":["../../src/dataloaders/findOrCreateDataLoader.ts"],"sourcesContent":["import type DataLoader from \"dataloader\";\nimport { whereFilterHash } from \"src/dataloaders/findDataLoader.ts\";\nimport { type Entity, isEntity } from \"src/Entity.ts\";\nimport { type EntityConstructor, type EntityManager, TooManyError, sameEntity } from \"src/EntityManager.ts\";\nimport { type EntityMetadata, getMetadata } from \"src/EntityMetadata.ts\";\nimport { type ManyToOneReference, type PolymorphicReference, isLoadedReference } from \"src/relations/index.ts\";\nimport { resurrectIfSoftDeleted } from \"src/resurrection.ts\";\nimport type { OptsOf } from \"src/typeMap.ts\";\nimport { cleanStringValue, fail } from \"src/utils.ts\";\n\ninterface FindOrCreateKey<T extends Entity> {\n ifNew: OptsOf<T>;\n upsert: Partial<OptsOf<T>> | undefined;\n}\n\nexport function findOrCreateDataLoader<T extends Entity>(\n em: EntityManager,\n type: EntityConstructor<T>,\n where: Partial<OptsOf<T>>,\n softDeletes: \"include\" | \"exclude\",\n): DataLoader<FindOrCreateKey<T>, T> {\n const meta = getMetadata(type);\n\n // Do some extra logic to make unclean strings/citext not create duplicate entities\n const hasAnyStrings = Object.values(meta.allFields).some((f) => f.kind === \"primitive\" && f.type === \"string\");\n const hasAnyCitext = Object.values(meta.allFields).some((f) => f.kind === \"primitive\" && f.citext);\n\n // The `where` here will be later used to `em.create`, so we only clean (not lower for citext)\n where = hasAnyStrings ? maybeClean(meta, where) : where;\n // Use `whereFilterHash` to batch the same `findOrCreate` `where: { firstName: \"a1\" }` calls together to avoid duplicates\n const whereValue = whereFilterHash(\n // Only maybeLower for the purposes of batching, not the later em.create\n hasAnyCitext ? maybeLower(meta, where) : (where as any),\n );\n const batchKey = `${type.name}-${whereValue}-${softDeletes}`;\n\n const invalidKeys = Object.keys(where).filter((key) => {\n const field = meta.allFields[key] ?? fail(`Invalid field ${key}`);\n const supported =\n field.kind === \"primitive\" || field.kind === \"enum\" || field.kind === \"m2o\" || field.kind === \"poly\";\n return !supported;\n });\n if (invalidKeys.length > 0) {\n throw new Error(\n \"findOrCreate only supports primitive, enum, m2o, or poly fields in the where clause. Invalid keys: \" +\n invalidKeys.join(\", \"),\n );\n }\n\n return em.getLoader<FindOrCreateKey<T>, T>(\n \"find-or-create\",\n batchKey,\n async (keys) => {\n // Because our `batchKey` is based only on the `where` clause, if the user called\n // `findOrCreate({ firstName: a1 })` multiple times, but with different ifNew/upsert\n // conditions (or different cased strings and is using a citext column), we'll end\n // up with multiple keys...\n //\n // This is fundamentally asking to create the same entity, but with different ifNew/upsert\n // conditions, which we could fail on, but for now just take the first tuple of\n // {where/ifNew/upsert} and assume it wins\n const [{ ifNew, upsert }] = keys;\n\n // Before we find/create an entity, see if we have a maybe-new one in the EM already.\n // This will also use any WIP changes we've made to the found entity, which ideally is\n // something `em.find` would do as well, but its queries are much more complex...\n const inMemory = em.filterEntities(type, where);\n if (inMemory.length > 1) {\n throw new TooManyError(`Found more than one existing ${type.name} with ${whereAsString(where)}`);\n } else if (inMemory.length === 1) {\n const entity = inMemory[0] as T;\n resurrectIfSoftDeleted(entity);\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n }\n\n // If there is a param like `{ publisher: newPublisherEntity }`, then we know that\n // an entity matching this condition can't be in the db anyway, so skip the em.find\n const hasNewEntityParam = Object.values(where).some((v) => isEntity(v) && v.isNewEntity);\n if (hasNewEntityParam) {\n const entity = em.create(type, { ...where, ...(ifNew as object) } as OptsOf<T>);\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n }\n\n // If we didn't find it in the EM, do the db query/em.create\n const entities = await em.find(\n type,\n // Convert `publisher: undefined` --> `publisher: null`, and we need to make a copy anyway\n Object.fromEntries(Object.entries(where).map(([k, v]) => [k, v === undefined ? null : v])) as any,\n // Always include soft-deleted rows so findOrCreate can resurrect them instead of creating duplicates.\n { softDeletes: \"include\" },\n );\n let entity: T;\n if (entities.length > 1) {\n throw new TooManyError(`Found more than one existing ${type.name} with ${whereAsString(where)}`);\n } else if (entities.length === 1) {\n entity = entities[0];\n resurrectIfSoftDeleted(entity);\n } else {\n entity = em.create(type, { ...where, ...(ifNew as object) } as OptsOf<T>);\n }\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n },\n // Our filter tuple is a complex object, so use a stable cache key to ensure caching works.\n { cacheKeyFn: whereFilterHash as any },\n );\n}\n\n/** A simple in-memory match of `entity` against a mini/flat \"WHERE clause\" of `opts`. */\nexport function entityMatches<T extends Entity>(entity: T, opts: Partial<OptsOf<T>>): boolean {\n const meta = getMetadata(entity);\n return Object.entries(opts).every(([fieldName, value]) => {\n const field = meta.allFields[fieldName] ?? fail(`Invalid field ${fieldName}`);\n const fn = fieldName as keyof T & keyof OptsOf<T>;\n switch (field.kind) {\n case \"primaryKey\":\n case \"enum\":\n return entity[fn] === value;\n case \"primitive\":\n if (field.citext) {\n return compareCaseInsensitive(entity[fn], value);\n } else {\n return entity[fn] === value;\n }\n case \"m2o\":\n case \"poly\":\n const relation = entity[fn] as ManyToOneReference<T, any, any> | PolymorphicReference<T, any, any>;\n if (isLoadedReference(relation)) {\n // Prefer using `.get` because it will handle new/id-less entities\n return sameEntity(relation.get, value as any);\n } else if (relation.isSet) {\n // Otherwise use ids\n return sameEntity(relation.id as any, value as any);\n } else {\n // Relation is not set, match if value is null-ish (null or undefined)\n return value === undefined || value === null;\n }\n default:\n throw new Error(`Unsupported field ${fieldName}`);\n }\n });\n}\n\nfunction whereAsString(where: object): string {\n return Object.entries(where)\n .map(([key, value]) => `${key}=${value}`)\n .join(\", \");\n}\n\nfunction compareCaseInsensitive(str1: any, str2: any): boolean {\n return (\n str1 !== undefined &&\n str2 !== undefined &&\n typeof str1 === \"string\" &&\n typeof str2 === \"string\" &&\n str1.toLowerCase() === str2.toLowerCase()\n );\n}\n\n/** Returns a copy of `opts` with any `citext` values turned to lower case. */\nfunction maybeLower<T extends object | undefined>(meta: EntityMetadata, opts: T): T {\n if (!opts) return opts;\n let result: T | undefined = undefined;\n for (const k in opts) {\n const v = (opts as any)[k];\n const field = meta.allFields[k];\n const isString = field && field.kind === \"primitive\" && field.type === \"string\";\n if (isString && field.citext) {\n const lowered = v?.toLowerCase();\n if (lowered !== v) {\n result ??= { ...opts };\n (result as any)[k] = lowered as any;\n }\n }\n }\n return result ?? opts;\n}\n\n/** Returns a copy of `opts` with any string values trimmed/coalesced. */\nfunction maybeClean<T extends object | undefined>(meta: EntityMetadata, opts: T): T {\n if (!opts) return opts;\n let result: T | undefined = undefined;\n for (const k in opts) {\n const v = (opts as any)[k];\n const field = meta.allFields[k];\n const isString = field && field.kind === \"primitive\" && field.type === \"string\";\n if (isString && field.sanitize !== false) {\n const cleaned = cleanStringValue(v);\n if (cleaned !== v) {\n result ??= { ...opts }; // Only create copy on first change\n (result as any)[k] = cleaned;\n }\n }\n }\n return result ?? opts;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"findOrCreateDataLoader.cjs","names":["getMetadata","whereFilterHash","fail","TooManyError","isEntity","newWhereEqual","equalArrays","isLoadedReference","sameEntity","cleanStringValue"],"sources":["../../src/dataloaders/findOrCreateDataLoader.ts"],"sourcesContent":["import type DataLoader from \"dataloader\";\nimport { whereFilterHash } from \"src/dataloaders/findDataLoader.ts\";\nimport { type Entity, isEntity } from \"src/Entity.ts\";\nimport { type EntityConstructor, type EntityManager, TooManyError, sameEntity } from \"src/EntityManager.ts\";\nimport { type EntityMetadata, getMetadata } from \"src/EntityMetadata.ts\";\nimport { equalArrays } from \"src/fields.ts\";\nimport { type ManyToOneReference, type PolymorphicReference, isLoadedReference } from \"src/relations/index.ts\";\nimport { newWhereEqual, resurrectIfSoftDeleted } from \"src/resurrection.ts\";\nimport type { OptsOf } from \"src/typeMap.ts\";\nimport { cleanStringValue, fail } from \"src/utils.ts\";\n\ninterface FindOrCreateKey<T extends Entity> {\n ifNew: OptsOf<T>;\n upsert: Partial<OptsOf<T>> | undefined;\n}\n\nexport function findOrCreateDataLoader<T extends Entity>(\n em: EntityManager,\n type: EntityConstructor<T>,\n where: Partial<OptsOf<T>>,\n softDeletes: \"include\" | \"exclude\",\n): DataLoader<FindOrCreateKey<T>, T> {\n const meta = getMetadata(type);\n\n // Do some extra logic to make unclean strings/citext not create duplicate entities\n const hasAnyStrings = Object.values(meta.allFields).some((f) => f.kind === \"primitive\" && f.type === \"string\");\n const hasAnyCitext = Object.values(meta.allFields).some((f) => f.kind === \"primitive\" && f.citext);\n\n // The `where` here will be later used to `em.create`, so we only clean (not lower for citext)\n where = hasAnyStrings ? maybeClean(meta, where) : where;\n // Use `whereFilterHash` to batch the same `findOrCreate` `where: { firstName: \"a1\" }` calls together to avoid duplicates\n const whereValue = whereFilterHash(\n // Only maybeLower for the purposes of batching, not the later em.create\n hasAnyCitext ? maybeLower(meta, where) : (where as any),\n );\n const batchKey = `${type.name}-${whereValue}-${softDeletes}`;\n\n const invalidKeys = Object.keys(where).filter((key) => {\n const field = meta.allFields[key] ?? fail(`Invalid field ${key}`);\n const supported =\n field.kind === \"primitive\" || field.kind === \"enum\" || field.kind === \"m2o\" || field.kind === \"poly\";\n return !supported;\n });\n if (invalidKeys.length > 0) {\n throw new Error(\n \"findOrCreate only supports primitive, enum, m2o, or poly fields in the where clause. Invalid keys: \" +\n invalidKeys.join(\", \"),\n );\n }\n\n return em.getLoader<FindOrCreateKey<T>, T>(\n \"find-or-create\",\n batchKey,\n async (keys) => {\n // Because our `batchKey` is based only on the `where` clause, if the user called\n // `findOrCreate({ firstName: a1 })` multiple times, but with different ifNew/upsert\n // conditions (or different cased strings and is using a citext column), we'll end\n // up with multiple keys...\n //\n // This is fundamentally asking to create the same entity, but with different ifNew/upsert\n // conditions, which we could fail on, but for now just take the first tuple of\n // {where/ifNew/upsert} and assume it wins\n const [{ ifNew, upsert }] = keys;\n\n // Before we find/create an entity, see if we have a maybe-new one in the EM already.\n // This will also use any WIP changes we've made to the found entity, which ideally is\n // something `em.find` would do as well, but its queries are much more complex...\n const inMemory = em.filterEntities(type, where);\n if (inMemory.length > 1) {\n throw new TooManyError(`Found more than one existing ${type.name} with ${whereAsString(where)}`);\n } else if (inMemory.length === 1) {\n const entity = inMemory[0] as T;\n resurrectIfSoftDeleted(entity);\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n }\n\n // If there is a param like `{ publisher: newPublisherEntity }`, then we know that\n // an entity matching this condition can't be in the db anyway, so skip the em.find\n const hasNewEntityParam = Object.values(where).some((v) => isEntity(v) && v.isNewEntity);\n if (hasNewEntityParam) {\n const entity = em.create(type, { ...where, ...(ifNew as object) } as OptsOf<T>);\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n }\n\n // If we didn't find it in the EM, do the db query/em.create\n const entities = await em.find(\n type,\n newWhereEqual(meta, where) as any,\n // Always include soft-deleted rows so findOrCreate can resurrect them instead of creating duplicates.\n { softDeletes: \"include\" },\n );\n let entity: T;\n if (entities.length > 1) {\n throw new TooManyError(`Found more than one existing ${type.name} with ${whereAsString(where)}`);\n } else if (entities.length === 1) {\n entity = entities[0];\n resurrectIfSoftDeleted(entity);\n } else {\n entity = em.create(type, { ...where, ...(ifNew as object) } as OptsOf<T>);\n }\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n },\n // Our filter tuple is a complex object, so use a stable cache key to ensure caching works.\n { cacheKeyFn: whereFilterHash as any },\n );\n}\n\n/** A simple in-memory match of `entity` against a mini/flat \"WHERE clause\" of `opts`. */\nexport function entityMatches<T extends Entity>(entity: T, opts: Partial<OptsOf<T>>): boolean {\n const meta = getMetadata(entity);\n return Object.entries(opts).every(([fieldName, value]) => {\n const field = meta.allFields[fieldName] ?? fail(`Invalid field ${fieldName}`);\n const fn = fieldName as keyof T & keyof OptsOf<T>;\n switch (field.kind) {\n case \"primaryKey\":\n case \"enum\":\n return entity[fn] === value;\n case \"primitive\":\n if (meta.columns[fieldName]?.isArray) {\n const current = entity[fn];\n return Array.isArray(current) && Array.isArray(value) ? equalArrays(current, value) : current === value;\n } else if (field.citext) {\n return compareCaseInsensitive(entity[fn], value);\n } else {\n return entity[fn] === value;\n }\n case \"m2o\":\n case \"poly\":\n const relation = entity[fn] as ManyToOneReference<T, any, any> | PolymorphicReference<T, any, any>;\n if (isLoadedReference(relation)) {\n // Prefer using `.get` because it will handle new/id-less entities\n return sameEntity(relation.get, value as any);\n } else if (relation.isSet) {\n // Otherwise use ids\n return sameEntity(relation.id as any, value as any);\n } else {\n // Relation is not set, match if value is null-ish (null or undefined)\n return value === undefined || value === null;\n }\n default:\n throw new Error(`Unsupported field ${fieldName}`);\n }\n });\n}\n\nfunction whereAsString(where: object): string {\n return Object.entries(where)\n .map(([key, value]) => `${key}=${value}`)\n .join(\", \");\n}\n\nfunction compareCaseInsensitive(str1: any, str2: any): boolean {\n return (\n str1 !== undefined &&\n str2 !== undefined &&\n typeof str1 === \"string\" &&\n typeof str2 === \"string\" &&\n str1.toLowerCase() === str2.toLowerCase()\n );\n}\n\n/** Returns a copy of `opts` with any `citext` values turned to lower case. */\nfunction maybeLower<T extends object | undefined>(meta: EntityMetadata, opts: T): T {\n if (!opts) return opts;\n let result: T | undefined = undefined;\n for (const k in opts) {\n const v = (opts as any)[k];\n const field = meta.allFields[k];\n const isString = field && field.kind === \"primitive\" && field.type === \"string\";\n if (isString && field.citext) {\n const lowered = v?.toLowerCase();\n if (lowered !== v) {\n result ??= { ...opts };\n (result as any)[k] = lowered as any;\n }\n }\n }\n return result ?? opts;\n}\n\n/** Returns a copy of `opts` with any string values trimmed/coalesced. */\nfunction maybeClean<T extends object | undefined>(meta: EntityMetadata, opts: T): T {\n if (!opts) return opts;\n let result: T | undefined = undefined;\n for (const k in opts) {\n const v = (opts as any)[k];\n const field = meta.allFields[k];\n const isString = field && field.kind === \"primitive\" && field.type === \"string\";\n if (isString && field.sanitize !== false) {\n const cleaned = cleanStringValue(v);\n if (cleaned !== v) {\n result ??= { ...opts }; // Only create copy on first change\n (result as any)[k] = cleaned;\n }\n }\n }\n return result ?? opts;\n}\n"],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"findOrCreateDataLoader.d.cts","names":[],"sources":["../../src/dataloaders/findOrCreateDataLoader.ts"],"mappings":";;;;;UAUU,gBAAgB,UAAU;EAClC,OAAO,OAAO;EACd,QAAQ,QAAQ,OAAO;;iBAGT,uBAAuB,UAAU,QAC/C,IAAI,eACJ,MAAM,kBAAkB,IACxB,OAAO,QAAQ,OAAO,KACtB,qCACC,WAAW,gBAAgB,IAAI;;iBAiGlB,cAAc,UAAU,QAAQ,QAAQ,GAAG,MAAM,QAAQ,OAAO"}
1
+ {"version":3,"file":"findOrCreateDataLoader.d.cts","names":[],"sources":["../../src/dataloaders/findOrCreateDataLoader.ts"],"mappings":";;;;;UAWU,gBAAgB,UAAU;EAClC,OAAO,OAAO;EACd,QAAQ,QAAQ,OAAO;;iBAGT,uBAAuB,UAAU,QAC/C,IAAI,eACJ,MAAM,kBAAkB,IACxB,OAAO,QAAQ,OAAO,KACtB,qCACC,WAAW,gBAAgB,IAAI;;iBAgGlB,cAAc,UAAU,QAAQ,QAAQ,GAAG,MAAM,QAAQ,OAAO"}
@@ -1 +1 @@
1
- {"version":3,"file":"findOrCreateDataLoader.d.mts","names":[],"sources":["../../src/dataloaders/findOrCreateDataLoader.ts"],"mappings":";;;;;UAUU,gBAAgB,UAAU;EAClC,OAAO,OAAO;EACd,QAAQ,QAAQ,OAAO;;iBAGT,uBAAuB,UAAU,QAC/C,IAAI,eACJ,MAAM,kBAAkB,IACxB,OAAO,QAAQ,OAAO,KACtB,qCACC,WAAW,gBAAgB,IAAI;;iBAiGlB,cAAc,UAAU,QAAQ,QAAQ,GAAG,MAAM,QAAQ,OAAO"}
1
+ {"version":3,"file":"findOrCreateDataLoader.d.mts","names":[],"sources":["../../src/dataloaders/findOrCreateDataLoader.ts"],"mappings":";;;;;UAWU,gBAAgB,UAAU;EAClC,OAAO,OAAO;EACd,QAAQ,QAAQ,OAAO;;iBAGT,uBAAuB,UAAU,QAC/C,IAAI,eACJ,MAAM,kBAAkB,IACxB,OAAO,QAAQ,OAAO,KACtB,qCACC,WAAW,gBAAgB,IAAI;;iBAgGlB,cAAc,UAAU,QAAQ,QAAQ,GAAG,MAAM,QAAQ,OAAO"}
@@ -1,9 +1,10 @@
1
+ import { equalArrays } from "../fields.js";
1
2
  import { isLoadedReference } from "../relations/Reference.js";
2
3
  import "../relations/index.js";
3
4
  import { cleanStringValue, fail } from "../utils.js";
4
5
  import { getMetadata } from "../EntityMetadata.js";
5
6
  import { whereFilterHash } from "./findDataLoader.js";
6
- import { resurrectIfSoftDeleted } from "../resurrection.js";
7
+ import { newWhereEqual, resurrectIfSoftDeleted } from "../resurrection.js";
7
8
  import { TooManyError, sameEntity } from "../EntityManager.js";
8
9
  import { isEntity } from "../Entity.js";
9
10
  //#region src/dataloaders/findOrCreateDataLoader.ts
@@ -37,7 +38,7 @@ function findOrCreateDataLoader(em, type, where, softDeletes) {
37
38
  if (upsert) entity.set(upsert);
38
39
  return keys.map(() => entity);
39
40
  }
40
- const entities = await em.find(type, Object.fromEntries(Object.entries(where).map(([k, v]) => [k, v === void 0 ? null : v])), { softDeletes: "include" });
41
+ const entities = await em.find(type, newWhereEqual(meta, where), { softDeletes: "include" });
41
42
  let entity;
42
43
  if (entities.length > 1) throw new TooManyError(`Found more than one existing ${type.name} with ${whereAsString(where)}`);
43
44
  else if (entities.length === 1) {
@@ -60,7 +61,10 @@ function entityMatches(entity, opts) {
60
61
  switch (field.kind) {
61
62
  case "primaryKey":
62
63
  case "enum": return entity[fn] === value;
63
- case "primitive": if (field.citext) return compareCaseInsensitive(entity[fn], value);
64
+ case "primitive": if (meta.columns[fieldName]?.isArray) {
65
+ const current = entity[fn];
66
+ return Array.isArray(current) && Array.isArray(value) ? equalArrays(current, value) : current === value;
67
+ } else if (field.citext) return compareCaseInsensitive(entity[fn], value);
64
68
  else return entity[fn] === value;
65
69
  case "m2o":
66
70
  case "poly":
@@ -1 +1 @@
1
- {"version":3,"file":"findOrCreateDataLoader.js","names":[],"sources":["../../src/dataloaders/findOrCreateDataLoader.ts"],"sourcesContent":["import type DataLoader from \"dataloader\";\nimport { whereFilterHash } from \"src/dataloaders/findDataLoader.ts\";\nimport { type Entity, isEntity } from \"src/Entity.ts\";\nimport { type EntityConstructor, type EntityManager, TooManyError, sameEntity } from \"src/EntityManager.ts\";\nimport { type EntityMetadata, getMetadata } from \"src/EntityMetadata.ts\";\nimport { type ManyToOneReference, type PolymorphicReference, isLoadedReference } from \"src/relations/index.ts\";\nimport { resurrectIfSoftDeleted } from \"src/resurrection.ts\";\nimport type { OptsOf } from \"src/typeMap.ts\";\nimport { cleanStringValue, fail } from \"src/utils.ts\";\n\ninterface FindOrCreateKey<T extends Entity> {\n ifNew: OptsOf<T>;\n upsert: Partial<OptsOf<T>> | undefined;\n}\n\nexport function findOrCreateDataLoader<T extends Entity>(\n em: EntityManager,\n type: EntityConstructor<T>,\n where: Partial<OptsOf<T>>,\n softDeletes: \"include\" | \"exclude\",\n): DataLoader<FindOrCreateKey<T>, T> {\n const meta = getMetadata(type);\n\n // Do some extra logic to make unclean strings/citext not create duplicate entities\n const hasAnyStrings = Object.values(meta.allFields).some((f) => f.kind === \"primitive\" && f.type === \"string\");\n const hasAnyCitext = Object.values(meta.allFields).some((f) => f.kind === \"primitive\" && f.citext);\n\n // The `where` here will be later used to `em.create`, so we only clean (not lower for citext)\n where = hasAnyStrings ? maybeClean(meta, where) : where;\n // Use `whereFilterHash` to batch the same `findOrCreate` `where: { firstName: \"a1\" }` calls together to avoid duplicates\n const whereValue = whereFilterHash(\n // Only maybeLower for the purposes of batching, not the later em.create\n hasAnyCitext ? maybeLower(meta, where) : (where as any),\n );\n const batchKey = `${type.name}-${whereValue}-${softDeletes}`;\n\n const invalidKeys = Object.keys(where).filter((key) => {\n const field = meta.allFields[key] ?? fail(`Invalid field ${key}`);\n const supported =\n field.kind === \"primitive\" || field.kind === \"enum\" || field.kind === \"m2o\" || field.kind === \"poly\";\n return !supported;\n });\n if (invalidKeys.length > 0) {\n throw new Error(\n \"findOrCreate only supports primitive, enum, m2o, or poly fields in the where clause. Invalid keys: \" +\n invalidKeys.join(\", \"),\n );\n }\n\n return em.getLoader<FindOrCreateKey<T>, T>(\n \"find-or-create\",\n batchKey,\n async (keys) => {\n // Because our `batchKey` is based only on the `where` clause, if the user called\n // `findOrCreate({ firstName: a1 })` multiple times, but with different ifNew/upsert\n // conditions (or different cased strings and is using a citext column), we'll end\n // up with multiple keys...\n //\n // This is fundamentally asking to create the same entity, but with different ifNew/upsert\n // conditions, which we could fail on, but for now just take the first tuple of\n // {where/ifNew/upsert} and assume it wins\n const [{ ifNew, upsert }] = keys;\n\n // Before we find/create an entity, see if we have a maybe-new one in the EM already.\n // This will also use any WIP changes we've made to the found entity, which ideally is\n // something `em.find` would do as well, but its queries are much more complex...\n const inMemory = em.filterEntities(type, where);\n if (inMemory.length > 1) {\n throw new TooManyError(`Found more than one existing ${type.name} with ${whereAsString(where)}`);\n } else if (inMemory.length === 1) {\n const entity = inMemory[0] as T;\n resurrectIfSoftDeleted(entity);\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n }\n\n // If there is a param like `{ publisher: newPublisherEntity }`, then we know that\n // an entity matching this condition can't be in the db anyway, so skip the em.find\n const hasNewEntityParam = Object.values(where).some((v) => isEntity(v) && v.isNewEntity);\n if (hasNewEntityParam) {\n const entity = em.create(type, { ...where, ...(ifNew as object) } as OptsOf<T>);\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n }\n\n // If we didn't find it in the EM, do the db query/em.create\n const entities = await em.find(\n type,\n // Convert `publisher: undefined` --> `publisher: null`, and we need to make a copy anyway\n Object.fromEntries(Object.entries(where).map(([k, v]) => [k, v === undefined ? null : v])) as any,\n // Always include soft-deleted rows so findOrCreate can resurrect them instead of creating duplicates.\n { softDeletes: \"include\" },\n );\n let entity: T;\n if (entities.length > 1) {\n throw new TooManyError(`Found more than one existing ${type.name} with ${whereAsString(where)}`);\n } else if (entities.length === 1) {\n entity = entities[0];\n resurrectIfSoftDeleted(entity);\n } else {\n entity = em.create(type, { ...where, ...(ifNew as object) } as OptsOf<T>);\n }\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n },\n // Our filter tuple is a complex object, so use a stable cache key to ensure caching works.\n { cacheKeyFn: whereFilterHash as any },\n );\n}\n\n/** A simple in-memory match of `entity` against a mini/flat \"WHERE clause\" of `opts`. */\nexport function entityMatches<T extends Entity>(entity: T, opts: Partial<OptsOf<T>>): boolean {\n const meta = getMetadata(entity);\n return Object.entries(opts).every(([fieldName, value]) => {\n const field = meta.allFields[fieldName] ?? fail(`Invalid field ${fieldName}`);\n const fn = fieldName as keyof T & keyof OptsOf<T>;\n switch (field.kind) {\n case \"primaryKey\":\n case \"enum\":\n return entity[fn] === value;\n case \"primitive\":\n if (field.citext) {\n return compareCaseInsensitive(entity[fn], value);\n } else {\n return entity[fn] === value;\n }\n case \"m2o\":\n case \"poly\":\n const relation = entity[fn] as ManyToOneReference<T, any, any> | PolymorphicReference<T, any, any>;\n if (isLoadedReference(relation)) {\n // Prefer using `.get` because it will handle new/id-less entities\n return sameEntity(relation.get, value as any);\n } else if (relation.isSet) {\n // Otherwise use ids\n return sameEntity(relation.id as any, value as any);\n } else {\n // Relation is not set, match if value is null-ish (null or undefined)\n return value === undefined || value === null;\n }\n default:\n throw new Error(`Unsupported field ${fieldName}`);\n }\n });\n}\n\nfunction whereAsString(where: object): string {\n return Object.entries(where)\n .map(([key, value]) => `${key}=${value}`)\n .join(\", \");\n}\n\nfunction compareCaseInsensitive(str1: any, str2: any): boolean {\n return (\n str1 !== undefined &&\n str2 !== undefined &&\n typeof str1 === \"string\" &&\n typeof str2 === \"string\" &&\n str1.toLowerCase() === str2.toLowerCase()\n );\n}\n\n/** Returns a copy of `opts` with any `citext` values turned to lower case. */\nfunction maybeLower<T extends object | undefined>(meta: EntityMetadata, opts: T): T {\n if (!opts) return opts;\n let result: T | undefined = undefined;\n for (const k in opts) {\n const v = (opts as any)[k];\n const field = meta.allFields[k];\n const isString = field && field.kind === \"primitive\" && field.type === \"string\";\n if (isString && field.citext) {\n const lowered = v?.toLowerCase();\n if (lowered !== v) {\n result ??= { ...opts };\n (result as any)[k] = lowered as any;\n }\n }\n }\n return result ?? opts;\n}\n\n/** Returns a copy of `opts` with any string values trimmed/coalesced. */\nfunction maybeClean<T extends object | undefined>(meta: EntityMetadata, opts: T): T {\n if (!opts) return opts;\n let result: T | undefined = undefined;\n for (const k in opts) {\n const v = (opts as any)[k];\n const field = meta.allFields[k];\n const isString = field && field.kind === \"primitive\" && field.type === \"string\";\n if (isString && field.sanitize !== false) {\n const cleaned = cleanStringValue(v);\n if (cleaned !== v) {\n result ??= { ...opts }; // Only create copy on first change\n (result as any)[k] = cleaned;\n }\n }\n }\n return result ?? opts;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"findOrCreateDataLoader.js","names":[],"sources":["../../src/dataloaders/findOrCreateDataLoader.ts"],"sourcesContent":["import type DataLoader from \"dataloader\";\nimport { whereFilterHash } from \"src/dataloaders/findDataLoader.ts\";\nimport { type Entity, isEntity } from \"src/Entity.ts\";\nimport { type EntityConstructor, type EntityManager, TooManyError, sameEntity } from \"src/EntityManager.ts\";\nimport { type EntityMetadata, getMetadata } from \"src/EntityMetadata.ts\";\nimport { equalArrays } from \"src/fields.ts\";\nimport { type ManyToOneReference, type PolymorphicReference, isLoadedReference } from \"src/relations/index.ts\";\nimport { newWhereEqual, resurrectIfSoftDeleted } from \"src/resurrection.ts\";\nimport type { OptsOf } from \"src/typeMap.ts\";\nimport { cleanStringValue, fail } from \"src/utils.ts\";\n\ninterface FindOrCreateKey<T extends Entity> {\n ifNew: OptsOf<T>;\n upsert: Partial<OptsOf<T>> | undefined;\n}\n\nexport function findOrCreateDataLoader<T extends Entity>(\n em: EntityManager,\n type: EntityConstructor<T>,\n where: Partial<OptsOf<T>>,\n softDeletes: \"include\" | \"exclude\",\n): DataLoader<FindOrCreateKey<T>, T> {\n const meta = getMetadata(type);\n\n // Do some extra logic to make unclean strings/citext not create duplicate entities\n const hasAnyStrings = Object.values(meta.allFields).some((f) => f.kind === \"primitive\" && f.type === \"string\");\n const hasAnyCitext = Object.values(meta.allFields).some((f) => f.kind === \"primitive\" && f.citext);\n\n // The `where` here will be later used to `em.create`, so we only clean (not lower for citext)\n where = hasAnyStrings ? maybeClean(meta, where) : where;\n // Use `whereFilterHash` to batch the same `findOrCreate` `where: { firstName: \"a1\" }` calls together to avoid duplicates\n const whereValue = whereFilterHash(\n // Only maybeLower for the purposes of batching, not the later em.create\n hasAnyCitext ? maybeLower(meta, where) : (where as any),\n );\n const batchKey = `${type.name}-${whereValue}-${softDeletes}`;\n\n const invalidKeys = Object.keys(where).filter((key) => {\n const field = meta.allFields[key] ?? fail(`Invalid field ${key}`);\n const supported =\n field.kind === \"primitive\" || field.kind === \"enum\" || field.kind === \"m2o\" || field.kind === \"poly\";\n return !supported;\n });\n if (invalidKeys.length > 0) {\n throw new Error(\n \"findOrCreate only supports primitive, enum, m2o, or poly fields in the where clause. Invalid keys: \" +\n invalidKeys.join(\", \"),\n );\n }\n\n return em.getLoader<FindOrCreateKey<T>, T>(\n \"find-or-create\",\n batchKey,\n async (keys) => {\n // Because our `batchKey` is based only on the `where` clause, if the user called\n // `findOrCreate({ firstName: a1 })` multiple times, but with different ifNew/upsert\n // conditions (or different cased strings and is using a citext column), we'll end\n // up with multiple keys...\n //\n // This is fundamentally asking to create the same entity, but with different ifNew/upsert\n // conditions, which we could fail on, but for now just take the first tuple of\n // {where/ifNew/upsert} and assume it wins\n const [{ ifNew, upsert }] = keys;\n\n // Before we find/create an entity, see if we have a maybe-new one in the EM already.\n // This will also use any WIP changes we've made to the found entity, which ideally is\n // something `em.find` would do as well, but its queries are much more complex...\n const inMemory = em.filterEntities(type, where);\n if (inMemory.length > 1) {\n throw new TooManyError(`Found more than one existing ${type.name} with ${whereAsString(where)}`);\n } else if (inMemory.length === 1) {\n const entity = inMemory[0] as T;\n resurrectIfSoftDeleted(entity);\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n }\n\n // If there is a param like `{ publisher: newPublisherEntity }`, then we know that\n // an entity matching this condition can't be in the db anyway, so skip the em.find\n const hasNewEntityParam = Object.values(where).some((v) => isEntity(v) && v.isNewEntity);\n if (hasNewEntityParam) {\n const entity = em.create(type, { ...where, ...(ifNew as object) } as OptsOf<T>);\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n }\n\n // If we didn't find it in the EM, do the db query/em.create\n const entities = await em.find(\n type,\n newWhereEqual(meta, where) as any,\n // Always include soft-deleted rows so findOrCreate can resurrect them instead of creating duplicates.\n { softDeletes: \"include\" },\n );\n let entity: T;\n if (entities.length > 1) {\n throw new TooManyError(`Found more than one existing ${type.name} with ${whereAsString(where)}`);\n } else if (entities.length === 1) {\n entity = entities[0];\n resurrectIfSoftDeleted(entity);\n } else {\n entity = em.create(type, { ...where, ...(ifNew as object) } as OptsOf<T>);\n }\n if (upsert) {\n entity.set(upsert);\n }\n return keys.map(() => entity);\n },\n // Our filter tuple is a complex object, so use a stable cache key to ensure caching works.\n { cacheKeyFn: whereFilterHash as any },\n );\n}\n\n/** A simple in-memory match of `entity` against a mini/flat \"WHERE clause\" of `opts`. */\nexport function entityMatches<T extends Entity>(entity: T, opts: Partial<OptsOf<T>>): boolean {\n const meta = getMetadata(entity);\n return Object.entries(opts).every(([fieldName, value]) => {\n const field = meta.allFields[fieldName] ?? fail(`Invalid field ${fieldName}`);\n const fn = fieldName as keyof T & keyof OptsOf<T>;\n switch (field.kind) {\n case \"primaryKey\":\n case \"enum\":\n return entity[fn] === value;\n case \"primitive\":\n if (meta.columns[fieldName]?.isArray) {\n const current = entity[fn];\n return Array.isArray(current) && Array.isArray(value) ? equalArrays(current, value) : current === value;\n } else if (field.citext) {\n return compareCaseInsensitive(entity[fn], value);\n } else {\n return entity[fn] === value;\n }\n case \"m2o\":\n case \"poly\":\n const relation = entity[fn] as ManyToOneReference<T, any, any> | PolymorphicReference<T, any, any>;\n if (isLoadedReference(relation)) {\n // Prefer using `.get` because it will handle new/id-less entities\n return sameEntity(relation.get, value as any);\n } else if (relation.isSet) {\n // Otherwise use ids\n return sameEntity(relation.id as any, value as any);\n } else {\n // Relation is not set, match if value is null-ish (null or undefined)\n return value === undefined || value === null;\n }\n default:\n throw new Error(`Unsupported field ${fieldName}`);\n }\n });\n}\n\nfunction whereAsString(where: object): string {\n return Object.entries(where)\n .map(([key, value]) => `${key}=${value}`)\n .join(\", \");\n}\n\nfunction compareCaseInsensitive(str1: any, str2: any): boolean {\n return (\n str1 !== undefined &&\n str2 !== undefined &&\n typeof str1 === \"string\" &&\n typeof str2 === \"string\" &&\n str1.toLowerCase() === str2.toLowerCase()\n );\n}\n\n/** Returns a copy of `opts` with any `citext` values turned to lower case. */\nfunction maybeLower<T extends object | undefined>(meta: EntityMetadata, opts: T): T {\n if (!opts) return opts;\n let result: T | undefined = undefined;\n for (const k in opts) {\n const v = (opts as any)[k];\n const field = meta.allFields[k];\n const isString = field && field.kind === \"primitive\" && field.type === \"string\";\n if (isString && field.citext) {\n const lowered = v?.toLowerCase();\n if (lowered !== v) {\n result ??= { ...opts };\n (result as any)[k] = lowered as any;\n }\n }\n }\n return result ?? opts;\n}\n\n/** Returns a copy of `opts` with any string values trimmed/coalesced. */\nfunction maybeClean<T extends object | undefined>(meta: EntityMetadata, opts: T): T {\n if (!opts) return opts;\n let result: T | undefined = undefined;\n for (const k in opts) {\n const v = (opts as any)[k];\n const field = meta.allFields[k];\n const isString = field && field.kind === \"primitive\" && field.type === \"string\";\n if (isString && field.sanitize !== false) {\n const cleaned = cleanStringValue(v);\n if (cleaned !== v) {\n result ??= { ...opts }; // Only create copy on first change\n (result as any)[k] = cleaned;\n }\n }\n }\n return result ?? opts;\n}\n"],"mappings":"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"}
@@ -1,7 +1,7 @@
1
1
  Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
2
- const require_normalizeHints = require("../normalizeHints.cjs");
3
2
  const require_queries_find_QueryVisitor = require("../queries/find/QueryVisitor.cjs");
4
3
  const require_queries_find_QueryParser = require("../queries/find/QueryParser.cjs");
4
+ const require_normalizeHints = require("../normalizeHints.cjs");
5
5
  const require_EntityMetadata = require("../EntityMetadata.cjs");
6
6
  const require_loading_HintTree = require("../loading/HintTree.cjs");
7
7
  const require_queries_unnest = require("../queries/unnest.cjs");