mirror of
https://github.com/status-im/realm-js.git
synced 2025-01-10 22:36:01 +00:00
Merge pull request #289 from realm/sk-accept-constructor
Accept constructor in create() and objects() methods
This commit is contained in:
commit
1a127b425b
@ -27,9 +27,9 @@ class Realm {
|
||||
* Create a new `Realm` instance using the provided `config`. If a Realm does not yet exist
|
||||
* at `config.path` (or {@link Realm.defaultPath} if not provided), then this constructor
|
||||
* will create it with the provided `config.schema` (which is _required_ in this case).
|
||||
* Otherwise, the instance will access the existing realm from the file at that path.
|
||||
* Otherwise, the instance will access the existing Realm from the file at that path.
|
||||
* In this case, `config.schema` is _optional_ or not have changed, unless
|
||||
* `config.schemaVersion` is incremented, in which case the realm will be automatically
|
||||
* `config.schemaVersion` is incremented, in which case the Realm will be automatically
|
||||
* migrated to use the new schema.
|
||||
* @param {Realm~Configuration} [config] - **Required** when first creating the Realm.
|
||||
*/
|
||||
@ -37,8 +37,7 @@ class Realm {
|
||||
|
||||
/**
|
||||
* Create a new Realm object of the given type and with the specified properties.
|
||||
* @param {string} type - The type of object as specified by its `name` in the
|
||||
* {@link Realm~ObjectSchema ObjectSchema} definition.
|
||||
* @param {Realm~ObjectType} type - The type of Realm object to create.
|
||||
* @param {Object} properties - Property values for all required properties without a
|
||||
* default value.
|
||||
* @param {boolean} [update=false] - Signals that an existing object with matching primary key
|
||||
@ -61,12 +60,11 @@ class Realm {
|
||||
|
||||
/**
|
||||
* Returns all objects of the given `type` in the Realm.
|
||||
* @param {string} type - The type of object as specified by its `name` in the
|
||||
* {@link Realm~ObjectSchema ObjectSchema} definition.
|
||||
* @param {Realm~ObjectType} type - The type of Realm objects to retrieve.
|
||||
* @throws {Error} If type passed into this method is invalid.
|
||||
* @returns {Realm.Results} that will live-update as objects are created and destroyed.
|
||||
*/
|
||||
objects(type, query, ...arg) {}
|
||||
objects(type) {}
|
||||
|
||||
/**
|
||||
* Add a listener `callback` for the specified event `name`.
|
||||
@ -116,12 +114,20 @@ Realm.defaultPath;
|
||||
* @type {Object}
|
||||
* @property {string} [path={@link Realm.defaultPath}] - The path to the file where the
|
||||
* Realm database should be stored.
|
||||
* @property {Realm~ObjectSchema[]} [schema] - Specifies all the object types in the realm.
|
||||
* **Required** when first creating realm at this `path`.
|
||||
* @property {Array<Realm~ObjectClass|Realm~ObjectSchema>} [schema] - Specifies all the
|
||||
* object types in this Realm. **Required** when first creating a Realm at this `path`.
|
||||
* @property {number} [schemaVersion] - **Required** (and must be incremented) after
|
||||
* changing the `schema`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* Realm objects will inherit methods, getters, and setters from the `prototype` of this
|
||||
* constructor.
|
||||
* @typedef Realm~ObjectClass
|
||||
* @type {Class}
|
||||
* @property {Realm~ObjectSchema} schema - Static property specifying object schema information.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @typedef Realm~ObjectSchema
|
||||
* @type {Object}
|
||||
@ -143,6 +149,14 @@ Realm.defaultPath;
|
||||
* @property {boolean} [optional] - Signals if this property may be assigned `null` or `undefined`.
|
||||
*/
|
||||
|
||||
/**
|
||||
* The type of an object may either be specified as a string equal to the `name` in a
|
||||
* {@link Realm~ObjectSchema ObjectSchema} definition, **or** a constructor that was specified
|
||||
* in the {@link Realm~Configuration configuration} `schema`.
|
||||
* @typedef Realm~ObjectType
|
||||
* @type {string|Realm~ObjectClass}
|
||||
*/
|
||||
|
||||
/**
|
||||
* A property type may be specified as one of the standard builtin types, or as an object type
|
||||
* inside the same schema.
|
||||
|
@ -74,6 +74,24 @@ export default class Realm {
|
||||
});
|
||||
}
|
||||
|
||||
create(type, ...args) {
|
||||
if (typeof type == 'function') {
|
||||
type = objects.typeForConstructor(this[keys.realm], type);
|
||||
}
|
||||
|
||||
let method = util.createMethod(objectTypes.REALM, 'create', true);
|
||||
return method.apply(this, [type, ...args]);
|
||||
}
|
||||
|
||||
objects(type, ...args) {
|
||||
if (typeof type == 'function') {
|
||||
type = objects.typeForConstructor(this[keys.realm], type);
|
||||
}
|
||||
|
||||
let method = util.createMethod(objectTypes.REALM, 'objects');
|
||||
return method.apply(this, [type, ...args]);
|
||||
}
|
||||
|
||||
addListener(name, callback) {
|
||||
if (typeof callback != 'function') {
|
||||
throw new Error('Realm.addListener must be passed a function!');
|
||||
@ -130,12 +148,10 @@ export default class Realm {
|
||||
// Non-mutating methods:
|
||||
util.createMethods(Realm.prototype, objectTypes.REALM, [
|
||||
'close',
|
||||
'objects',
|
||||
]);
|
||||
|
||||
// Mutating methods:
|
||||
util.createMethods(Realm.prototype, objectTypes.REALM, [
|
||||
'create',
|
||||
'delete',
|
||||
'deleteAll',
|
||||
], true);
|
||||
|
@ -53,3 +53,15 @@ export function create(realmId, info) {
|
||||
export function registerConstructors(realmId, constructors) {
|
||||
registeredConstructors[realmId] = constructors;
|
||||
}
|
||||
|
||||
export function typeForConstructor(realmId, constructor) {
|
||||
let constructors = registeredConstructors[realmId];
|
||||
|
||||
for (let name in constructors) {
|
||||
if (constructors[name] == constructor) {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
@ -254,11 +254,28 @@ JSValueRef RealmGetProperty(JSContextRef ctx, JSObjectRef object, JSStringRef pr
|
||||
return NULL;
|
||||
}
|
||||
|
||||
std::string RJSValidatedObjectTypeForValue(SharedRealm &realm, JSContextRef ctx, JSValueRef value) {
|
||||
if (JSValueIsObject(ctx, value) && JSObjectIsConstructor(ctx, (JSObjectRef)value)) {
|
||||
JSObjectRef constructor = (JSObjectRef)value;
|
||||
|
||||
for (auto pair : RJSConstructors(realm.get())) {
|
||||
if (pair.second == constructor) {
|
||||
return pair.first;
|
||||
}
|
||||
}
|
||||
|
||||
throw std::runtime_error("Constructor was not registered in the schema for this Realm");
|
||||
}
|
||||
|
||||
return RJSValidatedStringForValue(ctx, value, "objectType");
|
||||
}
|
||||
|
||||
JSValueRef RealmObjects(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
|
||||
try {
|
||||
RJSValidateArgumentCount(1, argumentCount);
|
||||
std::string className = RJSValidatedStringForValue(ctx, arguments[0], "objectType");
|
||||
RJSValidateArgumentCount(argumentCount, 1);
|
||||
|
||||
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
std::string className = RJSValidatedObjectTypeForValue(sharedRealm, ctx, arguments[0]);
|
||||
return RJSResultsCreate(ctx, sharedRealm, className);
|
||||
}
|
||||
catch (std::exception &exp) {
|
||||
@ -296,10 +313,12 @@ JSValueRef RealmCreateObject(JSContextRef ctx, JSObjectRef function, JSObjectRef
|
||||
try {
|
||||
RJSValidateArgumentRange(argumentCount, 2, 3);
|
||||
|
||||
std::string className = RJSValidatedStringForValue(ctx, arguments[0], "objectType");
|
||||
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
|
||||
auto object_schema = sharedRealm->config().schema->find(className);
|
||||
if (object_schema == sharedRealm->config().schema->end()) {
|
||||
std::string className = RJSValidatedObjectTypeForValue(sharedRealm, ctx, arguments[0]);
|
||||
auto &schema = sharedRealm->config().schema;
|
||||
auto object_schema = schema->find(className);
|
||||
|
||||
if (object_schema == schema->end()) {
|
||||
*jsException = RJSMakeError(ctx, "Object type '" + className + "' not found in schema.");
|
||||
return NULL;
|
||||
}
|
||||
|
@ -136,16 +136,10 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob
|
||||
|
||||
JSObjectRef objectConstructor = NULL;
|
||||
|
||||
if (JSObjectIsFunction(ctx, objectSchemaObject) || JSObjectIsConstructor(ctx, objectSchemaObject)) {
|
||||
if (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);
|
||||
if (!JSValueIsUndefined(ctx, subSchemaValue)) {
|
||||
objectSchemaObject = RJSValidatedValueToObject(ctx, subSchemaValue);
|
||||
}
|
||||
}
|
||||
|
||||
ObjectDefaults objectDefaults;
|
||||
ObjectSchema objectSchema;
|
||||
|
@ -317,6 +317,13 @@ module.exports = BaseTest.extend({
|
||||
|
||||
// Should have been multiplied by 100 in the constructor.
|
||||
TestCase.assertEqual(object.intCol, 100);
|
||||
|
||||
// Should be able to create object by passing in constructor.
|
||||
object = realm.create(CustomObject, {intCol: 2});
|
||||
TestCase.assertTrue(object instanceof CustomObject);
|
||||
TestCase.assertTrue(Object.getPrototypeOf(object) == CustomObject.prototype);
|
||||
TestCase.assertEqual(customCreated, 2);
|
||||
TestCase.assertEqual(object.intCol, 200);
|
||||
});
|
||||
|
||||
TestCase.assertThrows(function() {
|
||||
@ -324,6 +331,16 @@ module.exports = BaseTest.extend({
|
||||
realm.create('InvalidObject', {intCol: 1});
|
||||
});
|
||||
});
|
||||
|
||||
// Only the original constructor should be valid.
|
||||
function InvalidCustomObject() {}
|
||||
InvalidCustomObject.schema = CustomObject.schema;
|
||||
|
||||
TestCase.assertThrows(function() {
|
||||
realm.write(function() {
|
||||
realm.create(InvalidCustomObject, {intCol: 1});
|
||||
});
|
||||
});
|
||||
},
|
||||
|
||||
testRealmDelete: function() {
|
||||
@ -389,6 +406,7 @@ module.exports = BaseTest.extend({
|
||||
|
||||
testRealmObjects: function() {
|
||||
var realm = new Realm({schema: [schemas.PersonObject, schemas.DefaultValues, schemas.TestObject]});
|
||||
|
||||
realm.write(function() {
|
||||
realm.create('PersonObject', {name: 'Ari', age: 10});
|
||||
realm.create('PersonObject', {name: 'Tim', age: 11});
|
||||
@ -396,18 +414,28 @@ module.exports = BaseTest.extend({
|
||||
realm.create('PersonObject', {name: 'Alex', age: 12, married: true});
|
||||
});
|
||||
|
||||
TestCase.assertThrows(function() {
|
||||
// Should be able to pass constructor for getting objects.
|
||||
var objects = realm.objects(schemas.PersonObject);
|
||||
TestCase.assertTrue(objects[0] instanceof schemas.PersonObject);
|
||||
|
||||
function InvalidPerson() {}
|
||||
InvalidPerson.schema = schemas.PersonObject.schema;
|
||||
|
||||
TestCase.assertThrows(function() {
|
||||
realm.objects();
|
||||
});
|
||||
TestCase.assertThrows(function() {
|
||||
TestCase.assertThrows(function() {
|
||||
realm.objects([]);
|
||||
});
|
||||
TestCase.assertThrows(function() {
|
||||
TestCase.assertThrows(function() {
|
||||
realm.objects('InvalidClass');
|
||||
});
|
||||
TestCase.assertThrows(function() {
|
||||
TestCase.assertThrows(function() {
|
||||
realm.objects('PersonObject', 'truepredicate');
|
||||
});
|
||||
TestCase.assertThrows(function() {
|
||||
realm.objects(InvalidPerson);
|
||||
});
|
||||
},
|
||||
|
||||
testNotifications: function() {
|
||||
|
Loading…
x
Reference in New Issue
Block a user