CSOL-site/db.js

94 строки
3.0 KiB
JavaScript
Исходник Обычный вид История

2013-04-18 15:10:15 +04:00
const path = require('path');
2013-04-08 20:57:55 +04:00
const Sequelize = require('sequelize');
2013-04-08 21:24:18 +04:00
const DB_NAME = process.env['CSOL_DB_NAME'] || 'csol';
2013-04-08 20:57:55 +04:00
const USERNAME = process.env['CSOL_DB_USER'] || 'root';
const PASSWORD = process.env['CSOL_DB_PASS'];
2013-04-18 15:10:15 +04:00
const MODEL_PATH = process.env['CSOL_MODEL_PATH'] || path.join(__dirname, 'models');
2013-04-08 20:57:55 +04:00
const db = new Sequelize(DB_NAME, USERNAME, PASSWORD, {
2013-04-08 20:57:55 +04:00
define: { charset: 'utf8' }
});
/**
* In order to get useful bi-directional relationships on models, the relationship
* has to be defined on both sides:
*
* Learner.hasOne(Guardian);
* Guardian.hasMany(Learner);
*
* This automatically adds functionality to both parties, and without both
* relationships being defined, half would be missing:
*
* Learner.[get|set]Guardian();
* Guardian.[get|set]Learners();
* Guardian.[add|remove]Learner();
*
* However, this doesn't work when models are split out into their own files, as
* we end up with circular references. That is, in order for `Learner` to reference
* `Guardian`, it has to `require(.../guardian)`, but `Guardian` has to do likewise
* in order to reference `Learner`.
*
* Hence the following abstraction, which allows us to define models in their own
* files, but also allows for fully-defined bi-directional relationships. So,
* rather than pull in models directly by `require(.../model)`, we now go via the
* database instead.
*
* model = require(.../db).model('Model');
*/
var modelCache = {};
db.model = function(name) {
2013-04-19 11:58:27 +04:00
// `normalizedName` is a conversion from 'some name' to 'someName'
var normalized = name.replace(/(^| +)([a-z])/ig, function(match, space, character) {
return character[space ? 'toUpperCase' : 'toLowerCase']();
2013-04-19 11:58:27 +04:00
});
// `name` is a conversion from 'some name' into 'SomeName'
var name = normalized.replace(/(^| +)([a-z])/ig, function(match, space, character) {
return character.toUpperCase();
2013-04-19 11:58:27 +04:00
});
// `key` is a conversion from 'some name' to 'somename'
var key = name.toLowerCase();
if (!modelCache[key]) {
console.log('Defining model:', name);
2013-04-18 15:10:15 +04:00
var definition = require(path.join(MODEL_PATH, normalized)),
properties = definition.properties,
relationships = definition.relationships;
delete definition.properties;
delete definition.relationships;
var model = db.define(name, properties, definition);
2013-04-19 11:58:27 +04:00
// We need to cache the model before resolving any relationships, so that it
// is available to any related models that might reference it.
modelCache[key] = model;
if (relationships) {
relationships.forEach(function(relationship) {
var relatedModel = db.model(relationship.model),
type = relationship.type;
console.log('Establishing relationship:', name + '.' + type + '(' + relatedModel.name + ')');
delete relationship.model;
delete relationship.type;
model[type](relatedModel, relationship);
});
}
model.sync();
}
return modelCache[key];
}
2013-04-08 20:57:55 +04:00
db.type = Sequelize;
module.exports = db;