@coderich/autograph 0.10.0 → 0.10.3

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.
Files changed (44) hide show
  1. package/CHANGELOG.md +20 -3
  2. package/index.js +2 -8
  3. package/package.json +5 -7
  4. package/src/.DS_Store +0 -0
  5. package/src/core/EventEmitter.js +2 -4
  6. package/src/core/Resolver.js +32 -57
  7. package/src/core/Schema.js +5 -38
  8. package/src/data/.DS_Store +0 -0
  9. package/src/data/DataLoader.js +71 -32
  10. package/src/data/DataService.js +82 -59
  11. package/src/data/Field.js +59 -126
  12. package/src/data/Model.js +113 -105
  13. package/src/data/Pipeline.js +184 -0
  14. package/src/data/Type.js +38 -74
  15. package/src/driver/MongoDriver.js +27 -22
  16. package/src/graphql/.DS_Store +0 -0
  17. package/src/graphql/ast/Field.js +46 -24
  18. package/src/graphql/ast/Model.js +5 -16
  19. package/src/graphql/ast/Node.js +0 -25
  20. package/src/graphql/ast/Schema.js +105 -112
  21. package/src/graphql/extension/api.js +20 -18
  22. package/src/graphql/extension/framework.js +27 -33
  23. package/src/graphql/extension/type.js +2 -2
  24. package/src/query/Query.js +82 -14
  25. package/src/query/QueryBuilder.js +38 -30
  26. package/src/query/QueryBuilderTransaction.js +3 -3
  27. package/src/query/QueryResolver.js +77 -41
  28. package/src/query/QueryService.js +24 -42
  29. package/src/service/app.service.js +70 -13
  30. package/src/service/event.service.js +30 -73
  31. package/src/service/graphql.service.js +0 -9
  32. package/src/service/schema.service.js +5 -3
  33. package/src/core/GraphQL.js +0 -21
  34. package/src/core/Rule.js +0 -107
  35. package/src/core/SchemaDecorator.js +0 -46
  36. package/src/core/Transformer.js +0 -68
  37. package/src/data/Memoizer.js +0 -39
  38. package/src/data/ResultSet.js +0 -205
  39. package/src/data/stream/DataHydrator.js +0 -58
  40. package/src/data/stream/ResultSet.js +0 -34
  41. package/src/data/stream/ResultSetItem.js +0 -158
  42. package/src/data/stream/ResultSetItemProxy.js +0 -161
  43. package/src/graphql/ast/SchemaDecorator.js +0 -141
  44. package/src/graphql/directive/authz.directive.js +0 -84
@@ -1,58 +0,0 @@
1
- const { get } = require('lodash');
2
- const Stream = require('stream');
3
- const ResultSet = require('./ResultSet');
4
- const ResultSetItem = require('./ResultSetItemProxy');
5
- const { promiseChain, mapPromise, toKeyObj } = require('../../service/app.service');
6
-
7
- module.exports = class DataHydrator {
8
- constructor(query, data) {
9
- let { select = {} } = query.toObject();
10
- select = toKeyObj(select);
11
- return data instanceof Stream ? DataHydrator.stream(query, data, select) : DataHydrator.process(query, data, select);
12
- }
13
-
14
- static stream(query, stream, select) {
15
- const promises = [];
16
-
17
- return new Promise((resolve, reject) => {
18
- stream.on('data', (data) => {
19
- promises.push(DataHydrator.hydrate(query, data, select));
20
- });
21
-
22
- stream.on('error', reject);
23
-
24
- stream.on('end', () => {
25
- Promise.all(promises).then(results => resolve(new ResultSet(query, results)));
26
- });
27
- });
28
- }
29
-
30
- static process(query, data, select) {
31
- return mapPromise(data, d => DataHydrator.hydrate(query, d, select)).then(results => new ResultSet(query, results));
32
- }
33
-
34
- static hydrate(query, data, select) {
35
- const loopArray = Array.from(new Array(Math.max(0, ...Object.keys(select).map(key => key.split('.').length))));
36
-
37
- return new Promise((resolve, reject) => {
38
- const item = new ResultSetItem(query, data);
39
-
40
- return Promise.all(Object.keys(select).map((path) => {
41
- const arrPath = path.split('.');
42
-
43
- return Promise.all(loopArray.map((el, depth) => {
44
- const arr = arrPath.slice(0, depth);
45
- const $arr = arr.map(ele => `$${ele}`);
46
- const key = arr[depth];
47
-
48
- // id has special handling
49
- if (!key || key === 'id') return Promise.resolve();
50
-
51
- // Resolve all other attributes
52
- get(item, arr.join('.'));
53
- return promiseChain($arr.map($prop => chain => (chain.pop() || item)[$prop]()));
54
- }));
55
- })).then(() => resolve(item)).catch(e => reject(e));
56
- });
57
- }
58
- };
@@ -1,34 +0,0 @@
1
- const { get } = require('lodash');
2
- const DataService = require('../DataService');
3
- const { ensureArray } = require('../../service/app.service');
4
-
5
- module.exports = class ResultSet {
6
- constructor(query, data, adjustForPagination = true) {
7
- if (data == null) return data;
8
- const { first, after, last, before } = query.toObject();
9
-
10
- let hasNextPage = false;
11
- let hasPreviousPage = false;
12
- if (adjustForPagination && data.length) (({ hasPreviousPage, hasNextPage } = DataService.paginateResultSet(data, first, after, last, before)));
13
-
14
- return Object.defineProperties(data, {
15
- $$pageInfo: {
16
- get() {
17
- const edges = ensureArray(data);
18
-
19
- return {
20
- startCursor: get(edges, '0.$$cursor', ''),
21
- endCursor: get(edges, `${edges.length - 1}.$$cursor`, ''),
22
- hasPreviousPage,
23
- hasNextPage,
24
- };
25
- },
26
- enumerable: false,
27
- },
28
- $$isResultSet: {
29
- value: true,
30
- enumerable: false,
31
- },
32
- });
33
- }
34
- };
@@ -1,158 +0,0 @@
1
- const { get } = require('lodash');
2
- const ResultSet = require('./ResultSet');
3
- const { map, keyPaths, mapPromise, toGUID, hashObject } = require('../../service/app.service');
4
-
5
- module.exports = class ResultSetItem {
6
- constructor(query, doc) {
7
- if (doc == null) return doc;
8
-
9
- const cache = new Map();
10
- const { resolver, model, sort } = query.toObject();
11
- const fields = model.getFields().filter(f => f.getName() !== 'id');
12
-
13
- const definition = fields.reduce((prev, field) => {
14
- const name = field.getName();
15
- const $name = `$${name}`;
16
- const value = doc[name];
17
-
18
- // Field attributes
19
- prev[name] = {
20
- get() {
21
- if (cache.has(name)) return cache.get(name);
22
- let $value = field.deserialize(query, value);
23
-
24
- if ($value != null && field.isEmbedded()) {
25
- const newModel = field.getModelRef();
26
- const newQuery = query.model(newModel);
27
- const newFields = newModel.getFields().filter(f => f.getName() !== 'id');
28
- $value = new ResultSet(newQuery, map($value, v => new ResultSetItem(newQuery, v, newFields)), false);
29
- }
30
- cache.set(name, $value);
31
- return $value;
32
- },
33
- set($value) {
34
- cache.set(name, $value);
35
- },
36
- enumerable: true,
37
- configurable: true, // Allows things like delete
38
- };
39
-
40
- // Hydrated field attributes
41
- prev[`$${name}`] = {
42
- get() {
43
- return (args = {}) => {
44
- // Ensure where clause
45
- args.where = args.where || {};
46
-
47
- // Cache
48
- const cacheKey = `${$name}-${hashObject(args)}`;
49
- if (cache.has(cacheKey)) return cache.get(cacheKey);
50
-
51
- const promise = new Promise((resolve, reject) => {
52
- (() => {
53
- const $value = this[name];
54
-
55
- if (field.isScalar() || field.isEmbedded()) return Promise.resolve($value);
56
-
57
- const modelRef = field.getModelRef();
58
-
59
- if (field.isArray()) {
60
- if (field.isVirtual()) {
61
- args.where[[field.getVirtualField()]] = this.id; // Is where[[field.getVirtualField()]] correct?
62
- return resolver.match(modelRef).merge(args).many();
63
- }
64
-
65
- // Not a "required" query + strip out nulls
66
- args.where.id = $value;
67
- return resolver.match(modelRef).merge(args).many();
68
- }
69
-
70
- if (field.isVirtual()) {
71
- args.where[[field.getVirtualField()]] = this.id;
72
- return resolver.match(modelRef).merge(args).one();
73
- }
74
-
75
- return resolver.match(modelRef).id($value).one({ required: field.isRequired() });
76
- })().then((results) => {
77
- if (results == null) return field.resolve(query, results); // Allow field to determine
78
- return mapPromise(results, result => field.resolve(query, result)).then(() => results); // Resolve the inside fields but still return "results"!!!!
79
- }).then((resolved) => {
80
- resolve(resolved);
81
- }).catch((e) => {
82
- reject(e);
83
- });
84
- });
85
-
86
- cache.set(cacheKey, promise);
87
- return promise;
88
- };
89
- },
90
- enumerable: false,
91
- };
92
-
93
- // Field count (let's assume it's a Connection Type - meaning dont try with anything else)
94
- prev[`$${name}:count`] = {
95
- get() {
96
- return (q = {}) => {
97
- q.where = q.where || {};
98
- if (field.isVirtual()) q.where[field.getVirtualField()] = this.id;
99
- else q.where.id = this[name];
100
- return resolver.match(field.getModelRef()).merge(q).count();
101
- };
102
- },
103
- enumerable: false,
104
- };
105
-
106
- return prev;
107
- }, {
108
- id: {
109
- get() { return doc.id || doc[model.idKey()]; },
110
- set(id) { doc.id = id; }, // Embedded array of documents need to set id
111
- enumerable: true,
112
- },
113
-
114
- $id: {
115
- get() { return toGUID(model.getName(), this.id); },
116
- enumerable: false,
117
- },
118
-
119
- $$cursor: {
120
- get() {
121
- const sortPaths = keyPaths(sort);
122
- const sortValues = sortPaths.reduce((prv, path) => Object.assign(prv, { [path]: get(this, path) }), {});
123
- const sortJSON = JSON.stringify(sortValues);
124
- return Buffer.from(sortJSON).toString('base64');
125
- },
126
- enumerable: false,
127
- },
128
-
129
- $$model: {
130
- value: model,
131
- enumerable: false,
132
- },
133
-
134
- $$isResultSetItem: {
135
- value: true,
136
- enumerable: false,
137
- },
138
-
139
- $$save: {
140
- get() { return input => resolver.match(model).id(this.id).save({ ...this, ...input }); },
141
- enumerable: false,
142
- },
143
-
144
- $$remove: {
145
- get() { return () => resolver.match(model).id(this.id).remove(); },
146
- enumerable: false,
147
- },
148
-
149
- $$delete: {
150
- get() { return () => resolver.match(model).id(this.id).delete(); },
151
- enumerable: false,
152
- },
153
- });
154
-
155
- // Create and return ResultSetItem
156
- return Object.defineProperties(this, definition);
157
- }
158
- };
@@ -1,161 +0,0 @@
1
- const { get } = require('lodash');
2
- const ResultSet = require('./ResultSet');
3
- const { map, keyPaths, mapPromise, toGUID, hashObject } = require('../../service/app.service');
4
-
5
- module.exports = class ResultSetItem {
6
- constructor(query, doc) {
7
- if (doc == null) return doc;
8
-
9
- const cache = new Map();
10
- const { resolver, model, sort } = query.toObject();
11
- const fields = model.getFields().filter(f => f.getName() !== 'id');
12
-
13
- const proxy = new Proxy(doc, {
14
- get(target, prop, rec) {
15
- const value = Reflect.get(target, prop, rec);
16
- if (typeof value === 'function') return value.bind(target);
17
-
18
- if (cache.has(prop)) return cache.get(prop);
19
-
20
- const field = fields.find(f => `${f}` === prop);
21
-
22
- if (field) {
23
- let $value = field.deserialize(query, value);
24
-
25
- if ($value != null && field.isEmbedded()) {
26
- const newQuery = query.model(field.getModelRef());
27
- $value = new ResultSet(newQuery, map($value, v => new ResultSetItem(newQuery, v)), false);
28
- }
29
-
30
- cache.set(prop, $value);
31
- return $value;
32
- }
33
-
34
- return value;
35
- },
36
- set(target, prop, value, receiver) {
37
- cache.set(prop, value);
38
- return Reflect.set(target, prop, value);
39
- },
40
- deleteProperty(target, prop) {
41
- cache.delete(prop);
42
- return Reflect.delete(target, prop);
43
- },
44
- });
45
-
46
- const definition = fields.reduce((prev, field) => {
47
- const name = field.getName();
48
- const $name = `$${name}`;
49
-
50
- // Hydrated field attributes
51
- prev[`$${name}`] = {
52
- get() {
53
- return (args = {}) => {
54
- // Ensure where clause
55
- args.where = args.where || {};
56
-
57
- // Cache
58
- const cacheKey = `${$name}-${hashObject(args)}`;
59
- if (cache.has(cacheKey)) return cache.get(cacheKey);
60
-
61
- const promise = new Promise((resolve, reject) => {
62
- (() => {
63
- const $value = this[name];
64
-
65
- if (field.isScalar() || field.isEmbedded()) return Promise.resolve($value);
66
-
67
- const modelRef = field.getModelRef();
68
-
69
- if (field.isArray()) {
70
- if (field.isVirtual()) {
71
- args.where[[field.getVirtualField()]] = this.id; // Is where[[field.getVirtualField()]] correct?
72
- return resolver.match(modelRef).merge(args).many();
73
- }
74
-
75
- // Not a "required" query + strip out nulls
76
- args.where.id = $value;
77
- return resolver.match(modelRef).merge(args).many();
78
- }
79
-
80
- if (field.isVirtual()) {
81
- args.where[[field.getVirtualField()]] = this.id;
82
- return resolver.match(modelRef).merge(args).one();
83
- }
84
-
85
- return resolver.match(modelRef).id($value).one({ required: field.isRequired() });
86
- })().then((results) => {
87
- if (results == null) return field.resolve(query, results); // Allow field to determine
88
- return mapPromise(results, result => field.resolve(query, result)).then(() => results); // Resolve the inside fields but still return "results"!!!!
89
- }).then((resolved) => {
90
- resolve(resolved);
91
- }).catch((e) => {
92
- reject(e);
93
- });
94
- });
95
-
96
- cache.set(cacheKey, promise);
97
- return promise;
98
- };
99
- },
100
- enumerable: false,
101
- };
102
-
103
- // Field count (let's assume it's a Connection Type - meaning dont try with anything else)
104
- prev[`$${name}:count`] = {
105
- get() {
106
- return (q = {}) => {
107
- q.where = q.where || {};
108
- if (field.isVirtual()) q.where[field.getVirtualField()] = this.id;
109
- else q.where.id = this[name];
110
- return resolver.match(field.getModelRef()).merge(q).count();
111
- };
112
- },
113
- enumerable: false,
114
- };
115
-
116
- return prev;
117
- }, {
118
- $id: {
119
- get() { return toGUID(model.getName(), this.id); },
120
- enumerable: false,
121
- },
122
-
123
- $$cursor: {
124
- get() {
125
- const sortPaths = keyPaths(sort);
126
- const sortValues = sortPaths.reduce((prv, path) => Object.assign(prv, { [path]: get(this, path) }), {});
127
- const sortJSON = JSON.stringify(sortValues);
128
- return Buffer.from(sortJSON).toString('base64');
129
- },
130
- enumerable: false,
131
- },
132
-
133
- $$model: {
134
- value: model,
135
- enumerable: false,
136
- },
137
-
138
- $$isResultSetItem: {
139
- value: true,
140
- enumerable: false,
141
- },
142
-
143
- $$save: {
144
- get() { return input => resolver.match(model).id(this.id).save({ ...this, ...input }); },
145
- enumerable: false,
146
- },
147
-
148
- $$remove: {
149
- get() { return () => resolver.match(model).id(this.id).remove(); },
150
- enumerable: false,
151
- },
152
-
153
- $$delete: {
154
- get() { return () => resolver.match(model).id(this.id).delete(); },
155
- enumerable: false,
156
- },
157
- });
158
-
159
- return Object.defineProperties(proxy, definition);
160
- }
161
- };
@@ -1,141 +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, makeExecutableSchema } = 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
- * SchemaDecorator
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
- * context <Object> - Globally shared object by all resolvers
22
- * typeDefs <String|Object> - GQL String or AST Object (also supports a mixed array of both)
23
- * resolvers <Object> - GraphQL resolvers
24
- * schemaDirectives <Object> - GraphQL directives
25
- *
26
- */
27
- module.exports = class SchemaDecorator extends TypeDefApi {
28
- constructor(schema) {
29
- super();
30
- this.schema = { context: {}, typeDefs: [], resolvers: {}, schemaDirectives: {} };
31
- if (schema) this.mergeSchema(schema);
32
- }
33
-
34
- /**
35
- * Synchronously merge a schema
36
- */
37
- mergeSchema(schema, options = {}) {
38
- // Ensure this is a schema of sorts otherwise skip it
39
- if (typeof schema !== 'string' && ['context', 'typeDefs', 'resolvers', 'schemaDirectives'].every(key => !schema[key])) return this;
40
-
41
- // Here we want to normalize the schema into the shape { context, typeDefs, resolvers, schemaDirectives }
42
- // We do NOT want to modify the schema object because that may cause unwanted side-effects.
43
- const normalizedSchema = { ...schema };
44
- if (typeof schema === 'string') normalizedSchema.typeDefs = [schema];
45
- else if (schema.typeDefs && !Array.isArray(schema.typeDefs)) normalizedSchema.typeDefs = [schema.typeDefs];
46
-
47
- // For typeDefs we want the AST so that it can be intelligently merged. Here we convert
48
- // GQL strings to AST objects and also filter out anything that does not parse to AST.
49
- if (normalizedSchema.typeDefs && normalizedSchema.typeDefs.length) {
50
- normalizedSchema.typeDefs = deleteKeys(normalizedSchema.typeDefs.map((td) => {
51
- try {
52
- const ast = typeof td === 'object' ? td : parse(td);
53
- return ast.definitions;
54
- } catch (e) {
55
- return null;
56
- }
57
- }), ['loc']).filter(Boolean).flat();
58
- }
59
-
60
- // Now we're ready to merge the schema
61
- const [left, right] = options.passive ? [normalizedSchema, this.schema] : [this.schema, normalizedSchema];
62
- if (normalizedSchema.typeDefs && normalizedSchema.typeDefs.length) this.schema.typeDefs = mergeASTArray(left.typeDefs.concat(right.typeDefs));
63
- if (normalizedSchema.context) this.schema.context = Merge(left.context, right.context);
64
- if (normalizedSchema.resolvers) this.schema.resolvers = Merge(left.resolvers, right.resolvers);
65
- if (normalizedSchema.schemaDirectives) this.schema.schemaDirectives = Merge(left.schemaDirectives, right.schemaDirectives);
66
-
67
- // Chaining
68
- return this;
69
- }
70
-
71
- /**
72
- * Asynchronously load files from a given glob pattern and merge each schema
73
- */
74
- mergeSchemaFromFiles(globPattern, options) {
75
- return new Promise((resolve, reject) => {
76
- Glob(globPattern, options, (err, files) => {
77
- if (err) return reject(err);
78
-
79
- return Promise.all(files.map((file) => {
80
- return new Promise((res) => {
81
- if (file.endsWith('.js')) res(require(file)); // eslint-disable-line global-require,import/no-dynamic-require
82
- else res(FS.readFileSync(file, 'utf8'));
83
- }).then(schema => this.mergeSchema(schema, options));
84
- })).then(() => resolve(this)).catch(e => reject(e));
85
- });
86
- });
87
- }
88
-
89
- /**
90
- * Traverses the current schema's typeDefs in order to keep the TypeDefApi in sync. This operation
91
- * only needs to be called when typeDefs have been changed and you want to keep the data model in sync.
92
- */
93
- initialize() {
94
- return super.initialize(this.schema.typeDefs);
95
- }
96
-
97
- /**
98
- * Decorate the schema with Autograph's default api/definitions
99
- */
100
- decorate() {
101
- this.initialize();
102
- this.mergeSchema(frameworkExt(this), { passive: true });
103
- this.mergeSchema(typeExt(this), { passive: true });
104
- this.initialize();
105
- this.mergeSchema(apiExt(this), { passive: true });
106
- this.finalize();
107
- return this;
108
- }
109
-
110
- /**
111
- * This should be called once before passing to makeExecutableSchema()
112
- */
113
- finalize() {
114
- const definitions = visit(this.schema.typeDefs, {
115
- [Kind.FIELD_DEFINITION]: (node) => {
116
- const scope = new Node(node, 'field').getDirectiveArg('field', 'gqlScope', 'crud');
117
- if (scope === null || scope.indexOf('r') === -1) return null; // Delete node
118
- return false; // Stop traversing this node
119
- },
120
- });
121
-
122
- this.schema.typeDefs = { kind: Kind.DOCUMENT, definitions };
123
- return this;
124
- }
125
-
126
- makeExecutableSchema() {
127
- return makeExecutableSchema(this.schema);
128
- }
129
-
130
- getContext() {
131
- return this.schema.context;
132
- }
133
-
134
- toObject() {
135
- return this.schema;
136
- }
137
-
138
- toString() {
139
- return print(this.typeDefs);
140
- }
141
- };
@@ -1,84 +0,0 @@
1
- const PicoMatch = require('picomatch');
2
- const { SchemaDirectiveVisitor } = require('graphql-tools');
3
-
4
- const getCrudOperation = (mutationName) => {
5
- const crudMap = {
6
- create: 'C',
7
- add: 'C',
8
- findOrCreate: 'C',
9
- get: 'R',
10
- find: 'R',
11
- count: 'R',
12
- update: 'U',
13
- replace: 'U',
14
- edit: 'U',
15
- set: 'U',
16
- move: 'U',
17
- delete: 'D',
18
- remove: 'D',
19
- subscribe: 'S',
20
- };
21
-
22
- return Object.entries(crudMap).reduce((prev, [key, value]) => {
23
- if (prev) return prev;
24
- if (mutationName.indexOf(key) === 0) return value;
25
- return null;
26
- }, null);
27
- };
28
-
29
- const authorize = (context, model, fields, crud) => {
30
- const { schema, permissions = [] } = context.autograph;
31
- const namespace = schema.getModel(model).getNamespace();
32
- const parts = namespace.split('/').reverse();
33
-
34
- // const flags = fields.reduce((obj, field) => {
35
- // const directTargets = parts.reduce((prev, part, i) => prev.concat(`${part}/${prev[i]}`), [`${model}/${field}/${crud}`]);
36
- // let result = directTargets.some(target => PicoMatch.isMatch(target, permissions, { nocase: true }));
37
-
38
- // if (!result) {
39
- // const authorTargets = parts.reduce((prev, part, i) => prev.concat(`${part}/${prev[i]}`), [`${model}/${field}/${crud}`]);
40
- // result = authorTargets.some(target => PicoMatch.isMatch(target, permissions, { nocase: true })) ? 1 : false;
41
- // }
42
-
43
- // return Object.assign(obj, { [field]: result });
44
- // }, {});
45
-
46
- // console.log(flags);
47
- // console.log('------');
48
-
49
- const authorized = fields.every((field) => {
50
- const targets = parts.reduce((prev, part, i) => prev.concat(`${part}/${prev[i]}`), [`${model}/${field}/${crud}`]);
51
- return targets.some(target => PicoMatch.isMatch(target, permissions, { nocase: true }));
52
- });
53
-
54
- if (!authorized) throw new Error('Not Authorized');
55
- };
56
-
57
- module.exports = class extends SchemaDirectiveVisitor {
58
- visitObject(type) { // eslint-disable-line
59
- const fields = type.getFields();
60
-
61
- Object.keys(fields).forEach((fieldName) => {
62
- const field = fields[fieldName];
63
- const { resolve = root => root[fieldName] } = field;
64
- const { model = `${type}` } = this.args;
65
-
66
- field.resolve = async function resolver(root, args, context, info) {
67
- authorize(context, model, [fieldName], 'R');
68
- return resolve.call(this, root, args, context, info);
69
- };
70
- });
71
- }
72
-
73
- visitFieldDefinition(field, details) { // eslint-disable-line
74
- const { name, type, resolve = root => root[name] } = field;
75
- const dataType = type.toString().replace(/[[\]!]/g, '');
76
- const crudOperation = getCrudOperation(name);
77
- const { model = dataType } = this.args;
78
-
79
- field.resolve = async function resolver(root, args, context, info) {
80
- authorize(context, model, Object.keys(args.input || { id: 1 }), crudOperation);
81
- return resolve.call(this, root, args, context, info);
82
- };
83
- }
84
- };