chore(orchestrator): remote joiner using entitymap (#9205)

This commit is contained in:
Carlos R. L. Rodrigues
2024-09-20 05:30:08 -03:00
committed by GitHub
parent 2cb9322ef5
commit 1215a7c094
6 changed files with 361 additions and 140 deletions
@@ -170,7 +170,7 @@ medusaIntegrationTestRunner({
} }
) )
).rejects.toThrow( ).rejects.toThrow(
"Payment id not found: pp_system_default_non_existent" "PaymentProvider id not found: pp_system_default_non_existent"
) )
// everything is fine // everything is fine
@@ -72,7 +72,10 @@ export class RemoteQuery {
this.remoteJoiner = new RemoteJoiner( this.remoteJoiner = new RemoteJoiner(
servicesConfig_ as JoinerServiceConfig[], servicesConfig_ as JoinerServiceConfig[],
this.remoteFetchData.bind(this), this.remoteFetchData.bind(this),
{ autoCreateServiceNameAlias: false } {
autoCreateServiceNameAlias: false,
entitiesMap,
}
) )
} }
@@ -9,7 +9,13 @@ import {
} from "@medusajs/types" } from "@medusajs/types"
import { RemoteJoinerOptions } from "@medusajs/types" import { RemoteJoinerOptions } from "@medusajs/types"
import { MedusaError, deduplicate, isDefined, isString } from "@medusajs/utils" import {
MedusaError,
deduplicate,
extractRelationsFromGQL,
isDefined,
isString,
} from "@medusajs/utils"
import GraphQLParser from "./graphql-ast" import GraphQLParser from "./graphql-ast"
const BASE_PATH = "_root" const BASE_PATH = "_root"
@@ -35,6 +41,8 @@ export class RemoteJoiner {
private serviceConfigCache: Map<string, InternalJoinerServiceConfig> = private serviceConfigCache: Map<string, InternalJoinerServiceConfig> =
new Map() new Map()
private entityMap: Map<string, Map<string, string>> = new Map()
private static filterFields( private static filterFields(
data: any, data: any,
fields?: string[], fields?: string[],
@@ -142,12 +150,21 @@ export class RemoteJoiner {
private remoteFetchData: RemoteFetchDataCallback, private remoteFetchData: RemoteFetchDataCallback,
private options: { private options: {
autoCreateServiceNameAlias?: boolean autoCreateServiceNameAlias?: boolean
entitiesMap?: Map<string, any>
} = {} } = {}
) { ) {
this.options.autoCreateServiceNameAlias ??= true this.options.autoCreateServiceNameAlias ??= true
if (this.options.entitiesMap) {
this.entityMap = extractRelationsFromGQL(this.options.entitiesMap)
}
this.serviceConfigs = this.buildReferences( this.serviceConfigs = this.buildReferences(
JSON.parse(JSON.stringify(serviceConfigs)) JSON.parse(JSON.stringify(serviceConfigs), (key, value) => {
if (key === "schema") {
return
}
return value
})
) )
} }
@@ -158,12 +175,15 @@ export class RemoteJoiner {
private buildReferences(serviceConfigs: ModuleJoinerConfig[]) { private buildReferences(serviceConfigs: ModuleJoinerConfig[]) {
const expandedRelationships: Map< const expandedRelationships: Map<
string, string,
{ fieldAlias; relationships: Map<string, JoinerRelationship> } {
fieldAlias
relationships: Map<string, JoinerRelationship | JoinerRelationship[]>
}
> = new Map() > = new Map()
for (const service of serviceConfigs) { for (const service of serviceConfigs) {
const service_ = service as Omit<ModuleJoinerConfig, "relationships"> & { const service_ = service as Omit<ModuleJoinerConfig, "relationships"> & {
relationships?: Map<string, JoinerRelationship> relationships?: Map<string, JoinerRelationship | JoinerRelationship[]>
} }
if (this.serviceConfigCache.has(service_.serviceName!)) { if (this.serviceConfigCache.has(service_.serviceName!)) {
@@ -233,18 +253,33 @@ export class RemoteJoiner {
? { ...service_.args, ...alias.args } ? { ...service_.args, ...alias.args }
: undefined : undefined
service_.relationships?.set(alias.name as string, { const aliasName = alias.name as string
alias: alias.name as string, const rel = {
alias: aliasName,
entity: alias.entity, entity: alias.entity,
foreignKey: alias.name + "_id", foreignKey: alias.name + "_id",
primaryKey: "id", primaryKey: "id",
serviceName: service_.serviceName!, serviceName: service_.serviceName!,
args, args,
}) }
this.cacheServiceConfig(serviceConfigs, undefined, alias)
if (service_.relationships?.has(aliasName)) {
const existing = service_.relationships.get(aliasName)!
const newRelation = Array.isArray(existing)
? existing.concat(rel)
: [existing, rel]
service_.relationships?.set(aliasName, newRelation)
} else {
service_.relationships?.set(aliasName, rel)
}
this.cacheServiceConfig(serviceConfigs, { serviceAlias: alias })
} }
this.cacheServiceConfig(serviceConfigs, service_.serviceName) this.cacheServiceConfig(serviceConfigs, {
serviceName: service_.serviceName,
})
} }
for (const extend of service_.extends) { for (const extend of service_.extends) {
@@ -256,10 +291,20 @@ export class RemoteJoiner {
} }
const service_ = expandedRelationships.get(extend.serviceName)! const service_ = expandedRelationships.get(extend.serviceName)!
service_.relationships.set(
extend.relationship.alias, const aliasName = extend.relationship.alias
extend.relationship const rel = extend.relationship
) if (service_.relationships?.has(aliasName)) {
const existing = service_.relationships.get(aliasName)!
const newRelation = Array.isArray(existing)
? existing.concat(rel)
: [existing, rel]
service_.relationships?.set(aliasName, newRelation)
} else {
service_.relationships?.set(aliasName, rel)
}
Object.assign(service_.fieldAlias ?? {}, extend.fieldAlias) Object.assign(service_.fieldAlias ?? {}, extend.fieldAlias)
} }
} }
@@ -274,8 +319,19 @@ export class RemoteJoiner {
const service_ = this.serviceConfigCache.get(serviceName)! const service_ = this.serviceConfigCache.get(serviceName)!
relationships.forEach((relationship, alias) => { relationships.forEach((relationship, alias) => {
service_.relationships!.set(alias, relationship) const rel = relationship as JoinerRelationship
if (service_.relationships?.has(alias)) {
const existing = service_.relationships.get(alias)!
const newRelation = Array.isArray(existing)
? existing.concat(rel)
: [existing, rel]
service_.relationships?.set(alias, newRelation)
} else {
service_.relationships?.set(alias, rel)
}
}) })
Object.assign(service_.fieldAlias!, fieldAlias ?? {}) Object.assign(service_.fieldAlias!, fieldAlias ?? {})
if (Object.keys(service_.fieldAlias!).length) { if (Object.keys(service_.fieldAlias!).length) {
@@ -296,10 +352,23 @@ export class RemoteJoiner {
return serviceConfigs return serviceConfigs
} }
private getServiceConfig( private getServiceConfig({
serviceName?: string, serviceName,
serviceAlias,
entity,
}: {
serviceName?: string
serviceAlias?: string serviceAlias?: string
): InternalJoinerServiceConfig | undefined { entity?: string
}): InternalJoinerServiceConfig | undefined {
if (entity) {
const name = `entity_${entity}`
const serviceConfig = this.serviceConfigCache.get(name)
if (serviceConfig) {
return serviceConfig
}
}
if (serviceAlias) { if (serviceAlias) {
const name = `alias_${serviceAlias}` const name = `alias_${serviceAlias}`
return this.serviceConfigCache.get(name) return this.serviceConfigCache.get(name)
@@ -309,10 +378,14 @@ export class RemoteJoiner {
} }
private cacheServiceConfig( private cacheServiceConfig(
serviceConfigs, serviceConfigs: ModuleJoinerConfig[],
serviceName?: string, params: {
serviceAlias?: JoinerServiceConfigAlias serviceName?: string
serviceAlias?: JoinerServiceConfigAlias
}
): void { ): void {
const { serviceName, serviceAlias } = params
if (serviceAlias) { if (serviceAlias) {
const name = `alias_${serviceAlias.name}` const name = `alias_${serviceAlias.name}`
if (!this.serviceConfigCache.has(name)) { if (!this.serviceConfigCache.has(name)) {
@@ -331,7 +404,19 @@ export class RemoteJoiner {
if (aliasConfig) { if (aliasConfig) {
serviceConfig.args = { ...config?.args, ...aliasConfig?.args } serviceConfig.args = { ...config?.args, ...aliasConfig?.args }
} }
this.serviceConfigCache.set(name, serviceConfig) this.serviceConfigCache.set(
name,
serviceConfig as InternalJoinerServiceConfig
)
const entity = serviceAlias.entity
if (entity) {
const name = `entity_${entity}`
this.serviceConfigCache.set(
name,
serviceConfig as InternalJoinerServiceConfig
)
}
} }
} }
return return
@@ -339,20 +424,22 @@ export class RemoteJoiner {
const config = serviceConfigs.find( const config = serviceConfigs.find(
(config) => config.serviceName === serviceName (config) => config.serviceName === serviceName
) ) as InternalJoinerServiceConfig
this.serviceConfigCache.set(serviceName!, config) this.serviceConfigCache.set(serviceName!, config)
} }
private async fetchData( private async fetchData(params: {
expand: RemoteExpandProperty, expand: RemoteExpandProperty
pkField: string, pkField: string
ids?: (unknown | unknown[])[], ids?: (unknown | unknown[])[]
relationship?: any, relationship?: any
options?: RemoteJoinerOptions options?: RemoteJoinerOptions
): Promise<{ }): Promise<{
data: unknown[] | { [path: string]: unknown } data: unknown[] | { [path: string]: unknown }
path?: string path?: string
}> { }> {
const { expand, pkField, ids, relationship, options } = params
let uniqueIds = Array.isArray(ids) ? ids : ids ? [ids] : undefined let uniqueIds = Array.isArray(ids) ? ids : ids ? [ids] : undefined
if (uniqueIds) { if (uniqueIds) {
@@ -372,15 +459,16 @@ export class RemoteJoiner {
uniqueIds = uniqueIds.filter((id) => isDefined(id)) uniqueIds = uniqueIds.filter((id) => isDefined(id))
} }
let pkFieldAdjusted = pkField
if (relationship) { if (relationship) {
pkField = relationship.inverse pkFieldAdjusted = relationship.inverse
? relationship.foreignKey.split(".").pop()! ? relationship.foreignKey.split(".").pop()!
: relationship.primaryKey : relationship.primaryKey
} }
const response = await this.remoteFetchData( const response = await this.remoteFetchData(
expand, expand,
pkField, pkFieldAdjusted,
uniqueIds, uniqueIds,
relationship relationship
) )
@@ -394,14 +482,14 @@ export class RemoteJoiner {
: [resData] : [resData]
: [] : []
this.checkIfKeysExist( this.checkIfKeysExist({
uniqueIds, uniqueIds,
resData, resData,
expand, expand,
pkField, pkField: pkFieldAdjusted,
relationship, relationship,
options options,
) })
const filteredDataArray = resData.map((data: any) => const filteredDataArray = resData.map((data: any) =>
RemoteJoiner.filterFields(data, expand.fields, expand.expands) RemoteJoiner.filterFields(data, expand.fields, expand.expands)
@@ -416,14 +504,17 @@ export class RemoteJoiner {
return response return response
} }
private checkIfKeysExist( private checkIfKeysExist(params: {
uniqueIds: unknown[] | undefined, uniqueIds: unknown[] | undefined
resData: any[], resData: any[]
expand: RemoteExpandProperty, expand: RemoteExpandProperty
pkField: string, pkField: string
relationship?: any, relationship?: any
options?: RemoteJoinerOptions options?: RemoteJoinerOptions
) { }) {
const { uniqueIds, resData, expand, pkField, relationship, options } =
params
if ( if (
!( !(
isDefined(uniqueIds) && isDefined(uniqueIds) &&
@@ -461,11 +552,13 @@ export class RemoteJoiner {
} }
} }
private handleFieldAliases( private handleFieldAliases(params: {
items: any[], items: any[]
parsedExpands: Map<string, RemoteExpandProperty>, parsedExpands: Map<string, RemoteExpandProperty>
implodeMapping: InternalImplodeMapping[] implodeMapping: InternalImplodeMapping[]
) { }) {
const { items, parsedExpands, implodeMapping } = params
const getChildren = (item: any, prop: string) => { const getChildren = (item: any, prop: string) => {
if (Array.isArray(item)) { if (Array.isArray(item)) {
return item.flatMap((currentItem) => currentItem[prop]) return item.flatMap((currentItem) => currentItem[prop])
@@ -541,12 +634,14 @@ export class RemoteJoiner {
} }
} }
private async handleExpands( private async handleExpands(params: {
items: any[], items: any[]
parsedExpands: Map<string, RemoteExpandProperty>, parsedExpands: Map<string, RemoteExpandProperty>
implodeMapping: InternalImplodeMapping[] = [], implodeMapping?: InternalImplodeMapping[]
options?: RemoteJoinerOptions options?: RemoteJoinerOptions
): Promise<void> { }): Promise<void> {
const { items, parsedExpands, implodeMapping = [], options } = params
if (!parsedExpands) { if (!parsedExpands) {
return return
} }
@@ -567,48 +662,87 @@ export class RemoteJoiner {
} }
if (nestedItems.length > 0) { if (nestedItems.length > 0) {
await this.expandProperty( await this.expandProperty({
nestedItems, items: nestedItems,
expand.parentConfig!, parentServiceConfig: expand.parentConfig!,
expand, expand,
options options,
) })
} }
} }
this.handleFieldAliases(items, parsedExpands, implodeMapping) this.handleFieldAliases({ items, parsedExpands, implodeMapping })
} }
private async expandProperty( private getEntityRelationship(params: {
items: any[], parentServiceConfig: InternalJoinerServiceConfig
parentServiceConfig: InternalJoinerServiceConfig, property: string
expand?: RemoteExpandProperty, entity?: string
}): JoinerRelationship {
const { parentServiceConfig, property, entity } = params
const propEntity = entity ?? parentServiceConfig?.entity
const rel = parentServiceConfig?.relationships?.get(property)
if (Array.isArray(rel)) {
if (!propEntity) {
return rel[0]
}
const entityRel = rel.find((r) => r.entity === propEntity)
if (entityRel) {
return entityRel
}
// If entity is not found, return the relationship where the primary key matches
const serviceEntity = this.getServiceConfig({
entity: propEntity,
})!
return rel.find((r) => serviceEntity.primaryKeys.includes(r.primaryKey))!
}
return rel as JoinerRelationship
}
private async expandProperty(params: {
items: any[]
parentServiceConfig: InternalJoinerServiceConfig
expand?: RemoteExpandProperty
options?: RemoteJoinerOptions options?: RemoteJoinerOptions
): Promise<void> { }): Promise<void> {
const { items, parentServiceConfig, expand, options } = params
if (!expand) { if (!expand) {
return return
} }
const relationship = parentServiceConfig?.relationships?.get( const relationship = this.getEntityRelationship({
expand.property parentServiceConfig,
) property: expand.property,
entity: expand.entity,
})
if (relationship) { if (!relationship) {
await this.expandRelationshipProperty( return
items,
expand,
relationship,
options
)
} }
await this.expandRelationshipProperty({
items,
expand,
relationship,
options,
})
} }
private async expandRelationshipProperty( private async expandRelationshipProperty(params: {
items: any[], items: any[]
expand: RemoteExpandProperty, expand: RemoteExpandProperty
relationship: JoinerRelationship, relationship: JoinerRelationship
options?: RemoteJoinerOptions options?: RemoteJoinerOptions
): Promise<void> { }): Promise<void> {
const { items, expand, relationship, options } = params
const field = relationship.inverse const field = relationship.inverse
? relationship.primaryKey ? relationship.primaryKey
: relationship.foreignKey.split(".").pop()! : relationship.foreignKey.split(".").pop()!
@@ -639,13 +773,13 @@ export class RemoteJoiner {
return return
} }
const relatedDataArray = await this.fetchData( const relatedDataArray = await this.fetchData({
expand, expand,
field, pkField: field,
idsToFetch, ids: idsToFetch,
relationship, relationship,
options options,
) })
const joinFields = relationship.inverse const joinFields = relationship.inverse
? relationship.foreignKey.split(",") ? relationship.foreignKey.split(",")
@@ -689,36 +823,46 @@ export class RemoteJoiner {
}) })
} }
private parseExpands( private parseExpands(params: {
initialService: RemoteExpandProperty, initialService: RemoteExpandProperty
query: RemoteJoinerQuery, query: RemoteJoinerQuery
serviceConfig: InternalJoinerServiceConfig, serviceConfig: InternalJoinerServiceConfig
expands: RemoteJoinerQuery["expands"], expands: RemoteJoinerQuery["expands"]
implodeMapping: InternalImplodeMapping[], implodeMapping: InternalImplodeMapping[]
options?: RemoteJoinerOptions options?: RemoteJoinerOptions
): Map<string, RemoteExpandProperty> { }): Map<string, RemoteExpandProperty> {
const parsedExpands = this.parseProperties( const {
initialService, initialService,
query, query,
serviceConfig, serviceConfig,
expands, expands,
implodeMapping, implodeMapping,
options options,
) } = params
const parsedExpands = this.parseProperties({
initialService,
query,
serviceConfig,
expands,
implodeMapping,
})
const groupedExpands = this.groupExpands(parsedExpands) const groupedExpands = this.groupExpands(parsedExpands)
return groupedExpands return groupedExpands
} }
private parseProperties( private parseProperties(params: {
initialService: RemoteExpandProperty, initialService: RemoteExpandProperty
query: RemoteJoinerQuery, query: RemoteJoinerQuery
serviceConfig: InternalJoinerServiceConfig, serviceConfig: InternalJoinerServiceConfig
expands: RemoteJoinerQuery["expands"], expands: RemoteJoinerQuery["expands"]
implodeMapping: InternalImplodeMapping[], implodeMapping: InternalImplodeMapping[]
options?: RemoteJoinerOptions }): Map<string, RemoteExpandProperty> {
): Map<string, RemoteExpandProperty> { const { initialService, query, serviceConfig, expands, implodeMapping } =
params
const aliasRealPathMap = new Map<string, string[]>() const aliasRealPathMap = new Map<string, string[]>()
const parsedExpands = new Map<string, any>() const parsedExpands = new Map<string, any>()
parsedExpands.set(BASE_PATH, initialService) parsedExpands.set(BASE_PATH, initialService)
@@ -760,7 +904,19 @@ export class RemoteJoiner {
const fullPath = [BASE_PATH, ...currentPath, prop].join(".") const fullPath = [BASE_PATH, ...currentPath, prop].join(".")
const fullAliasPath = [BASE_PATH, ...currentAliasPath, prop].join(".") const fullAliasPath = [BASE_PATH, ...currentAliasPath, prop].join(".")
const relationship = currentServiceConfig.relationships?.get(prop) let entity = currentServiceConfig.entity
if (entity) {
const completePath = fullPath.split(".")
for (let i = 1; i < completePath.length; i++) {
entity = this.getEntity({ entity, prop: completePath[i] }) ?? entity
}
}
const relationship = this.getEntityRelationship({
parentServiceConfig: currentServiceConfig,
property: prop,
entity,
})
const isCurrentProp = const isCurrentProp =
fullPath === BASE_PATH + "." + expand.property || fullPath === BASE_PATH + "." + expand.property ||
@@ -772,7 +928,6 @@ export class RemoteJoiner {
if (relationship) { if (relationship) {
const parentExpand = const parentExpand =
parsedExpands.get([BASE_PATH, ...currentPath].join(".")) || query parsedExpands.get([BASE_PATH, ...currentPath].join(".")) || query
if (parentExpand) { if (parentExpand) {
const parRelField = relationship.inverse const parRelField = relationship.inverse
? relationship.primaryKey ? relationship.primaryKey
@@ -792,9 +947,10 @@ export class RemoteJoiner {
fields = fields.concat(relField.split(",")) fields = fields.concat(relField.split(","))
} }
currentServiceConfig = this.getServiceConfig( currentServiceConfig = this.getServiceConfig({
relationship.serviceName serviceName: relationship.serviceName,
)! entity: relationship.entity,
})!
if (!currentServiceConfig) { if (!currentServiceConfig) {
throw new Error( throw new Error(
@@ -817,6 +973,7 @@ export class RemoteJoiner {
parsedExpands.set(fullPath, { parsedExpands.set(fullPath, {
property: prop, property: prop,
serviceConfig: currentServiceConfig, serviceConfig: currentServiceConfig,
entity: entity,
fields, fields,
args: isAliasMapping args: isAliasMapping
? forwardArgumentsOnPath.includes(fullPath) ? forwardArgumentsOnPath.includes(fullPath)
@@ -848,6 +1005,10 @@ export class RemoteJoiner {
return parsedExpands return parsedExpands
} }
private getEntity({ entity, prop }: { entity: string; prop: string }) {
return this.entityMap.get(entity)?.get(prop)
}
private parseAlias({ private parseAlias({
aliasPath, aliasPath,
aliasRealPathMap, aliasRealPathMap,
@@ -875,7 +1036,6 @@ export class RemoteJoiner {
return parsedExpands.get(fullPath).serviceConfig return parsedExpands.get(fullPath).serviceConfig
} }
// remove alias from fields
const parentPath = [BASE_PATH, ...currentPath].join(".") const parentPath = [BASE_PATH, ...currentPath].join(".")
const parentExpands = parsedExpands.get(parentPath) const parentExpands = parsedExpands.get(parentPath)
parentExpands.fields = parentExpands.fields?.filter( parentExpands.fields = parentExpands.fields?.filter(
@@ -926,10 +1086,31 @@ export class RemoteJoiner {
const partialPath: string[] = [] const partialPath: string[] = []
for (const partial of path.split(".")) { for (const partial of path.split(".")) {
const relationship = currentServiceConfig.relationships?.get(partial) const completePath = [
BASE_PATH,
...currentPath.concat(partialPath),
partial,
]
const parentPath = completePath.slice(0, -1).join(".")
let entity = serviceConfig.entity
if (entity) {
for (let i = 1; i < completePath.length; i++) {
entity = this.getEntity({ entity, prop: completePath[i] }) ?? entity
}
}
const relationship = this.getEntityRelationship({
parentServiceConfig: currentServiceConfig,
property: partial,
entity,
})
if (relationship) { if (relationship) {
currentServiceConfig = this.getServiceConfig(relationship.serviceName)! currentServiceConfig = this.getServiceConfig({
serviceName: relationship.serviceName,
entity: relationship.entity,
})!
if (!currentServiceConfig) { if (!currentServiceConfig) {
throw new Error( throw new Error(
@@ -938,17 +1119,11 @@ export class RemoteJoiner {
} }
} }
const completePath = [
BASE_PATH,
...currentPath.concat(partialPath),
partial,
]
const parentPath = completePath.slice(0, -1).join(".")
partialPath.push(partial) partialPath.push(partial)
parsedExpands.set(completePath.join("."), { parsedExpands.set(completePath.join("."), {
property: partial, property: partial,
serviceConfig: currentServiceConfig, serviceConfig: currentServiceConfig,
entity: entity,
parent: parentPath, parent: parentPath,
parentConfig: parsedExpands.get(parentPath).serviceConfig, parentConfig: parsedExpands.get(parentPath).serviceConfig,
}) })
@@ -980,7 +1155,6 @@ export class RemoteJoiner {
break break
} }
// Merge the current expand into its parent
const nestedKeys = path.split(".").slice(parentPath.split(".").length) const nestedKeys = path.split(".").slice(parentPath.split(".").length)
let targetExpand = parentExpand as Omit< let targetExpand = parentExpand as Omit<
RemoteExpandProperty, RemoteExpandProperty,
@@ -1009,10 +1183,10 @@ export class RemoteJoiner {
queryObj: RemoteJoinerQuery, queryObj: RemoteJoinerQuery,
options?: RemoteJoinerOptions options?: RemoteJoinerOptions
): Promise<any> { ): Promise<any> {
const serviceConfig = this.getServiceConfig( const serviceConfig = this.getServiceConfig({
queryObj.service, serviceName: queryObj.service,
queryObj.alias serviceAlias: queryObj.alias,
) })
if (!serviceConfig) { if (!serviceConfig) {
if (queryObj.alias) { if (queryObj.alias) {
@@ -1035,38 +1209,39 @@ export class RemoteJoiner {
) )
const implodeMapping: InternalImplodeMapping[] = [] const implodeMapping: InternalImplodeMapping[] = []
const parsedExpands = this.parseExpands( const parsedExpands = this.parseExpands({
{ initialService: {
property: "", property: "",
parent: "", parent: "",
serviceConfig: serviceConfig, serviceConfig,
entity: serviceConfig.entity,
fields: queryObj.fields, fields: queryObj.fields,
args: otherArgs, args: otherArgs,
}, },
queryObj, query: queryObj,
serviceConfig, serviceConfig,
queryObj.expands!, expands: queryObj.expands!,
implodeMapping implodeMapping,
) options,
})
const root = parsedExpands.get(BASE_PATH)! const root = parsedExpands.get(BASE_PATH)!
const response = await this.fetchData( const response = await this.fetchData({
root, expand: root,
pkName, pkField: pkName,
primaryKeyArg?.value, ids: primaryKeyArg?.value,
undefined, options,
options })
)
const data = response.path ? response.data[response.path!] : response.data const data = response.path ? response.data[response.path!] : response.data
await this.handleExpands( await this.handleExpands({
Array.isArray(data) ? data : [data], items: Array.isArray(data) ? data : [data],
parsedExpands, parsedExpands,
implodeMapping, implodeMapping,
options options,
) })
return response.data return response.data
} }
+2 -1
View File
@@ -97,7 +97,7 @@ export type InternalJoinerServiceConfig = Omit<
JoinerServiceConfig, JoinerServiceConfig,
"relationships" "relationships"
> & { > & {
relationships?: Map<string, JoinerRelationship> relationships?: Map<string, JoinerRelationship | JoinerRelationship[]>
entity?: string entity?: string
} }
@@ -106,6 +106,7 @@ export interface RemoteExpandProperty {
parent: string parent: string
parentConfig?: InternalJoinerServiceConfig parentConfig?: InternalJoinerServiceConfig
serviceConfig: InternalJoinerServiceConfig serviceConfig: InternalJoinerServiceConfig
entity?: string
fields?: string[] fields?: string[]
args?: JoinerArgument[] args?: JoinerArgument[]
expands?: RemoteNestedExpands expands?: RemoteNestedExpands
@@ -0,0 +1,41 @@
import { isListType, isNonNullType, isObjectType } from "graphql"
/**
* Extracts only the relation fields from the GraphQL type map.
* @param {Map<string, any>} typeMap - The GraphQL schema TypeMap.
* @returns {Map<string, Map<string, string>>} A map where each key is an entity name, and the values are a map of relation fields and their corresponding entity type.
*/
export function extractRelationsFromGQL(
typeMap: Map<string, any>
): Map<string, Map<string, string>> {
const relationMap = new Map()
// Extract the actual type
const getBaseType = (type) => {
if (isNonNullType(type) || isListType(type)) {
return getBaseType(type.ofType)
}
return type
}
for (const [typeName, graphqlType] of Object.entries(typeMap)) {
if (!isObjectType(graphqlType)) {
continue
}
const fields = graphqlType.getFields()
const entityRelations = new Map()
for (const [fieldName, fieldConfig] of Object.entries(fields)) {
const fieldType = getBaseType((fieldConfig as any).type)
// only add relation fields
if (isObjectType(fieldType)) {
entityRelations.set(fieldName, fieldType.name)
}
}
relationMap.set(typeName, entityRelations)
}
return relationMap
}
+1
View File
@@ -26,6 +26,7 @@ export * from "./get-node-version"
export * from "./get-selects-and-relations-from-object-array" export * from "./get-selects-and-relations-from-object-array"
export * from "./get-set-difference" export * from "./get-set-difference"
export * from "./graceful-shutdown-server" export * from "./graceful-shutdown-server"
export * from "./graphql-relations-entity-map"
export * from "./group-by" export * from "./group-by"
export * from "./handle-postgres-database-error" export * from "./handle-postgres-database-error"
export * from "./is-big-number" export * from "./is-big-number"