1 | ;
|
2 |
|
3 | const { setProp } = require('./util');
|
4 | const ValidationError = require('./error/validation');
|
5 |
|
6 | /**
|
7 | * This is the basic schema type.
|
8 | * All schema types should inherit from this class.
|
9 | * For example:
|
10 | *
|
11 | * ``` js
|
12 | * class SchemaTypeCustom extends SchemaType {};
|
13 | * ```
|
14 | *
|
15 | * **Query operators**
|
16 | *
|
17 | * To add a query operator, defines a method whose name is started with `q$`.
|
18 | * For example:
|
19 | *
|
20 | * ``` js
|
21 | * SchemaTypeCustom.q$foo = function(value, query, data){
|
22 | * // ...
|
23 | * };
|
24 | * ```
|
25 | *
|
26 | * The `value` parameter is the value of specified field; the `query` parameter
|
27 | * is the value passed to the query operator; the `data` parameter is the
|
28 | * complete data.
|
29 | *
|
30 | * The return value must be a boolean indicating whether the data passed.
|
31 | *
|
32 | * **Update operators**
|
33 | *
|
34 | * To add a update operator, defines a method whose name is started with `u$`.
|
35 | * For example:
|
36 | *
|
37 | * ``` js
|
38 | * SchemaTypeCustom.u$foo = function(value, update, data){
|
39 | * // ...
|
40 | * };
|
41 | * ```
|
42 | *
|
43 | * The `value` parameter is the value of specified field; the `update` parameter
|
44 | * is the value passed to the update operator; the `data` parameter is the
|
45 | * complete data.
|
46 | *
|
47 | * The return value will replace the original data.
|
48 | */
|
49 | class SchemaType {
|
50 |
|
51 | /**
|
52 | * SchemaType constructor.
|
53 | *
|
54 | * @param {String} name
|
55 | * @param {Object} [options]
|
56 | * @param {Boolean} [options.required=false]
|
57 | * @param {*} [options.default]
|
58 | */
|
59 | constructor(name, options) {
|
60 | this.name = name || '';
|
61 |
|
62 | this.options = Object.assign({
|
63 | required: false
|
64 | }, options);
|
65 |
|
66 | const default_ = this.options.default;
|
67 |
|
68 | if (typeof default_ === 'function') {
|
69 | this.default = default_;
|
70 | } else {
|
71 | this.default = () => default_;
|
72 | }
|
73 | }
|
74 |
|
75 | /**
|
76 | * Casts data. This function is used by getters to cast an object to document
|
77 | * instances. If the value is null, the default value will be returned.
|
78 | *
|
79 | * @param {*} value
|
80 | * @param {Object} data
|
81 | * @return {*}
|
82 | */
|
83 | cast(value, data) {
|
84 | if (value == null) {
|
85 | return this.default();
|
86 | }
|
87 |
|
88 | return value;
|
89 | }
|
90 |
|
91 | /**
|
92 | * Validates data. This function is used by setters.
|
93 | *
|
94 | * @param {*} value
|
95 | * @param {Object} data
|
96 | * @return {*|Error}
|
97 | */
|
98 | validate(value, data) {
|
99 | if (this.options.required && value == null) {
|
100 | throw new ValidationError(`\`${this.name}\` is required!`);
|
101 | }
|
102 |
|
103 | return value;
|
104 | }
|
105 |
|
106 | /**
|
107 | * Compares data. This function is used when sorting.
|
108 | *
|
109 | * @param {*} a
|
110 | * @param {*} b
|
111 | * @return {Number}
|
112 | */
|
113 | compare(a, b) {
|
114 | if (a > b) {
|
115 | return 1;
|
116 | } else if (a < b) {
|
117 | return -1;
|
118 | }
|
119 |
|
120 | return 0;
|
121 | }
|
122 |
|
123 | /**
|
124 | * Parses data. This function is used when restoring data from database files.
|
125 | *
|
126 | * @param {*} value
|
127 | * @param {Object} data
|
128 | * @return {*}
|
129 | */
|
130 | parse(value, data) {
|
131 | return value;
|
132 | }
|
133 |
|
134 | /**
|
135 | * Transforms value. This function is used when saving data to database files.
|
136 | *
|
137 | * @param {*} value
|
138 | * @param {Object} data
|
139 | * @return {*}
|
140 | */
|
141 | value(value, data) {
|
142 | return value;
|
143 | }
|
144 |
|
145 | /**
|
146 | * Checks the equality of data.
|
147 | *
|
148 | * @param {*} value
|
149 | * @param {*} query
|
150 | * @param {Object} data
|
151 | * @return {Boolean}
|
152 | */
|
153 | match(value, query, data) {
|
154 | return value === query;
|
155 | }
|
156 |
|
157 | /**
|
158 | * Checks the existance of data.
|
159 | *
|
160 | * @param {*} value
|
161 | * @param {*} query
|
162 | * @param {Object} data
|
163 | * @return {Boolean}
|
164 | */
|
165 | q$exist(value, query, data) {
|
166 | return (value != null) === query;
|
167 | }
|
168 |
|
169 | /**
|
170 | * Checks the equality of data. Returns true if the value doesn't match.
|
171 | *
|
172 | * @param {*} value
|
173 | * @param {*} query
|
174 | * @param {Object} data
|
175 | * @return {boolean}
|
176 | */
|
177 | q$ne(value, query, data) {
|
178 | return !this.match(value, query, data);
|
179 | }
|
180 |
|
181 | /**
|
182 | * Checks whether `value` is less than (i.e. <) the `query`.
|
183 | *
|
184 | * @param {*} value
|
185 | * @param {*} query
|
186 | * @param {Object} data
|
187 | * @return {Boolean}
|
188 | */
|
189 | q$lt(value, query, data) {
|
190 | return value < query;
|
191 | }
|
192 |
|
193 | /**
|
194 | * Checks whether `value` is less than or equal to (i.e. <=) the `query`.
|
195 | *
|
196 | * @param {*} value
|
197 | * @param {*} query
|
198 | * @param {Object} data
|
199 | * @return {Boolean}
|
200 | */
|
201 | q$lte(value, query, data) {
|
202 | return value <= query;
|
203 | }
|
204 |
|
205 | /**
|
206 | * Checks whether `value` is greater than (i.e. >) the `query`.
|
207 | *
|
208 | * @param {*} value
|
209 | * @param {*} query
|
210 | * @param {Object} data
|
211 | * @return {Boolean}
|
212 | */
|
213 | q$gt(value, query, data) {
|
214 | return value > query;
|
215 | }
|
216 |
|
217 | /**
|
218 | * Checks whether `value` is greater than or equal to (i.e. >=) the `query`.
|
219 | *
|
220 | * @param {*} value
|
221 | * @param {*} query
|
222 | * @param {Object} data
|
223 | * @return {Boolean}
|
224 | */
|
225 | q$gte(value, query, data) {
|
226 | return value >= query;
|
227 | }
|
228 |
|
229 | /**
|
230 | * Checks whether `value` is equal to one of elements in `query`.
|
231 | *
|
232 | * @param {*} value
|
233 | * @param {Array} query
|
234 | * @param {Object} data
|
235 | * @return {Boolean}
|
236 | */
|
237 | q$in(value, query, data) {
|
238 | return query.includes(value);
|
239 | }
|
240 |
|
241 | /**
|
242 | * Checks whether `value` is not equal to any elements in `query`.
|
243 | *
|
244 | * @param {*} value
|
245 | * @param {Array} query
|
246 | * @param {Object} data
|
247 | * @return {Boolean}
|
248 | */
|
249 | q$nin(value, query, data) {
|
250 | return !query.includes(value);
|
251 | }
|
252 |
|
253 | /**
|
254 | * Sets the value.
|
255 | *
|
256 | * @param {*} value
|
257 | * @param {*} update
|
258 | * @param {Object} data
|
259 | * @return {*}
|
260 | */
|
261 | u$set(value, update, data) {
|
262 | return update;
|
263 | }
|
264 |
|
265 | /**
|
266 | * Unsets the value.
|
267 | *
|
268 | * @param {*} value
|
269 | * @param {*} update
|
270 | * @param {Object} data
|
271 | * @return {*}
|
272 | */
|
273 | u$unset(value, update, data) { return update ? undefined : value; }
|
274 |
|
275 | /**
|
276 | * Renames a field.
|
277 | *
|
278 | * @param {*} value
|
279 | * @param {*} update
|
280 | * @param {Object} data
|
281 | * @return {*}
|
282 | */
|
283 | u$rename(value, update, data) {
|
284 | if (value !== undefined) setProp(data, update, value);
|
285 | return undefined;
|
286 | }
|
287 | }
|
288 |
|
289 | SchemaType.prototype.q$exists = SchemaType.prototype.q$exist;
|
290 |
|
291 | SchemaType.prototype.q$max = SchemaType.prototype.q$lte;
|
292 |
|
293 | SchemaType.prototype.q$min = SchemaType.prototype.q$gte;
|
294 |
|
295 | module.exports = SchemaType;
|