alchemymvc 1.2.0 → 1.2.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.
@@ -5,9 +5,14 @@
5
5
  *
6
6
  * @author Jelle De Loecker <jelle@develry.be>
7
7
  * @since 0.2.0
8
- * @version 1.1.0
8
+ * @version 1.2.1
9
9
  */
10
10
  var Enum = Function.inherits('Alchemy.Field', function Enum(schema, name, options) {
11
+
12
+ if (options.values) {
13
+ options.values = new Classes.Alchemy.Map.Enum(options.values);
14
+ }
15
+
11
16
  Enum.super.call(this, schema, name, options);
12
17
  });
13
18
 
@@ -40,9 +45,9 @@ Enum.setMethod(function cast(value) {
40
45
  *
41
46
  * @author Jelle De Loecker <jelle@develry.be>
42
47
  * @since 0.2.0
43
- * @version 0.2.0
48
+ * @version 1.2.1
44
49
  *
45
- * @return {Object}
50
+ * @return {EnumValues}
46
51
  */
47
52
  Enum.setMethod(function getValues() {
48
53
 
@@ -62,7 +67,7 @@ Enum.setMethod(function getValues() {
62
67
  *
63
68
  * @author Jelle De Loecker <jelle@develry.be>
64
69
  * @since 1.1.0
65
- * @version 1.1.0
70
+ * @version 1.2.1
66
71
  *
67
72
  * @param {WeakMap} wm
68
73
  *
@@ -72,37 +77,5 @@ Enum.setMethod(function getClientConfigOptions(wm) {
72
77
 
73
78
  let options = JSON.clone(this.options, 'toHawkejs', wm);
74
79
 
75
- if (this.options.values) {
76
- let value,
77
- entry,
78
- key;
79
-
80
- if (!options.values) {
81
- options.values = {};
82
- }
83
-
84
- for (key in this.options.values) {
85
-
86
- if (options.values[key]) {
87
- continue;
88
- }
89
-
90
- value = this.options.values[key];
91
-
92
- if (typeof value == 'function') {
93
- entry = {
94
- name : value.name,
95
- title : value.title,
96
- };
97
-
98
- if (value.schema) {
99
- entry.schema = JSON.clone(value.schema, 'toHawkejs', wm);
100
- }
101
-
102
- options.values[key] = entry;
103
- }
104
- }
105
- }
106
-
107
80
  return options;
108
81
  });
@@ -91,7 +91,7 @@ SchemaField.setProperty(function requires_translating() {
91
91
  *
92
92
  * @author Jelle De Loecker <jelle@develry.be>
93
93
  * @since 0.2.0
94
- * @version 0.4.0
94
+ * @version 1.2.1
95
95
  *
96
96
  * @param {Object} record
97
97
  * @param {String} some_path Some path to a field in the wanted schema
@@ -106,8 +106,7 @@ SchemaField.setMethod(function getSubschema(record, some_path) {
106
106
  record_value,
107
107
  pieces,
108
108
  field,
109
- name,
110
- temp;
109
+ name;
111
110
 
112
111
  // If schema is a string,
113
112
  // it needs to be extracted from another field's value
@@ -131,9 +130,9 @@ SchemaField.setMethod(function getSubschema(record, some_path) {
131
130
  }
132
131
 
133
132
  // Get the values that field can have (probably an enum)
134
- temp = field.getValues();
133
+ let values = field.getValues();
135
134
 
136
- if (temp == null) {
135
+ if (values == null) {
137
136
  return null;
138
137
  }
139
138
 
@@ -146,23 +145,14 @@ SchemaField.setMethod(function getSubschema(record, some_path) {
146
145
  }
147
146
 
148
147
  // Get the correct field value
149
- temp = temp[record_value];
150
-
151
- if (temp != null) {
152
- schema = temp[property_name];
148
+ let enum_value = values.get(record_value);
153
149
 
154
- if (schema == null && typeof temp == 'function') {
155
- temp = new temp();
156
- schema = temp[property_name] || temp.schema || temp.blueprint;
157
-
158
- if (schema != null) {
159
- schema.setModel(this.schema.model_name);
160
- schema.setName(this.name);
161
- schema.setParent(this.schema);
162
- }
163
- }
164
- } else {
150
+ if (!enum_value) {
165
151
  schema = null;
152
+ } else if (enum_value.schema) {
153
+ schema = enum_value.schema;
154
+ } else if (enum_value.value) {
155
+ schema = enum_value.value[property_name] || enum_value.value.schema;
166
156
  }
167
157
  }
168
158
 
@@ -243,7 +233,7 @@ SchemaField.setMethod(function _toDatasource(value, data, datasource, callback)
243
233
  }
244
234
  }
245
235
 
246
- log.warning('Model and subschema were not found for', that.name);
236
+ log.warning('Model and subschema were not found for', that.path);
247
237
  return datasource.toDatasource(null, value, callback);
248
238
  });
249
239
 
@@ -59,7 +59,7 @@ Criteria.setStatic(function isCriteria(instance) {
59
59
  *
60
60
  * @author Jelle De Loecker <jelle@develry.be>
61
61
  * @since 1.1.0
62
- * @version 1.1.5
62
+ * @version 1.2.3
63
63
  *
64
64
  * @param {Object} data
65
65
  *
@@ -81,10 +81,14 @@ Criteria.setStatic(function unDry(data) {
81
81
  // Revive the group instance
82
82
  criteria.group = Group.revive(data.group, criteria);
83
83
 
84
+ if(!data.options) {
85
+ data.options = {};
86
+ }
87
+
84
88
  // Revive the select
85
89
  data.options.select = Select.revive(data.options.select, criteria);
86
90
 
87
- criteria.options = data.options;
91
+ criteria.options = data.options || {};
88
92
 
89
93
  return criteria;
90
94
  });
@@ -248,7 +252,7 @@ Criteria.setProperty(function recursive_level() {
248
252
  *
249
253
  * @author Jelle De Loecker <jelle@develry.be>
250
254
  * @since 1.1.0
251
- * @version 1.1.0
255
+ * @version 1.2.3
252
256
  */
253
257
  Criteria.setMethod(Blast.checksumSymbol, function toChecksum() {
254
258
 
@@ -259,7 +263,7 @@ Criteria.setMethod(Blast.checksumSymbol, function toChecksum() {
259
263
 
260
264
  for (key in this.options) {
261
265
 
262
- if (key == 'init_model' || key == 'init_record') {
266
+ if (key == 'init_model' || key == 'init_record' || key == 'assoc_cache') {
263
267
  continue;
264
268
  }
265
269
 
@@ -319,21 +323,30 @@ Criteria.setMethod(Symbol.asyncIterator, function asyncIterator() {
319
323
  *
320
324
  * @author Jelle De Loecker <jelle@develry.be>
321
325
  * @since 1.1.0
322
- * @version 1.1.5
326
+ * @version 1.2.3
323
327
  *
324
328
  * @return {Object}
325
329
  */
326
330
  Criteria.setMethod(function toJSON() {
327
331
 
328
- var result = {},
329
- options = Object.assign({}, this.options);
332
+ let result = {},
333
+ options;
330
334
 
331
335
  if (this.model && this.model.name) {
332
336
  result.model = this.model.name;
333
337
  }
334
338
 
335
- if (options.init_record) {
336
- options.init_record = null;
339
+ if (this.options) {
340
+ let key;
341
+ options = {};
342
+
343
+ for (key in this.options) {
344
+ if (key == 'assoc_cache' || key == 'init_record') {
345
+ continue;
346
+ }
347
+
348
+ options[key] = this.options[key];
349
+ }
337
350
  }
338
351
 
339
352
  result.group = this.group;
@@ -388,7 +401,7 @@ Criteria.setMethod(function clone() {
388
401
  *
389
402
  * @author Jelle De Loecker <jelle@develry.be>
390
403
  * @since 1.1.0
391
- * @version 1.2.0
404
+ * @version 1.2.3
392
405
  *
393
406
  * @return {String[]}
394
407
  */
@@ -396,14 +409,14 @@ Criteria.setMethod(function getFieldsToSelect() {
396
409
 
397
410
  let result;
398
411
 
399
- if (this.options.select.fields && this.options.select.fields.length) {
412
+ if (this.options?.select?.fields?.length) {
400
413
  result = this.options.select.fields.slice(0);
401
414
  }
402
415
 
403
416
  // Fields can sometimes be required for a query (like in a join) but they
404
417
  // won't be selected if other fields are explicitly set.
405
418
  // So in that case: add these special fields to the projection
406
- if (result && this.options.select.query_fields && this.options.select.query_fields) {
419
+ if (result && this.options?.select?.query_fields) {
407
420
  result.push(...this.options.select.query_fields);
408
421
  }
409
422
 
@@ -479,7 +492,7 @@ Criteria.setMethod(function getAssociationConfiguration(alias) {
479
492
  *
480
493
  * @author Jelle De Loecker <jelle@develry.be>
481
494
  * @since 1.1.0
482
- * @version 1.1.0
495
+ * @version 1.2.3
483
496
  *
484
497
  * @param {String} name
485
498
  * @param {Object} item
@@ -524,6 +537,16 @@ Criteria.setMethod(function getCriteriaForAssociation(name, item) {
524
537
  assoc_crit.setOption('assoc_key', assoc_key);
525
538
  assoc_crit.setOption('assoc_value', value);
526
539
 
540
+ // Make the assoc_cache if it doesn't exist yet
541
+ if (options.create_references !== false && !options.assoc_cache) {
542
+ options.assoc_cache = {};
543
+ }
544
+
545
+ // Add the assoc_cache
546
+ if (options.assoc_cache) {
547
+ assoc_crit.setOption('assoc_cache', options.assoc_cache);
548
+ }
549
+
527
550
  // Take over the locale option
528
551
  if (options.locale) {
529
552
  assoc_crit.setOption('locale', options.locale);
@@ -1310,13 +1333,17 @@ var Select = Function.inherits('Alchemy.Base', 'Alchemy.Criteria', function Sele
1310
1333
  *
1311
1334
  * @author Jelle De Loecker <jelle@develry.be>
1312
1335
  * @since 1.1.0
1313
- * @version 1.1.0
1336
+ * @version 1.2.3
1314
1337
  *
1315
1338
  * @return {Select}
1316
1339
  */
1317
1340
  Select.setStatic(function revive(data, criteria) {
1318
1341
 
1319
- var result = new Select(criteria),
1342
+ if (!data) {
1343
+ return;
1344
+ }
1345
+
1346
+ let result = new Select(criteria),
1320
1347
  key;
1321
1348
 
1322
1349
  result.fields = data.fields;
@@ -0,0 +1,92 @@
1
+ /**
2
+ * The DataProvider class
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 1.2.2
6
+ * @version 1.2.2
7
+ */
8
+ const DataProvider = Function.inherits('Alchemy.Base', 'Alchemy.DataProvider', function DataProvider(config) {
9
+ this.config = config || {};
10
+ });
11
+
12
+
13
+ /**
14
+ * Undry
15
+ *
16
+ * @author Jelle De Loecker <jelle@elevenways.be>
17
+ * @since 1.2.2
18
+ * @version 1.2.2
19
+ *
20
+ * @param {Object} obj
21
+ * @param {Boolean|String} cloned
22
+ *
23
+ * @return {DataProvider}
24
+ */
25
+ DataProvider.setStatic(function unDry(obj) {
26
+ let result = new this(obj.config);
27
+ return result;
28
+ });
29
+
30
+ /**
31
+ * Configure a new config
32
+ *
33
+ * @author Jelle De Loecker <jelle@elevenways.be>
34
+ * @since 1.2.2
35
+ * @version 1.2.2
36
+ */
37
+ DataProvider.setStatic(function addConfig(name, default_value) {
38
+ this.setProperty(name, function getValue() {
39
+
40
+ if (this.config[name] != null) {
41
+ return this.config[name];
42
+ }
43
+
44
+ return default_value;
45
+ }, function setValue(value) {
46
+ return this.config[name] = value;
47
+ });
48
+ });
49
+
50
+ /**
51
+ * The wanted page size
52
+ *
53
+ * @author Jelle De Loecker <jelle@elevenways.be>
54
+ * @since 1.2.2
55
+ * @version 1.2.2
56
+ */
57
+ DataProvider.addConfig('page_size');
58
+
59
+ /**
60
+ * Get all the data
61
+ *
62
+ * @author Jelle De Loecker <jelle@elevenways.be>
63
+ * @since 1.2.2
64
+ * @version 1.2.2
65
+ */
66
+ DataProvider.setAbstractMethod('getAll');
67
+
68
+ /**
69
+ * Get the data for the given page (pages are 1-index based)
70
+ *
71
+ * @author Jelle De Loecker <jelle@elevenways.be>
72
+ * @since 1.2.2
73
+ * @version 1.2.2
74
+ */
75
+ DataProvider.setAbstractMethod('getPage');
76
+
77
+ /**
78
+ * Return an object for json-drying this document
79
+ *
80
+ * @author Jelle De Loecker <jelle@elevenways.be>
81
+ * @since 1.2.2
82
+ * @version 1.2.2
83
+ *
84
+ * @return {Object}
85
+ */
86
+ DataProvider.setMethod(function toDry() {
87
+ return {
88
+ value : {
89
+ config : this.config,
90
+ }
91
+ };
92
+ });
@@ -143,14 +143,31 @@ DocumentList.setMethod(function createIterator() {
143
143
  *
144
144
  * @author Jelle De Loecker <jelle@develry.be>
145
145
  * @since 1.0.0
146
- * @version 1.1.3
146
+ * @version 1.2.3
147
147
  *
148
148
  * @return {Object}
149
149
  */
150
150
  DocumentList.setMethod(function toDry() {
151
+
152
+ let options;
153
+
154
+ if (this.options) {
155
+ let key;
156
+
157
+ options = {};
158
+
159
+ for (key in this.options) {
160
+ if (key == 'options' || key == 'assoc_cache') {
161
+ continue;
162
+ }
163
+
164
+ options[key] = this.options[key];
165
+ }
166
+ }
167
+
151
168
  return {
152
169
  value: {
153
- options : this.options,
170
+ options : options,
154
171
  records : this.records,
155
172
  available : this.available,
156
173
  }
@@ -29,6 +29,9 @@ const FieldConfig = Fn.inherits('Alchemy.Base', 'Alchemy.Criteria', function Fie
29
29
  // The association this belongs to
30
30
  this.association = null;
31
31
 
32
+ // The main model this field is in
33
+ this.model = null;
34
+
32
35
  this.options = options || {};
33
36
 
34
37
  if (path) {
@@ -41,15 +44,24 @@ const FieldConfig = Fn.inherits('Alchemy.Base', 'Alchemy.Criteria', function Fie
41
44
  *
42
45
  * @author Jelle De Loecker <jelle@elevenways.be>
43
46
  * @since 1.1.3
44
- * @version 1.1.3
47
+ * @version 1.2.3
45
48
  *
46
49
  * @param {Object} obj
47
50
  *
48
51
  * @return {Alchemy.Form.FieldConfig}
49
52
  */
50
53
  FieldConfig.setStatic(function unDry(obj) {
51
- let set = new FieldConfig(obj.path, obj.options);
52
- return set;
54
+ let result = new FieldConfig(obj.path, obj.options);
55
+
56
+ if (obj.association) {
57
+ result.association = obj.association;
58
+ }
59
+
60
+ if (obj.model) {
61
+ result.model = obj.model;
62
+ }
63
+
64
+ return result;
53
65
  });
54
66
 
55
67
  /**
@@ -72,6 +84,94 @@ FieldConfig.setProperty(function title() {
72
84
  return title;
73
85
  });
74
86
 
87
+ /**
88
+ * Set the main model context this field is used for
89
+ * (Actual field can be in an association of this model)
90
+ *
91
+ * @author Jelle De Loecker <jelle@elevenways.be>
92
+ * @since 1.2.2
93
+ * @version 1.2.2
94
+ *
95
+ * @param {String|Model} model
96
+ */
97
+ FieldConfig.setMethod(function setContextModel(model) {
98
+
99
+ if (typeof model == 'string') {
100
+ this.model = model;
101
+ this._model = alchemy.getModel(model);
102
+ } else {
103
+ this._model = model;
104
+ this.model = model.model_name;
105
+ }
106
+ });
107
+
108
+ /**
109
+ * Get the context model this field is used for
110
+ *
111
+ * @author Jelle De Loecker <jelle@elevenways.be>
112
+ * @since 1.2.2
113
+ * @version 1.2.2
114
+ */
115
+ FieldConfig.setMethod(function getContextModel() {
116
+
117
+ if (this._model) {
118
+ return this._model;
119
+ }
120
+
121
+ if (!this.model) {
122
+ return;
123
+ }
124
+
125
+ this._model = alchemy.getModel(this.model);
126
+ return this._model;
127
+ });
128
+
129
+ /**
130
+ * Get the actual model this field is in
131
+ *
132
+ * @author Jelle De Loecker <jelle@elevenways.be>
133
+ * @since 1.2.2
134
+ * @version 1.2.2
135
+ */
136
+ FieldConfig.setMethod(function getModel() {
137
+
138
+ let model = this.getContextModel();
139
+
140
+ if (!model) {
141
+ return;
142
+ }
143
+
144
+ if (this.association) {
145
+ let config = model.getAssociation(this.association);
146
+
147
+ if (config) {
148
+ model = alchemy.getModel(config.modelName);
149
+ } else {
150
+ model = null;
151
+ }
152
+ }
153
+
154
+ return model;
155
+ });
156
+
157
+ /**
158
+ * Get the field definition
159
+ *
160
+ * @author Jelle De Loecker <jelle@elevenways.be>
161
+ * @since 1.2.2
162
+ * @version 1.2.2
163
+ */
164
+ FieldConfig.setMethod(function getFieldDefinition() {
165
+
166
+ let model = this.getModel();
167
+
168
+ if (!model) {
169
+ return;
170
+ }
171
+
172
+ return model.getField(this.local_path);
173
+ });
174
+
75
175
  /**
76
176
  * Return an object for json-drying this list
77
177
  *
@@ -103,6 +203,7 @@ FieldConfig.setMethod(function toJSON() {
103
203
  local_path : this.local_path,
104
204
  association : this.association,
105
205
  options : this.options,
206
+ model : this.model,
106
207
  };
107
208
  });
108
209
 
@@ -143,6 +143,28 @@ FieldSet.setMethod(function toJSON() {
143
143
  return result;
144
144
  });
145
145
 
146
+ /**
147
+ * Get an instance of the model
148
+ *
149
+ * @author Jelle De Loecker <jelle@elevenways.be>
150
+ * @since 1.2.2
151
+ * @version 1.2.2
152
+ *
153
+ * @return {Model}
154
+ */
155
+ FieldSet.setMethod(function getModel() {
156
+
157
+ if (!this.model) {
158
+ return;
159
+ }
160
+
161
+ if (!this._model) {
162
+ this._model = alchemy.getModel(this.model);
163
+ }
164
+
165
+ return this._model;
166
+ });
167
+
146
168
  /**
147
169
  * Iterator method
148
170
  *
@@ -165,7 +187,7 @@ FieldSet.setMethod(Symbol.iterator, function* iterate() {
165
187
  *
166
188
  * @author Jelle De Loecker <jelle@elevenways.be>
167
189
  * @since 1.1.3
168
- * @version 1.1.3
190
+ * @version 1.2.2
169
191
  *
170
192
  * @param {String} name The name of the field to add
171
193
  * @param {Object} options
@@ -176,6 +198,10 @@ FieldSet.setMethod(function addField(name, options) {
176
198
 
177
199
  let config = new Classes.Alchemy.Criteria.FieldConfig(name, options);
178
200
 
201
+ if (this.model && !config.getContextModel()) {
202
+ config.setContextModel(this.model);
203
+ }
204
+
179
205
  this.fields.set(name, config);
180
206
 
181
207
  return config;
@@ -1103,13 +1103,20 @@ Model.setMethod(function addAssociatedDataToRecord(criteria, item, callback) {
1103
1103
 
1104
1104
  aliases[alias] = function aliasRecordTask(nextAlias) {
1105
1105
 
1106
- var key;
1106
+ let pledge,
1107
+ key;
1107
1108
 
1108
1109
  if (options.create_references !== false) {
1109
1110
  key = alchemy.checksum(assoc_crit);
1110
1111
 
1111
- if (key != null && options.assoc_cache[key]) {
1112
- return nextAlias(null, options.assoc_cache[key]);
1112
+ if (key != null) {
1113
+ if (options.assoc_cache[key]) {
1114
+ Pledge.done(options.assoc_cache[key], nextAlias);
1115
+ return;
1116
+ } else {
1117
+ pledge = new Pledge();
1118
+ options.assoc_cache[key] = pledge;
1119
+ }
1113
1120
  }
1114
1121
  }
1115
1122
 
@@ -1125,6 +1132,11 @@ Model.setMethod(function addAssociatedDataToRecord(criteria, item, callback) {
1125
1132
  }
1126
1133
 
1127
1134
  if (err != null) {
1135
+
1136
+ if (pledge) {
1137
+ pledge.reject(err);
1138
+ }
1139
+
1128
1140
  return nextAlias(err);
1129
1141
  }
1130
1142
 
@@ -1140,6 +1152,10 @@ Model.setMethod(function addAssociatedDataToRecord(criteria, item, callback) {
1140
1152
 
1141
1153
  if (key) {
1142
1154
  options.assoc_cache[key] = result;
1155
+
1156
+ if (pledge) {
1157
+ pledge.resolve(result);
1158
+ }
1143
1159
  }
1144
1160
 
1145
1161
  nextAlias(null, result);
@@ -0,0 +1,35 @@
1
+ /**
2
+ * The Remote DataProvider class
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 1.2.2
6
+ * @version 1.2.2
7
+ */
8
+ const RemoteDataProvider = Function.inherits('Alchemy.DataProvider', 'Remote');
9
+
10
+ /**
11
+ * The url to load
12
+ *
13
+ * @author Jelle De Loecker <jelle@elevenways.be>
14
+ * @since 1.2.2
15
+ * @version 1.2.2
16
+ */
17
+ RemoteDataProvider.addConfig('source');
18
+
19
+ /**
20
+ * Get all the data
21
+ *
22
+ * @author Jelle De Loecker <jelle@elevenways.be>
23
+ * @since 1.2.2
24
+ * @version 1.2.2
25
+ */
26
+ RemoteDataProvider.setMethod(async function getAll() {
27
+
28
+ if (!this.source) {
29
+ return [];
30
+ }
31
+
32
+ let result = await Blast.fetch(this.source);
33
+
34
+ return result;
35
+ });
package/lib/bootstrap.js CHANGED
@@ -3,6 +3,22 @@
3
3
  var libpath = require('path'),
4
4
  starting;
5
5
 
6
+ /**
7
+ * Calling dynamic `import()` from certain places in the codebase actually
8
+ * causes segfaults. This is a workaround for that.
9
+ *
10
+ * @author Jelle De Loecker <jelle@elevenways.be>
11
+ * @since 1.2.2
12
+ * @version 1.2.2
13
+ *
14
+ * @param {String} path
15
+ *
16
+ * @return {Promise}
17
+ */
18
+ global.doImport = function doImport(path) {
19
+ return import(path);
20
+ };
21
+
6
22
  /**
7
23
  * Extend prototypes
8
24
  */