diff --git a/packages/core/modules-sdk/src/loaders/utils/__tests__/load-internal.spec.ts b/packages/core/modules-sdk/src/loaders/utils/__tests__/load-internal.spec.ts index 5034dc7463..2648d51c33 100644 --- a/packages/core/modules-sdk/src/loaders/utils/__tests__/load-internal.spec.ts +++ b/packages/core/modules-sdk/src/loaders/utils/__tests__/load-internal.spec.ts @@ -1,5 +1,5 @@ -import { loadResources } from "../load-internal" import { IModuleService, ModuleResolution } from "@medusajs/types" +import { upperCaseFirst } from "@medusajs/utils" import { join } from "path" import { ModuleWithDmlMixedWithoutJoinerConfigFixtures, @@ -7,7 +7,7 @@ import { ModuleWithJoinerConfigFixtures, ModuleWithoutJoinerConfigFixtures, } from "../__fixtures__" -import { upperCaseFirst } from "@medusajs/utils" +import { loadResources } from "../load-internal" describe("load internal - load resources", () => { describe("when loading the module resources from a path", () => { @@ -64,30 +64,32 @@ describe("load internal - load resources", () => { resources.moduleService.prototype as IModuleService ).__joinerConfig() - expect(generatedJoinerConfig).toEqual({ - serviceName: "module-with-dml-mixed-without-joiner-config", - primaryKeys: ["id"], - linkableKeys: { - dml_entity_id: "DmlEntity", - entity_model_id: "EntityModel", - }, - alias: [ - { - name: ["dml_entity", "dml_entities"], - args: { - entity: "DmlEntity", - methodSuffix: "DmlEntities", - }, + expect(generatedJoinerConfig).toEqual( + expect.objectContaining({ + serviceName: "module-with-dml-mixed-without-joiner-config", + primaryKeys: ["id"], + linkableKeys: { + dml_entity_id: "DmlEntity", + entity_model_id: "EntityModel", }, - { - name: ["entity_model", "entity_models"], - args: { - entity: "EntityModel", - methodSuffix: "EntityModels", + alias: [ + { + name: ["dml_entity", "dml_entities"], + args: { + entity: "DmlEntity", + methodSuffix: "DmlEntities", + }, }, - }, - ], - }) + { + name: ["entity_model", "entity_models"], + args: { + entity: "EntityModel", + methodSuffix: "EntityModels", + }, + }, + ], + }) + ) }) test("should return the correct resources and generate the correct joiner config from DML entities", async () => { @@ -143,30 +145,32 @@ describe("load internal - load resources", () => { resources.moduleService.prototype as IModuleService ).__joinerConfig() - expect(generatedJoinerConfig).toEqual({ - serviceName: "module-with-dml-without-joiner-config", - primaryKeys: ["id"], - linkableKeys: { - entity_model_id: "EntityModel", - dml_entity_id: "DmlEntity", - }, - alias: [ - { - name: ["entity_model", "entity_models"], - args: { - entity: "EntityModel", - methodSuffix: "EntityModels", - }, + expect(generatedJoinerConfig).toEqual( + expect.objectContaining({ + serviceName: "module-with-dml-without-joiner-config", + primaryKeys: ["id"], + linkableKeys: { + entity_model_id: "EntityModel", + dml_entity_id: "DmlEntity", }, - { - name: ["dml_entity", "dml_entities"], - args: { - entity: "DmlEntity", - methodSuffix: "DmlEntities", + alias: [ + { + name: ["entity_model", "entity_models"], + args: { + entity: "EntityModel", + methodSuffix: "EntityModels", + }, }, - }, - ], - }) + { + name: ["dml_entity", "dml_entities"], + args: { + entity: "DmlEntity", + methodSuffix: "DmlEntities", + }, + }, + ], + }) + ) }) test("should return the correct resources and generate the correct joiner config from mikro orm entities", async () => { @@ -229,6 +233,7 @@ describe("load internal - load resources", () => { entity2_id: "Entity2", entity_model_id: "EntityModel", }, + schema: "", alias: [ { name: ["entity2", "entity2s"], @@ -301,6 +306,7 @@ describe("load internal - load resources", () => { serviceName: "module-service", primaryKeys: ["id"], linkableKeys: {}, + schema: "", alias: [ { name: ["custom_name"], diff --git a/packages/core/utils/src/dml/__tests__/create-graphql.spec.ts b/packages/core/utils/src/dml/__tests__/create-graphql.spec.ts new file mode 100644 index 0000000000..88b026df39 --- /dev/null +++ b/packages/core/utils/src/dml/__tests__/create-graphql.spec.ts @@ -0,0 +1,91 @@ +import { model } from "../entity-builder" +import { toGraphQLSchema } from "../helpers/create-graphql" + +describe("GraphQL builder", () => { + test("define an entity", () => { + const tag = model.define("tag", { + id: model.id(), + value: model.text(), + }) + + const email = model.define("email", { + email: model.text(), + isVerified: model.boolean(), + }) + + const user = model.define("user", { + id: model.id(), + username: model.text(), + email: model.hasOne(() => email, { mappedBy: "owner" }), + spend_limit: model.bigNumber(), + phones: model.array(), + group: model.belongsTo(() => group, { mappedBy: "users" }), + role: model.enum(["moderator", "admin", "guest"]).default("guest"), + tags: model.manyToMany(() => tag, { + pivotTable: "custom_user_tags", + }), + }) + + const group = model.define("group", { + id: model.number(), + name: model.text(), + users: model.hasMany(() => user), + }) + + const toGql = toGraphQLSchema([tag, email, user, group]) + + const expected = ` + type Tag { + id: ID! + value: String! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + } + + type Email { + email: String! + isVerified: Boolean! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + } + + extend type Email { + owner: User! + } + + enum UserRoleEnum { + moderator + admin + guest + } + + type User { + id: ID! + username: String! + email: Email! + spend_limit: String! + phones: [String]! + group: [Group]! + role: UserRoleEnum! + tags: [Tag]! + raw_spend_limit: JSON! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + } + + type Group { + id: Int! + name: String! + users: [User]! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + } + ` + + expect(toGql.replace(/\s/g, "")).toEqual(expected.replace(/\s/g, "")) + }) +}) diff --git a/packages/core/utils/src/dml/__tests__/entity-builder.spec.ts b/packages/core/utils/src/dml/__tests__/entity-builder.spec.ts index 3a15cf391e..e8c1fef2a9 100644 --- a/packages/core/utils/src/dml/__tests__/entity-builder.spec.ts +++ b/packages/core/utils/src/dml/__tests__/entity-builder.spec.ts @@ -2131,7 +2131,7 @@ describe("Entity builder", () => { entity: "Email", nullable: false, mappedBy: "user", - cascade: ["perist", "soft-remove"], + cascade: ["persist", "soft-remove"], }, created_at: { reference: "scalar", @@ -2284,7 +2284,7 @@ describe("Entity builder", () => { entity: "Email", nullable: false, mappedBy: "user", - cascade: ["perist", "soft-remove"], + cascade: ["persist", "soft-remove"], }, created_at: { reference: "scalar", @@ -2891,7 +2891,7 @@ describe("Entity builder", () => { entity: "Email", orphanRemoval: true, mappedBy: "user", - cascade: ["perist", "soft-remove"], + cascade: ["persist", "soft-remove"], }, created_at: { reference: "scalar", @@ -2981,7 +2981,7 @@ describe("Entity builder", () => { entity: "Email", orphanRemoval: true, mappedBy: "user", - cascade: ["perist", "soft-remove"], + cascade: ["persist", "soft-remove"], }, created_at: { reference: "scalar", diff --git a/packages/core/utils/src/dml/helpers/create-graphql.ts b/packages/core/utils/src/dml/helpers/create-graphql.ts new file mode 100644 index 0000000000..b89b9a5dc3 --- /dev/null +++ b/packages/core/utils/src/dml/helpers/create-graphql.ts @@ -0,0 +1,63 @@ +import type { PropertyType } from "@medusajs/types" +import { DmlEntity } from "../entity" +import { parseEntityName } from "./entity-builder/parse-entity-name" +import { getGraphQLAttributeFromDMLPropety } from "./graphql-builder/get-attribute" +import { setGraphQLRelationship } from "./graphql-builder/set-relationship" + +export function generateGraphQLFromEntity>( + entity: T +): string { + const { schema } = entity.parse() + const { modelName } = parseEntityName(entity) + + let extra: string[] = [] + let gqlSchema: string[] = [] + + Object.entries(schema).forEach(([name, property]) => { + const field = property.parse(name) + + if ("fieldName" in field) { + const prop = getGraphQLAttributeFromDMLPropety( + modelName, + name, + property as PropertyType + ) + + if (prop.enum) { + extra.push(prop.enum) + } + + gqlSchema.push(`${prop.attribute}`) + } else { + const prop = setGraphQLRelationship(modelName, field) + if (prop.extra) { + extra.push(prop.extra) + } + + gqlSchema.push(`${prop.attribute}`) + } + }) + + return ` + ${extra.join("\n")} + type ${modelName} { + ${gqlSchema.join("\n")} + } + ` +} + +/** + * Takes a DML entity and returns a GraphQL schema string. + * @param entity + */ +export const toGraphQLSchema = (entities: T): string => { + const gqlSchemas = entities.map((entity) => { + if (DmlEntity.isDmlEntity(entity)) { + return generateGraphQLFromEntity(entity) + } + + return entity + }) + + return gqlSchemas.join("\n") +} diff --git a/packages/core/utils/src/dml/helpers/create-mikro-orm-entity.ts b/packages/core/utils/src/dml/helpers/create-mikro-orm-entity.ts index 4b2c3db732..71be269c34 100644 --- a/packages/core/utils/src/dml/helpers/create-mikro-orm-entity.ts +++ b/packages/core/utils/src/dml/helpers/create-mikro-orm-entity.ts @@ -8,13 +8,13 @@ import type { import { Entity, Filter } from "@mikro-orm/core" import { mikroOrmSoftDeletableFilterOptions } from "../../dal" import { DmlEntity } from "../entity" +import { DuplicateIdPropertyError } from "../errors" +import { IdProperty } from "../properties/id" import { applySearchable } from "./entity-builder/apply-searchable" import { defineProperty } from "./entity-builder/define-property" import { defineRelationship } from "./entity-builder/define-relationship" import { parseEntityName } from "./entity-builder/parse-entity-name" import { applyEntityIndexes, applyIndexes } from "./mikro-orm/apply-indexes" -import { IdProperty } from "../properties/id" -import { DuplicateIdPropertyError } from "../errors" /** * Factory function to create the mikro orm entity builder. The return @@ -36,7 +36,7 @@ export function createMikrORMEntity() { * - [team.users] // cannot be an owner */ // TODO: if we use the util toMikroOrmEntities then a new builder will be used each time, lets think about this. Currently if means that with many to many we need to use the same builder - const MANY_TO_MANY_TRACKED_REALTIONS: Record = {} + const MANY_TO_MANY_TRACKED_RELATIONS: Record = {} /** * A helper function to define a Mikro ORM entity from a @@ -61,7 +61,7 @@ export function createMikrORMEntity() { }) const context = { - MANY_TO_MANY_TRACKED_REALTIONS, + MANY_TO_MANY_TRACKED_RELATIONS, } let hasIdAlreadyDefined = false diff --git a/packages/core/utils/src/dml/helpers/entity-builder/define-relationship.ts b/packages/core/utils/src/dml/helpers/entity-builder/define-relationship.ts index fe7fc23d97..36d46708f6 100644 --- a/packages/core/utils/src/dml/helpers/entity-builder/define-relationship.ts +++ b/packages/core/utils/src/dml/helpers/entity-builder/define-relationship.ts @@ -9,9 +9,9 @@ import { BeforeCreate, ManyToMany, ManyToOne, + OnInit, OneToMany, OneToOne, - OnInit, Property, rel, } from "@mikro-orm/core" @@ -24,7 +24,7 @@ import { ManyToMany as DmlManyToMany } from "../../relations/many-to-many" import { parseEntityName } from "./parse-entity-name" type Context = { - MANY_TO_MANY_TRACKED_REALTIONS: Record + MANY_TO_MANY_TRACKED_RELATIONS: Record } /** @@ -43,7 +43,7 @@ export function defineHasOneRelationship( nullable: relationship.nullable, mappedBy: relationship.mappedBy || camelToSnakeCase(MikroORMEntity.name), cascade: shouldRemoveRelated - ? (["perist", "soft-remove"] as any) + ? (["persist", "soft-remove"] as any) : undefined, })(MikroORMEntity.prototype, relationship.name) } @@ -64,7 +64,7 @@ export function defineHasManyRelationship( orphanRemoval: true, mappedBy: relationship.mappedBy || camelToSnakeCase(MikroORMEntity.name), cascade: shouldRemoveRelated - ? (["perist", "soft-remove"] as any) + ? (["persist", "soft-remove"] as any) : undefined, })(MikroORMEntity.prototype, relationship.name) } @@ -238,7 +238,7 @@ export function defineManyToManyRelationship( relatedModelName, pgSchema, }: { relatedModelName: string; pgSchema: string | undefined }, - { MANY_TO_MANY_TRACKED_REALTIONS }: Context + { MANY_TO_MANY_TRACKED_RELATIONS }: Context ) { let mappedBy = relationship.mappedBy let inversedBy: undefined | string @@ -271,12 +271,12 @@ export function defineManyToManyRelationship( */ if ( otherSideRelation.parse(mappedBy).mappedBy && - MANY_TO_MANY_TRACKED_REALTIONS[`${relatedModelName}.${mappedBy}`] + MANY_TO_MANY_TRACKED_RELATIONS[`${relatedModelName}.${mappedBy}`] ) { inversedBy = mappedBy mappedBy = undefined } else { - MANY_TO_MANY_TRACKED_REALTIONS[ + MANY_TO_MANY_TRACKED_RELATIONS[ `${MikroORMEntity.name}.${relationship.name}` ] = true } diff --git a/packages/core/utils/src/dml/helpers/graphql-builder/get-attribute.ts b/packages/core/utils/src/dml/helpers/graphql-builder/get-attribute.ts new file mode 100644 index 0000000000..2938fa0689 --- /dev/null +++ b/packages/core/utils/src/dml/helpers/graphql-builder/get-attribute.ts @@ -0,0 +1,81 @@ +import { PropertyType } from "@medusajs/types" +import { toPascalCase } from "../../../common" +import { PrimaryKeyModifier } from "../../properties/primary-key" + +/* + * Map of DML data types to GraphQL types + */ +const GRAPHQL_TYPES = { + boolean: "Boolean", + dateTime: "DateTime", + number: "Int", + bigNumber: "String", + text: "String", + json: "JSON", + array: "[String]", + id: "ID", +} + +/** + * Defines a DML entity schema field as a Mikro ORM property + */ +export function getGraphQLAttributeFromDMLPropety( + modelName: string, + propertyName: string, + property: PropertyType +): { + enum?: string + attribute: string +} { + const field = property.parse(propertyName) + const fieldType = PrimaryKeyModifier.isPrimaryKeyModifier(property) + ? "id" + : field.dataType.name + + let enumSchema: string | undefined + let gqlAttr: { + property: string + type: string + } + + const specialType = { + enum: () => { + const enumName = toPascalCase(modelName + "_" + field.fieldName + "Enum") + const enumValues = field.dataType + .options!.choices.map((value) => { + return ` ${value}` + }) + .join("\n") + + enumSchema = `enum ${enumName} {\n${enumValues}\n}` + gqlAttr = { + property: field.fieldName, + type: enumName, + } + }, + id: () => { + gqlAttr = { + property: field.fieldName, + type: GRAPHQL_TYPES.id, + } + }, + } + + if (specialType[fieldType]) { + specialType[fieldType]() + } else { + gqlAttr = { + property: field.fieldName, + type: GRAPHQL_TYPES[fieldType] ?? "String", + } + } + + if (!field.nullable) { + gqlAttr!.type += "!" + } + + return { + enum: enumSchema, + attribute: `${gqlAttr!.property}: ${gqlAttr!.type}`, + } +} diff --git a/packages/core/utils/src/dml/helpers/graphql-builder/set-relationship.ts b/packages/core/utils/src/dml/helpers/graphql-builder/set-relationship.ts new file mode 100644 index 0000000000..d8ecd9d838 --- /dev/null +++ b/packages/core/utils/src/dml/helpers/graphql-builder/set-relationship.ts @@ -0,0 +1,100 @@ +import { + PropertyType, + RelationshipMetadata, + RelationshipType, +} from "@medusajs/types" +import { camelToSnakeCase } from "../../../common" +import { DmlEntity } from "../../entity" +import { BelongsTo } from "../../relations/belongs-to" +import { HasMany } from "../../relations/has-many" +import { HasOne } from "../../relations/has-one" +import { ManyToMany as DmlManyToMany } from "../../relations/many-to-many" +import { parseEntityName } from "../entity-builder/parse-entity-name" + +type Context = { + MANY_TO_MANY_TRACKED_RELATIONS: Record +} + +function defineRelationships( + modelName: string, + relationship: RelationshipMetadata, + relatedEntity: DmlEntity< + Record | RelationshipType>, + any + >, + { relatedModelName }: { relatedModelName: string } +) { + let extra: string | undefined + const fieldName = relationship.name + + const mappedBy = relationship.mappedBy || camelToSnakeCase(modelName) + const { schema: relationSchema } = relatedEntity.parse() + + const otherSideRelation = relationSchema[mappedBy] + + if (relationship.options?.mappedBy && HasOne.isHasOne(relationship)) { + const otherSideFieldName = relationship.options.mappedBy + extra = `extend type ${relatedModelName} {\n ${otherSideFieldName}: ${modelName}!\n}` + } + + let isArray = false + + /** + * Otherside is a has many. Hence we should defined a ManyToOne + */ + if ( + HasMany.isHasMany(otherSideRelation) || + DmlManyToMany.isManyToMany(relationship) || + (BelongsTo.isBelongsTo(otherSideRelation) && + HasMany.isHasMany(relationship)) + ) { + isArray = true + } + + return { + attribute: + `${fieldName}: ${isArray ? "[" : ""}${relatedModelName}${ + isArray ? "]" : "" + }` + (relationship.nullable ? "" : "!"), + extra, + } +} + +export function setGraphQLRelationship( + entityName: string, + relationship: RelationshipMetadata +): { + extra?: string + attribute: string +} { + const relatedEntity = + typeof relationship.entity === "function" + ? (relationship.entity() as unknown) + : undefined + + if (!relatedEntity) { + throw new Error( + `Invalid relationship reference for "${entityName}.${relationship.name}". Make sure to define the relationship using a factory function` + ) + } + + if (!DmlEntity.isDmlEntity(relatedEntity)) { + throw new Error( + `Invalid relationship reference for "${entityName}.${relationship.name}". Make sure to return a DML entity from the relationship callback` + ) + } + + const { modelName, tableName, pgSchema } = parseEntityName(relatedEntity) + const relatedEntityInfo = { + relatedModelName: modelName, + relatedTableName: tableName, + pgSchema, + } + + return defineRelationships( + entityName, + relationship, + relatedEntity, + relatedEntityInfo + ) +} diff --git a/packages/core/utils/src/modules-sdk/__tests__/joiner-config-builder.spec.ts b/packages/core/utils/src/modules-sdk/__tests__/joiner-config-builder.spec.ts index 5dfa02996c..9fad50fe16 100644 --- a/packages/core/utils/src/modules-sdk/__tests__/joiner-config-builder.spec.ts +++ b/packages/core/utils/src/modules-sdk/__tests__/joiner-config-builder.spec.ts @@ -1,13 +1,6 @@ -import { - buildLinkableKeysFromDmlObjects, - buildLinkableKeysFromMikroOrmObjects, - buildLinkConfigFromLinkableKeys, - buildLinkConfigFromModelObjects, - defineJoinerConfig, -} from "../joiner-config-builder" -import { Modules } from "../definition" -import { model } from "../../dml" import { expectTypeOf } from "expect-type" +import { upperCaseFirst } from "../../common" +import { model } from "../../dml" import { dmlFulfillment, dmlFulfillmentProvider, @@ -26,7 +19,14 @@ import { ShippingOptionRule, ShippingProfile, } from "../__fixtures__/joiner-config/entities" -import { upperCaseFirst } from "../../common" +import { Modules } from "../definition" +import { + buildLinkableKeysFromDmlObjects, + buildLinkableKeysFromMikroOrmObjects, + buildLinkConfigFromLinkableKeys, + buildLinkConfigFromModelObjects, + defineJoinerConfig, +} from "../joiner-config-builder" describe("joiner-config-builder", () => { describe("defineJoiner | Mikro orm objects", () => { @@ -47,7 +47,7 @@ describe("joiner-config-builder", () => { expect(joinerConfig).toEqual({ serviceName: Modules.FULFILLMENT, primaryKeys: ["id"], - schema: undefined, + schema: "", linkableKeys: { fulfillment_set_id: FulfillmentSet.name, shipping_option_id: ShippingOption.name, @@ -135,7 +135,7 @@ describe("joiner-config-builder", () => { expect(joinerConfig).toEqual({ serviceName: Modules.FULFILLMENT, primaryKeys: ["id"], - schema: undefined, + schema: "", linkableKeys: {}, alias: [ { @@ -175,7 +175,7 @@ describe("joiner-config-builder", () => { expect(joinerConfig).toEqual({ serviceName: Modules.FULFILLMENT, primaryKeys: ["id"], - schema: undefined, + schema: "", linkableKeys: { fulfillment_set_id: FulfillmentSet.name, shipping_option_id: ShippingOption.name, @@ -269,7 +269,7 @@ describe("joiner-config-builder", () => { expect(joinerConfig).toEqual({ serviceName: Modules.FULFILLMENT, primaryKeys: ["id"], - schema: undefined, + schema: "", linkableKeys: {}, alias: [ { @@ -300,7 +300,7 @@ describe("joiner-config-builder", () => { expect(joinerConfig).toEqual({ serviceName: Modules.FULFILLMENT, primaryKeys: ["id"], - schema: undefined, + schema: "", linkableKeys: { fulfillment_set_id: FulfillmentSet.name, }, @@ -335,7 +335,7 @@ describe("joiner-config-builder", () => { expect(joinerConfig).toEqual({ serviceName: Modules.FULFILLMENT, primaryKeys: ["id"], - schema: undefined, + schema: expect.any(String), linkableKeys: { fulfillment_set_id: FulfillmentSet.name, shipping_option_id: ShippingOption.name, @@ -405,6 +405,59 @@ describe("joiner-config-builder", () => { }, ], }) + + const schemaExpected = `type FulfillmentSet { + id: ID! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + } + type ShippingOption { + id: ID! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + } + type ShippingProfile { + id: ID! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + } + type Fulfillment { + id: ID! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + } + type FulfillmentProvider { + id: ID! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + } + type ServiceZone { + id: ID! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + } + type GeoZone { + id: ID! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + } + type ShippingOptionRule { + id: ID! + created_at: DateTime! + updated_at: DateTime! + deleted_at: DateTime + }` + + expect(joinerConfig.schema!.replace(/\s/g, "")).toEqual( + schemaExpected.replace(/\s/g, "") + ) }) }) diff --git a/packages/core/utils/src/modules-sdk/joiner-config-builder.ts b/packages/core/utils/src/modules-sdk/joiner-config-builder.ts index 31236abc74..71f4d9ca1a 100644 --- a/packages/core/utils/src/modules-sdk/joiner-config-builder.ts +++ b/packages/core/utils/src/modules-sdk/joiner-config-builder.ts @@ -4,25 +4,26 @@ import { ModuleJoinerConfig, PropertyType, } from "@medusajs/types" +import { accessSync } from "fs" import * as path from "path" import { dirname, join, normalize } from "path" import { + MapToConfig, camelToSnakeCase, deduplicate, getCallerFilePath, isObject, lowerCaseFirst, - MapToConfig, pluralize, toCamelCase, upperCaseFirst, } from "../common" -import { loadModels } from "./loaders/load-models" import { DmlEntity } from "../dml" -import { BaseRelationship } from "../dml/relations/base" +import { toGraphQLSchema } from "../dml/helpers/create-graphql" import { PrimaryKeyModifier } from "../dml/properties/primary-key" +import { BaseRelationship } from "../dml/relations/base" +import { loadModels } from "./loaders/load-models" import { InferLinkableKeys, InfersLinksConfig } from "./types/links-config" -import { accessSync } from "fs" /** * Define joiner config for a module based on the models (object representation or entities) present in the models directory. This action will be sync until @@ -146,6 +147,10 @@ export function defineJoinerConfig( deduplicatedLoadedModels.push(model) }) + if (!schema) { + schema = toGraphQLSchema([...modelDefinitions.values()]) + } + if (!linkableKeys) { const linkableKeysFromDml = buildLinkableKeysFromDmlObjects([ ...modelDefinitions.values(), diff --git a/packages/modules/inventory-next/src/joiner-config.ts b/packages/modules/inventory-next/src/joiner-config.ts index 6306c9e2f1..775888d278 100644 --- a/packages/modules/inventory-next/src/joiner-config.ts +++ b/packages/modules/inventory-next/src/joiner-config.ts @@ -1,6 +1,8 @@ import { defineJoinerConfig, Modules } from "@medusajs/utils" +import { default as schema } from "./schema" export const joinerConfig = defineJoinerConfig(Modules.INVENTORY, { + schema, alias: [ { name: ["inventory_items", "inventory_item", "inventory"],