1 | | // Generated by CoffeeScript 1.4.0 |
2 | 1 | (function() { |
3 | 1 | var ObjectId, async, mongojs, mongoose, _, |
4 | | __slice = [].slice; |
5 | | |
6 | 1 | async = require('async'); |
7 | | |
8 | 1 | _ = require('underscore'); |
9 | | |
10 | 1 | mongoose = require('mongoose'); |
11 | | |
12 | 1 | mongojs = require('mongojs'); |
13 | | |
14 | 1 | ObjectId = mongoose.Schema.ObjectId; |
15 | | |
16 | 1 | exports.create = function() { |
17 | 17 | var api, db, defModel, desugarModel, getKeys, getManyToMany, getMetaFields, getOwnedModels, getOwners, internalListSub, massage, massageCore, massageOne, massaged, meta, model, models, nullablesValidation, preRemoveCascadeNonNullable, preRemoveCascadeNullable, preprocFilter, propagate, specTransform, specmodels; |
18 | 17 | db = null; |
19 | 17 | api = {}; |
20 | 17 | models = {}; |
21 | 17 | specmodels = {}; |
22 | 17 | meta = {}; |
23 | 17 | propagate = function(callback, f) { |
24 | 4 | return function() { |
25 | 4 | var args, err; |
26 | 4 | err = arguments[0], args = 2 <= arguments.length ? __slice.call(arguments, 1) : []; |
27 | 4 | if (err) { |
28 | 0 | return callback(err); |
29 | | } else { |
30 | 4 | return f.apply(this, args); |
31 | | } |
32 | | }; |
33 | | }; |
34 | 17 | model = function(name, schema) { |
35 | 25 | var ss; |
36 | 25 | ss = new mongoose.Schema(schema, { |
37 | | strict: true |
38 | | }); |
39 | 25 | ss.set('versionKey', false); |
40 | 25 | return mongoose.model(name, ss); |
41 | | }; |
42 | 17 | api.isValidId = function(id) { |
43 | 2 | try { |
44 | 2 | mongoose.mongo.ObjectID(id); |
45 | 1 | return true; |
46 | | } catch (ex) { |
47 | 1 | return false; |
48 | | } |
49 | | }; |
50 | 17 | preprocFilter = function(filter) { |
51 | 15 | var x; |
52 | 15 | x = _.extend({}, filter); |
53 | 15 | if (x.id) { |
54 | 8 | x._id = x.id; |
55 | | } |
56 | 15 | delete x.id; |
57 | 15 | return x; |
58 | | }; |
59 | 17 | massageOne = function(x) { |
60 | 28 | if (!(x != null)) { |
61 | 0 | return x; |
62 | | } |
63 | 28 | x.id = x._id; |
64 | 28 | delete x._id; |
65 | 28 | return x; |
66 | | }; |
67 | 17 | massageCore = function(r2) { |
68 | 25 | if (Array.isArray(r2)) { |
69 | 4 | return r2.map(massageOne); |
70 | | } else { |
71 | 21 | return massageOne(r2); |
72 | | } |
73 | | }; |
74 | 17 | massage = function(r2) { |
75 | 25 | return massageCore(JSON.parse(JSON.stringify(r2))); |
76 | | }; |
77 | 17 | massaged = function(f) { |
78 | 16 | return function(err, data) { |
79 | 16 | if (err) { |
80 | 0 | return f(err); |
81 | | } else { |
82 | 16 | return f(null, massage(data)); |
83 | | } |
84 | | }; |
85 | | }; |
86 | 17 | api.connect = function(databaseUrl, callback) { |
87 | 11 | mongoose.connect(databaseUrl); |
88 | 7 | db = mongojs.connect(databaseUrl, Object.keys(api.getModels())); |
89 | 7 | return db[Object.keys(models)[0]].find(function(err) { |
90 | 7 | return callback(err); |
91 | | }); |
92 | | }; |
93 | 17 | api.close = function(callback) { |
94 | 6 | mongoose.connection.close(); |
95 | 6 | return callback(); |
96 | | }; |
97 | 17 | api.list = function(model, filter, callback) { |
98 | 3 | var rr; |
99 | 3 | filter = preprocFilter(filter); |
100 | 3 | rr = models[model].find(filter); |
101 | 3 | if (meta[model].defaultSort != null) { |
102 | 1 | rr = rr.sort(_.object([[meta[model].defaultSort, 'asc']])); |
103 | | } |
104 | 3 | return rr.exec(massaged(callback)); |
105 | | }; |
106 | 17 | api.getOne = function(model, config, callback) { |
107 | 9 | var filter; |
108 | 9 | filter = preprocFilter(config.filter || {}); |
109 | 9 | return models[model].findOne(filter, function(err, data) { |
110 | 9 | if (err) { |
111 | 1 | if (err.toString() === 'Error: Invalid ObjectId') { |
112 | 1 | callback(new Error('No such id')); |
113 | | } else { |
114 | 0 | callback(err); |
115 | | } |
116 | 8 | } else if (!(data != null)) { |
117 | 1 | return callback(new Error('No match')); |
118 | | } else { |
119 | 7 | return callback(null, massage(data)); |
120 | | } |
121 | | }); |
122 | | }; |
123 | 17 | api.delOne = function(model, filter, callback) { |
124 | 2 | filter = preprocFilter(filter); |
125 | 2 | return models[model].findOne(filter, function(err, d) { |
126 | 2 | if (err) { |
127 | 1 | if (err.toString() === 'Error: Invalid ObjectId') { |
128 | 1 | return callback(new Error('No such id')); |
129 | | } else { |
130 | 0 | return callback(err); |
131 | | } |
132 | 1 | } else if (!(d != null)) { |
133 | 0 | return callback(new Error('No such id')); |
134 | | } else { |
135 | 1 | return d.remove(function(err) { |
136 | 0 | return callback(err, !err ? massage(d) : void 0); |
137 | | }); |
138 | | } |
139 | | }); |
140 | | }; |
141 | 17 | getKeys = function(data, target, prefix) { |
142 | 2 | var valids; |
143 | 2 | if (target == null) { |
144 | 1 | target = []; |
145 | | } |
146 | 2 | if (prefix == null) { |
147 | 1 | prefix = ''; |
148 | | } |
149 | 2 | valids = ['Array', 'String', 'Boolean', 'Date', 'Number', 'Null']; |
150 | 2 | Object.keys(data).forEach(function(key) { |
151 | 6 | if (valids.some(function(x) { |
152 | 20 | return _(data[key])['is' + x](); |
153 | | })) { |
154 | 5 | return target.push(prefix + key); |
155 | | } else { |
156 | 1 | return getKeys(data[key], target, prefix + key + '.'); |
157 | | } |
158 | | }); |
159 | 2 | return target; |
160 | | }; |
161 | 17 | api.putOne = function(modelName, data, filter, callback) { |
162 | 1 | var inputFields, inputFieldsValid, invalidFields, validField; |
163 | 1 | filter = preprocFilter(filter); |
164 | 1 | model = models[modelName]; |
165 | 1 | inputFieldsValid = getKeys(data); |
166 | 1 | inputFields = Object.keys(data); |
167 | 1 | validField = Object.keys(model.schema.paths); |
168 | 1 | invalidFields = _.difference(inputFieldsValid, validField); |
169 | 1 | if (invalidFields.length > 0) { |
170 | 0 | callback(new Error("Invalid fields: " + invalidFields.join(', '))); |
171 | 0 | return; |
172 | | } |
173 | 1 | return model.findOne(filter, propagate(callback, function(d) { |
174 | 1 | if (!(d != null)) { |
175 | 0 | callback(new Error("No such id")); |
176 | 0 | return; |
177 | | } |
178 | 1 | inputFields.forEach(function(key) { |
179 | 4 | return d[key] = data[key]; |
180 | | }); |
181 | 1 | return d.save(function(err) { |
182 | 1 | return callback(err, err ? null : massage(d)); |
183 | | }); |
184 | | })); |
185 | | }; |
186 | 17 | api.post = function(model, indata, callback) { |
187 | 13 | var owners, ownersOwners, ownersRaw, saveFunc; |
188 | 13 | saveFunc = function(data) { |
189 | 13 | return new models[model](data).save(function(err) { |
190 | 13 | var fieldMatch, valueMatch; |
191 | 13 | if (err && err.code === 11000) { |
192 | 0 | fieldMatch = err.err.match(/\$([a-zA-Z]+)_1/); |
193 | 0 | valueMatch = err.err.match(/"([a-zA-Z]+)"/); |
194 | 0 | if (fieldMatch && valueMatch) { |
195 | 0 | return callback(new Error("Duplicate value '" + valueMatch[1] + "' for " + fieldMatch[1])); |
196 | | } else { |
197 | 0 | return callback(new Error("Unique constraint violated")); |
198 | | } |
199 | | } else { |
200 | 13 | return massaged(callback).apply(this, arguments); |
201 | | } |
202 | | }); |
203 | | }; |
204 | 13 | ownersRaw = getOwners(model); |
205 | 13 | owners = _(ownersRaw).pluck('plur'); |
206 | 13 | ownersOwners = _(owners.map(function(x) { |
207 | 3 | return getOwners(x); |
208 | | })).flatten(); |
209 | 13 | if (ownersOwners.length === 0) { |
210 | 12 | return saveFunc(indata); |
211 | | } else { |
212 | 1 | return api.getOne(owners[0], { |
213 | | id: indata[ownersRaw[0].sing] |
214 | | }, function(err, ownerdata) { |
215 | 1 | var metaFields, paths; |
216 | 1 | paths = models[owners[0]].schema.paths; |
217 | 1 | metaFields = Object.keys(paths).filter(function(key) { |
218 | 5 | return !!paths[key].options['x-owner'] || !!paths[key].options['x-indirect-owner']; |
219 | | }); |
220 | 1 | metaFields.forEach(function(key) { |
221 | 1 | return indata[key] = ownerdata[key]; |
222 | | }); |
223 | 1 | return saveFunc(indata); |
224 | | }); |
225 | | } |
226 | | }; |
227 | 17 | internalListSub = function(model, outer, id, filter, callback) { |
228 | 0 | var finalFilter; |
229 | 0 | if (!(callback != null)) { |
230 | 0 | callback = filter; |
231 | 0 | filter = {}; |
232 | | } |
233 | 0 | if ((filter[outer] != null) && filter[outer].toString() !== id.toString()) { |
234 | 0 | callback(new Error('No such id')); |
235 | 0 | return; |
236 | | } |
237 | 0 | filter = preprocFilter(filter); |
238 | 0 | finalFilter = _.extend({}, filter, _.object([[outer, id]])); |
239 | 0 | return models[model].find(finalFilter, callback); |
240 | | }; |
241 | 17 | api.delMany = function(primaryModel, primaryId, propertyName, secondaryId, callback) { |
242 | 0 | var inverseName, mm, secondaryModel; |
243 | 0 | mm = getManyToMany(primaryModel).filter(function(x) { |
244 | 0 | return x.name === propertyName; |
245 | | })[0]; |
246 | 0 | if (mm === null) { |
247 | 0 | callback(new Error('Invalid manyToMany-property')); |
248 | 0 | return; |
249 | | } |
250 | 0 | secondaryModel = mm.ref; |
251 | 0 | inverseName = mm.inverseName; |
252 | 0 | return async.forEach([ |
253 | | { |
254 | | model: primaryModel, |
255 | | id: primaryId, |
256 | | property: propertyName, |
257 | | secondaryId: secondaryId |
258 | | }, { |
259 | | model: secondaryModel, |
260 | | id: secondaryId, |
261 | | property: inverseName, |
262 | | secondaryId: primaryId |
263 | | } |
264 | | ], function(item, callback) { |
265 | 0 | return models[item.model].findById(item.id, propagate(callback, function(data) { |
266 | 0 | var conditions, options, update; |
267 | 0 | conditions = { |
268 | | _id: item.id |
269 | | }; |
270 | 0 | update = { |
271 | | $pull: _.object([[item.property, item.secondaryId]]) |
272 | | }; |
273 | 0 | options = {}; |
274 | 0 | return models[item.model].update(conditions, update, options, function(err, numAffected) { |
275 | 0 | return callback(err); |
276 | | }); |
277 | | })); |
278 | | }, callback); |
279 | | }; |
280 | 17 | api.postMany = function(primaryModel, primaryId, propertyName, secondaryId, callback) { |
281 | 1 | var inverseName, mm, secondaryModel; |
282 | 1 | mm = getManyToMany(primaryModel).filter(function(x) { |
283 | 1 | return x.name === propertyName; |
284 | | })[0]; |
285 | 1 | if (mm === null) { |
286 | 0 | callback(new Error('Invalid manyToMany-property')); |
287 | 0 | return; |
288 | | } |
289 | 1 | secondaryModel = mm.ref; |
290 | 1 | inverseName = mm.inverseName; |
291 | 1 | return models[primaryModel].findById(primaryId, propagate(callback, function(data) { |
292 | 1 | return models[secondaryModel].findById(secondaryId, propagate(callback, function(data2) { |
293 | 1 | if (-1 === data[propertyName].indexOf(secondaryId)) { |
294 | 1 | data[propertyName].push(secondaryId); |
295 | | } |
296 | 1 | if (-1 === data2[inverseName].indexOf(primaryId)) { |
297 | 1 | data2[inverseName].push(primaryId); |
298 | | } |
299 | 1 | return data.save(propagate(callback, function() { |
300 | 1 | return data2.save(function(err) { |
301 | 1 | return callback(err, {}); |
302 | | }); |
303 | | })); |
304 | | })); |
305 | | })); |
306 | | }; |
307 | 17 | api.getMany = function(primaryModel, primaryId, propertyName, callback) { |
308 | 1 | return models[primaryModel].findOne({ |
309 | | _id: primaryId |
310 | | }).populate(propertyName).exec(function(err, story) { |
311 | 1 | return callback(err, massage(story[propertyName])); |
312 | | }); |
313 | | }; |
314 | 17 | desugarModel = function(modelName, tgt, src, keys) { |
315 | 41 | return keys.forEach(function(key) { |
316 | 60 | var obj; |
317 | 60 | if (typeof src[key] === 'string') { |
318 | 14 | obj = {}; |
319 | 14 | obj[key] = { |
320 | | type: src[key] |
321 | | }; |
322 | 14 | return desugarModel(modelName, tgt, obj, [key]); |
323 | 46 | } else if (!(src[key].type != null)) { |
324 | 0 | throw new Error("must assign a type: " + JSON.stringify(keys)); |
325 | 46 | } else if (src[key].type === 'mixed') { |
326 | 2 | return tgt[key] = { |
327 | | type: 'mixed' |
328 | | }; |
329 | 44 | } else if (src[key].type === 'nested') { |
330 | 1 | tgt[key] = { |
331 | | type: 'nested' |
332 | | }; |
333 | 1 | return desugarModel(modelName, tgt[key], src[key], _.without(Object.keys(src[key]), 'type')); |
334 | 43 | } else if (_(['string', 'number', 'date', 'boolean']).contains(src[key].type)) { |
335 | 38 | tgt[key] = { |
336 | | type: src[key].type, |
337 | | required: !!src[key].required, |
338 | | index: !!src[key].index, |
339 | | unique: !!src[key].unique |
340 | | }; |
341 | 38 | if (src[key]["default"] != null) { |
342 | 18 | tgt[key]["default"] = src[key]["default"]; |
343 | | } |
344 | 38 | if (src[key].validate != null) { |
345 | 1 | return tgt[key].validate = src[key].validate; |
346 | | } |
347 | 5 | } else if (src[key].type === 'hasOne') { |
348 | 0 | return tgt[key] = { |
349 | | ref: src[key].model, |
350 | | validation: src[key].validation |
351 | | }; |
352 | 5 | } else if (src[key].type === 'hasMany') { |
353 | 4 | tgt[key] = src[key]; |
354 | 4 | return tgt[key].inverseName = src[key].inverseName || key; |
355 | | } else { |
356 | 1 | throw new Error("Invalid type: " + src[key].type); |
357 | | } |
358 | | }); |
359 | | }; |
360 | 17 | specTransform = function(allspec, modelName, tgt, src, keys) { |
361 | 26 | return keys.forEach(function(key) { |
362 | 45 | if (src[key].type === 'mixed') { |
363 | 2 | return tgt[key] = { |
364 | | type: mongoose.Schema.Types.Mixed |
365 | | }; |
366 | 43 | } else if (src[key].type === 'nested') { |
367 | 1 | tgt[key] = {}; |
368 | 1 | return specTransform(allspec, modelName, tgt[key], src[key], _.without(Object.keys(src[key]), 'type')); |
369 | 42 | } else if (src[key].type === 'string') { |
370 | 31 | tgt[key] = _.extend({}, src[key], { |
371 | | type: String |
372 | | }); |
373 | 31 | if (src[key].validate != null) { |
374 | 1 | return tgt[key].validate = function(value, callback) { |
375 | 0 | return src[key].validate(api, value, callback); |
376 | | }; |
377 | | } |
378 | 11 | } else if (src[key].type === 'number') { |
379 | 4 | return tgt[key] = _.extend({}, src[key], { |
380 | | type: Number |
381 | | }); |
382 | 7 | } else if (src[key].type === 'date') { |
383 | 2 | return tgt[key] = _.extend({}, src[key], { |
384 | | type: Date |
385 | | }); |
386 | 5 | } else if (src[key].type === 'boolean') { |
387 | 1 | return tgt[key] = _.extend({}, src[key], { |
388 | | type: Boolean |
389 | | }); |
390 | 4 | } else if (src[key].type === 'hasOne') { |
391 | 0 | return tgt[key] = { |
392 | | ref: src[key].model, |
393 | | 'x-validation': src[key].validation |
394 | | }; |
395 | 4 | } else if (src[key].type === 'hasMany') { |
396 | 4 | tgt[key] = [ |
397 | | { |
398 | | type: ObjectId, |
399 | | ref: src[key].model, |
400 | | inverseName: src[key].inverseName |
401 | | } |
402 | | ]; |
403 | 4 | return allspec[src[key].model][src[key].inverseName] = [ |
404 | | { |
405 | | type: ObjectId, |
406 | | ref: modelName, |
407 | | inverseName: key |
408 | | } |
409 | | ]; |
410 | | } |
411 | | }); |
412 | | }; |
413 | 17 | api.defModels = function(models) { |
414 | 14 | var allspec, newrest, rest; |
415 | 14 | rest = {}; |
416 | 14 | Object.keys(models).forEach(function(modelName) { |
417 | 26 | var inspec, spec; |
418 | 26 | spec = {}; |
419 | 26 | inspec = models[modelName].fields || {}; |
420 | 26 | desugarModel(modelName, spec, inspec, Object.keys(inspec)); |
421 | 25 | rest[modelName] = _.extend({}, models[modelName], { |
422 | | fields: spec |
423 | | }); |
424 | 25 | if (!rest[modelName].owners) { |
425 | 7 | return rest[modelName].owners = {}; |
426 | | } |
427 | | }); |
428 | 13 | specmodels = rest; |
429 | 13 | newrest = {}; |
430 | 13 | allspec = {}; |
431 | 13 | Object.keys(rest).forEach(function(modelName) { |
432 | 25 | return allspec[modelName] = {}; |
433 | | }); |
434 | 13 | Object.keys(rest).forEach(function(modelName) { |
435 | 25 | var inspec, owners, spec; |
436 | 25 | spec = allspec[modelName]; |
437 | 25 | owners = rest[modelName].owners || {}; |
438 | 25 | inspec = rest[modelName].fields || {}; |
439 | 25 | specTransform(allspec, modelName, spec, inspec, Object.keys(inspec)); |
440 | 25 | return newrest[modelName] = _.extend({}, rest[modelName], { |
441 | | fields: spec |
442 | | }); |
443 | | }); |
444 | 13 | return Object.keys(newrest).forEach(function(modelName) { |
445 | 25 | return defModel(modelName, newrest[modelName]); |
446 | | }); |
447 | | }; |
448 | 17 | defModel = function(name, conf) { |
449 | 25 | var owners, spec; |
450 | 25 | spec = conf.fields; |
451 | 25 | owners = conf.owners; |
452 | 25 | Object.keys(owners).forEach(function(ownerName) { |
453 | 8 | return spec[ownerName] = { |
454 | | type: ObjectId, |
455 | | ref: owners[ownerName], |
456 | | required: true, |
457 | | 'x-owner': true |
458 | | }; |
459 | | }); |
460 | 25 | Object.keys(owners).forEach(function(ownerName) { |
461 | 8 | var paths; |
462 | 8 | paths = models[owners[ownerName]].schema.paths; |
463 | 8 | return Object.keys(paths).filter(function(p) { |
464 | 25 | return paths[p].options['x-owner'] || paths[p].options['x-indirect-owner']; |
465 | | }).forEach(function(p) { |
466 | 4 | return spec[p] = { |
467 | | type: ObjectId, |
468 | | ref: paths[p].options.ref, |
469 | | required: true, |
470 | | 'x-indirect-owner': true |
471 | | }; |
472 | | }); |
473 | | }); |
474 | 25 | Object.keys(spec).forEach(function(fieldName) { |
475 | 59 | if (spec[fieldName].ref != null) { |
476 | 12 | return spec[fieldName].type = ObjectId; |
477 | | } |
478 | | }); |
479 | 25 | meta[name] = { |
480 | | defaultSort: conf.defaultSort |
481 | | }; |
482 | 25 | models[name] = model(name, spec); |
483 | 25 | models[name].schema.pre('save', nullablesValidation(models[name].schema)); |
484 | 25 | models[name].schema.pre('remove', function(next) { |
485 | 1 | return preRemoveCascadeNonNullable(models[name], this._id.toString(), next); |
486 | | }); |
487 | 25 | return models[name].schema.pre('remove', function(next) { |
488 | 0 | return preRemoveCascadeNullable(models[name], this._id.toString(), next); |
489 | | }); |
490 | | }; |
491 | 17 | getMetaFields = function(modelName) { |
492 | 3 | var metaFields, paths, typeFunc, typeMap; |
493 | 3 | typeMap = { |
494 | | ObjectID: 'string', |
495 | | String: 'string', |
496 | | Number: 'number', |
497 | | Boolean: 'boolean', |
498 | | Date: 'date' |
499 | | }; |
500 | 3 | paths = models[modelName].schema.paths; |
501 | 3 | typeFunc = function(x) { |
502 | 0 | if (x === Boolean) { |
503 | 0 | return 'boolean'; |
504 | | } |
505 | 0 | if (x === Date) { |
506 | 0 | return 'date'; |
507 | | } |
508 | | }; |
509 | 3 | metaFields = Object.keys(paths).filter(function(key) { |
510 | 10 | return !Array.isArray(paths[key].options.type); |
511 | | }).map(function(key) { |
512 | 8 | return { |
513 | | name: (key === '_id' ? 'id' : key), |
514 | | readonly: key === '_id' || !!paths[key].options['x-owner'] || !!paths[key].options['x-indirect-owner'], |
515 | | required: !!paths[key].options.required, |
516 | | type: typeMap[paths[key].instance] || typeFunc(paths[key].options.type) || 'unknown' |
517 | | }; |
518 | | }); |
519 | 3 | return _.sortBy(metaFields, 'name'); |
520 | | }; |
521 | 17 | getOwners = function(modelName) { |
522 | 19 | var outers, paths; |
523 | 19 | paths = models[modelName].schema.paths; |
524 | 19 | outers = Object.keys(paths).filter(function(x) { |
525 | 66 | return paths[x].options['x-owner']; |
526 | | }).map(function(x) { |
527 | 5 | return { |
528 | | plur: paths[x].options.ref, |
529 | | sing: x |
530 | | }; |
531 | | }); |
532 | 19 | return outers; |
533 | | }; |
534 | 17 | getOwnedModels = function(ownerModelName) { |
535 | 3 | return _.flatten(Object.keys(models).map(function(modelName) { |
536 | 9 | var paths; |
537 | 9 | paths = models[modelName].schema.paths; |
538 | 9 | return Object.keys(paths).filter(function(x) { |
539 | 30 | return paths[x].options.type === ObjectId && paths[x].options.ref === ownerModelName && paths[x].options['x-owner']; |
540 | | }).map(function(x) { |
541 | 1 | return { |
542 | | name: modelName, |
543 | | field: x |
544 | | }; |
545 | | }); |
546 | | })); |
547 | | }; |
548 | 17 | getManyToMany = function(modelName) { |
549 | 5 | var manyToMany, paths; |
550 | 5 | paths = models[modelName].schema.paths; |
551 | 5 | manyToMany = Object.keys(paths).filter(function(x) { |
552 | 16 | return Array.isArray(paths[x].options.type); |
553 | | }).map(function(x) { |
554 | 4 | return { |
555 | | inverseName: paths[x].options.type[0].inverseName, |
556 | | ref: paths[x].options.type[0].ref, |
557 | | name: x |
558 | | }; |
559 | | }); |
560 | 5 | return manyToMany; |
561 | | }; |
562 | 17 | api.getMeta = function(modelName) { |
563 | 3 | return { |
564 | | fields: getMetaFields(modelName), |
565 | | owns: getOwnedModels(modelName), |
566 | | owners: getOwners(modelName), |
567 | | manyToMany: getManyToMany(modelName) |
568 | | }; |
569 | | }; |
570 | 17 | api.getModels = function() { |
571 | 8 | return specmodels; |
572 | | }; |
573 | 17 | nullablesValidation = function(schema) { |
574 | 25 | return function(next) { |
575 | 20 | var nonNullOuters, outers, paths, self; |
576 | 20 | self = this; |
577 | 20 | paths = schema.paths; |
578 | 20 | outers = Object.keys(paths).filter(function(x) { |
579 | 74 | return paths[x].options.type === ObjectId && typeof paths[x].options.ref === 'string' && !paths[x].options['x-owner']; |
580 | | }).map(function(x) { |
581 | 1 | return { |
582 | | plur: paths[x].options.ref, |
583 | | sing: x, |
584 | | validation: paths[x].options['x-validation'] |
585 | | }; |
586 | | }); |
587 | 20 | nonNullOuters = outers.filter(function(x) { |
588 | 1 | return self[x.sing] != null; |
589 | | }); |
590 | 20 | return async.forEach(nonNullOuters, function(o, callback) { |
591 | 1 | return api.getOne(o.plur, { |
592 | | id: self[o.sing] |
593 | | }, function(err, data) { |
594 | 1 | if (err || !data) { |
595 | 0 | return callback(new Error("Invalid pointer")); |
596 | 1 | } else if (o.validation) { |
597 | 0 | return o.validation(self, data, function(err) { |
598 | 0 | return callback(err ? new Error(err) : void 0); |
599 | | }); |
600 | | } else { |
601 | 1 | return callback(); |
602 | | } |
603 | | }); |
604 | | }, next); |
605 | | }; |
606 | | }; |
607 | 17 | preRemoveCascadeNonNullable = function(owner, id, next) { |
608 | 1 | var manys; |
609 | 1 | manys = getManyToMany(owner.modelName); |
610 | 1 | return manys.forEach(function(many) { |
611 | 1 | return models[many.ref].find(_.object([[many.inverseName, id]]).exec(function(err, val) { |
612 | 0 | var flattenedModels; |
613 | 0 | console.log("eec"); |
614 | 0 | console.log(val); |
615 | 0 | flattenedModels = getOwnedModels(owner.modelName); |
616 | 0 | return async.forEach(flattenedModels, function(mod, callback) { |
617 | 0 | return internalListSub(mod.name, mod.field, id, function(err, data) { |
618 | 0 | return async.forEach(data, function(item, callback) { |
619 | 0 | console.log(item); |
620 | 0 | return item.remove(callback); |
621 | | }, callback); |
622 | | }); |
623 | | }, next); |
624 | | })); |
625 | | }); |
626 | | }; |
627 | 17 | preRemoveCascadeNullable = function(owner, id, next) { |
628 | 0 | var flattenedModels, ownedModels; |
629 | 0 | ownedModels = Object.keys(models).map(function(modelName) { |
630 | 0 | var paths; |
631 | 0 | paths = models[modelName].schema.paths; |
632 | 0 | return Object.keys(paths).filter(function(x) { |
633 | 0 | return paths[x].options.type === ObjectId && paths[x].options.ref === owner.modelName && !paths[x].options['x-owner']; |
634 | | }).map(function(x) { |
635 | 0 | return { |
636 | | name: modelName, |
637 | | field: x |
638 | | }; |
639 | | }); |
640 | | }); |
641 | 0 | flattenedModels = _.flatten(ownedModels); |
642 | 0 | return async.forEach(flattenedModels, function(mod, callback) { |
643 | 0 | return internalListSub(mod.name, mod.field, id, function(err, data) { |
644 | 0 | return async.forEach(data, function(item, callback) { |
645 | 0 | item[mod.field] = null; |
646 | 0 | item.save(); |
647 | 0 | return callback(); |
648 | | }, callback); |
649 | | }); |
650 | | }, next); |
651 | | }; |
652 | 17 | return api; |
653 | | }; |
654 | | |
655 | | }).call(this); |