@coderich/autograph 0.11.1 → 0.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.js +4 -6
- package/package.json +30 -44
- package/src/data/DataLoader.js +77 -70
- package/src/data/Emitter.js +89 -0
- package/src/data/Loader.js +33 -0
- package/src/data/Pipeline.js +88 -96
- package/src/data/Resolver.js +304 -0
- package/src/data/Transaction.js +49 -0
- package/src/query/Query.js +159 -334
- package/src/query/QueryBuilder.js +228 -114
- package/src/query/QueryResolver.js +110 -216
- package/src/query/QueryResolverTransaction.js +16 -0
- package/src/schema/Schema.js +593 -0
- package/src/service/AppService.js +38 -0
- package/src/service/ErrorService.js +7 -0
- package/CHANGELOG.md +0 -41
- package/LICENSE +0 -21
- package/README.md +0 -76
- package/src/.DS_Store +0 -0
- package/src/core/.DS_Store +0 -0
- package/src/core/Boom.js +0 -9
- package/src/core/EventEmitter.js +0 -95
- package/src/core/Resolver.js +0 -124
- package/src/core/Schema.js +0 -55
- package/src/core/ServerResolver.js +0 -15
- package/src/data/.DS_Store +0 -0
- package/src/data/DataService.js +0 -120
- package/src/data/DataTransaction.js +0 -96
- package/src/data/Field.js +0 -83
- package/src/data/Model.js +0 -223
- package/src/data/TreeMap.js +0 -78
- package/src/data/Type.js +0 -50
- package/src/driver/.DS_Store +0 -0
- package/src/driver/MongoDriver.js +0 -227
- package/src/driver/index.js +0 -11
- package/src/graphql/.DS_Store +0 -0
- package/src/graphql/ast/.DS_Store +0 -0
- package/src/graphql/ast/Field.js +0 -206
- package/src/graphql/ast/Model.js +0 -145
- package/src/graphql/ast/Node.js +0 -291
- package/src/graphql/ast/Schema.js +0 -133
- package/src/graphql/ast/Type.js +0 -26
- package/src/graphql/ast/TypeDefApi.js +0 -93
- package/src/graphql/extension/.DS_Store +0 -0
- package/src/graphql/extension/api.js +0 -193
- package/src/graphql/extension/framework.js +0 -71
- package/src/graphql/extension/type.js +0 -34
- package/src/query/.DS_Store +0 -0
- package/src/query/QueryBuilderTransaction.js +0 -26
- package/src/query/QueryService.js +0 -111
- package/src/service/.DS_Store +0 -0
- package/src/service/app.service.js +0 -319
- package/src/service/decorator.service.js +0 -114
- package/src/service/event.service.js +0 -66
- package/src/service/graphql.service.js +0 -92
- package/src/service/schema.service.js +0 -95
|
@@ -1,133 +0,0 @@
|
|
|
1
|
-
const FS = require('fs');
|
|
2
|
-
const Glob = require('glob');
|
|
3
|
-
const Merge = require('deepmerge');
|
|
4
|
-
const { Kind, print, parse, visit } = require('graphql');
|
|
5
|
-
const { mergeASTArray } = require('../../service/graphql.service');
|
|
6
|
-
const { deleteKeys } = require('../../service/app.service');
|
|
7
|
-
const frameworkExt = require('../extension/framework');
|
|
8
|
-
const typeExt = require('../extension/type');
|
|
9
|
-
const apiExt = require('../extension/api');
|
|
10
|
-
const TypeDefApi = require('./TypeDefApi');
|
|
11
|
-
const Node = require('./Node');
|
|
12
|
-
|
|
13
|
-
/**
|
|
14
|
-
* Schema
|
|
15
|
-
*
|
|
16
|
-
* This class helps facilitate dynamic modification of a schema before it is passed to makeExecutableSchema(). It allows
|
|
17
|
-
* for "intelligent" merging of schemas and exposes an API wrapper for typeDefs.
|
|
18
|
-
*
|
|
19
|
-
* A "schema" is defined by the following object attributes:
|
|
20
|
-
*
|
|
21
|
-
* typeDefs <String|Object> - GQL String or AST Object (also supports a mixed array of both)
|
|
22
|
-
* resolvers <Object> - GraphQL resolvers
|
|
23
|
-
* schemaDirectives <Object> - GraphQL directives
|
|
24
|
-
*
|
|
25
|
-
*/
|
|
26
|
-
module.exports = class Schema extends TypeDefApi {
|
|
27
|
-
constructor(schema) {
|
|
28
|
-
super();
|
|
29
|
-
this.schema = { typeDefs: [], resolvers: {}, schemaDirectives: {} };
|
|
30
|
-
if (schema) this.mergeSchema(schema);
|
|
31
|
-
}
|
|
32
|
-
|
|
33
|
-
/**
|
|
34
|
-
* Synchronously merge a schema
|
|
35
|
-
*/
|
|
36
|
-
mergeSchema(schema, options = {}) {
|
|
37
|
-
// Ensure this is a schema of sorts otherwise skip it
|
|
38
|
-
if (typeof schema !== 'string' && ['typeDefs', 'resolvers', 'schemaDirectives'].every(key => !schema[key])) return this;
|
|
39
|
-
|
|
40
|
-
// Here we want to normalize the schema into the shape { typeDefs, resolvers, schemaDirectives }
|
|
41
|
-
// We do NOT want to modify the schema object because that may cause unwanted side-effects.
|
|
42
|
-
const normalizedSchema = { ...schema };
|
|
43
|
-
if (typeof schema === 'string') normalizedSchema.typeDefs = [schema];
|
|
44
|
-
else if (schema.typeDefs && !Array.isArray(schema.typeDefs)) normalizedSchema.typeDefs = [schema.typeDefs];
|
|
45
|
-
|
|
46
|
-
// For typeDefs we want the AST so that it can be intelligently merged. Here we convert
|
|
47
|
-
// GQL strings to AST objects and also filter out anything that does not parse to AST.
|
|
48
|
-
if (normalizedSchema.typeDefs && normalizedSchema.typeDefs.length) {
|
|
49
|
-
normalizedSchema.typeDefs = deleteKeys(normalizedSchema.typeDefs.map((td) => {
|
|
50
|
-
try {
|
|
51
|
-
const ast = typeof td === 'object' ? td : parse(td);
|
|
52
|
-
return ast.definitions;
|
|
53
|
-
} catch (e) {
|
|
54
|
-
return null;
|
|
55
|
-
}
|
|
56
|
-
}), ['loc']).filter(Boolean).flat();
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// Now we're ready to merge the schema
|
|
60
|
-
const [left, right] = options.passive ? [normalizedSchema, this.schema] : [this.schema, normalizedSchema];
|
|
61
|
-
if (normalizedSchema.typeDefs && normalizedSchema.typeDefs.length) this.schema.typeDefs = mergeASTArray(left.typeDefs.concat(right.typeDefs));
|
|
62
|
-
if (normalizedSchema.resolvers) this.schema.resolvers = Merge(left.resolvers, right.resolvers);
|
|
63
|
-
if (normalizedSchema.schemaDirectives) this.schema.schemaDirectives = Merge(left.schemaDirectives, right.schemaDirectives);
|
|
64
|
-
|
|
65
|
-
// Chaining
|
|
66
|
-
return this;
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
/**
|
|
70
|
-
* Asynchronously load files from a given glob pattern and merge each schema
|
|
71
|
-
*/
|
|
72
|
-
mergeSchemaFromFiles(globPattern, options) {
|
|
73
|
-
return new Promise((resolve, reject) => {
|
|
74
|
-
Glob(globPattern, options, (err, files) => {
|
|
75
|
-
if (err) return reject(err);
|
|
76
|
-
|
|
77
|
-
return Promise.all(files.map((file) => {
|
|
78
|
-
return new Promise((res) => {
|
|
79
|
-
if (file.endsWith('.js')) res(require(file)); // eslint-disable-line global-require,import/no-dynamic-require
|
|
80
|
-
else res(FS.readFileSync(file, 'utf8'));
|
|
81
|
-
}).then(schema => this.mergeSchema(schema, options));
|
|
82
|
-
})).then(() => resolve(this)).catch(e => reject(e));
|
|
83
|
-
});
|
|
84
|
-
});
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
/**
|
|
88
|
-
* Traverses the current schema's typeDefs in order to keep the TypeDefApi in sync. This operation
|
|
89
|
-
* only needs to be called when typeDefs have been changed and you want to keep the data model in sync.
|
|
90
|
-
*/
|
|
91
|
-
initialize() {
|
|
92
|
-
super.initialize(this.schema.typeDefs);
|
|
93
|
-
return this;
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
/**
|
|
97
|
-
* Decorate the schema with Autograph's default api/definitions
|
|
98
|
-
*/
|
|
99
|
-
decorate() {
|
|
100
|
-
this.initialize();
|
|
101
|
-
this.mergeSchema(frameworkExt(this), { passive: true });
|
|
102
|
-
this.mergeSchema(typeExt(this), { passive: true });
|
|
103
|
-
this.initialize();
|
|
104
|
-
this.mergeSchema(apiExt(this), { passive: true });
|
|
105
|
-
this.finalize();
|
|
106
|
-
return this;
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
/**
|
|
110
|
-
* This should be called once before passing to makeExecutableSchema()
|
|
111
|
-
*/
|
|
112
|
-
finalize() {
|
|
113
|
-
const definitions = visit(this.schema.typeDefs, {
|
|
114
|
-
[Kind.FIELD_DEFINITION]: (node) => {
|
|
115
|
-
const scope = new Node(node, 'field').getDirectiveArg('field', 'gqlScope', 'crud');
|
|
116
|
-
if (scope === null || scope.indexOf('r') === -1) return null; // Delete node
|
|
117
|
-
return false; // Stop traversing this node
|
|
118
|
-
},
|
|
119
|
-
});
|
|
120
|
-
|
|
121
|
-
this.getModels().forEach(model => model.finalize());
|
|
122
|
-
this.schema.typeDefs = { kind: Kind.DOCUMENT, definitions };
|
|
123
|
-
return this;
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
toObject() {
|
|
127
|
-
return this.schema;
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
toString() {
|
|
131
|
-
return print(this.schema.typeDefs);
|
|
132
|
-
}
|
|
133
|
-
};
|
package/src/graphql/ast/Type.js
DELETED
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const Node = require('./Node');
|
|
2
|
-
const { getTypeInfo } = require('../../service/graphql.service');
|
|
3
|
-
|
|
4
|
-
const scalars = ['ID', 'String', 'Float', 'Int', 'Boolean'];
|
|
5
|
-
|
|
6
|
-
module.exports = class Type extends Node {
|
|
7
|
-
getName() {
|
|
8
|
-
return getTypeInfo(this.ast).name;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
isArray() {
|
|
12
|
-
return Boolean(getTypeInfo(this.ast).isArray);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
isRequired(debug) {
|
|
16
|
-
return Boolean(getTypeInfo(this.ast, {}, false).isRequired);
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
isArrayElementRequired() {
|
|
20
|
-
return this.isArray() && Boolean(getTypeInfo(this.ast.type).isRequired);
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
isScalar() {
|
|
24
|
-
return scalars.indexOf(this.getName()) > -1;
|
|
25
|
-
}
|
|
26
|
-
};
|
|
@@ -1,93 +0,0 @@
|
|
|
1
|
-
const { Kind, visit } = require('graphql');
|
|
2
|
-
const Model = require('./Model');
|
|
3
|
-
const Node = require('./Node');
|
|
4
|
-
|
|
5
|
-
const operations = ['Query', 'Mutation', 'Subscription'];
|
|
6
|
-
const modelKinds = [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION, Kind.INTERFACE_TYPE_DEFINITION, Kind.INTERFACE_TYPE_EXTENSION];
|
|
7
|
-
const inputKinds = [Kind.INPUT_OBJECT_TYPE_DEFINITION, Kind.INPUT_OBJECT_TYPE_EXTENSION];
|
|
8
|
-
const scalarKinds = [Kind.SCALAR_TYPE_DEFINITION, Kind.SCALAR_TYPE_EXTENSION];
|
|
9
|
-
const enumKinds = [Kind.ENUM_TYPE_DEFINITION, Kind.ENUM_TYPE_EXTENSION];
|
|
10
|
-
|
|
11
|
-
module.exports = class TypeDefApi {
|
|
12
|
-
constructor() {
|
|
13
|
-
this.models = [];
|
|
14
|
-
this.scalars = [];
|
|
15
|
-
this.inputs = [];
|
|
16
|
-
this.enums = [];
|
|
17
|
-
}
|
|
18
|
-
|
|
19
|
-
initialize(typeDefs) {
|
|
20
|
-
this.models.length = 0;
|
|
21
|
-
this.scalars.length = 0;
|
|
22
|
-
this.inputs.length = 0;
|
|
23
|
-
this.enums.length = 0;
|
|
24
|
-
|
|
25
|
-
visit(typeDefs, {
|
|
26
|
-
enter: (node) => {
|
|
27
|
-
if (modelKinds.indexOf(node.kind) > -1 && operations.indexOf(node.name.value) === -1) {
|
|
28
|
-
this.models.push(new Model(this, node));
|
|
29
|
-
} else if (scalarKinds.indexOf(node.kind) > -1) {
|
|
30
|
-
this.scalars.push(new Node(node));
|
|
31
|
-
} else if (inputKinds.indexOf(node.kind) > -1) {
|
|
32
|
-
this.inputs.push(new Node(node));
|
|
33
|
-
} else if (enumKinds.indexOf(node.kind) > -1) {
|
|
34
|
-
this.enums.push(new Node(node));
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
return false; // Stop traversing this node
|
|
38
|
-
},
|
|
39
|
-
});
|
|
40
|
-
|
|
41
|
-
return this;
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
// Models
|
|
45
|
-
getModel(name) {
|
|
46
|
-
return this.models.find(m => m.getName() === name);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
getModels() {
|
|
50
|
-
return this.models;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
getModelNames() {
|
|
54
|
-
return this.getModels().map(model => model.getName());
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
getModelMap() {
|
|
58
|
-
return this.getModels().reduce((prev, model) => Object.assign(prev, { [model.getName()]: model }), {});
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
getMarkedModels() {
|
|
62
|
-
return Object.values(this.models).filter(model => model.isMarkedModel());
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
getEntityModels() {
|
|
66
|
-
return Object.values(this.models).filter(model => model.isEntity());
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
// Definitions
|
|
70
|
-
getInput(name) {
|
|
71
|
-
return this.getInputs().find(input => input.getName() === name);
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
getInputs() {
|
|
75
|
-
return this.inputs;
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
getScalar(name) {
|
|
79
|
-
return this.getScalars().find(scalar => scalar.getName() === name);
|
|
80
|
-
}
|
|
81
|
-
|
|
82
|
-
getScalars() {
|
|
83
|
-
return this.scalars;
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
getEnum(name) {
|
|
87
|
-
return this.getEnums().find(el => el.getName() === name);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
getEnums() {
|
|
91
|
-
return this.enums;
|
|
92
|
-
}
|
|
93
|
-
};
|
|
Binary file
|
|
@@ -1,193 +0,0 @@
|
|
|
1
|
-
const { get } = require('lodash');
|
|
2
|
-
const { Kind } = require('graphql');
|
|
3
|
-
const ServerResolver = require('../../core/ServerResolver');
|
|
4
|
-
const { ucFirst, toGUID, fromGUID } = require('../../service/app.service');
|
|
5
|
-
const { findGQLModels } = require('../../service/schema.service');
|
|
6
|
-
const { makeCreateAPI, makeReadAPI, makeUpdateAPI, makeDeleteAPI, makeSubscriptionAPI, makeQueryResolver, makeMutationResolver } = require('../../service/decorator.service');
|
|
7
|
-
|
|
8
|
-
const interfaceKinds = [Kind.INTERFACE_TYPE_DEFINITION, Kind.INTERFACE_TYPE_EXTENSION];
|
|
9
|
-
|
|
10
|
-
const getGQLWhereFields = (model) => {
|
|
11
|
-
return model.getFields().filter((field) => {
|
|
12
|
-
if (!field.hasGQLScope('r')) return false;
|
|
13
|
-
const modelRef = field.getModelRef();
|
|
14
|
-
if (modelRef && !modelRef.isEmbedded() && !modelRef.isEntity()) return false;
|
|
15
|
-
return true;
|
|
16
|
-
});
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
module.exports = (schema) => {
|
|
20
|
-
const resolver = new ServerResolver();
|
|
21
|
-
const allModels = schema.getModels();
|
|
22
|
-
const entityModels = schema.getEntityModels();
|
|
23
|
-
const markedModels = schema.getMarkedModels();
|
|
24
|
-
const createModels = findGQLModels('c', markedModels, allModels);
|
|
25
|
-
const readModels = findGQLModels('r', markedModels, allModels);
|
|
26
|
-
const updateModels = findGQLModels('u', markedModels, allModels);
|
|
27
|
-
|
|
28
|
-
return ({
|
|
29
|
-
typeDefs: [
|
|
30
|
-
...createModels.map(model => `
|
|
31
|
-
input ${model.getName()}InputCreate {
|
|
32
|
-
${model.getFields().filter(field => field.hasGQLScope('c') && !field.isVirtual()).map(field => `${field.getName()}: ${field.getGQLType('InputCreate')}`)}
|
|
33
|
-
}
|
|
34
|
-
`),
|
|
35
|
-
|
|
36
|
-
...updateModels.map(model => `
|
|
37
|
-
input ${model.getName()}InputUpdate {
|
|
38
|
-
${model.getFields().filter(field => field.hasGQLScope('u') && !field.isVirtual()).map(field => `${field.getName()}: ${field.getGQLType('InputUpdate')}`)}
|
|
39
|
-
}
|
|
40
|
-
`),
|
|
41
|
-
|
|
42
|
-
...readModels.map(model => `
|
|
43
|
-
input ${model.getName()}InputWhere {
|
|
44
|
-
${getGQLWhereFields(model).map(field => `${field.getName()}: ${field.getModelRef() ? `${ucFirst(field.getDataRef())}InputWhere` : 'AutoGraphMixed'}`)}
|
|
45
|
-
}
|
|
46
|
-
input ${model.getName()}InputSort {
|
|
47
|
-
${getGQLWhereFields(model).map(field => `${field.getName()}: ${field.getModelRef() ? `${ucFirst(field.getDataRef())}InputSort` : 'SortOrderEnum'}`)}
|
|
48
|
-
}
|
|
49
|
-
extend ${interfaceKinds.indexOf(model.getKind()) > -1 ? 'interface' : 'type'} ${model.getName()} {
|
|
50
|
-
${model.getFields().filter(field => field.hasGQLScope('r')).map(field => `${field.getName()}${field.getExtendArgs()}: ${field.getPayloadType()}`)}
|
|
51
|
-
}
|
|
52
|
-
type ${model.getName()}Connection {
|
|
53
|
-
count: Int!
|
|
54
|
-
pageInfo: PageInfo!
|
|
55
|
-
edges: [${model.getName()}Edge]
|
|
56
|
-
}
|
|
57
|
-
type ${model.getName()}Edge {
|
|
58
|
-
node: ${model.getName()}
|
|
59
|
-
cursor: String!
|
|
60
|
-
}
|
|
61
|
-
`),
|
|
62
|
-
|
|
63
|
-
...entityModels.filter(model => model.hasGQLScope('s')).map(model => `
|
|
64
|
-
input ${model.getName()}SubscriptionInputFilter {
|
|
65
|
-
when: [SubscriptionWhenEnum!]! = [preEvent, postEvent]
|
|
66
|
-
where: ${model.getName()}SubscriptionInputWhere! = {}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
|
-
input ${model.getName()}SubscriptionInputWhere {
|
|
70
|
-
${getGQLWhereFields(model).map(field => `${field.getName()}: ${field.getModelRef() && !field.isFKReference() ? `${ucFirst(field.getDataRef())}InputWhere` : 'AutoGraphMixed'}`)}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
type ${model.getName()}SubscriptionPayload {
|
|
74
|
-
event: ${model.getName()}SubscriptionPayloadEvent
|
|
75
|
-
query: ${model.getName()}SubscriptionQuery
|
|
76
|
-
}
|
|
77
|
-
|
|
78
|
-
type ${model.getName()}SubscriptionPayloadEvent {
|
|
79
|
-
crud: SubscriptionCrudEnum!
|
|
80
|
-
data: ${model.getName()}SubscriptionPayloadEventData!
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
type ${model.getName()}SubscriptionPayloadEventData {
|
|
84
|
-
${getGQLWhereFields(model).map(field => `${field.getName()}: ${field.getSubscriptionType()}`)}
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
interface ${model.getName()}SubscriptionQuery {
|
|
88
|
-
${model.getFields().filter(field => field.hasGQLScope('r')).map(field => `${field.getName()}: ${field.getPayloadType()}`)}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
type ${model.getName()}Create implements ${model.getName()}SubscriptionQuery {
|
|
92
|
-
${model.getFields().filter(field => field.hasGQLScope('r')).map(field => `${field.getName()}: ${field.getPayloadType()}`)}
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
type ${model.getName()}Update implements ${model.getName()}SubscriptionQuery {
|
|
96
|
-
${model.getFields().filter(field => field.hasGQLScope('r')).map(field => `${field.getName()}: ${field.getPayloadType()}`)}
|
|
97
|
-
}
|
|
98
|
-
`),
|
|
99
|
-
].concat([
|
|
100
|
-
`type PageInfo {
|
|
101
|
-
startCursor: String!
|
|
102
|
-
endCursor: String!
|
|
103
|
-
hasPreviousPage: Boolean!
|
|
104
|
-
hasNextPage: Boolean!
|
|
105
|
-
}`,
|
|
106
|
-
|
|
107
|
-
`type Query {
|
|
108
|
-
node(id: ID!): Node
|
|
109
|
-
${entityModels.map(model => makeReadAPI(model.getName(), model))}
|
|
110
|
-
}`,
|
|
111
|
-
|
|
112
|
-
`type Mutation {
|
|
113
|
-
_noop: String
|
|
114
|
-
${entityModels.map(model => makeCreateAPI(model.getName(), model))}
|
|
115
|
-
${entityModels.map(model => makeUpdateAPI(model.getName(), model))}
|
|
116
|
-
${entityModels.map(model => makeDeleteAPI(model.getName(), model))}
|
|
117
|
-
}`,
|
|
118
|
-
|
|
119
|
-
`type Subscription {
|
|
120
|
-
_noop: String
|
|
121
|
-
${entityModels.map(model => makeSubscriptionAPI(model.getName(), model))}
|
|
122
|
-
}`,
|
|
123
|
-
]),
|
|
124
|
-
resolvers: readModels.reduce((prev, model) => {
|
|
125
|
-
const modelName = model.getName();
|
|
126
|
-
|
|
127
|
-
// Default field resolvers
|
|
128
|
-
const fieldResolvers = model.getFields().filter(field => field.hasGQLScope('r')).reduce((def, field) => {
|
|
129
|
-
const fieldName = field.getName();
|
|
130
|
-
const isConnection = field.isConnection();
|
|
131
|
-
|
|
132
|
-
return Object.assign(def, {
|
|
133
|
-
[fieldName]: (doc, args, { autograph }, info) => {
|
|
134
|
-
if (fieldName === 'id') return autograph.legacyMode ? doc.id : toGUID(modelName, doc.id);
|
|
135
|
-
|
|
136
|
-
// If this field is a connection we return thunks in order to delay query
|
|
137
|
-
// until the "Connection" resolver (below) is run
|
|
138
|
-
if (isConnection) {
|
|
139
|
-
return {
|
|
140
|
-
count: () => field.count(autograph.resolver, doc, args),
|
|
141
|
-
edges: () => field.resolve(autograph.resolver, doc, args),
|
|
142
|
-
pageInfo: () => field.resolve(autograph.resolver, doc, args),
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
return field.resolve(autograph.resolver, doc, args);
|
|
147
|
-
},
|
|
148
|
-
});
|
|
149
|
-
}, {});
|
|
150
|
-
|
|
151
|
-
if (model.isEntity() && model.hasGQLScope('s')) {
|
|
152
|
-
prev[`${model.getName()}SubscriptionQuery`] = {
|
|
153
|
-
__resolveType: root => root.__typename, // eslint-disable-line no-underscore-dangle
|
|
154
|
-
...fieldResolvers,
|
|
155
|
-
};
|
|
156
|
-
prev[`${model.getName()}Create`] = fieldResolvers;
|
|
157
|
-
prev[`${model.getName()}Update`] = fieldResolvers;
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
return Object.assign(prev, {
|
|
161
|
-
[modelName]: fieldResolvers,
|
|
162
|
-
[`${modelName}Connection`]: {
|
|
163
|
-
count: ({ count }) => count(),
|
|
164
|
-
edges: ({ edges }) => edges().then(rs => rs.map(node => ({ cursor: get(node, '$cursor'), node }))),
|
|
165
|
-
pageInfo: ({ pageInfo }) => pageInfo().then(rs => get(rs, '$pageInfo')),
|
|
166
|
-
},
|
|
167
|
-
});
|
|
168
|
-
}, {
|
|
169
|
-
Node: {
|
|
170
|
-
__resolveType: (doc, args, context, info) => doc.__typename, // eslint-disable-line no-underscore-dangle
|
|
171
|
-
},
|
|
172
|
-
|
|
173
|
-
Query: entityModels.reduce((prev, model) => {
|
|
174
|
-
return Object.assign(prev, makeQueryResolver(model.getName(), model, resolver));
|
|
175
|
-
}, {
|
|
176
|
-
node: (doc, args, context, info) => {
|
|
177
|
-
const { id } = args;
|
|
178
|
-
const [modelName] = fromGUID(id);
|
|
179
|
-
const model = schema.getModel(modelName);
|
|
180
|
-
return resolver.get(context, model, args, false, info).then((result) => {
|
|
181
|
-
if (result == null) return result;
|
|
182
|
-
result.__typename = modelName; // eslint-disable-line no-underscore-dangle
|
|
183
|
-
return result;
|
|
184
|
-
});
|
|
185
|
-
},
|
|
186
|
-
}),
|
|
187
|
-
|
|
188
|
-
Mutation: entityModels.reduce((prev, model) => {
|
|
189
|
-
return Object.assign(prev, makeMutationResolver(model.getName(), model, resolver));
|
|
190
|
-
}, {}),
|
|
191
|
-
}),
|
|
192
|
-
});
|
|
193
|
-
};
|
|
@@ -1,71 +0,0 @@
|
|
|
1
|
-
const Pipeline = require('../../data/Pipeline');
|
|
2
|
-
|
|
3
|
-
Pipeline.createPresets();
|
|
4
|
-
|
|
5
|
-
module.exports = (schema) => {
|
|
6
|
-
return {
|
|
7
|
-
typeDefs: `
|
|
8
|
-
scalar AutoGraphMixed
|
|
9
|
-
scalar AutoGraphDriver
|
|
10
|
-
scalar AutoGraphDateTime @field(transform: toDate)
|
|
11
|
-
enum AutoGraphPipelineEnum { ${Object.keys(Pipeline).join(' ')} }
|
|
12
|
-
enum AutoGraphAuthzEnum { private protected public }
|
|
13
|
-
enum AutoGraphOnDeleteEnum { cascade nullify restrict defer }
|
|
14
|
-
enum AutoGraphIndexEnum { unique }
|
|
15
|
-
|
|
16
|
-
directive @model(
|
|
17
|
-
id: String # Specify db key (default "id")
|
|
18
|
-
key: String # Specify db table/collection name
|
|
19
|
-
driver: AutoGraphDriver # External data driver
|
|
20
|
-
createdAt: String # Specify db key (default "createdAt")
|
|
21
|
-
updatedAt: String # Specify db key (default "updatedAt")
|
|
22
|
-
meta: AutoGraphMixed # Custom input "meta" field for mutations
|
|
23
|
-
embed: Boolean # Mark this an embedded model (default false)
|
|
24
|
-
persist: Boolean # Persist this model (default true)
|
|
25
|
-
gqlScope: AutoGraphMixed # Dictate how GraphQL API behaves
|
|
26
|
-
dalScope: AutoGraphMixed # Dictate how the DAL behaves
|
|
27
|
-
fieldScope: AutoGraphMixed # Dictate how a FIELD may use me
|
|
28
|
-
authz: AutoGraphAuthzEnum # Access level used for authorization (default: private)
|
|
29
|
-
namespace: String # Logical grouping of models that can be globbed (useful for authz)
|
|
30
|
-
) on OBJECT | INTERFACE
|
|
31
|
-
|
|
32
|
-
directive @field(
|
|
33
|
-
id: String # Specify the ModelRef this field FK References
|
|
34
|
-
ref: AutoGraphMixed # Specify the modelRef field's name (overrides isEmbedded)
|
|
35
|
-
key: String # Specify db key
|
|
36
|
-
persist: Boolean # Persist this field (default true)
|
|
37
|
-
connection: Boolean # Treat this field as a connection type (default false - rolling this out slowly)
|
|
38
|
-
default: AutoGraphMixed # Define a default value
|
|
39
|
-
gqlScope: AutoGraphMixed # Dictate how GraphQL API behaves
|
|
40
|
-
dalScope: AutoGraphMixed # Dictate how the DAL behaves
|
|
41
|
-
fieldScope: AutoGraphMixed # Dictate how a FIELD may use me
|
|
42
|
-
onDelete: AutoGraphOnDeleteEnum # onDelete behavior
|
|
43
|
-
|
|
44
|
-
authz: AutoGraphAuthzEnum # Access level used for authorization (default: private)
|
|
45
|
-
|
|
46
|
-
# Pipeline Structure
|
|
47
|
-
validate: [AutoGraphPipelineEnum!]
|
|
48
|
-
construct: [AutoGraphPipelineEnum!]
|
|
49
|
-
restruct: [AutoGraphPipelineEnum!]
|
|
50
|
-
destruct: [AutoGraphPipelineEnum!]
|
|
51
|
-
instruct: [AutoGraphPipelineEnum!]
|
|
52
|
-
normalize: [AutoGraphPipelineEnum!]
|
|
53
|
-
transform: [AutoGraphPipelineEnum!]
|
|
54
|
-
serialize: [AutoGraphPipelineEnum!]
|
|
55
|
-
deserialize: [AutoGraphPipelineEnum!]
|
|
56
|
-
) on FIELD_DEFINITION | INPUT_FIELD_DEFINITION | SCALAR
|
|
57
|
-
|
|
58
|
-
directive @link(
|
|
59
|
-
to: AutoGraphMixed # The MODEL to link to (default's to modelRef)
|
|
60
|
-
by: AutoGraphMixed! # The FIELD to match yourself by
|
|
61
|
-
use: AutoGraphMixed # The VALUE to use (default's to @link'd value); useful for many-to-many relationships
|
|
62
|
-
) on FIELD_DEFINITION
|
|
63
|
-
|
|
64
|
-
directive @index(
|
|
65
|
-
name: String
|
|
66
|
-
on: [AutoGraphMixed!]!
|
|
67
|
-
type: AutoGraphIndexEnum!
|
|
68
|
-
) repeatable on OBJECT
|
|
69
|
-
`,
|
|
70
|
-
};
|
|
71
|
-
};
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Decorate Entity Models
|
|
3
|
-
*/
|
|
4
|
-
module.exports = (schema) => {
|
|
5
|
-
return ({
|
|
6
|
-
typeDefs: schema.getMarkedModels().map((model) => {
|
|
7
|
-
const id = model.idKey();
|
|
8
|
-
const modelName = model.getName();
|
|
9
|
-
const createdAt = model.getDirectiveArg('model', 'createdAt', 'createdAt');
|
|
10
|
-
const updatedAt = model.getDirectiveArg('model', 'updatedAt', 'updatedAt');
|
|
11
|
-
|
|
12
|
-
if (model.getKind() === 'ObjectTypeDefinition' && (id || createdAt || updatedAt)) {
|
|
13
|
-
const interfaces = [];
|
|
14
|
-
if (id) interfaces.push('Node');
|
|
15
|
-
const interfacesGQL = interfaces.length ? ' implements'.concat(' ', interfaces.join(' & ')) : '';
|
|
16
|
-
|
|
17
|
-
return `
|
|
18
|
-
extend type ${modelName}${interfacesGQL} {
|
|
19
|
-
${id ? `id: ID! @field(key: "${id}", gqlScope: r)` : ''}
|
|
20
|
-
${createdAt ? `createdAt: AutoGraphDateTime @field(key: "${createdAt}", construct: createdAt, gqlScope: r)` : ''}
|
|
21
|
-
${updatedAt ? `updatedAt: AutoGraphDateTime @field(key: "${updatedAt}", serialize: timestamp, gqlScope: r)` : ''}
|
|
22
|
-
}
|
|
23
|
-
`;
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
return '';
|
|
27
|
-
}).concat(`
|
|
28
|
-
interface Node { id: ID! }
|
|
29
|
-
enum SortOrderEnum { asc desc }
|
|
30
|
-
enum SubscriptionCrudEnum { create update delete } # Not going to support "read"
|
|
31
|
-
enum SubscriptionWhenEnum { preEvent postEvent }
|
|
32
|
-
`),
|
|
33
|
-
});
|
|
34
|
-
};
|
package/src/query/.DS_Store
DELETED
|
Binary file
|
|
@@ -1,26 +0,0 @@
|
|
|
1
|
-
const QueryBuilder = require('./QueryBuilder');
|
|
2
|
-
|
|
3
|
-
module.exports = class QueryBuilderTransaction extends QueryBuilder {
|
|
4
|
-
constructor(resolver, model, transaction) {
|
|
5
|
-
super(resolver, model);
|
|
6
|
-
this.query.transaction(transaction);
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
execute(cmd, args) {
|
|
10
|
-
return new Promise((resolve, reject) => {
|
|
11
|
-
this.theCall = { cmd, args, resolve, reject };
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
exec(options) {
|
|
16
|
-
if (!this.theCall) return undefined;
|
|
17
|
-
|
|
18
|
-
const { cmd, args, resolve } = this.theCall;
|
|
19
|
-
this.query.options(options);
|
|
20
|
-
|
|
21
|
-
return super.execute(cmd, args).then((result) => {
|
|
22
|
-
resolve(result);
|
|
23
|
-
return result;
|
|
24
|
-
});
|
|
25
|
-
}
|
|
26
|
-
};
|