Allow sortedBy to accept array of properties

It now optionally accepts an array of properties for both parameters and the tests have been updated to reflect new capabilities.
This commit is contained in:
Scott Kyle 2016-01-13 02:40:26 -08:00
parent 249bcd8f3f
commit 76865d0da4
3 changed files with 99 additions and 32 deletions

View File

@ -95,19 +95,50 @@ JSValueRef ResultsSorted(JSContextRef ctx, JSObjectRef function, JSObjectRef thi
try {
Results *results = RJSGetInternal<Results *>(thisObject);
RJSValidateArgumentRange(argumentCount, 1, 2);
size_t prop_count;
std::vector<std::string> prop_names;
std::string propName = RJSValidatedStringForValue(ctx, arguments[0]);
const Property *prop = results->get_object_schema().property_for_name(propName);
if (!prop) {
throw std::runtime_error("Property '" + propName + "' does not exist on object type '" + results->get_object_schema().name + "'");
if (RJSIsValueArray(ctx, arguments[0])) {
JSObjectRef js_prop_names = RJSValidatedValueToObject(ctx, arguments[0]);
prop_count = RJSValidatedListLength(ctx, js_prop_names);
prop_names.resize(prop_count);
for (unsigned int i = 0; i < prop_count; i++) {
prop_names[i] = RJSValidatedStringForValue(ctx, RJSValidatedPropertyAtIndex(ctx, js_prop_names, i));
}
}
else {
prop_count = 1;
prop_names.push_back(RJSValidatedStringForValue(ctx, arguments[0]));
}
std::vector<size_t> columns(prop_count);
std::vector<bool> ascending(prop_count, true);
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;
}
bool ascending = true;
if (argumentCount == 2) {
ascending = !JSValueToBoolean(ctx, arguments[1]);
if (RJSIsValueArray(ctx, arguments[1])) {
JSObjectRef js_reverse = RJSValidatedValueToObject(ctx, arguments[1]);
size_t js_reverse_count = std::min(RJSValidatedListLength(ctx, js_reverse), prop_count);
for (unsigned int i = 0; i < js_reverse_count; i++) {
ascending[i] = !JSValueToBoolean(ctx, RJSValidatedPropertyAtIndex(ctx, js_reverse, i));
}
}
else if (JSValueToBoolean(ctx, arguments[1])) {
ascending.assign(prop_count, false);
}
}
results = new Results(results->sort({{prop->table_column}, {ascending}}));
results = new Results(results->sort({std::move(columns), std::move(ascending)}));
return RJSWrapObject<Results *>(ctx, RJSResultsClass(), results);
}
catch (std::exception &exp) {

View File

@ -143,6 +143,15 @@ static inline JSValueRef RJSValidatedPropertyValue(JSContextRef ctx, JSObjectRef
return propertyValue;
}
static inline JSValueRef RJSValidatedPropertyAtIndex(JSContextRef ctx, JSObjectRef object, unsigned int index) {
JSValueRef exception = NULL;
JSValueRef propertyValue = JSObjectGetPropertyAtIndex(ctx, object, index, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
return propertyValue;
}
static inline JSObjectRef RJSValidatedObjectProperty(JSContextRef ctx, JSObjectRef object, JSStringRef property, const char *err = NULL) {
JSValueRef propertyValue = RJSValidatedPropertyValue(ctx, object, property);
if (JSValueIsUndefined(ctx, propertyValue)) {
@ -152,12 +161,7 @@ static inline JSObjectRef RJSValidatedObjectProperty(JSContextRef ctx, JSObjectR
}
static inline JSObjectRef RJSValidatedObjectAtIndex(JSContextRef ctx, JSObjectRef object, unsigned int index) {
JSValueRef exception = NULL;
JSValueRef objectValue = JSObjectGetPropertyAtIndex(ctx, object, index, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
return RJSValidatedValueToObject(ctx, objectValue);
return RJSValidatedValueToObject(ctx, RJSValidatedPropertyAtIndex(ctx, object, index));
}
static inline std::string RJSValidatedStringProperty(JSContextRef ctx, JSObjectRef object, JSStringRef property) {

View File

@ -136,29 +136,61 @@ module.exports = BaseTest.extend({
});
},
testSort: function() {
var realm = new Realm({schema: [schemas.TestObject]});
var objects = realm.objects('TestObject');
var realm = new Realm({schema: [schemas.IntPrimary]});
var objects = realm.objects('IntPrimaryObject');
realm.write(function() {
realm.create('TestObject', {doubleCol: 2});
realm.create('TestObject', {doubleCol: 3});
realm.create('TestObject', {doubleCol: 1});
realm.create('TestObject', {doubleCol: 4});
realm.create('TestObject', {doubleCol: 0});
realm.create('IntPrimaryObject', {primaryCol: 2, valueCol: 'a'});
realm.create('IntPrimaryObject', {primaryCol: 3, valueCol: 'a'});
realm.create('IntPrimaryObject', {primaryCol: 1, valueCol: 'b'});
realm.create('IntPrimaryObject', {primaryCol: 4, valueCol: 'c'});
realm.create('IntPrimaryObject', {primaryCol: 0, valueCol: 'c'});
});
objects = objects.sortedBy('doubleCol');
TestCase.assertEqual(objects[0].doubleCol, 0);
TestCase.assertEqual(objects[1].doubleCol, 1);
TestCase.assertEqual(objects[2].doubleCol, 2);
TestCase.assertEqual(objects[3].doubleCol, 3);
TestCase.assertEqual(objects[4].doubleCol, 4);
var primaries = function(results, prop) {
return Array.prototype.map.call(results, function(object) {
return object.primaryCol;
});
};
objects = objects.sortedBy('doubleCol', true);
TestCase.assertEqual(objects[0].doubleCol, 4);
TestCase.assertEqual(objects[1].doubleCol, 3);
TestCase.assertEqual(objects[2].doubleCol, 2);
TestCase.assertEqual(objects[3].doubleCol, 1);
TestCase.assertEqual(objects[4].doubleCol, 0);
objects = objects.sortedBy('primaryCol');
TestCase.assertArraysEqual(primaries(objects), [0, 1, 2, 3, 4]);
objects = objects.sortedBy('primaryCol', true);
TestCase.assertArraysEqual(primaries(objects), [4, 3, 2, 1, 0]);
objects = objects.sortedBy(['primaryCol', 'valueCol']);
TestCase.assertArraysEqual(primaries(objects), [0, 1, 2, 3, 4]);
objects = objects.sortedBy(['primaryCol', 'valueCol'], true);
TestCase.assertArraysEqual(primaries(objects), [4, 3, 2, 1, 0]);
objects = objects.sortedBy(['primaryCol', 'valueCol'], [false]);
TestCase.assertArraysEqual(primaries(objects), [0, 1, 2, 3, 4]);
objects = objects.sortedBy(['valueCol', 'primaryCol']);
TestCase.assertArraysEqual(primaries(objects), [2, 3, 1, 0, 4]);
objects = objects.sortedBy(['valueCol', 'primaryCol'], [false, true]);
TestCase.assertArraysEqual(primaries(objects), [3, 2, 1, 4, 0]);
objects = objects.sortedBy(['valueCol', 'primaryCol'], [true, false]);
TestCase.assertArraysEqual(primaries(objects), [0, 4, 1, 2, 3]);
objects = objects.sortedBy(['valueCol', 'primaryCol'], true);
TestCase.assertArraysEqual(primaries(objects), [4, 0, 1, 3, 2]);
TestCase.assertThrows(function() {
objects.sortedBy(1);
});
TestCase.assertThrows(function() {
objects.sortedBy([1]);
});
TestCase.assertThrows(function() {
objects.sortedBy('fish');
});
TestCase.assertThrows(function() {
objects.sortedBy(['valueCol', 'fish']);
});
},
});