apply latest changes from master

This commit is contained in:
Ari Lazier 2016-05-16 15:37:40 -07:00
commit 5fc79d4e99
31 changed files with 219 additions and 99 deletions

1
.gitignore vendored
View File

@ -13,6 +13,7 @@
*.zip
*.realm
*.realm.lock
*.management/
# core
core

View File

@ -1,3 +1,22 @@
0.13.0 Release notes (2016-5-16)
=============================================================
### Breaking changes
* With this release we have switched over to a new cross platform compatible date format.
This change will only require action from users who are using both the JS and Cocoa or Android
bindings simultaneously and accessing Realm files from both bindings. In these cases you need to
open the Realm file with the latest version of the iOS or Android bindings before accessing the
Realm from JS to prevent an unnecessary conversion.
### Enhancements
* None
### Bugfixes
* Date properties are now stored in a format compatible with the Realm Browser and other bindings.
* Fix for using `class MyObject extends Realm.Object` in a React Native project.
* Fix a memory leak caused by constructing a Realm instance of an already opened Realm.
* Fix for better supporting hot module reloading.
* Fix for some warnings when using `ListView` with React Native 0.25+
0.12.0 Release notes (2016-5-4)
=============================================================
### Breaking changes

View File

@ -14,6 +14,6 @@
location = "group:examples/ReactExample/ios/ReactExample.xcodeproj">
</FileRef>
<FileRef
location = "group:examples/ReactExample/ios/../../../src/node/RealmNode.xcodeproj">
location = "group:src/node/RealmNode.xcodeproj">
</FileRef>
</Workspace>

View File

@ -20,20 +20,22 @@
import Realm from 'realm';
class Todo {}
class Todo extends Realm.Object {}
Todo.schema = {
name: 'Todo',
properties: {
done: {type: Realm.Types.BOOL, default: false},
text: Realm.Types.STRING,
done: {type: 'bool', default: false},
text: 'string',
},
};
class TodoList {}
class TodoList extends Realm.Object {}
TodoList.schema = {
name: 'TodoList',
properties: {
name: Realm.Types.STRING,
items: {type: Realm.Types.LIST, objectType: 'Todo', default: []},
name: 'string',
items: {type: 'list', objectType: 'Todo'},
},
};
export default new Realm({schema: [Todo, TodoList]});

View File

@ -18,10 +18,13 @@
'use strict';
import React, {
import React from 'react';
import {
Component,
Navigator,
StatusBarIOS,
Platform,
StatusBar,
Text,
TouchableOpacity,
View,
@ -60,8 +63,8 @@ export default class TodoApp extends Component {
}
componentWillMount() {
if (StatusBarIOS) {
StatusBarIOS.setStyle('light-content');
if (Platform.OS == 'ios') {
StatusBar.setBarStyle('light-content');
}
}

View File

@ -18,7 +18,9 @@
'use strict';
import React, {
import React from 'react';
import {
Text,
TouchableWithoutFeedback,
View,

View File

@ -18,7 +18,9 @@
'use strict';
import React, {
import React from 'react';
import {
Platform,
Text,
TextInput,

View File

@ -18,7 +18,9 @@
'use strict';
import React, {
import React from 'react';
import {
Text,
View,
} from 'react-native';

View File

@ -6,8 +6,8 @@
"start": "react-native start"
},
"dependencies": {
"react": "^0.14.5",
"react-native": "^0.24.1",
"react": "^0.14.8",
"react-native": "^0.25.1",
"realm": "file:../.."
}
}

View File

@ -17,8 +17,10 @@
////////////////////////////////////////////////////////////////////////////
'use strict';
import React, {
AppRegistry,
import React from 'react';
import {
Component,
StyleSheet,
Text,
@ -27,9 +29,9 @@ import React, {
TouchableHighlight
} from 'react-native';
const Store = require('react-native-store');
const SQLite = require('react-native-sqlite-storage');
const Realm = require('realm');
import Store from 'react-native-store';
import SQLite from 'react-native-sqlite-storage';
import Realm from 'realm';
// Make SQLite module use Promises.
SQLite.enablePromise(true);
@ -353,7 +355,7 @@ class RNSqliteTests extends Tests {
const apiTests = [new RealmTests, new RNSqliteTests, new RNStoreTests];
class ReactNativeBenchmarks extends Component {
export default class ReactNativeBenchmarks extends Component {
constructor(props) {
super(props);
@ -497,5 +499,3 @@ const styles = StyleSheet.create({
fontSize: 12
}
});
module.exports = ReactNativeBenchmarks;

View File

@ -1,8 +1,24 @@
////////////////////////////////////////////////////////////////////////////
//
// 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';
import React, {
AppRegistry
} from 'react-native';
const ReactNativeBenchmarks = require('./benchmarks');
import { AppRegistry } from 'react-native';
import ReactNativeBenchmarks from './benchmarks';
AppRegistry.registerComponent('ReactNativeBenchmarks', () => ReactNativeBenchmarks);
AppRegistry.registerComponent('ReactNativeBenchmarks', () => ReactNativeBenchmarks);

View File

@ -1,8 +1,24 @@
'use strict';
import React, {
AppRegistry
} from 'react-native';
////////////////////////////////////////////////////////////////////////////
//
// 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.
//
////////////////////////////////////////////////////////////////////////////
const ReactNativeBenchmarks = require('./benchmarks');
'use strict';
import { AppRegistry } from 'react-native';
import ReactNativeBenchmarks from './benchmarks';
AppRegistry.registerComponent('ReactNativeBenchmarks', () => ReactNativeBenchmarks);

View File

@ -6,8 +6,8 @@
"start": "react-native start"
},
"dependencies": {
"react": "^0.14.5",
"react-native": "^0.24.1",
"react": "^0.14.8",
"react-native": "^0.25.1",
"react-native-sqlite-storage": "^2.1.3",
"react-native-store": "^0.4.1",
"realm": "file:../.."

View File

@ -1,7 +1,7 @@
{
"name": "realm",
"description": "Realm is a mobile database: an alternative to SQLite and key-value stores",
"version": "0.12.0",
"version": "0.13.0-rc",
"license": "Apache-2.0",
"homepage": "https://realm.io",
"keywords": [

View File

@ -18,4 +18,6 @@
'use strict';
exports.ListView = require('./listview');
import ListView from './listview';
export { ListView };

View File

@ -18,7 +18,8 @@
'use strict';
const React = require('react-native');
import React from 'react';
import { ListView as BaseListView } from 'react-native';
function hashObjects(array) {
let hash = Object.create(null);
@ -28,7 +29,7 @@ function hashObjects(array) {
return hash;
}
class ListViewDataSource extends React.ListView.DataSource {
class ListViewDataSource extends BaseListView.DataSource {
cloneWithRowsAndSections(inputData, sectionIds, rowIds) {
let data = {};
@ -160,7 +161,7 @@ class ListViewDataSource extends React.ListView.DataSource {
}
}
class ListView extends React.Component {
export default class ListView extends React.Component {
constructor(props) {
super(props);
@ -169,7 +170,7 @@ class ListView extends React.Component {
render() {
return (
<React.ListView {...this.props} ref="listView" renderRow={this.renderRow} />
<BaseListView {...this.props} ref="listView" renderRow={this.renderRow} />
);
}
@ -200,5 +201,3 @@ ListView.propTypes = {
};
ListView.DataSource = ListViewDataSource;
module.exports = ListView;

View File

@ -811,7 +811,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.12.0;
CURRENT_PROJECT_VERSION = 0.13.0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
ENABLE_TESTABILITY = YES;
@ -872,7 +872,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.12.0;
CURRENT_PROJECT_VERSION = 0.13.0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_NS_ASSERTIONS = NO;
ENABLE_STRICT_OBJC_MSGSEND = YES;
@ -966,7 +966,7 @@
CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
"CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
COPY_PHASE_STRIP = NO;
CURRENT_PROJECT_VERSION = 0.12.0;
CURRENT_PROJECT_VERSION = 0.13.0;
DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
ENABLE_STRICT_OBJC_MSGSEND = YES;
GCC_C_LANGUAGE_STANDARD = gnu99;
@ -1033,7 +1033,7 @@
buildSettings = {
DEBUG_INFORMATION_FORMAT = dwarf;
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 0.12.0;
DYLIB_CURRENT_VERSION = 0.13.0;
EXECUTABLE_PREFIX = lib;
GCC_PREPROCESSOR_DEFINITIONS = (
"DEBUG=1",
@ -1063,7 +1063,7 @@
isa = XCBuildConfiguration;
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 0.12.0;
DYLIB_CURRENT_VERSION = 0.13.0;
EXECUTABLE_PREFIX = lib;
GCC_PREPROCESSOR_DEFINITIONS = (
"REALM_PLATFORM_NODE=1",
@ -1092,7 +1092,7 @@
isa = XCBuildConfiguration;
buildSettings = {
DYLIB_COMPATIBILITY_VERSION = 1;
DYLIB_CURRENT_VERSION = 0.12.0;
DYLIB_CURRENT_VERSION = 0.13.0;
EXECUTABLE_PREFIX = lib;
GCC_PREPROCESSOR_DEFINITIONS = (
"REALM_PLATFORM_NODE=1",

View File

@ -66,11 +66,10 @@ void ensure_directory_exists_for_file(const std::string &fileName)
void copy_bundled_realm_files()
{
NSString *docsDir = @(default_realm_file_directory().c_str());
NSFileManager *manager = [NSFileManager defaultManager];
for (id bundle in [NSBundle allBundles]) {
NSString *resourcePath = [bundle resourcePath];
NSString *docsDir = @(default_realm_file_directory().c_str());
NSFileManager *manager = [NSFileManager defaultManager];
for (NSString *path in [manager enumeratorAtPath:resourcePath]) {
if (![path containsString:@".realm"]) {
continue;

View File

@ -245,7 +245,7 @@ inline typename T::Function Realm<T>::create_constructor(ContextType ctx) {
FunctionType results_constructor = ObjectWrap<T, ResultsClass<T>>::create_constructor(ctx);
FunctionType realm_object_constructor = ObjectWrap<T, RealmObjectClass<T>>::create_constructor(ctx);
PropertyAttributes attributes = PropertyAttributes(ReadOnly | DontEnum | DontDelete);
PropertyAttributes attributes = ReadOnly | DontEnum | DontDelete;
Object::set_property(ctx, realm_constructor, "Collection", collection_constructor, attributes);
Object::set_property(ctx, realm_constructor, "List", list_constructor, attributes);
Object::set_property(ctx, realm_constructor, "Results", results_constructor, attributes);
@ -253,6 +253,31 @@ inline typename T::Function Realm<T>::create_constructor(ContextType ctx) {
return realm_constructor;
}
static void convert_outdated_datetime_columns(const SharedRealm &realm) {
if (realm->config().upgrade_initial_version != realm->config().upgrade_final_version &&
realm->config().upgrade_initial_version < 5) {
// any versions earlier than file format 5 are stored as milliseconds and need to be converted to the new format
for (auto& object_schema : *realm->config().schema) {
auto table = ObjectStore::table_for_object_type(realm->read_group(), object_schema.name);
for (auto& property : object_schema.properties) {
if (property.type == PropertyTypeDate) {
if (!realm->is_in_transaction()) {
realm->begin_transaction();
}
for (size_t row_index = 0; row_index < table->size(); row_index++) {
auto milliseconds = table->get_timestamp(property.table_column, row_index).get_seconds();
table->set_timestamp(property.table_column, row_index, Timestamp(milliseconds / 1000, (milliseconds % 1000) * 1000000));
}
}
}
if (realm->is_in_transaction()) {
realm->commit_transaction();
}
}
}
}
template<typename T>
void Realm<T>::constructor(ContextType ctx, ObjectType this_object, size_t argc, const ValueType arguments[]) {
@ -365,28 +390,7 @@ void Realm<T>::constructor(ContextType ctx, ObjectType this_object, size_t argc,
}
// Fix for datetime -> timestamp conversion
if (realm->config().upgrade_initial_version != realm->config().upgrade_final_version &&
realm->config().upgrade_initial_version < 5) {
// any versions earlier than file format 5 are stored as milliseconds and need to be converted to the new format
for (auto object_schema : *realm->config().schema) {
auto table = ObjectStore::table_for_object_type(realm->read_group(), object_schema.name);
for (auto property : object_schema.properties) {
if (property.type == realm::PropertyType::Date) {
if (!realm->is_in_transaction()) {
realm->begin_transaction();
}
for (size_t row_index = 0; row_index < table->size(); row_index++) {
auto milliseconds = table->get_timestamp(property.table_column, row_index).get_seconds();
table->set_timestamp(property.table_column, row_index, Timestamp(milliseconds / 1000, (milliseconds % 1000) * 1000000));
}
}
}
if (realm->is_in_transaction()) {
realm->commit_transaction();
}
}
}
convert_outdated_datetime_columns(realm);
set_internal<T, RealmClass<T>>(this_object, new SharedRealm(realm));
}

View File

@ -35,13 +35,17 @@
namespace realm {
namespace js {
enum PropertyAttributes {
enum PropertyAttributes : unsigned {
None = 0,
ReadOnly = 1 << 0,
DontEnum = 1 << 1,
DontDelete = 1 << 2
};
inline PropertyAttributes operator|(PropertyAttributes a, PropertyAttributes b) {
return PropertyAttributes(static_cast<unsigned>(a) | static_cast<unsigned>(b));
}
template<typename T>
struct String {
using StringType = typename T::String;

View File

@ -48,10 +48,7 @@ class ObjectWrap {
}
static JSObjectRef create_constructor(JSContextRef ctx) {
if (JSClassRef constructor_class = get_constructor_class()) {
return JSObjectMake(ctx, constructor_class, nullptr);
}
return JSObjectMakeConstructor(ctx, get_class(), construct);
return JSObjectMake(ctx, get_constructor_class(), nullptr);
}
static JSClassRef get_class() {
@ -92,7 +89,9 @@ class ObjectWrap {
static std::vector<JSStaticFunction> get_methods(const MethodMap &);
static std::vector<JSStaticValue> get_properties(const PropertyMap &);
static JSValueRef call(JSContextRef, JSObjectRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef*);
static JSObjectRef construct(JSContextRef, JSObjectRef, size_t, const JSValueRef[], JSValueRef*);
static void initialize_constructor(JSContextRef, JSObjectRef);
static void finalize(JSObjectRef);
static void get_property_names(JSContextRef, JSObjectRef, JSPropertyNameAccumulatorRef);
static JSValueRef get_property(JSContextRef, JSObjectRef, JSStringRef, JSValueRef*);
@ -104,7 +103,7 @@ class ObjectWrap {
}
static bool has_instance(JSContextRef ctx, JSObjectRef constructor, JSValueRef value, JSValueRef* exception) {
return JSValueIsObjectOfClass(ctx, value, get_class());
return has_instance(ctx, value);
}
};
@ -158,19 +157,18 @@ inline JSClassRef ObjectWrap<ClassType>::create_class() {
template<typename ClassType>
inline JSClassRef ObjectWrap<ClassType>::create_constructor_class() {
// Skip creating a special constructor class if possible.
if (!s_class.constructor && s_class.static_methods.empty() && s_class.static_properties.empty()) {
return nullptr;
}
JSClassDefinition definition = kJSClassDefinitionEmpty;
std::vector<JSStaticFunction> methods;
std::vector<JSStaticValue> properties;
definition.attributes = kJSClassAttributeNoAutomaticPrototype;
definition.className = s_class.name.c_str();
definition.className = "Function";
definition.initialize = initialize_constructor;
definition.hasInstance = has_instance;
// This must be set for `typeof constructor` to be 'function'.
definition.callAsFunction = call;
if (s_class.constructor) {
definition.callAsConstructor = construct;
}
@ -220,22 +218,57 @@ inline std::vector<JSStaticValue> ObjectWrap<ClassType>::get_properties(const Pr
}
template<typename ClassType>
inline JSObjectRef ObjectWrap<ClassType>::construct(JSContextRef ctx, JSObjectRef constructor, size_t argc, const JSValueRef arguments[], JSValueRef* exception) {
if (!s_class.constructor) {
*exception = jsc::Exception::value(ctx, "Illegal constructor");
inline JSValueRef ObjectWrap<ClassType>::call(JSContextRef ctx, JSObjectRef function, JSObjectRef this_object, size_t argc, const JSValueRef arguments[], JSValueRef* exception) {
// This should only be called as a super() call in the constructor of a subclass.
if (!has_instance(ctx, this_object)) {
*exception = jsc::Exception::value(ctx, s_class.name + " cannot be called as a function");
return nullptr;
}
JSObjectRef this_object = ObjectWrap<ClassType>::create_instance(ctx);
// Classes without a constructor should still be subclassable.
if (s_class.constructor) {
try {
s_class.constructor(ctx, this_object, argc, arguments);
}
catch (std::exception &e) {
*exception = jsc::Exception::value(ctx, e);
return nullptr;
}
}
return JSValueMakeUndefined(ctx);
}
template<typename ClassType>
inline JSObjectRef ObjectWrap<ClassType>::construct(JSContextRef ctx, JSObjectRef constructor, size_t argc, const JSValueRef arguments[], JSValueRef* exception) {
if (!s_class.constructor) {
*exception = jsc::Exception::value(ctx, s_class.name + " is not a constructor");
return nullptr;
}
JSObjectRef this_object = create_instance(ctx);
try {
s_class.constructor(ctx, this_object, argc, arguments);
}
catch (std::exception &e) {
*exception = jsc::Exception::value(ctx, e);
return nullptr;
}
return this_object;
}
template<typename ClassType>
inline void ObjectWrap<ClassType>::initialize_constructor(JSContextRef ctx, JSObjectRef constructor) {
static const String prototype_string = "prototype";
// Set the prototype of the constructor to be Function.prototype.
Object::set_prototype(ctx, constructor, Object::get_prototype(ctx, JSObjectMakeFunctionWithCallback(ctx, nullptr, call)));
// Set the constructor prototype to be the prototype generated from the instance JSClassRef.
JSObjectRef prototype = Object::validated_get_object(ctx, JSObjectMakeConstructor(ctx, get_class(), construct), prototype_string);
Object::set_property(ctx, constructor, prototype_string, prototype, js::ReadOnly | js::DontEnum | js::DontDelete);
}
template<typename ClassType>
inline void ObjectWrap<ClassType>::finalize(JSObjectRef object) {
// This is called for the most derived class before superclasses.

View File

@ -37,7 +37,7 @@ void RJSInitializeInContext(JSContextRef ctx) {
JSObjectRef global_object = JSContextGetGlobalObject(ctx);
JSObjectRef realm_constructor = RJSConstructorCreate(ctx);
jsc::Object::set_property(ctx, global_object, realm_string, realm_constructor, js::PropertyAttributes(js::ReadOnly | js::DontEnum | js::DontDelete));
jsc::Object::set_property(ctx, global_object, realm_string, realm_constructor, js::ReadOnly | js::DontEnum | js::DontDelete);
}
} // extern "C"

View File

@ -6,6 +6,7 @@ set -e
cd "$(dirname "$0")"
CONFIGURATION="${1:-"Release"}"
PATH="$(cd ../../node_modules/.bin && pwd):$PATH"
if [ -s "${HOME}/.nvm/nvm.sh" ]; then
. "${HOME}/.nvm/nvm.sh"

View File

@ -111,10 +111,12 @@ module.exports = {
},
isNode: function() {
// eslint-disable-next-line no-undef
return typeof process == 'object' && Object.prototype.toString.call(process) == '[object process]';
},
isNode6: function() {
// eslint-disable-next-line no-undef
return this.isNode() && process.version.indexOf('v6.') == 0;
},
};

View File

@ -36,6 +36,9 @@ module.exports = BaseTest.extend({
TestCase.assertThrows(function() {
new Realm.List();
});
TestCase.assertEqual(typeof Realm.List, 'function');
TestCase.assertTrue(Realm.List instanceof Function);
},
testListLength: function() {

View File

@ -435,10 +435,14 @@ module.exports = BaseTest.extend({
testObjectConstructor: function() {
var realm = new Realm({schema: [schemas.TestObject]});
realm.write(function() {
var obj = realm.create('TestObject', {doubleCol: 1});
TestCase.assertTrue(obj instanceof Realm.Object);
});
TestCase.assertEqual(typeof Realm.Object, 'function');
TestCase.assertTrue(Realm.Object instanceof Function);
},
testIsValid: function() {

View File

@ -27,6 +27,9 @@ module.exports = BaseTest.extend({
testRealmConstructor: function() {
var realm = new Realm({schema: []});
TestCase.assertTrue(realm instanceof Realm);
TestCase.assertEqual(typeof Realm, 'function');
TestCase.assertTrue(Realm instanceof Function);
},
testRealmConstructorPath: function() {

View File

@ -34,6 +34,9 @@ module.exports = BaseTest.extend({
TestCase.assertThrows(function() {
new Realm.Results();
});
TestCase.assertEqual(typeof Realm.Results, 'function');
TestCase.assertTrue(Realm.Results instanceof Function);
},
testResultsLength: function() {

View File

@ -17,7 +17,7 @@
////////////////////////////////////////////////////////////////////////////
'use strict';
const React = require('react-native');
const React = require('react');
const Realm = require('realm');
const RealmTests = require('realm-tests');
const builder = require('xmlbuilder');
@ -30,7 +30,7 @@ const {
Text,
View,
TouchableNativeFeedback,
} = React;
} = require('react-native');
RealmTests.registerTests({
ListViewTest: require('./tests/listview-test'),

View File

@ -18,7 +18,7 @@
'use strict';
const React = require('react-native');
const React = require('react');
const Realm = require('realm');
const tests = require('./tests');
@ -28,7 +28,7 @@ const {
Text,
TouchableHighlight,
View,
} = React;
} = require('react-native');
class ReactTests extends React.Component {
render() {

View File

@ -6,8 +6,8 @@
"start": "react-native start"
},
"dependencies": {
"react": "^0.14.5",
"react-native": "^0.24.1",
"react": "^0.14.8",
"react-native": "^0.25.1",
"react-native-fs": "^1.1.0",
"xmlbuilder": "^4.2.1",
"realm": "file:../..",