mirror of
https://github.com/status-im/realm-js.git
synced 2025-01-10 22:36:01 +00:00
The schema property should be directly on constructor
The constructor is now also called with `this` set as the constructed object. Fixes #232
This commit is contained in:
parent
c39c62d0db
commit
b34e52b290
@ -32,6 +32,13 @@ function create(realmId, info) {
|
||||
});
|
||||
});
|
||||
|
||||
if (constructor) {
|
||||
let result = constructor.call(object);
|
||||
if (result != null && result != object) {
|
||||
throw new Error('Realm object constructor must not return another value');
|
||||
}
|
||||
}
|
||||
|
||||
return object;
|
||||
}
|
||||
|
||||
|
25
lib/realm.js
25
lib/realm.js
@ -20,16 +20,27 @@ rpc.registerTypeConverter(objectTypes.RESULTS, results.create);
|
||||
|
||||
class Realm {
|
||||
constructor(config) {
|
||||
let schema = typeof config == 'object' && config.schema;
|
||||
let schemas = typeof config == 'object' && config.schema;
|
||||
let constructors = {};
|
||||
|
||||
for (let i = 0, len = schema ? schema.length : 0; i < len; i++) {
|
||||
let item = schema[i];
|
||||
let proto = item.prototype;
|
||||
for (let i = 0, len = schemas ? schemas.length : 0; i < len; i++) {
|
||||
let item = schemas[i];
|
||||
|
||||
if (proto && proto.schema) {
|
||||
schema.splice(i, 1, proto.schema);
|
||||
constructors[proto.schema.name] = item;
|
||||
if (typeof item == 'function') {
|
||||
let schema = item.schema;
|
||||
if (!schema || typeof schema != 'object') {
|
||||
throw new Error("Realm object constructor must have 'schema' property");
|
||||
}
|
||||
|
||||
let {name, properties} = schema;
|
||||
if (!name || typeof name != 'string') {
|
||||
throw new Error("Realm object schema must have 'name' property");
|
||||
} else if (!properties || typeof properties != 'object') {
|
||||
throw new Error("Realm object schema must have 'properties' property");
|
||||
}
|
||||
|
||||
schemas.splice(i, 1, schema);
|
||||
constructors[name] = item;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -58,8 +58,24 @@ JSClassRef RJSObjectClass() {
|
||||
}
|
||||
|
||||
JSObjectRef RJSObjectCreate(JSContextRef ctx, Object object) {
|
||||
JSValueRef prototype = RJSPrototypes(object.realm().get())[object.get_object_schema().name];
|
||||
static JSStringRef prototypeString = JSStringCreateWithUTF8CString("prototype");
|
||||
|
||||
JSObjectRef constructor = RJSConstructors(object.realm().get())[object.get_object_schema().name];
|
||||
JSObjectRef prototype = constructor ? RJSValidatedObjectProperty(ctx, constructor, prototypeString) : NULL;
|
||||
JSObjectRef jsObject = RJSWrapObject(ctx, RJSObjectClass(), new Object(object), prototype);
|
||||
|
||||
if (constructor) {
|
||||
JSValueRef exception = NULL;
|
||||
JSValueRef result = JSObjectCallAsFunction(ctx, constructor, jsObject, 0, NULL, &exception);
|
||||
|
||||
if (exception) {
|
||||
throw RJSException(ctx, exception);
|
||||
}
|
||||
else if (result != jsObject && !JSValueIsNull(ctx, result) && !JSValueIsUndefined(ctx, result)) {
|
||||
throw std::runtime_error("Realm object constructor must not return another value");
|
||||
}
|
||||
}
|
||||
|
||||
return jsObject;
|
||||
}
|
||||
|
||||
|
@ -39,8 +39,8 @@ public:
|
||||
~RJSRealmDelegate() {
|
||||
remove_all_notifications();
|
||||
|
||||
for (auto prototype : m_prototypes) {
|
||||
JSValueUnprotect(m_context, prototype.second);
|
||||
for (auto constructor : m_constructors) {
|
||||
JSValueUnprotect(m_context, constructor.second);
|
||||
}
|
||||
for (auto objectDefaults : m_defaults) {
|
||||
for (auto value : objectDefaults.second) {
|
||||
@ -70,7 +70,7 @@ public:
|
||||
}
|
||||
|
||||
std::map<std::string, ObjectDefaults> m_defaults;
|
||||
std::map<std::string, JSValueRef> m_prototypes;
|
||||
std::map<std::string, JSObjectRef> m_constructors;
|
||||
|
||||
private:
|
||||
std::set<JSObjectRef> m_notifications;
|
||||
@ -101,8 +101,8 @@ std::map<std::string, ObjectDefaults> &RJSDefaults(Realm *realm) {
|
||||
return static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->m_defaults;
|
||||
}
|
||||
|
||||
std::map<std::string, JSValueRef> &RJSPrototypes(Realm *realm) {
|
||||
return static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->m_prototypes;
|
||||
std::map<std::string, JSObjectRef> &RJSConstructors(Realm *realm) {
|
||||
return static_cast<RJSRealmDelegate *>(realm->m_binding_context.get())->m_constructors;
|
||||
}
|
||||
|
||||
// static std::string s_defaultPath = realm::default_realm_file_directory() + "/default.realm";
|
||||
@ -137,7 +137,7 @@ JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t a
|
||||
try {
|
||||
Realm::Config config;
|
||||
std::map<std::string, realm::ObjectDefaults> defaults;
|
||||
std::map<std::string, JSValueRef> prototypes;
|
||||
std::map<std::string, JSObjectRef> constructors;
|
||||
switch (argumentCount) {
|
||||
case 0:
|
||||
config.path = RJSDefaultPath();
|
||||
@ -163,7 +163,7 @@ JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t a
|
||||
static JSStringRef schemaString = JSStringCreateWithUTF8CString("schema");
|
||||
JSValueRef schemaValue = RJSValidatedPropertyValue(ctx, object, schemaString);
|
||||
if (!JSValueIsUndefined(ctx, schemaValue)) {
|
||||
config.schema.reset(new Schema(RJSParseSchema(ctx, RJSValidatedValueToObject(ctx, schemaValue), defaults, prototypes)));
|
||||
config.schema.reset(new Schema(RJSParseSchema(ctx, RJSValidatedValueToObject(ctx, schemaValue), defaults, constructors)));
|
||||
}
|
||||
|
||||
static JSStringRef schemaVersionString = JSStringCreateWithUTF8CString("schemaVersion");
|
||||
@ -187,7 +187,7 @@ JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t a
|
||||
realm->m_binding_context.reset(new RJSRealmDelegate(realm, JSContextGetGlobalContext(ctx)));
|
||||
}
|
||||
RJSDefaults(realm.get()) = defaults;
|
||||
RJSPrototypes(realm.get()) = prototypes;
|
||||
RJSConstructors(realm.get()) = constructors;
|
||||
return RJSWrapObject<SharedRealm *>(ctx, RJSRealmClass(), new SharedRealm(realm));
|
||||
}
|
||||
catch (std::exception &ex) {
|
||||
|
@ -19,4 +19,4 @@ std::string RJSDefaultPath();
|
||||
void RJSSetDefaultPath(std::string path);
|
||||
|
||||
std::map<std::string, realm::ObjectDefaults> &RJSDefaults(realm::Realm *realm);
|
||||
std::map<std::string, JSValueRef> &RJSPrototypes(realm::Realm *realm);
|
||||
std::map<std::string, JSObjectRef> &RJSConstructors(realm::Realm *realm);
|
||||
|
@ -114,19 +114,17 @@ static inline Property RJSParseProperty(JSContextRef ctx, JSValueRef propertyAtt
|
||||
return prop;
|
||||
}
|
||||
|
||||
static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef objectSchemaObject, std::map<std::string, realm::ObjectDefaults> &defaults, std::map<std::string, JSValueRef> &prototypes) {
|
||||
static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef objectSchemaObject, std::map<std::string, realm::ObjectDefaults> &defaults, std::map<std::string, JSObjectRef> &constructors) {
|
||||
static JSStringRef nameString = JSStringCreateWithUTF8CString("name");
|
||||
static JSStringRef primaryString = JSStringCreateWithUTF8CString("primaryKey");
|
||||
static JSStringRef prototypeString = JSStringCreateWithUTF8CString("prototype");
|
||||
static JSStringRef propertiesString = JSStringCreateWithUTF8CString("properties");
|
||||
static JSStringRef schemaString = JSStringCreateWithUTF8CString("schema");
|
||||
|
||||
JSObjectRef prototypeObject = NULL;
|
||||
JSValueRef prototypeValue = RJSValidatedPropertyValue(ctx, objectSchemaObject, prototypeString);
|
||||
JSObjectRef objectConstructor = NULL;
|
||||
|
||||
if (!JSValueIsUndefined(ctx, prototypeValue)) {
|
||||
prototypeObject = RJSValidatedValueToObject(ctx, prototypeValue);
|
||||
objectSchemaObject = RJSValidatedObjectProperty(ctx, prototypeObject, schemaString, "Realm object prototype must have a 'schema' property.");
|
||||
if (JSObjectIsFunction(ctx, objectSchemaObject) || JSObjectIsConstructor(ctx, objectSchemaObject)) {
|
||||
objectConstructor = objectSchemaObject;
|
||||
objectSchemaObject = RJSValidatedObjectProperty(ctx, objectConstructor, schemaString, "Realm object constructor must have a 'schema' property.");
|
||||
}
|
||||
else {
|
||||
JSValueRef subSchemaValue = RJSValidatedPropertyValue(ctx, objectSchemaObject, schemaString);
|
||||
@ -170,9 +168,9 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob
|
||||
}
|
||||
|
||||
// Store prototype so that objects of this type will have their prototype set to this prototype object.
|
||||
if (prototypeObject) {
|
||||
JSValueProtect(ctx, prototypeObject);
|
||||
prototypes[objectSchema.name] = std::move(prototypeObject);
|
||||
if (objectConstructor) {
|
||||
JSValueProtect(ctx, objectConstructor);
|
||||
constructors[objectSchema.name] = std::move(objectConstructor);
|
||||
}
|
||||
|
||||
defaults.emplace(objectSchema.name, std::move(objectDefaults));
|
||||
@ -180,12 +178,12 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob
|
||||
return objectSchema;
|
||||
}
|
||||
|
||||
realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject, std::map<std::string, realm::ObjectDefaults> &defaults, std::map<std::string, JSValueRef> &prototypes) {
|
||||
realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject, std::map<std::string, realm::ObjectDefaults> &defaults, std::map<std::string, JSObjectRef> &constructors) {
|
||||
std::vector<ObjectSchema> schema;
|
||||
size_t length = RJSValidatedListLength(ctx, jsonObject);
|
||||
for (unsigned int i = 0; i < length; i++) {
|
||||
JSObjectRef jsonObjectSchema = RJSValidatedObjectAtIndex(ctx, jsonObject, i);
|
||||
ObjectSchema objectSchema = RJSParseObjectSchema(ctx, jsonObjectSchema, defaults, prototypes);
|
||||
ObjectSchema objectSchema = RJSParseObjectSchema(ctx, jsonObjectSchema, defaults, constructors);
|
||||
schema.emplace_back(std::move(objectSchema));
|
||||
}
|
||||
|
||||
|
@ -15,4 +15,4 @@ namespace realm {
|
||||
JSClassRef RJSSchemaClass();
|
||||
JSObjectRef RJSSchemaCreate(JSContextRef ctx, realm::Schema *schema);
|
||||
|
||||
realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject, std::map<std::string, realm::ObjectDefaults> &defaults, std::map<std::string, JSValueRef> &prototypes);
|
||||
realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject, std::map<std::string, realm::ObjectDefaults> &defaults, std::map<std::string, JSObjectRef> &constructors);
|
||||
|
@ -261,6 +261,49 @@ module.exports = BaseTest.extend({
|
||||
});
|
||||
},
|
||||
|
||||
testRealmCreateWithConstructor: function() {
|
||||
var customCreated = 0;
|
||||
|
||||
function CustomObject() {
|
||||
customCreated++;
|
||||
}
|
||||
CustomObject.schema = {
|
||||
name: 'CustomObject',
|
||||
properties: {
|
||||
intCol: 'int'
|
||||
}
|
||||
}
|
||||
|
||||
function InvalidObject() {
|
||||
return {};
|
||||
}
|
||||
TestCase.assertThrows(function() {
|
||||
new Realm({schema: [InvalidObject]});
|
||||
});
|
||||
|
||||
InvalidObject.schema = {
|
||||
name: 'InvalidObject',
|
||||
properties: {
|
||||
intCol: 'int'
|
||||
}
|
||||
}
|
||||
|
||||
var realm = new Realm({schema: [CustomObject, InvalidObject]});
|
||||
|
||||
realm.write(function() {
|
||||
var object = realm.create('CustomObject', {intCol: 1});
|
||||
TestCase.assertTrue(object instanceof CustomObject);
|
||||
TestCase.assertTrue(Object.getPrototypeOf(object) == CustomObject.prototype);
|
||||
TestCase.assertEqual(customCreated, 1);
|
||||
});
|
||||
|
||||
TestCase.assertThrows(function() {
|
||||
realm.write(function() {
|
||||
realm.create('InvalidObject', {intCol: 1});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
testRealmDelete: function() {
|
||||
var realm = new Realm({schema: [schemas.TestObject]});
|
||||
|
||||
|
@ -14,7 +14,7 @@ exports.TestObject = {
|
||||
};
|
||||
|
||||
function PersonObject() {}
|
||||
PersonObject.prototype.schema = {
|
||||
PersonObject.schema = {
|
||||
name: 'PersonObject',
|
||||
properties: {
|
||||
name: Realm.Types.STRING,
|
||||
|
Loading…
x
Reference in New Issue
Block a user