feat(utils): dml to graphql (#8951)
This commit is contained in:
committed by
GitHub
parent
419cf1b7d7
commit
5a097d8954
@@ -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"],
|
||||
|
||||
@@ -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, ""))
|
||||
})
|
||||
})
|
||||
@@ -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",
|
||||
|
||||
@@ -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<T extends DmlEntity<any, any>>(
|
||||
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<any>
|
||||
)
|
||||
|
||||
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 = <T extends any[]>(entities: T): string => {
|
||||
const gqlSchemas = entities.map((entity) => {
|
||||
if (DmlEntity.isDmlEntity(entity)) {
|
||||
return generateGraphQLFromEntity(entity)
|
||||
}
|
||||
|
||||
return entity
|
||||
})
|
||||
|
||||
return gqlSchemas.join("\n")
|
||||
}
|
||||
@@ -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<string, boolean> = {}
|
||||
const MANY_TO_MANY_TRACKED_RELATIONS: Record<string, boolean> = {}
|
||||
|
||||
/**
|
||||
* 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
|
||||
|
||||
@@ -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<string, boolean>
|
||||
MANY_TO_MANY_TRACKED_RELATIONS: Record<string, boolean>
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -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
|
||||
}
|
||||
|
||||
@@ -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<any>
|
||||
): {
|
||||
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}`,
|
||||
}
|
||||
}
|
||||
@@ -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<string, boolean>
|
||||
}
|
||||
|
||||
function defineRelationships(
|
||||
modelName: string,
|
||||
relationship: RelationshipMetadata,
|
||||
relatedEntity: DmlEntity<
|
||||
Record<string, PropertyType<any> | RelationshipType<any>>,
|
||||
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
|
||||
)
|
||||
}
|
||||
@@ -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, "")
|
||||
)
|
||||
})
|
||||
})
|
||||
|
||||
|
||||
@@ -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(),
|
||||
|
||||
@@ -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"],
|
||||
|
||||
Reference in New Issue
Block a user