mirror of
https://github.com/TryGhost/Ghost.git
synced 2025-01-13 22:41:32 -05:00
cddd23f926
This frees us up to enforce one single point of access, thus paving the way towards allowing us to initialize the models at are request, and not when it's require(). addresses #2170
248 lines
No EOL
8.5 KiB
JavaScript
248 lines
No EOL
8.5 KiB
JavaScript
var _ = require('lodash'),
|
|
when = require('when'),
|
|
path = require('path'),
|
|
fs = require('fs'),
|
|
nodefn = require('when/node'),
|
|
errors = require('../../errors'),
|
|
sequence = require('when/sequence'),
|
|
|
|
versioning = require('../versioning'),
|
|
models = require('../../models'),
|
|
fixtures = require('../fixtures'),
|
|
schema = require('../schema').tables,
|
|
dataExport = require('../export'),
|
|
utils = require('../utils'),
|
|
config = require('../../config'),
|
|
|
|
schemaTables = _.keys(schema),
|
|
|
|
init,
|
|
reset,
|
|
migrateUp,
|
|
migrateUpFreshDb;
|
|
|
|
function getDeleteCommands(oldTables, newTables) {
|
|
var deleteTables = _.difference(oldTables, newTables);
|
|
if (!_.isEmpty(deleteTables)) {
|
|
return _.map(deleteTables, function (table) {
|
|
return function () {
|
|
return utils.deleteTable(table);
|
|
};
|
|
});
|
|
}
|
|
}
|
|
|
|
function getAddCommands(oldTables, newTables) {
|
|
var addTables = _.difference(newTables, oldTables);
|
|
if (!_.isEmpty(addTables)) {
|
|
return _.map(addTables, function (table) {
|
|
return function () {
|
|
return utils.createTable(table);
|
|
};
|
|
});
|
|
}
|
|
}
|
|
|
|
function addColumnCommands(table, columns) {
|
|
var columnKeys = _.keys(schema[table]),
|
|
addColumns = _.difference(columnKeys, columns);
|
|
|
|
return _.map(addColumns, function (column) {
|
|
return function () {
|
|
utils.addColumn(table, column);
|
|
};
|
|
});
|
|
}
|
|
|
|
function modifyUniqueCommands(table, indexes) {
|
|
var columnKeys = _.keys(schema[table]);
|
|
return _.map(columnKeys, function (column) {
|
|
if (schema[table][column].unique && schema[table][column].unique === true) {
|
|
if (!_.contains(indexes, table + '_' + column + '_unique')) {
|
|
return function () {
|
|
return utils.addUnique(table, column);
|
|
};
|
|
}
|
|
} else if (!schema[table][column].unique) {
|
|
if (_.contains(indexes, table + '_' + column + '_unique')) {
|
|
return function () {
|
|
return utils.dropUnique(table, column);
|
|
};
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Check for whether data is needed to be bootstrapped or not
|
|
init = function () {
|
|
var self = this;
|
|
// There are 4 possibilities:
|
|
// 1. The database exists and is up-to-date
|
|
// 2. The database exists but is out of date
|
|
// 3. The database exists but the currentVersion setting does not or cannot be understood
|
|
// 4. The database has not yet been created
|
|
return versioning.getDatabaseVersion().then(function (databaseVersion) {
|
|
var defaultVersion = versioning.getDefaultDatabaseVersion();
|
|
if (databaseVersion === defaultVersion) {
|
|
// 1. The database exists and is up-to-date
|
|
return when.resolve();
|
|
}
|
|
if (databaseVersion < defaultVersion) {
|
|
// 2. The database exists but is out of date
|
|
// Migrate to latest version
|
|
return self.migrateUp().then(function () {
|
|
// Finally update the databases current version
|
|
return versioning.setDatabaseVersion();
|
|
});
|
|
}
|
|
if (databaseVersion > defaultVersion) {
|
|
// 3. The database exists but the currentVersion setting does not or cannot be understood
|
|
// In this case we don't understand the version because it is too high
|
|
errors.logErrorAndExit(
|
|
'Your database is not compatible with this version of Ghost',
|
|
'You will need to create a new database'
|
|
);
|
|
}
|
|
}, function (err) {
|
|
if (err.message || err === 'Settings table does not exist') {
|
|
// 4. The database has not yet been created
|
|
// Bring everything up from initial version.
|
|
return self.migrateUpFreshDb();
|
|
}
|
|
// 3. The database exists but the currentVersion setting does not or cannot be understood
|
|
// In this case the setting was missing or there was some other problem
|
|
errors.logErrorAndExit('There is a problem with the database', err.message || err);
|
|
});
|
|
};
|
|
|
|
// ### Reset
|
|
// Delete all tables from the database in reverse order
|
|
reset = function () {
|
|
var tables = [];
|
|
tables = _.map(schemaTables, function (table) {
|
|
return function () {
|
|
return utils.deleteTable(table);
|
|
};
|
|
}).reverse();
|
|
|
|
return sequence(tables);
|
|
};
|
|
|
|
// Only do this if we have no database at all
|
|
migrateUpFreshDb = function () {
|
|
var tables = [];
|
|
tables = _.map(schemaTables, function (table) {
|
|
return function () {
|
|
return utils.createTable(table);
|
|
};
|
|
});
|
|
|
|
return sequence(tables).then(function () {
|
|
// Load the fixtures
|
|
return fixtures.populateFixtures().then(function () {
|
|
// Initialise the default settings
|
|
return models.Settings.populateDefaults();
|
|
});
|
|
});
|
|
};
|
|
|
|
// This function changes the type of posts.html and posts.markdown columns to mediumtext. Due to
|
|
// a wrong datatype in schema.js some installations using mysql could have been created using the
|
|
// data type text instead of mediumtext.
|
|
// For details see: https://github.com/TryGhost/Ghost/issues/1947
|
|
function checkMySQLPostTable() {
|
|
var knex = config().database.knex;
|
|
|
|
return knex.raw("SHOW FIELDS FROM posts where Field ='html' OR Field = 'markdown'").then(function (response) {
|
|
return _.flatten(_.map(response[0], function (entry) {
|
|
if (entry.Type.toLowerCase() !== 'mediumtext') {
|
|
return knex.raw("ALTER TABLE posts MODIFY " + entry.Field + " MEDIUMTEXT").then(function () {
|
|
return when.resolve();
|
|
});
|
|
}
|
|
}));
|
|
});
|
|
}
|
|
|
|
function backupDatabase() {
|
|
return dataExport().then(function (exportedData) {
|
|
// Save the exported data to the file system for download
|
|
var fileName = path.resolve(config().paths.contentPath + '/data/exported-' + (new Date().getTime()) + '.json');
|
|
|
|
return nodefn.call(fs.writeFile, fileName, JSON.stringify(exportedData));
|
|
});
|
|
}
|
|
|
|
// Migrate from a specific version to the latest
|
|
migrateUp = function () {
|
|
var deleteCommands,
|
|
addCommands,
|
|
oldTables,
|
|
client = config().database.client,
|
|
addColumns = [],
|
|
modifyUniCommands = [],
|
|
commands = [];
|
|
|
|
return backupDatabase().then(function () {
|
|
return utils.getTables().then(function (tables) {
|
|
oldTables = tables;
|
|
});
|
|
}).then(function () {
|
|
// if tables exist and client is mysqls check if posts table is okay
|
|
if (!_.isEmpty(oldTables) && client === 'mysql') {
|
|
return checkMySQLPostTable();
|
|
}
|
|
}).then(function () {
|
|
deleteCommands = getDeleteCommands(oldTables, schemaTables);
|
|
addCommands = getAddCommands(oldTables, schemaTables);
|
|
return when.all(
|
|
_.map(oldTables, function (table) {
|
|
return utils.getIndexes(table).then(function (indexes) {
|
|
modifyUniCommands = modifyUniCommands.concat(modifyUniqueCommands(table, indexes));
|
|
});
|
|
})
|
|
);
|
|
}).then(function () {
|
|
return when.all(
|
|
_.map(oldTables, function (table) {
|
|
return utils.getColumns(table).then(function (columns) {
|
|
addColumns = addColumns.concat(addColumnCommands(table, columns));
|
|
});
|
|
})
|
|
);
|
|
|
|
}).then(function () {
|
|
modifyUniCommands = _.compact(modifyUniCommands);
|
|
|
|
// delete tables
|
|
if (!_.isEmpty(deleteCommands)) {
|
|
commands = commands.concat(deleteCommands);
|
|
}
|
|
// add tables
|
|
if (!_.isEmpty(addCommands)) {
|
|
commands = commands.concat(addCommands);
|
|
}
|
|
// add columns if needed
|
|
if (!_.isEmpty(addColumns)) {
|
|
commands = commands.concat(addColumns);
|
|
}
|
|
// add/drop unique constraint
|
|
if (!_.isEmpty(modifyUniCommands)) {
|
|
commands = commands.concat(modifyUniCommands);
|
|
}
|
|
// execute the commands in sequence
|
|
if (!_.isEmpty(commands)) {
|
|
return sequence(commands);
|
|
}
|
|
return;
|
|
}).then(function () {
|
|
return fixtures.updateFixtures();
|
|
});
|
|
};
|
|
|
|
module.exports = {
|
|
init: init,
|
|
reset: reset,
|
|
migrateUp: migrateUp,
|
|
migrateUpFreshDb: migrateUpFreshDb
|
|
}; |