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
@@ -3,7 +3,7 @@
3
3
  *
4
4
  * @constructor
5
5
  *
6
- * @author Jelle De Loecker <jelle@develry.be>
6
+ * @author Jelle De Loecker <jelle@elevenways.be>
7
7
  * @since 0.2.0
8
8
  * @version 1.1.0
9
9
  */
@@ -14,7 +14,7 @@ var Time = Function.inherits('Alchemy.Field', function Time(schema, name, option
14
14
  /**
15
15
  * Set the datatype name
16
16
  *
17
- * @author Jelle De Loecker <jelle@develry.be>
17
+ * @author Jelle De Loecker <jelle@elevenways.be>
18
18
  * @since 0.2.0
19
19
  * @version 1.1.0
20
20
  */
@@ -23,7 +23,7 @@ Time.setDatatype('time');
23
23
  /**
24
24
  * Dates are self-contained objects
25
25
  *
26
- * @author Jelle De Loecker <jelle@develry.be>
26
+ * @author Jelle De Loecker <jelle@elevenways.be>
27
27
  * @since 1.1.0
28
28
  * @version 1.1.0
29
29
  */
@@ -32,15 +32,15 @@ Time.setSelfContained(true);
32
32
  /**
33
33
  * Cast the given value to this field's type
34
34
  *
35
- * @author Jelle De Loecker <jelle@develry.be>
35
+ * @author Jelle De Loecker <jelle@elevenways.be>
36
36
  * @since 0.2.0
37
37
  * @version 0.4.1
38
38
  *
39
- * @param {Mixed} value
39
+ * @param {*} value
40
40
  *
41
41
  * @return {Date}
42
42
  */
43
- Time.setMethod(function cast(value) {
43
+ Time.setCastFunction(function cast(value) {
44
44
 
45
45
  var result;
46
46
 
@@ -3,10 +3,8 @@
3
3
  *
4
4
  * @constructor
5
5
  *
6
- * @author Jelle De Loecker <jelle@develry.be>
6
+ * @author Jelle De Loecker <jelle@elevenways.be>
7
7
  * @since 1.1.0
8
8
  * @version 1.1.0
9
9
  */
10
- var UrlField = Function.inherits('Alchemy.Field', function Url(schema, name, options) {
11
- Url.super.call(this, schema, name, options);
12
- });
10
+ const UrlField = Function.inherits('Alchemy.Field', 'Url');
@@ -0,0 +1,662 @@
1
+ const AUGMENTED = Symbol('AUGMENTED'),
2
+ CriteriaNS = Function.getNamespace('Alchemy.Criteria'),
3
+ Expressions = Function.getNamespace('Alchemy.Criteria.Expression');
4
+
5
+ /**
6
+ * The Criteria class
7
+ *
8
+ * @author Jelle De Loecker <jelle@elevenways.be>
9
+ * @since 1.4.0
10
+ * @version 1.4.0
11
+ */
12
+ const Criteria = Function.inherits('Alchemy.Base', 'Alchemy.Criteria', function Criteria(options) {
13
+
14
+ // The current active group
15
+ this.group = null;
16
+
17
+ // All the created expressions
18
+ this.all_expressions = [];
19
+
20
+ // Create the actual group (is always AND)
21
+ this.createGroup('and');
22
+
23
+ // Store the root group
24
+ this.root_group = this.group;
25
+
26
+ // Other options
27
+ this.options = options || {};
28
+ });
29
+
30
+ /**
31
+ * Is the given argument a Criteria instance?
32
+ *
33
+ * @author Jelle De Loecker <jelle@elevenways.be>
34
+ * @since 1.1.0
35
+ * @version 1.1.0
36
+ *
37
+ * @param {Object} instance
38
+ *
39
+ * @return {boolean}
40
+ */
41
+ Criteria.setStatic(function isCriteria(instance) {
42
+
43
+ if (!instance || typeof instance != 'object') {
44
+ return false;
45
+ }
46
+
47
+ if (instance instanceof Criteria) {
48
+ return true;
49
+ }
50
+
51
+ return false;
52
+ });
53
+
54
+ /**
55
+ * Make sure to get a criteria
56
+ *
57
+ * @author Jelle De Loecker <jelle@elevenways.be>
58
+ * @since 1.4.0
59
+ * @version 1.4.0
60
+ *
61
+ * @param {Object|string|Criteria} conditions
62
+ * @param {Object} options
63
+ *
64
+ * @return {Criteria}
65
+ */
66
+ Criteria.setStatic(function cast(conditions, options) {
67
+
68
+ if (Criteria.isCriteria(conditions)) {
69
+ return conditions;
70
+ }
71
+
72
+ if (typeof conditions == 'string') {
73
+ conditions = Classes.Alchemy.Datasource.Nosql.convertAQLToConditions(conditions);
74
+ }
75
+
76
+ let instance = new Criteria(options);
77
+
78
+ if (conditions) {
79
+ instance.applyConditions(conditions);
80
+ }
81
+
82
+ return instance;
83
+ });
84
+
85
+ /**
86
+ * Add a new value expression type
87
+ *
88
+ * @author Jelle De Loecker <jelle@elevenways.be>
89
+ * @since 1.1.0
90
+ * @version 1.1.0
91
+ *
92
+ * @param {string} name The name of the expression
93
+ * @param {boolean} cast Cast the value [true]
94
+ *
95
+ * @return {Criteria}
96
+ */
97
+ Criteria.setStatic(function addValueExpression(name, cast) {
98
+ this.setMethod(name, function valueExpressionAdder(value) {
99
+
100
+ var entry;
101
+
102
+ this._ensureExpression(name);
103
+ entry = this._active.addItem(name, value);
104
+
105
+ if (cast != null) {
106
+ entry.cast = cast;
107
+ }
108
+
109
+ return this;
110
+ });
111
+ });
112
+
113
+ /**
114
+ * Add a new field expression type
115
+ *
116
+ * @author Jelle De Loecker <jelle@elevenways.be>
117
+ * @since 1.1.0
118
+ * @version 1.1.0
119
+ *
120
+ * @param {string} name The name of the expression
121
+ *
122
+ * @return {Criteria}
123
+ */
124
+ Criteria.setStatic(function addFieldExpression(name) {
125
+ this.setMethod(name, function fieldExpressionAdder(value) {
126
+
127
+ var entry;
128
+
129
+ this._ensureExpression(name);
130
+ entry = this._active.addItem(name, value);
131
+ entry.field_expression = true;
132
+
133
+ return this;
134
+ });
135
+ });
136
+
137
+ /**
138
+ * Undry the given object
139
+ *
140
+ * @author Jelle De Loecker <jelle@elevenways.be>
141
+ * @since 1.4.0
142
+ * @version 1.4.0
143
+ *
144
+ * @param {Object} data
145
+ *
146
+ * @return {Criteria}
147
+ */
148
+ Criteria.setStatic(function unDry(data) {
149
+
150
+ let criteria = new this(data.options);
151
+
152
+ // Revive the group instance
153
+ criteria.group = Expressions.Group.revive(data.group, criteria);
154
+
155
+ return criteria;
156
+ });
157
+
158
+ /**
159
+ * Dry this Criteria instance
160
+ *
161
+ * @author Jelle De Loecker <jelle@elevenways.be>
162
+ * @since 1.1.0
163
+ * @version 1.1.0
164
+ *
165
+ * @return {Object}
166
+ */
167
+ Criteria.setMethod(function toDry() {
168
+
169
+ // Augments cannot be dried, it's ALWAYS the original instance
170
+ let value = this.toJSON();
171
+
172
+ return {
173
+ value : value
174
+ };
175
+ });
176
+
177
+ /**
178
+ * Return object for jsonifying
179
+ *
180
+ * @author Jelle De Loecker <jelle@elevenways.be>
181
+ * @since 1.1.0
182
+ * @version 1.4.0
183
+ *
184
+ * @return {Object}
185
+ */
186
+ Criteria.setMethod(function toJSON() {
187
+
188
+ let result = {
189
+ group : this.group,
190
+ options : {...this.options},
191
+ };
192
+
193
+ return result;
194
+ });
195
+
196
+ /**
197
+ * Return the elements to checksum in place of this object
198
+ *
199
+ * @author Jelle De Loecker <jelle@elevenways.be>
200
+ * @since 1.1.0
201
+ * @version 1.2.3
202
+ */
203
+ Criteria.setMethod(Blast.checksumSymbol, function toChecksum() {
204
+
205
+ let name = this.model ? this.model.name : undefined,
206
+ result = [name],
207
+ options = {},
208
+ key;
209
+
210
+ for (key in this.options) {
211
+
212
+ if (key == 'init_model' || key == 'init_record' || key == 'assoc_cache') {
213
+ continue;
214
+ }
215
+
216
+ options[key] = this.options[key];
217
+ }
218
+
219
+ result.push(options);
220
+ result.push(this.group);
221
+
222
+ return result;
223
+ });
224
+
225
+ /**
226
+ * Create an augmented version of this instance
227
+ *
228
+ * @author Jelle De Loecker <jelle@elevenways.be>
229
+ * @since 1.1.0
230
+ * @version 1.1.0
231
+ *
232
+ * @param {string} type
233
+ *
234
+ * @return {Criteria}
235
+ */
236
+ Criteria.setMethod(function augment(type) {
237
+
238
+ let context = this;
239
+
240
+ if (context[AUGMENTED]) {
241
+ // NO don't do this, we want chaining!
242
+ //context = context[AUGMENTED];
243
+ }
244
+
245
+ // Create the new object with this instance as the prototype
246
+ let result = Object.create(context);
247
+
248
+ // Remembed which object we augmented
249
+ result[AUGMENTED] = context;
250
+
251
+ return result;
252
+ });
253
+
254
+ /**
255
+ * Set a specific option
256
+ *
257
+ * @author Jelle De Loecker <jelle@elevenways.be>
258
+ * @since 1.1.0
259
+ * @version 1.1.0
260
+ *
261
+ * @param {string} key
262
+ * @param {string} value
263
+ *
264
+ * @return {Criteria}
265
+ */
266
+ Criteria.setMethod(function setOption(key, value) {
267
+ this.options[key] = value;
268
+ return this;
269
+ });
270
+
271
+ /**
272
+ * Get all the queried fields
273
+ *
274
+ * @author Jelle De Loecker <jelle@elevenways.be>
275
+ * @since 1.4.0
276
+ * @version 1.4.0
277
+ *
278
+ * @return {string[]}
279
+ */
280
+ Criteria.setMethod(function getAllExpressionTargetPaths() {
281
+
282
+ let field_set = new Set(),
283
+ expression;
284
+
285
+ for (expression of this.all_expressions) {
286
+
287
+ if (!expression.target_path) {
288
+ continue;
289
+ }
290
+
291
+ field_set.add(expression.target_path);
292
+ }
293
+
294
+ return [...field_set];
295
+ });
296
+
297
+ /**
298
+ * Create a new group
299
+ *
300
+ * @author Jelle De Loecker <jelle@elevenways.be>
301
+ * @since 1.1.0
302
+ * @version 1.1.0
303
+ *
304
+ * @param {string} type
305
+ */
306
+ Criteria.setMethod(function createGroup(type) {
307
+
308
+ let context = this,
309
+ group;
310
+
311
+ if (this.group) {
312
+ let old_group = context.group;
313
+ context = context.augment('group');
314
+
315
+ group = new Expressions.Group(context, type);
316
+ old_group.addItem(group);
317
+
318
+ context.group = group;
319
+ } else {
320
+ group = new Expressions.Group(this, type);
321
+ this.group = group;
322
+ }
323
+
324
+ return context;
325
+ });
326
+
327
+ /**
328
+ * Close the current active group
329
+ *
330
+ * @author Jelle De Loecker <jelle@elevenways.be>
331
+ * @since 1.1.0
332
+ * @version 1.1.0
333
+ *
334
+ * @return {Criteria}
335
+ */
336
+ Criteria.setMethod(function closeGroup() {
337
+
338
+ let context = this;
339
+
340
+ if (this.group && this.group.current_group) {
341
+ context = this.group.current_group.criteria;
342
+ }
343
+
344
+ return context;
345
+ });
346
+
347
+ /**
348
+ * Compile to a (NoSQL) conditions object
349
+ *
350
+ * @author Jelle De Loecker <jelle@elevenways.be>
351
+ * @since 1.4.0
352
+ * @version 1.4.0
353
+ *
354
+ * @param {Object} context The optional context (for resolving values)
355
+ *
356
+ * @return {Object}
357
+ */
358
+ Criteria.setMethod(function compileToConditions(context) {
359
+ return Classes.Alchemy.Datasource.Nosql.convertCriteriaToConditions(this, context);
360
+ });
361
+
362
+ /**
363
+ * Apply old-style mongodb conditions
364
+ *
365
+ * @author Jelle De Loecker <jelle@elevenways.be>
366
+ * @since 1.1.0
367
+ * @version 1.4.0
368
+ *
369
+ * @param {Object} conditions
370
+ *
371
+ * @return {Criteria}
372
+ */
373
+ Criteria.setMethod(function applyConditions(conditions) {
374
+
375
+ if (!conditions || Object.isEmpty(conditions)) {
376
+ return this;
377
+ }
378
+
379
+ if (conditions instanceof Criteria) {
380
+ conditions = conditions.compileToConditions();
381
+ }
382
+
383
+ if (typeof conditions == 'string') {
384
+ conditions = Classes.Alchemy.Datasource.Nosql.convertAQLToConditions(conditions);
385
+ }
386
+
387
+ let context = this;
388
+
389
+ if (Array.isArray(conditions)) {
390
+ let i;
391
+
392
+ for (i = 0; i < conditions.length; i++) {
393
+ context.applyConditions(conditions[i]);
394
+ }
395
+
396
+ return context;
397
+ }
398
+
399
+ let value,
400
+ group,
401
+ key,
402
+ i = -1;
403
+
404
+ for (key in conditions) {
405
+ value = conditions[key];
406
+ i++;
407
+
408
+ if (key[0] == '$') {
409
+
410
+ // Make sure no field is currently active,
411
+ // else it'll be added to the $and or $or group
412
+ context._active = null;
413
+
414
+ if (key == '$or') {
415
+ group = context.or();
416
+ } else if (key == '$and') {
417
+
418
+ group = context.and();
419
+ } else {
420
+ throw new Error('Unable to parse "' + key + '" group');
421
+ }
422
+
423
+ group.applyConditions(value);
424
+
425
+ } else {
426
+
427
+ if (i) {
428
+ // If an object contains multiple items,
429
+ // that's always treated as an $and group
430
+ context = context.and();
431
+ }
432
+
433
+ context = context.where(key);
434
+
435
+ if (Array.isArray(value)) {
436
+ context = context.in(value);
437
+ continue;
438
+ } else if (value && typeof value == 'object') {
439
+ let had_dollar,
440
+ method,
441
+ key;
442
+
443
+ for (key in value) {
444
+ if (key[0] == '$') {
445
+ had_dollar = true;
446
+ method = key.slice(1);
447
+
448
+ if (typeof context[method] != 'function') {
449
+ if (method == 'regex') {
450
+ let regex;
451
+
452
+ if (typeof value[key] == 'string') {
453
+ regex = RegExp.interpret(RegExp.escape(value[key]), value.$options);
454
+ } else {
455
+ regex = RegExp.interpret(value[key], value.$options);
456
+ }
457
+
458
+ context.contains(regex);
459
+ break;
460
+ } else {
461
+ throw new Error('Unable to parse "' + key + '" expression');
462
+ }
463
+ } else {
464
+ context[method](value[key]);
465
+ }
466
+ }
467
+ }
468
+
469
+ if (had_dollar) {
470
+ continue;
471
+ }
472
+ }
473
+
474
+ context.equals(value);
475
+ }
476
+ }
477
+ });
478
+
479
+ /**
480
+ * Target a field
481
+ *
482
+ * @author Jelle De Loecker <jelle@elevenways.be>
483
+ * @since 1.1.0
484
+ * @version 1.4.0
485
+ *
486
+ * @param {string} name
487
+ * @param {*} value
488
+ */
489
+ Criteria.setMethod(function where(name, value) {
490
+
491
+ let context = this.augment('field'),
492
+ expression = new Expressions.Field(context, name);
493
+
494
+ this.addNewExpression(expression);
495
+
496
+ context._active = expression;
497
+
498
+ if (arguments.length == 2) {
499
+ context = context.equals(value);
500
+ }
501
+
502
+ return context;
503
+ });
504
+
505
+ /**
506
+ * Add a new expression
507
+ *
508
+ * @author Jelle De Loecker <jelle@elevenways.be>
509
+ * @since 1.1.0
510
+ * @version 1.1.0
511
+ *
512
+ * @param {Expression} expression
513
+ */
514
+ Criteria.setMethod(function addNewExpression(expression) {
515
+
516
+ // Make sure there is a criteria link
517
+ if (!expression.criteria) {
518
+ expression.criteria = this;
519
+ }
520
+
521
+ // Move the expression to the currently active group by default
522
+ expression.moveToGroup(this.group);
523
+
524
+ this.all_expressions.push(expression);
525
+ });
526
+
527
+ /**
528
+ * Make sure there is an active expression
529
+ *
530
+ * @author Jelle De Loecker <jelle@elevenways.be>
531
+ * @since 1.1.0
532
+ * @version 1.1.0
533
+ *
534
+ * @param {string} method
535
+ */
536
+ Criteria.setMethod(function _ensureExpression(method) {
537
+
538
+ if (!this._active) {
539
+ throw new Error(method + '() must be called when an expression is active');
540
+ }
541
+
542
+ this._last_method = method;
543
+ });
544
+
545
+ /**
546
+ * Create an or group
547
+ *
548
+ * @author Jelle De Loecker <jelle@elevenways.be>
549
+ * @since 1.1.0
550
+ * @version 1.1.0
551
+ *
552
+ * @param {string} type Type of group: or, and, not, ...
553
+ * @param {string} value
554
+ */
555
+ Criteria.setMethod(function _applyGroup(type, value) {
556
+
557
+ let context = this;
558
+
559
+ if (context._active) {
560
+ let temp = context._active.moveToGroup(type);
561
+ context = temp;
562
+ } else {
563
+ context = context.createGroup(type);
564
+ }
565
+
566
+ if (arguments.length > 1) {
567
+ let method = context._last_method;
568
+
569
+ if (!method) {
570
+ throw new Error('Unable to call ' + type + '() with a value when no previous method is called');
571
+ }
572
+
573
+ // Create new expression with the same field
574
+ context = context.where(context._active.target_path);
575
+
576
+ // Apply the method on it
577
+ context[method](value);
578
+ } else if (context._active) {
579
+ // Create new expression with the same field
580
+ context = context.where(context._active.target_path);
581
+ }
582
+
583
+ return context;
584
+ });
585
+
586
+ /**
587
+ * Create an or group
588
+ *
589
+ * @author Jelle De Loecker <jelle@elevenways.be>
590
+ * @since 1.1.0
591
+ * @version 1.1.0
592
+ *
593
+ * @param {string} value
594
+ */
595
+ Criteria.setMethod(function or(value) {
596
+
597
+ if (arguments.length) {
598
+ return this._applyGroup('or', value);
599
+ }
600
+
601
+ return this._applyGroup('or');
602
+ });
603
+
604
+ /**
605
+ * Create an and group
606
+ *
607
+ * @author Jelle De Loecker <jelle@elevenways.be>
608
+ * @since 1.1.0
609
+ * @version 1.1.0
610
+ *
611
+ * @param {string} value
612
+ */
613
+ Criteria.setMethod(function and(value) {
614
+
615
+ if (arguments.length) {
616
+ return this._applyGroup('and', value);
617
+ }
618
+
619
+ return this._applyGroup('and');
620
+ });
621
+
622
+ /**
623
+ * Alias for `ne`: Not equals check
624
+ *
625
+ * @author Jelle De Loecker <jelle@elevenways.be>
626
+ * @since 1.3.21
627
+ * @version 1.3.2
628
+ *
629
+ * @param {*} value
630
+ */
631
+ Criteria.setMethod(function notEquals(value) {
632
+ return this.ne(value);
633
+ });
634
+
635
+ /**
636
+ * Alias for `equals`
637
+ *
638
+ * @author Jelle De Loecker <jelle@elevenways.be>
639
+ * @since 1.4.0
640
+ * @version 1.4.0
641
+ *
642
+ * @param {*} value
643
+ */
644
+ Criteria.setMethod(function eq(value) {
645
+ return this.equals(value);
646
+ });
647
+
648
+ Criteria.addValueExpression('equals');
649
+ Criteria.addValueExpression('gte');
650
+ Criteria.addValueExpression('gt');
651
+ Criteria.addValueExpression('lte');
652
+ Criteria.addValueExpression('lt');
653
+ Criteria.addValueExpression('in');
654
+
655
+ // Add as value expressions of which we don't cast values
656
+ Criteria.addValueExpression('contains', false);
657
+ Criteria.addValueExpression('not', false);
658
+ Criteria.addValueExpression('ne', false);
659
+
660
+ Criteria.addFieldExpression('exists');
661
+ Criteria.addFieldExpression('isNull');
662
+ Criteria.addFieldExpression('isEmpty');