PersistenceJS:使用migrate()更新现有数据库

rob*_*bro 2 javascript html5 persistence

我目前正在尝试使用PersistenceJS的迁移插件对现有数据库进行更改.我可以添加/编辑/删除数据库中的项目 - 但是......

  • 如何将列添加到现有(!)表?
  • 如何更改现有(!)列的类型,例如从"text"更改为"integer"?

  • These changes should retain currently existing data.

可悲的是,文档有点稀缺,也许你可以帮忙吗?

这是当前的工作设置:

persistence.store.websql.config(persistence, 'tododatabase', 'todos are fun', 5*1024*1024);

var Todo = persistence.define('Todo', {
    task: 'TEXT',
    priority: 'INT',
    done: 'BOOL'
});

persistence.schemaSync();

function addTodo( item ){
    var todo = new Todo();
    todo.task = item.task;
    todo.priority = item.priority;
    todo.done = item.done;

    persistence.add(todo);
    persistence.flush();
};

function deleteTodo( item, callback ){
    // item.id was created automatically by calling "new Todo()"
    Todo.all().filter('id','=', item.id ).destroyAll( function(){
        persistence.flush( callback );
    });
};
Run Code Online (Sandbox Code Playgroud)

有点工作的迁移代码:

persistence.defineMigration(1, {
    up: function() {
        this.createTable('Todo', function(t){
            t.text('task');
            t.integer('priority');
            t.boolean('done');
        });
    },
    down: function() {
        this.dropTable('Todo');
    }
});

persistence.defineMigration(2, {
    up: function() {
        this.addColumn('Todo', 'due', 'DATE');
    },
    down: function() {
        this.removeColumn('Todo', 'due');
    }
});


function migrate( callback ){
    console.log('migrating...');
    persistence.migrations.init( function(){
        console.log('migration init');
        // this should migrate up to the latest version, in our case: 2
        persistence.migrate( function(){
            console.log('migration complete!');
        } );
    });
}
Run Code Online (Sandbox Code Playgroud)

结果...

  1. 调用migrate()只会注册到"migration init",永远不会调用完整的处理程序,不会创建"due"列
  2. 在调用migrate()之前不调用schemaSync(),因为Zef Hemel本人在这篇文章中提出的结果与1相同.
  3. 更改第一行persistence.store.websql.config(persistence, 'newdatabase', 'testing migration', 5*1024*1024);,而不是调用schemaSync(),只调用migrate()将成功记录"迁移完成!" - 但它在一个新的,完全空的数据库"newdatabase"中这样做,当然不会保留任何现有数据.

摘要

还有为利用创建的数据库persistence.store.websql.config(...),persistence.define('Todo',...)persistence.schemaSync().

我现在想要保留该数据库中已存在的所有数据,但希望如此

  • 将列的类型priority从"整数"更改为"文本"
  • due向所有现有Todos 添加类型为"date" 的列

如果你能把我推向正确的方向,我将非常感激!

谢谢!

rob*_*bro 5

我终于搞定了.我的初始要求存在许多问题,我想指出以供将来参考.看一下第一个迁移定义:

persistence.defineMigration(1, {
    up: function() {
        this.createTable('Todo', function(t){
        ...
Run Code Online (Sandbox Code Playgroud)


毫不奇怪,它createTable会做到这一点:它将执行SQL语句'CREATE TABLE Todo ...',如果有一个Todo已经有名称的表,它将默默地失败并停止迁移.这就是为什么它适用于新数据库,而不是现有数据库.请记住:我已经拥有一个带有"Todo"表的实时数据库,需要更新.如果你刚刚开始新鲜(即你没有使用过schemaSync),那就行createTable得很好.由于迁移插件不提供createTableIfNotExists方法,我需要使用executeSql如下:

persistence.defineMigration(1, {
    up: function() {
        this.executeSql('CREATE TABLE IF NOT EXISTS Todo (id VARCHAR(32) PRIMARY KEY, task TEXT, priority INT, done BOOL)');
        ...
Run Code Online (Sandbox Code Playgroud)


既然从模式版本0到1的迁移成功,那么迁移到版本2也是成功的.

迁移到版本3时,priority需要将列的类型更改inttext.这通常是使用ALTER COLUMNSQL命令完成的,Web SQL/SQLite不支持.请参阅SQLite的省略功能.

使用SQLite更改列需要一个4步骤的解决方法:

persistence.defineMigration(3, {
    up: function() {
        // rename current table
        this.executeSql('ALTER TABLE Todo RENAME TO OldTodo');
        // create new table with required columns and column types
        this.executeSql('CREATE TABLE Todo (id VARCHAR(32) PRIMARY KEY, task TEXT, priority TEXT, done BOOL)');
        // copy contents from old table to new table
        this.executeSql('INSERT INTO Todo(id, task, priority, done) SELECT id, task, priority, done FROM OldTodo');
        // delete old table
        this.executeSql('DROP TABLE OldTodo');
    },
    ...
Run Code Online (Sandbox Code Playgroud)


当然,在更改列类型后,还应更改"Todo"的实体定义:

var Todo = persistence.define('Todo', {
    task: 'TEXT',
    priority: 'TEXT', // was 'INT'
    due: 'DATE',
    done: 'BOOL'
});
Run Code Online (Sandbox Code Playgroud)


最后,完整的来源:

persistence.store.websql.config(persistence, 'tododatabase', 'todos are fun', 5*1024*1024);

// persistence.debug = true;

//v0 + v1
// var Todo = persistence.define('Todo', {
//  task: 'TEXT',
//  priority: 'INT',
//  done: 'BOOL'
// });

//v2
// var Todo = persistence.define('Todo', {
//  task: 'TEXT',
//  priority: 'INT',
//  due: 'DATE',
//  done: 'BOOL'
// });

//v3
var Todo = persistence.define('Todo', {
    task: 'TEXT',
    priority: 'TEXT',
    due: 'DATE',
    done: 'BOOL'
});


persistence.defineMigration(1, {
    up: function() {
        this.executeSql('CREATE TABLE IF NOT EXISTS Todo (id VARCHAR(32) PRIMARY KEY, task TEXT, priority INT, done BOOL)');
    },
    down: function() {
        this.dropTable('Todo');
    }
});

persistence.defineMigration(2, {
    up: function() {
        this.addColumn('Todo', 'due', 'DATE');
    },
    down: function() {
        this.removeColumn('Todo', 'due');
    }
});

persistence.defineMigration(3, {
    up: function() {
        // rename current table
        this.executeSql('ALTER TABLE Todo RENAME TO OldTodo');
        // create new table with required columns
        this.executeSql('CREATE TABLE Todo (id VARCHAR(32) PRIMARY KEY, task TEXT, priority TEXT, due DATE, done BOOL)');
        // copy contents from old table to new table
        this.executeSql('INSERT INTO Todo(id, task, priority, due, done) SELECT id, task, priority, due, done FROM OldTodo');
        // delete current table
        this.executeSql('DROP TABLE OldTodo');
    },
    down: function() {
        this.executeSql('ALTER TABLE Todo RENAME TO OldTodo');
        this.executeSql('CREATE TABLE Todo (id VARCHAR(32) PRIMARY KEY, task TEXT, priority INT, due DATE, done BOOL)');
        this.executeSql('INSERT INTO Todo(id, task, priority, due, done) SELECT id, task, priority, due, done FROM OldTodo');
        this.executeSql('DROP TABLE OldTodo');
    }
});


function migrate( callback ){
    console.log('migrating...');
    persistence.migrations.init( function(){
        console.log('migration init');
        persistence.migrate( function(){
            console.debug('migration complete!');
            callback();
        } );
    });
};

migrate( onMigrationComplete );

function onMigrationComplete(){
    // database is ready. do amazing things...
};
Run Code Online (Sandbox Code Playgroud)