feat(codegen,types): SetRelation on expanded types (#3477)

## What

On expanded relations, mutate type using SetRelation, an alias for SetRequired with SetNonNullable.

## Why

Simplifies implementation in client code.

## How

* Export SetRelation type util
* Update codegen template

Extra scope:

* Improve codegen error handling when processing x-expanded-relations
* Add `eager` sub-categorization to x-expanded-relations to highlight relations that are loaded using TypeORM eager.
This commit is contained in:
Patrick
2023-03-15 11:29:21 +00:00
committed by GitHub
parent 6748877c69
commit 826d4bedfe
7 changed files with 59 additions and 20 deletions
+6
View File
@@ -0,0 +1,6 @@
---
"@medusajs/openapi-typescript-codegen": minor
"@medusajs/client-types": minor
---
feat(codegen,types): SetRelation on expanded types
@@ -1 +1,7 @@
export * from "./lib" export * from "./lib"
export {
Merge,
SetNonNullable,
SetRelation,
SetRequired,
} from "./lib/core/ModelUtils"
@@ -4,5 +4,6 @@ export interface WithExtendedRelationsExtension {
relations?: string[] relations?: string[]
totals?: string[] totals?: string[]
implicit?: string[] implicit?: string[]
eager?: string[]
} }
} }
@@ -9,13 +9,14 @@ export const handleExpandedRelations = (model: Model, allModels: Model[]) => {
const relations = xExpandedRelation.relations ?? [] const relations = xExpandedRelation.relations ?? []
const totals = xExpandedRelation.totals ?? [] const totals = xExpandedRelation.totals ?? []
const implicit = xExpandedRelation.implicit ?? [] const implicit = xExpandedRelation.implicit ?? []
const eager = xExpandedRelation.eager ?? []
const nestedRelation: NestedRelation = { const nestedRelation: NestedRelation = {
field, field,
nestedRelations: [], nestedRelations: [],
} }
for (const relation of [...relations, ...totals, ...implicit]) { for (const relation of [...relations, ...totals, ...implicit, ...eager]) {
const splitRelation = relation.split(".") const splitRelation = relation.split(".")
walkSplitRelations(nestedRelation, splitRelation, 0) walkSplitRelations(nestedRelation, splitRelation, 0)
} }
@@ -24,9 +25,13 @@ export const handleExpandedRelations = (model: Model, allModels: Model[]) => {
model.imports = [...new Set(model.imports)] model.imports = [...new Set(model.imports)]
const prop = getPropertyByName(nestedRelation.field, model) const prop = getPropertyByName(nestedRelation.field, model)
if (prop) { if (!prop) {
prop.nestedRelations = [nestedRelation] throw new Error(`x-expanded-relations error - field not found
Schema: ${model.name}
NestedRelation: ${JSON.stringify(nestedRelation, null, 2)}
Model: ${JSON.stringify(model.spec, null, 2)}`)
} }
prop.nestedRelations = [nestedRelation]
} }
const walkSplitRelations = ( const walkSplitRelations = (
@@ -59,12 +64,20 @@ const walkNestedRelations = (
nestedRelation: NestedRelation, nestedRelation: NestedRelation,
parentNestedRelation?: NestedRelation parentNestedRelation?: NestedRelation
) => { ) => {
const prop = const prop = ["all-of", "any-of", "one-of"].includes(model.export)
model.export === "all-of" ? findPropInCombination(nestedRelation.field, model, allModels)
? findPropInAllOf(nestedRelation.field, model, allModels) : getPropertyByName(nestedRelation.field, model)
: getPropertyByName(nestedRelation.field, model)
if (!prop) { if (!prop) {
return throw new Error(`x-expanded-relations - field not found
Schema: ${rootModel.name}
NestedRelation: ${JSON.stringify(nestedRelation, null, 2)}
Model: ${JSON.stringify(model.spec, null, 2)}`)
}
if (["all-of", "any-of", "one-of"].includes(prop.export)) {
throw new Error(`x-expanded-relations - unsupported - field referencing multiple models
Schema: ${rootModel.name}
NestedRelation: ${JSON.stringify(nestedRelation, null, 2)}
Model: ${JSON.stringify(model.spec, null, 2)}`)
} }
if (!["reference", "array"].includes(prop.export)) { if (!["reference", "array"].includes(prop.export)) {
return return
@@ -73,15 +86,21 @@ const walkNestedRelations = (
nestedRelation.base = prop.type nestedRelation.base = prop.type
nestedRelation.isArray = prop.export === "array" nestedRelation.isArray = prop.export === "array"
if (!nestedRelation.nestedRelations.length) {
return
}
const childModel = getModelByName(prop.type, allModels)
if (!childModel) {
throw new Error(`x-expanded-relations - field referencing unknown model
Schema: ${rootModel.name}
NestedRelation: ${JSON.stringify(nestedRelation, null, 2)}
Model: ${JSON.stringify(model.spec, null, 2)}`)
}
rootModel.imports.push(prop.type)
if (parentNestedRelation) {
parentNestedRelation.hasDepth = true
}
for (const childNestedRelation of nestedRelation.nestedRelations) { for (const childNestedRelation of nestedRelation.nestedRelations) {
const childModel = getModelByName(prop.type, allModels)
if (!childModel) {
return
}
rootModel.imports.push(prop.type)
if (parentNestedRelation) {
parentNestedRelation.hasDepth = true
}
walkNestedRelations( walkNestedRelations(
allModels, allModels,
rootModel, rootModel,
@@ -92,7 +111,7 @@ const walkNestedRelations = (
} }
} }
const findPropInAllOf = ( const findPropInCombination = (
fieldName: string, fieldName: string,
model: Model, model: Model,
allModels: Model[] allModels: Model[]
@@ -91,4 +91,11 @@ export type SetNonNullable<BaseType, Keys extends keyof BaseType = keyof BaseTyp
export type Merge<Destination, Source> = EnforceOptional< export type Merge<Destination, Source> = EnforceOptional<
SimpleMerge<PickIndexSignature<Destination>, PickIndexSignature<Source>> SimpleMerge<PickIndexSignature<Destination>, PickIndexSignature<Source>>
& SimpleMerge<OmitIndexSignature<Destination>, OmitIndexSignature<Source>> & SimpleMerge<OmitIndexSignature<Destination>, OmitIndexSignature<Source>>
>; >;
/**
* SetRelation
* Alias combining SetRequire and SetNonNullable.
*/
export type SetRelation<BaseType, Keys extends keyof BaseType> =
SetRequired<SetNonNullable<BaseType, Keys>, Keys>;
@@ -1,6 +1,6 @@
{{>header}} {{>header}}
import { SetRequired, Merge } from '../core/ModelUtils'; import { SetRelation, Merge } from '../core/ModelUtils';
{{#if imports}} {{#if imports}}
{{#each imports}} {{#each imports}}
@@ -1,6 +1,6 @@
{{~#if isArray}}Array<{{/if~}} {{~#if isArray}}Array<{{/if~}}
{{~#if hasDepth}}Merge<{{/if~}} {{~#if hasDepth}}Merge<{{/if~}}
SetRequired<{{>base}}, {{#each nestedRelations}}'{{{field}}}'{{#unless @last}} | {{/unless}}{{/each}}>{{#if hasDepth}}, { SetRelation<{{>base}}, {{#each nestedRelations}}'{{{field}}}'{{#unless @last}} | {{/unless}}{{/each}}>{{#if hasDepth}}, {
{{/if}} {{/if}}
{{~#each nestedRelations~}} {{~#each nestedRelations~}}
{{#if nestedRelations~}} {{#if nestedRelations~}}