@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.
- package/CHANGELOG.md +20 -3
- package/index.js +2 -8
- package/package.json +5 -7
- package/src/.DS_Store +0 -0
- package/src/core/EventEmitter.js +2 -4
- package/src/core/Resolver.js +32 -57
- package/src/core/Schema.js +5 -38
- package/src/data/.DS_Store +0 -0
- package/src/data/DataLoader.js +71 -32
- package/src/data/DataService.js +82 -59
- package/src/data/Field.js +59 -126
- package/src/data/Model.js +113 -105
- package/src/data/Pipeline.js +184 -0
- package/src/data/Type.js +38 -74
- package/src/driver/MongoDriver.js +27 -22
- package/src/graphql/.DS_Store +0 -0
- package/src/graphql/ast/Field.js +46 -24
- package/src/graphql/ast/Model.js +5 -16
- package/src/graphql/ast/Node.js +0 -25
- package/src/graphql/ast/Schema.js +105 -112
- package/src/graphql/extension/api.js +20 -18
- package/src/graphql/extension/framework.js +27 -33
- package/src/graphql/extension/type.js +2 -2
- package/src/query/Query.js +82 -14
- package/src/query/QueryBuilder.js +38 -30
- package/src/query/QueryBuilderTransaction.js +3 -3
- package/src/query/QueryResolver.js +77 -41
- package/src/query/QueryService.js +24 -42
- package/src/service/app.service.js +70 -13
- package/src/service/event.service.js +30 -73
- package/src/service/graphql.service.js +0 -9
- package/src/service/schema.service.js +5 -3
- package/src/core/GraphQL.js +0 -21
- package/src/core/Rule.js +0 -107
- package/src/core/SchemaDecorator.js +0 -46
- package/src/core/Transformer.js +0 -68
- package/src/data/Memoizer.js +0 -39
- package/src/data/ResultSet.js +0 -205
- package/src/data/stream/DataHydrator.js +0 -58
- package/src/data/stream/ResultSet.js +0 -34
- package/src/data/stream/ResultSetItem.js +0 -158
- package/src/data/stream/ResultSetItemProxy.js +0 -161
- package/src/graphql/ast/SchemaDecorator.js +0 -141
- package/src/graphql/directive/authz.directive.js +0 -84
package/src/data/Type.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const Type = require('../graphql/ast/Type');
|
|
2
|
-
const
|
|
3
|
-
const Transformer = require('../core/Transformer');
|
|
2
|
+
const Pipeline = require('./Pipeline');
|
|
4
3
|
|
|
5
4
|
module.exports = class extends Type {
|
|
6
5
|
constructor(field) {
|
|
@@ -8,79 +7,44 @@ module.exports = class extends Type {
|
|
|
8
7
|
this.field = field;
|
|
9
8
|
}
|
|
10
9
|
|
|
11
|
-
|
|
12
|
-
const
|
|
13
|
-
const scalarType = this.field.getScalarRef();
|
|
10
|
+
getStructures() {
|
|
11
|
+
const type = this.field.getType();
|
|
14
12
|
const enumType = this.field.getEnumRef();
|
|
15
|
-
|
|
16
|
-
if (scalarType) {
|
|
17
|
-
Object.entries(scalarType.getDirectiveArgs('field', {})).forEach(([key, value]) => {
|
|
18
|
-
if (!Array.isArray(value)) value = [value];
|
|
19
|
-
if (key === 'enforce') rules.push(...value.map(r => Rule.getInstances()[r]));
|
|
20
|
-
});
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
if (enumType) {
|
|
24
|
-
const values = enumType.getValue();
|
|
25
|
-
rules.push(Rule.allow(...values));
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
return rules;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
getTransformers() {
|
|
32
|
-
const transformers = [];
|
|
33
13
|
const scalarType = this.field.getScalarRef();
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
return transformers;
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
getResolvers() {
|
|
74
|
-
const resolvers = [];
|
|
75
|
-
const scalarType = this.field.getScalarRef();
|
|
76
|
-
|
|
77
|
-
if (scalarType) {
|
|
78
|
-
Object.entries(scalarType.getDirectiveArgs('field', {})).forEach(([key, value]) => {
|
|
79
|
-
if (!Array.isArray(value)) value = [value];
|
|
80
|
-
if (key === 'resolve') resolvers.push(...value.map(t => Transformer.getInstances()[t]));
|
|
81
|
-
});
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
return resolvers;
|
|
14
|
+
const structures = {
|
|
15
|
+
validators: [],
|
|
16
|
+
instructs: [],
|
|
17
|
+
restructs: [],
|
|
18
|
+
destructs: [],
|
|
19
|
+
constructs: [],
|
|
20
|
+
normalizers: [],
|
|
21
|
+
$serializers: [],
|
|
22
|
+
$deserializers: [],
|
|
23
|
+
serializers: [],
|
|
24
|
+
deserializers: [],
|
|
25
|
+
transforms: [],
|
|
26
|
+
};
|
|
27
|
+
|
|
28
|
+
// Built-in pipelines
|
|
29
|
+
structures.castValue = Pipeline.castValue;
|
|
30
|
+
structures.defaultValue = Pipeline.defaultValue;
|
|
31
|
+
structures.ensureArrayValue = Pipeline.ensureArrayValue;
|
|
32
|
+
|
|
33
|
+
if (enumType) structures.validators.push(Pipeline.define(`allow:${type}`, Pipeline.Allow(...enumType.getValue()), { configurable: true }));
|
|
34
|
+
if (!scalarType) return structures;
|
|
35
|
+
|
|
36
|
+
return Object.entries(scalarType.getDirectiveArgs('field', {})).reduce((prev, [key, value]) => {
|
|
37
|
+
if (!Array.isArray(value)) value = [value];
|
|
38
|
+
if (key === 'validate') prev.validators.push(...value.map(t => Pipeline[t]));
|
|
39
|
+
if (key === 'instruct') prev.instructs.push(...value.map(t => Pipeline[t]));
|
|
40
|
+
if (key === 'restruct') prev.restructs.push(...value.map(t => Pipeline[t]));
|
|
41
|
+
if (key === 'destruct') prev.destructs.push(...value.map(t => Pipeline[t]));
|
|
42
|
+
if (key === 'construct') prev.constructs.push(...value.map(t => Pipeline[t]));
|
|
43
|
+
if (key === 'transform') prev.transforms.push(...value.map(t => Pipeline[t]));
|
|
44
|
+
if (key === 'normalize') prev.normalizers.push(...value.map(t => Pipeline[t]));
|
|
45
|
+
if (key === 'serialize') prev.serializers.push(...value.map(t => Pipeline[t]));
|
|
46
|
+
if (key === 'deserialize') prev.deserializers.push(...value.map(t => Pipeline[t]));
|
|
47
|
+
return prev;
|
|
48
|
+
}, structures);
|
|
85
49
|
}
|
|
86
50
|
};
|
|
@@ -1,6 +1,7 @@
|
|
|
1
|
-
const
|
|
2
|
-
const {
|
|
3
|
-
const {
|
|
1
|
+
const Util = require('util');
|
|
2
|
+
const { get } = require('lodash');
|
|
3
|
+
const { MongoClient, ObjectId } = require('mongodb');
|
|
4
|
+
const { map, ensureArray, proxyDeep, toKeyObj, globToRegex, proxyPromise, isScalarDataType, promiseRetry } = require('../service/app.service');
|
|
4
5
|
|
|
5
6
|
module.exports = class MongoDriver {
|
|
6
7
|
constructor(config) {
|
|
@@ -24,7 +25,7 @@ module.exports = class MongoDriver {
|
|
|
24
25
|
}
|
|
25
26
|
|
|
26
27
|
query(collection, method, ...args) {
|
|
27
|
-
if (
|
|
28
|
+
if (get(args[args.length - 1], 'debug') === true) console.log(collection, method, Util.inspect(args, { depth: null, showHidden: false, colors: true }));
|
|
28
29
|
if (method === 'aggregate') args.splice(2);
|
|
29
30
|
return this.raw(collection)[method](...args);
|
|
30
31
|
}
|
|
@@ -48,10 +49,7 @@ module.exports = class MongoDriver {
|
|
|
48
49
|
findMany(query) {
|
|
49
50
|
const { model, options = {}, flags } = query;
|
|
50
51
|
Object.assign(options, this.config.query || {});
|
|
51
|
-
|
|
52
|
-
return this.query(model, 'aggregate', MongoDriver.aggregateQuery(query), options, flags).then((cursor) => {
|
|
53
|
-
return cursor.stream();
|
|
54
|
-
});
|
|
52
|
+
return this.query(model, 'aggregate', MongoDriver.aggregateQuery(query), options, flags).then(cursor => cursor.stream());
|
|
55
53
|
}
|
|
56
54
|
|
|
57
55
|
count(query) {
|
|
@@ -128,10 +126,10 @@ module.exports = class MongoDriver {
|
|
|
128
126
|
}
|
|
129
127
|
|
|
130
128
|
static idValue(value) {
|
|
131
|
-
if (value instanceof
|
|
129
|
+
if (value instanceof ObjectId) return value;
|
|
132
130
|
|
|
133
131
|
try {
|
|
134
|
-
const id =
|
|
132
|
+
const id = ObjectId(value);
|
|
135
133
|
return id;
|
|
136
134
|
} catch (e) {
|
|
137
135
|
return value;
|
|
@@ -142,10 +140,13 @@ module.exports = class MongoDriver {
|
|
|
142
140
|
return proxyDeep(toKeyObj(where), {
|
|
143
141
|
get(target, prop, rec) {
|
|
144
142
|
const value = Reflect.get(target, prop, rec);
|
|
145
|
-
if (Array.isArray(value)) return { $in: value };
|
|
146
143
|
if (typeof value === 'function') return value.bind(target);
|
|
147
|
-
|
|
148
|
-
|
|
144
|
+
const $value = map(value, v => (typeof v === 'string' ? globToRegex(v, { nocase: true, regex: true }) : v));
|
|
145
|
+
if (Array.isArray($value)) {
|
|
146
|
+
// console.log(Util.inspect({ value, $value }, { depth: null, showHidden: false, colors: true }));
|
|
147
|
+
return { $in: $value };
|
|
148
|
+
}
|
|
149
|
+
return $value;
|
|
149
150
|
},
|
|
150
151
|
}).toObject();
|
|
151
152
|
}
|
|
@@ -153,13 +154,17 @@ module.exports = class MongoDriver {
|
|
|
153
154
|
static getAddFields(query) {
|
|
154
155
|
const { shape, where } = query;
|
|
155
156
|
|
|
156
|
-
return shape.reduce((prev, { from, type }) => {
|
|
157
|
-
|
|
157
|
+
return shape.reduce((prev, { from, type, isArray }) => {
|
|
158
|
+
// Basic checks to see if worth converting for regex
|
|
159
|
+
let value = where[from];
|
|
158
160
|
if (value === undefined) return prev;
|
|
159
161
|
if (!isScalarDataType(type)) return prev;
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
162
|
+
|
|
163
|
+
// Do regex conversion
|
|
164
|
+
if (isArray) value = value.$in || value; // Where clause does not always use $in
|
|
165
|
+
if (!ensureArray(value).some(el => el instanceof RegExp)) return prev;
|
|
166
|
+
const conversion = isArray ? { $map: { input: `$${from}`, as: 'el', in: { $toString: '$$el' } } } : { $toString: `$${from}` };
|
|
167
|
+
return Object.assign(prev, { [from]: conversion });
|
|
163
168
|
}, {});
|
|
164
169
|
}
|
|
165
170
|
|
|
@@ -182,7 +187,7 @@ module.exports = class MongoDriver {
|
|
|
182
187
|
}
|
|
183
188
|
|
|
184
189
|
static aggregateQuery(query, count = false) {
|
|
185
|
-
const { where: $match, sort = {}, skip, limit, joins,
|
|
190
|
+
const { where: $match, sort = {}, skip, limit, joins, after, before, first } = query;
|
|
186
191
|
const $aggregate = [{ $match }];
|
|
187
192
|
|
|
188
193
|
// Used for $regex matching
|
|
@@ -215,9 +220,9 @@ module.exports = class MongoDriver {
|
|
|
215
220
|
if (before) $aggregate.push({ $match: { $or: Object.entries(before).reduce((prev, [key, value]) => prev.concat({ [key]: { [sort[key] === 1 ? '$lte' : '$gte']: value } }), []) } });
|
|
216
221
|
if (first) $aggregate.push({ $limit: first });
|
|
217
222
|
|
|
218
|
-
// Projection
|
|
219
|
-
const $project = MongoDriver.getProjectFields(shape);
|
|
220
|
-
$aggregate.push({ $project });
|
|
223
|
+
// // Projection
|
|
224
|
+
// const $project = MongoDriver.getProjectFields(shape);
|
|
225
|
+
// $aggregate.push({ $project });
|
|
221
226
|
}
|
|
222
227
|
|
|
223
228
|
return $aggregate;
|
package/src/graphql/.DS_Store
CHANGED
|
Binary file
|
package/src/graphql/ast/Field.js
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const { get } = require('lodash');
|
|
2
1
|
const Node = require('./Node');
|
|
3
2
|
const Type = require('./Type');
|
|
4
3
|
const { uvl } = require('../../service/app.service');
|
|
@@ -44,27 +43,6 @@ module.exports = class Field extends Node {
|
|
|
44
43
|
return this.getDirectiveArg('field', 'default');
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
resolveBoundValue(query, initialValue) {
|
|
48
|
-
// If no bound value, return default value
|
|
49
|
-
const defaultValue = uvl(initialValue, this.getDefaultValue());
|
|
50
|
-
if (!this.hasBoundValue()) return defaultValue;
|
|
51
|
-
|
|
52
|
-
// Grab @value definition, if passive then check for initialValue
|
|
53
|
-
const { scope, path, passive = false } = this.getDirectiveArgs('value');
|
|
54
|
-
if (passive && initialValue !== undefined) return initialValue;
|
|
55
|
-
|
|
56
|
-
// Resolve @value
|
|
57
|
-
switch (scope) {
|
|
58
|
-
case 'context': {
|
|
59
|
-
const { resolver } = query.toObject();
|
|
60
|
-
const context = resolver.getContext();
|
|
61
|
-
const value = get(context, path);
|
|
62
|
-
return uvl((typeof value === 'function') ? value() : value, defaultValue);
|
|
63
|
-
}
|
|
64
|
-
default: return this[path];
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
46
|
// Model Methods
|
|
69
47
|
getSchema() {
|
|
70
48
|
return this.model.getSchema();
|
|
@@ -75,7 +53,8 @@ module.exports = class Field extends Node {
|
|
|
75
53
|
}
|
|
76
54
|
|
|
77
55
|
getModelRef() {
|
|
78
|
-
|
|
56
|
+
const refType = this.getDirectiveArg('field', 'id', this.getType());
|
|
57
|
+
return this.schema.getModel(refType);
|
|
79
58
|
}
|
|
80
59
|
|
|
81
60
|
getFieldRef() {
|
|
@@ -90,6 +69,10 @@ module.exports = class Field extends Node {
|
|
|
90
69
|
return model ? model.getField(this.getVirtualRef()) : null;
|
|
91
70
|
}
|
|
92
71
|
|
|
72
|
+
getIdModel() {
|
|
73
|
+
return this.getModelRef() || this.getModel();
|
|
74
|
+
}
|
|
75
|
+
|
|
93
76
|
resolveField() {
|
|
94
77
|
const field = this.getVirtualField() || this;
|
|
95
78
|
return field === this ? this : field.resolveField();
|
|
@@ -101,7 +84,7 @@ module.exports = class Field extends Node {
|
|
|
101
84
|
}
|
|
102
85
|
|
|
103
86
|
isDefaulted() {
|
|
104
|
-
return Boolean(this.
|
|
87
|
+
return Boolean(this.getDefaultValue() != null);
|
|
105
88
|
}
|
|
106
89
|
|
|
107
90
|
isRequired() {
|
|
@@ -117,6 +100,16 @@ module.exports = class Field extends Node {
|
|
|
117
100
|
return Boolean(modelRef && !this.isEmbedded());
|
|
118
101
|
}
|
|
119
102
|
|
|
103
|
+
isIdField() {
|
|
104
|
+
return this.isPrimaryKeyId() || this.isFKReference();
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
isPrimaryKeyId() {
|
|
108
|
+
const key = this.getKey();
|
|
109
|
+
const idKey = this.getModel().idKey();
|
|
110
|
+
return key === idKey;
|
|
111
|
+
}
|
|
112
|
+
|
|
120
113
|
getJoinInfo() {
|
|
121
114
|
const modelRef = this.getModelRef();
|
|
122
115
|
if (!modelRef || this.isEmbedded()) return null;
|
|
@@ -179,4 +172,33 @@ module.exports = class Field extends Node {
|
|
|
179
172
|
if (this.isFKReference()) return this.isArray() ? '[ID]' : 'ID';
|
|
180
173
|
return this.getGQLType();
|
|
181
174
|
}
|
|
175
|
+
|
|
176
|
+
initialize() {
|
|
177
|
+
this.props = {
|
|
178
|
+
key: this.getKey(),
|
|
179
|
+
name: this.getName(),
|
|
180
|
+
type: this.getType(),
|
|
181
|
+
model: this.model,
|
|
182
|
+
datatype: this.getDataType(),
|
|
183
|
+
defaultValue: this.getDefaultValue(),
|
|
184
|
+
isArray: this.isArray(),
|
|
185
|
+
isScalar: this.isScalar(),
|
|
186
|
+
isVirtual: this.isVirtual(),
|
|
187
|
+
isRequired: this.isRequired(),
|
|
188
|
+
isEmbedded: this.isEmbedded(),
|
|
189
|
+
isIdField: this.isIdField(),
|
|
190
|
+
isPrimaryKeyId: this.isPrimaryKeyId(),
|
|
191
|
+
isPersistable: this.isPersistable(),
|
|
192
|
+
idModel: this.getIdModel(),
|
|
193
|
+
modelRef: this.getModelRef(),
|
|
194
|
+
virtualRef: this.getVirtualRef(),
|
|
195
|
+
virtualField: this.getVirtualField(),
|
|
196
|
+
};
|
|
197
|
+
|
|
198
|
+
return this;
|
|
199
|
+
}
|
|
200
|
+
|
|
201
|
+
toObject() {
|
|
202
|
+
return this.props;
|
|
203
|
+
}
|
|
182
204
|
};
|
package/src/graphql/ast/Model.js
CHANGED
|
@@ -92,10 +92,6 @@ module.exports = class Model extends Node {
|
|
|
92
92
|
return this.getFields().filter(field => field.isDefaulted());
|
|
93
93
|
}
|
|
94
94
|
|
|
95
|
-
getBoundValueFields() {
|
|
96
|
-
return this.getFields().filter(field => field.hasBoundValue());
|
|
97
|
-
}
|
|
98
|
-
|
|
99
95
|
getDataRefFields() {
|
|
100
96
|
return this.getFields().filter(field => Boolean(field.getDataRef()));
|
|
101
97
|
}
|
|
@@ -104,10 +100,6 @@ module.exports = class Model extends Node {
|
|
|
104
100
|
return this.getFields().filter(field => Boolean(field.getModelRef()));
|
|
105
101
|
}
|
|
106
102
|
|
|
107
|
-
// getDataRefFields() {
|
|
108
|
-
// return this.fields.filter(field => Boolean(field.getDataRef() && !field.isEmbedded()));
|
|
109
|
-
// }
|
|
110
|
-
|
|
111
103
|
getEmbeddedFields() {
|
|
112
104
|
return this.getFields().filter(field => field.isEmbedded());
|
|
113
105
|
}
|
|
@@ -128,14 +120,6 @@ module.exports = class Model extends Node {
|
|
|
128
120
|
return this.getFields().filter(field => field.isPersistable());
|
|
129
121
|
}
|
|
130
122
|
|
|
131
|
-
getSerializeFields() {
|
|
132
|
-
return this.getFields().filter(field => field.getSerializers().length);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
getDeserializeFields() {
|
|
136
|
-
return this.getFields().filter(field => field.getDeserializers().length);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
123
|
// Misc
|
|
140
124
|
getIndexes() {
|
|
141
125
|
return this.getDirectives('index').map((d) => {
|
|
@@ -153,4 +137,9 @@ module.exports = class Model extends Node {
|
|
|
153
137
|
}, {});
|
|
154
138
|
});
|
|
155
139
|
}
|
|
140
|
+
|
|
141
|
+
initialize() {
|
|
142
|
+
this.fields.forEach(field => field.initialize());
|
|
143
|
+
return this;
|
|
144
|
+
}
|
|
156
145
|
};
|
package/src/graphql/ast/Node.js
CHANGED
|
@@ -2,7 +2,6 @@ const { get } = require('lodash');
|
|
|
2
2
|
const { Kind } = require('graphql');
|
|
3
3
|
const { nvl, uvl } = require('../../service/app.service');
|
|
4
4
|
const { mergeAST } = require('../../service/graphql.service');
|
|
5
|
-
// const Memoizer = require('../../data/Memoizer');
|
|
6
5
|
|
|
7
6
|
const operations = ['Query', 'Mutation', 'Subscription'];
|
|
8
7
|
const modelKinds = [Kind.OBJECT_TYPE_DEFINITION, Kind.OBJECT_TYPE_EXTENSION, Kind.INTERFACE_TYPE_DEFINITION, Kind.INTERFACE_TYPE_EXTENSION];
|
|
@@ -18,7 +17,6 @@ module.exports = class Node {
|
|
|
18
17
|
this.toString = () => this.getName();
|
|
19
18
|
this.nodeType = nodeType;
|
|
20
19
|
this.name = get(this.ast, 'name.value');
|
|
21
|
-
// return new Memoizer(this, Object.getOwnPropertyNames(Node.prototype).filter(m => ['getContext'].indexOf(m) === -1));
|
|
22
20
|
}
|
|
23
21
|
|
|
24
22
|
// Basic AST Methods
|
|
@@ -130,14 +128,6 @@ module.exports = class Node {
|
|
|
130
128
|
return this.getDirectiveArg('model', 'meta');
|
|
131
129
|
}
|
|
132
130
|
|
|
133
|
-
getSerialize() {
|
|
134
|
-
return this.getDirectiveArg('field', 'serialize', this.getDirectiveArg('model', 'serialize'));
|
|
135
|
-
}
|
|
136
|
-
|
|
137
|
-
getDeserialize() {
|
|
138
|
-
return this.getDirectiveArg('field', 'deserialize', this.getDirectiveArg('model', 'deserialize'));
|
|
139
|
-
}
|
|
140
|
-
|
|
141
131
|
// Booleans
|
|
142
132
|
isModel() {
|
|
143
133
|
return Boolean(modelKinds.some(k => this.getKind() === k) && operations.every(o => this.getName() !== o));
|
|
@@ -166,13 +156,6 @@ module.exports = class Node {
|
|
|
166
156
|
return Boolean(this.getDirectiveArg('link', 'by'));
|
|
167
157
|
}
|
|
168
158
|
|
|
169
|
-
/**
|
|
170
|
-
* Does the model/field have a bound @value directive
|
|
171
|
-
*/
|
|
172
|
-
hasBoundValue() {
|
|
173
|
-
return Boolean(this.getDirective('value'));
|
|
174
|
-
}
|
|
175
|
-
|
|
176
159
|
/**
|
|
177
160
|
* Is a model annotated with @model
|
|
178
161
|
*/
|
|
@@ -208,14 +191,6 @@ module.exports = class Node {
|
|
|
208
191
|
}
|
|
209
192
|
}
|
|
210
193
|
|
|
211
|
-
/**
|
|
212
|
-
* Can the field be changed after it's set
|
|
213
|
-
*/
|
|
214
|
-
isImmutable() {
|
|
215
|
-
const enforce = this.getDirectiveArg('field', 'enforce', '');
|
|
216
|
-
return Boolean(JSON.stringify(enforce).indexOf('immutable') > -1);
|
|
217
|
-
}
|
|
218
|
-
|
|
219
194
|
/**
|
|
220
195
|
* Define it's behavior at the Data Access Layer
|
|
221
196
|
*
|