1 | var fs = require('fs'),
|
2 | path = require('path'),
|
3 | async = require('async'),
|
4 | Document = require('./document'),
|
5 | Queriable = require('./query'),
|
6 | db_helper = require('./connection'),
|
7 | logger = require('./logger');
|
8 |
|
9 | var defined_models = {};
|
10 |
|
11 |
|
12 | var ModelDocument = function (model_type, schema, views) {
|
13 |
|
14 | var self = this;
|
15 | var base = self;
|
16 |
|
17 | self.model_type = model_type;
|
18 | self.schema = schema;
|
19 | self.views = views;
|
20 | self.methods = {};
|
21 |
|
22 | this.beforeSave = function (fn) {
|
23 | self.beforeSaveFn = fn;
|
24 | };
|
25 |
|
26 | this.afterSave = function (fn) {
|
27 | self.afterSaveFn = fn;
|
28 | };
|
29 |
|
30 | this.beforeCreate = function (fn) {
|
31 | self.beforeCreateFn = fn;
|
32 | };
|
33 |
|
34 | this.beforeRemove = function (fn) {
|
35 | self.beforeRemoveFn = fn
|
36 | };
|
37 |
|
38 | this.afterRemove = function (fn) {
|
39 | self.afterRemoveFn = fn
|
40 | };
|
41 |
|
42 | this.validate = function (fn) {
|
43 | self.validateFn = fn;
|
44 | };
|
45 |
|
46 | this.addView = function (view_name, view) {
|
47 | self.views[view_name] = view;
|
48 | };
|
49 |
|
50 | this.addMethod = function (method_name, method) {
|
51 | self.methods[method_name] = method;
|
52 | };
|
53 |
|
54 |
|
55 | this.view = function (view_name, options, cb) {
|
56 | if (cb) {
|
57 | this._view(self.model_type + '/' + view_name, options, cb);
|
58 | } else {
|
59 | this._view(self.model_type + '/' + view_name, options);
|
60 | }
|
61 | };
|
62 |
|
63 | self.load = function (model_data) {
|
64 | logger.info("Create model %s for %s", self.schema, model_data);
|
65 |
|
66 | var model = new Document( self.beforeSaveFn,
|
67 | self.beforeAfterFn,
|
68 | self.beforeRemoveFn,
|
69 | self.afterRemoveFn,
|
70 | self.validateFn,
|
71 | self.schema,
|
72 | self.model_type);
|
73 |
|
74 | self._load_methods(model);
|
75 |
|
76 | if (!model_data) return model;
|
77 |
|
78 | self._load_model_from_schema(key, model, model_data);
|
79 |
|
80 | if (model_data._id) {
|
81 | model.id = model_data._id;
|
82 | }
|
83 |
|
84 | if(model_data._rev) {
|
85 | model.rev = model_data._rev;
|
86 | }
|
87 |
|
88 | model.dateCreated = model_data.dateCreated;
|
89 | model.lastUpdated = model_data.lastUpdated;
|
90 |
|
91 | return model;
|
92 | };
|
93 |
|
94 | self._load_methods = function (model) {
|
95 | Object.keys(self.methods).forEach(function (key) {
|
96 | model[key] = self.methods[key];
|
97 | });
|
98 | };
|
99 |
|
100 | self._load_model_from_schema = function (key, model, model_data) {
|
101 |
|
102 | Object.keys(self.schema).forEach(function (key) {
|
103 |
|
104 | if (self.schema[key].type.has_one) {
|
105 | model[key] = self.schema[key].type.has_one.load(model_data[key]);
|
106 |
|
107 | } else if (self.schema[key].type.has_many) {
|
108 | var created_docs = [];
|
109 | var key_store = key;
|
110 |
|
111 | if(model_data[key]) {
|
112 |
|
113 | model_data[key].forEach(function (item) {
|
114 | created_docs.push(Model(item.model_type).load(item));
|
115 | });
|
116 | }
|
117 |
|
118 | model[key] = created_docs;
|
119 |
|
120 | } else if (model_data[key] !== undefined) {
|
121 | model[key] = model_data[key];
|
122 |
|
123 | } else {
|
124 | model[key] = schema[key].default;
|
125 | }
|
126 | });
|
127 |
|
128 | }
|
129 |
|
130 | self.create = function (model_data) {
|
131 |
|
132 | var model = self.load(model_data);
|
133 | self.beforeCreateFn && self.beforeCreateFn(model);
|
134 |
|
135 | return model;
|
136 | };
|
137 |
|
138 | self.onDocLoad(self.load);
|
139 |
|
140 | };
|
141 |
|
142 |
|
143 |
|
144 | Queriable.call(ModelDocument.prototype);
|
145 |
|
146 |
|
147 | var Model = function (model_type) {
|
148 | var model_document = defined_models[model_type];
|
149 |
|
150 | if (!model_document) {
|
151 | logger.error("No schema defined for", model_type);
|
152 | throw {
|
153 | message: "Model " + model_type + " does not exist"
|
154 | }
|
155 | }
|
156 |
|
157 | if (model_document.instance) {
|
158 | return model_document.instance;
|
159 | }
|
160 |
|
161 | model_document.instance = new ModelDocument(model_type, model_document.schema);
|
162 |
|
163 | return model_document.instance;
|
164 | };
|
165 |
|
166 | Model.create_connection= function (db_name) {
|
167 | return db_helper.create_connection(db_name);
|
168 | }
|
169 |
|
170 | Model.connect = Model.create_connection;
|
171 |
|
172 | Model.create_views = function (model_type, model_schema) {
|
173 | logger.info("creating views for %s", model_type);
|
174 | var db = db_helper.connection();
|
175 |
|
176 | var model_views = {};
|
177 |
|
178 | Object.keys(model_schema).forEach(function (property) {
|
179 | model_views[property] = {};
|
180 | model_views[property].map = 'function (doc) {if (doc.model_type === \''+model_type+'\' && doc.' +property +') { emit(doc.' +property +',doc)} }'
|
181 | });
|
182 |
|
183 | model_views.all = {};
|
184 | model_views.all.map = 'function (doc) { if (doc.model_type === \''+model_type+'\'){emit(null, doc)}}';
|
185 |
|
186 | return model_views
|
187 | };
|
188 |
|
189 |
|
190 | Model.load = function () {
|
191 | var cb = function () {};
|
192 | if (typeof(arguments[0]) === 'string') {
|
193 | var dir = path.resolve(process.cwd(),arguments[0]);
|
194 | fs.readdirSync(dir).forEach(function (file) {
|
195 | var full_path = path.join(dir,file);
|
196 | logger.info("loading " + full_path);
|
197 | require(full_path);
|
198 | });
|
199 | }
|
200 |
|
201 | var _cb = arguments[arguments.length - 1];
|
202 |
|
203 | if (typeof(_cb) === 'function') {
|
204 | cb = _cb;
|
205 | }
|
206 |
|
207 | logger.info("saving views");
|
208 | var db = db_helper.connection();
|
209 |
|
210 | Object.keys(defined_models).forEach(function (model_type) {
|
211 | var model_document = defined_models[model_type]
|
212 |
|
213 | db.save('_design/'+model_type, model_document.views, function (err, res) {
|
214 | if (err) {
|
215 | logger.error("Error creating views for %s %s",model_type, err);
|
216 | return cb(err)
|
217 | }
|
218 |
|
219 | cb();
|
220 | });
|
221 | });
|
222 |
|
223 | };
|
224 |
|
225 |
|
226 | Model.define = function (model_type, model_schema) {
|
227 | var schema = create_schema(model_schema);
|
228 |
|
229 | var model_document = {};
|
230 | model_document.schema = schema;
|
231 | model_document.views = Model.create_views(model_type, schema);
|
232 | model_document.instance = new ModelDocument(model_type, schema, model_document.views);
|
233 |
|
234 | defined_models[model_type] = model_document;
|
235 |
|
236 | logger.info("Defined schema %s for %s", schema, model_type);
|
237 |
|
238 | return model_document.instance
|
239 | };
|
240 |
|
241 | function create_schema(model_schema) {
|
242 | for (key in model_schema) {
|
243 | if (model_schema[key].hasOwnProperty('type')) {
|
244 | if (!model_schema[key].hasOwnProperty('default')) {
|
245 | model_schema[key].default = undefined;
|
246 | }
|
247 | } else {
|
248 | model_schema[key] = {
|
249 | type: model_schema[key],
|
250 | default: undefined
|
251 | };
|
252 | }
|
253 | };
|
254 |
|
255 | return model_schema;
|
256 | };
|
257 |
|
258 |
|
259 |
|
260 | Model.remove_models = function () {
|
261 | defined_models = {};
|
262 | };
|
263 |
|
264 | Model.dump = function () {
|
265 | console.dir(defined_models);
|
266 | };
|
267 |
|
268 |
|
269 |
|
270 | module.exports = Model;
|