Implement implicit property conversion for date and binary (#1557)
* Implement implicit property conversion for date and binary Closes #1542 Closes #1551 * fix include * changelog
This commit is contained in:
parent
70004b9304
commit
23f965060e
|
@ -10,7 +10,8 @@ x.y.z Release notes
|
|||
* When authentication fails due to a misbehaving server, a proper error is thrown.
|
||||
|
||||
### Internal
|
||||
* None
|
||||
* Strings can now be assigned to Date columns. When that happens the JavaScript Date constructor will be invoked to parse the string.
|
||||
* Base64 strings can now be assigned to Data columns.
|
||||
|
||||
2.0.12 Release notes (2017-12-1)
|
||||
=============================================================
|
||||
|
|
|
@ -22,6 +22,10 @@
|
|||
#include "js_realm_object.hpp"
|
||||
#include "js_schema.hpp"
|
||||
|
||||
#if REALM_ENABLE_SYNC
|
||||
#include <realm/util/base64.hpp>
|
||||
#endif
|
||||
|
||||
namespace realm {
|
||||
class List;
|
||||
class Object;
|
||||
|
@ -239,7 +243,23 @@ struct Unbox<JSEngine, BinaryData> {
|
|||
if (ctx->is_null(value)) {
|
||||
return BinaryData();
|
||||
}
|
||||
ctx->m_owned_binary_data = js::Value<JSEngine>::validated_to_binary(ctx->m_ctx, value, "Property");
|
||||
#if REALM_ENABLE_SYNC
|
||||
// realm-sync holds the base64-decoding routine
|
||||
if (js::Value<JSEngine>::is_string(ctx->m_ctx, value)) {
|
||||
// the incoming value might be a base64 string, so let's try to parse it
|
||||
std::string str = js::Value<JSEngine>::to_string(ctx->m_ctx, value);
|
||||
size_t max_size = util::base64_decoded_size(str.size());
|
||||
std::unique_ptr<char[]> data(new char[max_size]);
|
||||
if (auto size = util::base64_decode(str, data.get(), max_size)) {
|
||||
ctx->m_owned_binary_data = OwnedBinaryData(std::move(data), *size);
|
||||
return ctx->m_owned_binary_data.get();
|
||||
} else {
|
||||
throw std::runtime_error("Attempting to populate BinaryData from string that is not valid base64");
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
ctx->m_owned_binary_data = js::Value<JSEngine>::validated_to_binary(ctx->m_ctx, value);
|
||||
return ctx->m_owned_binary_data.get();
|
||||
}
|
||||
};
|
||||
|
@ -257,7 +277,14 @@ struct Unbox<JSEngine, Timestamp> {
|
|||
if (ctx->is_null(value)) {
|
||||
return Timestamp();
|
||||
}
|
||||
auto date = js::Value<JSEngine>::validated_to_date(ctx->m_ctx, value, "Property");
|
||||
typename JSEngine::Value date;
|
||||
if (js::Value<JSEngine>::is_string(ctx->m_ctx, value)) {
|
||||
// the incoming value might be a date string, so let the Date constructor have at it
|
||||
date = js::Value<JSEngine>::to_date(ctx->m_ctx, value);
|
||||
} else {
|
||||
date = js::Value<JSEngine>::validated_to_date(ctx->m_ctx, value);
|
||||
}
|
||||
|
||||
double milliseconds = js::Value<JSEngine>::to_number(ctx->m_ctx, date);
|
||||
int64_t seconds = milliseconds / 1000;
|
||||
int32_t nanoseconds = ((int64_t)milliseconds % 1000) * 1000000;
|
||||
|
|
|
@ -389,9 +389,9 @@ inline bool Value<T>::is_valid_for_property_type(ContextType context, const Valu
|
|||
case PropertyType::String:
|
||||
return is_string(context, value);
|
||||
case PropertyType::Data:
|
||||
return is_binary(context, value);
|
||||
return is_binary(context, value) || is_string(context, value);
|
||||
case PropertyType::Date:
|
||||
return is_date(context, value);
|
||||
return is_date(context, value) || is_string(context, value);
|
||||
case PropertyType::Object:
|
||||
return true;
|
||||
case PropertyType::Any:
|
||||
|
|
|
@ -203,6 +203,15 @@ inline JSObjectRef jsc::Value::to_constructor(JSContextRef ctx, const JSValueRef
|
|||
|
||||
template<>
|
||||
inline JSObjectRef jsc::Value::to_date(JSContextRef ctx, const JSValueRef &value) {
|
||||
if (JSValueIsString(ctx, value)) {
|
||||
JSValueRef error;
|
||||
std::array<JSValueRef, 1> args { value };
|
||||
if (JSObjectRef result = JSObjectMakeDate(ctx, args.size(), args.data(), &error)) {
|
||||
return result;
|
||||
} else {
|
||||
throw jsc::Exception(ctx, error);
|
||||
}
|
||||
}
|
||||
return to_object(ctx, value);
|
||||
}
|
||||
|
||||
|
|
|
@ -21,9 +21,9 @@
|
|||
#include "node_string.hpp"
|
||||
#include "node_protected.hpp"
|
||||
#include "node_context.hpp"
|
||||
#include "node_value.hpp"
|
||||
#include "node_object.hpp"
|
||||
#include "node_function.hpp"
|
||||
#include "node_value.hpp"
|
||||
#include "node_exception.hpp"
|
||||
#include "node_return_value.hpp"
|
||||
#include "node_class.hpp"
|
||||
|
|
|
@ -204,11 +204,6 @@ inline v8::Local<v8::Object> node::Value::to_array(v8::Isolate* isolate, const v
|
|||
return to_object(isolate, value);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline v8::Local<v8::Object> node::Value::to_date(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
|
||||
return to_object(isolate, value);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline v8::Local<v8::Function> node::Value::to_function(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
|
||||
return value->IsFunction() ? v8::Local<v8::Function>::Cast(value) : v8::Local<v8::Function>();
|
||||
|
@ -219,5 +214,15 @@ inline v8::Local<v8::Function> node::Value::to_constructor(v8::Isolate* isolate,
|
|||
return to_function(isolate, value);
|
||||
}
|
||||
|
||||
template<>
|
||||
inline v8::Local<v8::Object> node::Value::to_date(v8::Isolate* isolate, const v8::Local<v8::Value> &value) {
|
||||
if (value->IsString()) {
|
||||
v8::Local<v8::Function> date_constructor = to_constructor(isolate, node::Object::get_property(isolate, isolate->GetCurrentContext()->Global(), "Date"));
|
||||
std::array<v8::Local<v8::Value>, 1> args { {value} };
|
||||
return node::Function::construct(isolate, date_constructor, args.size(), args.data());
|
||||
}
|
||||
return to_object(isolate, value);
|
||||
}
|
||||
|
||||
} // js
|
||||
} // realm
|
||||
|
|
|
@ -297,6 +297,15 @@ module.exports = {
|
|||
});
|
||||
TestCase.assertArraysEqual(new Uint8Array(object.dataCol), RANDOM_DATA);
|
||||
|
||||
if (Realm.Sync) {
|
||||
// The base64 decoder comes from realm-sync
|
||||
// Should be able to also set a data property to base64-encoded string.
|
||||
realm.write(function() {
|
||||
object.dataCol = require('buffer/').Buffer.from(RANDOM_DATA).toString('base64');
|
||||
});
|
||||
TestCase.assertArraysEqual(new Uint8Array(object.dataCol), RANDOM_DATA);
|
||||
}
|
||||
|
||||
// Should be to set a data property to a DataView.
|
||||
realm.write(function() {
|
||||
object.dataCol = new DataView(RANDOM_DATA.buffer);
|
||||
|
@ -348,7 +357,7 @@ module.exports = {
|
|||
object.dataCol = 1;
|
||||
});
|
||||
TestCase.assertThrows(function() {
|
||||
object.dataCol = 'data';
|
||||
object.dataCol = 'some binary data';
|
||||
});
|
||||
TestCase.assertThrows(function() {
|
||||
object.dataCol = [1];
|
||||
|
@ -431,15 +440,18 @@ module.exports = {
|
|||
|
||||
// test different dates
|
||||
var realm = new Realm({schema: [schemas.DateObject]});
|
||||
const stringifiedDate = new Date();
|
||||
realm.write(function() {
|
||||
realm.create('Date', { currentDate: new Date(10000) });
|
||||
realm.create('Date', { currentDate: new Date(-10000) });
|
||||
realm.create('Date', { currentDate: new Date(1000000000000) });
|
||||
realm.create('Date', { currentDate: new Date(-1000000000000) });
|
||||
realm.create('Date', { currentDate: stringifiedDate.toString() });
|
||||
});
|
||||
TestCase.assertEqual(realm.objects('Date')[0].currentDate.getTime(), 10000);
|
||||
TestCase.assertEqual(realm.objects('Date')[1].currentDate.getTime(), -10000);
|
||||
TestCase.assertEqual(realm.objects('Date')[2].currentDate.getTime(), 1000000000000);
|
||||
TestCase.assertEqual(realm.objects('Date')[3].currentDate.getTime(), -1000000000000);
|
||||
TestCase.assertEqual(realm.objects('Date')[4].currentDate.toString(), stringifiedDate.toString());
|
||||
}
|
||||
};
|
||||
|
|
|
@ -3,6 +3,7 @@
|
|||
"version": "0.0.1",
|
||||
"private": true,
|
||||
"dependencies": {
|
||||
"buffer": "^5.0.8",
|
||||
"es6-promise": "^3.2.1"
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue