Skip to content

Commit

Permalink
chore(fulfillment, utils): Migrate module to DML (medusajs#10617)
Browse files Browse the repository at this point in the history
**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>
  • Loading branch information
adrien2p and carlos-r-l-rodrigues authored Dec 19, 2024
1 parent 65007c4 commit 100da64
Show file tree
Hide file tree
Showing 39 changed files with 1,142 additions and 1,846 deletions.
8 changes: 8 additions & 0 deletions .changeset/clean-news-sin.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
---
"@medusajs/fulfillment": patch
"@medusajs/types": patch
"@medusajs/utils": patch
"@medusajs/medusa": patch
---

chore: fulfillment module DML
Original file line number Diff line number Diff line change
Expand Up @@ -237,10 +237,10 @@ medusaIntegrationTestRunner({
},
]),
provider_id: "manual_test-provider",
provider: {
provider: expect.objectContaining({
id: "manual_test-provider",
is_enabled: true,
},
}),
rules: [],
service_zone_id: expect.any(String),
service_zone: {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,10 @@ medusaIntegrationTestRunner({

expect(response.status).toEqual(200)
expect(response.data.stock_location.fulfillment_providers).toEqual([
{ id: "manual_test-provider", is_enabled: true },
expect.objectContaining({
id: "manual_test-provider",
is_enabled: true,
}),
])
})

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -502,6 +502,7 @@ medusaIntegrationTestRunner({
provider_id: provider_id,
data: null,
metadata: null,
shipping_option_type_id: expect.any(String),
type: expect.objectContaining({
id: expect.any(String),
code: shippingOptionData.type.code,
Expand Down
4 changes: 3 additions & 1 deletion packages/core/types/src/dml/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -147,7 +147,9 @@ export interface EntityConstructor<Props> extends Function {
*/
export type InferForeignKeys<Schema extends DMLSchema> = {
[K in keyof Schema as Schema[K] extends { $foreignKey: true }
? `${K & string}_id`
? Schema[K] extends { $foreignKeyName: `${infer FkName}` }
? `${FkName & string}`
: `${K & string}_id`
: never]: Schema[K] extends { $foreignKey: true }
? null extends Schema[K]["$dataType"]
? string | null
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -87,7 +87,7 @@ export interface UpdateShippingOptionDTO {
/**
* The shipping option type associated with the shipping option.
*/
type:
type?:
| Omit<CreateShippingOptionTypeDTO, "shipping_option_id">
| {
/**
Expand Down
44 changes: 22 additions & 22 deletions packages/core/utils/src/dml/__tests__/entity-builder.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3018,6 +3018,7 @@ describe("Entity builder", () => {
persist: false,
name: "user_id",
nullable: false,
formula: expect.any(Function),
reference: "scalar",
setter: false,
type: "string",
Expand Down Expand Up @@ -3123,14 +3124,16 @@ describe("Entity builder", () => {
reference: "1:1",
name: "email",
entity: "Email",
fieldName: "email_id",
},
email_id: {
columnType: "text",
type: "string",
reference: "scalar",
name: "email_id",
formula: expect.any(Function),
nullable: false,
persist: true,
persist: false,
getter: false,
setter: false,
},
Expand Down Expand Up @@ -3233,14 +3236,16 @@ describe("Entity builder", () => {
name: "emails",
entity: "Email",
nullable: true,
fieldName: "emails_id",
},
emails_id: {
columnType: "text",
type: "string",
reference: "scalar",
name: "emails_id",
formula: expect.any(Function),
nullable: true,
persist: true,
persist: false,
getter: false,
setter: false,
},
Expand Down Expand Up @@ -3334,14 +3339,16 @@ describe("Entity builder", () => {
name: "email",
entity: "Email",
mappedBy: "owner",
fieldName: "email_id",
},
email_id: {
columnType: "text",
type: "string",
reference: "scalar",
name: "email_id",
formula: expect.any(Function),
nullable: false,
persist: true,
persist: false,
getter: false,
setter: false,
},
Expand Down Expand Up @@ -3439,14 +3446,16 @@ describe("Entity builder", () => {
entity: "Email",
cascade: ["persist", "soft-remove"],
mappedBy: "user",
fieldName: "email_id",
},
email_id: {
columnType: "text",
type: "string",
reference: "scalar",
name: "email_id",
formula: expect.any(Function),
nullable: false,
persist: true,
persist: false,
getter: false,
setter: false,
},
Expand Down Expand Up @@ -3614,14 +3623,16 @@ describe("Entity builder", () => {
entity: "Email",
cascade: ["persist", "soft-remove"],
mappedBy: "user",
fieldName: "email_id",
},
email_id: {
columnType: "text",
type: "string",
reference: "scalar",
formula: expect.any(Function),
name: "email_id",
nullable: false,
persist: true,
persist: false,
getter: false,
setter: false,
},
Expand Down Expand Up @@ -3704,6 +3715,7 @@ describe("Entity builder", () => {
name: "user_id",
nullable: false,
reference: "scalar",
formula: expect.any(Function),
setter: false,
type: "string",
persist: false,
Expand Down Expand Up @@ -4649,6 +4661,7 @@ describe("Entity builder", () => {
reference: "scalar",
persist: false,
type: "string",
formula: expect.any(Function),
columnType: "text",
nullable: false,
name: "user_id",
Expand Down Expand Up @@ -4848,6 +4861,7 @@ describe("Entity builder", () => {
type: "string",
columnType: "text",
nullable: true,
formula: expect.any(Function),
name: "user_id",
getter: false,
setter: false,
Expand Down Expand Up @@ -5268,23 +5282,6 @@ describe("Entity builder", () => {
})
})

test("throw error when other side relationship is missing", () => {
const email = model.define("email", {
email: model.text(),
isVerified: model.boolean(),
user: model.belongsTo(() => user),
})

const user = model.define("user", {
id: model.number(),
username: model.text(),
})

expect(() => toMikroORMEntity(email)).toThrow(
'Missing property "email" on "User" entity. Make sure to define it as a relationship'
)
})

test("throw error when other side relationship is invalid", () => {
const email = model.define("email", {
email: model.text(),
Expand Down Expand Up @@ -5482,6 +5479,7 @@ describe("Entity builder", () => {
type: "string",
persist: false,
columnType: "text",
formula: expect.any(Function),
nullable: false,
name: "user_id",
getter: false,
Expand Down Expand Up @@ -5682,6 +5680,7 @@ describe("Entity builder", () => {
type: "string",
columnType: "text",
nullable: false,
formula: expect.any(Function),
name: "user_id",
getter: false,
setter: false,
Expand Down Expand Up @@ -5903,6 +5902,7 @@ describe("Entity builder", () => {
type: "string",
columnType: "text",
reference: "scalar",
formula: expect.any(Function),
persist: false,
getter: false,
setter: false,
Expand Down
48 changes: 23 additions & 25 deletions packages/core/utils/src/dml/entity-builder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,9 @@ import {
IDmlEntityConfig,
RelationshipOptions,
} from "@medusajs/types"
import { DmlEntity } from "./entity"
import {
createBigNumberProperties,
DMLSchemaWithBigNumber,
} from "./helpers/entity-builder/create-big-number-properties"
import {
createDefaultProperties,
DMLSchemaDefaults,
} from "./helpers/entity-builder/create-default-properties"
import { DmlEntity, DMLEntitySchemaBuilder } from "./entity"
import { createBigNumberProperties } from "./helpers/entity-builder/create-big-number-properties"
import { createDefaultProperties } from "./helpers/entity-builder/create-default-properties"
import { ArrayProperty } from "./properties/array"
import { AutoIncrementProperty } from "./properties/autoincrement"
import { BigNumberProperty } from "./properties/big-number"
Expand Down Expand Up @@ -131,20 +125,14 @@ export class EntityBuilder {
define<Schema extends DMLSchema, const TConfig extends IDmlEntityConfig>(
nameOrConfig: TConfig,
schema: Schema
): DmlEntity<
Schema & DMLSchemaWithBigNumber<Schema> & DMLSchemaDefaults,
TConfig
> {
): DmlEntity<DMLEntitySchemaBuilder<Schema>, TConfig> {
this.#disallowImplicitProperties(schema)

return new DmlEntity<Schema, TConfig>(nameOrConfig, {
...schema,
...createBigNumberProperties(schema),
...createDefaultProperties(),
}) as unknown as DmlEntity<
Schema & DMLSchemaWithBigNumber<Schema> & DMLSchemaDefaults,
TConfig
>
}) as unknown as DmlEntity<DMLEntitySchemaBuilder<Schema>, TConfig>
}

/**
Expand Down Expand Up @@ -253,7 +241,7 @@ export class EntityBuilder {
/**
* This method defines a float property that allows for
* values with decimal places
*
*
* @version 2.1.2
*
* @example
Expand Down Expand Up @@ -398,26 +386,31 @@ export class EntityBuilder {
*
* @customNamespace Relationship Methods
*/
hasOne<T>(
hasOne<T, const ForeignKeyName extends string | undefined = undefined>(
entityBuilder: T,
options: RelationshipOptions & {
foreignKey: true
foreignKeyName?: ForeignKeyName
}
): HasOneWithForeignKey<T>
): HasOneWithForeignKey<T, ForeignKeyName>
hasOne<T>(
entityBuilder: T,
options?: RelationshipOptions & {
foreignKey?: false
}
): HasOne<T>
hasOne<T>(
hasOne<T, const ForeignKeyName extends string | undefined = undefined>(
entityBuilder: T,
options?: RelationshipOptions & {
foreignKey?: boolean
foreignKeyName?: ForeignKeyName
}
): HasOneWithForeignKey<T> | HasOne<T> {
): HasOneWithForeignKey<T, ForeignKeyName> | HasOne<T> {
if (options?.foreignKey) {
return new HasOneWithForeignKey<T>(entityBuilder, options || {})
return new HasOneWithForeignKey<T, ForeignKeyName>(
entityBuilder,
options || {}
)
}
return new HasOne<T>(entityBuilder, options || {})
}
Expand Down Expand Up @@ -445,8 +438,13 @@ export class EntityBuilder {
*
* @customNamespace Relationship Methods
*/
belongsTo<T>(entityBuilder: T, options?: RelationshipOptions) {
return new BelongsTo<T>(entityBuilder, options || {})
belongsTo<T, const ForeignKeyName extends string | undefined = undefined>(
entityBuilder: T,
options?: RelationshipOptions & {
foreignKeyName?: ForeignKeyName
}
) {
return new BelongsTo<T, ForeignKeyName>(entityBuilder, options || {})
}

/**
Expand Down
7 changes: 7 additions & 0 deletions packages/core/utils/src/dml/entity.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,16 @@ import {
import { isObject, isString, toCamelCase, upperCaseFirst } from "../common"
import { transformIndexWhere } from "./helpers/entity-builder/build-indexes"
import { BelongsTo } from "./relations/belongs-to"
import {
DMLSchemaDefaults,
DMLSchemaWithBigNumber,
} from "./helpers/entity-builder"

const IsDmlEntity = Symbol.for("isDmlEntity")

export type DMLEntitySchemaBuilder<Schema extends DMLSchema> =
DMLSchemaWithBigNumber<Schema> & DMLSchemaDefaults & Schema

function extractNameAndTableName<const Config extends IDmlEntityConfig>(
nameOrConfig: Config
) {
Expand Down
Loading

0 comments on commit 100da64

Please sign in to comment.