263 lines
6.2 KiB
JavaScript
263 lines
6.2 KiB
JavaScript
const fs = require('fs');
|
|
const db = require('db');
|
|
const log = require('log');
|
|
const bc = require('bcryptjs');
|
|
|
|
let models = [];
|
|
|
|
module.exports.BaseModel = class {
|
|
constructor(name) {
|
|
models.push(this);
|
|
this.name = name;
|
|
this.fields = [];
|
|
|
|
}
|
|
|
|
addField(field) {
|
|
this.fields.push(field);
|
|
}
|
|
|
|
reinitialize(callback = () => {}) {
|
|
log.debug('Reinitializing ' + this.name);
|
|
db.query('DROP TABLE IF EXISTS ' + this.name + ' CASCADE')
|
|
.then(res => this.createTable(callback))
|
|
.catch(err => log.dberror(err));
|
|
}
|
|
|
|
createTable(callback) {
|
|
let query = 'CREATE TABLE ' + this.name + '(\n';
|
|
query += this.fields
|
|
.map(f => '\t' + f.getCreationString())
|
|
.join(',\n');
|
|
query += ');';
|
|
|
|
log.debug(query);
|
|
|
|
db.query(query)
|
|
.then(res => {
|
|
log.debug("Table " + this.name + " created")
|
|
callback();
|
|
})
|
|
.catch(err => log.dberror(err));
|
|
}
|
|
}
|
|
|
|
module.exports.BaseField = class {
|
|
constructor(name) {
|
|
this.name = name;
|
|
}
|
|
|
|
createMutators() {
|
|
return {
|
|
get: this.createGetter(),
|
|
set: this.createSetter(),
|
|
};
|
|
}
|
|
|
|
createGetter() {
|
|
var self = this;
|
|
return function() {
|
|
return this['_' + self.name].value;
|
|
}
|
|
}
|
|
|
|
createSetter() {
|
|
var self = this;
|
|
return function(e) {
|
|
this['_' + self.name] = {
|
|
value: e,
|
|
changed: true,
|
|
};
|
|
}
|
|
}
|
|
}
|
|
|
|
module.exports.SmallIntegerField = class extends module.exports.BaseField {
|
|
constructor(name) {
|
|
super(name);
|
|
}
|
|
|
|
getCreationString() {
|
|
return this.name + " SMALLINT";
|
|
}
|
|
}
|
|
|
|
module.exports.SerialField = class extends module.exports.BaseField {
|
|
constructor(name) {
|
|
super(name);
|
|
}
|
|
|
|
getCreationString() {
|
|
return this.name + " SERIAL";
|
|
}
|
|
|
|
}
|
|
|
|
module.exports.TextField = class extends module.exports.BaseField {
|
|
constructor(name) {
|
|
super(name);
|
|
}
|
|
|
|
getCreationString() {
|
|
return this.name + " TEXT";
|
|
}
|
|
}
|
|
|
|
module.exports.PasswordField = class extends module.exports.BaseField {
|
|
constructor(name) {
|
|
super(name);
|
|
}
|
|
|
|
getCreationString() {
|
|
return this.name + ' TEXT';
|
|
}
|
|
|
|
|
|
createSetter() {
|
|
let self = this;
|
|
return function(e) {
|
|
this['_' + self.name] = {
|
|
value: bc.hashSync(e, 8),
|
|
changed: true,
|
|
};
|
|
}
|
|
|
|
}
|
|
}
|
|
|
|
module.exports.PasswordField.testSync = function(password, hash) {
|
|
return bc.compareSync(password, hash);
|
|
}
|
|
|
|
|
|
module.exports.createClass = function(model) {
|
|
|
|
let ret = function(param) {
|
|
this._persisted = false;
|
|
for (let field of model.fields) {
|
|
this['_' + field.name] = {
|
|
value: undefined,
|
|
changed: false,
|
|
}
|
|
Object.defineProperty(this, field.name, field.createMutators());
|
|
}
|
|
};
|
|
|
|
ret.getById = function(id, callback) {
|
|
db
|
|
.query('SELECT * FROM ' + model.name + ' WHERE id=$1;', [id])
|
|
.then(res => {
|
|
// Create the instance
|
|
let instance = new ret();
|
|
instance._persisted = true;
|
|
instance._setFromDbResult(res);
|
|
callback(undefined, instance);
|
|
})
|
|
.catch(err => callback(err));
|
|
}
|
|
|
|
ret.prototype._setFromDbResult = function(res) {
|
|
for (let field of model.fields) {
|
|
this['_' + field.name] = {
|
|
value: res.rows[0][field.name],
|
|
changed: false,
|
|
};
|
|
}
|
|
}
|
|
|
|
ret.prototype.save = function(callback = () => {}) {
|
|
let fieldsToSave = [];
|
|
for (let field of model.fields) {
|
|
if (this['_' + field.name].changed) {
|
|
fieldsToSave.push({
|
|
field: field,
|
|
value: this[field.name],
|
|
});
|
|
}
|
|
}
|
|
|
|
fieldsToSave = fieldsToSave.filter((field) => {
|
|
return !(field.field instanceof module.exports.SerialField);
|
|
});
|
|
|
|
if (!this._persisted) {
|
|
// INSERT INTO
|
|
let queryBegin = 'INSERT INTO ' + model.name + '('
|
|
let queryEnd = ' VALUES (';
|
|
queryBegin += fieldsToSave
|
|
.map(f => f.field.name)
|
|
.join(',');
|
|
|
|
queryEnd += fieldsToSave
|
|
.map((f, id) => '$' + (id + 1))
|
|
.join(',');
|
|
|
|
queryBegin += ')'
|
|
queryEnd += ') RETURNING *;'
|
|
|
|
let query = queryBegin + queryEnd;
|
|
|
|
db
|
|
.query(query, fieldsToSave.map(f => f.value))
|
|
.then(res => {
|
|
this._setFromDbResult(res);
|
|
this._persisted = true;
|
|
callback(undefined, this);
|
|
})
|
|
.catch(err => callback(err));
|
|
|
|
} else {
|
|
// UPDATE FROM
|
|
let query = 'UPDATE FROM ' + model.name + ' SET ';
|
|
|
|
query += fieldsToSave.map(f => {
|
|
return f.field.name + '=' + f.value;
|
|
}).join(',');
|
|
|
|
query += ') RETURNING *;'
|
|
|
|
db
|
|
.query(query, fieldsToSave.map(f => f.value))
|
|
.then(res => {
|
|
this._setFromDbResult(res);
|
|
this._persisted = true;
|
|
callback(undefined, this);
|
|
})
|
|
.catch(err => callback(err));
|
|
|
|
|
|
}
|
|
}
|
|
|
|
return ret;
|
|
}
|
|
|
|
module.exports.reinitialize = function(callback = () => {}) {
|
|
let finished = models.map(m => false);
|
|
for (let i = 0; i < models.length; i++) {
|
|
let model = models[i];
|
|
model.reinitialize(() => {
|
|
finished[i] = true;
|
|
if (finished.reduce((a, b) => a && b, true)) {
|
|
callback();
|
|
}
|
|
});
|
|
}
|
|
}
|
|
|
|
module.exports.load = function(controllersDir) {
|
|
|
|
fs.readdirSync(controllersDir).forEach(function(name) {
|
|
|
|
let path = controllersDir + '/' + name + '/models.js';
|
|
try {
|
|
fs.accessSync(path);
|
|
} catch (e) {
|
|
return;
|
|
}
|
|
|
|
require(path);
|
|
});
|
|
|
|
}
|