nodal
Version:
An API Server and Framework for node.js
212 lines (148 loc) • 5.01 kB
JavaScript
;
const Command = require('cmnd').Command;
const GenerateMigrationCommand = require('./migration.js');
const generateMigration = new GenerateMigrationCommand();
const fs = require('fs');
const Database = require('../../../core/module.js').Database;
const colors = require('colors/safe');
const inflect = require('i')();
const dot = require('dot');
let templateSettings = Object.keys(dot.templateSettings).reduce((o, k) => {
o[k] = dot.templateSettings[k];
return o;
}, {})
templateSettings.strip = false;
templateSettings.varname = 'data';
let modelDir = './app/models';
function generateModelDefinition(modelName, columns) {
let model = {
name: modelName,
columns: columns
};
return dot.template(
fs.readFileSync(__dirname + '/../../templates/model.jst').toString(),
templateSettings
)(model);
}
function generateUserDefinition() {
return dot.template(
fs.readFileSync(__dirname + '/../../templates/models/user.jst').toString(),
templateSettings
)();
};
function generateAccessTokenDefinition() {
return dot.template(
fs.readFileSync(__dirname + '/../../templates/models/access_token.jst').toString(),
templateSettings
)();
};
function convertArgListToPropertyList(argList) {
// Instantiate Database so we can get access to the Adapater types
let db = new Database();
db.connect(require(`${process.cwd()}/config/db.json`)[process.env.NODE_ENV || 'development']);
return argList.slice(1).map(function(v) {
v = v.split(':');
if (Object.keys(db.adapter.types).indexOf(v[1].toLowerCase()) == -1) {
throw new Error(`Un-supported column type ${colors.yellow.bold(v[1])} for field ${colors.yellow.bold(v[0])}`);
}
let obj = {name: inflect.underscore(v[0]), type: v[1].toLowerCase()};
let rest = v.slice(2);
let properties = {};
['array', 'unique'].forEach(v => {
if (rest.indexOf(v) !== -1) {
properties[v] = true;
}
});
Object.keys(properties).length && (obj.properties = properties);
return obj;
});
}
function generateModelSchemaObject(modelName, propertyList) {
let tableName = inflect.tableize(modelName);
if (propertyList.filter(c => c.name === tableName).length) {
throw new Error(`Can not create a table with an identical field name. (${tableName}.${tableName})`);
}
return {
table: inflect.tableize(modelName),
columns: propertyList
};
}
class GenerateModelCommand extends Command {
constructor() {
super('g', 'model');
}
help() {
return {
description: 'Generate a new model and associated migration',
args: ['ModelName', 'field_1:type_1', '...', 'field_n:type_n'],
vflags: {
user: 'Use a prebuilt User model',
access_token: 'Use a prebuilt AccessToken model'
}
};
}
run(params, callback) {
if (params.vflags.hasOwnProperty('user')) {
params.args = [
'User',
'email:string:unique',
'password:string',
'username:string'
];
} else if (params.vflags.hasOwnProperty('access_token')) {
params.args = [
'AccessToken',
'user_id:int',
'access_token:string',
'token_type:string',
'expires_at:datetime',
'ip_address:string'
];
}
if (!params.args.length) {
return callback(new Error('No model name specified.'));
}
let modelName = inflect.classify(params.args[0]);
let schemaObject;
try {
schemaObject = generateModelSchemaObject(modelName, convertArgListToPropertyList(params.args));
} catch(e) {
return callback(e);
}
!fs.existsSync(modelDir) && fs.mkdirSync(modelDir);
let createPath = modelDir + '/' + inflect.underscore(modelName) + '.js';
if (fs.existsSync(createPath)) {
return callback(new Error('Model already exists'));
}
if (params.vflags.hasOwnProperty('user')) {
fs.writeFileSync(createPath, generateUserDefinition());
} else if (params.vflags.hasOwnProperty('access_token')) {
fs.writeFileSync(createPath, generateAccessTokenDefinition());
} else {
fs.writeFileSync(createPath, generateModelDefinition(modelName));
}
console.log(colors.green.bold('Create: ') + createPath);
generateMigration.run({
args: [`create_${schemaObject.table}`],
flags: [],
vflags: {for: params.args}
}, (err, result) => {
if (err) {
return callback(err);
}
if (params.vflags.hasOwnProperty('user')) {
console.log('Installing additional packages in this directory...');
console.log('');
let spawn = require('cross-spawn-async');
let child = spawn('npm', ['install', 'bcryptjs', '--save'], {cwd: process.cwd(), stdio: 'inherit'});
child.on('exit', function() {
child && child.kill();
callback(null);
});
return;
}
callback(null);
});
}
}
module.exports = GenerateModelCommand;