Add sorted() method to List

This commit is contained in:
Scott Kyle 2016-02-18 13:41:11 -08:00
parent d847fbceb1
commit 5332131c14
8 changed files with 129 additions and 72 deletions

View File

@ -18,6 +18,7 @@ class List {}
// Non-mutating methods:
util.createMethods(List.prototype, objectTypes.LIST, [
'filtered',
'sorted',
'snapshot',
]);

View File

@ -15,8 +15,8 @@ class Results {}
util.createMethods(Results.prototype, constants.objectTypes.RESULTS, [
'filtered',
'snapshot',
'sorted',
'snapshot',
]);
function create(realmId, info) {

View File

@ -191,6 +191,7 @@ JSValueRef ListStaticResults(JSContextRef ctx, JSObjectRef function, JSObjectRef
try {
List *list = RJSGetInternal<List *>(thisObject);
RJSValidateArgumentCount(argumentCount, 0);
return RJSResultsCreate(ctx, list->realm(), list->get_object_schema(), std::move(list->get_query()), false);
}
catch (std::exception &exp) {
@ -204,10 +205,10 @@ JSValueRef ListStaticResults(JSContextRef ctx, JSObjectRef function, JSObjectRef
JSValueRef ListFiltered(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
List *list = RJSGetInternal<List *>(thisObject);
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
return RJSResultsCreate(ctx, sharedRealm, list->get_object_schema(), std::move(list->get_query()), argumentCount, arguments);
return RJSResultsCreateFiltered(ctx, sharedRealm, list->get_object_schema(), std::move(list->get_query()), argumentCount, arguments);
}
catch (std::exception &exp) {
if (jsException) {
@ -217,7 +218,23 @@ JSValueRef ListFiltered(JSContextRef ctx, JSObjectRef function, JSObjectRef this
return NULL;
}
JSObjectRef RJSListCreate(JSContextRef ctx, realm::List &list) {
JSValueRef ListSorted(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
List *list = RJSGetInternal<List *>(thisObject);
RJSValidateArgumentRange(argumentCount, 1, 2);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
return RJSResultsCreateSorted(ctx, sharedRealm, list->get_object_schema(), std::move(list->get_query()), argumentCount, arguments);
}
catch (std::exception &exp) {
if (jsException) {
*jsException = RJSMakeError(ctx, exp);
}
}
return NULL;
}
JSObjectRef RJSListCreate(JSContextRef ctx, List &list) {
return RJSWrapObject<List *>(ctx, RJSListClass(), new List(list));
}
@ -228,6 +245,7 @@ static const JSStaticFunction RJSListFuncs[] = {
{"unshift", ListUnshift, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"splice", ListSplice, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"filtered", ListFiltered, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"sorted", ListSorted, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{"snapshot", ListStaticResults, kJSPropertyAttributeReadOnly | kJSPropertyAttributeDontEnum | kJSPropertyAttributeDontDelete},
{NULL, NULL},
};

View File

@ -96,54 +96,8 @@ JSValueRef ResultsSorted(JSContextRef ctx, JSObjectRef function, JSObjectRef thi
Results *results = RJSGetInternal<Results *>(thisObject);
RJSValidateArgumentRange(argumentCount, 1, 2);
size_t prop_count;
std::vector<std::string> prop_names;
std::vector<bool> ascending;
if (RJSIsValueArray(ctx, arguments[0])) {
RJSValidateArgumentCount(argumentCount, 1, "Second argument is not allowed if passed an array of sort descriptors");
JSObjectRef js_prop_names = RJSValidatedValueToObject(ctx, arguments[0]);
prop_count = RJSValidatedListLength(ctx, js_prop_names);
if (!prop_count) {
throw std::invalid_argument("Sort descriptor array must not be empty");
}
prop_names.resize(prop_count);
ascending.resize(prop_count);
for (unsigned int i = 0; i < prop_count; i++) {
JSValueRef val = RJSValidatedPropertyAtIndex(ctx, js_prop_names, i);
if (RJSIsValueArray(ctx, val)) {
prop_names[i] = RJSValidatedStringForValue(ctx, RJSValidatedPropertyAtIndex(ctx, (JSObjectRef)val, 0));
ascending[i] = !JSValueToBoolean(ctx, RJSValidatedPropertyAtIndex(ctx, (JSObjectRef)val, 1));
}
else {
prop_names[i] = RJSValidatedStringForValue(ctx, val);
ascending[i] = true;
}
}
}
else {
prop_count = 1;
prop_names.push_back(RJSValidatedStringForValue(ctx, arguments[0]));
ascending.push_back(argumentCount == 1 ? true : !JSValueToBoolean(ctx, arguments[1]));
}
std::vector<size_t> columns(prop_count);
size_t index = 0;
for (std::string prop_name : prop_names) {
const Property *prop = results->get_object_schema().property_for_name(prop_name);
if (!prop) {
throw std::runtime_error("Property '" + prop_name + "' does not exist on object type '" + results->get_object_schema().name + "'");
}
columns[index++] = prop->table_column;
}
results = new Results(results->sort({std::move(columns), std::move(ascending)}));
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), results);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
return RJSResultsCreateSorted(ctx, sharedRealm, results->get_object_schema(), std::move(results->get_query()), argumentCount, arguments);
}
catch (std::exception &exp) {
if (jsException) {
@ -153,14 +107,13 @@ JSValueRef ResultsSorted(JSContextRef ctx, JSObjectRef function, JSObjectRef thi
return NULL;
}
JSValueRef ResultsFiltered(JSContextRef ctx, JSObjectRef function, JSObjectRef thisObject, size_t argumentCount, const JSValueRef arguments[], JSValueRef* jsException) {
try {
Results *results = RJSGetInternal<Results *>(thisObject);
RJSValidateArgumentCountIsAtLeast(argumentCount, 1);
SharedRealm sharedRealm = *RJSGetInternal<SharedRealm *>(thisObject);
return RJSResultsCreate(ctx, sharedRealm, results->get_object_schema(), std::move(results->get_query()), argumentCount, arguments);
return RJSResultsCreateFiltered(ctx, sharedRealm, results->get_object_schema(), std::move(results->get_query()), argumentCount, arguments);
}
catch (std::exception &exp) {
if (jsException) {
@ -194,7 +147,14 @@ JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string cl
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), new Results(realm, *object_schema, std::move(query)));
}
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, const realm::ObjectSchema &objectSchema, realm::Query query, size_t argumentCount, const JSValueRef arguments[]) {
JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, const ObjectSchema &objectSchema, Query query, bool live) {
Results *results = new Results(realm, objectSchema, std::move(query));
results->set_live(live);
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), results);
}
JSObjectRef RJSResultsCreateFiltered(JSContextRef ctx, SharedRealm realm, const ObjectSchema &objectSchema, Query query, size_t argumentCount, const JSValueRef arguments[]) {
std::string queryString = RJSValidatedStringForValue(ctx, arguments[0], "predicate");
std::vector<JSValueRef> args(argumentCount - 1);
for (size_t i = 1; i < argumentCount; i++) {
@ -208,10 +168,56 @@ JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, const r
return RJSResultsCreate(ctx, realm, objectSchema, std::move(query));
}
JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, const ObjectSchema &objectSchema, Query query, bool live) {
Results *results = new Results(realm, objectSchema, std::move(query));
results->set_live(live);
JSObjectRef RJSResultsCreateSorted(JSContextRef ctx, SharedRealm realm, const ObjectSchema &objectSchema, Query query, size_t argumentCount, const JSValueRef arguments[]) {
size_t prop_count;
std::vector<std::string> prop_names;
std::vector<bool> ascending;
if (RJSIsValueArray(ctx, arguments[0])) {
RJSValidateArgumentCount(argumentCount, 1, "Second argument is not allowed if passed an array of sort descriptors");
JSObjectRef js_prop_names = RJSValidatedValueToObject(ctx, arguments[0]);
prop_count = RJSValidatedListLength(ctx, js_prop_names);
if (!prop_count) {
throw std::invalid_argument("Sort descriptor array must not be empty");
}
prop_names.resize(prop_count);
ascending.resize(prop_count);
for (unsigned int i = 0; i < prop_count; i++) {
JSValueRef val = RJSValidatedPropertyAtIndex(ctx, js_prop_names, i);
if (RJSIsValueArray(ctx, val)) {
prop_names[i] = RJSValidatedStringForValue(ctx, RJSValidatedPropertyAtIndex(ctx, (JSObjectRef)val, 0));
ascending[i] = !JSValueToBoolean(ctx, RJSValidatedPropertyAtIndex(ctx, (JSObjectRef)val, 1));
}
else {
prop_names[i] = RJSValidatedStringForValue(ctx, val);
ascending[i] = true;
}
}
}
else {
RJSValidateArgumentRange(argumentCount, 1, 2);
prop_count = 1;
prop_names.push_back(RJSValidatedStringForValue(ctx, arguments[0]));
ascending.push_back(argumentCount == 1 ? true : !JSValueToBoolean(ctx, arguments[1]));
}
std::vector<size_t> columns(prop_count);
size_t index = 0;
for (std::string prop_name : prop_names) {
const Property *prop = objectSchema.property_for_name(prop_name);
if (!prop) {
throw std::runtime_error("Property '" + prop_name + "' does not exist on object type '" + objectSchema.name + "'");
}
columns[index++] = prop->table_column;
}
Results *results = new Results(realm, objectSchema, std::move(query), {std::move(columns), std::move(ascending)});
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), results);
}

View File

@ -16,6 +16,6 @@ namespace realm {
JSClassRef RJSResultsClass();
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className);
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, std::string className, std::string query, std::vector<JSValueRef> args);
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, const realm::ObjectSchema &objectSchema, realm::Query query, size_t argumentCount, const JSValueRef arguments[]);
JSObjectRef RJSResultsCreate(JSContextRef ctx, realm::SharedRealm realm, const realm::ObjectSchema &objectSchema, realm::Query query, bool live = true);
JSObjectRef RJSResultsCreateFiltered(JSContextRef ctx, realm::SharedRealm realm, const realm::ObjectSchema &objectSchema, realm::Query query, size_t argumentCount, const JSValueRef arguments[]);
JSObjectRef RJSResultsCreateSorted(JSContextRef ctx, realm::SharedRealm realm, const realm::ObjectSchema &objectSchema, realm::Query query, size_t argumentCount, const JSValueRef arguments[]);

View File

@ -445,29 +445,54 @@ module.exports = BaseTest.extend({
},
testListFiltered: function() {
var personListSchema = {
name: 'PersonList',
properties: {
list: {type: 'list', objectType: 'PersonObject'}
}
};
var realm = new Realm({schema: [schemas.PersonObject, personListSchema]});
var listObject;
var realm = new Realm({schema: [schemas.PersonObject, schemas.PersonList]});
var list;
realm.write(function() {
listObject = realm.create('PersonList', {list: [
var object = realm.create('PersonList', {list: [
{name: 'Ari', age: 10},
{name: 'Tim', age: 11},
{name: 'Bjarne', age: 12},
{name: 'Alex', age: 12, married: true}
]});
realm.create('PersonObject', {name: 'NotInList', age: 10});
list = object.list;
});
var list = listObject.list;
TestCase.assertEqual(list.filtered("truepredicate").length, 4);
TestCase.assertEqual(list.filtered('age = 11')[0].name, 'Tim');
TestCase.assertEqual(list.filtered('age = 12').length, 2);
TestCase.assertEqual(list.filtered('age > 10 && age < 13').length, 3);
TestCase.assertEqual(list.filtered('age > 10').filtered('age < 13').length, 3);
},
testListSorted: function() {
var realm = new Realm({schema: [schemas.PersonObject, schemas.PersonList]});
var list;
realm.write(function() {
var object = realm.create('PersonList', {list: [
{name: 'Ari', age: 10},
{name: 'Tim', age: 11},
{name: 'Bjarne', age: 12},
{name: 'Alex', age: 12, married: true}
]});
realm.create('PersonObject', {name: 'NotInList', age: 10});
list = object.list;
});
var names = function(results, prop) {
return Array.prototype.map.call(results, function(object) {
return object.name;
});
};
var objects = list.sorted('name', true);
TestCase.assertArraysEqual(names(objects), ['Tim', 'Bjarne', 'Ari', 'Alex']);
objects = list.sorted(['age', 'name']);
TestCase.assertArraysEqual(names(objects), ['Ari', 'Tim', 'Alex', 'Bjarne']);
},
});

View File

@ -135,7 +135,7 @@ module.exports = BaseTest.extend({
realm.objects('PersonObject').filtered("invalidQuery");
});
},
testSort: function() {
testResultsSorted: function() {
var realm = new Realm({schema: [schemas.IntPrimary]});
var objects = realm.objects('IntPrimaryObject');

View File

@ -27,6 +27,13 @@ PersonObject.prototype.description = function() {
};
exports.PersonObject = PersonObject;
exports.PersonList = {
name: 'PersonList',
properties: {
list: {type: 'list', objectType: 'PersonObject'},
}
};
exports.BasicTypes = {
name: 'BasicTypesObject',
properties: {