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.
- package/LICENSE +1 -1
- package/README.md +3 -3
- package/lib/app/behaviour/publishable_behaviour.js +5 -5
- package/lib/app/behaviour/revision_behaviour.js +10 -10
- package/lib/app/behaviour/sluggable_behaviour.js +14 -14
- package/lib/app/conduit/electron_conduit.js +9 -9
- package/lib/app/conduit/http_conduit.js +13 -13
- package/lib/app/conduit/loopback_conduit.js +15 -15
- package/lib/app/conduit/socket_conduit.js +43 -43
- package/lib/app/config/routes.js +26 -0
- package/lib/app/controller/00-default_app_controller.js +21 -0
- package/lib/app/controller/alchemy_info_controller.js +12 -12
- package/lib/app/datasource/mongo_datasource.js +16 -16
- package/lib/app/element/00-default_app_element.js +19 -0
- package/lib/app/element/time_ago.js +5 -5
- package/lib/app/helper/00-default_app_helper.js +11 -0
- package/lib/app/helper/alchemy_helper.js +22 -22
- package/lib/app/helper/backed_map.js +1 -1
- package/lib/app/helper/breadcrumb.js +10 -10
- package/lib/app/helper/client_collection.js +3 -3
- package/lib/app/helper/cron.js +29 -29
- package/lib/app/helper/enum_values.js +6 -6
- package/lib/app/helper/pagination_helper.js +36 -36
- package/lib/app/helper/router_helper.js +35 -35
- package/lib/app/helper/socket_helper.js +57 -57
- package/lib/app/helper/syncable.js +84 -59
- package/lib/app/helper_component/paginate_component.js +9 -9
- package/lib/app/helper_controller/component.js +1 -1
- package/lib/app/helper_controller/conduit.js +31 -31
- package/lib/app/helper_controller/controller.js +54 -39
- package/lib/app/helper_datasource/00-nosql_datasource.js +624 -70
- package/lib/app/helper_datasource/05-fallback_datasource.js +10 -10
- package/lib/app/helper_datasource/idb_datasource.js +6 -6
- package/lib/app/helper_datasource/indexed_db.js +22 -22
- package/lib/app/helper_datasource/remote_datasource.js +5 -5
- package/lib/app/helper_error/http_error.js +4 -4
- package/lib/app/helper_error/model_error.js +2 -2
- package/lib/app/helper_error/validation_error.js +12 -12
- package/lib/app/helper_field/00-objectid_field.js +7 -7
- package/lib/app/helper_field/05-string_field.js +16 -12
- package/lib/app/helper_field/06-text_field.js +2 -4
- package/lib/app/helper_field/10-number_field.js +9 -12
- package/lib/app/helper_field/11-date_field.js +15 -15
- package/lib/app/helper_field/15-local_temporal_field.js +10 -10
- package/lib/app/helper_field/20-decimal_field.js +8 -9
- package/lib/app/helper_field/belongsto_field.js +1 -1
- package/lib/app/helper_field/big_int_field.js +8 -8
- package/lib/app/helper_field/boolean_field.js +9 -11
- package/lib/app/helper_field/datetime_field.js +3 -3
- package/lib/app/helper_field/enum_field.js +13 -8
- package/lib/app/helper_field/fixed_decimal_field.js +6 -7
- package/lib/app/helper_field/geopoint_field.js +9 -10
- package/lib/app/helper_field/habtm_field.js +3 -3
- package/lib/app/helper_field/hasoneparent_field.js +1 -1
- package/lib/app/helper_field/html_field.js +2 -4
- package/lib/app/helper_field/integer_field.js +8 -11
- package/lib/app/helper_field/local_date_field.js +5 -5
- package/lib/app/helper_field/local_date_time_field.js +5 -5
- package/lib/app/helper_field/local_time_field.js +5 -5
- package/lib/app/helper_field/mixed_field.js +5 -5
- package/lib/app/helper_field/object_field.js +8 -8
- package/lib/app/helper_field/password_field.js +3 -3
- package/lib/app/helper_field/regexp_field.js +7 -9
- package/lib/app/helper_field/schema_field.js +91 -88
- package/lib/app/helper_field/settings_field.js +92 -0
- package/lib/app/helper_field/time_field.js +6 -6
- package/lib/app/helper_field/url_field.js +2 -4
- package/lib/app/helper_model/00-base_criteria.js +662 -0
- package/lib/app/helper_model/05-criteria_expressions.js +605 -0
- package/lib/app/helper_model/10-model_criteria.js +1182 -0
- package/lib/app/helper_model/data_provider.js +2 -2
- package/lib/app/helper_model/document.js +103 -92
- package/lib/app/helper_model/document_list.js +14 -14
- package/lib/app/helper_model/field_config.js +11 -11
- package/lib/app/helper_model/field_set.js +17 -17
- package/lib/app/helper_model/model.js +203 -124
- package/lib/app/helper_model/remote_data_provider.js +2 -2
- package/lib/app/helper_validator/00_validator.js +16 -16
- package/lib/app/helper_validator/not_empty_validator.js +9 -9
- package/lib/app/model/00-default_app_model.js +18 -0
- package/lib/app/model/05-system_model.js +27 -0
- package/lib/app/model/{alchemy_migration_model.js → system_migration_model.js} +4 -4
- package/lib/app/model/system_setting_model.js +154 -0
- package/lib/app/model/{alchemy_task_history_model.js → system_task_history_model.js} +7 -7
- package/lib/app/model/{alchemy_task_model.js → system_task_model.js} +11 -11
- package/lib/bootstrap.js +22 -312
- package/lib/class/accumulator.js +5 -5
- package/lib/class/behaviour.js +5 -5
- package/lib/class/component.js +3 -3
- package/lib/class/conduit.js +203 -163
- package/lib/class/controller.js +42 -42
- package/lib/class/datasource.js +74 -79
- package/lib/class/document.js +74 -95
- package/lib/class/document_list.js +5 -5
- package/lib/class/element.js +17 -17
- package/lib/class/error.js +3 -3
- package/lib/class/field.js +169 -91
- package/lib/class/field_value.js +6 -6
- package/lib/class/helper.js +3 -3
- package/lib/class/inode.js +17 -17
- package/lib/class/inode_dir.js +12 -12
- package/lib/class/inode_file.js +50 -25
- package/lib/class/inode_list.js +4 -4
- package/lib/class/migration.js +4 -4
- package/lib/class/model.js +182 -168
- package/lib/class/path_definition.js +22 -22
- package/lib/class/path_evaluator.js +5 -5
- package/lib/class/path_param_definition.js +7 -7
- package/lib/class/plugin.js +312 -0
- package/lib/class/postponement.js +29 -29
- package/lib/class/reciprocal.js +8 -8
- package/lib/class/route.js +33 -33
- package/lib/class/router.js +73 -73
- package/lib/class/schema.js +21 -21
- package/lib/class/schema_client.js +73 -67
- package/lib/class/session.js +63 -29
- package/lib/class/session_scene.js +4 -4
- package/lib/class/sitemap.js +16 -16
- package/lib/class/task.js +39 -39
- package/lib/class/task_service.js +43 -47
- package/lib/{init → core}/alchemy.js +413 -374
- package/lib/{init/functions.js → core/alchemy_functions.js} +171 -108
- package/lib/core/alchemy_load_functions.js +715 -0
- package/lib/core/base.js +50 -62
- package/lib/core/client_alchemy.js +144 -152
- package/lib/core/client_base.js +39 -52
- package/lib/core/discovery.js +16 -18
- package/lib/core/middleware.js +54 -43
- package/lib/core/{routing.js → prefix.js} +14 -16
- package/lib/core/setting.js +1684 -0
- package/lib/core/stage.js +758 -0
- package/lib/scripts/create_constants.js +119 -0
- package/lib/{init/languages.js → scripts/create_languages.js} +5 -5
- package/lib/scripts/create_settings.js +449 -0
- package/lib/scripts/create_shared_constants.js +95 -0
- package/lib/scripts/create_stages.js +55 -0
- package/lib/scripts/init_alchemy.js +51 -0
- package/lib/{init/requirements.js → scripts/preload_modules.js} +15 -2
- package/lib/scripts/setup_devwatch.js +238 -0
- package/lib/stages/00-load_core.js +342 -0
- package/lib/stages/05-load_app.js +57 -0
- package/lib/stages/10-datasource.js +61 -0
- package/lib/stages/15-tasks.js +27 -0
- package/lib/stages/20-settings.js +68 -0
- package/lib/stages/50-routes.js +218 -0
- package/lib/stages/90-server.js +347 -0
- package/package.json +5 -7
- package/lib/app/helper_model/criteria.js +0 -2294
- package/lib/app/helper_model/db_query.js +0 -1488
- package/lib/app/routes.js +0 -11
- package/lib/core/socket.js +0 -171
- package/lib/init/constants.js +0 -158
- package/lib/init/devwatch.js +0 -238
- package/lib/init/load_functions.js +0 -973
- package/lib/stages.js +0 -513
|
@@ -1,2294 +0,0 @@
|
|
|
1
|
-
const AUGMENTED = Symbol('AUGMENTED');
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* The Criteria class
|
|
5
|
-
*
|
|
6
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
7
|
-
* @since 1.1.0
|
|
8
|
-
* @version 1.3.4
|
|
9
|
-
*
|
|
10
|
-
* @param {Model} model
|
|
11
|
-
*/
|
|
12
|
-
var Criteria = Function.inherits('Alchemy.Base', 'Alchemy.Criteria', function Criteria(model) {
|
|
13
|
-
|
|
14
|
-
// The current active group
|
|
15
|
-
this.group = null;
|
|
16
|
-
|
|
17
|
-
// The model
|
|
18
|
-
this.model = model;
|
|
19
|
-
|
|
20
|
-
// All the created expressions
|
|
21
|
-
this.all_expressions = [];
|
|
22
|
-
|
|
23
|
-
// Create the actual group (is always AND)
|
|
24
|
-
this.createGroup('and');
|
|
25
|
-
|
|
26
|
-
// Store the root group
|
|
27
|
-
this.root_group = this.group;
|
|
28
|
-
|
|
29
|
-
// Other options
|
|
30
|
-
this.options = {
|
|
31
|
-
select : new Select(this),
|
|
32
|
-
document : true,
|
|
33
|
-
document_list : true
|
|
34
|
-
};
|
|
35
|
-
});
|
|
36
|
-
|
|
37
|
-
/**
|
|
38
|
-
* Is the given argument a Criteria instance?
|
|
39
|
-
*
|
|
40
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
41
|
-
* @since 1.1.0
|
|
42
|
-
* @version 1.1.0
|
|
43
|
-
*
|
|
44
|
-
* @param {Object} instance
|
|
45
|
-
*
|
|
46
|
-
* @return {Boolean}
|
|
47
|
-
*/
|
|
48
|
-
Criteria.setStatic(function isCriteria(instance) {
|
|
49
|
-
|
|
50
|
-
if (!instance || typeof instance != 'object') {
|
|
51
|
-
return false;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
if (instance instanceof Criteria) {
|
|
55
|
-
return true;
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
return false;
|
|
59
|
-
});
|
|
60
|
-
|
|
61
|
-
/**
|
|
62
|
-
* Make sure to get a criteria
|
|
63
|
-
*
|
|
64
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
65
|
-
* @since 1.2.5
|
|
66
|
-
* @version 1.3.4
|
|
67
|
-
*
|
|
68
|
-
* @param {Object} obj The thing that should be a criteria
|
|
69
|
-
* @param {Model} model The model that it probably belongs to
|
|
70
|
-
*
|
|
71
|
-
* @return {Criteria}
|
|
72
|
-
*/
|
|
73
|
-
Criteria.setStatic(function cast(obj, model) {
|
|
74
|
-
|
|
75
|
-
if (Criteria.isCriteria(obj)) {
|
|
76
|
-
return obj;
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
let instance = new Criteria(model);
|
|
80
|
-
|
|
81
|
-
if (obj) {
|
|
82
|
-
instance.applyOldOptions(obj);
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
return instance;
|
|
86
|
-
});
|
|
87
|
-
|
|
88
|
-
/**
|
|
89
|
-
* Undry the given object
|
|
90
|
-
*
|
|
91
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
92
|
-
* @since 1.1.0
|
|
93
|
-
* @version 1.2.3
|
|
94
|
-
*
|
|
95
|
-
* @param {Object} data
|
|
96
|
-
*
|
|
97
|
-
* @return {Criteria}
|
|
98
|
-
*/
|
|
99
|
-
Criteria.setStatic(function unDry(data) {
|
|
100
|
-
|
|
101
|
-
var criteria = new Criteria();
|
|
102
|
-
|
|
103
|
-
if (data.model) {
|
|
104
|
-
try {
|
|
105
|
-
criteria.model = alchemy.getModel(data.model);
|
|
106
|
-
} catch (err) {
|
|
107
|
-
// Ignore
|
|
108
|
-
console.warn('Failed to find "' + data.model + '" model');
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
|
|
112
|
-
// Revive the group instance
|
|
113
|
-
criteria.group = Group.revive(data.group, criteria);
|
|
114
|
-
|
|
115
|
-
if (!data.options) {
|
|
116
|
-
data.options = {};
|
|
117
|
-
}
|
|
118
|
-
|
|
119
|
-
// Revive the select
|
|
120
|
-
data.options.select = Select.revive(data.options.select, criteria);
|
|
121
|
-
|
|
122
|
-
criteria.options = data.options || {};
|
|
123
|
-
|
|
124
|
-
return criteria;
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
/**
|
|
128
|
-
* Add a new value expression type
|
|
129
|
-
*
|
|
130
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
131
|
-
* @since 1.1.0
|
|
132
|
-
* @version 1.1.0
|
|
133
|
-
*
|
|
134
|
-
* @param {String} name The name of the expression
|
|
135
|
-
* @param {Boolean} cast Cast the value [true]
|
|
136
|
-
*
|
|
137
|
-
* @return {Criteria}
|
|
138
|
-
*/
|
|
139
|
-
Criteria.setStatic(function addValueExpression(name, cast) {
|
|
140
|
-
this.setMethod(name, function valueExpressionAdder(value) {
|
|
141
|
-
|
|
142
|
-
var entry;
|
|
143
|
-
|
|
144
|
-
this._ensureExpression(name);
|
|
145
|
-
entry = this._active.addItem(name, value);
|
|
146
|
-
|
|
147
|
-
if (cast != null) {
|
|
148
|
-
entry.cast = cast;
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
return this;
|
|
152
|
-
});
|
|
153
|
-
});
|
|
154
|
-
|
|
155
|
-
/**
|
|
156
|
-
* Add a new field expression type
|
|
157
|
-
*
|
|
158
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
159
|
-
* @since 1.1.0
|
|
160
|
-
* @version 1.1.0
|
|
161
|
-
*
|
|
162
|
-
* @param {String} name The name of the expression
|
|
163
|
-
*
|
|
164
|
-
* @return {Criteria}
|
|
165
|
-
*/
|
|
166
|
-
Criteria.setStatic(function addFieldExpression(name) {
|
|
167
|
-
this.setMethod(name, function fieldExpressionAdder(value) {
|
|
168
|
-
|
|
169
|
-
var entry;
|
|
170
|
-
|
|
171
|
-
this._ensureExpression(name);
|
|
172
|
-
entry = this._active.addItem(name, value);
|
|
173
|
-
entry.field_expression = true;
|
|
174
|
-
|
|
175
|
-
return this;
|
|
176
|
-
});
|
|
177
|
-
});
|
|
178
|
-
|
|
179
|
-
/**
|
|
180
|
-
* Create an augmented of this instance
|
|
181
|
-
*
|
|
182
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
183
|
-
* @since 1.1.0
|
|
184
|
-
* @version 1.1.0
|
|
185
|
-
*
|
|
186
|
-
* @param {String} path
|
|
187
|
-
* @param {Criteria} criteria
|
|
188
|
-
*
|
|
189
|
-
* @return {Object}
|
|
190
|
-
*/
|
|
191
|
-
Criteria.setStatic(function parsePath(path, criteria) {
|
|
192
|
-
|
|
193
|
-
var target_path,
|
|
194
|
-
result = {},
|
|
195
|
-
pieces,
|
|
196
|
-
piece,
|
|
197
|
-
alias,
|
|
198
|
-
i;
|
|
199
|
-
|
|
200
|
-
if (path.indexOf('.') > -1) {
|
|
201
|
-
pieces = path.split('.');
|
|
202
|
-
} else {
|
|
203
|
-
pieces = [path];
|
|
204
|
-
}
|
|
205
|
-
|
|
206
|
-
for (i = 0; i < pieces.length; i++) {
|
|
207
|
-
piece = pieces[i];
|
|
208
|
-
alias = null;
|
|
209
|
-
|
|
210
|
-
if (criteria && criteria.model) {
|
|
211
|
-
if (criteria.model.associations[piece]) {
|
|
212
|
-
alias = piece;
|
|
213
|
-
}
|
|
214
|
-
}
|
|
215
|
-
|
|
216
|
-
if (!alias && piece[0].isUpperCase()) {
|
|
217
|
-
alias = piece;
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
if (alias) {
|
|
221
|
-
if (!result.association) {
|
|
222
|
-
result.association = [];
|
|
223
|
-
}
|
|
224
|
-
|
|
225
|
-
result.association.push(alias);
|
|
226
|
-
continue;
|
|
227
|
-
}
|
|
228
|
-
|
|
229
|
-
target_path = pieces.slice(i).join('.');
|
|
230
|
-
break;
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
if (target_path) {
|
|
234
|
-
result.target_path = target_path;
|
|
235
|
-
}
|
|
236
|
-
|
|
237
|
-
return result;
|
|
238
|
-
});
|
|
239
|
-
|
|
240
|
-
/**
|
|
241
|
-
* Create a reference to the datasource
|
|
242
|
-
*
|
|
243
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
244
|
-
* @since 1.1.0
|
|
245
|
-
* @version 1.1.0
|
|
246
|
-
*
|
|
247
|
-
* @type {Datasource}
|
|
248
|
-
*/
|
|
249
|
-
Criteria.setProperty(function datasource() {
|
|
250
|
-
|
|
251
|
-
if (this._datasource) {
|
|
252
|
-
return this._datasource;
|
|
253
|
-
}
|
|
254
|
-
|
|
255
|
-
if (this.model) {
|
|
256
|
-
return this.model.datasource;
|
|
257
|
-
}
|
|
258
|
-
}, function setDatasource(ds) {
|
|
259
|
-
this._datasource = ds;
|
|
260
|
-
return this._datasource;
|
|
261
|
-
});
|
|
262
|
-
|
|
263
|
-
/**
|
|
264
|
-
* The recursiveness of this criteria
|
|
265
|
-
*
|
|
266
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
267
|
-
* @since 1.1.0
|
|
268
|
-
* @version 1.1.0
|
|
269
|
-
*
|
|
270
|
-
* @type {Number}
|
|
271
|
-
*/
|
|
272
|
-
Criteria.setProperty(function recursive_level() {
|
|
273
|
-
|
|
274
|
-
if (this.options.recursive) {
|
|
275
|
-
return this.options.recursive;
|
|
276
|
-
}
|
|
277
|
-
|
|
278
|
-
return 0;
|
|
279
|
-
});
|
|
280
|
-
|
|
281
|
-
/**
|
|
282
|
-
* Return the elements to checksum in place of this object
|
|
283
|
-
*
|
|
284
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
285
|
-
* @since 1.1.0
|
|
286
|
-
* @version 1.2.3
|
|
287
|
-
*/
|
|
288
|
-
Criteria.setMethod(Blast.checksumSymbol, function toChecksum() {
|
|
289
|
-
|
|
290
|
-
var name = this.model ? this.model.name : undefined,
|
|
291
|
-
result = [name],
|
|
292
|
-
options = {},
|
|
293
|
-
key;
|
|
294
|
-
|
|
295
|
-
for (key in this.options) {
|
|
296
|
-
|
|
297
|
-
if (key == 'init_model' || key == 'init_record' || key == 'assoc_cache') {
|
|
298
|
-
continue;
|
|
299
|
-
}
|
|
300
|
-
|
|
301
|
-
options[key] = this.options[key];
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
result.push(options);
|
|
305
|
-
result.push(this.group);
|
|
306
|
-
|
|
307
|
-
return result;
|
|
308
|
-
});
|
|
309
|
-
|
|
310
|
-
/**
|
|
311
|
-
* Allow the criteria to be used in a for wait loop
|
|
312
|
-
*
|
|
313
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
314
|
-
* @since 1.1.0
|
|
315
|
-
* @version 1.1.0
|
|
316
|
-
*/
|
|
317
|
-
Criteria.setMethod(Symbol.asyncIterator, function asyncIterator() {
|
|
318
|
-
|
|
319
|
-
const that = this,
|
|
320
|
-
model = this.model;
|
|
321
|
-
|
|
322
|
-
if (!model) {
|
|
323
|
-
throw new Error('Unable to iterate over a criteria without a model');
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
// Clone it
|
|
327
|
-
let criteria = this.clone();
|
|
328
|
-
|
|
329
|
-
// Set the limit to 1
|
|
330
|
-
criteria.limit(1);
|
|
331
|
-
|
|
332
|
-
// Create the iterator context
|
|
333
|
-
let context = {
|
|
334
|
-
index : 0,
|
|
335
|
-
next : async function next() {
|
|
336
|
-
|
|
337
|
-
criteria.skip(this.index++);
|
|
338
|
-
|
|
339
|
-
let record = await model.find('first', criteria);
|
|
340
|
-
|
|
341
|
-
if (!record) {
|
|
342
|
-
return {done: true};
|
|
343
|
-
}
|
|
344
|
-
|
|
345
|
-
return {value: record, done: false};
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
return context;
|
|
350
|
-
});
|
|
351
|
-
|
|
352
|
-
/**
|
|
353
|
-
* Return object for jsonifying
|
|
354
|
-
*
|
|
355
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
356
|
-
* @since 1.1.0
|
|
357
|
-
* @version 1.2.3
|
|
358
|
-
*
|
|
359
|
-
* @return {Object}
|
|
360
|
-
*/
|
|
361
|
-
Criteria.setMethod(function toJSON() {
|
|
362
|
-
|
|
363
|
-
let result = {},
|
|
364
|
-
options;
|
|
365
|
-
|
|
366
|
-
if (this.model && this.model.name) {
|
|
367
|
-
result.model = this.model.name;
|
|
368
|
-
}
|
|
369
|
-
|
|
370
|
-
if (this.options) {
|
|
371
|
-
let key;
|
|
372
|
-
options = {};
|
|
373
|
-
|
|
374
|
-
for (key in this.options) {
|
|
375
|
-
if (key == 'assoc_cache' || key == 'init_record') {
|
|
376
|
-
continue;
|
|
377
|
-
}
|
|
378
|
-
|
|
379
|
-
options[key] = this.options[key];
|
|
380
|
-
}
|
|
381
|
-
}
|
|
382
|
-
|
|
383
|
-
result.group = this.group;
|
|
384
|
-
result.options = options;
|
|
385
|
-
|
|
386
|
-
return result;
|
|
387
|
-
});
|
|
388
|
-
|
|
389
|
-
/**
|
|
390
|
-
* Dry this Criteria instance
|
|
391
|
-
*
|
|
392
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
393
|
-
* @since 1.1.0
|
|
394
|
-
* @version 1.1.0
|
|
395
|
-
*
|
|
396
|
-
* @return {Object}
|
|
397
|
-
*/
|
|
398
|
-
Criteria.setMethod(function toDry() {
|
|
399
|
-
|
|
400
|
-
// Augments cannot be dried, it's ALWAYS the original instance
|
|
401
|
-
var value = this.toJSON();
|
|
402
|
-
|
|
403
|
-
return {
|
|
404
|
-
value : value
|
|
405
|
-
};
|
|
406
|
-
});
|
|
407
|
-
|
|
408
|
-
/**
|
|
409
|
-
* Clone this instance
|
|
410
|
-
*
|
|
411
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
412
|
-
* @since 1.1.0
|
|
413
|
-
* @version 1.1.0
|
|
414
|
-
*
|
|
415
|
-
* @return {Criteria}
|
|
416
|
-
*/
|
|
417
|
-
Criteria.setMethod(function clone() {
|
|
418
|
-
|
|
419
|
-
var data = JSON.toDryObject(this),
|
|
420
|
-
result;
|
|
421
|
-
|
|
422
|
-
data.model = null;
|
|
423
|
-
result = JSON.undry(data);
|
|
424
|
-
|
|
425
|
-
result.model = this.model;
|
|
426
|
-
|
|
427
|
-
return result;
|
|
428
|
-
});
|
|
429
|
-
|
|
430
|
-
/**
|
|
431
|
-
* Get the main fields to select
|
|
432
|
-
*
|
|
433
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
434
|
-
* @since 1.1.0
|
|
435
|
-
* @version 1.2.3
|
|
436
|
-
*
|
|
437
|
-
* @return {String[]}
|
|
438
|
-
*/
|
|
439
|
-
Criteria.setMethod(function getFieldsToSelect() {
|
|
440
|
-
|
|
441
|
-
let result;
|
|
442
|
-
|
|
443
|
-
if (this.options?.select?.fields?.length) {
|
|
444
|
-
result = this.options.select.fields.slice(0);
|
|
445
|
-
}
|
|
446
|
-
|
|
447
|
-
// Fields can sometimes be required for a query (like in a join) but they
|
|
448
|
-
// won't be selected if other fields are explicitly set.
|
|
449
|
-
// So in that case: add these special fields to the projection
|
|
450
|
-
if (result && this.options?.select?.query_fields) {
|
|
451
|
-
result.push(...this.options.select.query_fields);
|
|
452
|
-
}
|
|
453
|
-
|
|
454
|
-
return result || [];
|
|
455
|
-
});
|
|
456
|
-
|
|
457
|
-
/**
|
|
458
|
-
* Get the association selects, if any
|
|
459
|
-
*
|
|
460
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
461
|
-
* @since 1.1.0
|
|
462
|
-
* @version 1.1.0
|
|
463
|
-
*
|
|
464
|
-
* @return {Object}
|
|
465
|
-
*/
|
|
466
|
-
Criteria.setMethod(function getAssociationsToSelect() {
|
|
467
|
-
|
|
468
|
-
var result = this.options.select.associations;
|
|
469
|
-
|
|
470
|
-
return result;
|
|
471
|
-
});
|
|
472
|
-
|
|
473
|
-
/**
|
|
474
|
-
* Should the given association be queried?
|
|
475
|
-
*
|
|
476
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
477
|
-
* @since 1.1.0
|
|
478
|
-
* @version 1.1.0
|
|
479
|
-
*
|
|
480
|
-
* @param {String} name
|
|
481
|
-
*
|
|
482
|
-
* @return {Boolean}
|
|
483
|
-
*/
|
|
484
|
-
Criteria.setMethod(function shouldQueryAssociation(name) {
|
|
485
|
-
|
|
486
|
-
var result = false;
|
|
487
|
-
|
|
488
|
-
// If there are explicit associations selected,
|
|
489
|
-
// then this one has to be in it!
|
|
490
|
-
if (this.getAssociationsToSelect()) {
|
|
491
|
-
result = this.options.select.shouldQueryAssociation(name);
|
|
492
|
-
} else {
|
|
493
|
-
// There are no explicit associations, look at the recursive level
|
|
494
|
-
result = this.recursive_level > 0;
|
|
495
|
-
}
|
|
496
|
-
|
|
497
|
-
return result;
|
|
498
|
-
});
|
|
499
|
-
|
|
500
|
-
/**
|
|
501
|
-
* Get association configuration in the current active model
|
|
502
|
-
* or in the options
|
|
503
|
-
*
|
|
504
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
505
|
-
* @since 1.1.0
|
|
506
|
-
* @version 1.1.0
|
|
507
|
-
*
|
|
508
|
-
* @param {String} alias
|
|
509
|
-
*
|
|
510
|
-
* @return {Object}
|
|
511
|
-
*/
|
|
512
|
-
Criteria.setMethod(function getAssociationConfiguration(alias) {
|
|
513
|
-
|
|
514
|
-
if (this.options.associations && this.options.associations[alias]) {
|
|
515
|
-
return this.options.associations[alias];
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
return this.model.getAssociation(alias);
|
|
519
|
-
});
|
|
520
|
-
|
|
521
|
-
/**
|
|
522
|
-
* Get a new criteria for adding associated data
|
|
523
|
-
*
|
|
524
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
525
|
-
* @since 1.1.0
|
|
526
|
-
* @version 1.2.3
|
|
527
|
-
*
|
|
528
|
-
* @param {String} name
|
|
529
|
-
* @param {Object} item
|
|
530
|
-
*
|
|
531
|
-
* @return {Criteria}
|
|
532
|
-
*/
|
|
533
|
-
Criteria.setMethod(function getCriteriaForAssociation(name, item) {
|
|
534
|
-
|
|
535
|
-
if (!this.model) {
|
|
536
|
-
throw new Error('Unable to create criteria for association "' + name + '" without originating model instance');
|
|
537
|
-
}
|
|
538
|
-
|
|
539
|
-
let assoc_model = this.model.getAliasModel(name),
|
|
540
|
-
data = item[this.model.name];
|
|
541
|
-
|
|
542
|
-
// @TODO: For deadlock reasons we don't query self-referencing links!
|
|
543
|
-
// (Implemented in Schema fields, BelongsTo and such could still pose problems!)
|
|
544
|
-
if (assoc_model.name == this.options.init_model) {
|
|
545
|
-
return;
|
|
546
|
-
}
|
|
547
|
-
|
|
548
|
-
let association = this.getAssociationConfiguration(name);
|
|
549
|
-
|
|
550
|
-
let value = data[association.options.localKey];
|
|
551
|
-
|
|
552
|
-
// If no valid value is found for the associated key, do nothing
|
|
553
|
-
if (value == null) {
|
|
554
|
-
return;
|
|
555
|
-
}
|
|
556
|
-
|
|
557
|
-
let assoc_crit = assoc_model.find(),
|
|
558
|
-
assoc_key = association.options.foreignKey,
|
|
559
|
-
options = this.options,
|
|
560
|
-
select;
|
|
561
|
-
|
|
562
|
-
if (Array.isArray(value)) {
|
|
563
|
-
assoc_crit.where(assoc_key).in(value);
|
|
564
|
-
} else {
|
|
565
|
-
assoc_crit.where(assoc_key).equals(value);
|
|
566
|
-
}
|
|
567
|
-
|
|
568
|
-
assoc_crit.setOption('assoc_key', assoc_key);
|
|
569
|
-
assoc_crit.setOption('assoc_value', value);
|
|
570
|
-
|
|
571
|
-
// Make the assoc_cache if it doesn't exist yet
|
|
572
|
-
if (options.create_references !== false && !options.assoc_cache) {
|
|
573
|
-
options.assoc_cache = {};
|
|
574
|
-
}
|
|
575
|
-
|
|
576
|
-
// Add the assoc_cache
|
|
577
|
-
if (options.assoc_cache) {
|
|
578
|
-
assoc_crit.setOption('assoc_cache', options.assoc_cache);
|
|
579
|
-
}
|
|
580
|
-
|
|
581
|
-
// Take over the locale option
|
|
582
|
-
if (options.locale) {
|
|
583
|
-
assoc_crit.setOption('locale', options.locale);
|
|
584
|
-
}
|
|
585
|
-
|
|
586
|
-
// The debug object, if there is one
|
|
587
|
-
if (options._debugObject) {
|
|
588
|
-
assoc_crit.setOption('_debugObject', options._debugObject);
|
|
589
|
-
}
|
|
590
|
-
|
|
591
|
-
// Don't get the available count
|
|
592
|
-
assoc_crit.setOption('available', false);
|
|
593
|
-
|
|
594
|
-
if (options.select.associations && options.select.associations[name]) {
|
|
595
|
-
select = options.select.associations[name];
|
|
596
|
-
assoc_crit.options.select = select.cloneForCriteria(assoc_crit);
|
|
597
|
-
}
|
|
598
|
-
|
|
599
|
-
// Sort the results
|
|
600
|
-
// @TODO: add sorts
|
|
601
|
-
// if (query.sort && query.sort[alias]) {
|
|
602
|
-
// assocOpts.sort = query.sort[alias];
|
|
603
|
-
// }
|
|
604
|
-
|
|
605
|
-
if (Number.isSafeInteger(options.recursive) && options.recursive > 0) {
|
|
606
|
-
assoc_crit.recursive(options.recursive - 1);
|
|
607
|
-
} else {
|
|
608
|
-
// Disable recursiveness for the next level
|
|
609
|
-
assoc_crit.recursive(0);
|
|
610
|
-
}
|
|
611
|
-
|
|
612
|
-
// Add the model name from where we're adding associated data
|
|
613
|
-
assoc_crit.setOption('init_model', options.init_model || this.model.name);
|
|
614
|
-
assoc_crit.setOption('init_record', options.init_record || item);
|
|
615
|
-
|
|
616
|
-
assoc_crit.setOption('from_alias', options.for_alias);
|
|
617
|
-
assoc_crit.setOption('from_model', options.for_model);
|
|
618
|
-
|
|
619
|
-
assoc_crit.setOption('for_alias', name);
|
|
620
|
-
assoc_crit.setOption('for_model', assoc_model.name);
|
|
621
|
-
|
|
622
|
-
// Honor the original document option
|
|
623
|
-
assoc_crit.setOption('document', options.document);
|
|
624
|
-
|
|
625
|
-
if (options.debug) {
|
|
626
|
-
assoc_crit.setOption('debug', true);
|
|
627
|
-
console.log('Associated criteria:', assoc_model.name, assoc_crit);
|
|
628
|
-
}
|
|
629
|
-
|
|
630
|
-
return assoc_crit;
|
|
631
|
-
});
|
|
632
|
-
|
|
633
|
-
/**
|
|
634
|
-
* Create an augmented of this instance
|
|
635
|
-
*
|
|
636
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
637
|
-
* @since 1.1.0
|
|
638
|
-
* @version 1.1.0
|
|
639
|
-
*
|
|
640
|
-
* @param {String} type
|
|
641
|
-
*
|
|
642
|
-
* @return {Criteria}
|
|
643
|
-
*/
|
|
644
|
-
Criteria.setMethod(function augment(type) {
|
|
645
|
-
|
|
646
|
-
var context = this,
|
|
647
|
-
result;
|
|
648
|
-
|
|
649
|
-
if (context[AUGMENTED]) {
|
|
650
|
-
// NO don't do this, we want chaining!
|
|
651
|
-
//context = context[AUGMENTED];
|
|
652
|
-
}
|
|
653
|
-
|
|
654
|
-
// Create the new object with this instance as the prototype
|
|
655
|
-
result = Object.create(context);
|
|
656
|
-
|
|
657
|
-
// Remembed which object we augmented
|
|
658
|
-
result[AUGMENTED] = context;
|
|
659
|
-
|
|
660
|
-
return result;
|
|
661
|
-
});
|
|
662
|
-
|
|
663
|
-
/**
|
|
664
|
-
* Limit the amount of records to get
|
|
665
|
-
*
|
|
666
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
667
|
-
* @since 1.1.0
|
|
668
|
-
* @version 1.2.7
|
|
669
|
-
*
|
|
670
|
-
* @param {Number} amount
|
|
671
|
-
*
|
|
672
|
-
* @return {Criteria}
|
|
673
|
-
*/
|
|
674
|
-
Criteria.setMethod(function limit(amount) {
|
|
675
|
-
|
|
676
|
-
if (typeof amount != 'number') {
|
|
677
|
-
amount = parseInt(amount);
|
|
678
|
-
}
|
|
679
|
-
|
|
680
|
-
this.options.limit = amount;
|
|
681
|
-
return this;
|
|
682
|
-
});
|
|
683
|
-
|
|
684
|
-
/**
|
|
685
|
-
* Skip an amount of records
|
|
686
|
-
*
|
|
687
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
688
|
-
* @since 1.1.0
|
|
689
|
-
* @version 1.2.7
|
|
690
|
-
*
|
|
691
|
-
* @param {Number} amount
|
|
692
|
-
*
|
|
693
|
-
* @return {Criteria}
|
|
694
|
-
*/
|
|
695
|
-
Criteria.setMethod(function skip(amount) {
|
|
696
|
-
|
|
697
|
-
if (typeof amount != 'number') {
|
|
698
|
-
amount = parseInt(amount);
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
this.options.skip = amount;
|
|
702
|
-
return this;
|
|
703
|
-
});
|
|
704
|
-
|
|
705
|
-
/**
|
|
706
|
-
* Get a specific page
|
|
707
|
-
*
|
|
708
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
709
|
-
* @since 1.1.3
|
|
710
|
-
* @version 1.2.7
|
|
711
|
-
*
|
|
712
|
-
* @param {Number} page A 1-indexed page number
|
|
713
|
-
* @param {Number} page_size
|
|
714
|
-
*
|
|
715
|
-
* @return {Criteria}
|
|
716
|
-
*/
|
|
717
|
-
Criteria.setMethod(function page(page, page_size) {
|
|
718
|
-
|
|
719
|
-
if (typeof page != 'number') {
|
|
720
|
-
page = parseInt(page);
|
|
721
|
-
}
|
|
722
|
-
|
|
723
|
-
if (page_size && typeof page_size != 'number') {
|
|
724
|
-
page_size = parseInt(page_size);
|
|
725
|
-
}
|
|
726
|
-
|
|
727
|
-
if (!page) {
|
|
728
|
-
throw new Error('A page number is required');
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
if (!page_size || !isFinite(page_size)) {
|
|
732
|
-
page_size = 10;
|
|
733
|
-
}
|
|
734
|
-
|
|
735
|
-
let skip = (page - 1) * page_size;
|
|
736
|
-
|
|
737
|
-
this.options.page = page;
|
|
738
|
-
this.options.page_size = page_size;
|
|
739
|
-
|
|
740
|
-
this.skip(skip);
|
|
741
|
-
return this.limit(page_size);
|
|
742
|
-
});
|
|
743
|
-
|
|
744
|
-
/**
|
|
745
|
-
* Select a specific field or association
|
|
746
|
-
*
|
|
747
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
748
|
-
* @since 1.1.0
|
|
749
|
-
* @version 1.2.0
|
|
750
|
-
*
|
|
751
|
-
* @param {String|Array} field
|
|
752
|
-
*
|
|
753
|
-
* @return {Criteria}
|
|
754
|
-
*/
|
|
755
|
-
Criteria.setMethod(function select(field) {
|
|
756
|
-
|
|
757
|
-
var context;
|
|
758
|
-
|
|
759
|
-
if (Object.isIterable(field)) {
|
|
760
|
-
let entry;
|
|
761
|
-
|
|
762
|
-
for (entry of field) {
|
|
763
|
-
context = this.select(entry);
|
|
764
|
-
}
|
|
765
|
-
} else {
|
|
766
|
-
|
|
767
|
-
if (this._select) {
|
|
768
|
-
context = this._select.parse(field);
|
|
769
|
-
} else {
|
|
770
|
-
context = this.options.select.parse(field);
|
|
771
|
-
}
|
|
772
|
-
}
|
|
773
|
-
|
|
774
|
-
// Selects don't always change the context
|
|
775
|
-
if (context) {
|
|
776
|
-
return context;
|
|
777
|
-
}
|
|
778
|
-
|
|
779
|
-
return this;
|
|
780
|
-
});
|
|
781
|
-
|
|
782
|
-
/**
|
|
783
|
-
* Add a specific association
|
|
784
|
-
*
|
|
785
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
786
|
-
* @since 1.1.0
|
|
787
|
-
* @version 1.1.0
|
|
788
|
-
*
|
|
789
|
-
* @param {String} alias
|
|
790
|
-
*
|
|
791
|
-
* @return {Criteria}
|
|
792
|
-
*/
|
|
793
|
-
Criteria.setMethod(['contain', 'populate'], function populate(alias) {
|
|
794
|
-
|
|
795
|
-
if (Array.isArray(alias)) {
|
|
796
|
-
let i;
|
|
797
|
-
|
|
798
|
-
for (i = 0; i < alias.length; i++) {
|
|
799
|
-
this.populate(alias[i]);
|
|
800
|
-
}
|
|
801
|
-
} else {
|
|
802
|
-
let select = this._select || this.options.select;
|
|
803
|
-
|
|
804
|
-
select.addAssociation(alias);
|
|
805
|
-
}
|
|
806
|
-
|
|
807
|
-
return this;
|
|
808
|
-
});
|
|
809
|
-
|
|
810
|
-
/**
|
|
811
|
-
* How deep can we go?
|
|
812
|
-
*
|
|
813
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
814
|
-
* @since 1.1.0
|
|
815
|
-
* @version 1.1.0
|
|
816
|
-
*
|
|
817
|
-
* @param {Number} amount
|
|
818
|
-
*
|
|
819
|
-
* @return {Criteria}
|
|
820
|
-
*/
|
|
821
|
-
Criteria.setMethod(function recursive(amount) {
|
|
822
|
-
this.options.recursive = amount;
|
|
823
|
-
return this;
|
|
824
|
-
});
|
|
825
|
-
|
|
826
|
-
|
|
827
|
-
/**
|
|
828
|
-
* Set the sort
|
|
829
|
-
*
|
|
830
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
831
|
-
* @since 1.1.0
|
|
832
|
-
* @version 1.1.4
|
|
833
|
-
*
|
|
834
|
-
* @param {Array} value
|
|
835
|
-
*
|
|
836
|
-
* @return {Criteria}
|
|
837
|
-
*/
|
|
838
|
-
Criteria.setMethod(function sort(value) {
|
|
839
|
-
|
|
840
|
-
var result;
|
|
841
|
-
|
|
842
|
-
if (value) {
|
|
843
|
-
result = [];
|
|
844
|
-
|
|
845
|
-
// Parse strings
|
|
846
|
-
if (typeof value == 'string') {
|
|
847
|
-
// When it contains a space, we expect something
|
|
848
|
-
// like "_id asc"
|
|
849
|
-
if (value.indexOf(' ') > -1) {
|
|
850
|
-
result.push(value.split(' '));
|
|
851
|
-
} else {
|
|
852
|
-
// Sort ascending by default
|
|
853
|
-
result.push([value, 1]);
|
|
854
|
-
}
|
|
855
|
-
} else if (Array.isArray(value)) {
|
|
856
|
-
if (Array.isArray(value[0])) {
|
|
857
|
-
result = value;
|
|
858
|
-
} else {
|
|
859
|
-
result.push(value);
|
|
860
|
-
}
|
|
861
|
-
} else {
|
|
862
|
-
let keys = Object.keys(value),
|
|
863
|
-
key;
|
|
864
|
-
|
|
865
|
-
if (keys.length == 2 && ~keys.indexOf('dir') && ~keys.indexOf('field')) {
|
|
866
|
-
|
|
867
|
-
if (value.field && value.dir) {
|
|
868
|
-
result.push([value.field, value.dir]);
|
|
869
|
-
}
|
|
870
|
-
|
|
871
|
-
} else {
|
|
872
|
-
for (key in value) {
|
|
873
|
-
result.push([key, value[key]]);
|
|
874
|
-
}
|
|
875
|
-
}
|
|
876
|
-
}
|
|
877
|
-
|
|
878
|
-
let entry,
|
|
879
|
-
i;
|
|
880
|
-
|
|
881
|
-
for (i = 0; i < result.length; i++) {
|
|
882
|
-
entry = result[i];
|
|
883
|
-
|
|
884
|
-
if (typeof entry[1] == 'string') {
|
|
885
|
-
entry[1] = entry[1].toLowerCase();
|
|
886
|
-
|
|
887
|
-
if (entry[1] == 'asc') {
|
|
888
|
-
entry[1] = 1;
|
|
889
|
-
} else if (entry[1] == 'desc') {
|
|
890
|
-
entry[1] = -1;
|
|
891
|
-
} else {
|
|
892
|
-
throw new Error('Unable to parse sort specification "' + entry[1] + '"');
|
|
893
|
-
}
|
|
894
|
-
}
|
|
895
|
-
}
|
|
896
|
-
|
|
897
|
-
// @TODO: implement better handling of ModelName.field sort stuff
|
|
898
|
-
// (Because at this moment, it's just ignored!)
|
|
899
|
-
for (entry of result) {
|
|
900
|
-
if (entry[0].indexOf('.') > -1) {
|
|
901
|
-
let pieces = entry[0].split('.'),
|
|
902
|
-
char = pieces[0][0];
|
|
903
|
-
|
|
904
|
-
if (char == char.toUpperCase()) {
|
|
905
|
-
pieces = pieces.slice(1);
|
|
906
|
-
}
|
|
907
|
-
|
|
908
|
-
entry[0] = pieces.join('.');
|
|
909
|
-
}
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
} else {
|
|
913
|
-
result = null;
|
|
914
|
-
}
|
|
915
|
-
|
|
916
|
-
this.options.sort = result;
|
|
917
|
-
|
|
918
|
-
return this;
|
|
919
|
-
});
|
|
920
|
-
|
|
921
|
-
/**
|
|
922
|
-
* Set a specific option
|
|
923
|
-
*
|
|
924
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
925
|
-
* @since 1.1.0
|
|
926
|
-
* @version 1.1.0
|
|
927
|
-
*
|
|
928
|
-
* @param {String} key
|
|
929
|
-
* @param {String} value
|
|
930
|
-
*
|
|
931
|
-
* @return {Criteria}
|
|
932
|
-
*/
|
|
933
|
-
Criteria.setMethod(function setOption(key, value) {
|
|
934
|
-
this.options[key] = value;
|
|
935
|
-
return this;
|
|
936
|
-
});
|
|
937
|
-
|
|
938
|
-
/**
|
|
939
|
-
* Create a new group
|
|
940
|
-
*
|
|
941
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
942
|
-
* @since 1.1.0
|
|
943
|
-
* @version 1.1.0
|
|
944
|
-
*
|
|
945
|
-
* @param {String} type
|
|
946
|
-
*/
|
|
947
|
-
Criteria.setMethod(function createGroup(type) {
|
|
948
|
-
|
|
949
|
-
var context = this,
|
|
950
|
-
group;
|
|
951
|
-
|
|
952
|
-
if (this.group) {
|
|
953
|
-
let old_group = context.group;
|
|
954
|
-
context = context.augment('group');
|
|
955
|
-
|
|
956
|
-
group = new Group(context, type);
|
|
957
|
-
old_group.addItem(group);
|
|
958
|
-
|
|
959
|
-
context.group = group;
|
|
960
|
-
} else {
|
|
961
|
-
group = new Group(this, type);
|
|
962
|
-
this.group = group;
|
|
963
|
-
}
|
|
964
|
-
|
|
965
|
-
return context;
|
|
966
|
-
});
|
|
967
|
-
|
|
968
|
-
/**
|
|
969
|
-
* Close the current active group
|
|
970
|
-
*
|
|
971
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
972
|
-
* @since 1.1.0
|
|
973
|
-
* @version 1.1.0
|
|
974
|
-
*
|
|
975
|
-
* @return {Criteria}
|
|
976
|
-
*/
|
|
977
|
-
Criteria.setMethod(function closeGroup() {
|
|
978
|
-
|
|
979
|
-
var context = this;
|
|
980
|
-
|
|
981
|
-
if (this.group && this.group.current_group) {
|
|
982
|
-
context = this.group.current_group.criteria;
|
|
983
|
-
}
|
|
984
|
-
|
|
985
|
-
return context;
|
|
986
|
-
});
|
|
987
|
-
|
|
988
|
-
/**
|
|
989
|
-
* Add a new expression
|
|
990
|
-
*
|
|
991
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
992
|
-
* @since 1.1.0
|
|
993
|
-
* @version 1.1.0
|
|
994
|
-
*
|
|
995
|
-
* @param {Expression} expression
|
|
996
|
-
*/
|
|
997
|
-
Criteria.setMethod(function addNewExpression(expression) {
|
|
998
|
-
|
|
999
|
-
// Make sure there is a criteria link
|
|
1000
|
-
if (!expression.criteria) {
|
|
1001
|
-
expression.criteria = this;
|
|
1002
|
-
}
|
|
1003
|
-
|
|
1004
|
-
// Move the expression to the currently active group by default
|
|
1005
|
-
expression.moveToGroup(this.group);
|
|
1006
|
-
|
|
1007
|
-
this.all_expressions.push(expression);
|
|
1008
|
-
});
|
|
1009
|
-
|
|
1010
|
-
/**
|
|
1011
|
-
* Target a field
|
|
1012
|
-
*
|
|
1013
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1014
|
-
* @since 1.1.0
|
|
1015
|
-
* @version 1.1.0
|
|
1016
|
-
*
|
|
1017
|
-
* @param {String} name
|
|
1018
|
-
* @param {*} value
|
|
1019
|
-
*/
|
|
1020
|
-
Criteria.setMethod(function where(name, value) {
|
|
1021
|
-
|
|
1022
|
-
var context = this.augment('field'),
|
|
1023
|
-
expression = new FieldExpression(context, name);
|
|
1024
|
-
|
|
1025
|
-
this.addNewExpression(expression);
|
|
1026
|
-
|
|
1027
|
-
context._active = expression;
|
|
1028
|
-
|
|
1029
|
-
if (arguments.length == 2) {
|
|
1030
|
-
context = context.equals(value);
|
|
1031
|
-
}
|
|
1032
|
-
|
|
1033
|
-
return context;
|
|
1034
|
-
});
|
|
1035
|
-
|
|
1036
|
-
/**
|
|
1037
|
-
* Create an or group
|
|
1038
|
-
*
|
|
1039
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1040
|
-
* @since 1.1.0
|
|
1041
|
-
* @version 1.1.0
|
|
1042
|
-
*
|
|
1043
|
-
* @param {String} type Type of group: or, and, not, ...
|
|
1044
|
-
* @param {String} value
|
|
1045
|
-
*/
|
|
1046
|
-
Criteria.setMethod(function _applyGroup(type, value) {
|
|
1047
|
-
|
|
1048
|
-
var context = this,
|
|
1049
|
-
group,
|
|
1050
|
-
temp;
|
|
1051
|
-
|
|
1052
|
-
if (context._active) {
|
|
1053
|
-
temp = context._active.moveToGroup(type);
|
|
1054
|
-
context = temp;
|
|
1055
|
-
} else {
|
|
1056
|
-
context = context.createGroup(type);
|
|
1057
|
-
}
|
|
1058
|
-
|
|
1059
|
-
if (arguments.length > 1) {
|
|
1060
|
-
let method = context._last_method;
|
|
1061
|
-
|
|
1062
|
-
if (!method) {
|
|
1063
|
-
throw new Error('Unable to call ' + type + '() with a value when no previous method is called');
|
|
1064
|
-
}
|
|
1065
|
-
|
|
1066
|
-
// Create new expression with the same field
|
|
1067
|
-
context = context.where(context._active.target_path);
|
|
1068
|
-
|
|
1069
|
-
// Apply the method on it
|
|
1070
|
-
context[method](value);
|
|
1071
|
-
} else if (context._active) {
|
|
1072
|
-
// Create new expression with the same field
|
|
1073
|
-
context = context.where(context._active.target_path);
|
|
1074
|
-
}
|
|
1075
|
-
|
|
1076
|
-
return context;
|
|
1077
|
-
});
|
|
1078
|
-
|
|
1079
|
-
/**
|
|
1080
|
-
* Create an or group
|
|
1081
|
-
*
|
|
1082
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1083
|
-
* @since 1.1.0
|
|
1084
|
-
* @version 1.1.0
|
|
1085
|
-
*
|
|
1086
|
-
* @param {String} value
|
|
1087
|
-
*/
|
|
1088
|
-
Criteria.setMethod(function or(value) {
|
|
1089
|
-
|
|
1090
|
-
var result;
|
|
1091
|
-
|
|
1092
|
-
if (arguments.length) {
|
|
1093
|
-
return this._applyGroup('or', value);
|
|
1094
|
-
}
|
|
1095
|
-
|
|
1096
|
-
return this._applyGroup('or');
|
|
1097
|
-
});
|
|
1098
|
-
|
|
1099
|
-
/**
|
|
1100
|
-
* Create an and group
|
|
1101
|
-
*
|
|
1102
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1103
|
-
* @since 1.1.0
|
|
1104
|
-
* @version 1.1.0
|
|
1105
|
-
*
|
|
1106
|
-
* @param {String} value
|
|
1107
|
-
*/
|
|
1108
|
-
Criteria.setMethod(function and(value) {
|
|
1109
|
-
|
|
1110
|
-
var result;
|
|
1111
|
-
|
|
1112
|
-
if (arguments.length) {
|
|
1113
|
-
return this._applyGroup('and', value);
|
|
1114
|
-
}
|
|
1115
|
-
|
|
1116
|
-
return this._applyGroup('and');
|
|
1117
|
-
});
|
|
1118
|
-
|
|
1119
|
-
/**
|
|
1120
|
-
* Alias for `ne`: Not equals check
|
|
1121
|
-
*
|
|
1122
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1123
|
-
* @since 1.3.21
|
|
1124
|
-
* @version 1.3.2
|
|
1125
|
-
*
|
|
1126
|
-
* @param {*} value
|
|
1127
|
-
*/
|
|
1128
|
-
Criteria.setMethod(function notEquals(value) {
|
|
1129
|
-
return this.ne(value);
|
|
1130
|
-
});
|
|
1131
|
-
|
|
1132
|
-
Criteria.addValueExpression('equals');
|
|
1133
|
-
Criteria.addValueExpression('gte');
|
|
1134
|
-
Criteria.addValueExpression('gt');
|
|
1135
|
-
Criteria.addValueExpression('lte');
|
|
1136
|
-
Criteria.addValueExpression('lt');
|
|
1137
|
-
Criteria.addValueExpression('in');
|
|
1138
|
-
|
|
1139
|
-
// Add as value expressions of which we don't cast values
|
|
1140
|
-
Criteria.addValueExpression('contains', false);
|
|
1141
|
-
Criteria.addValueExpression('not', false);
|
|
1142
|
-
Criteria.addValueExpression('ne', false);
|
|
1143
|
-
|
|
1144
|
-
Criteria.addFieldExpression('exists');
|
|
1145
|
-
Criteria.addFieldExpression('isNull');
|
|
1146
|
-
Criteria.addFieldExpression('isEmpty');
|
|
1147
|
-
|
|
1148
|
-
/**
|
|
1149
|
-
* Make sure there is an active expression
|
|
1150
|
-
*
|
|
1151
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1152
|
-
* @since 1.1.0
|
|
1153
|
-
* @version 1.1.0
|
|
1154
|
-
*
|
|
1155
|
-
* @param {String} method
|
|
1156
|
-
*/
|
|
1157
|
-
Criteria.setMethod(function _ensureExpression(method) {
|
|
1158
|
-
|
|
1159
|
-
if (!this._active) {
|
|
1160
|
-
throw new Error(method + '() must be called when an expression is active');
|
|
1161
|
-
}
|
|
1162
|
-
|
|
1163
|
-
this._last_method = method;
|
|
1164
|
-
});
|
|
1165
|
-
|
|
1166
|
-
/**
|
|
1167
|
-
* Normalize the criteria by filling in some values on datasources without joins
|
|
1168
|
-
*
|
|
1169
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1170
|
-
* @since 1.1.0
|
|
1171
|
-
* @version 1.1.0
|
|
1172
|
-
*
|
|
1173
|
-
* @return {Pledge}
|
|
1174
|
-
*/
|
|
1175
|
-
Criteria.setMethod(function normalize() {
|
|
1176
|
-
|
|
1177
|
-
if (!this.model) {
|
|
1178
|
-
return Pledge.reject(new Error('Unable to normalize criteria without model instance'));
|
|
1179
|
-
}
|
|
1180
|
-
|
|
1181
|
-
let that = this,
|
|
1182
|
-
tasks = [],
|
|
1183
|
-
i;
|
|
1184
|
-
|
|
1185
|
-
for (i = 0; i < this.all_expressions.length; i++) {
|
|
1186
|
-
let expression = this.all_expressions[i];
|
|
1187
|
-
|
|
1188
|
-
if (!expression) {
|
|
1189
|
-
continue;
|
|
1190
|
-
}
|
|
1191
|
-
|
|
1192
|
-
// Do we need to normalize association values?
|
|
1193
|
-
if (expression.requires_association_normalization) {
|
|
1194
|
-
tasks.push(function doNormalize(next) {
|
|
1195
|
-
expression.normalizeAssociationValues().done(next);
|
|
1196
|
-
});
|
|
1197
|
-
|
|
1198
|
-
continue;
|
|
1199
|
-
}
|
|
1200
|
-
|
|
1201
|
-
let pledge = expression.normalize();
|
|
1202
|
-
|
|
1203
|
-
if (pledge) {
|
|
1204
|
-
tasks.push(pledge);
|
|
1205
|
-
}
|
|
1206
|
-
}
|
|
1207
|
-
|
|
1208
|
-
return Function.parallel(4, tasks);
|
|
1209
|
-
});
|
|
1210
|
-
|
|
1211
|
-
/**
|
|
1212
|
-
* Compile to MongoDB-like query
|
|
1213
|
-
*
|
|
1214
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1215
|
-
* @since 1.1.0
|
|
1216
|
-
* @version 1.1.0
|
|
1217
|
-
*
|
|
1218
|
-
* @return {Object}
|
|
1219
|
-
*/
|
|
1220
|
-
Criteria.setMethod(function compile() {
|
|
1221
|
-
|
|
1222
|
-
if (!this.datasource) {
|
|
1223
|
-
throw new Error('Unable to compile criteria without a datasource target');
|
|
1224
|
-
}
|
|
1225
|
-
|
|
1226
|
-
return this.datasource.compileCriteria(this);
|
|
1227
|
-
});
|
|
1228
|
-
|
|
1229
|
-
/**
|
|
1230
|
-
* Parse an old, mongodb specific options object
|
|
1231
|
-
*
|
|
1232
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1233
|
-
* @since 1.1.0
|
|
1234
|
-
* @version 1.1.0
|
|
1235
|
-
*
|
|
1236
|
-
* @param {Object} options
|
|
1237
|
-
*
|
|
1238
|
-
* @return {Criteria}
|
|
1239
|
-
*/
|
|
1240
|
-
Criteria.setMethod(function applyOldOptions(options) {
|
|
1241
|
-
|
|
1242
|
-
if (!options || Object.isEmpty(options)) {
|
|
1243
|
-
return this;
|
|
1244
|
-
}
|
|
1245
|
-
|
|
1246
|
-
let entry,
|
|
1247
|
-
key;
|
|
1248
|
-
|
|
1249
|
-
for (key in options) {
|
|
1250
|
-
entry = options[key];
|
|
1251
|
-
|
|
1252
|
-
switch (key) {
|
|
1253
|
-
case 'sort' : this.sort(entry); break;
|
|
1254
|
-
case 'limit' : this.limit(entry); break;
|
|
1255
|
-
case 'fields' : this.select(entry); break;
|
|
1256
|
-
case 'select' : this.select(entry); break;
|
|
1257
|
-
case 'recursive' : this.recursive(entry); break;
|
|
1258
|
-
case 'offset' : this.skip(entry); break;
|
|
1259
|
-
case 'populate' : this.populate(entry); break;
|
|
1260
|
-
|
|
1261
|
-
case 'conditions':
|
|
1262
|
-
this.applyOldConditions(entry);
|
|
1263
|
-
break;
|
|
1264
|
-
|
|
1265
|
-
default:
|
|
1266
|
-
this.setOption(key, entry);
|
|
1267
|
-
}
|
|
1268
|
-
}
|
|
1269
|
-
|
|
1270
|
-
return this;
|
|
1271
|
-
});
|
|
1272
|
-
|
|
1273
|
-
/**
|
|
1274
|
-
* Apply old-style mongodb conditions
|
|
1275
|
-
*
|
|
1276
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1277
|
-
* @since 1.1.0
|
|
1278
|
-
* @version 1.1.0
|
|
1279
|
-
*
|
|
1280
|
-
* @param {Object} conditions
|
|
1281
|
-
*
|
|
1282
|
-
* @return {Criteria}
|
|
1283
|
-
*/
|
|
1284
|
-
Criteria.setMethod(function applyOldConditions(conditions) {
|
|
1285
|
-
|
|
1286
|
-
if (!conditions || Object.isEmpty(conditions)) {
|
|
1287
|
-
return this;
|
|
1288
|
-
}
|
|
1289
|
-
|
|
1290
|
-
let context = this,
|
|
1291
|
-
value,
|
|
1292
|
-
group,
|
|
1293
|
-
key,
|
|
1294
|
-
i;
|
|
1295
|
-
|
|
1296
|
-
if (Array.isArray(conditions)) {
|
|
1297
|
-
for (i = 0; i < conditions.length; i++) {
|
|
1298
|
-
context.applyOldConditions(conditions[i]);
|
|
1299
|
-
}
|
|
1300
|
-
|
|
1301
|
-
return context;
|
|
1302
|
-
}
|
|
1303
|
-
|
|
1304
|
-
i = -1;
|
|
1305
|
-
|
|
1306
|
-
for (key in conditions) {
|
|
1307
|
-
value = conditions[key];
|
|
1308
|
-
i++;
|
|
1309
|
-
|
|
1310
|
-
if (key[0] == '$') {
|
|
1311
|
-
|
|
1312
|
-
// Make sure no field is currently active,
|
|
1313
|
-
// else it'll be added to the $and or $or group
|
|
1314
|
-
context._active = null;
|
|
1315
|
-
|
|
1316
|
-
if (key == '$or') {
|
|
1317
|
-
group = context.or();
|
|
1318
|
-
} else if (key == '$and') {
|
|
1319
|
-
|
|
1320
|
-
group = context.and();
|
|
1321
|
-
} else {
|
|
1322
|
-
throw new Error('Unable to parse "' + key + '" group');
|
|
1323
|
-
}
|
|
1324
|
-
|
|
1325
|
-
group.applyOldConditions(value);
|
|
1326
|
-
|
|
1327
|
-
} else {
|
|
1328
|
-
|
|
1329
|
-
if (i) {
|
|
1330
|
-
// If an object contains multiple items,
|
|
1331
|
-
// that's always treated as an $and group
|
|
1332
|
-
context = context.and();
|
|
1333
|
-
}
|
|
1334
|
-
|
|
1335
|
-
context = context.where(key);
|
|
1336
|
-
|
|
1337
|
-
if (Array.isArray(value)) {
|
|
1338
|
-
context = context.in(value);
|
|
1339
|
-
continue;
|
|
1340
|
-
} else if (value && typeof value == 'object') {
|
|
1341
|
-
let had_dollar,
|
|
1342
|
-
method,
|
|
1343
|
-
key;
|
|
1344
|
-
|
|
1345
|
-
for (key in value) {
|
|
1346
|
-
if (key[0] == '$') {
|
|
1347
|
-
had_dollar = true;
|
|
1348
|
-
method = key.slice(1);
|
|
1349
|
-
|
|
1350
|
-
if (typeof context[method] != 'function') {
|
|
1351
|
-
if (method == 'regex') {
|
|
1352
|
-
let regex;
|
|
1353
|
-
|
|
1354
|
-
if (typeof value[key] == 'string') {
|
|
1355
|
-
regex = RegExp.interpret(RegExp.escape(value[key]), value.$options);
|
|
1356
|
-
} else {
|
|
1357
|
-
regex = RegExp.interpret(value[key], value.$options);
|
|
1358
|
-
}
|
|
1359
|
-
|
|
1360
|
-
context.contains(regex);
|
|
1361
|
-
break;
|
|
1362
|
-
} else {
|
|
1363
|
-
throw new Error('Unable to parse "' + key + '" expression');
|
|
1364
|
-
}
|
|
1365
|
-
} else {
|
|
1366
|
-
context[method](value[key]);
|
|
1367
|
-
}
|
|
1368
|
-
}
|
|
1369
|
-
}
|
|
1370
|
-
|
|
1371
|
-
if (had_dollar) {
|
|
1372
|
-
continue;
|
|
1373
|
-
}
|
|
1374
|
-
}
|
|
1375
|
-
|
|
1376
|
-
context.equals(value);
|
|
1377
|
-
}
|
|
1378
|
-
}
|
|
1379
|
-
});
|
|
1380
|
-
|
|
1381
|
-
/**
|
|
1382
|
-
* The Criteria Select class
|
|
1383
|
-
*
|
|
1384
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1385
|
-
* @since 1.1.0
|
|
1386
|
-
* @version 1.1.0
|
|
1387
|
-
*/
|
|
1388
|
-
var Select = Function.inherits('Alchemy.Base', 'Alchemy.Criteria', function Select(criteria) {
|
|
1389
|
-
// The parent criteria instance
|
|
1390
|
-
this.criteria = criteria;
|
|
1391
|
-
});
|
|
1392
|
-
|
|
1393
|
-
/**
|
|
1394
|
-
* Revive the given object
|
|
1395
|
-
*
|
|
1396
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1397
|
-
* @since 1.1.0
|
|
1398
|
-
* @version 1.2.3
|
|
1399
|
-
*
|
|
1400
|
-
* @return {Select}
|
|
1401
|
-
*/
|
|
1402
|
-
Select.setStatic(function revive(data, criteria) {
|
|
1403
|
-
|
|
1404
|
-
if (!data) {
|
|
1405
|
-
return;
|
|
1406
|
-
}
|
|
1407
|
-
|
|
1408
|
-
let result = new Select(criteria),
|
|
1409
|
-
key;
|
|
1410
|
-
|
|
1411
|
-
result.fields = data.fields;
|
|
1412
|
-
|
|
1413
|
-
if (data.associations) {
|
|
1414
|
-
result.associations = {};
|
|
1415
|
-
|
|
1416
|
-
for (key in data.associations) {
|
|
1417
|
-
result.associations[key] = Select.revive(data.associations[key], criteria);
|
|
1418
|
-
}
|
|
1419
|
-
}
|
|
1420
|
-
|
|
1421
|
-
if (data.association_name) {
|
|
1422
|
-
result.association_name = data.association_name;
|
|
1423
|
-
}
|
|
1424
|
-
|
|
1425
|
-
return result;
|
|
1426
|
-
});
|
|
1427
|
-
|
|
1428
|
-
/**
|
|
1429
|
-
* Return object to jsonify
|
|
1430
|
-
*
|
|
1431
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1432
|
-
* @since 1.1.0
|
|
1433
|
-
* @version 1.1.0
|
|
1434
|
-
*
|
|
1435
|
-
* @return {Object}
|
|
1436
|
-
*/
|
|
1437
|
-
Select.setMethod(function toJSON() {
|
|
1438
|
-
return {
|
|
1439
|
-
association_name : this.association_name,
|
|
1440
|
-
associations : this.associations,
|
|
1441
|
-
fields : this.fields
|
|
1442
|
-
};
|
|
1443
|
-
});
|
|
1444
|
-
|
|
1445
|
-
/**
|
|
1446
|
-
* Return the elements to checksum in place of this object
|
|
1447
|
-
*
|
|
1448
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1449
|
-
* @since 1.1.0
|
|
1450
|
-
* @version 1.1.0
|
|
1451
|
-
*/
|
|
1452
|
-
Select.setMethod(Blast.checksumSymbol, function toChecksum() {
|
|
1453
|
-
|
|
1454
|
-
var result = [];
|
|
1455
|
-
|
|
1456
|
-
if (this.associations) {
|
|
1457
|
-
result.push(this.associations);
|
|
1458
|
-
}
|
|
1459
|
-
|
|
1460
|
-
if (this.fields) {
|
|
1461
|
-
result.push(this.fields);
|
|
1462
|
-
}
|
|
1463
|
-
|
|
1464
|
-
if (this.association_name) {
|
|
1465
|
-
result.push(this.association_name);
|
|
1466
|
-
}
|
|
1467
|
-
|
|
1468
|
-
if (!result.length) {
|
|
1469
|
-
return null;
|
|
1470
|
-
}
|
|
1471
|
-
|
|
1472
|
-
return result;
|
|
1473
|
-
});
|
|
1474
|
-
|
|
1475
|
-
/**
|
|
1476
|
-
* Add an association
|
|
1477
|
-
*
|
|
1478
|
-
* @author Jelle De Loecker <jelle@elevenways.be>
|
|
1479
|
-
* @since 1.1.0
|
|
1480
|
-
* @version 1.3.4
|
|
1481
|
-
*
|
|
1482
|
-
* @param {String} name
|
|
1483
|
-
*
|
|
1484
|
-
* @return {Select} This creates a new Select instance
|
|
1485
|
-
*/
|
|
1486
|
-
Select.setMethod(function addAssociation(name) {
|
|
1487
|
-
|
|
1488
|
-
if (!this.criteria?.model) {
|
|
1489
|
-
throw new Error('Unable to select an association: this Criteria has no model info');
|
|
1490
|
-
}
|
|
1491
|
-
|
|
1492
|
-
var pieces;
|
|
1493
|
-
|
|
1494
|
-
if (!this.associations) {
|
|
1495
|
-
this.associations = {};
|
|
1496
|
-
}
|
|
1497
|
-
|
|
1498
|
-
if (Array.isArray(name)) {
|
|
1499
|
-
pieces = name;
|
|
1500
|
-
} else if (name.indexOf('.') > -1) {
|
|
1501
|
-
pieces = name.split('.');
|
|
1502
|
-
}
|
|
1503
|
-
|
|
1504
|
-
if (pieces && pieces.length) {
|
|
1505
|
-
let context = this;
|
|
1506
|
-
|
|
1507
|
-
while (pieces.length) {
|
|
1508
|
-
name = pieces.shift();
|
|
1509
|
-
context = context.addAssociation(name);
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
return context;
|
|
1513
|
-
}
|
|
1514
|
-
|
|
1515
|
-
if (!this.associations[name]) {
|
|
1516
|
-
this.associations[name] = new Select(this.criteria);
|
|
1517
|
-
this.associations[name].association_name = name;
|
|
1518
|
-
}
|
|
1519
|
-
|
|
1520
|
-
// Get the association data
|
|
1521
|
-
try {
|
|
1522
|
-
let info = this.criteria.model.getAssociation(name);
|
|
1523
|
-
|
|
1524
|
-
if (info) {
|
|
1525
|
-
// Make sure the localkey is added to the resultset
|
|
1526
|
-
this.requireFieldForQuery(info.options.localKey);
|
|
1527
|
-
}
|
|
1528
|
-
} catch (err) {
|
|
1529
|
-
console.warn('Failed to find "' + name + '" association for ' + this.criteria.model.model_name);
|
|
1530
|
-
}
|
|
1531
|
-
|
|
1532
|
-
return this.associations[name];
|
|
1533
|
-
});
|
|
1534
|
-
|
|
1535
|
-
/**
|
|
1536
|
-
* Require a field for query purposes
|
|
1537
|
-
*
|
|
1538
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1539
|
-
* @since 1.2.0
|
|
1540
|
-
* @version 1.2.0
|
|
1541
|
-
*
|
|
1542
|
-
* @param {String} path
|
|
1543
|
-
*/
|
|
1544
|
-
Select.setMethod(function requireFieldForQuery(path) {
|
|
1545
|
-
|
|
1546
|
-
if (!this.query_fields) {
|
|
1547
|
-
this.query_fields = [];
|
|
1548
|
-
}
|
|
1549
|
-
|
|
1550
|
-
this.query_fields.push(path);
|
|
1551
|
-
});
|
|
1552
|
-
|
|
1553
|
-
/**
|
|
1554
|
-
* Add a field
|
|
1555
|
-
*
|
|
1556
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1557
|
-
* @since 1.1.0
|
|
1558
|
-
* @version 1.1.0
|
|
1559
|
-
*
|
|
1560
|
-
* @param {String} path
|
|
1561
|
-
*/
|
|
1562
|
-
Select.setMethod(function addField(path) {
|
|
1563
|
-
|
|
1564
|
-
if (!this.fields) {
|
|
1565
|
-
this.fields = [];
|
|
1566
|
-
}
|
|
1567
|
-
|
|
1568
|
-
this.fields.push(path);
|
|
1569
|
-
});
|
|
1570
|
-
|
|
1571
|
-
/**
|
|
1572
|
-
* Parse a path meant to add as a selection
|
|
1573
|
-
*
|
|
1574
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1575
|
-
* @since 1.1.0
|
|
1576
|
-
* @version 1.2.0
|
|
1577
|
-
*
|
|
1578
|
-
* @param {String|Object} path
|
|
1579
|
-
*
|
|
1580
|
-
* @return {Criteria|Null} A criteria object if the context has changed
|
|
1581
|
-
*/
|
|
1582
|
-
Select.setMethod(function parse(path) {
|
|
1583
|
-
|
|
1584
|
-
let context,
|
|
1585
|
-
select = this,
|
|
1586
|
-
parsed;
|
|
1587
|
-
|
|
1588
|
-
if (typeof path == 'object' && path && path.name) {
|
|
1589
|
-
|
|
1590
|
-
if (path.path) {
|
|
1591
|
-
path = path.path;
|
|
1592
|
-
} else {
|
|
1593
|
-
let obj = path;
|
|
1594
|
-
path = obj.name;
|
|
1595
|
-
|
|
1596
|
-
if (obj.association) {
|
|
1597
|
-
path = obj.association + '.' + path;
|
|
1598
|
-
}
|
|
1599
|
-
}
|
|
1600
|
-
}
|
|
1601
|
-
|
|
1602
|
-
parsed = Criteria.parsePath(path, this.criteria);
|
|
1603
|
-
|
|
1604
|
-
// Associations were found,
|
|
1605
|
-
// like "Comment._id" or "Comment.User"
|
|
1606
|
-
if (parsed.association) {
|
|
1607
|
-
let name,
|
|
1608
|
-
i;
|
|
1609
|
-
|
|
1610
|
-
for (i = 0; i < parsed.association.length; i++) {
|
|
1611
|
-
name = parsed.association[i];
|
|
1612
|
-
|
|
1613
|
-
if (this.model && this.model.name == name) {
|
|
1614
|
-
continue;
|
|
1615
|
-
}
|
|
1616
|
-
|
|
1617
|
-
select = select.addAssociation(name);
|
|
1618
|
-
}
|
|
1619
|
-
}
|
|
1620
|
-
|
|
1621
|
-
if (parsed.target_path) {
|
|
1622
|
-
select.addField(parsed.target_path);
|
|
1623
|
-
} else if (parsed.association) {
|
|
1624
|
-
// When only an association was given, then the context changes
|
|
1625
|
-
context = this.criteria.augment('select');
|
|
1626
|
-
context._select = select;
|
|
1627
|
-
return context;
|
|
1628
|
-
}
|
|
1629
|
-
});
|
|
1630
|
-
|
|
1631
|
-
/**
|
|
1632
|
-
* Clone this select for the given criteria
|
|
1633
|
-
*
|
|
1634
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1635
|
-
* @since 1.1.0
|
|
1636
|
-
* @version 1.2.0
|
|
1637
|
-
*
|
|
1638
|
-
* @param {Criteria} criteria
|
|
1639
|
-
*
|
|
1640
|
-
* @return {Select}
|
|
1641
|
-
*/
|
|
1642
|
-
Select.setMethod(function cloneForCriteria(criteria) {
|
|
1643
|
-
|
|
1644
|
-
var clone = new Select(criteria);
|
|
1645
|
-
|
|
1646
|
-
if (this.association_name) {
|
|
1647
|
-
clone.association_name = this.association_name;
|
|
1648
|
-
}
|
|
1649
|
-
|
|
1650
|
-
if (this.fields && this.fields.length) {
|
|
1651
|
-
clone.fields = this.fields.slice(0);
|
|
1652
|
-
}
|
|
1653
|
-
|
|
1654
|
-
if (this.query_fields && this.query_fields.length) {
|
|
1655
|
-
clone.query_fields = this.query_fields.slice(0);
|
|
1656
|
-
}
|
|
1657
|
-
|
|
1658
|
-
if (this.associations) {
|
|
1659
|
-
let key;
|
|
1660
|
-
|
|
1661
|
-
clone.associations = {};
|
|
1662
|
-
|
|
1663
|
-
for (key in this.associations) {
|
|
1664
|
-
clone.associations[key] = this.associations[key].cloneForCriteria(criteria);
|
|
1665
|
-
}
|
|
1666
|
-
}
|
|
1667
|
-
|
|
1668
|
-
return clone;
|
|
1669
|
-
});
|
|
1670
|
-
|
|
1671
|
-
/**
|
|
1672
|
-
* Should the given association be queried according to this select?
|
|
1673
|
-
* (The Criteria instance can also have a recursive level set)
|
|
1674
|
-
*
|
|
1675
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1676
|
-
* @since 1.1.0
|
|
1677
|
-
* @version 1.1.0
|
|
1678
|
-
*
|
|
1679
|
-
* @param {String} name
|
|
1680
|
-
*
|
|
1681
|
-
* @return {Boolean}
|
|
1682
|
-
*/
|
|
1683
|
-
Select.setMethod(function shouldQueryAssociation(name) {
|
|
1684
|
-
|
|
1685
|
-
if (this.associations) {
|
|
1686
|
-
return !!this.associations[name];
|
|
1687
|
-
}
|
|
1688
|
-
|
|
1689
|
-
return false;
|
|
1690
|
-
});
|
|
1691
|
-
|
|
1692
|
-
/**
|
|
1693
|
-
* The Base Criteria Expression class
|
|
1694
|
-
*
|
|
1695
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1696
|
-
* @since 1.1.0
|
|
1697
|
-
* @version 1.1.0
|
|
1698
|
-
*/
|
|
1699
|
-
var Expression = Function.inherits('Alchemy.Base', 'Alchemy.Criteria.Expression', function Expression(criteria) {
|
|
1700
|
-
|
|
1701
|
-
// The parent criteria instance
|
|
1702
|
-
this.criteria = criteria;
|
|
1703
|
-
|
|
1704
|
-
// The current group it's in
|
|
1705
|
-
this.current_group = null;
|
|
1706
|
-
|
|
1707
|
-
// The items this contains
|
|
1708
|
-
this.items = [];
|
|
1709
|
-
});
|
|
1710
|
-
|
|
1711
|
-
/**
|
|
1712
|
-
* Revive an object
|
|
1713
|
-
*
|
|
1714
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1715
|
-
* @since 1.1.0
|
|
1716
|
-
* @version 1.1.0
|
|
1717
|
-
*
|
|
1718
|
-
* @return {Expression}
|
|
1719
|
-
*/
|
|
1720
|
-
Expression.setStatic(function revive(data, criteria) {
|
|
1721
|
-
|
|
1722
|
-
if (data._type == 'group') {
|
|
1723
|
-
return Group.revive(data, criteria);
|
|
1724
|
-
} else if (data._type == 'field') {
|
|
1725
|
-
return FieldExpression.revive(data, criteria);
|
|
1726
|
-
} else {
|
|
1727
|
-
throw new Error('Unable to revive "' + data._type + '" expression');
|
|
1728
|
-
}
|
|
1729
|
-
|
|
1730
|
-
});
|
|
1731
|
-
|
|
1732
|
-
/**
|
|
1733
|
-
* Does this expression do something with an association,
|
|
1734
|
-
* and do we need to normalize this on the current given datasource?
|
|
1735
|
-
*
|
|
1736
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1737
|
-
* @since 1.1.0
|
|
1738
|
-
* @version 1.1.0
|
|
1739
|
-
*
|
|
1740
|
-
* @type {Boolean}
|
|
1741
|
-
*/
|
|
1742
|
-
Expression.setProperty(function requires_association_normalization() {
|
|
1743
|
-
|
|
1744
|
-
if (!this.association) {
|
|
1745
|
-
return false;
|
|
1746
|
-
}
|
|
1747
|
-
|
|
1748
|
-
if (!this.datasource.supports('querying_associations')) {
|
|
1749
|
-
return true;
|
|
1750
|
-
}
|
|
1751
|
-
|
|
1752
|
-
return false;
|
|
1753
|
-
});
|
|
1754
|
-
|
|
1755
|
-
/**
|
|
1756
|
-
* Create a reference to the datasource
|
|
1757
|
-
*
|
|
1758
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1759
|
-
* @since 1.1.0
|
|
1760
|
-
* @version 1.1.0
|
|
1761
|
-
*
|
|
1762
|
-
* @type {Datasource}
|
|
1763
|
-
*/
|
|
1764
|
-
Expression.setProperty(function datasource() {
|
|
1765
|
-
if (this.criteria) {
|
|
1766
|
-
return this.criteria.datasource;
|
|
1767
|
-
}
|
|
1768
|
-
});
|
|
1769
|
-
|
|
1770
|
-
/**
|
|
1771
|
-
* Create a reference to the model
|
|
1772
|
-
*
|
|
1773
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1774
|
-
* @since 1.1.0
|
|
1775
|
-
* @version 1.1.0
|
|
1776
|
-
*
|
|
1777
|
-
* @type {Model}
|
|
1778
|
-
*/
|
|
1779
|
-
Expression.setProperty(function model() {
|
|
1780
|
-
if (this.criteria) {
|
|
1781
|
-
return this.criteria.model;
|
|
1782
|
-
}
|
|
1783
|
-
});
|
|
1784
|
-
|
|
1785
|
-
/**
|
|
1786
|
-
* Create a reference to the field instance
|
|
1787
|
-
*
|
|
1788
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1789
|
-
* @since 1.1.0
|
|
1790
|
-
* @version 1.1.0
|
|
1791
|
-
*
|
|
1792
|
-
* @type {FieldType}
|
|
1793
|
-
*/
|
|
1794
|
-
Expression.setProperty(function field() {
|
|
1795
|
-
if (this.criteria && this.criteria.model) {
|
|
1796
|
-
return this.criteria.model.schema.getField(this.target_path);
|
|
1797
|
-
}
|
|
1798
|
-
});
|
|
1799
|
-
|
|
1800
|
-
/**
|
|
1801
|
-
* Return the elements to checksum in place of this object
|
|
1802
|
-
*
|
|
1803
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1804
|
-
* @since 1.1.0
|
|
1805
|
-
* @version 1.1.0
|
|
1806
|
-
*/
|
|
1807
|
-
Expression.setMethod(Blast.checksumSymbol, function toChecksum() {
|
|
1808
|
-
return this.items;
|
|
1809
|
-
});
|
|
1810
|
-
|
|
1811
|
-
/**
|
|
1812
|
-
* Get a clone without any Criteria or Group links
|
|
1813
|
-
*
|
|
1814
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1815
|
-
* @since 1.1.0
|
|
1816
|
-
* @version 1.1.0
|
|
1817
|
-
*
|
|
1818
|
-
* @return {Expression}
|
|
1819
|
-
*/
|
|
1820
|
-
Expression.setMethod(function getCleanClone() {
|
|
1821
|
-
|
|
1822
|
-
var result = new this.constructor();
|
|
1823
|
-
|
|
1824
|
-
// Add the cloned array
|
|
1825
|
-
result.items = JSON.clone(this.items);
|
|
1826
|
-
|
|
1827
|
-
if (this.association) {
|
|
1828
|
-
result.association = this.association;
|
|
1829
|
-
}
|
|
1830
|
-
|
|
1831
|
-
if (this.target_path) {
|
|
1832
|
-
result.target_path = this.target_path;
|
|
1833
|
-
}
|
|
1834
|
-
|
|
1835
|
-
if (this.group_type) {
|
|
1836
|
-
result.group_type = this.group_type;
|
|
1837
|
-
}
|
|
1838
|
-
|
|
1839
|
-
if (this.db_property) {
|
|
1840
|
-
result.db_property = this.db_property;
|
|
1841
|
-
}
|
|
1842
|
-
|
|
1843
|
-
return result;
|
|
1844
|
-
});
|
|
1845
|
-
|
|
1846
|
-
/**
|
|
1847
|
-
* Move the expression to the given group (object)
|
|
1848
|
-
* or the given group type (and/or)
|
|
1849
|
-
*
|
|
1850
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1851
|
-
* @since 1.1.0
|
|
1852
|
-
* @version 1.1.0
|
|
1853
|
-
*
|
|
1854
|
-
* @param {Object|String} group
|
|
1855
|
-
*/
|
|
1856
|
-
Expression.setMethod(function moveToGroup(group) {
|
|
1857
|
-
|
|
1858
|
-
var context = this.criteria;
|
|
1859
|
-
|
|
1860
|
-
// Move to a specific type?
|
|
1861
|
-
if (typeof group == 'string') {
|
|
1862
|
-
|
|
1863
|
-
// Is it already part of the same type of group?
|
|
1864
|
-
// Then we can ignore this call
|
|
1865
|
-
if (this.current_group && this.current_group.group_type == group) {
|
|
1866
|
-
return context;
|
|
1867
|
-
}
|
|
1868
|
-
|
|
1869
|
-
// Create a new group of the given type
|
|
1870
|
-
context = context.createGroup(group);
|
|
1871
|
-
group = context.group;
|
|
1872
|
-
}
|
|
1873
|
-
|
|
1874
|
-
if (this.current_group) {
|
|
1875
|
-
this.current_group.removeItem(this);
|
|
1876
|
-
}
|
|
1877
|
-
|
|
1878
|
-
this.current_group = group;
|
|
1879
|
-
group.addItem(this);
|
|
1880
|
-
|
|
1881
|
-
return context;
|
|
1882
|
-
});
|
|
1883
|
-
|
|
1884
|
-
/**
|
|
1885
|
-
* Remove this expression from the criteria
|
|
1886
|
-
*
|
|
1887
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1888
|
-
* @since 1.1.0
|
|
1889
|
-
* @version 1.1.0
|
|
1890
|
-
*/
|
|
1891
|
-
Expression.setMethod(function remove() {
|
|
1892
|
-
|
|
1893
|
-
if (arguments.length) {
|
|
1894
|
-
throw new Error('Expression#remove() can only remove itself');
|
|
1895
|
-
}
|
|
1896
|
-
|
|
1897
|
-
let index = this.criteria.all_expressions.indexOf(this);
|
|
1898
|
-
|
|
1899
|
-
if (index > -1) {
|
|
1900
|
-
this.criteria.all_expressions.splice(index, 1);
|
|
1901
|
-
}
|
|
1902
|
-
|
|
1903
|
-
if (this.current_group) {
|
|
1904
|
-
this.current_group.removeItem(this);
|
|
1905
|
-
}
|
|
1906
|
-
});
|
|
1907
|
-
|
|
1908
|
-
/**
|
|
1909
|
-
* Add an item
|
|
1910
|
-
*
|
|
1911
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1912
|
-
* @since 1.1.0
|
|
1913
|
-
* @version 1.1.0
|
|
1914
|
-
*
|
|
1915
|
-
* @param {Object} item
|
|
1916
|
-
*/
|
|
1917
|
-
Expression.setMethod(function addItem(item) {
|
|
1918
|
-
this.items.push(item);
|
|
1919
|
-
return item;
|
|
1920
|
-
});
|
|
1921
|
-
|
|
1922
|
-
/**
|
|
1923
|
-
* Remove an item from this expression
|
|
1924
|
-
*
|
|
1925
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1926
|
-
* @since 1.1.0
|
|
1927
|
-
* @version 1.1.0
|
|
1928
|
-
*
|
|
1929
|
-
* @param {Object} item
|
|
1930
|
-
*/
|
|
1931
|
-
Expression.setMethod(function removeItem(item) {
|
|
1932
|
-
|
|
1933
|
-
var index = this.items.indexOf(item);
|
|
1934
|
-
|
|
1935
|
-
// If this expression was found in the current group, remove it
|
|
1936
|
-
if (index > -1) {
|
|
1937
|
-
this.items.splice(index, 1);
|
|
1938
|
-
return true;
|
|
1939
|
-
}
|
|
1940
|
-
|
|
1941
|
-
return false;
|
|
1942
|
-
});
|
|
1943
|
-
|
|
1944
|
-
/**
|
|
1945
|
-
* The Field Expression class
|
|
1946
|
-
*
|
|
1947
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1948
|
-
* @since 1.1.0
|
|
1949
|
-
* @version 1.1.0
|
|
1950
|
-
*/
|
|
1951
|
-
var FieldExpression = Function.inherits('Alchemy.Criteria.Expression', function Field(criteria, field) {
|
|
1952
|
-
|
|
1953
|
-
Field.super.call(this, criteria);
|
|
1954
|
-
|
|
1955
|
-
if (arguments.length) {
|
|
1956
|
-
// Set the target
|
|
1957
|
-
this.setTargetPath(field);
|
|
1958
|
-
}
|
|
1959
|
-
});
|
|
1960
|
-
|
|
1961
|
-
/**
|
|
1962
|
-
* Revive an object
|
|
1963
|
-
*
|
|
1964
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
1965
|
-
* @since 1.1.0
|
|
1966
|
-
* @version 1.1.0
|
|
1967
|
-
*
|
|
1968
|
-
* @return {FieldExpression}
|
|
1969
|
-
*/
|
|
1970
|
-
FieldExpression.setStatic(function revive(data, criteria) {
|
|
1971
|
-
|
|
1972
|
-
var result = new FieldExpression();
|
|
1973
|
-
|
|
1974
|
-
result.criteria = criteria;
|
|
1975
|
-
|
|
1976
|
-
criteria.all_expressions.push(result);
|
|
1977
|
-
|
|
1978
|
-
if (data.association) {
|
|
1979
|
-
result.association = data.association;
|
|
1980
|
-
}
|
|
1981
|
-
|
|
1982
|
-
if (data.target_path) {
|
|
1983
|
-
result.target_path = data.target_path;
|
|
1984
|
-
}
|
|
1985
|
-
|
|
1986
|
-
if (data.items) {
|
|
1987
|
-
result.items = data.items;
|
|
1988
|
-
}
|
|
1989
|
-
|
|
1990
|
-
if (data.db_property) {
|
|
1991
|
-
result.db_property = data.db_property;
|
|
1992
|
-
}
|
|
1993
|
-
|
|
1994
|
-
return result;
|
|
1995
|
-
});
|
|
1996
|
-
|
|
1997
|
-
/**
|
|
1998
|
-
* Return object to jsonify
|
|
1999
|
-
*
|
|
2000
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
2001
|
-
* @since 1.1.0
|
|
2002
|
-
* @version 1.1.0
|
|
2003
|
-
*
|
|
2004
|
-
* @return {Object}
|
|
2005
|
-
*/
|
|
2006
|
-
FieldExpression.setMethod(function toJSON() {
|
|
2007
|
-
return {
|
|
2008
|
-
_type : 'field',
|
|
2009
|
-
association : this.association,
|
|
2010
|
-
target_path : this.target_path,
|
|
2011
|
-
items : this.items,
|
|
2012
|
-
db_property : this.db_property
|
|
2013
|
-
};
|
|
2014
|
-
});
|
|
2015
|
-
|
|
2016
|
-
/**
|
|
2017
|
-
* Return the elements to checksum in place of this object
|
|
2018
|
-
*
|
|
2019
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
2020
|
-
* @since 1.1.0
|
|
2021
|
-
* @version 1.1.0
|
|
2022
|
-
*/
|
|
2023
|
-
FieldExpression.setMethod(Blast.checksumSymbol, function toChecksum() {
|
|
2024
|
-
return [this.target_path, this.items];
|
|
2025
|
-
});
|
|
2026
|
-
|
|
2027
|
-
/**
|
|
2028
|
-
* Set the target
|
|
2029
|
-
*
|
|
2030
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
2031
|
-
* @since 1.1.0
|
|
2032
|
-
* @version 1.1.0
|
|
2033
|
-
*
|
|
2034
|
-
* @param {String} path
|
|
2035
|
-
*/
|
|
2036
|
-
FieldExpression.setMethod(function setTargetPath(path) {
|
|
2037
|
-
|
|
2038
|
-
var pieces;
|
|
2039
|
-
|
|
2040
|
-
if (typeof path == 'string') {
|
|
2041
|
-
if (path.indexOf('.') > -1) {
|
|
2042
|
-
pieces = path.split('.');
|
|
2043
|
-
}
|
|
2044
|
-
} else if (Array.isArray(path)) {
|
|
2045
|
-
pieces = path;
|
|
2046
|
-
} else {
|
|
2047
|
-
throw new Error('Field#setTargetPath(path) requires a string or an array');
|
|
2048
|
-
}
|
|
2049
|
-
|
|
2050
|
-
if (!pieces) {
|
|
2051
|
-
this.target_path = path;
|
|
2052
|
-
} else {
|
|
2053
|
-
let first = pieces[0];
|
|
2054
|
-
|
|
2055
|
-
// @TODO: better check if the first part is an association
|
|
2056
|
-
if (first[0].isUpperCase()) {
|
|
2057
|
-
this.association = first;
|
|
2058
|
-
pieces.shift();
|
|
2059
|
-
}
|
|
2060
|
-
|
|
2061
|
-
this.target_path = pieces.join('.');
|
|
2062
|
-
}
|
|
2063
|
-
|
|
2064
|
-
});
|
|
2065
|
-
|
|
2066
|
-
/**
|
|
2067
|
-
* Add a new condition item
|
|
2068
|
-
*
|
|
2069
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
2070
|
-
* @since 1.1.0
|
|
2071
|
-
* @version 1.1.5
|
|
2072
|
-
*
|
|
2073
|
-
* @param {Object|String} group
|
|
2074
|
-
*
|
|
2075
|
-
* @return {Object}
|
|
2076
|
-
*/
|
|
2077
|
-
FieldExpression.setMethod(function addItem(type, value) {
|
|
2078
|
-
|
|
2079
|
-
var entry = {
|
|
2080
|
-
type : type
|
|
2081
|
-
};
|
|
2082
|
-
|
|
2083
|
-
if (arguments.length > 1) {
|
|
2084
|
-
|
|
2085
|
-
if (typeof value == 'object' && value && value instanceof Classes.Alchemy.Base) {
|
|
2086
|
-
throw new Classes.Alchemy.Error.Model('"' + value.constructor.getClassPath() + '" instance was given as a "' + this.target_path + '" condition');
|
|
2087
|
-
}
|
|
2088
|
-
|
|
2089
|
-
entry.value = value;
|
|
2090
|
-
}
|
|
2091
|
-
|
|
2092
|
-
this.items.push(entry);
|
|
2093
|
-
|
|
2094
|
-
return entry;
|
|
2095
|
-
});
|
|
2096
|
-
|
|
2097
|
-
/**
|
|
2098
|
-
* Normalize the values (like casting strings to objectids)
|
|
2099
|
-
*
|
|
2100
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
2101
|
-
* @since 1.1.0
|
|
2102
|
-
* @version 1.1.0
|
|
2103
|
-
*
|
|
2104
|
-
* @return {Pledge|Null}
|
|
2105
|
-
*/
|
|
2106
|
-
FieldExpression.setMethod(function normalize() {
|
|
2107
|
-
|
|
2108
|
-
var field = this.field;
|
|
2109
|
-
|
|
2110
|
-
if (!field) {
|
|
2111
|
-
return;
|
|
2112
|
-
}
|
|
2113
|
-
|
|
2114
|
-
let item,
|
|
2115
|
-
i;
|
|
2116
|
-
|
|
2117
|
-
for (i = 0; i < this.items.length; i++) {
|
|
2118
|
-
item = this.items[i];
|
|
2119
|
-
|
|
2120
|
-
// Skip field_expression items
|
|
2121
|
-
// (like $exists: true and such)
|
|
2122
|
-
// or items where `cast` is explicitly false
|
|
2123
|
-
if (item.field_expression || item.cast === false) {
|
|
2124
|
-
continue;
|
|
2125
|
-
}
|
|
2126
|
-
|
|
2127
|
-
if (item.value != null) {
|
|
2128
|
-
if (Array.isArray(item.value)) {
|
|
2129
|
-
let result = [],
|
|
2130
|
-
i;
|
|
2131
|
-
|
|
2132
|
-
for (i = 0; i < item.value.length; i++) {
|
|
2133
|
-
result[i] = field.castCondition(item.value[i], this);
|
|
2134
|
-
}
|
|
2135
|
-
|
|
2136
|
-
item.value = result;
|
|
2137
|
-
} else {
|
|
2138
|
-
item.value = field.castCondition(item.value, this);
|
|
2139
|
-
}
|
|
2140
|
-
}
|
|
2141
|
-
}
|
|
2142
|
-
});
|
|
2143
|
-
|
|
2144
|
-
/**
|
|
2145
|
-
* Normalize association values by separately querying them
|
|
2146
|
-
* and adding the found values to the criteria
|
|
2147
|
-
*
|
|
2148
|
-
* @WARNING: this can be extremely resource intensive when using
|
|
2149
|
-
* on big collections.
|
|
2150
|
-
*
|
|
2151
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
2152
|
-
* @since 1.1.0
|
|
2153
|
-
* @version 1.1.0
|
|
2154
|
-
*
|
|
2155
|
-
* @return {Pledge}
|
|
2156
|
-
*/
|
|
2157
|
-
FieldExpression.setMethod(function normalizeAssociationValues() {
|
|
2158
|
-
|
|
2159
|
-
if (!this.association) {
|
|
2160
|
-
return Pledge.reject(new Error('Unable to normalize a field without an association'));
|
|
2161
|
-
}
|
|
2162
|
-
|
|
2163
|
-
let that = this,
|
|
2164
|
-
association = this.model.getAssociation(this.association),
|
|
2165
|
-
assoc_model = this.model.getModel(association.modelName),
|
|
2166
|
-
assoc_crit = new Classes.Alchemy.Criteria(),
|
|
2167
|
-
pledge = new Pledge(),
|
|
2168
|
-
clone = this.getCleanClone(),
|
|
2169
|
-
item,
|
|
2170
|
-
i;
|
|
2171
|
-
|
|
2172
|
-
// Unset the association
|
|
2173
|
-
clone.association = null;
|
|
2174
|
-
|
|
2175
|
-
// Add the clone
|
|
2176
|
-
assoc_crit.addNewExpression(clone);
|
|
2177
|
-
|
|
2178
|
-
// Only select the wanted field
|
|
2179
|
-
assoc_crit.select(association.options.foreignKey);
|
|
2180
|
-
|
|
2181
|
-
assoc_model.find('all', {criteria: assoc_crit, document: false}, function gotAssocItems(err, items) {
|
|
2182
|
-
|
|
2183
|
-
if (err) {
|
|
2184
|
-
return pledge.reject(err);
|
|
2185
|
-
}
|
|
2186
|
-
|
|
2187
|
-
let values = [],
|
|
2188
|
-
record,
|
|
2189
|
-
i;
|
|
2190
|
-
|
|
2191
|
-
for (i = 0; i < items.length; i++) {
|
|
2192
|
-
values.push(items[i][association.options.foreignKey]);
|
|
2193
|
-
}
|
|
2194
|
-
|
|
2195
|
-
if (!values.length) {
|
|
2196
|
-
// @TODO: make this more elegant
|
|
2197
|
-
values.push('_impossible_');
|
|
2198
|
-
}
|
|
2199
|
-
|
|
2200
|
-
// Remove the expression from the criteria
|
|
2201
|
-
that.remove();
|
|
2202
|
-
|
|
2203
|
-
// And add this new one
|
|
2204
|
-
that.criteria.where(association.options.localKey).in(values);
|
|
2205
|
-
|
|
2206
|
-
pledge.resolve();
|
|
2207
|
-
});
|
|
2208
|
-
|
|
2209
|
-
return pledge;
|
|
2210
|
-
});
|
|
2211
|
-
|
|
2212
|
-
/**
|
|
2213
|
-
* The Group Expression class
|
|
2214
|
-
*
|
|
2215
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
2216
|
-
* @since 1.1.0
|
|
2217
|
-
* @version 1.1.0
|
|
2218
|
-
*/
|
|
2219
|
-
var Group = Function.inherits('Alchemy.Criteria.Expression', function Group(criteria, type) {
|
|
2220
|
-
|
|
2221
|
-
Group.super.call(this, criteria);
|
|
2222
|
-
|
|
2223
|
-
// The group type
|
|
2224
|
-
this.group_type = type;
|
|
2225
|
-
});
|
|
2226
|
-
|
|
2227
|
-
/**
|
|
2228
|
-
* Revive an object
|
|
2229
|
-
*
|
|
2230
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
2231
|
-
* @since 1.1.0
|
|
2232
|
-
* @version 1.1.0
|
|
2233
|
-
*
|
|
2234
|
-
* @return {Group}
|
|
2235
|
-
*/
|
|
2236
|
-
Group.setStatic(function revive(data, criteria) {
|
|
2237
|
-
|
|
2238
|
-
var result = new Group(criteria),
|
|
2239
|
-
i;
|
|
2240
|
-
|
|
2241
|
-
result.group_type = data.group_type;
|
|
2242
|
-
|
|
2243
|
-
if (data.items) {
|
|
2244
|
-
result.items = [];
|
|
2245
|
-
|
|
2246
|
-
for (i = 0; i < data.items.length; i++) {
|
|
2247
|
-
result.items.push(Expression.revive(data.items[i], criteria));
|
|
2248
|
-
}
|
|
2249
|
-
}
|
|
2250
|
-
|
|
2251
|
-
return result;
|
|
2252
|
-
});
|
|
2253
|
-
|
|
2254
|
-
/**
|
|
2255
|
-
* Return object to jsonify
|
|
2256
|
-
*
|
|
2257
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
2258
|
-
* @since 1.1.0
|
|
2259
|
-
* @version 1.1.0
|
|
2260
|
-
*
|
|
2261
|
-
* @return {Object}
|
|
2262
|
-
*/
|
|
2263
|
-
Group.setMethod(function toJSON() {
|
|
2264
|
-
return {
|
|
2265
|
-
_type : 'group',
|
|
2266
|
-
association : this.association,
|
|
2267
|
-
group_type : this.group_type,
|
|
2268
|
-
items : this.items.slice(0)
|
|
2269
|
-
};
|
|
2270
|
-
});
|
|
2271
|
-
|
|
2272
|
-
/**
|
|
2273
|
-
* Return the elements to checksum in place of this object
|
|
2274
|
-
*
|
|
2275
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
2276
|
-
* @since 1.1.0
|
|
2277
|
-
* @version 1.1.0
|
|
2278
|
-
*/
|
|
2279
|
-
Group.setMethod(Blast.checksumSymbol, function toChecksum() {
|
|
2280
|
-
return [this.group_type, this.items];
|
|
2281
|
-
});
|
|
2282
|
-
|
|
2283
|
-
// PROTOBLAST START CUT
|
|
2284
|
-
/**
|
|
2285
|
-
* Make the Criteria class a global
|
|
2286
|
-
*
|
|
2287
|
-
* @author Jelle De Loecker <jelle@develry.be>
|
|
2288
|
-
* @since 1.1.0
|
|
2289
|
-
* @version 1.1.0
|
|
2290
|
-
*
|
|
2291
|
-
* @type {Function}
|
|
2292
|
-
*/
|
|
2293
|
-
global.Criteria = Criteria;
|
|
2294
|
-
// PROTOBLAST END CUT
|