mirror of
https://github.com/status-im/realm-js.git
synced 2025-01-12 07:14:23 +00:00
Merge pull request #103 from realm/al-optional-properties
Support null properties
This commit is contained in:
commit
57aadc0bda
@ -90,6 +90,10 @@ function serialize(realmId, value) {
|
|||||||
return {type: objectTypes.FUNCTION};
|
return {type: objectTypes.FUNCTION};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (typeof value === 'undefined') {
|
||||||
|
return {type: 'undefined'};
|
||||||
|
}
|
||||||
|
|
||||||
if (!value || typeof value != 'object') {
|
if (!value || typeof value != 'object') {
|
||||||
return {value: value};
|
return {value: value};
|
||||||
}
|
}
|
||||||
|
@ -100,7 +100,7 @@ template<> JSValueRef RJSAccessor::default_value_for_property(JSContextRef ctx,
|
|||||||
}
|
}
|
||||||
|
|
||||||
template<> bool RJSAccessor::is_null(JSContextRef ctx, JSValueRef &val) {
|
template<> bool RJSAccessor::is_null(JSContextRef ctx, JSValueRef &val) {
|
||||||
return JSValueIsUndefined(ctx, val) || JSValueIsNull(ctx, val);
|
return JSValueIsNull(ctx, val);
|
||||||
}
|
}
|
||||||
template<> JSValueRef RJSAccessor::null_value(JSContextRef ctx) {
|
template<> JSValueRef RJSAccessor::null_value(JSContextRef ctx) {
|
||||||
return JSValueMakeNull(ctx);
|
return JSValueMakeNull(ctx);
|
||||||
|
@ -49,10 +49,20 @@ static inline Property RJSParseProperty(JSContextRef ctx, JSObjectRef propertyOb
|
|||||||
static JSStringRef nameString = JSStringCreateWithUTF8CString("name");
|
static JSStringRef nameString = JSStringCreateWithUTF8CString("name");
|
||||||
static JSStringRef typeString = JSStringCreateWithUTF8CString("type");
|
static JSStringRef typeString = JSStringCreateWithUTF8CString("type");
|
||||||
static JSStringRef objectTypeString = JSStringCreateWithUTF8CString("objectType");
|
static JSStringRef objectTypeString = JSStringCreateWithUTF8CString("objectType");
|
||||||
|
static JSStringRef optionalString = JSStringCreateWithUTF8CString("optional");
|
||||||
|
|
||||||
Property prop;
|
Property prop;
|
||||||
prop.name = RJSValidatedStringProperty(ctx, propertyObject, nameString);
|
prop.name = RJSValidatedStringProperty(ctx, propertyObject, nameString);
|
||||||
|
|
||||||
|
prop.is_nullable = false;
|
||||||
|
JSValueRef optionalValue = JSObjectGetProperty(ctx, propertyObject, optionalString, NULL);
|
||||||
|
if (!JSValueIsUndefined(ctx, optionalValue)) {
|
||||||
|
if (!JSValueIsBoolean(ctx, optionalValue)) {
|
||||||
|
throw std::runtime_error("'optional' designation expected to be of type boolean");
|
||||||
|
}
|
||||||
|
prop.is_nullable = JSValueToBoolean(ctx, optionalValue);
|
||||||
|
}
|
||||||
|
|
||||||
std::string type = RJSValidatedStringProperty(ctx, propertyObject, typeString);
|
std::string type = RJSValidatedStringProperty(ctx, propertyObject, typeString);
|
||||||
if (type == "PropTypesBOOL") {
|
if (type == "PropTypesBOOL") {
|
||||||
prop.type = PropertyTypeBool;
|
prop.type = PropertyTypeBool;
|
||||||
@ -75,19 +85,14 @@ static inline Property RJSParseProperty(JSContextRef ctx, JSObjectRef propertyOb
|
|||||||
else if (type == "PropTypesDATA") {
|
else if (type == "PropTypesDATA") {
|
||||||
prop.type = PropertyTypeData;
|
prop.type = PropertyTypeData;
|
||||||
}
|
}
|
||||||
else if (type == "PropTypesOBJECT") {
|
|
||||||
prop.type = PropertyTypeObject;
|
|
||||||
prop.object_type = RJSValidatedStringProperty(ctx, propertyObject, objectTypeString);
|
|
||||||
prop.is_nullable = true;
|
|
||||||
}
|
|
||||||
else if (type == "PropTypesLIST") {
|
else if (type == "PropTypesLIST") {
|
||||||
prop.type = PropertyTypeArray;
|
prop.type = PropertyTypeArray;
|
||||||
prop.object_type = RJSValidatedStringProperty(ctx, propertyObject, objectTypeString);
|
prop.object_type = RJSValidatedStringProperty(ctx, propertyObject, objectTypeString);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
prop.type = PropertyTypeObject;
|
prop.type = PropertyTypeObject;
|
||||||
prop.object_type = type;
|
|
||||||
prop.is_nullable = true;
|
prop.is_nullable = true;
|
||||||
|
prop.object_type = type == "PropTypesOBJECT" ? RJSValidatedStringProperty(ctx, propertyObject, objectTypeString) : type;
|
||||||
}
|
}
|
||||||
return prop;
|
return prop;
|
||||||
}
|
}
|
||||||
|
@ -315,6 +315,10 @@ JSValueRef RPCServer::deserialize_json_value(const json dict)
|
|||||||
}
|
}
|
||||||
return date;
|
return date;
|
||||||
}
|
}
|
||||||
|
else if (type_string == "undefined") {
|
||||||
|
return JSValueMakeUndefined(m_context);
|
||||||
|
}
|
||||||
|
assert(0);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (value.is_null()) {
|
if (value.is_null()) {
|
||||||
@ -353,5 +357,5 @@ JSValueRef RPCServer::deserialize_json_value(const json dict)
|
|||||||
return js_object;
|
return js_object;
|
||||||
}
|
}
|
||||||
|
|
||||||
return JSValueMakeUndefined(m_context);
|
assert(0);
|
||||||
}
|
}
|
||||||
|
@ -156,6 +156,11 @@ namespace realm {
|
|||||||
}
|
}
|
||||||
|
|
||||||
size_t column = property.table_column;
|
size_t column = property.table_column;
|
||||||
|
if (property.is_nullable && Accessor::is_null(ctx, value)) {
|
||||||
|
m_row.set_null(column);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
switch (property.type) {
|
switch (property.type) {
|
||||||
case PropertyTypeBool:
|
case PropertyTypeBool:
|
||||||
m_row.set_bool(column, Accessor::to_bool(ctx, value));
|
m_row.set_bool(column, Accessor::to_bool(ctx, value));
|
||||||
@ -209,6 +214,10 @@ namespace realm {
|
|||||||
using Accessor = NativeAccessor<ValueType, ContextType>;
|
using Accessor = NativeAccessor<ValueType, ContextType>;
|
||||||
|
|
||||||
size_t column = property.table_column;
|
size_t column = property.table_column;
|
||||||
|
if (property.is_nullable && m_row.is_null(column)) {
|
||||||
|
return Accessor::null_value(ctx);
|
||||||
|
}
|
||||||
|
|
||||||
switch (property.type) {
|
switch (property.type) {
|
||||||
case PropertyTypeBool:
|
case PropertyTypeBool:
|
||||||
return Accessor::from_bool(ctx, m_row.get_bool(column));
|
return Accessor::from_bool(ctx, m_row.get_bool(column));
|
||||||
|
@ -555,11 +555,7 @@ InvalidNullabilityException::InvalidNullabilityException(std::string const& obje
|
|||||||
m_what = "'Object' property '" + property.name + "' must be nullable.";
|
m_what = "'Object' property '" + property.name + "' must be nullable.";
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
#if REALM_NULL_STRINGS == 1
|
|
||||||
m_what = "Array or Mixed property '" + property.name + "' cannot be nullable";
|
m_what = "Array or Mixed property '" + property.name + "' cannot be nullable";
|
||||||
#else
|
|
||||||
m_what = "Only 'Object' property types are nullable";
|
|
||||||
#endif
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -71,11 +71,7 @@ void Schema::validate() const
|
|||||||
|
|
||||||
// check nullablity
|
// check nullablity
|
||||||
if (prop.is_nullable) {
|
if (prop.is_nullable) {
|
||||||
#if REALM_NULL_STRINGS == 1
|
|
||||||
if (prop.type == PropertyTypeArray || prop.type == PropertyTypeAny) {
|
if (prop.type == PropertyTypeArray || prop.type == PropertyTypeAny) {
|
||||||
#else
|
|
||||||
if (prop.type != PropertyTypeObject) {
|
|
||||||
#endif
|
|
||||||
exceptions.emplace_back(InvalidNullabilityException(object.name, prop));
|
exceptions.emplace_back(InvalidNullabilityException(object.name, prop));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -47,6 +47,34 @@ module.exports = BaseTest.extend({
|
|||||||
|
|
||||||
TestCase.assertEqual(object.nonexistent, undefined);
|
TestCase.assertEqual(object.nonexistent, undefined);
|
||||||
},
|
},
|
||||||
|
testNullableBasicTypesPropertyGetters: function() {
|
||||||
|
var nullValues = [null, null, null, null, null, null, null];
|
||||||
|
var basicTypesValues = [true, 1, 1.1, 1.11, 'string', new Date(1), 'DATA'];
|
||||||
|
|
||||||
|
var realm = new Realm({schema: [schemas.NullableBasicTypes]});
|
||||||
|
var nullObject = null;
|
||||||
|
var object = null;
|
||||||
|
realm.write(function() {
|
||||||
|
nullObject = realm.create('NullableBasicTypesObject', nullValues);
|
||||||
|
object = realm.create('NullableBasicTypesObject', basicTypesValues);
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var i = 0; i < schemas.BasicTypes.properties.length; i++) {
|
||||||
|
var prop = schemas.BasicTypes.properties[i];
|
||||||
|
TestCase.assertEqual(nullObject[prop.name], null);
|
||||||
|
|
||||||
|
if (prop.type == Realm.Types.FLOAT) {
|
||||||
|
TestCase.assertEqualWithTolerance(object[prop.name], basicTypesValues[i], 0.000001);
|
||||||
|
}
|
||||||
|
else if (prop.type == Realm.Types.DATE) {
|
||||||
|
TestCase.assertEqual(object[prop.name].getTime(), basicTypesValues[i].getTime());
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
TestCase.assertEqual(object[prop.name], basicTypesValues[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
},
|
||||||
testBasicTypesPropertySetters: function() {
|
testBasicTypesPropertySetters: function() {
|
||||||
var basicTypesValues = [true, 1, 1.1, 1.11, 'string', new Date(1), 'DATA'];
|
var basicTypesValues = [true, 1, 1.1, 1.11, 'string', new Date(1), 'DATA'];
|
||||||
var realm = new Realm({schema: [schemas.BasicTypes]});
|
var realm = new Realm({schema: [schemas.BasicTypes]});
|
||||||
@ -129,6 +157,57 @@ module.exports = BaseTest.extend({
|
|||||||
|
|
||||||
TestCase.assertEqual(obj.boolCol, false, 'bool value changed outside transaction');
|
TestCase.assertEqual(obj.boolCol, false, 'bool value changed outside transaction');
|
||||||
},
|
},
|
||||||
|
testNullableBasicTypesPropertySetters: function() {
|
||||||
|
var basicTypesValues = [true, 1, 1.1, 1.11, 'string', new Date(1), 'DATA'];
|
||||||
|
var realm = new Realm({schema: [schemas.NullableBasicTypes]});
|
||||||
|
var obj = null;
|
||||||
|
|
||||||
|
realm.write(function() {
|
||||||
|
obj = realm.create('NullableBasicTypesObject', basicTypesValues);
|
||||||
|
for (var prop of schemas.NullableBasicTypes.properties) {
|
||||||
|
obj[prop.name] = null;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
for (var prop of schemas.NullableBasicTypes.properties) {
|
||||||
|
TestCase.assertEqual(obj[prop.name], null);
|
||||||
|
}
|
||||||
|
|
||||||
|
realm.write(function() {
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
obj.boolCol = 'cat';
|
||||||
|
});
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
obj.intCol = 'dog';
|
||||||
|
});
|
||||||
|
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
obj.boolCol = undefined;
|
||||||
|
});
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
obj.intCol = undefined;
|
||||||
|
});
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
obj.floatCol = undefined;
|
||||||
|
});
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
obj.doubleCol = undefined;
|
||||||
|
});
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
obj.stringCol = undefined;
|
||||||
|
});
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
obj.dateCol = undefined;
|
||||||
|
});
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
obj.dataCol = undefined;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
TestCase.assertThrows(function() {
|
||||||
|
obj.boolCol = null;
|
||||||
|
}, 'can only set property values in a write transaction');
|
||||||
|
},
|
||||||
testLinkTypesPropertyGetters: function() {
|
testLinkTypesPropertyGetters: function() {
|
||||||
var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]});
|
var realm = new Realm({schema: [schemas.LinkTypes, schemas.TestObject]});
|
||||||
var obj = null;
|
var obj = null;
|
||||||
|
@ -53,6 +53,19 @@ exports.BasicTypes = {
|
|||||||
]
|
]
|
||||||
};
|
};
|
||||||
|
|
||||||
|
exports.NullableBasicTypes = {
|
||||||
|
name: 'NullableBasicTypesObject',
|
||||||
|
properties: [
|
||||||
|
{name: 'boolCol', type: Realm.Types.BOOL, optional: true},
|
||||||
|
{name: 'intCol', type: Realm.Types.INT, optional: true},
|
||||||
|
{name: 'floatCol', type: Realm.Types.FLOAT, optional: true},
|
||||||
|
{name: 'doubleCol', type: Realm.Types.DOUBLE, optional: true},
|
||||||
|
{name: 'stringCol', type: Realm.Types.STRING, optional: true},
|
||||||
|
{name: 'dateCol', type: Realm.Types.DATE, optional: true},
|
||||||
|
{name: 'dataCol', type: Realm.Types.DATA, optional: true},
|
||||||
|
]
|
||||||
|
};
|
||||||
|
|
||||||
exports.LinkTypes = {
|
exports.LinkTypes = {
|
||||||
name: 'LinkTypesObject',
|
name: 'LinkTypesObject',
|
||||||
properties: [
|
properties: [
|
||||||
|
Loading…
x
Reference in New Issue
Block a user