alchemymvc 1.3.19 → 1.3.21

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 (42) hide show
  1. package/lib/app/behaviour/sluggable_behaviour.js +0 -0
  2. package/lib/app/datasource/mongo_datasource.js +94 -1
  3. package/lib/app/element/time_ago.js +0 -0
  4. package/lib/app/helper/alchemy_helper.js +8 -4
  5. package/lib/app/helper_controller/controller.js +1 -0
  6. package/lib/app/helper_datasource/00-nosql_datasource.js +0 -0
  7. package/lib/app/helper_field/{date_field.js → 11-date_field.js} +1 -3
  8. package/lib/app/helper_field/15-local_temporal_field.js +100 -0
  9. package/lib/app/helper_field/20-decimal_field.js +105 -0
  10. package/lib/app/helper_field/big_int_field.js +7 -13
  11. package/lib/app/helper_field/fixed_decimal_field.js +44 -0
  12. package/lib/app/helper_field/local_date_field.js +39 -0
  13. package/lib/app/helper_field/local_date_time_field.js +39 -0
  14. package/lib/app/helper_field/local_time_field.js +39 -0
  15. package/lib/app/helper_field/mixed_field.js +73 -0
  16. package/lib/app/helper_field/schema_field.js +121 -35
  17. package/lib/app/helper_model/criteria.js +13 -0
  18. package/lib/app/helper_model/document.js +229 -0
  19. package/lib/app/helper_model/field_set.js +0 -0
  20. package/lib/app/helper_model/model.js +91 -18
  21. package/lib/app/model/alchemy_task_history_model.js +0 -0
  22. package/lib/bootstrap.js +0 -0
  23. package/lib/class/conduit.js +2 -2
  24. package/lib/class/datasource.js +80 -0
  25. package/lib/class/document.js +27 -0
  26. package/lib/class/field.js +110 -0
  27. package/lib/class/inode_file.js +0 -0
  28. package/lib/class/model.js +50 -28
  29. package/lib/class/path_evaluator.js +16 -9
  30. package/lib/class/route.js +4 -1
  31. package/lib/class/router.js +4 -2
  32. package/lib/class/schema_client.js +163 -20
  33. package/lib/class/session.js +0 -0
  34. package/lib/class/task.js +48 -2
  35. package/lib/class/task_service.js +37 -8
  36. package/lib/core/base.js +19 -4
  37. package/lib/core/client_alchemy.js +84 -1
  38. package/lib/core/middleware.js +27 -7
  39. package/lib/init/alchemy.js +4 -1
  40. package/lib/init/constants.js +23 -0
  41. package/lib/init/requirements.js +0 -0
  42. package/package.json +3 -3
@@ -116,6 +116,86 @@ Datasource.setMethod(function allows(name) {
116
116
  return true;
117
117
  });
118
118
 
119
+ /**
120
+ * Convert the given value to a BigInt (for use in JS)
121
+ *
122
+ * @author Jelle De Loecker <jelle@elevenways.be>
123
+ * @since 1.3.20
124
+ * @version 1.3.20
125
+ *
126
+ * @param {*} value
127
+ *
128
+ * @return {BigInt}
129
+ */
130
+ Datasource.setMethod(function castToBigInt(value) {
131
+
132
+ if (value == null) {
133
+ return value;
134
+ }
135
+
136
+ return BigInt(value);
137
+ });
138
+
139
+ /**
140
+ * Convert the given value from a BigInt (for use in DB)
141
+ *
142
+ * @author Jelle De Loecker <jelle@elevenways.be>
143
+ * @since 1.3.20
144
+ * @version 1.3.20
145
+ *
146
+ * @param {BigInt} value
147
+ *
148
+ * @return {BigInt}
149
+ */
150
+ Datasource.setMethod(function convertBigIntForDatasource(value) {
151
+
152
+ if (value == null) {
153
+ return value;
154
+ }
155
+
156
+ return BigInt(value);
157
+ });
158
+
159
+ /**
160
+ * Convert the given value to a Decimal (for use in JS)
161
+ *
162
+ * @author Jelle De Loecker <jelle@elevenways.be>
163
+ * @since 1.3.20
164
+ * @version 1.3.20
165
+ *
166
+ * @param {*} value
167
+ *
168
+ * @return {BigInt}
169
+ */
170
+ Datasource.setMethod(function castToDecimal(value) {
171
+
172
+ if (value == null) {
173
+ return value;
174
+ }
175
+
176
+ return new Blast.Classes.Develry.Decimal(value);
177
+ });
178
+
179
+ /**
180
+ * Convert the given decimal for use in DB
181
+ *
182
+ * @author Jelle De Loecker <jelle@elevenways.be>
183
+ * @since 1.3.20
184
+ * @version 1.3.20
185
+ *
186
+ * @param {Decimal|String} value
187
+ *
188
+ * @return {Decimal}
189
+ */
190
+ Datasource.setMethod(function convertDecimalForDatasource(value) {
191
+
192
+ if (value == null) {
193
+ return value;
194
+ }
195
+
196
+ return new Blast.Classes.Develry.Decimal(value);
197
+ });
198
+
119
199
  /**
120
200
  * Hash a string synchronously
121
201
  *
@@ -178,6 +178,33 @@ Document.setStatic(function unDry(obj, cloned) {
178
178
  return result;
179
179
  });
180
180
 
181
+ /**
182
+ * Set the getter for this computed field
183
+ *
184
+ * @author Jelle De Loecker <jelle@elevenways.be>
185
+ * @since 1.3.21
186
+ * @version 1.3.21
187
+ *
188
+ * @param {String} name Name of the property
189
+ * @param {Function} getter Optional getter function
190
+ * @param {Function} setter Optional setter function
191
+ */
192
+ Document.setStatic(function setComputedFieldGetter(name) {
193
+ this.setProperty(name, function getComputedFieldValue() {
194
+ this.recomputeFieldIfNecessary(name);
195
+ return this.$main[name];
196
+ }, function setComputedFieldValue(value) {
197
+
198
+ const field = this.$model.schema.getField(name);
199
+
200
+ if (field?.options?.allow_manual_set) {
201
+ return this.$main[name] = value;
202
+ }
203
+
204
+ console.error('Can not set computed field "' + name + '" to', value);
205
+ });
206
+ });
207
+
181
208
  /**
182
209
  * Set the getter for this field
183
210
  *
@@ -207,6 +207,116 @@ Field.setProperty(function is_array() {
207
207
  return !!result;
208
208
  });
209
209
 
210
+ /**
211
+ * Does this field have a computed value?
212
+ *
213
+ * @author Jelle De Loecker <jelle@elevenways.be>
214
+ * @since 1.3.21
215
+ * @version 1.3.21
216
+ *
217
+ * @type {Boolean}
218
+ */
219
+ Field.setProperty(function is_computed() {
220
+ return !!this.options.is_computed;
221
+ });
222
+
223
+ /**
224
+ * Get the required related fields
225
+ *
226
+ * @author Jelle De Loecker <jelle@elevenways.be>
227
+ * @since 1.3.21
228
+ * @version 1.3.21
229
+ *
230
+ * @type {Field[]}
231
+ */
232
+ Field.enforceProperty(function required_fields(new_value) {
233
+
234
+ if (!new_value) {
235
+ new_value = resolveFieldPaths(this, this.options.required_fields);
236
+ }
237
+
238
+ return new_value;
239
+ });
240
+
241
+ /**
242
+ * Get the optional related fields
243
+ *
244
+ * @author Jelle De Loecker <jelle@elevenways.be>
245
+ * @since 1.3.21
246
+ * @version 1.3.21
247
+ *
248
+ * @type {Field[]}
249
+ */
250
+ Field.enforceProperty(function optional_fields(new_value) {
251
+
252
+ if (!new_value) {
253
+ new_value = resolveFieldPaths(this, this.options.optional_fields);
254
+ }
255
+
256
+ return new_value;
257
+ });
258
+
259
+ /**
260
+ * Get all the dependency fields
261
+ *
262
+ * @author Jelle De Loecker <jelle@elevenways.be>
263
+ * @since 1.3.21
264
+ * @version 1.3.21
265
+ *
266
+ * @type {Field[]}
267
+ */
268
+ Field.enforceProperty(function dependency_fields(new_value) {
269
+
270
+ if (!new_value) {
271
+ let required_fields = this.required_fields,
272
+ optional_fields = this.optional_fields;
273
+
274
+ new_value = [];
275
+
276
+ if (required_fields) {
277
+ new_value = new_value.concat(required_fields);
278
+ }
279
+
280
+ if (optional_fields) {
281
+ new_value = new_value.concat(optional_fields);
282
+ }
283
+ }
284
+
285
+ return new_value;
286
+ });
287
+
288
+ /**
289
+ * Resolve a field path to a field instance
290
+ *
291
+ * @author Jelle De Loecker <jelle@elevenways.be>
292
+ * @since 1.3.21
293
+ * @version 1.3.21
294
+ */
295
+ function resolveFieldPaths(field, field_paths) {
296
+
297
+ let result = [],
298
+ i;
299
+
300
+ if (!field_paths) {
301
+ return result;
302
+ }
303
+
304
+ for (i = 0; i < field_paths.length; i++) {
305
+
306
+ if (!field.parent_schema) {
307
+ continue
308
+ }
309
+
310
+ let other_field = field.parent_schema.getField(field_paths[i]);
311
+
312
+ if (other_field && result.indexOf(other_field) == -1) {
313
+ result.push(other_field);
314
+ }
315
+ }
316
+
317
+ return result;
318
+ }
319
+
210
320
  /**
211
321
  * The datasource this field is used in
212
322
  *
File without changes
@@ -366,24 +366,49 @@ Model.setStatic(async function checkPathValue(value, name, field_name, conduit)
366
366
  return result;
367
367
  });
368
368
 
369
+ /**
370
+ * Add a computed field to this model's schema
371
+ *
372
+ * @author Jelle De Loecker <jelle@elevenways.be>
373
+ * @since 1.3.21
374
+ * @version 1.3.21
375
+ *
376
+ * @return {Alchemy.Field}
377
+ */
378
+ Model.setStatic(function addComputedField(name, type, options) {
379
+ let is_new = !this.schema.has(name);
380
+
381
+ // Add it to the schema
382
+ let field = this.schema.addComputedField(name, type, options);
383
+
384
+ if (is_new) {
385
+ // Add it to the Document class
386
+ this.Document.setComputedFieldGetter(name);
387
+
388
+ // False means it should not be set on the server implementation
389
+ // (because that's where it's coming from)
390
+ // Yes, this also sets private fields on the server-side client document.
391
+ this.ClientDocument.setComputedFieldGetter(name, null, null, false);
392
+ }
393
+
394
+ return field;
395
+ });
396
+
369
397
  /**
370
398
  * Add a field to this model's schema
371
399
  *
372
400
  * @author Jelle De Loecker <jelle@develry.be>
373
401
  * @since 0.2.0
374
- * @version 1.2.4
402
+ * @version 1.2.21
375
403
  *
376
404
  * @return {Alchemy.Field}
377
405
  */
378
406
  Model.setStatic(function addField(name, type, options) {
379
407
 
380
- var field,
381
- is_new;
382
-
383
- is_new = !this.schema.has(name);
408
+ let is_new = !this.schema.has(name);
384
409
 
385
410
  // Add it to the schema
386
- field = this.schema.addField(name, type, options);
411
+ let field = this.schema.addField(name, type, options);
387
412
 
388
413
  if (is_new) {
389
414
  // Add it to the Document class
@@ -845,7 +870,7 @@ Model.setMethod(function ensureIds(list, callback) {
845
870
  *
846
871
  * @author Jelle De Loecker <jelle@develry.be>
847
872
  * @since 0.0.1
848
- * @version 1.3.16
873
+ * @version 1.3.20
849
874
  *
850
875
  * @param {Document} document
851
876
  * @param {Object} options
@@ -895,21 +920,8 @@ Model.setMethod(function saveRecord(document, options, callback) {
895
920
  creating = options.create || doc[that.primary_key] == null;
896
921
  next();
897
922
  });
898
- }, function doBeforeSave(next) {
899
-
900
- if (typeof that.beforeSave == 'function') {
901
- let promise = that.beforeSave(document, options, next);
902
-
903
- if (promise) {
904
- Pledge.done(promise, next);
905
- } else if (that.beforeSave.length < 3) {
906
- // If the method accepts no `next` callback, call it now
907
- next();
908
- }
909
- } else {
910
- next();
911
- }
912
-
923
+ }, function doBeforeNormalize(next) {
924
+ that.callOrNext('beforeNormalize', [document, options], next);
913
925
  }, function emitSavingEvent(next) {
914
926
  that.emit('saving', document, options, creating, function afterSavingEvent(err, stopped) {
915
927
  return next(err);
@@ -1275,7 +1287,7 @@ Model.setMethod(async function executeMongoPipeline(pipeline) {
1275
1287
  *
1276
1288
  * @author Jelle De Loecker <jelle@develry.be>
1277
1289
  * @since 0.0.1
1278
- * @version 1.0.7
1290
+ * @version 1.3.21
1279
1291
  *
1280
1292
  * @param {String} id The object id
1281
1293
  * @param {Function} callback
@@ -1304,14 +1316,24 @@ Model.setMethod(function remove(id, callback) {
1304
1316
  let query = {};
1305
1317
  query[this.primary_key] = id;
1306
1318
 
1307
- this.datasource.remove(this, query, {}, function afterRemove(err, result) {
1319
+ Function.series(function recompute(next) {
1320
+ that.callOrNext('beforeRemove', [id], next);
1321
+ }, function done(err) {
1308
1322
 
1309
- if (err != null) {
1310
- return pledge.reject(err);
1323
+ if (err) {
1324
+ pledge.reject(err);
1325
+ return;
1311
1326
  }
1312
1327
 
1313
- that.emit('removed', result, {}, false, function afterRemovedEvent() {
1314
- pledge.resolve(result);
1328
+ that.datasource.remove(that, query, {}, function afterRemove(err, result) {
1329
+
1330
+ if (err != null) {
1331
+ return pledge.reject(err);
1332
+ }
1333
+
1334
+ that.emit('removed', result, {}, false, function afterRemovedEvent() {
1335
+ pledge.resolve(result);
1336
+ });
1315
1337
  });
1316
1338
  });
1317
1339
 
@@ -4,14 +4,18 @@
4
4
  *
5
5
  * @constructor
6
6
  *
7
- * @author Jelle De Loecker <jelle@develry.be>
7
+ * @author Jelle De Loecker <jelle@elevenways.be>
8
8
  * @since 1.1.0
9
- * @version 1.1.0
9
+ * @version 1.3.20
10
10
  *
11
11
  * @param {String} path
12
12
  */
13
13
  const PathEvaluator = Function.inherits(null, 'Alchemy', function PathEvaluator(path) {
14
14
 
15
+ if (!(this instanceof PathEvaluator)) {
16
+ return new PathEvaluator(path);
17
+ }
18
+
15
19
  if (typeof path == 'string') {
16
20
  path = path.split('.');
17
21
  }
@@ -22,7 +26,7 @@ const PathEvaluator = Function.inherits(null, 'Alchemy', function PathEvaluator(
22
26
  /**
23
27
  * Undry the value
24
28
  *
25
- * @author Jelle De Loecker <jelle@develry.be>
29
+ * @author Jelle De Loecker <jelle@elevenways.be>
26
30
  * @since 1.1.0
27
31
  * @version 1.1.0
28
32
  */
@@ -33,7 +37,7 @@ PathEvaluator.setStatic(function unDry(value) {
33
37
  /**
34
38
  * Create a dry object
35
39
  *
36
- * @author Jelle De Loecker <jelle@develry.be>
40
+ * @author Jelle De Loecker <jelle@elevenways.be>
37
41
  * @since 1.1.0
38
42
  * @version 1.1.0
39
43
  */
@@ -48,14 +52,17 @@ PathEvaluator.setMethod(function toDry() {
48
52
  /**
49
53
  * Get the actual value
50
54
  *
51
- * @author Jelle De Loecker <jelle@develry.be>
55
+ * @author Jelle De Loecker <jelle@elevenways.be>
52
56
  * @since 1.1.0
53
- * @version 1.1.0
57
+ * @version 1.3.20
54
58
  */
55
- PathEvaluator.setMethod(function getValue() {
59
+ PathEvaluator.setMethod(function getValue(context) {
60
+
61
+ if (arguments.length == 0) {
62
+ context = Blast.Globals;
63
+ }
56
64
 
57
- var context = Blast.Globals,
58
- result = Object.path(context, this.path);
65
+ let result = Object.path(context, this.path);
59
66
 
60
67
  if (typeof result == 'function') {
61
68
  result = result();
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @author Jelle De Loecker <jelle@elevenways.be>
5
5
  * @since 0.2.0
6
- * @version 1.3.16
6
+ * @version 1.3.21
7
7
  */
8
8
  const Route = Function.inherits('Alchemy.Base', function Route(router, paths, options) {
9
9
 
@@ -62,6 +62,9 @@ const Route = Function.inherits('Alchemy.Base', function Route(router, paths, op
62
62
  // All routes can be postponed by default
63
63
  this.can_be_postponed = true;
64
64
 
65
+ // Possible cache instructions
66
+ this.cache = null;
67
+
65
68
  this.setPaths(paths);
66
69
  });
67
70
 
@@ -767,7 +767,7 @@ RouterClass.setMethod(function setOption(name, value) {
767
767
  *
768
768
  * @author Jelle De Loecker <jelle@elevenways.be>
769
769
  * @since 0.2.0
770
- * @version 1.3.16
770
+ * @version 1.3.21
771
771
  *
772
772
  * @param {Object} args
773
773
  * @param {String} args.name Optional route name
@@ -819,6 +819,7 @@ RouterClass.setMethod(function add(args) {
819
819
  route.setBreadcrumb(args.breadcrumb);
820
820
  route.sitemap = args.sitemap;
821
821
  route.title = args.title;
822
+ route.cache = args.cache;
822
823
 
823
824
  if (args.visible_location != null) {
824
825
  route.visible_location = args.visible_location;
@@ -1167,7 +1168,7 @@ RouterClass.setMethod(function getOptions(result) {
1167
1168
  *
1168
1169
  * @author Jelle De Loecker <jelle@elevenways.be>
1169
1170
  * @since 0.2.0
1170
- * @version 1.3.16
1171
+ * @version 1.3.21
1171
1172
  *
1172
1173
  * @param {Object} result Optional object to store sectioned results in
1173
1174
  *
@@ -1219,6 +1220,7 @@ RouterClass.setMethod(function getRoutes(result) {
1219
1220
  is_system_route : route.is_system_route,
1220
1221
  schema : route.schema,
1221
1222
  param_definitions : route.param_definitions,
1223
+ cache : route.cache,
1222
1224
  };
1223
1225
  }
1224
1226