From 0c4ccc284b833e4c00999d95b410076f50c8e3a9 Mon Sep 17 00:00:00 2001 From: Jacob Gable Date: Sat, 15 Jun 2013 20:52:03 +0000 Subject: [PATCH] Data import and export --- core/shared/api.js | 1 - core/shared/data/export/001.js | 49 ++++++++++++++++++ core/shared/data/export/index.js | 21 ++++++++ core/shared/data/fixtures/001.js | 8 +++ core/shared/data/import/001.js | 58 ++++++++++++++++++++++ core/shared/data/import/index.js | 21 ++++++++ core/test/ghost/export_spec.js | 67 +++++++++++++++++++++++++ core/test/ghost/helpers.js | 7 ++- core/test/ghost/import_spec.js | 85 ++++++++++++++++++++++++++++++++ 9 files changed, 315 insertions(+), 2 deletions(-) create mode 100644 core/shared/data/export/001.js create mode 100644 core/shared/data/export/index.js create mode 100644 core/shared/data/import/001.js create mode 100644 core/shared/data/import/index.js create mode 100644 core/test/ghost/export_spec.js create mode 100644 core/test/ghost/import_spec.js diff --git a/core/shared/api.js b/core/shared/api.js index 305f0cf709..0e0a3f407c 100644 --- a/core/shared/api.js +++ b/core/shared/api.js @@ -114,7 +114,6 @@ }; }; - module.exports.posts = posts; module.exports.users = users; module.exports.settings = settings; diff --git a/core/shared/data/export/001.js b/core/shared/data/export/001.js new file mode 100644 index 0000000000..ffa0f9263b --- /dev/null +++ b/core/shared/data/export/001.js @@ -0,0 +1,49 @@ +(function () { + "use strict"; + + var _ = require("underscore"), + when = require("when"), + knex = require('../../models/base').Knex, + Exporter001; + + Exporter001 = function () { + this.version = "001"; + }; + + Exporter001.prototype.exportData = function () { + var self = this, + tables = ['posts', 'users', 'roles', 'roles_users', 'permissions', 'permissions_roles', 'settings'], + selectOps = _.map(tables, function (name) { + return knex(name).select(); + }); + + return when.all(selectOps).then(function (tableData) { + var exportData = { + meta: { + exported_on: new Date().getTime(), + version: self.version + }, + data: { + // Filled below + } + }; + + _.each(tables, function (name, i) { + exportData.data[name] = tableData[i]; + }); + + return when.resolve(exportData); + }, function (err) { + console.log("Error exporting data: " + err); + }); + }; + + module.exports = { + // Make available for unit tests + Exporter001: Exporter001, + + exportData: function () { + return new Exporter001().exportData(); + } + }; +}()); \ No newline at end of file diff --git a/core/shared/data/export/index.js b/core/shared/data/export/index.js new file mode 100644 index 0000000000..acc03a8fe5 --- /dev/null +++ b/core/shared/data/export/index.js @@ -0,0 +1,21 @@ +(function () { + "use strict"; + + var when = require('when'); + + module.exports = function (version) { + var exporter; + + try { + exporter = require("./" + version); + } catch (ignore) { + // Zero effs given + } + + if (!exporter) { + return when.reject("No exporter found"); + } + + return exporter.exportData(); + }; +}()); \ No newline at end of file diff --git a/core/shared/data/fixtures/001.js b/core/shared/data/fixtures/001.js index 106d602fd9..7070c00c3b 100644 --- a/core/shared/data/fixtures/001.js +++ b/core/shared/data/fixtures/001.js @@ -92,6 +92,14 @@ module.exports = { "created_by": 1, "updated_by": 1, "type": "general" + }, + { + "uuid": uuid.v4(), + "key": "currentVersion", + "value": "001", + "created_by": 1, + "updated_by": 1, + "type": "general" } ], diff --git a/core/shared/data/import/001.js b/core/shared/data/import/001.js new file mode 100644 index 0000000000..72662537a9 --- /dev/null +++ b/core/shared/data/import/001.js @@ -0,0 +1,58 @@ +(function () { + "use strict"; + + var when = require("when"), + _ = require("underscore"), + knex = require('../../models/base').Knex, + Importer001; + + Importer001 = function () { + _.bindAll(this, "importFrom001"); + + this.version = "001"; + + this.importFrom = { + "001": this.importFrom001 + }; + }; + + Importer001.prototype.importData = function (data) { + return this.canImport(data) + .then(function (importerFunc) { + return importerFunc(data); + }, function (reason) { + return when.reject(reason); + }); + }; + + Importer001.prototype.canImport = function (data) { + if (data.meta && data.meta.version && this.importFrom[data.meta.version]) { + return when.resolve(this.importFrom[data.meta.version]); + } + + return when.reject("Unsupported version of data"); + }; + + Importer001.prototype.importFrom001 = function (data) { + var insertOps = []; + + _.each(data.data, function (tableData, name) { + if (tableData && tableData.length) { + insertOps.push(knex(name).insert(tableData)); + } + }); + + return when.all(insertOps).then(function (results) { + return when.resolve(results); + }, function (err) { + console.log("Error inserting imported data: ", err.message || err, err.stack); + }); + }; + + module.exports = { + Importer001: Importer001, + importData: function (data) { + new Importer001().importData(data); + } + }; +}()); \ No newline at end of file diff --git a/core/shared/data/import/index.js b/core/shared/data/import/index.js new file mode 100644 index 0000000000..93a1090f23 --- /dev/null +++ b/core/shared/data/import/index.js @@ -0,0 +1,21 @@ +(function () { + "use strict"; + + var when = require('when'); + + module.exports = function (version, data) { + var importer; + + try { + importer = require("./" + version); + } catch (ignore) { + // Zero effs given + } + + if (!importer) { + return when.reject("No importer found"); + } + + return importer.importData(data); + }; +}()); \ No newline at end of file diff --git a/core/test/ghost/export_spec.js b/core/test/ghost/export_spec.js new file mode 100644 index 0000000000..0d747e166b --- /dev/null +++ b/core/test/ghost/export_spec.js @@ -0,0 +1,67 @@ +/*globals describe, beforeEach, it*/ + +(function () { + "use strict"; + + var _ = require("underscore"), + should = require('should'), + when = require('when'), + sinon = require('sinon'), + helpers = require('./helpers'), + exporter = require('../../shared/data/export'), + Exporter001 = require('../../shared/data/export/001'), + errors = require('../../shared/errorHandling'); + + describe("Export", function () { + + should.exist(exporter); + + beforeEach(function (done) { + helpers.resetData().then(function () { + done(); + }, done); + }); + + it("resolves 001", function (done) { + var exportStub = sinon.stub(Exporter001, "exportData", function () { + return when.resolve(); + }); + + exporter("001").then(function () { + exportStub.called.should.equal(true); + + exportStub.restore(); + + done(); + }, errors.throwError); + }); + + describe("001", function () { + + should.exist(Exporter001); + + it("exports data", function (done) { + exporter("001").then(function (exportData) { + var tables = ['posts', 'users', 'roles', 'roles_users', 'permissions', 'permissions_roles', 'settings']; + + should.exist(exportData); + + should.exist(exportData.meta); + should.exist(exportData.data); + + exportData.meta.version.should.equal("001"); + + _.each(tables, function (name) { + should.exist(exportData.data[name]); + }); + + done(); + }, function () { + console.log("Error in exporter"); + }); + }); + }); + + }); + +}()); \ No newline at end of file diff --git a/core/test/ghost/helpers.js b/core/test/ghost/helpers.js index 9744cbb89f..42e7027a4a 100644 --- a/core/test/ghost/helpers.js +++ b/core/test/ghost/helpers.js @@ -47,10 +47,15 @@ helpers = { resetData: function () { - return migrations.one.down().then(function () { + return this.clearData().then(function () { return migrations.one.up(); }); }, + + clearData: function () { + return migrations.one.down(); + }, + insertMorePosts: function () { var lang, status, posts, promises = [], i, j; for (i = 0; i < 2; i += 1) { diff --git a/core/test/ghost/import_spec.js b/core/test/ghost/import_spec.js new file mode 100644 index 0000000000..61441ef369 --- /dev/null +++ b/core/test/ghost/import_spec.js @@ -0,0 +1,85 @@ +/*globals describe, beforeEach, it*/ + +(function () { + "use strict"; + + var _ = require("underscore"), + should = require('should'), + when = require('when'), + sinon = require('sinon'), + knex = require("../../shared/models/base").Knex, + helpers = require('./helpers'), + exporter = require('../../shared/data/export'), + importer = require('../../shared/data/import'), + Importer001 = require('../../shared/data/import/001'), + errors = require('../../shared/errorHandling'); + + describe("Import", function () { + + should.exist(exporter); + + beforeEach(function (done) { + helpers.resetData().then(function () { + done(); + }, done); + }); + + it("resolves 001", function (done) { + var importStub = sinon.stub(Importer001, "importData", function () { + return when.resolve(); + }), + fakeData = { test: true }; + + importer("001", fakeData).then(function () { + importStub.calledWith(fakeData).should.equal(true); + + importStub.restore(); + + done(); + }, errors.throwError); + }); + + describe("001", function () { + this.timeout(4000); + + should.exist(Importer001); + + it("imports data from 001", function (done) { + var exportData; + // TODO: Should have static test data here? + exporter("001").then(function (exported) { + exportData = exported; + + // Clear the data from all tables. + var tables = ['posts', 'users', 'roles', 'roles_users', 'permissions', 'permissions_roles', 'settings'], + truncateOps = _.map(tables, function (name) { + return knex(name).truncate(); + }); + + return when.all(truncateOps); + }).then(function () { + return importer("001", exportData); + }).then(function (importResult) { + // Grab the data from tables + return when.all([ + knex("users").select(), + knex("posts").select(), + knex("settings").select() + ]); + }).then(function (importedData) { + + should.exist(importedData); + importedData.length.should.equal(3); + + importedData[0].length.should.equal(exportData.data.users.length); + importedData[1].length.should.equal(exportData.data.posts.length); + importedData[2].length.should.equal(exportData.data.settings.length); + + done(); + }); + }); + }); + + }); + +}()); \ No newline at end of file