@notadd/graphql
Version:
notadd core none dependence
415 lines (414 loc) • 16.9 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.isPromise = exports.isInlineFragmentNode = exports.isFragmentSpreadNode = exports.isFieldNode = exports.isArgumentNode = exports.isNullValueNode = exports.isBooleanValueNode = exports.isStringValueNode = exports.isFloatValueNode = exports.isIntValueNode = exports.isVariableNode = exports.isObjectValueNode = exports.isListValueNode = exports.isEnumValueNode = exports.Graphql = void 0;
const tslib_1 = require("tslib");
const core_1 = require("@notadd/core");
const token_1 = require("./token");
const graphql_1 = require("graphql");
const rxjs_1 = require("rxjs");
const operators_1 = require("rxjs/operators");
const graphql_2 = require("graphql");
const schemaBuilder_1 = require("./schemaBuilder");
let Graphql = class Graphql {
constructor(injector) {
this.injector = injector;
}
async query(source, variables, operationName = undefined, ...middlewars) {
const builder = this.injector.get(schemaBuilder_1.DefaultSchemaBuilder);
const schema = await builder.buildSchema();
if (schema) {
return graphql_1.graphql({
schema,
source,
rootValue: undefined,
contextValue: middlewars,
variableValues: variables,
operationName
});
}
}
async run(query, variables, operationName, ...middlewars) {
this.ast = graphql_2.parse(query);
const schema = await this.injector.get(token_1.GRAPHQL_SCHEMA);
const operationDefinition = graphql_1.getOperationAST(this.ast, operationName);
if (operationDefinition) {
const rootType = graphql_1.getOperationRootType(schema, operationDefinition);
const selectionSet = operationDefinition.selectionSet;
const method = rootType.name;
const source = await this.handlerSelectionSet(middlewars, rootType, selectionSet, variables, method);
return source;
}
}
getFragmentDefinition(name) {
return this.ast.definitions.find((it) => it.name.value === name);
}
handlerSelectionSet(middlewars, root, set, variables, method) {
middlewars.push(new core_1.Middleware('graphql', async (root) => {
const injector = await root;
return injector.create([{
provide: token_1.GRAPHQL_OBJECT_TYPE,
useValue: root
}, {
provide: token_1.GRAPHQL_SELECTION_SET,
useValue: set
}, {
provide: core_1.ARGS,
useValue: variables
}, {
provide: token_1.GRAPHQL_SELECTIONS,
useFactory: () => {
if (set) {
return set.selections.map(it => {
if (isFieldNode(it)) {
return it.name.value;
}
return;
}).filter(it => !!it);
}
return [];
}
}], 'graphql');
}));
if (set.selections && set.selections.length === 1) {
const selection = set.selections[0];
return this.handlerField(middlewars, selection, set, variables, method);
}
throw new graphql_1.GraphQLError(`subscription support only one top selection`);
}
async handlerField(middlewars, field, set, variables, method) {
if (isFieldNode(field)) {
let { alias, name, arguments: args, directives, selectionSet } = field;
alias = alias || name;
const router = this.injector.get(core_1.Router);
const [handler] = router.find(`/${name.value}`, method.toUpperCase());
if (handler) {
const graphqlMiddlware = new core_1.Middleware('selection', async (_root) => {
const injector = await _root;
return injector.create([{
provide: token_1.GRAPHQL_SELECTION_SET,
useValue: selectionSet
}, {
provide: token_1.GRAPHQL_SELECTION,
useValue: field
}, {
provide: token_1.GRAPHQL_SELECTIONS,
useFactory: () => {
if (selectionSet) {
return selectionSet.selections.map(it => {
if (isFieldNode(it)) {
return it.name.value;
}
return;
}).filter(it => !!it);
}
return [];
}
}], 'selection');
});
middlewars.push(graphqlMiddlware);
let res = await handler(middlewars);
if (res instanceof core_1.Injector) {
res = res.get(core_1.METHOD_RESULT);
}
if (selectionSet) {
return this.parseSelectionSetFirst(middlewars, res, alias, name, selectionSet, variables);
}
else {
if (isPromise(res)) {
return res.then(item => {
return { [alias.value]: item };
});
}
return { [alias.value]: res };
}
}
}
else if (isFragmentSpreadNode(field)) {
debugger;
}
else if (isInlineFragmentNode(field)) {
debugger;
}
else {
throw new Error(`not support field type`);
}
}
parseSelectionSetFirst(middlewars, source, alias, name, selectionSet, variables) {
if (selectionSet) {
middlewars.push(new core_1.Middleware('selection', async (root) => {
const injector = await root;
return injector.create([{
provide: token_1.GRAPHQL_SELECTION_SET,
useValue: selectionSet
}, {
provide: token_1.GRAPHQL_SELECTIONS,
useFactory: () => {
return selectionSet.selections.map(it => {
if (isFieldNode(it)) {
return it.name.value;
}
return;
}).filter(it => !!it);
}
}], 'selection');
}));
const selections = selectionSet.selections;
if (selections) {
if (rxjs_1.isObservable(source)) {
return source.pipe(operators_1.map((item) => {
return { [alias.value]: this.parseSelectionSet(item, selectionSet, variables) };
}));
}
else if (isPromise(source)) {
return source.then(res => ({
[alias.value]: this.parseSelectionSet(res, selectionSet, variables)
}));
}
else if (Array.isArray(source)) {
return { [alias.value]: source.map(it => this.parseSelectionSet(it, selectionSet, variables)) };
}
else if (source !== null && source !== undefined) {
if (selections && selections.length > 0) {
let res = {};
selections.map(it => {
const val = this.parseField(source, it, variables);
res = {
...res,
...val
};
});
return { [alias.value]: res };
}
return { [alias.value]: source };
}
else {
return { [alias.value]: null };
}
}
}
return source;
}
parseValue(value, variables) {
if (isVariableNode(value)) {
return Reflect.get(variables, value.name.value);
}
else if (isIntValueNode(value)) {
return parseInt(value.value, 10);
}
else if (isFloatValueNode(value)) {
return parseFloat(value.value);
}
else if (isStringValueNode(value)) {
return `${value.value}`;
}
else if (isBooleanValueNode(value)) {
return value.value;
}
if (isNullValueNode(value)) {
return null;
}
else if (isEnumValueNode(value)) {
console.log(`enum value`);
return value.value;
}
else if (isListValueNode(value)) {
return value.values.map(it => this.parseValue(it, variables));
}
else if (isObjectValueNode(value)) {
const res = {};
value.fields.map(it => {
Reflect.set(res, it.name.value, this.parseValue(it.value, variables));
});
return res;
}
else {
throw new Error(`not support value type`);
}
}
parseField(source, selection, variables) {
if (isFieldNode(selection)) {
let { alias, name, arguments: args, directives, selectionSet } = selection;
let value = source[name.value];
alias = alias || name;
const parameters = {};
const getNger = this.injector.get(core_1.GET_INGER_DECORATOR);
const type = source.constructor;
const nger = getNger(type);
const method = nger.methods.find(it => it.property === name.value);
const _args = (args || []).map(arg => {
const { name, value } = arg;
const val = this.parseValue(value, variables);
Reflect.set(parameters, name.value, val);
return val;
});
const argsInjector = this.injector.create([{
provide: token_1.GRAPHQL_SOURCE,
useValue: source
}, {
provide: core_1.ARGS,
useValue: parameters
}, {
provide: token_1.GRAPHQL_SELECTION_SET,
useValue: selectionSet
}, {
provide: token_1.GRAPHQL_SELECTIONS,
useFactory: () => {
if (selectionSet) {
return selectionSet.selections.map(it => {
if (isFieldNode(it)) {
return it.name.value;
}
return;
}).filter(it => !!it);
}
return [];
}
}], 'field');
if (method) {
const args = new Array(method.paramTypes);
nger.properties.map(pro => {
if (pro.metadataKey) {
const handler = argsInjector.get(pro.metadataKey, null);
if (handler) {
handler.property(pro, argsInjector);
}
}
});
method.parameters.map(par => {
if (par.metadataKey) {
const handler = argsInjector.get(par.metadataKey, null);
if (handler) {
const value = handler.methodParams(args, par, argsInjector);
Reflect.set(args, par.parameterIndex, value);
}
}
});
value = value(...args);
}
else {
if (typeof value === 'function') {
value = value(..._args);
}
}
if (selectionSet) {
const res = { [alias.value]: this.parseSelectionSet(value, selectionSet, variables) };
return res;
}
else {
return { [alias.value]: value };
}
}
else if (isFragmentSpreadNode(selection)) {
const fragment = this.getFragmentDefinition(selection.name.value);
if (fragment) {
return this.parseSelectionSet(source, fragment.selectionSet, variables);
}
else {
throw new Error(`not found fragment ${selection.name.value}`);
}
}
else if (isInlineFragmentNode(selection)) {
debugger;
}
else {
throw new Error(`not support field type`);
}
}
parseSelectionSet(source, selectionSet, variables) {
if (selectionSet) {
const selections = selectionSet.selections;
if (selections) {
if (rxjs_1.isObservable(source)) {
return source.pipe(operators_1.map(item => {
return this.parseSelectionSet(item, selectionSet, variables);
}));
}
else if (isPromise(source)) {
return source.then(res => this.parseSelectionSet(res, selectionSet, variables));
}
else if (Array.isArray(source)) {
return source.map(it => this.parseSelectionSet(it, selectionSet, variables));
}
else if (source !== null && source !== undefined) {
if (selections && selections.length > 0) {
let res = {};
selections.map(it => {
const val = this.parseField(source, it, variables);
res = {
...res,
...val
};
});
return res;
}
return source;
}
else {
return null;
}
}
}
return source;
}
};
Graphql = tslib_1.__decorate([
core_1.Injectable(),
tslib_1.__metadata("design:paramtypes", [core_1.Injector])
], Graphql);
exports.Graphql = Graphql;
function isEnumValueNode(val) {
return Reflect.get(val, 'kind') === 'EnumValue';
}
exports.isEnumValueNode = isEnumValueNode;
function isListValueNode(val) {
return Reflect.get(val, 'kind') === 'ListValue';
}
exports.isListValueNode = isListValueNode;
function isObjectValueNode(val) {
return Reflect.get(val, 'kind') === 'ObjectValue';
}
exports.isObjectValueNode = isObjectValueNode;
function isVariableNode(val) {
return Reflect.get(val, 'kind') === 'Variable';
}
exports.isVariableNode = isVariableNode;
function isIntValueNode(val) {
return Reflect.get(val, 'kind') === 'IntValue';
}
exports.isIntValueNode = isIntValueNode;
function isFloatValueNode(val) {
return Reflect.get(val, 'kind') === 'FloatValue';
}
exports.isFloatValueNode = isFloatValueNode;
function isStringValueNode(val) {
return Reflect.get(val, 'kind') === 'StringValue';
}
exports.isStringValueNode = isStringValueNode;
function isBooleanValueNode(val) {
return Reflect.get(val, 'kind') === 'BooleanValue';
}
exports.isBooleanValueNode = isBooleanValueNode;
function isNullValueNode(val) {
return Reflect.get(val, 'kind') === 'NullValue';
}
exports.isNullValueNode = isNullValueNode;
function isArgumentNode(val) {
return Reflect.get(val, 'kind') === 'Argument';
}
exports.isArgumentNode = isArgumentNode;
function isFieldNode(val) {
return Reflect.get(val, 'kind') === 'Field';
}
exports.isFieldNode = isFieldNode;
function isFragmentSpreadNode(val) {
return Reflect.get(val, 'kind') === 'FragmentSpread';
}
exports.isFragmentSpreadNode = isFragmentSpreadNode;
function isInlineFragmentNode(val) {
return Reflect.get(val, 'kind') === 'InlineFragment';
}
exports.isInlineFragmentNode = isInlineFragmentNode;
function isPromise(val) {
return val && typeof val === 'object' && Reflect.has(val, 'then') && Reflect.has(val, 'catch');
}
exports.isPromise = isPromise;