graphql-composer-typeorm
Version:
TypeORM plugin for graphql-composer-decorators
207 lines • 9.28 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.Parser = void 0;
const graphql_composer_1 = require("graphql-composer");
const graphql_composer_decorators_1 = require("graphql-composer-decorators");
const typeorm_1 = require("typeorm");
class Parser {
constructor(classType, args) {
this._classType = classType;
this._args = args;
}
get classType() {
return this._classType;
}
get computedArgs() {
if (!this._computedArgs) {
this._computedArgs = this._args();
}
return this._computedArgs;
}
getRelationPath(item) {
const name = `${this._classType.name}.${item}`;
const nameArgs = name.split(/\./g);
const prop = nameArgs[nameArgs.length - 1];
nameArgs.splice(nameArgs.length - 1, 1);
return `${nameArgs.join("_")}.${prop}`;
}
async buildQuery(ctx) {
const args = ctx.rawArgs;
const where = args.where;
const relations = await this.getRelations(ctx);
const query = typeorm_1.createQueryBuilder(this._classType, this._classType.name);
if (args.orders !== undefined) {
args.orders.map((item) => {
query.addOrderBy(this.getRelationPath(item.field), item.order);
});
}
if (args.limit !== undefined && args.skip !== undefined) {
query.limit(args.limit);
query.offset(args.skip);
}
relations.map((item) => {
const relationName = this.getRelationPath(item);
query.leftJoinAndSelect(relationName, relationName.replace(/\./g, "_"));
});
if (args.where !== undefined) {
const parseWhere = (object, inputType, parent) => {
Object.keys(object).map((key) => {
const value = object[key];
if (inputType instanceof graphql_composer_1.InputType) {
const field = inputType.fields.find((f) => f.name === key);
const type = Parser.unwrapModifiedType(field.type);
const propName = `${parent}.${key}`;
if (type instanceof graphql_composer_1.InputType) {
switch (type.name) {
case "StringArgument":
const strArg = value;
if (strArg.eq !== undefined) {
query.andWhere(`${propName} = :${key}`, {
[key]: strArg.eq,
});
}
else if (strArg.like !== undefined) {
query.andWhere(`${propName} LIKE :${key}`, {
[key]: strArg.like,
});
}
return;
case "NumberArgument":
const nbArg = value;
if (nbArg.eq !== undefined) {
query.andWhere(`${propName} = :${key}`, {
[key]: nbArg.eq,
});
}
else if (nbArg.gt !== undefined) {
query.andWhere(`${propName} > :${key}`, {
[key]: nbArg.gt,
});
}
else if (nbArg.gte !== undefined) {
query.andWhere(`${propName} >= :${key}`, {
[key]: nbArg.gte,
});
}
else if (nbArg.lt !== undefined) {
query.andWhere(`${propName} < :${key}`, {
[key]: nbArg.lt,
});
}
else if (nbArg.lte !== undefined) {
query.andWhere(`${propName} <= :${key}`, {
[key]: nbArg.lte,
});
}
return;
}
}
else {
query.andWhere(`${propName} = :${key}`, {
[key]: value,
});
}
parseWhere(value, type, `${parent}_${key}`);
}
});
};
parseWhere(where, this._computedArgs.fields.find((f) => f.name === "where")
.type.type, this._classType.name);
}
return query;
}
async getRelations(ctx) {
const selections = ctx.infos.fieldNodes[0].selectionSet.selections;
const relationsWhere = await this.parseWhereToRelations(ctx.rawArgs.where);
const relationsSelection = await this.parseSelectionsToRelations(this._classType, selections);
let relations = [...relationsWhere, ...relationsSelection];
relations = relations.filter((item, index) => relations.indexOf(item) === index);
return relations;
}
async parseWhereToRelations(where) {
const relations = [];
const ormMetadatas = typeorm_1.getMetadataArgsStorage();
const args = this.computedArgs.fields.find((f) => f.name === "where")
.type.type;
if (where === undefined) {
return relations;
}
const parse = async (obj, args, parent) => {
if (!obj) {
return;
}
Object.keys(obj).map((key) => {
if (typeof obj[key] === "object" && obj[key]) {
const relation = ormMetadatas.relations.find((relation) => {
return relation.propertyName === key;
});
if (relation) {
const table = ormMetadatas.tables.find((t) => {
return t.target === relation.type();
});
if (table) {
const prefix = parent ? `${parent}.` : "";
const relationName = prefix + relation.propertyName;
relations.push(relationName);
const field = args.fields.find((f) => f.name === key);
if (field) {
const t = Parser.unwrapModifiedType(field.type);
parse(obj[key], t, relationName);
}
}
}
}
});
};
await parse(where, args);
return relations;
}
async parseSelectionsToRelations(classType, selections) {
const relations = [];
const ormMetadatas = typeorm_1.getMetadataArgsStorage();
const objectType = graphql_composer_decorators_1.MetadataStorage.instance.classTypeMap.get(classType)
.object;
if (!objectType) {
throw new Error(`You should decorate the class ${classType.name} with @ObjectType`);
}
const parse = async (selections, parent) => {
selections.map((selection) => {
if (!selection.selectionSet) {
return;
}
const relationInfos = ormMetadatas.relations.find((item) => {
return item.propertyName === selection.name.value;
});
if (relationInfos) {
const relationType = relationInfos.type();
const relation = ormMetadatas.tables.find((item) => {
return item.target === relationType;
});
if (relation) {
const prefix = parent ? `${parent}.` : "";
const relationName = prefix + relationInfos.propertyName;
relations.push(relationName);
parse(selection.selectionSet.selections, relationName);
}
}
});
};
await parse(selections);
return relations;
}
static unwrapModifiedType(fieldType) {
let type = fieldType;
if (type instanceof graphql_composer_1.NullableType) {
type = type.type;
}
if (type instanceof graphql_composer_1.RequiredType) {
type = type.type;
}
if (Array.isArray(type)) {
type = type[0];
}
return type;
}
}
exports.Parser = Parser;
//# sourceMappingURL=Parser.js.map