yekonga-server
Version:
Yekonga Server
552 lines (446 loc) • 15.7 kB
JavaScript
// @ts-nocheck
/*global Yekonga, serverLibrary */
const fs = serverLibrary.fs;
const path = serverLibrary.path;
const H = Yekonga.Helper;
var migrationDir = null;
var archivesDir = null;
function initiateMigration() {
if (!Yekonga.MigrationDB) {
migrationDir = path.join(serverLibrary.__dirname, 'migration');
archivesDir = path.join(serverLibrary.__dirname, 'archives');
if (!fs.existsSync(migrationDir)) {
fs.mkdirSync(migrationDir);
}
if (!fs.existsSync(archivesDir)) {
fs.mkdirSync(archivesDir);
}
Yekonga.MigrationDB = Yekonga.DBbuilder({
type: 'nedb',
tables: {
migrations: { path: path.join(serverLibrary.__dirname, 'archives/migrations.db') }
}
});
}
}
class Migration {
constructor(collection) {
this.collection = collection;
initiateMigration();
}
static async load() {
initiateMigration();
if (migrationDir) {
var files = fs.readdirSync(migrationDir);
var exists = await Yekonga.MigrationDB.table('migrations').lists('name');
for (const file of files) {
if (!exists.includes(file)) {
var result = null;
console.info(`Start migration`, `migrating file => ${file}`);
var response = (await require(path.join(migrationDir, file)));
if (typeof response == 'function') {
result = await response(file);
} else {
result = response;
}
if (typeof result == 'undefined') result = { data: { status: "SUCCESS" } };
if (!result || result.error) {
console.error(`End migration`, `Error on migrating file => ${file}`);
console.log(result);
break;
} else {
console.info(`End migration`, `Success on migrating file => ${file}`);
}
}
}
}
}
}
class MigrationBuilder {
constructor(collection, action) {
this.collection = collection;
this.action = action;
this.file = null;
this.fields = {};
this.tables = [];
}
renameTable(name) {
var table = new MigrationBuilderTable(this.collection);
table.renameTo(name);
this.tables.push(table);
return table;
}
emptyTable() {
var table = new MigrationBuilderTable(this.collection);
table.empty();
this.tables.push(table);
return table;
}
dropTable() {
var table = new MigrationBuilderTable(this.collection);
table.drop();
this.tables.push(table);
return table;
}
setField(name, type = null, autoincrement = false) {
var field = new MigrationBuilderField(name, type, autoincrement);
return field;
}
increments(value, primaryKey = false) {
var field = this.setField(value, 'int', true);
field.increments().length(11);
if (primaryKey) {
field.primaryKey();
}
this.fields[value] = field;
return this.fields[value];
}
bigIncrements(value, primaryKey = false) {
var field = this.setField(value, 'bigInt', true);
field.increments().length(24);
if (primaryKey) {
field.primaryKey();
}
this.fields[value] = field;
return this.fields[value];
}
string(value, length = 248) {
var field = this.setField(value, 'string');
field.length(length);
this.fields[value] = field;
return this.fields[value];
}
text(value) {
var field = this.setField(value, 'text');
field.nullable().default('NULL')
this.fields[value] = field;
return this.fields[value];
}
longText(value) {
var field = this.setField(value, 'longText');
this.fields[value] = field;
return this.fields[value];
}
float(value) {
var field = this.setField(value, 'float');
this.fields[value] = field;
return this.fields[value];
}
double(value) {
var field = this.setField(value, 'double');
this.fields[value] = field;
return this.fields[value];
}
decimal(value, length = '12,2') {
var field = this.setField(value, 'double');
field.length(length);
this.fields[value] = field;
return this.fields[value];
}
int(value, length = 11) {
var field = this.setField(value, 'int');
field.length(length);
this.fields[value] = field;
return this.fields[value];
}
bigInt(value) {
var field = this.setField(value, 'bigInt');
this.fields[value] = field;
return this.fields[value];
}
tinyInt(value, length = 1) {
var field = this.setField(value, 'tinyInt');
field.length(length);
this.fields[value] = field;
return this.fields[value];
}
boolean(value) {
var field = this.setField(value, 'boolean');
field.length(1);
this.fields[value] = field;
return this.fields[value];
}
timestamp(value) {
var field = this.setField(value, 'timestamp');
this.fields[value] = field;
return this.fields[value];
}
datetime(value) {
var field = this.setField(value, 'datetime');
this.fields[value] = field;
return this.fields[value];
}
year(value) {
var field = this.setField(value, 'year');
this.fields[value] = field;
return this.fields[value];
}
date(value) {
var field = this.setField(value, 'date');
this.fields[value] = field;
return this.fields[value];
}
time(value) {
var field = this.setField(value, 'time');
this.fields[value] = field;
return this.fields[value];
}
rename(arg1, arg2) {
var field = this.setField(arg1);
field.renameTo(arg2);
this.fields[arg1] = field;
return this.fields[arg1];
}
drop(value) {
var field = this.setField(value);
field.drop();
this.fields[value] = field;
return this.fields[value];
}
getType(field) {
var str = `VARCHAR(${field._length})`;
switch (field._type) {
case 'boolean':
str = 'BOOLEAN';
break;
case 'int':
str = `INT(${field._length})`;
break;
case 'bigInt':
str = `BIGINT(${field._length})`;
break;
case 'tinyInt':
str = `TINYINT(${field._length})`;
break;
case 'float':
str = `FLOAT`;
break;
case 'double':
str = `DOUBLE`;
break;
case 'decimal':
str = `DECIMAL(${field._length})`;
break;
case 'text':
str = 'TEXT';
break;
case 'longText':
str = 'LONGTEXT';
break;
case 'timestamp':
str = 'TIMESTAMP';
break;
case 'datetime':
str = 'DATETIME';
break;
case 'date':
str = 'DATE';
break;
case 'time':
str = 'TIME';
break;
case 'year':
str = 'YEAR';
break;
default:
break;
}
return str;
}
async run() {
var str = '';
if (H.tableActions.includes(this.action)) {
for (const table of this.tables) {
if (table._action == 'drop') {
str += `DROP TABLE \`${table._name}\`;`;
} else if (table._action == 'empty') {
str += `TRUNCATE \`${table._name}\`;`;
} else if (table._action == 'rename') {
str += `RENAME TABLE \`${table._name}\` TO \`${table._renameTo}\`;`;
}
}
} else {
if (this.action == 'create') {
str += `CREATE TABLE \`${this.collection}\` ( `;
} else {
str += `ALTER TABLE \`${this.collection}\` `;
}
var subStr = [];
for (const key in this.fields) {
if (this.fields.hasOwnProperty(key)) {
const field = this.fields[key];
if (this.action == 'create') {
var type = this.getType(field);
var nullable = (field._nullable) ? 'NULL' : 'NOT NULL';
var comment = (field._comment) ? `COMMENT '${field._comment}'` : ``;
var defaultValue = (typeof field._default != 'undefined') ? `${((field._default == 'AUTO_INCREMENT')? '':'DEFAULT')} ${((field._default == null)? 'NULL': field._default)}` : '';
subStr.push(`\`${field._name}\` ${type} ${nullable} ${defaultValue} ${comment}`);
if (field._primaryKey) {
subStr.push(`PRIMARY KEY (\`${field._name}\`)`);
}
if (field._unique && !field._primaryKey) {
subStr.push(`UNIQUE (\`${field._name}\`)`);
}
if (field._index && !field._primaryKey && !field._unique) {
subStr.push(`INDEX (\`${field._name}\`)`);
}
} else {
if (field._drop) {
subStr.push(`DROP \`${field._name}\``);
} else {
var action = (field._change) ? `CHANGE \`${field._name}\` \`${field._renameTo}\`` : `ADD \`${field._name}\``;
var type = this.getType(field);
var after = (field._after) ? `AFTER \`${field._after}\`` : '';
var first = (field._first) ? `${field._first}` : '';
var nullable = (field._nullable) ? 'NULL' : 'NOT NULL';
var comment = (field._comment) ? `COMMENT '${field._comment}'` : ``;
var defaultValue = (typeof field._default != 'undefined') ? `${((field._default == 'AUTO_INCREMENT')? '':'DEFAULT')} ${((field._default == null)? 'NULL': field._default)}` : '';
if (field._type.includes('text') && field._name != field._renameTo) {
subStr.push(`DROP INDEX \`${field._name}\``);
}
if (field._name != field._renameTo) {
subStr.push(`${action} ${type} ${nullable} ${defaultValue} ${comment} ${after} ${first}`);
} else {
subStr.push(`${action} ${type} ${nullable} ${defaultValue} ${comment} ${after} ${first}`);
}
if (field._primaryKey) {
subStr.push(`ADD PRIMARY KEY (\`${field._renameTo}\`)`);
}
if (field._unique && !field._primaryKey) {
subStr.push(`ADD UNIQUE (\`${field._renameTo}\`)`);
}
if (field._index && !field._primaryKey && !field._unique) {
subStr.push(`ADD INDEX (\`${field._renameTo}\`)`);
}
}
}
}
}
if (this.action == 'create') {
str += subStr.join(', ');
str += ` ) ENGINE = InnoDB;`;
} else {
for (const row of subStr) {
str += `${row.trim()}, `;
}
str = str.trim().substr(0, (str.length - 2)) + ';';
}
}
var result = await Yekonga.DB.query(str);
if (result.code && (result.code.includes('FIELD') || result.code.includes('ERROR'))) {
return {
error: result.code,
message: result.sqlMessage,
}
} else if (result.error) {
return result
} else if (result.errors) {
return { error: result.errors }
}
return { data: result }
}
}
class MigrationBuilderTable {
constructor(name) {
this._name = name;
this._renameTo = name;
this._action = null;
}
renameTo(value) {
this._renameTo = value;
this._action = 'rename';
return this;
}
empty() {
this._action = 'empty';
return this;
}
drop() {
this._action = 'drop';
return this;
}
}
class MigrationBuilderField {
constructor(name, type, autoincrement) {
this._name = name;
this._type = type;
this._autoincrement = autoincrement;
this._renameTo = name;
this._action = null;
this._default = undefined;
this._after = null;
this._first = null;
this._length = 248;
this._index = false;
this._unique = false;
this._primaryKey = false;
this._nullable = false;
this._change = false;
this._drop = false;
this._comment = null;
}
renameTo(value) {
this._renameTo = value;
this.change();
return this;
}
index() {
this._index = true;
return this;
}
unique() {
this._unique = true;
return this;
}
primaryKey() {
this._primaryKey = true;
return this;
}
length(value) {
this._length = value;
return this;
}
nullable() {
this._nullable = true;
return this;
}
default (value) {
this._default = value;
if (value == null) {
this.nullable();
}
return this;
}
after(value) {
this._after = value;
return this;
}
first(value) {
this._first = 'FIRST';
return this;
}
comment(value) {
this._comment = value;
return this;
}
increments() {
this._default = 'AUTO_INCREMENT';
return this;
}
current() {
this._default = 'CURRENT_TIMESTAMP';
return this;
}
change() {
this._change = true;
return this;
}
drop() {
this._drop = true;
return this;
}
}
module.exports = {
Migration,
MigrationBuilder
}