chore(fulfillment, utils): Migrate module to DML (#10617)

**What**
- Allow to provide `foreignKeyName` option for hasOne and belongsTo relationships
  - `model.hasOne(() => OtherEntity, { foreignKey: true, foreignKeyName: 'other_entity_something_id' })`
  - The above will also output a generated type that takes into consideration the custom fk name 🔽 
- Update types to account for defined custom foreign key name
- Fix joiner config linkable generation to account for custom linkable keys that provide a public API for their model but are not part of the list of the models included in the MedusaService
  - This was supposed to be handled correctly but the implementation was not considering that custom linkable keys could reference models not part of the one provided to medusa service
- Migrate fulfillment module to DML
- Fix has one with fk behaviour and hooks (the relation should be assigned but not the fk)
- Fix has one belongsTo hooks (the relation should be assigned but not the fk)
- Fix hasOneWithFk and belongsTo non persisted fk to be selectable
- Allow to define `belongsTo` without other side definition for `ManyToOne` with no counter part defined
  - Meaning that if a user defined `belongsTo` on one side andnot mapped by and no counter part on the other entity it will be considered as a `ManyToOne`
- `orphanRemoval` on `OneToOne` have been removed, this means that when assigning a new object relation to an entity, the previous one gets deconected but not deleted automatically. This prevent removing data un volountarely

**NOTE**
As per our convention here are some information to keep in mind

**HasOne <> BelongsTo**
Define `OneToOne`, The foreign key is owned by the belongs to and the relation needs to be provided to cascade if wanted

**HasMany <> BelongsTo**
Define `OneToMane` <> `ManyToOne`, the foreign key is owned by the many to one and for those relation no cascade will be performed, the foreign key must be provided. For the `HasMany` the cascade is available

**HasOne (with FK)**
Will act similarly to belongs to with **HasOne <> BelongsTo**

Co-authored-by: Carlos R. L. Rodrigues <37986729+carlos-r-l-rodrigues@users.noreply.github.com>
This commit is contained in:
Adrien de Peretti
2024-12-19 17:40:11 +01:00
committed by GitHub
parent 65007c49f6
commit 100da64242
39 changed files with 1154 additions and 1858 deletions
@@ -613,10 +613,15 @@ describe("joiner-config-builder", () => {
}
)
const linkConfig = buildLinkConfigFromModelObjects("myService", {
user,
car,
})
const linkableKeysFromDml = buildLinkableKeysFromDmlObjects([user, car])
const linkConfig = buildLinkConfigFromModelObjects(
"myService",
{
user,
car,
},
linkableKeysFromDml
)
expectTypeOf(linkConfig).toMatchTypeOf<{
user: {
@@ -413,41 +413,41 @@ export function buildLinkConfigFromModelObjects<
}
}
}
}
/**
* If the joiner config specify some custom linkable keys, we merge them with the
* existing linkable keys infered from the model above.
*/
const linkableKeysPerModel = Object.entries(linkableKeys).reduce(
(acc, [key, entityName]) => {
acc[entityName] ??= []
acc[entityName].push(key)
return acc
},
{}
/**
* If the joiner config specify some custom linkable keys, we merge them with the
* existing linkable keys infered from the model above.
*/
for (const [linkableKey, modelName] of Object.entries(linkableKeys) ?? []) {
const snakeCasedModelName = camelToSnakeCase(toCamelCase(modelName))
// Linkable keys by default are prepared with snake cased model name _id
// So to be able to compare only the property we have to remove the first part
const inferredReferenceProperty = linkableKey.replace(
`${snakeCasedModelName}_`,
""
)
for (const linkableKey of linkableKeysPerModel[classLikeModelName] ?? []) {
const snakeCasedModelName = camelToSnakeCase(toCamelCase(model.name))
linkConfig[lowerCaseFirst(modelName)] ??= {
toJSON: function () {
const linkables = Object.entries(this)
.filter(([name]) => name !== "toJSON")
.map(([, object]) => object)
return linkables[0]
},
}
// Linkable keys by default are prepared with snake cased model name _id
// So to be able to compare only the property we have to remove the first part
const inferredReferenceProperty = linkableKey.replace(
`${snakeCasedModelName}_`,
""
)
if (linkConfig[lowerCaseFirst(modelName)][inferredReferenceProperty]) {
continue
}
if (modelLinkConfig[inferredReferenceProperty]) {
continue
}
modelLinkConfig[linkableKey] = {
linkable: linkableKey,
primaryKey: linkableKey,
serviceName,
field: lowerCaseFirst(model.name),
entity: upperCaseFirst(model.name),
}
linkConfig[lowerCaseFirst(modelName)][inferredReferenceProperty] = {
linkable: linkableKey,
primaryKey: inferredReferenceProperty,
serviceName,
field: lowerCaseFirst(modelName),
entity: upperCaseFirst(modelName),
}
}