alchemymvc 1.3.21 → 1.4.0-alpha.1

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 (155) hide show
  1. package/LICENSE +1 -1
  2. package/README.md +3 -3
  3. package/lib/app/behaviour/publishable_behaviour.js +5 -5
  4. package/lib/app/behaviour/revision_behaviour.js +10 -10
  5. package/lib/app/behaviour/sluggable_behaviour.js +14 -14
  6. package/lib/app/conduit/electron_conduit.js +9 -9
  7. package/lib/app/conduit/http_conduit.js +13 -13
  8. package/lib/app/conduit/loopback_conduit.js +15 -15
  9. package/lib/app/conduit/socket_conduit.js +43 -43
  10. package/lib/app/config/routes.js +26 -0
  11. package/lib/app/controller/00-default_app_controller.js +21 -0
  12. package/lib/app/controller/alchemy_info_controller.js +12 -12
  13. package/lib/app/datasource/mongo_datasource.js +16 -16
  14. package/lib/app/element/00-default_app_element.js +19 -0
  15. package/lib/app/element/time_ago.js +5 -5
  16. package/lib/app/helper/00-default_app_helper.js +11 -0
  17. package/lib/app/helper/alchemy_helper.js +22 -22
  18. package/lib/app/helper/backed_map.js +1 -1
  19. package/lib/app/helper/breadcrumb.js +10 -10
  20. package/lib/app/helper/client_collection.js +3 -3
  21. package/lib/app/helper/cron.js +29 -29
  22. package/lib/app/helper/enum_values.js +6 -6
  23. package/lib/app/helper/pagination_helper.js +36 -36
  24. package/lib/app/helper/router_helper.js +35 -35
  25. package/lib/app/helper/socket_helper.js +57 -57
  26. package/lib/app/helper/syncable.js +84 -59
  27. package/lib/app/helper_component/paginate_component.js +9 -9
  28. package/lib/app/helper_controller/component.js +1 -1
  29. package/lib/app/helper_controller/conduit.js +31 -31
  30. package/lib/app/helper_controller/controller.js +54 -39
  31. package/lib/app/helper_datasource/00-nosql_datasource.js +624 -70
  32. package/lib/app/helper_datasource/05-fallback_datasource.js +10 -10
  33. package/lib/app/helper_datasource/idb_datasource.js +6 -6
  34. package/lib/app/helper_datasource/indexed_db.js +22 -22
  35. package/lib/app/helper_datasource/remote_datasource.js +5 -5
  36. package/lib/app/helper_error/http_error.js +4 -4
  37. package/lib/app/helper_error/model_error.js +2 -2
  38. package/lib/app/helper_error/validation_error.js +12 -12
  39. package/lib/app/helper_field/00-objectid_field.js +7 -7
  40. package/lib/app/helper_field/05-string_field.js +16 -12
  41. package/lib/app/helper_field/06-text_field.js +2 -4
  42. package/lib/app/helper_field/10-number_field.js +9 -12
  43. package/lib/app/helper_field/11-date_field.js +15 -15
  44. package/lib/app/helper_field/15-local_temporal_field.js +10 -10
  45. package/lib/app/helper_field/20-decimal_field.js +8 -9
  46. package/lib/app/helper_field/belongsto_field.js +1 -1
  47. package/lib/app/helper_field/big_int_field.js +8 -8
  48. package/lib/app/helper_field/boolean_field.js +9 -11
  49. package/lib/app/helper_field/datetime_field.js +3 -3
  50. package/lib/app/helper_field/enum_field.js +13 -8
  51. package/lib/app/helper_field/fixed_decimal_field.js +6 -7
  52. package/lib/app/helper_field/geopoint_field.js +9 -10
  53. package/lib/app/helper_field/habtm_field.js +3 -3
  54. package/lib/app/helper_field/hasoneparent_field.js +1 -1
  55. package/lib/app/helper_field/html_field.js +2 -4
  56. package/lib/app/helper_field/integer_field.js +8 -11
  57. package/lib/app/helper_field/local_date_field.js +5 -5
  58. package/lib/app/helper_field/local_date_time_field.js +5 -5
  59. package/lib/app/helper_field/local_time_field.js +5 -5
  60. package/lib/app/helper_field/mixed_field.js +5 -5
  61. package/lib/app/helper_field/object_field.js +8 -8
  62. package/lib/app/helper_field/password_field.js +3 -3
  63. package/lib/app/helper_field/regexp_field.js +7 -9
  64. package/lib/app/helper_field/schema_field.js +91 -88
  65. package/lib/app/helper_field/settings_field.js +92 -0
  66. package/lib/app/helper_field/time_field.js +6 -6
  67. package/lib/app/helper_field/url_field.js +2 -4
  68. package/lib/app/helper_model/00-base_criteria.js +662 -0
  69. package/lib/app/helper_model/05-criteria_expressions.js +605 -0
  70. package/lib/app/helper_model/10-model_criteria.js +1182 -0
  71. package/lib/app/helper_model/data_provider.js +2 -2
  72. package/lib/app/helper_model/document.js +103 -92
  73. package/lib/app/helper_model/document_list.js +14 -14
  74. package/lib/app/helper_model/field_config.js +11 -11
  75. package/lib/app/helper_model/field_set.js +17 -17
  76. package/lib/app/helper_model/model.js +203 -124
  77. package/lib/app/helper_model/remote_data_provider.js +2 -2
  78. package/lib/app/helper_validator/00_validator.js +16 -16
  79. package/lib/app/helper_validator/not_empty_validator.js +9 -9
  80. package/lib/app/model/00-default_app_model.js +18 -0
  81. package/lib/app/model/05-system_model.js +27 -0
  82. package/lib/app/model/{alchemy_migration_model.js → system_migration_model.js} +4 -4
  83. package/lib/app/model/system_setting_model.js +154 -0
  84. package/lib/app/model/{alchemy_task_history_model.js → system_task_history_model.js} +7 -7
  85. package/lib/app/model/{alchemy_task_model.js → system_task_model.js} +11 -11
  86. package/lib/bootstrap.js +22 -312
  87. package/lib/class/accumulator.js +5 -5
  88. package/lib/class/behaviour.js +5 -5
  89. package/lib/class/component.js +3 -3
  90. package/lib/class/conduit.js +203 -163
  91. package/lib/class/controller.js +42 -42
  92. package/lib/class/datasource.js +74 -79
  93. package/lib/class/document.js +74 -95
  94. package/lib/class/document_list.js +5 -5
  95. package/lib/class/element.js +17 -17
  96. package/lib/class/error.js +3 -3
  97. package/lib/class/field.js +169 -91
  98. package/lib/class/field_value.js +6 -6
  99. package/lib/class/helper.js +3 -3
  100. package/lib/class/inode.js +17 -17
  101. package/lib/class/inode_dir.js +12 -12
  102. package/lib/class/inode_file.js +50 -25
  103. package/lib/class/inode_list.js +4 -4
  104. package/lib/class/migration.js +4 -4
  105. package/lib/class/model.js +182 -168
  106. package/lib/class/path_definition.js +22 -22
  107. package/lib/class/path_evaluator.js +5 -5
  108. package/lib/class/path_param_definition.js +7 -7
  109. package/lib/class/plugin.js +312 -0
  110. package/lib/class/postponement.js +29 -29
  111. package/lib/class/reciprocal.js +8 -8
  112. package/lib/class/route.js +33 -33
  113. package/lib/class/router.js +73 -73
  114. package/lib/class/schema.js +21 -21
  115. package/lib/class/schema_client.js +73 -67
  116. package/lib/class/session.js +63 -29
  117. package/lib/class/session_scene.js +4 -4
  118. package/lib/class/sitemap.js +16 -16
  119. package/lib/class/task.js +39 -39
  120. package/lib/class/task_service.js +43 -47
  121. package/lib/{init → core}/alchemy.js +413 -374
  122. package/lib/{init/functions.js → core/alchemy_functions.js} +171 -108
  123. package/lib/core/alchemy_load_functions.js +715 -0
  124. package/lib/core/base.js +50 -62
  125. package/lib/core/client_alchemy.js +144 -152
  126. package/lib/core/client_base.js +39 -52
  127. package/lib/core/discovery.js +16 -18
  128. package/lib/core/middleware.js +54 -43
  129. package/lib/core/{routing.js → prefix.js} +14 -16
  130. package/lib/core/setting.js +1684 -0
  131. package/lib/core/stage.js +758 -0
  132. package/lib/scripts/create_constants.js +119 -0
  133. package/lib/{init/languages.js → scripts/create_languages.js} +5 -5
  134. package/lib/scripts/create_settings.js +449 -0
  135. package/lib/scripts/create_shared_constants.js +95 -0
  136. package/lib/scripts/create_stages.js +55 -0
  137. package/lib/scripts/init_alchemy.js +51 -0
  138. package/lib/{init/requirements.js → scripts/preload_modules.js} +15 -2
  139. package/lib/scripts/setup_devwatch.js +238 -0
  140. package/lib/stages/00-load_core.js +342 -0
  141. package/lib/stages/05-load_app.js +57 -0
  142. package/lib/stages/10-datasource.js +61 -0
  143. package/lib/stages/15-tasks.js +27 -0
  144. package/lib/stages/20-settings.js +68 -0
  145. package/lib/stages/50-routes.js +218 -0
  146. package/lib/stages/90-server.js +347 -0
  147. package/package.json +5 -7
  148. package/lib/app/helper_model/criteria.js +0 -2294
  149. package/lib/app/helper_model/db_query.js +0 -1488
  150. package/lib/app/routes.js +0 -11
  151. package/lib/core/socket.js +0 -171
  152. package/lib/init/constants.js +0 -158
  153. package/lib/init/devwatch.js +0 -238
  154. package/lib/init/load_functions.js +0 -973
  155. package/lib/stages.js +0 -513
@@ -0,0 +1,605 @@
1
+ /**
2
+ * The Base Criteria Expression class
3
+ *
4
+ * @author Jelle De Loecker <jelle@elevenways.be>
5
+ * @since 1.1.0
6
+ * @version 1.1.0
7
+ */
8
+ const Expression = Function.inherits('Alchemy.Base', 'Alchemy.Criteria.Expression', function Expression(criteria) {
9
+
10
+ // The parent criteria instance
11
+ this.criteria = criteria;
12
+
13
+ // The current group it's in
14
+ this.current_group = null;
15
+
16
+ // The items this contains
17
+ this.items = [];
18
+ });
19
+
20
+ /**
21
+ * Revive an object
22
+ *
23
+ * @author Jelle De Loecker <jelle@elevenways.be>
24
+ * @since 1.1.0
25
+ * @version 1.1.0
26
+ *
27
+ * @return {Expression}
28
+ */
29
+ Expression.setStatic(function revive(data, criteria) {
30
+
31
+ if (data._type == 'group') {
32
+ return Group.revive(data, criteria);
33
+ } else if (data._type == 'field') {
34
+ return FieldExpression.revive(data, criteria);
35
+ } else {
36
+ throw new Error('Unable to revive "' + data._type + '" expression');
37
+ }
38
+
39
+ });
40
+
41
+ /**
42
+ * Does this expression do something with an association,
43
+ * and do we need to normalize this on the current given datasource?
44
+ *
45
+ * @author Jelle De Loecker <jelle@elevenways.be>
46
+ * @since 1.1.0
47
+ * @version 1.1.0
48
+ *
49
+ * @type {boolean}
50
+ */
51
+ Expression.setProperty(function requires_association_normalization() {
52
+
53
+ if (!this.association) {
54
+ return false;
55
+ }
56
+
57
+ if (!this.datasource.supports('querying_associations')) {
58
+ return true;
59
+ }
60
+
61
+ return false;
62
+ });
63
+
64
+ /**
65
+ * Create a reference to the datasource
66
+ *
67
+ * @author Jelle De Loecker <jelle@elevenways.be>
68
+ * @since 1.1.0
69
+ * @version 1.1.0
70
+ *
71
+ * @type {Datasource}
72
+ */
73
+ Expression.setProperty(function datasource() {
74
+ if (this.criteria) {
75
+ return this.criteria.datasource;
76
+ }
77
+ });
78
+
79
+ /**
80
+ * Create a reference to the model
81
+ *
82
+ * @author Jelle De Loecker <jelle@elevenways.be>
83
+ * @since 1.1.0
84
+ * @version 1.1.0
85
+ *
86
+ * @type {Model}
87
+ */
88
+ Expression.setProperty(function model() {
89
+ if (this.criteria) {
90
+ return this.criteria.model;
91
+ }
92
+ });
93
+
94
+ /**
95
+ * Create a reference to the field instance
96
+ *
97
+ * @author Jelle De Loecker <jelle@elevenways.be>
98
+ * @since 1.1.0
99
+ * @version 1.1.0
100
+ *
101
+ * @type {FieldType}
102
+ */
103
+ Expression.setProperty(function field() {
104
+ if (this.criteria && this.criteria.model) {
105
+ return this.criteria.model.schema.getField(this.target_path);
106
+ }
107
+ });
108
+
109
+ /**
110
+ * Return the elements to checksum in place of this object
111
+ *
112
+ * @author Jelle De Loecker <jelle@elevenways.be>
113
+ * @since 1.1.0
114
+ * @version 1.1.0
115
+ */
116
+ Expression.setMethod(Blast.checksumSymbol, function toChecksum() {
117
+ return this.items;
118
+ });
119
+
120
+ /**
121
+ * Get a clone without any Criteria or Group links
122
+ *
123
+ * @author Jelle De Loecker <jelle@elevenways.be>
124
+ * @since 1.1.0
125
+ * @version 1.1.0
126
+ *
127
+ * @return {Expression}
128
+ */
129
+ Expression.setMethod(function getCleanClone() {
130
+
131
+ var result = new this.constructor();
132
+
133
+ // Add the cloned array
134
+ result.items = JSON.clone(this.items);
135
+
136
+ if (this.association) {
137
+ result.association = this.association;
138
+ }
139
+
140
+ if (this.target_path) {
141
+ result.target_path = this.target_path;
142
+ }
143
+
144
+ if (this.group_type) {
145
+ result.group_type = this.group_type;
146
+ }
147
+
148
+ if (this.db_property) {
149
+ result.db_property = this.db_property;
150
+ }
151
+
152
+ return result;
153
+ });
154
+
155
+ /**
156
+ * Move the expression to the given group (object)
157
+ * or the given group type (and/or)
158
+ *
159
+ * @author Jelle De Loecker <jelle@elevenways.be>
160
+ * @since 1.1.0
161
+ * @version 1.1.0
162
+ *
163
+ * @param {Object|string} group
164
+ */
165
+ Expression.setMethod(function moveToGroup(group) {
166
+
167
+ var context = this.criteria;
168
+
169
+ // Move to a specific type?
170
+ if (typeof group == 'string') {
171
+
172
+ // Is it already part of the same type of group?
173
+ // Then we can ignore this call
174
+ if (this.current_group && this.current_group.group_type == group) {
175
+ return context;
176
+ }
177
+
178
+ // Create a new group of the given type
179
+ context = context.createGroup(group);
180
+ group = context.group;
181
+ }
182
+
183
+ if (this.current_group) {
184
+ this.current_group.removeItem(this);
185
+ }
186
+
187
+ this.current_group = group;
188
+ group.addItem(this);
189
+
190
+ return context;
191
+ });
192
+
193
+ /**
194
+ * Remove this expression from the criteria
195
+ *
196
+ * @author Jelle De Loecker <jelle@elevenways.be>
197
+ * @since 1.1.0
198
+ * @version 1.1.0
199
+ */
200
+ Expression.setMethod(function remove() {
201
+
202
+ if (arguments.length) {
203
+ throw new Error('Expression#remove() can only remove itself');
204
+ }
205
+
206
+ let index = this.criteria.all_expressions.indexOf(this);
207
+
208
+ if (index > -1) {
209
+ this.criteria.all_expressions.splice(index, 1);
210
+ }
211
+
212
+ if (this.current_group) {
213
+ this.current_group.removeItem(this);
214
+ }
215
+ });
216
+
217
+ /**
218
+ * Add an item
219
+ *
220
+ * @author Jelle De Loecker <jelle@elevenways.be>
221
+ * @since 1.1.0
222
+ * @version 1.1.0
223
+ *
224
+ * @param {Object} item
225
+ */
226
+ Expression.setMethod(function addItem(item) {
227
+ this.items.push(item);
228
+ return item;
229
+ });
230
+
231
+ /**
232
+ * Remove an item from this expression
233
+ *
234
+ * @author Jelle De Loecker <jelle@elevenways.be>
235
+ * @since 1.1.0
236
+ * @version 1.1.0
237
+ *
238
+ * @param {Object} item
239
+ */
240
+ Expression.setMethod(function removeItem(item) {
241
+
242
+ var index = this.items.indexOf(item);
243
+
244
+ // If this expression was found in the current group, remove it
245
+ if (index > -1) {
246
+ this.items.splice(index, 1);
247
+ return true;
248
+ }
249
+
250
+ return false;
251
+ });
252
+
253
+ /**
254
+ * The Field Expression class
255
+ *
256
+ * @author Jelle De Loecker <jelle@elevenways.be>
257
+ * @since 1.1.0
258
+ * @version 1.1.0
259
+ */
260
+ const FieldExpression = Function.inherits('Alchemy.Criteria.Expression', function Field(criteria, field) {
261
+
262
+ Field.super.call(this, criteria);
263
+
264
+ if (arguments.length) {
265
+ // Set the target
266
+ this.setTargetPath(field);
267
+ }
268
+ });
269
+
270
+ /**
271
+ * Revive an object
272
+ *
273
+ * @author Jelle De Loecker <jelle@elevenways.be>
274
+ * @since 1.1.0
275
+ * @version 1.1.0
276
+ *
277
+ * @return {FieldExpression}
278
+ */
279
+ FieldExpression.setStatic(function revive(data, criteria) {
280
+
281
+ var result = new FieldExpression();
282
+
283
+ result.criteria = criteria;
284
+
285
+ criteria.all_expressions.push(result);
286
+
287
+ if (data.association) {
288
+ result.association = data.association;
289
+ }
290
+
291
+ if (data.target_path) {
292
+ result.target_path = data.target_path;
293
+ }
294
+
295
+ if (data.items) {
296
+ result.items = data.items;
297
+ }
298
+
299
+ if (data.db_property) {
300
+ result.db_property = data.db_property;
301
+ }
302
+
303
+ return result;
304
+ });
305
+
306
+ /**
307
+ * Return object to jsonify
308
+ *
309
+ * @author Jelle De Loecker <jelle@elevenways.be>
310
+ * @since 1.1.0
311
+ * @version 1.4.0
312
+ *
313
+ * @return {Object}
314
+ */
315
+ FieldExpression.setMethod(function toJSON() {
316
+
317
+ let result = {
318
+ _type : 'field',
319
+ target_path : this.target_path,
320
+ items : this.items,
321
+ };
322
+
323
+ if (this.association) {
324
+ result.association = this.association;
325
+ }
326
+
327
+ if (this.db_property) {
328
+ result.db_property = this.db_property;
329
+ }
330
+
331
+ return result;
332
+ });
333
+
334
+ /**
335
+ * Return the elements to checksum in place of this object
336
+ *
337
+ * @author Jelle De Loecker <jelle@elevenways.be>
338
+ * @since 1.1.0
339
+ * @version 1.4.0
340
+ */
341
+ FieldExpression.setMethod(Blast.checksumSymbol, function toChecksum() {
342
+ return this.toJSON();
343
+ });
344
+
345
+ /**
346
+ * Set the target
347
+ *
348
+ * @author Jelle De Loecker <jelle@elevenways.be>
349
+ * @since 1.1.0
350
+ * @version 1.1.0
351
+ *
352
+ * @param {string} path
353
+ */
354
+ FieldExpression.setMethod(function setTargetPath(path) {
355
+
356
+ var pieces;
357
+
358
+ if (typeof path == 'string') {
359
+ if (path.indexOf('.') > -1) {
360
+ pieces = path.split('.');
361
+ }
362
+ } else if (Array.isArray(path)) {
363
+ pieces = path;
364
+ } else {
365
+ throw new Error('Field#setTargetPath(path) requires a string or an array');
366
+ }
367
+
368
+ if (!pieces) {
369
+ this.target_path = path;
370
+ } else {
371
+ let first = pieces[0];
372
+
373
+ // @TODO: better check if the first part is an association
374
+ if (first[0].isUpperCase()) {
375
+ this.association = first;
376
+ pieces.shift();
377
+ }
378
+
379
+ this.target_path = pieces.join('.');
380
+ }
381
+
382
+ });
383
+
384
+ /**
385
+ * Add a new condition item
386
+ *
387
+ * @author Jelle De Loecker <jelle@elevenways.be>
388
+ * @since 1.1.0
389
+ * @version 1.1.5
390
+ *
391
+ * @param {Object|string} group
392
+ *
393
+ * @return {Object}
394
+ */
395
+ FieldExpression.setMethod(function addItem(type, value) {
396
+
397
+ var entry = {
398
+ type : type
399
+ };
400
+
401
+ if (arguments.length > 1) {
402
+
403
+ if (typeof value == 'object' && value && value instanceof Classes.Alchemy.Base) {
404
+ throw new Classes.Alchemy.Error.Model('"' + value.constructor.getClassPath() + '" instance was given as a "' + this.target_path + '" condition');
405
+ }
406
+
407
+ entry.value = value;
408
+ }
409
+
410
+ this.items.push(entry);
411
+
412
+ return entry;
413
+ });
414
+
415
+ /**
416
+ * Normalize the values (like casting strings to objectids)
417
+ *
418
+ * @author Jelle De Loecker <jelle@elevenways.be>
419
+ * @since 1.1.0
420
+ * @version 1.1.0
421
+ *
422
+ * @return {Pledge|Null}
423
+ */
424
+ FieldExpression.setMethod(function normalize() {
425
+
426
+ var field = this.field;
427
+
428
+ if (!field) {
429
+ return;
430
+ }
431
+
432
+ let item,
433
+ i;
434
+
435
+ for (i = 0; i < this.items.length; i++) {
436
+ item = this.items[i];
437
+
438
+ // Skip field_expression items
439
+ // (like $exists: true and such)
440
+ // or items where `cast` is explicitly false
441
+ if (item.field_expression || item.cast === false) {
442
+ continue;
443
+ }
444
+
445
+ if (item.value != null) {
446
+ if (Array.isArray(item.value)) {
447
+ let result = [],
448
+ i;
449
+
450
+ for (i = 0; i < item.value.length; i++) {
451
+ result[i] = field.castCondition(item.value[i], this);
452
+ }
453
+
454
+ item.value = result;
455
+ } else {
456
+ item.value = field.castCondition(item.value, this);
457
+ }
458
+ }
459
+ }
460
+ });
461
+
462
+ /**
463
+ * Normalize association values by separately querying them
464
+ * and adding the found values to the criteria
465
+ *
466
+ * @WARNING: this can be extremely resource intensive when using
467
+ * on big collections.
468
+ *
469
+ * @author Jelle De Loecker <jelle@elevenways.be>
470
+ * @since 1.1.0
471
+ * @version 1.4.0
472
+ *
473
+ * @return {Pledge}
474
+ */
475
+ FieldExpression.setMethod(function normalizeAssociationValues() {
476
+
477
+ if (!this.association) {
478
+ return Pledge.reject(new Error('Unable to normalize a field without an association'));
479
+ }
480
+
481
+ let that = this,
482
+ association = this.model.getAssociation(this.association),
483
+ assoc_model = this.model.getModel(association.modelName),
484
+ assoc_crit = new Classes.Alchemy.Criteria.Model(),
485
+ pledge = new Pledge(),
486
+ clone = this.getCleanClone(),
487
+ item,
488
+ i;
489
+
490
+ // Unset the association
491
+ clone.association = null;
492
+
493
+ // Add the clone
494
+ assoc_crit.addNewExpression(clone);
495
+
496
+ // Only select the wanted field
497
+ assoc_crit.select(association.options.foreignKey);
498
+
499
+ assoc_model.find('all', {criteria: assoc_crit, document: false}, function gotAssocItems(err, items) {
500
+
501
+ if (err) {
502
+ return pledge.reject(err);
503
+ }
504
+
505
+ let values = [],
506
+ record,
507
+ i;
508
+
509
+ for (i = 0; i < items.length; i++) {
510
+ values.push(items[i][association.options.foreignKey]);
511
+ }
512
+
513
+ if (!values.length) {
514
+ // @TODO: make this more elegant
515
+ values.push('_impossible_');
516
+ }
517
+
518
+ // Remove the expression from the criteria
519
+ that.remove();
520
+
521
+ // And add this new one
522
+ that.criteria.where(association.options.localKey).in(values);
523
+
524
+ pledge.resolve();
525
+ });
526
+
527
+ return pledge;
528
+ });
529
+
530
+ /**
531
+ * The Group Expression class
532
+ *
533
+ * @author Jelle De Loecker <jelle@elevenways.be>
534
+ * @since 1.1.0
535
+ * @version 1.1.0
536
+ */
537
+ const Group = Function.inherits('Alchemy.Criteria.Expression', function Group(criteria, type) {
538
+
539
+ Group.super.call(this, criteria);
540
+
541
+ // The group type
542
+ this.group_type = type;
543
+ });
544
+
545
+ /**
546
+ * Revive an object
547
+ *
548
+ * @author Jelle De Loecker <jelle@elevenways.be>
549
+ * @since 1.1.0
550
+ * @version 1.1.0
551
+ *
552
+ * @return {Group}
553
+ */
554
+ Group.setStatic(function revive(data, criteria) {
555
+
556
+ let result = new Group(criteria);
557
+
558
+ result.group_type = data.group_type;
559
+
560
+ if (data.items) {
561
+ let i;
562
+ result.items = [];
563
+
564
+ for (i = 0; i < data.items.length; i++) {
565
+ result.items.push(Expression.revive(data.items[i], criteria));
566
+ }
567
+ }
568
+
569
+ return result;
570
+ });
571
+
572
+ /**
573
+ * Return object to jsonify
574
+ *
575
+ * @author Jelle De Loecker <jelle@elevenways.be>
576
+ * @since 1.1.0
577
+ * @version 1.4.0
578
+ *
579
+ * @return {Object}
580
+ */
581
+ Group.setMethod(function toJSON() {
582
+
583
+ let result = {
584
+ _type : 'group',
585
+ group_type : this.group_type,
586
+ items : this.items.slice(0)
587
+ };
588
+
589
+ if (this.association) {
590
+ result.association = this.association;
591
+ }
592
+
593
+ return result;
594
+ });
595
+
596
+ /**
597
+ * Return the elements to checksum in place of this object
598
+ *
599
+ * @author Jelle De Loecker <jelle@elevenways.be>
600
+ * @since 1.1.0
601
+ * @version 1.1.0
602
+ */
603
+ Group.setMethod(Blast.checksumSymbol, function toChecksum() {
604
+ return this.toJSON();
605
+ });