realm-js/src/RJSObject.mm

189 lines
7.5 KiB
Plaintext
Raw Normal View History

2015-08-14 08:18:49 -07:00
////////////////////////////////////////////////////////////////////////////
2015-08-13 09:12:48 -07:00
//
2015-08-14 08:18:49 -07:00
// Copyright 2015 Realm Inc.
2015-08-13 09:12:48 -07:00
//
2015-08-14 08:18:49 -07:00
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
2015-08-13 09:12:48 -07:00
//
2015-08-14 08:18:49 -07:00
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//
////////////////////////////////////////////////////////////////////////////
2015-08-13 09:12:48 -07:00
#import "RJSUtil.hpp"
#import "RJSObject.hpp"
#import "RJSResults.hpp"
#import "RJSSchema.hpp"
#import "RJSArray.hpp"
#import "object_store.hpp"
#import "object_accessor.hpp"
using namespace realm;
using RJSAccessor = NativeAccessor<JSValueRef, JSContextRef>;
JSValueRef ObjectGetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef* exception) {
Object *obj = RJSGetInternal<Object *>(jsObject);
std::string propName = RJSStringForJSString(jsPropertyName);
ObjectSchema &objectSchema = obj->object_schema;
Property *prop = objectSchema.property_for_name(propName);
if (!prop) {
return NULL;
}
switch (prop->type) {
case PropertyTypeBool:
return JSValueMakeBoolean(ctx, obj->row.get_bool(prop->table_column));
case PropertyTypeInt:
return JSValueMakeNumber(ctx, obj->row.get_int(prop->table_column));
case PropertyTypeFloat:
return JSValueMakeNumber(ctx, obj->row.get_float(prop->table_column));
case PropertyTypeDouble:
return JSValueMakeNumber(ctx, obj->row.get_double(prop->table_column));
case PropertyTypeString:
return RJSValueForString(ctx, obj->row.get_string(prop->table_column));
case PropertyTypeData:
return RJSValueForString(ctx, (std::string)obj->row.get_binary(prop->table_column));
case PropertyTypeAny:
*exception = RJSMakeError(ctx, "'Any' type not supported");
return NULL;
case PropertyTypeDate: {
JSValueRef time = JSValueMakeNumber(ctx, obj->row.get_datetime(prop->table_column).get_datetime());
return JSObjectMakeDate(ctx, 1, &time, exception);
}
case PropertyTypeObject: {
ObjectSchema &linkObjectSchema = obj->realm->config().schema->at(prop->object_type);
TableRef table = ObjectStore::table_for_object_type(obj->realm->read_group(), linkObjectSchema.name);
if (obj->row.is_null_link(prop->table_column)) {
return JSValueMakeNull(ctx);
}
return RJSObjectCreate(ctx, Object(obj->realm, linkObjectSchema, table->get(obj->row.get_link(prop->table_column))));
}
case PropertyTypeArray: {
ObjectSchema &arrayObjectSchema = obj->realm->config().schema->at(prop->object_type);
return RJSArrayCreate(ctx, new ObjectArray(obj->realm, arrayObjectSchema, static_cast<LinkViewRef>(obj->row.get_linklist(prop->table_column))));
}
}
return NULL;
}
bool ObjectSetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef jsPropertyName, JSValueRef value, JSValueRef* exception) {
try {
Object *obj = RJSGetInternal<Object *>(jsObject);
obj->set_property_value(ctx, RJSStringForJSString(jsPropertyName), value, true);
} catch (std::exception &ex) {
if (*exception) {
*exception = RJSMakeError(ctx, ex);
}
}
return true;
}
void ObjectPropertyNames(JSContextRef ctx, JSObjectRef object, JSPropertyNameAccumulatorRef propertyNames) {
return;
}
JSClassRef RJSObjectClass() {
static JSClassRef s_objectClass = RJSCreateWrapperClass<Object>("RealmObject", ObjectGetProperty, ObjectSetProperty, NULL, NULL, ObjectPropertyNames);
return s_objectClass;
}
JSObjectRef RJSObjectCreate(JSContextRef ctx, Object object) {
JSValueRef prototype = RJSPrototypeForClassName(object.object_schema.name);
JSObjectRef jsObject = RJSWrapObject(ctx, RJSObjectClass(), new Object(object), prototype);
return jsObject;
}
template<> JSValueRef RJSAccessor::dict_value_for_key(JSContextRef ctx, JSValueRef dict, const std::string &prop_name) {
JSObjectRef object = RJSValidatedValueToObject(ctx, dict);
JSStringRef propStr =JSStringCreateWithUTF8CString(prop_name.c_str());
JSValueRef ex = NULL;
JSValueRef ret = JSObjectGetProperty(ctx, object, propStr, &ex);
if (ex) {
throw RJSException(ctx, ex);
}
JSStringRelease(propStr);
return ret;
}
template<> bool RJSAccessor::is_null(JSContextRef ctx, JSValueRef &val) {
return JSValueIsUndefined(ctx, val) || JSValueIsNull(ctx, val);
}
template<> bool RJSAccessor::to_bool(JSContextRef ctx, JSValueRef &val) {
if (!JSValueIsBoolean(ctx, val)) {
throw std::runtime_error("Property expected to be of type boolean");
}
return JSValueToBoolean(ctx, val);
}
template<> long long RJSAccessor::to_long(JSContextRef ctx, JSValueRef &val) {
return RJSValidatedValueToNumber(ctx, val);
}
template<> float RJSAccessor::to_float(JSContextRef ctx, JSValueRef &val) {
return RJSValidatedValueToNumber(ctx, val);
}
template<> double RJSAccessor::to_double(JSContextRef ctx, JSValueRef &val) {
return RJSValidatedValueToNumber(ctx, val);
}
template<> std::string RJSAccessor::to_string(JSContextRef ctx, JSValueRef &val) {
return RJSValidatedStringForValue(ctx, val);
}
template<> DateTime RJSAccessor::to_datetime(JSContextRef ctx, JSValueRef &val) {
JSObjectRef object = RJSValidatedValueToObject(ctx, val, "Property must be a Date");
JSValueRef exception = NULL;
static JSStringRef utcString = JSStringCreateWithUTF8CString("getTime");
JSObjectRef utcGetter = RJSValidatedObjectProperty(ctx, object, utcString);
JSValueRef utcVal = JSObjectCallAsFunction(ctx, utcGetter, object, 0, NULL, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
double utc = JSValueToNumber(ctx, utcVal, &exception);
if (exception) {
throw RJSException(ctx, exception);
}
return DateTime(utc);
}
extern JSObjectRef RJSDictForPropertyArray(JSContextRef ctx, ObjectSchema &object_schema, JSObjectRef array);
template<> size_t RJSAccessor::to_object_index(JSContextRef ctx, SharedRealm &realm, JSValueRef &val, Property &prop, bool try_update) {
JSObjectRef object = RJSValidatedValueToObject(ctx, val);
if (JSValueIsObjectOfClass(ctx, val, RJSObjectClass())) {
return RJSGetInternal<Object *>(object)->row.get_index();
}
static JSStringRef arrayString = JSStringCreateWithUTF8CString("Array");
ObjectSchema &object_schema = realm->config().schema->at(prop.object_type);
if (RJSIsValueObjectOfType(ctx, object, arrayString)) {
object = RJSDictForPropertyArray(ctx, object_schema, object);
}
Object child = Object::create<JSValueRef>(ctx, realm, object_schema, (JSValueRef)object, try_update);
return child.row.get_index();
}
template<> size_t RJSAccessor::array_size(JSContextRef ctx, JSValueRef &val) {
return RJSValidatedArrayLength(ctx, RJSValidatedValueToObject(ctx, val));
}
template<> JSValueRef RJSAccessor::array_value_at_index(JSContextRef ctx, JSValueRef &val, size_t index) {
return RJSValidatedObjectAtIndex(ctx, RJSValidatedValueToObject(ctx, val), (unsigned int)index);
}