alchemymvc 1.1.10 → 1.2.2

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.
@@ -8,151 +8,98 @@
8
8
  * @since 0.0.1
9
9
  * @version 1.0.0
10
10
  */
11
- var Paginate = Function.inherits('Alchemy.Client.Component', function Paginate(controller, options) {
12
- Paginate.super.call(this, controller, options);
13
- });
11
+ const Paginate = Function.inherits('Alchemy.Client.Component', 'Paginate');
14
12
 
15
13
  /**
16
14
  * Perform a query
17
15
  *
18
- * @author Jelle De Loecker <jelle@develry.be>
16
+ * @author Jelle De Loecker <jelle@elevenways.be>
19
17
  * @since 0.0.1
20
- * @version 1.0.6
18
+ * @version 1.2.2
21
19
  *
22
20
  * @param {Model} model
23
- * @param {Object} options
24
- * @param {Function} callback
21
+ * @param {Criteria} criteria
25
22
  *
26
23
  * @return {Pledge}
27
24
  */
28
- Paginate.setMethod(function find(model, options, callback) {
29
-
30
- var that = this,
31
- conduit = this.controller.conduit,
32
- conditions,
33
- last_id,
34
- filter,
35
- pledge,
36
- order,
37
- name,
38
- sort;
25
+ Paginate.setMethod(function find(model, criteria) {
26
+
27
+ const conduit = this.controller.conduit;
39
28
 
40
29
  // Get the model if a name has been given
41
30
  if (typeof model == 'string') {
42
31
  model = this.getModel(model);
43
32
  }
44
33
 
45
- // Make sure callback is set correctly
46
- if (typeof options == 'function') {
47
- callback = options;
48
- }
49
-
50
- // Make sure options is an object
51
- if (!options || typeof options != 'object') {
52
- options = {};
53
- }
54
-
55
- // Set the name for this pagination
56
- if (!options.name) {
57
- options.name = model.name;
58
- } else {
59
- options.name = options.name.modelName();
60
- }
34
+ let page_size = criteria.options.page_size || 10,
35
+ skipless = criteria.options.skipless,
36
+ last_id,
37
+ name = criteria.options.name,
38
+ page = criteria.options.page;
61
39
 
62
- if (!options.pageSize) {
63
- options.pageSize = 10;
40
+ if (!name) {
41
+ name = model.name;
42
+ criteria.setOption('name', name);
64
43
  }
65
44
 
66
- if (options.skipless) {
67
- last_id = options.last_id || conduit.param('page');
45
+ if (skipless) {
46
+ let sort;
47
+ last_id = criteria.options.last_id || conduit.param('page');
68
48
 
69
49
  // When it's a skipless pagination,
70
50
  // a sort is always implied
71
- if (options.skipless === true) {
51
+ if (skipless === true) {
72
52
  sort = {_id: 1};
73
53
  } else {
74
54
  sort = {};
75
- sort[options.skipless] = 1;
55
+ sort[skipless] = 1;
76
56
  }
77
57
 
78
- options.sort = sort;
79
-
58
+ criteria.sort(sort);
80
59
  } else {
81
60
 
82
61
  // If no page has been given
83
- if (typeof options.page != 'number') {
84
- options.page = conduit.param('page');
62
+ if (typeof page != 'number') {
63
+ page = conduit.param('page');
85
64
  }
86
65
 
87
- if (options.page < 0 || !options.page) {
88
- options.page = 1;
66
+ if (page < 0 || !page) {
67
+ page = 1;
89
68
  }
90
69
 
91
- options.offset = (options.page-1) * options.pageSize;
92
-
93
- sort = conduit.param('sort');
70
+ let sort = conduit.param('sort');
94
71
 
95
72
  if (sort) {
96
73
  // Always override the sort
97
- options.sort = {};
74
+ let new_sort = {};
98
75
 
99
76
  order = conduit.param('order');
100
77
 
101
78
  if (typeof order == 'string' && order.toLowerCase() == 'desc') {
102
- options.sort[sort] = -1;
79
+ new_sort[sort] = -1;
103
80
  } else {
104
- options.sort[sort] = 1;
81
+ new_sort[sort] = 1;
105
82
  }
106
- }
107
- }
108
-
109
- options.limit = options.pageSize;
110
83
 
111
- if (conduit.param('filter_field') && conduit.param('filter_value')) {
112
- conditions = {};
113
- conditions[conduit.param('filter_field')] = RegExp.interpret('/.*' + conduit.param('filter_value') + '.*/i');
114
- options.conditions = conditions;
115
- }
116
-
117
- filter = conduit.param('filter');
118
-
119
- if (filter) {
120
- if (!conditions) {
121
- conditions = {};
84
+ criteria.sort(new_sort);
122
85
  }
123
86
 
124
- options.conditions = conditions;
125
-
126
- for (name in filter) {
127
- if (filter[name] !== '') {
128
- conditions[name] = RegExp.interpret('/.*' + filter[name] + '.*/i');
129
- }
87
+ if (page) {
88
+ criteria.page(page, page_size);
130
89
  }
131
90
  }
132
91
 
133
92
  if (last_id) {
134
- if (!options.conditions) {
135
- options.conditions = {};
136
- }
137
-
138
- if (!options.conditions.$and) {
139
- options.conditions.$and = [];
140
- }
141
-
142
- let entry = {};
143
-
144
- if (options.skipless === true) {
145
- entry._id = {$gt: alchemy.castObjectId(last_id)};
93
+ if (skipless === true) {
94
+ criteria.where('_id').gt(last_id);
146
95
  } else {
147
- entry[options.skipless] = {$gt: last_id};
96
+ criteria.where(skipless).gt(last_id);
148
97
  }
149
-
150
- options.conditions.$and.push(entry);
151
98
  }
152
99
 
153
- options.available = true;
100
+ criteria.setOption('available', true);
154
101
 
155
- pledge = model.find('all', options, function findAllPaginate(err, result) {
102
+ let pledge = model.find('all', criteria, function findAllPaginate(err, result) {
156
103
 
157
104
  if (err) {
158
105
  return;
@@ -166,21 +113,19 @@ Paginate.setMethod(function find(model, options, callback) {
166
113
  }
167
114
 
168
115
  let entry = {
169
- page : options.page,
170
- size : options.pageSize,
116
+ page : page,
117
+ size : page_size,
171
118
  items : result.available,
172
- pages : Math.ceil(result.available/options.pageSize),
173
- skipless : options.skipless
119
+ pages : Math.ceil(result.available/page_size),
120
+ skipless : skipless
174
121
  };
175
122
 
176
- if (options.skipless && result.length) {
123
+ if (skipless && result.length) {
177
124
  entry.last_id = result.last()._id;
178
125
  }
179
126
 
180
- PageInfo[options.name] = entry;
127
+ PageInfo[name] = entry;
181
128
  });
182
129
 
183
- pledge.handleCallback(callback);
184
-
185
130
  return pledge;
186
131
  });
@@ -34,7 +34,7 @@ var Conduit = Function.inherits('Alchemy.Client.Base', 'Alchemy.Client.Conduit',
34
34
  *
35
35
  * @author Jelle De Loecker <jelle@develry.be>
36
36
  * @since 1.1.0
37
- * @version 1.1.0
37
+ * @version 1.2.2
38
38
  *
39
39
  * @param {RURL} url
40
40
  * @param {Object} options
@@ -121,17 +121,19 @@ Conduit.setStatic(function handleUrlLocal(url, options) {
121
121
  conduit = new Conduit(url, options);
122
122
  }
123
123
 
124
- for (let key in options) {
125
- let info = Blast.Classes.Develry.Request.getMethodInfo(key);
124
+ if (conduit) {
125
+ for (let key in options) {
126
+ let info = Blast.Classes.Develry.Request.getMethodInfo(key);
126
127
 
127
- if (info && info.method != 'GET') {
128
- conduit.method = info.method.toLowerCase();
129
- break;
128
+ if (info && info.method != 'GET') {
129
+ conduit.method = info.method.toLowerCase();
130
+ break;
131
+ }
130
132
  }
131
- }
132
133
 
133
- if (!conduit.method) {
134
- conduit.method = 'get';
134
+ if (!conduit.method) {
135
+ conduit.method = 'get';
136
+ }
135
137
  }
136
138
 
137
139
  Function.series(tasks, function done(err) {
@@ -590,7 +590,7 @@ NoSQL.setStatic(function areComparable(a, b) {
590
590
  *
591
591
  * @author Jelle De Loecker <jelle@develry.be>
592
592
  * @since 1.1.0
593
- * @version 1.1.2
593
+ * @version 1.2.2
594
594
  *
595
595
  * @param {Criteria} criteria
596
596
  * @param {Group} group
@@ -611,6 +611,15 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
611
611
  group = criteria.group;
612
612
  }
613
613
 
614
+ let getAggregate = () => {
615
+ if (!aggregate) {
616
+ aggregate = {
617
+ pipeline: [],
618
+ lookups: {}
619
+ };
620
+ }
621
+ }
622
+
614
623
  for (i = 0; i < group.items.length; i++) {
615
624
  entry = group.items[i];
616
625
 
@@ -620,12 +629,7 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
620
629
  }
621
630
 
622
631
  if (entry.association) {
623
- if (!aggregate) {
624
- aggregate = {
625
- pipeline: [],
626
- lookups: {}
627
- };
628
- }
632
+ getAggregate();
629
633
 
630
634
  // Get the association info
631
635
  assoc = criteria.model.getAssociation(entry.association);
@@ -705,9 +709,45 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
705
709
  not,
706
710
  obj = {};
707
711
 
712
+ let field_entry = {},
713
+ name = entry.target_path;
714
+
715
+ // Do we need to look into an object itself?
716
+ // (Like the "timestamp" property of a date field when stored with units)
717
+ if (entry.db_property) {
718
+ name += '.' + entry.db_property;
719
+ }
720
+
721
+ if (entry.association) {
722
+ name = entry.association + '.' + name;
723
+ }
724
+
708
725
  for (let i = 0; i < entry.items.length; i++) {
709
726
  item = entry.items[i];
710
727
 
728
+ // If the value is a RegExp, we might have to stringify the value
729
+ if (shouldStringify(entry, item) && RegExp.isRegExp(item.value)) {
730
+
731
+ let stringified_field = name + '_stringified';
732
+
733
+ getAggregate();
734
+
735
+ aggregate.pipeline.push({
736
+ $addFields: {
737
+ [stringified_field]: {
738
+ $convert: {
739
+ input: '$' + name,
740
+ to: 'string',
741
+ onError: '',
742
+ onNull: ''
743
+ }
744
+ }
745
+ }
746
+ });
747
+
748
+ name = stringified_field;
749
+ }
750
+
711
751
  if (item.type == 'ne') {
712
752
  obj.$ne = item.value;
713
753
  } else if (item.type == 'not') {
@@ -758,6 +798,10 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
758
798
  {$exists: exists}
759
799
  ];
760
800
 
801
+ if (!entry.field) {
802
+ throw new Error('Could not find field for path "' + entry.target_path + '" in model ' + entry.model.name);
803
+ }
804
+
761
805
  if (entry.field.is_array) {
762
806
  $or.push({[comparator]: []});
763
807
  } else if (entry.field instanceof Classes.Alchemy.Field.String) {
@@ -771,19 +815,6 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
771
815
  throw new Error('Unknown criteria expression: "' + item.type + '"');
772
816
  }
773
817
 
774
- let field_entry = {},
775
- name = entry.target_path;
776
-
777
- // Do we need to look into an object itself?
778
- // (Like the "timestamp" property of a date field when stored with units)
779
- if (entry.db_property) {
780
- name += '.' + entry.db_property;
781
- }
782
-
783
- if (entry.association) {
784
- name = entry.association + '.' + name;
785
- }
786
-
787
818
  if (obj && obj.$or) {
788
819
 
789
820
  let $or = [],
@@ -870,6 +901,33 @@ NoSQL.setMethod(function compileCriteria(criteria, group) {
870
901
  return {$and: result};
871
902
  });
872
903
 
904
+ /**
905
+ * Is the given item about a string field?
906
+ *
907
+ * @author Jelle De Loecker <jelle@elevenways.be>
908
+ * @since 1.2.0
909
+ * @version 1.2.0
910
+ *
911
+ * @param {Object} entry
912
+ * @param {Object} item
913
+ *
914
+ * @return {boolean}
915
+ */
916
+ function shouldStringify(entry, item) {
917
+
918
+ if (!item || !item.value) {
919
+ return false;
920
+ }
921
+
922
+ try {
923
+ let field = entry.model.getField(entry.target_path);
924
+
925
+ // The field value should only be stringified if it isn't a string already
926
+ return !(field instanceof Classes.Alchemy.Field.String);
927
+ } catch (err) {}
928
+
929
+ return false;
930
+ }
873
931
 
874
932
  /**
875
933
  * Get the MongoDB options from this criteria
@@ -7,9 +7,7 @@
7
7
  * @since 0.2.0
8
8
  * @version 1.1.0
9
9
  */
10
- var StringField = Function.inherits('Alchemy.Field', function String(schema, name, options) {
11
- String.super.call(this, schema, name, options);
12
- });
10
+ var StringField = Function.inherits('Alchemy.Field', 'String');
13
11
 
14
12
  /**
15
13
  * Set the datatype name
@@ -7,23 +7,4 @@
7
7
  * @since 0.2.0
8
8
  * @version 1.1.0
9
9
  */
10
- var BelongsTo = Function.inherits('Alchemy.Field.ObjectId', function BelongsTo(schema, name, options) {
11
- BelongsTo.super.call(this, schema, name, options);
12
-
13
- // @todo: set index stuff
14
- });
15
-
16
- /**
17
- * Load remote data for some fields
18
- *
19
- * @author Jelle De Loecker <jelle@elevenways.be>
20
- * @since 0.2.0
21
- * @version 0.2.0
22
- *
23
- * @param {Object} config
24
- */
25
- BelongsTo.setMethod(async function loadData(config) {
26
-
27
-
28
-
29
- });
10
+ const BelongsTo = Function.inherits('Alchemy.Field.ObjectId', 'BelongsTo');
@@ -5,9 +5,14 @@
5
5
  *
6
6
  * @author Jelle De Loecker <jelle@develry.be>
7
7
  * @since 0.2.0
8
- * @version 1.1.0
8
+ * @version 1.2.1
9
9
  */
10
10
  var Enum = Function.inherits('Alchemy.Field', function Enum(schema, name, options) {
11
+
12
+ if (options.values) {
13
+ options.values = new Classes.Alchemy.Map.Enum(options.values);
14
+ }
15
+
11
16
  Enum.super.call(this, schema, name, options);
12
17
  });
13
18
 
@@ -40,9 +45,9 @@ Enum.setMethod(function cast(value) {
40
45
  *
41
46
  * @author Jelle De Loecker <jelle@develry.be>
42
47
  * @since 0.2.0
43
- * @version 0.2.0
48
+ * @version 1.2.1
44
49
  *
45
- * @return {Object}
50
+ * @return {EnumValues}
46
51
  */
47
52
  Enum.setMethod(function getValues() {
48
53
 
@@ -62,7 +67,7 @@ Enum.setMethod(function getValues() {
62
67
  *
63
68
  * @author Jelle De Loecker <jelle@develry.be>
64
69
  * @since 1.1.0
65
- * @version 1.1.0
70
+ * @version 1.2.1
66
71
  *
67
72
  * @param {WeakMap} wm
68
73
  *
@@ -72,37 +77,5 @@ Enum.setMethod(function getClientConfigOptions(wm) {
72
77
 
73
78
  let options = JSON.clone(this.options, 'toHawkejs', wm);
74
79
 
75
- if (this.options.values) {
76
- let value,
77
- entry,
78
- key;
79
-
80
- if (!options.values) {
81
- options.values = {};
82
- }
83
-
84
- for (key in this.options.values) {
85
-
86
- if (options.values[key]) {
87
- continue;
88
- }
89
-
90
- value = this.options.values[key];
91
-
92
- if (typeof value == 'function') {
93
- entry = {
94
- name : value.name,
95
- title : value.title,
96
- };
97
-
98
- if (value.schema) {
99
- entry.schema = JSON.clone(value.schema, 'toHawkejs', wm);
100
- }
101
-
102
- options.values[key] = entry;
103
- }
104
- }
105
- }
106
-
107
80
  return options;
108
81
  });
@@ -91,7 +91,7 @@ SchemaField.setProperty(function requires_translating() {
91
91
  *
92
92
  * @author Jelle De Loecker <jelle@develry.be>
93
93
  * @since 0.2.0
94
- * @version 0.4.0
94
+ * @version 1.2.1
95
95
  *
96
96
  * @param {Object} record
97
97
  * @param {String} some_path Some path to a field in the wanted schema
@@ -106,8 +106,7 @@ SchemaField.setMethod(function getSubschema(record, some_path) {
106
106
  record_value,
107
107
  pieces,
108
108
  field,
109
- name,
110
- temp;
109
+ name;
111
110
 
112
111
  // If schema is a string,
113
112
  // it needs to be extracted from another field's value
@@ -131,9 +130,9 @@ SchemaField.setMethod(function getSubschema(record, some_path) {
131
130
  }
132
131
 
133
132
  // Get the values that field can have (probably an enum)
134
- temp = field.getValues();
133
+ let values = field.getValues();
135
134
 
136
- if (temp == null) {
135
+ if (values == null) {
137
136
  return null;
138
137
  }
139
138
 
@@ -146,23 +145,14 @@ SchemaField.setMethod(function getSubschema(record, some_path) {
146
145
  }
147
146
 
148
147
  // Get the correct field value
149
- temp = temp[record_value];
150
-
151
- if (temp != null) {
152
- schema = temp[property_name];
148
+ let enum_value = values.get(record_value);
153
149
 
154
- if (schema == null && typeof temp == 'function') {
155
- temp = new temp();
156
- schema = temp[property_name] || temp.schema || temp.blueprint;
157
-
158
- if (schema != null) {
159
- schema.setModel(this.schema.model_name);
160
- schema.setName(this.name);
161
- schema.setParent(this.schema);
162
- }
163
- }
164
- } else {
150
+ if (!enum_value) {
165
151
  schema = null;
152
+ } else if (enum_value.schema) {
153
+ schema = enum_value.schema;
154
+ } else if (enum_value.value) {
155
+ schema = enum_value.value[property_name] || enum_value.value.schema;
166
156
  }
167
157
  }
168
158
 
@@ -243,7 +233,7 @@ SchemaField.setMethod(function _toDatasource(value, data, datasource, callback)
243
233
  }
244
234
  }
245
235
 
246
- log.warning('Model and subschema were not found for', that.name);
236
+ log.warning('Model and subschema were not found for', that.path);
247
237
  return datasource.toDatasource(null, value, callback);
248
238
  });
249
239