mirror of
https://github.com/status-im/realm-js.git
synced 2025-01-11 06:46:03 +00:00
Change schema API to take properties as an object
The keys are names of the properties, which is more natural in JS, but will cause issues with ability to create objects where arrays of values. This feature will be removed in a subsequent commit.
This commit is contained in:
parent
358e5dacf3
commit
43e14093cc
@ -32,7 +32,7 @@ JSClassRef RJSRealmTypeClass() {
|
||||
{ "DATE", RJSTypeGet, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
|
||||
{ "DATA", RJSTypeGet, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
|
||||
{ "OBJECT", RJSTypeGet, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
|
||||
{ "LIST", RJSTypeGet, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
|
||||
{ "LIST", RJSTypeGet, NULL, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontDelete },
|
||||
{ NULL, NULL, NULL, 0 }
|
||||
};
|
||||
realmTypesDefinition.staticValues = types;
|
||||
|
@ -31,25 +31,34 @@ JSObjectRef RJSSchemaCreate(JSContextRef ctx, Schema &schema) {
|
||||
return RJSWrapObject(ctx, RJSSchemaClass(), wrapper);
|
||||
}
|
||||
|
||||
static inline Property RJSParseProperty(JSContextRef ctx, JSObjectRef propertyObject) {
|
||||
static JSStringRef nameString = JSStringCreateWithUTF8CString("name");
|
||||
static inline Property RJSParseProperty(JSContextRef ctx, JSValueRef propertyAttributes, std::string propertyName, ObjectDefaults &objectDefaults) {
|
||||
static JSStringRef defaultString = JSStringCreateWithUTF8CString("default");
|
||||
static JSStringRef typeString = JSStringCreateWithUTF8CString("type");
|
||||
static JSStringRef objectTypeString = JSStringCreateWithUTF8CString("objectType");
|
||||
static JSStringRef optionalString = JSStringCreateWithUTF8CString("optional");
|
||||
|
||||
Property prop;
|
||||
prop.name = RJSValidatedStringProperty(ctx, propertyObject, nameString);
|
||||
prop.name = propertyName;
|
||||
|
||||
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");
|
||||
JSObjectRef propertyObject = NULL;
|
||||
std::string type;
|
||||
|
||||
if (JSValueIsObject(ctx, propertyAttributes)) {
|
||||
propertyObject = RJSValidatedValueToObject(ctx, propertyAttributes);
|
||||
type = RJSValidatedStringProperty(ctx, propertyObject, typeString);
|
||||
|
||||
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);
|
||||
}
|
||||
prop.is_nullable = JSValueToBoolean(ctx, optionalValue);
|
||||
}
|
||||
else {
|
||||
type = RJSValidatedStringForValue(ctx, propertyAttributes);
|
||||
}
|
||||
|
||||
std::string type = RJSValidatedStringProperty(ctx, propertyObject, typeString);
|
||||
if (type == "bool") {
|
||||
prop.type = PropertyTypeBool;
|
||||
}
|
||||
@ -72,14 +81,36 @@ static inline Property RJSParseProperty(JSContextRef ctx, JSObjectRef propertyOb
|
||||
prop.type = PropertyTypeData;
|
||||
}
|
||||
else if (type == "list") {
|
||||
if (!propertyObject) {
|
||||
throw std::runtime_error("List property must specify 'objectType'");
|
||||
}
|
||||
prop.type = PropertyTypeArray;
|
||||
prop.object_type = RJSValidatedStringProperty(ctx, propertyObject, objectTypeString);
|
||||
}
|
||||
else {
|
||||
prop.type = PropertyTypeObject;
|
||||
prop.is_nullable = true;
|
||||
prop.object_type = type == "object" ? RJSValidatedStringProperty(ctx, propertyObject, objectTypeString) : type;
|
||||
|
||||
// The type could either be 'object' or the name of another object type in the same schema.
|
||||
if (type == "object") {
|
||||
if (!propertyObject) {
|
||||
throw std::runtime_error("Object property must specify 'objectType'");
|
||||
}
|
||||
prop.object_type = RJSValidatedStringProperty(ctx, propertyObject, objectTypeString);
|
||||
}
|
||||
else {
|
||||
prop.object_type = type;
|
||||
}
|
||||
}
|
||||
|
||||
if (propertyObject) {
|
||||
JSValueRef defaultValue = RJSValidatedPropertyValue(ctx, propertyObject, defaultString);
|
||||
if (!JSValueIsUndefined(ctx, defaultValue)) {
|
||||
JSValueProtect(ctx, defaultValue);
|
||||
objectDefaults.emplace(prop.name, defaultValue);
|
||||
}
|
||||
}
|
||||
|
||||
return prop;
|
||||
}
|
||||
|
||||
@ -88,6 +119,7 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob
|
||||
static JSStringRef prototypeString = JSStringCreateWithUTF8CString("prototype");
|
||||
JSObjectRef prototypeObject = NULL;
|
||||
JSValueRef prototypeValue = RJSValidatedPropertyValue(ctx, objectSchemaObject, prototypeString);
|
||||
|
||||
if (!JSValueIsUndefined(ctx, prototypeValue)) {
|
||||
prototypeObject = RJSValidatedValueToObject(ctx, prototypeValue);
|
||||
objectSchemaObject = RJSValidatedObjectProperty(ctx, prototypeObject, schemaString, "Realm object prototype must have a 'schema' property.");
|
||||
@ -99,27 +131,46 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob
|
||||
}
|
||||
}
|
||||
|
||||
static JSStringRef propertiesString = JSStringCreateWithUTF8CString("properties");
|
||||
JSObjectRef propertiesObject = RJSValidatedObjectProperty(ctx, objectSchemaObject, propertiesString, "ObjectSchema object must have a 'properties' array.");
|
||||
|
||||
ObjectSchema objectSchema;
|
||||
ObjectDefaults objectDefaults;
|
||||
static JSStringRef nameString = JSStringCreateWithUTF8CString("name");
|
||||
static JSStringRef propertiesString = JSStringCreateWithUTF8CString("properties");
|
||||
JSObjectRef propertiesObject = RJSValidatedObjectProperty(ctx, objectSchemaObject, propertiesString, "ObjectSchema must have a 'properties' object.");
|
||||
|
||||
ObjectDefaults objectDefaults;
|
||||
ObjectSchema objectSchema;
|
||||
objectSchema.name = RJSValidatedStringProperty(ctx, objectSchemaObject, nameString);
|
||||
|
||||
size_t numProperties = RJSValidatedListLength(ctx, propertiesObject);
|
||||
for (unsigned int p = 0; p < numProperties; p++) {
|
||||
JSObjectRef property = RJSValidatedObjectAtIndex(ctx, propertiesObject, p);
|
||||
objectSchema.properties.emplace_back(RJSParseProperty(ctx, property));
|
||||
JSPropertyNameArrayRef propertyNames = NULL;
|
||||
size_t propertyCount;
|
||||
|
||||
static JSStringRef defaultString = JSStringCreateWithUTF8CString("default");
|
||||
JSValueRef defaultValue = JSObjectGetProperty(ctx, property, defaultString, NULL);
|
||||
if (!JSValueIsUndefined(ctx, defaultValue)) {
|
||||
JSValueProtect(ctx, defaultValue);
|
||||
objectDefaults.emplace(objectSchema.properties.back().name, defaultValue);
|
||||
}
|
||||
if (RJSIsValueArray(ctx, propertiesObject)) {
|
||||
propertyCount = RJSValidatedListLength(ctx, propertiesObject);
|
||||
}
|
||||
else {
|
||||
propertyNames = JSObjectCopyPropertyNames(ctx, propertiesObject);
|
||||
propertyCount = JSPropertyNameArrayGetCount(propertyNames);
|
||||
}
|
||||
|
||||
for (size_t i = 0; i < propertyCount; i++) {
|
||||
Property property;
|
||||
|
||||
// Check if the properties were provided as an object.
|
||||
if (propertyNames) {
|
||||
JSStringRef propertyName = JSPropertyNameArrayGetNameAtIndex(propertyNames, i);
|
||||
JSValueRef propertyValue = RJSValidatedPropertyValue(ctx, propertiesObject, propertyName);
|
||||
property = RJSParseProperty(ctx, propertyValue, RJSStringForJSString(propertyName), objectDefaults);
|
||||
}
|
||||
else {
|
||||
JSObjectRef propertyObject = RJSValidatedObjectAtIndex(ctx, propertiesObject, (unsigned int)i);
|
||||
std::string propertyName = RJSValidatedStringProperty(ctx, propertyObject, nameString);
|
||||
property = RJSParseProperty(ctx, propertyObject, propertyName, objectDefaults);
|
||||
}
|
||||
|
||||
objectSchema.properties.emplace_back(property);
|
||||
}
|
||||
|
||||
if (propertyNames) {
|
||||
JSPropertyNameArrayRelease(propertyNames);
|
||||
}
|
||||
defaults.emplace(objectSchema.name, std::move(objectDefaults));
|
||||
|
||||
static JSStringRef primaryString = JSStringCreateWithUTF8CString("primaryKey");
|
||||
JSValueRef primaryValue = RJSValidatedPropertyValue(ctx, objectSchemaObject, primaryString);
|
||||
@ -138,6 +189,8 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob
|
||||
prototypes[objectSchema.name] = std::move(prototypeObject);
|
||||
}
|
||||
|
||||
defaults.emplace(objectSchema.name, std::move(objectDefaults));
|
||||
|
||||
return objectSchema;
|
||||
}
|
||||
|
||||
|
@ -163,15 +163,15 @@ module.exports = BaseTest.extend({
|
||||
realm.write(function() {
|
||||
obj = realm.create('NullableBasicTypesObject', basicTypesValues);
|
||||
obj1 = realm.create('NullableBasicTypesObject', basicTypesValues);
|
||||
for (var prop of schemas.NullableBasicTypes.properties) {
|
||||
obj[prop.name] = null;
|
||||
obj1[prop.name] = undefined;
|
||||
for (var name in schemas.NullableBasicTypes.properties) {
|
||||
obj[name] = null;
|
||||
obj1[name] = undefined;
|
||||
}
|
||||
});
|
||||
|
||||
for (var prop of schemas.NullableBasicTypes.properties) {
|
||||
TestCase.assertEqual(obj[prop.name], null);
|
||||
TestCase.assertEqual(obj1[prop.name], null);
|
||||
for (var name in schemas.NullableBasicTypes.properties) {
|
||||
TestCase.assertEqual(obj[name], null);
|
||||
TestCase.assertEqual(obj1[name], null);
|
||||
}
|
||||
|
||||
realm.write(function() {
|
||||
@ -262,7 +262,7 @@ module.exports = BaseTest.extend({
|
||||
object = realm.create('BasicTypesObject', basicTypesValues);
|
||||
});
|
||||
|
||||
var propNames = schemas.BasicTypes.properties.map(function(prop) { return prop.name; });
|
||||
var propNames = Object.keys(schemas.BasicTypes.properties);
|
||||
TestCase.assertArraysEqual(Object.keys(object), propNames, 'Object.keys');
|
||||
|
||||
for (var key in object) {
|
||||
|
@ -162,17 +162,19 @@ module.exports = BaseTest.extend({
|
||||
var realm = new Realm({schema: [schemas.DefaultValues, schemas.TestObject]});
|
||||
realm.write(function() {
|
||||
var obj = realm.create('DefaultValuesObject', {});
|
||||
TestCase.assertEqual(obj.boolCol, schemas.DefaultValues.properties[0].default);
|
||||
TestCase.assertEqual(obj.intCol, schemas.DefaultValues.properties[1].default);
|
||||
TestCase.assertEqualWithTolerance(obj.floatCol, schemas.DefaultValues.properties[2].default, 0.000001);
|
||||
TestCase.assertEqual(obj.doubleCol, schemas.DefaultValues.properties[3].default);
|
||||
TestCase.assertEqual(obj.stringCol, schemas.DefaultValues.properties[4].default);
|
||||
TestCase.assertEqual(obj.dateCol.getTime(), schemas.DefaultValues.properties[5].default.getTime());
|
||||
TestCase.assertEqual(obj.dataCol.byteLength, schemas.DefaultValues.properties[6].default.byteLength);
|
||||
TestCase.assertEqual(obj.objectCol.doubleCol, schemas.DefaultValues.properties[7].default[0]);
|
||||
var properties = schemas.DefaultValues.properties;
|
||||
|
||||
TestCase.assertEqual(obj.boolCol, properties.boolCol.default);
|
||||
TestCase.assertEqual(obj.intCol, properties.intCol.default);
|
||||
TestCase.assertEqualWithTolerance(obj.floatCol, properties.floatCol.default, 0.000001);
|
||||
TestCase.assertEqual(obj.doubleCol, properties.doubleCol.default);
|
||||
TestCase.assertEqual(obj.stringCol, properties.stringCol.default);
|
||||
TestCase.assertEqual(obj.dateCol.getTime(), properties.dateCol.default.getTime());
|
||||
TestCase.assertEqual(obj.dataCol.byteLength, properties.dataCol.default.byteLength);
|
||||
TestCase.assertEqual(obj.objectCol.doubleCol, properties.objectCol.default[0]);
|
||||
TestCase.assertEqual(obj.nullObjectCol, null);
|
||||
TestCase.assertEqual(obj.arrayCol.length, schemas.DefaultValues.properties[9].default.length);
|
||||
TestCase.assertEqual(obj.arrayCol[0].doubleCol, schemas.DefaultValues.properties[9].default[0][0]);
|
||||
TestCase.assertEqual(obj.arrayCol.length, properties.arrayCol.default.length);
|
||||
TestCase.assertEqual(obj.arrayCol[0].doubleCol, properties.arrayCol.default[0][0]);
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -7,20 +7,20 @@
|
||||
var Realm = require('realm');
|
||||
|
||||
exports.TestObject = {
|
||||
name: 'TestObject',
|
||||
properties: [
|
||||
{name: 'doubleCol', type: Realm.Types.DOUBLE},
|
||||
]
|
||||
name: 'TestObject',
|
||||
properties: {
|
||||
doubleCol: Realm.Types.DOUBLE,
|
||||
}
|
||||
};
|
||||
|
||||
function PersonObject() {}
|
||||
PersonObject.prototype.schema = {
|
||||
name: 'PersonObject',
|
||||
properties: [
|
||||
{name: 'name', type: Realm.Types.STRING},
|
||||
{name: 'age', type: Realm.Types.DOUBLE},
|
||||
{name: 'married', type: Realm.Types.BOOL, default: false}
|
||||
]
|
||||
name: 'PersonObject',
|
||||
properties: {
|
||||
name: Realm.Types.STRING,
|
||||
age: Realm.Types.DOUBLE,
|
||||
married: {type: Realm.Types.BOOL, default: false},
|
||||
}
|
||||
};
|
||||
PersonObject.prototype.description = function() {
|
||||
return this.name + ' ' + this.age;
|
||||
@ -29,79 +29,79 @@ exports.PersonObject = PersonObject;
|
||||
|
||||
exports.BasicTypes = {
|
||||
name: 'BasicTypesObject',
|
||||
properties: [
|
||||
{name: 'boolCol', type: Realm.Types.BOOL},
|
||||
{name: 'intCol', type: Realm.Types.INT},
|
||||
{name: 'floatCol', type: Realm.Types.FLOAT},
|
||||
{name: 'doubleCol', type: Realm.Types.DOUBLE},
|
||||
{name: 'stringCol', type: Realm.Types.STRING},
|
||||
{name: 'dateCol', type: Realm.Types.DATE},
|
||||
{name: 'dataCol', type: Realm.Types.DATA},
|
||||
]
|
||||
properties: {
|
||||
boolCol: Realm.Types.BOOL,
|
||||
intCol: Realm.Types.INT,
|
||||
floatCol: Realm.Types.FLOAT,
|
||||
doubleCol: Realm.Types.DOUBLE,
|
||||
stringCol: Realm.Types.STRING,
|
||||
dateCol: Realm.Types.DATE,
|
||||
dataCol: Realm.Types.DATA,
|
||||
}
|
||||
};
|
||||
|
||||
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},
|
||||
]
|
||||
properties: {
|
||||
boolCol: {type: Realm.Types.BOOL, optional: true},
|
||||
intCol: {type: Realm.Types.INT, optional: true},
|
||||
floatCol: {type: Realm.Types.FLOAT, optional: true},
|
||||
doubleCol: {type: Realm.Types.DOUBLE, optional: true},
|
||||
stringCol: {type: Realm.Types.STRING, optional: true},
|
||||
dateCol: {type: Realm.Types.DATE, optional: true},
|
||||
dataCol: {type: Realm.Types.DATA, optional: true},
|
||||
}
|
||||
};
|
||||
|
||||
exports.LinkTypes = {
|
||||
name: 'LinkTypesObject',
|
||||
properties: [
|
||||
{name: 'objectCol', type: 'TestObject'},
|
||||
{name: 'objectCol1', type: Realm.Types.OBJECT, objectType: 'TestObject'},
|
||||
{name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject'},
|
||||
]
|
||||
properties: {
|
||||
objectCol: 'TestObject',
|
||||
objectCol1: {type: Realm.Types.OBJECT, objectType: 'TestObject'},
|
||||
arrayCol: {type: Realm.Types.LIST, objectType: 'TestObject'},
|
||||
}
|
||||
};
|
||||
|
||||
exports.IntPrimary = {
|
||||
name: 'IntPrimaryObject',
|
||||
primaryKey: 'primaryCol',
|
||||
properties: [
|
||||
{name: 'primaryCol', type: Realm.Types.INT},
|
||||
{name: 'valueCol', type: Realm.Types.STRING},
|
||||
]
|
||||
name: 'IntPrimaryObject',
|
||||
primaryKey: 'primaryCol',
|
||||
properties: {
|
||||
primaryCol: Realm.Types.INT,
|
||||
valueCol: Realm.Types.STRING,
|
||||
}
|
||||
};
|
||||
|
||||
exports.AllTypes = {
|
||||
name: 'AllTypesObject',
|
||||
primaryKey: 'primaryCol',
|
||||
properties: [
|
||||
{name: 'primaryCol',type: Realm.Types.STRING},
|
||||
{name: 'boolCol', type: Realm.Types.BOOL},
|
||||
{name: 'intCol', type: Realm.Types.INT},
|
||||
{name: 'floatCol', type: Realm.Types.FLOAT},
|
||||
{name: 'doubleCol', type: Realm.Types.DOUBLE},
|
||||
{name: 'stringCol', type: Realm.Types.STRING},
|
||||
{name: 'dateCol', type: Realm.Types.DATE},
|
||||
{name: 'dataCol', type: Realm.Types.DATA},
|
||||
{name: 'objectCol', type: 'TestObject'},
|
||||
{name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject'},
|
||||
]
|
||||
name: 'AllTypesObject',
|
||||
primaryKey: 'primaryCol',
|
||||
properties: {
|
||||
primaryCol: Realm.Types.STRING,
|
||||
boolCol: Realm.Types.BOOL,
|
||||
intCol: Realm.Types.INT,
|
||||
floatCol: Realm.Types.FLOAT,
|
||||
doubleCol: Realm.Types.DOUBLE,
|
||||
stringCol: Realm.Types.STRING,
|
||||
dateCol: Realm.Types.DATE,
|
||||
dataCol: Realm.Types.DATA,
|
||||
objectCol: 'TestObject',
|
||||
arrayCol: {type: Realm.Types.LIST, objectType: 'TestObject'},
|
||||
}
|
||||
};
|
||||
|
||||
exports.DefaultValues = {
|
||||
name: 'DefaultValuesObject',
|
||||
properties: [
|
||||
{name: 'boolCol', type: Realm.Types.BOOL, default: true},
|
||||
{name: 'intCol', type: Realm.Types.INT, default: -1},
|
||||
{name: 'floatCol', type: Realm.Types.FLOAT, default: -1.1},
|
||||
{name: 'doubleCol', type: Realm.Types.DOUBLE, default: -1.11},
|
||||
{name: 'stringCol', type: Realm.Types.STRING, default: 'defaultString'},
|
||||
{name: 'dateCol', type: Realm.Types.DATE, default: new Date(1.111)},
|
||||
{name: 'dataCol', type: Realm.Types.DATA, default: new ArrayBuffer(1)},
|
||||
{name: 'objectCol', type: 'TestObject', default: [1]},
|
||||
{name: 'nullObjectCol', type: 'TestObject', default: null},
|
||||
{name: 'arrayCol', type: Realm.Types.LIST, objectType: 'TestObject', default: [[2]]},
|
||||
]
|
||||
name: 'DefaultValuesObject',
|
||||
properties: {
|
||||
boolCol: {type: Realm.Types.BOOL, default: true},
|
||||
intCol: {type: Realm.Types.INT, default: -1},
|
||||
floatCol: {type: Realm.Types.FLOAT, default: -1.1},
|
||||
doubleCol: {type: Realm.Types.DOUBLE, default: -1.11},
|
||||
stringCol: {type: Realm.Types.STRING, default: 'defaultString'},
|
||||
dateCol: {type: Realm.Types.DATE, default: new Date(1.111)},
|
||||
dataCol: {type: Realm.Types.DATA, default: new ArrayBuffer(1)},
|
||||
objectCol: {type: 'TestObject', default: [1]},
|
||||
nullObjectCol: {type: 'TestObject', default: null},
|
||||
arrayCol: {type: Realm.Types.LIST, objectType: 'TestObject', default: [[2]]},
|
||||
}
|
||||
};
|
||||
|
||||
exports.QueryObject = {
|
||||
|
Loading…
x
Reference in New Issue
Block a user