support for data migrations
This commit is contained in:
parent
49fa4884ef
commit
17e5946af4
|
@ -243,11 +243,12 @@ inline typename T::Function Realm<T>::create_constructor(ContextType ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
void Realm<T>::constructor(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[]) {
|
void Realm<T>::constructor(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[]) {
|
||||||
static const String path_string = "path";
|
static const String path_string = "path";
|
||||||
static const String schema_string = "schema";
|
static const String schema_string = "schema";
|
||||||
static const String schema_version_string = "schemaVersion";
|
static const String schema_version_string = "schemaVersion";
|
||||||
static const String encryption_key_string = "encryptionKey";
|
static const String encryption_key_string = "encryptionKey";
|
||||||
|
static const String migration_string = "migration";
|
||||||
|
|
||||||
realm::Realm::Config config;
|
realm::Realm::Config config;
|
||||||
typename Schema<T>::ObjectDefaultsMap defaults;
|
typename Schema<T>::ObjectDefaultsMap defaults;
|
||||||
|
@ -286,6 +287,18 @@ void Realm<T>::constructor(ContextType ctx, ObjectType this_object, size_t argc,
|
||||||
config.schema_version = 0;
|
config.schema_version = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ValueType migration_value = Object::get_property(ctx, object, migration_string);
|
||||||
|
if (!Value::is_undefined(ctx, migration_value)) {
|
||||||
|
FunctionType migration_function = Value::validated_to_function(ctx, migration_value);
|
||||||
|
config.migration_function = [=](SharedRealm old_realm, SharedRealm realm) {
|
||||||
|
ValueType arguments[2] = {
|
||||||
|
create_object<T, RealmClass<T>>(ctx, new SharedRealm(old_realm)),
|
||||||
|
create_object<T, RealmClass<T>>(ctx, new SharedRealm(realm))
|
||||||
|
};
|
||||||
|
Function<T>::call(ctx, migration_function, nullptr, 2, arguments);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
ValueType encryption_key_value = Object::get_property(ctx, object, encryption_key_string);
|
ValueType encryption_key_value = Object::get_property(ctx, object, encryption_key_string);
|
||||||
if (!Value::is_undefined(ctx, encryption_key_value)) {
|
if (!Value::is_undefined(ctx, encryption_key_value)) {
|
||||||
std::string encryption_key = NativeAccessor::to_binary(ctx, encryption_key_value);
|
std::string encryption_key = NativeAccessor::to_binary(ctx, encryption_key_value);
|
||||||
|
|
|
@ -80,7 +80,7 @@ typename T::Object RealmObject<T>::create_instance(ContextType ctx, realm::Objec
|
||||||
auto name = realm_object.get_object_schema().name;
|
auto name = realm_object.get_object_schema().name;
|
||||||
auto object = create_object<T, RealmObjectClass<T>>(ctx, new realm::Object(realm_object));
|
auto object = create_object<T, RealmObjectClass<T>>(ctx, new realm::Object(realm_object));
|
||||||
|
|
||||||
if (!delegate->m_constructors.count(name)) {
|
if (!delegate || !delegate->m_constructors.count(name)) {
|
||||||
return object;
|
return object;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,23 @@ module.exports = {
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
assertThrowsException: function(func, expectedException) {
|
||||||
|
var caught = false;
|
||||||
|
try {
|
||||||
|
func();
|
||||||
|
}
|
||||||
|
catch (e) {
|
||||||
|
caught = true;
|
||||||
|
if (e != expectedException) {
|
||||||
|
throw new TestFailureError('Expected exception "' + expectedException + '" not thrown - instead caught: "' + e + '"');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!caught) {
|
||||||
|
throw new TestFailureError('Expected exception not thrown');
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
assertTrue: function(condition, errorMessage) {
|
assertTrue: function(condition, errorMessage) {
|
||||||
if (!condition) {
|
if (!condition) {
|
||||||
throw new TestFailureError(errorMessage || 'Condition expected to be true');
|
throw new TestFailureError(errorMessage || 'Condition expected to be true');
|
||||||
|
|
|
@ -25,6 +25,7 @@ var TESTS = {
|
||||||
ResultsTests: require('./results-tests'),
|
ResultsTests: require('./results-tests'),
|
||||||
QueryTests: require('./query-tests'),
|
QueryTests: require('./query-tests'),
|
||||||
EncryptionTests: require('./encryption-tests'),
|
EncryptionTests: require('./encryption-tests'),
|
||||||
|
MigrationTests: require('./migration-tests'),
|
||||||
};
|
};
|
||||||
|
|
||||||
var SPECIAL_METHODS = {
|
var SPECIAL_METHODS = {
|
||||||
|
|
|
@ -0,0 +1,118 @@
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// Copyright 2016 Realm Inc.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
|
'use strict';
|
||||||
|
|
||||||
|
var Realm = require('realm');
|
||||||
|
var BaseTest = require('./base-test');
|
||||||
|
var TestCase = require('./asserts');
|
||||||
|
var Schemas = require('./schemas');
|
||||||
|
|
||||||
|
module.exports = BaseTest.extend({
|
||||||
|
testMigrationFunction: function() {
|
||||||
|
var count = 0;
|
||||||
|
function migrationFunction(oldRealm, newRealm) {
|
||||||
|
TestCase.assertEqual(oldRealm.schemaVersion, 0);
|
||||||
|
TestCase.assertEqual(newRealm.schemaVersion, 1);
|
||||||
|
count++;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no migration should be run
|
||||||
|
var realm = new Realm({schema: [], migration: migrationFunction});
|
||||||
|
TestCase.assertEqual(0, count);
|
||||||
|
realm.close();
|
||||||
|
|
||||||
|
// migration should be run
|
||||||
|
realm = new Realm({schema: [Schemas.TestObject], migration: migrationFunction, schemaVersion: 1});
|
||||||
|
TestCase.assertEqual(1, count);
|
||||||
|
realm.close();
|
||||||
|
|
||||||
|
// invalid migration function
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
new Realm({schema: [], schemaVersion: 2, migration: 'invalid'});
|
||||||
|
});
|
||||||
|
|
||||||
|
// migration function exceptions should propogate
|
||||||
|
var exception = 'expected exception';
|
||||||
|
realm = undefined;
|
||||||
|
TestCase.assertThrowsException(function() {
|
||||||
|
realm = new Realm({schema: [], schemaVersion: 3, migration: function() {
|
||||||
|
throw exception;
|
||||||
|
}});
|
||||||
|
}, exception);
|
||||||
|
TestCase.assertEqual(realm, undefined);
|
||||||
|
TestCase.assertEqual(Realm.schemaVersion(Realm.defaultPath), 1);
|
||||||
|
|
||||||
|
// migration function shouldn't run if nothing changes
|
||||||
|
realm = new Realm({schema: [Schemas.TestObject], migration: migrationFunction, schemaVersion: 1});
|
||||||
|
TestCase.assertEqual(1, count);
|
||||||
|
realm.close();
|
||||||
|
|
||||||
|
// migration function should run if only schemaVersion changes
|
||||||
|
realm = new Realm({schema: [Schemas.TestObject], migration: function() { count++; }, schemaVersion: 2});
|
||||||
|
TestCase.assertEqual(2, count);
|
||||||
|
realm.close();
|
||||||
|
},
|
||||||
|
|
||||||
|
testDataMigration: function() {
|
||||||
|
var realm = new Realm({schema: [{
|
||||||
|
name: 'TestObject',
|
||||||
|
properties: {
|
||||||
|
prop0: 'string',
|
||||||
|
prop1: 'int',
|
||||||
|
}
|
||||||
|
}]});
|
||||||
|
realm.write(function() {
|
||||||
|
realm.create('TestObject', ['stringValue', 1]);
|
||||||
|
});
|
||||||
|
realm.close();
|
||||||
|
|
||||||
|
var realm = new Realm({
|
||||||
|
schema: [{
|
||||||
|
name: 'TestObject',
|
||||||
|
properties: {
|
||||||
|
renamed: 'string',
|
||||||
|
prop1: 'int',
|
||||||
|
}
|
||||||
|
}],
|
||||||
|
schemaVersion: 1,
|
||||||
|
migration: function(oldRealm, newRealm) {
|
||||||
|
var oldObjects = oldRealm.objects('TestObject');
|
||||||
|
var newObjects = newRealm.objects('TestObject');
|
||||||
|
TestCase.assertEqual(oldObjects.length, 1);
|
||||||
|
TestCase.assertEqual(newObjects.length, 1);
|
||||||
|
|
||||||
|
TestCase.assertEqual(oldObjects[0].prop0, 'stringValue');
|
||||||
|
TestCase.assertEqual(oldObjects[0].prop1, 1);
|
||||||
|
//TestCase.assertThrows(function() { oldObjects[0].renamed; });
|
||||||
|
|
||||||
|
//TestCase.assertThrows(function() { newObjects[0].prop0; });
|
||||||
|
TestCase.assertEqual(newObjects[0].renamed, '');
|
||||||
|
TestCase.assertEqual(newObjects[0].prop1, 1);
|
||||||
|
|
||||||
|
newObjects[0].renamed = oldObjects[0].prop0;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
var objects = realm.objects('TestObject');
|
||||||
|
TestCase.assertEqual(objects.length, 1);
|
||||||
|
TestCase.assertEqual(objects[0].renamed, 'stringValue');
|
||||||
|
TestCase.assertEqual(objects[0].prop1, 1);
|
||||||
|
TestCase.assertThrows(function() { newObjects[0].prop0; });
|
||||||
|
},
|
||||||
|
});
|
Loading…
Reference in New Issue