Skip to content

Instantly share code, notes, and snippets.

@dimensi
Created November 29, 2018 11:14
Show Gist options
  • Select an option

  • Save dimensi/e259e2aad8c50c5690ebb6a7a605fb07 to your computer and use it in GitHub Desktop.

Select an option

Save dimensi/e259e2aad8c50c5690ebb6a7a605fb07 to your computer and use it in GitHub Desktop.
get relations by graphql schema and typeorm
import graphqlFields, { ObjectFields } from 'graphql-fields'
import { GraphQLResolveInfo } from 'graphql'
import { Repository, getRepository, EntityMetadata } from 'typeorm'
import { get, set } from 'lodash'
interface Property {
propertyName: string
propertyPath: string
}
const flattenObject = (obj: ObjectFields, prefix = '', arr: Property[] = []) =>
Object.keys(obj).reduce((acc, k) => {
acc.push({
propertyName: k,
propertyPath: prefix.length ? `${prefix}.${k}` : k,
})
if (Object.keys(obj[k]).length) {
const childAcc = flattenObject(obj[k], k, [])
acc.push(...childAcc)
}
return acc
}, arr)
export const getRelationsForQuery = <T>(
info: GraphQLResolveInfo,
repo: Repository<T>,
): string[] => {
const properties = flattenObject(graphqlFields(info, {}, { excludedFields: ['__typename'] }))
const findRelations = (metadata: EntityMetadata, properties: Property[], relationsArr: string[]) => {
return metadata.relations.reduce((acc, relation) => {
const findedProp = properties.find(el => el.propertyName === relation.propertyName)
if (findedProp && findedProp.propertyPath === relation.propertyPath) {
acc.push(findedProp.propertyPath)
const relationMetadata = getRepository(relation.type).metadata
const newProps: Property[] = properties.reduce((acc, prop) => {
if (prop.propertyPath === relation.propertyName) return acc
if (prop.propertyPath.includes(relation.propertyName)) {
const newPath = prop.propertyPath.replace(relation.propertyName, '').replace(/^\./, '')
if (newPath) {
acc.push({
propertyName: prop.propertyName,
propertyPath: newPath,
})
}
}
return acc
}, [])
if (newProps.length) {
const childRelations = findRelations(relationMetadata, newProps, []).map(str => `${relation.propertyName}.${str}`)
acc.push(...childRelations)
}
}
return acc
}, relationsArr)
}
return findRelations(repo.metadata, properties, [])
}
export const setRelationsForMutation = async <T>(
repo: Repository<T>,
data: { [key: string]: any },
): Promise<{ [key: string]: any, findedProperties: string[] }> => {
const relations = repo.metadata.relations.map(({ propertyName, propertyPath, type }) => ({
propertyName,
propertyPath,
type,
}))
const findedProperties = []
for (let item of relations) {
const prop = get(data, item.propertyPath)
if (!prop) continue
if (Array.isArray(prop)) {
set(data, item.propertyPath, await getRepository(item.type).findByIds(prop))
} else {
set(data, item.propertyPath, await getRepository(item.type).findOne(prop))
}
findedProperties.push(item.propertyName)
}
return {
data,
findedProperties,
}
}
export const addToArgsRelations = (arrRelations: string[], where?: any): { [key: string]: string | number } => {
if (!arrRelations.length && !where) {
return undefined
}
const result = {}
if (where) {
Object.assign(result, where)
}
if (arrRelations.length) {
Object.assign(result, { relations: arrRelations })
}
return result
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment