Skip to content

Commit

Permalink
Datatype: UUID (#3482)
Browse files Browse the repository at this point in the history
* UUID: schema and node.js

* Mock UUID JS class implemented. Test extended with type & content compare. to/from logic changed to a working solution (can be optimized). Test-packages removed.

* Accessors reverted to non-string conversion, with required changes (input welcome).

* Test cases expanded.

* Reintroduce query-specific tests for UUID (with necessary addition to get_type_of).

* query-tests added for UUID (and ObjectId, as this was currently missing).

* JSC accessors implemented (UNTESTED due to RN build state).

* uuid mock updated with fromExtendedJSON

* query-tests for UUID & ObjectId extended with optional schemas

* UUID.generate() returns a Buffer, as ObjectId does.

* local bson package used in favor of mock.

* temp bson package updated

* added missing jsc is_uuid

* using bson package UUID in tests

* bson package (w. uuid) installed via github

* UUID included in basic list-tests.

* minor syntax changes

* extended UUID query tests

* tests working again...

* bson deps updated to temp github path

* uuid GH commit bumped

* uuid GH commit bumped

* expose BSON types on Realm.BSON (WIP)

* test bson package updated

* unused '_Binary' removed from realm constructor.

* cleanup

* uuid test cleanup

* testUUIDQuery removed (covered by generic query tests)

* integration-tests bson dependency removed

* cluttering syntax changes "rolled back", for a clearer changeset.

* removed unnecessary ObjectId/BSON import

* reference to external bson package removed

* mixed-test, pull Decimal128 & ObjectId from Realm

* uuid sync test for single instances

* bson depencendy remove from linkingobjects-tests

* ObjectId & UUID added to testResultsSortedAllTypes

* test_data.UUIDObject.json

* List<UUID> test added to uuid-sync-tests

* tab removed

Co-authored-by: Andrew Meyer <[email protected]>

* UUID case implemented in from_bson

* const in favour of var

Co-authored-by: Andrew Meyer <[email protected]>

* bson package version bump

* UUID as partition value (test does not include a complete roundtrip due to current limitations)

* UUID support in Mixed

Co-authored-by: Steffen Agger <[email protected]>
Co-authored-by: Andrew Meyer <[email protected]>
  • Loading branch information
3 people authored Mar 26, 2021
1 parent 7831892 commit ed5d466
Show file tree
Hide file tree
Showing 41 changed files with 3,992 additions and 2,661 deletions.
301 changes: 235 additions & 66 deletions integration-tests/tests/package-lock.json

Large diffs are not rendered by default.

1 change: 0 additions & 1 deletion integration-tests/tests/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@
"typescript": "^3.8.2"
},
"dependencies": {
"bson": "^4.2.0",
"chai": "^4.2.0"
},
"files": [
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,10 +19,9 @@
/* tslint:disable max-classes-per-file */

import Realm from "realm";
import { ObjectId } from "bson";

export interface IPerson {
_id: ObjectId;
_id: Realm.BSON.ObjectId;
name: string;
age: number;
friends: Realm.List<IPerson>;
Expand All @@ -41,7 +40,7 @@ export const PersonSchema: Realm.ObjectSchema = {
};

export class Person extends Realm.Object implements IPerson {
_id: ObjectId;
_id: Realm.BSON.ObjectId;
name: string;
age: number;
friends: Realm.List<Person>;
Expand All @@ -51,7 +50,7 @@ export class Person extends Realm.Object implements IPerson {
}

export interface IDog {
_id: ObjectId;
_id: Realm.BSON.ObjectId;
name: string;
age: number;
owner: IPerson;
Expand All @@ -69,7 +68,7 @@ export const DogSchema: Realm.ObjectSchema = {
};

export class Dog extends Realm.Object implements IDog {
_id: ObjectId;
_id: Realm.BSON.ObjectId;
name: string;
age: number;
owner: Person;
Expand Down
4 changes: 1 addition & 3 deletions lib/extensions.js
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@

/* global navigator */

const URL = require('url-parse');

let getOwnPropertyDescriptors = Object.getOwnPropertyDescriptors || function(obj) {
return Object.getOwnPropertyNames(obj).reduce(function (descriptors, name) {
descriptors[name] = Object.getOwnPropertyDescriptor(obj, name);
Expand Down Expand Up @@ -77,7 +75,7 @@ module.exports = function(realmConstructor, environment) {
realmConstructor.BSON = require('bson');
realmConstructor._Decimal128 = realmConstructor.BSON.Decimal128;
realmConstructor._ObjectId = realmConstructor.BSON.ObjectId;

realmConstructor._UUID = realmConstructor.BSON.UUID;
const { DefaultNetworkTransport } = require('realm-network-transport');
realmConstructor._networkTransport = new DefaultNetworkTransport();

Expand Down
13 changes: 3 additions & 10 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@
},
"dependencies": {
"bindings": "^1.5.0",
"bson": "^4.0.3",
"bson": "github:steffenagger/js-bson#uuid-realm",
"command-line-args": "^4.0.6",
"deepmerge": "2.1.0",
"deprecated-react-native-listview": "0.0.6",
Expand Down
4 changes: 4 additions & 0 deletions src/common/type_deduction.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ class GenericTypeDeductionImpl {
{types::Float, "Float"}, {types::Double, "Double"},
{types::Decimal, "Decimal128"}, {types::Boolean, "Boolean"},
{types::ObjectId, "ObjectId"}, {types::Object, "Object"},
{types::UUID, "UUID"}, {types::Object, "Object"},
{types::Undefined, "Undefined"}, {types::Null, "Null"}};
js_to_realm_map = reverse_deduction_types_map();
}
Expand Down Expand Up @@ -105,6 +106,9 @@ class GenericTypeDeductionImpl {
if (Value::is_object_id(context, value)) {
return types::ObjectId;
}
if (Value::is_uuid(context, value)) {
return types::UUID;
}
if (Value::is_object(context, value)) {
return types::Object;
}
Expand Down
12 changes: 12 additions & 0 deletions src/js_mixed.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -100,6 +100,17 @@ class MixedObjectID : public MixedWrapper<Context, Value> {
}
};

template <typename Context, typename Value, typename Utils>
class MixedUUID : public MixedWrapper<Context, Value> {
Mixed wrap(Context context, Value const &value) {
return Mixed(Utils::to_uuid(context, value));
}

Value unwrap(Context context, Mixed mixed) {
return Utils::from_uuid(context, mixed.get<UUID>());
}
};

template <typename Context, typename Value, typename Utils>
class MixedBinary : public MixedWrapper<Context, Value> {
private:
Expand Down Expand Up @@ -158,6 +169,7 @@ class TypeMixed {
{types::Boolean, new MixedBoolean<Context, Value, Utils>},
{types::Decimal, new MixedDecimal128<Context, Value, Utils>},
{types::ObjectId, new MixedObjectID<Context, Value, Utils>},
{types::UUID, new MixedUUID<Context, Value, Utils>},
{types::Binary, new MixedBinary<Context, Value, Utils>},
{types::Timestamp, new MixedTimeStamp<Context, Value, Utils>},
};
Expand Down
9 changes: 6 additions & 3 deletions src/js_object_accessor.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,8 +140,8 @@ class NativeAccessor {
ValueType box(BinaryData data) { return Value::from_binary(m_ctx, data); }
ValueType box(ObjectId objectId) { return Value::from_object_id(m_ctx, objectId); }
ValueType box(Decimal128 number) { return Value::from_decimal128(m_ctx, number); }
ValueType box(UUID uuid) { return Value::from_uuid(m_ctx, uuid); }
ValueType box(Mixed mixed) { return TypeMixed<JSEngine>::get_instance().wrap(m_ctx, mixed); }
ValueType box(UUID) { throw std::runtime_error("'UUID' type support is not implemented yet"); }

ValueType box(Timestamp ts) {
if (ts.is_null()) {
Expand Down Expand Up @@ -194,6 +194,9 @@ class NativeAccessor {
if (Value::is_object_id(m_ctx, value)) {
return type_ObjectId;
}
if (Value::is_uuid(m_ctx, value)) {
return type_UUID;
}
if (Value::is_decimal128(m_ctx, value)) {
return type_Decimal;
}
Expand Down Expand Up @@ -387,14 +390,14 @@ struct Unbox<JSEngine, Mixed> {
template<typename JSEngine>
struct Unbox<JSEngine, UUID> {
static UUID call(NativeAccessor<JSEngine> *ctx, typename JSEngine::Value const& value, realm::CreatePolicy, ObjKey) {
throw std::runtime_error("'UUID' type suport is not implemented yet");
return js::Value<JSEngine>::validated_to_uuid(ctx->m_ctx, value, "Property");
}
};

template<typename JSEngine>
struct Unbox<JSEngine, util::Optional<UUID>> {
static util::Optional<UUID> call(NativeAccessor<JSEngine> *ctx, typename JSEngine::Value const& value, realm::CreatePolicy, ObjKey) {
throw std::runtime_error("'UUID' type suport is not implemented yet");
return ctx->template unbox_optional<UUID>(value);
}
};

Expand Down
3 changes: 3 additions & 0 deletions src/js_realm.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,9 @@ std::string TypeErrorException::type_string(Property const& prop)
case PropertyType::ObjectId:
ret = "objectId";
break;
case PropertyType::UUID:
ret = "uuid";
break;
case PropertyType::LinkingObjects:
case PropertyType::Object:
ret = prop.object_type;
Expand Down
7 changes: 7 additions & 0 deletions src/js_schema.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,9 @@ static inline void parse_property_type(StringData object_name, Property& prop, S
else if (type == "objectId") {
prop.type |= PropertyType::ObjectId;
}
else if (type == "uuid") {
prop.type |= PropertyType::UUID;
}
else if (type == "list") {
if (prop.object_type == "bool") {
prop.type |= PropertyType::Bool | PropertyType::Array;
Expand Down Expand Up @@ -152,6 +155,10 @@ static inline void parse_property_type(StringData object_name, Property& prop, S
prop.type |= PropertyType::ObjectId | PropertyType::Array;
prop.object_type = "";
}
else if (prop.object_type == "uuid") {
prop.type |= PropertyType::UUID | PropertyType::Array;
prop.object_type = "";
}
else {
if (is_nullable(prop.type)) {
throw std::logic_error(util::format("List property '%1.%2' cannot be optional", object_name, prop.name));
Expand Down
4 changes: 4 additions & 0 deletions src/js_sync.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,10 @@ static std::string partition_value_bson_to_string(typename T::Context ctx, typen
auto pv = Value<T>::validated_to_object_id(ctx, partition_value_value);
partition_bson = bson::Bson(pv);
}
else if (Value<T>::is_uuid(ctx, partition_value_value)) {
auto pv = Value<T>::validated_to_uuid(ctx, partition_value_value);
partition_bson = bson::Bson(pv);
}
else if (Value<T>::is_null(ctx, partition_value_value)) {
partition_bson = bson::Bson();
}
Expand Down
15 changes: 6 additions & 9 deletions src/js_types.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,7 @@ struct Value {
static bool is_binary(ContextType, const ValueType &);
static bool is_valid(const ValueType &);
static bool is_bson(ContextType, const ValueType &);
static bool is_uuid(ContextType, const ValueType &);

static bool is_valid_for_property(ContextType, const ValueType&, const Property&);
static bool is_valid_for_property_type(ContextType, const ValueType&, realm::PropertyType type, StringData object_type);
Expand Down Expand Up @@ -169,6 +170,7 @@ struct Value {
static double to_number(ContextType, const ValueType &);
static Decimal128 to_decimal128(ContextType, const ValueType &);
static ObjectId to_object_id(ContextType, const ValueType &);
static UUID to_uuid(ContextType, const ValueType &);
static ObjectType to_object(ContextType, const ValueType &);
static String<T> to_string(ContextType, const ValueType &);
static OwnedBinaryData to_binary(ContextType, ValueType);
Expand All @@ -194,6 +196,7 @@ struct Value {
VALIDATED(OwnedBinaryData, binary)
VALIDATED(Decimal128, decimal128)
VALIDATED(ObjectId, object_id)
VALIDATED(UUID, uuid)

#undef VALIDATED
};
Expand Down Expand Up @@ -314,6 +317,7 @@ struct Object {
VALIDATED(ObjectType, object)
VALIDATED(String<T>, string)
VALIDATED(ObjectType, ObjectId)
VALIDATED(ObjectType, UUID)

#undef VALIDATED

Expand Down Expand Up @@ -490,7 +494,7 @@ inline bool Value<T>::is_valid_for_property_type(ContextType context, const Valu
case PropertyType::Mixed:
return true;
case PropertyType::UUID:
throw std::runtime_error("'UUID' type support is not implemented yet");
return is_uuid(context, value);
default:
REALM_UNREACHABLE();
}
Expand Down Expand Up @@ -565,13 +569,6 @@ inline typename T::Value Object<T>::create_from_optional_app_error(ContextType c
return create_from_app_error(ctx, *error);
}



template<typename T>
inline typename T::Value Value<T>::from_uuid(typename T::Context ctx, const UUID& value) {
throw std::runtime_error("'UUID' type support is not implemented yet");
}

template<typename T>
inline typename T::Value Value<T>::from_objkey(typename T::Context ctx, const ObjKey& value) {
throw std::runtime_error("'Mixed' type support is not implemented yet");
Expand All @@ -588,7 +585,7 @@ inline typename T::Value Value<T>::from_bson(typename T::Context ctx, const bson

switch (value.type()) {
case Type::Uuid:
throw std::runtime_error("'UUID' type support is not implemented yet");
return from_uuid(ctx, value.operator UUID());
case Type::MinKey:
return Object<T>::create_bson_type(ctx, "MinKey", {});
case Type::MaxKey:
Expand Down
33 changes: 33 additions & 0 deletions src/jsc/jsc_value.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,20 @@ JSValueRef jsc::Value::from_object_id(JSContextRef ctx, const ObjectId& value)
return jsc::Function::construct(ctx, object_id_constructor, args.size(), args.data());
}

template<>
JSValueRef jsc::Value::from_uuid(JSContextRef ctx, const UUID& value)
{
static jsc::String s_realm = "Realm";
static jsc::String s_uuid = "_UUID";

JSObjectRef global_object = JSContextGetGlobalObject(ctx);
JSObjectRef realm_constructor = jsc::Object::validated_get_constructor(ctx, global_object, s_realm);
JSObjectRef uuid_constructor = jsc::Object::validated_get_constructor(ctx, realm_constructor, s_uuid);

std::array<JSValueRef, 1> args { {jsc::Value::from_nonnull_string(ctx, jsc::String(value.to_string())) } };
return jsc::Function::construct(ctx, uuid_constructor, args.size(), args.data());
}

template<>
OwnedBinaryData jsc::Value::to_binary(JSContextRef ctx, JSValueRef value)
{
Expand Down Expand Up @@ -152,6 +166,7 @@ template<>
Decimal128 jsc::Value::to_decimal128(JSContextRef ctx, const JSValueRef& value)
{
auto object = to_object(ctx, value);
// EJSON input supported (in RN only) for enabling debugging of synced realms.
auto ejson_property = jsc::Object::get_property(ctx, object, "$numberDecimal");

if (is_undefined(ctx, ejson_property)) {
Expand All @@ -170,6 +185,7 @@ template<>
ObjectId jsc::Value::to_object_id(JSContextRef ctx, const JSValueRef& value)
{
auto object = to_object(ctx, value);
// EJSON input supported (in RN only) for enabling debugging of synced realms.
auto ejson_property = jsc::Object::get_property(ctx, object, "$oid");

if (is_undefined(ctx, ejson_property)) {
Expand All @@ -182,5 +198,22 @@ ObjectId jsc::Value::to_object_id(JSContextRef ctx, const JSValueRef& value)
}
}

template<>
UUID jsc::Value::to_uuid(JSContextRef ctx, const JSValueRef& value)
{
auto object = to_object(ctx, value);
// EJSON input supported (in RN only) for enabling debugging of synced realms.
auto ejson_property = jsc::Object::get_property(ctx, object, "$uuid");

if (is_undefined(ctx, ejson_property)) {
static jsc::String s_to_hex_string = "toHexString";
JSValueRef args[] = {};
JSValueRef as_string = jsc::Object::call_method(ctx, to_object(ctx, value), s_to_hex_string, 0, args);
return UUID(std::string(to_string(ctx, as_string)).c_str());
} else {
return UUID(std::string(to_string(ctx, ejson_property)).c_str());
}
}

} // namespace js
} // namespace realm
12 changes: 12 additions & 0 deletions src/jsc/jsc_value.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -193,6 +193,12 @@ inline bool jsc::Value::is_object_id(JSContextRef ctx, const JSValueRef &value)
return is_bson_type(ctx, value, "ObjectID") || is_ejson_type(ctx, value, "$oid");
}

template<>
inline bool jsc::Value::is_uuid(JSContextRef ctx, const JSValueRef &value) {
// TODO: is_ejson_type won't work for binary EJSON
return is_bson_type(ctx, value, "UUID") || is_ejson_type(ctx, value, "$uuid");
}

template<>
inline JSValueRef jsc::Value::from_boolean(JSContextRef ctx, bool boolean) {
return JSValueMakeBoolean(ctx, boolean);
Expand Down Expand Up @@ -227,6 +233,9 @@ JSValueRef jsc::Value::from_decimal128(JSContextRef ctx, const Decimal128& value
template<>
JSValueRef jsc::Value::from_object_id(JSContextRef ctx, const ObjectId& value);

template<>
JSValueRef jsc::Value::from_uuid(JSContextRef ctx, const UUID& value);

template<>
inline bool jsc::Value::to_boolean(JSContextRef ctx, const JSValueRef &value) {
return JSValueToBoolean(ctx, value);
Expand Down Expand Up @@ -308,5 +317,8 @@ Decimal128 jsc::Value::to_decimal128(JSContextRef ctx, const JSValueRef& value);
template<>
ObjectId jsc::Value::to_object_id(JSContextRef ctx, const JSValueRef& value);

template<>
UUID jsc::Value::to_uuid(JSContextRef ctx, const JSValueRef& value);

} // js
} // realm
Loading

0 comments on commit ed5d466

Please sign in to comment.