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 07:29:21 -04:00
committed by GitHub
parent 6748877c69
commit 826d4bedfe
7 changed files with 59 additions and 20 deletions

View File

@@ -0,0 +1,6 @@
---
"@medusajs/openapi-typescript-codegen": minor
"@medusajs/client-types": minor
---
feat(codegen,types): SetRelation on expanded types

View File

@@ -1 +1,7 @@
export * from "./lib"
export {
Merge,
SetNonNullable,
SetRelation,
SetRequired,
} from "./lib/core/ModelUtils"

View File

@@ -4,5 +4,6 @@ export interface WithExtendedRelationsExtension {
relations?: string[]
totals?: string[]
implicit?: string[]
eager?: string[]
}
}

View File

@@ -9,13 +9,14 @@ export const handleExpandedRelations = (model: Model, allModels: Model[]) => {
const relations = xExpandedRelation.relations ?? []
const totals = xExpandedRelation.totals ?? []
const implicit = xExpandedRelation.implicit ?? []
const eager = xExpandedRelation.eager ?? []
const nestedRelation: NestedRelation = {
field,
nestedRelations: [],
}
for (const relation of [...relations, ...totals, ...implicit]) {
for (const relation of [...relations, ...totals, ...implicit, ...eager]) {
const splitRelation = relation.split(".")
walkSplitRelations(nestedRelation, splitRelation, 0)
}
@@ -24,9 +25,13 @@ export const handleExpandedRelations = (model: Model, allModels: Model[]) => {
model.imports = [...new Set(model.imports)]
const prop = getPropertyByName(nestedRelation.field, model)
if (prop) {
prop.nestedRelations = [nestedRelation]
if (!prop) {
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 = (
@@ -59,12 +64,20 @@ const walkNestedRelations = (
nestedRelation: NestedRelation,
parentNestedRelation?: NestedRelation
) => {
const prop =
model.export === "all-of"
? findPropInAllOf(nestedRelation.field, model, allModels)
: getPropertyByName(nestedRelation.field, model)
const prop = ["all-of", "any-of", "one-of"].includes(model.export)
? findPropInCombination(nestedRelation.field, model, allModels)
: getPropertyByName(nestedRelation.field, model)
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)) {
return
@@ -73,15 +86,21 @@ const walkNestedRelations = (
nestedRelation.base = prop.type
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) {
const childModel = getModelByName(prop.type, allModels)
if (!childModel) {
return
}
rootModel.imports.push(prop.type)
if (parentNestedRelation) {
parentNestedRelation.hasDepth = true
}
walkNestedRelations(
allModels,
rootModel,
@@ -92,7 +111,7 @@ const walkNestedRelations = (
}
}
const findPropInAllOf = (
const findPropInCombination = (
fieldName: string,
model: Model,
allModels: Model[]

View File

@@ -91,4 +91,11 @@ export type SetNonNullable<BaseType, Keys extends keyof BaseType = keyof BaseTyp
export type Merge<Destination, Source> = EnforceOptional<
SimpleMerge<PickIndexSignature<Destination>, PickIndexSignature<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>;

View File

@@ -1,6 +1,6 @@
{{>header}}
import { SetRequired, Merge } from '../core/ModelUtils';
import { SetRelation, Merge } from '../core/ModelUtils';
{{#if imports}}
{{#each imports}}

View File

@@ -1,6 +1,6 @@
{{~#if isArray}}Array<{{/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}}
{{~#each nestedRelations~}}
{{#if nestedRelations~}}