diff --git a/RealmJS.xcodeproj/project.pbxproj b/RealmJS.xcodeproj/project.pbxproj index 9ff6dac2..af727ddb 100644 --- a/RealmJS.xcodeproj/project.pbxproj +++ b/RealmJS.xcodeproj/project.pbxproj @@ -7,6 +7,15 @@ objects = { /* Begin PBXBuildFile section */ + 02601F031BA0F0C4007C91FF /* external_commit_helper.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02601F011BA0F0C4007C91FF /* external_commit_helper.cpp */; }; + 02601F041BA0F0C4007C91FF /* external_commit_helper.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02601F021BA0F0C4007C91FF /* external_commit_helper.hpp */; }; + 02601F081BA0F0CD007C91FF /* index_set.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02601F051BA0F0CD007C91FF /* index_set.cpp */; }; + 02601F091BA0F0CD007C91FF /* index_set.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02601F061BA0F0CD007C91FF /* index_set.hpp */; }; + 02601F0A1BA0F0CD007C91FF /* realm_delegate.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02601F071BA0F0CD007C91FF /* realm_delegate.hpp */; }; + 02601F0D1BA0F3A7007C91FF /* schema.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02601F0B1BA0F3A7007C91FF /* schema.cpp */; }; + 02601F0E1BA0F3A7007C91FF /* schema.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02601F0C1BA0F3A7007C91FF /* schema.hpp */; }; + 02601F111BA10228007C91FF /* transact_log_handler.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 02601F0F1BA10228007C91FF /* transact_log_handler.cpp */; }; + 02601F121BA10228007C91FF /* transact_log_handler.hpp in Headers */ = {isa = PBXBuildFile; fileRef = 02601F101BA10228007C91FF /* transact_log_handler.hpp */; }; 0270BC4C1B7CFC0D00010E03 /* RealmJS.h in Headers */ = {isa = PBXBuildFile; fileRef = 0270BC3E1B7CFC0D00010E03 /* RealmJS.h */; settings = {ATTRIBUTES = (Public, ); }; }; 0270BC4D1B7CFC0D00010E03 /* RealmJS.mm in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */; }; 0270BC4E1B7CFC0D00010E03 /* RJSArray.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 0270BC401B7CFC0D00010E03 /* RJSArray.cpp */; }; @@ -76,6 +85,15 @@ /* End PBXCopyFilesBuildPhase section */ /* Begin PBXFileReference section */ + 02601F011BA0F0C4007C91FF /* external_commit_helper.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = external_commit_helper.cpp; path = "src/object-store/apple/external_commit_helper.cpp"; sourceTree = ""; }; + 02601F021BA0F0C4007C91FF /* external_commit_helper.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = external_commit_helper.hpp; path = "src/object-store/apple/external_commit_helper.hpp"; sourceTree = ""; }; + 02601F051BA0F0CD007C91FF /* index_set.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = index_set.cpp; path = "src/object-store/index_set.cpp"; sourceTree = ""; }; + 02601F061BA0F0CD007C91FF /* index_set.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = index_set.hpp; path = "src/object-store/index_set.hpp"; sourceTree = ""; }; + 02601F071BA0F0CD007C91FF /* realm_delegate.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = realm_delegate.hpp; path = "src/object-store/realm_delegate.hpp"; sourceTree = ""; }; + 02601F0B1BA0F3A7007C91FF /* schema.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = schema.cpp; path = "src/object-store/schema.cpp"; sourceTree = ""; }; + 02601F0C1BA0F3A7007C91FF /* schema.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = schema.hpp; path = "src/object-store/schema.hpp"; sourceTree = ""; }; + 02601F0F1BA10228007C91FF /* transact_log_handler.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = transact_log_handler.cpp; path = "src/object-store/transact_log_handler.cpp"; sourceTree = ""; }; + 02601F101BA10228007C91FF /* transact_log_handler.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; name = transact_log_handler.hpp; path = "src/object-store/transact_log_handler.hpp"; sourceTree = ""; }; 0270BC3E1B7CFC0D00010E03 /* RealmJS.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; name = RealmJS.h; path = src/RealmJS.h; sourceTree = ""; }; 0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; name = RealmJS.mm; path = src/RealmJS.mm; sourceTree = ""; }; 0270BC401B7CFC0D00010E03 /* RJSArray.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = RJSArray.cpp; path = src/RJSArray.cpp; sourceTree = ""; }; @@ -162,6 +180,15 @@ 0270BC641B7CFC1C00010E03 /* results.hpp */, 0270BC651B7CFC1C00010E03 /* shared_realm.cpp */, 0270BC661B7CFC1C00010E03 /* shared_realm.hpp */, + 02601F011BA0F0C4007C91FF /* external_commit_helper.cpp */, + 02601F021BA0F0C4007C91FF /* external_commit_helper.hpp */, + 02601F051BA0F0CD007C91FF /* index_set.cpp */, + 02601F061BA0F0CD007C91FF /* index_set.hpp */, + 02601F0B1BA0F3A7007C91FF /* schema.cpp */, + 02601F0C1BA0F3A7007C91FF /* schema.hpp */, + 02601F0F1BA10228007C91FF /* transact_log_handler.cpp */, + 02601F101BA10228007C91FF /* transact_log_handler.hpp */, + 02601F071BA0F0CD007C91FF /* realm_delegate.hpp */, 0270BC3E1B7CFC0D00010E03 /* RealmJS.h */, 0270BC3F1B7CFC0D00010E03 /* RealmJS.mm */, 0270BC401B7CFC0D00010E03 /* RJSArray.cpp */, @@ -244,12 +271,17 @@ files = ( 0270BC4C1B7CFC0D00010E03 /* RealmJS.h in Headers */, 0270BC4F1B7CFC0D00010E03 /* RJSArray.hpp in Headers */, + 02601F0E1BA0F3A7007C91FF /* schema.hpp in Headers */, 0270BC6C1B7CFC1C00010E03 /* object_store.hpp in Headers */, + 02601F0A1BA0F0CD007C91FF /* realm_delegate.hpp in Headers */, 0270BC541B7CFC0D00010E03 /* RJSResults.hpp in Headers */, + 02601F121BA10228007C91FF /* transact_log_handler.hpp in Headers */, 0270BC681B7CFC1C00010E03 /* object_accessor.hpp in Headers */, 0270BC711B7CFC1C00010E03 /* shared_realm.hpp in Headers */, 0270BC581B7CFC0D00010E03 /* RJSUtil.hpp in Headers */, 0270BC6A1B7CFC1C00010E03 /* object_schema.hpp in Headers */, + 02601F041BA0F0C4007C91FF /* external_commit_helper.hpp in Headers */, + 02601F091BA0F0CD007C91FF /* index_set.hpp in Headers */, 0270BC6D1B7CFC1C00010E03 /* property.hpp in Headers */, 0270BC6F1B7CFC1C00010E03 /* results.hpp in Headers */, 0270BC561B7CFC0D00010E03 /* RJSSchema.hpp in Headers */, @@ -391,7 +423,7 @@ ); runOnlyForDeploymentPostprocessing = 0; shellPath = /bin/sh; - shellScript = ": ${REALM_CORE_VERSION:=0.92.0} # set to \"current\" to always use the current build\n\necho \"Downloading dependency: core ${REALM_CORE_VERSION}\"\nTMP_DIR=\"$TMPDIR/core_bin\"\nmkdir -p \"${TMP_DIR}\"\nCORE_TMP_TAR=\"${TMP_DIR}/core-${REALM_CORE_VERSION}.tar.bz2.tmp\"\nCORE_TAR=\"${TMP_DIR}/core-${REALM_CORE_VERSION}.tar.bz2\"\nif [ ! -f \"${CORE_TAR}\" ]; then\ncurl -f -L -s \"http://static.realm.io/downloads/core/realm-core-${REALM_CORE_VERSION}.tar.bz2\" -o \"${CORE_TMP_TAR}\" ||\n(echo \"Downloading core failed. Please try again once you have an Internet connection.\" && exit 1)\nmv \"${CORE_TMP_TAR}\" \"${CORE_TAR}\"\nfi\n\n(\ncd \"${TMP_DIR}\"\nrm -rf core\ntar xjf \"${CORE_TAR}\"\nmv core core-${REALM_CORE_VERSION}\n)\n\nrm -rf core-${REALM_CORE_VERSION} core\nmv ${TMP_DIR}/core-${REALM_CORE_VERSION} .\nln -s core-${REALM_CORE_VERSION} core"; + shellScript = ": ${REALM_CORE_VERSION:=0.92.1.1} # set to \"current\" to always use the current build\n\necho \"Downloading dependency: core ${REALM_CORE_VERSION}\"\nTMP_DIR=\"$TMPDIR/core_bin\"\nmkdir -p \"${TMP_DIR}\"\nCORE_TMP_TAR=\"${TMP_DIR}/core-${REALM_CORE_VERSION}.tar.bz2.tmp\"\nCORE_TAR=\"${TMP_DIR}/core-${REALM_CORE_VERSION}.tar.bz2\"\nif [ ! -f \"${CORE_TAR}\" ]; then\ncurl -f -L -s \"http://static.realm.io/downloads/core/realm-core-${REALM_CORE_VERSION}.tar.bz2\" -o \"${CORE_TMP_TAR}\" ||\n(echo \"Downloading core failed. Please try again once you have an Internet connection.\" && exit 1)\nmv \"${CORE_TMP_TAR}\" \"${CORE_TAR}\"\nfi\n\n(\ncd \"${TMP_DIR}\"\nrm -rf core\ntar xjf \"${CORE_TAR}\"\nmv core core-${REALM_CORE_VERSION}\n)\n\nrm -rf core-${REALM_CORE_VERSION} core\nmv ${TMP_DIR}/core-${REALM_CORE_VERSION} .\nln -s core-${REALM_CORE_VERSION} core"; }; /* End PBXShellScriptBuildPhase section */ @@ -410,11 +442,15 @@ files = ( 0270BC571B7CFC0D00010E03 /* RJSSchema.mm in Sources */, 0270BC691B7CFC1C00010E03 /* object_schema.cpp in Sources */, + 02601F0D1BA0F3A7007C91FF /* schema.cpp in Sources */, 0270BC6E1B7CFC1C00010E03 /* results.cpp in Sources */, 0270BC511B7CFC0D00010E03 /* RJSObject.mm in Sources */, 0270BC4D1B7CFC0D00010E03 /* RealmJS.mm in Sources */, + 02601F081BA0F0CD007C91FF /* index_set.cpp in Sources */, + 02601F111BA10228007C91FF /* transact_log_handler.cpp in Sources */, 0270BC591B7CFC0D00010E03 /* RJSUtil.mm in Sources */, 0270BC551B7CFC0D00010E03 /* RJSResults.mm in Sources */, + 02601F031BA0F0C4007C91FF /* external_commit_helper.cpp in Sources */, 0270BC6B1B7CFC1C00010E03 /* object_store.cpp in Sources */, 0270BC701B7CFC1C00010E03 /* shared_realm.cpp in Sources */, 0270BC671B7CFC1C00010E03 /* object_accessor.cpp in Sources */, diff --git a/schema.cpp b/schema.cpp index bf7a6181..fe9b4de0 100644 --- a/schema.cpp +++ b/schema.cpp @@ -58,6 +58,15 @@ Schema::const_iterator Schema::find(ObjectSchema const& object) const noexcept return const_cast(this)->find(object); } +ObjectSchema& Schema::operator[] (std::string const& name) +{ + auto iter = find(name); + if (iter == end()) { + throw std::runtime_error("Object type '" + name + "' not present in schema."); + } + return *iter; +} + void Schema::validate() const { std::vector exceptions; diff --git a/schema.hpp b/schema.hpp index 0a7fa425..1e44b74c 100644 --- a/schema.hpp +++ b/schema.hpp @@ -39,6 +39,9 @@ public: iterator find(ObjectSchema const& object) noexcept; const_iterator find(ObjectSchema const& object) const noexcept; + // get and ObjectSchema by name, throws if not present in the Schema + ObjectSchema& operator[] (std::string const& name); + // Verify that this schema is internally consistent (i.e. all properties are // valid, links link to types that actually exist, etc.) void validate() const; diff --git a/src/RJSObject.mm b/src/RJSObject.mm index 440daae1..da31c9dd 100644 --- a/src/RJSObject.mm +++ b/src/RJSObject.mm @@ -58,16 +58,16 @@ JSValueRef ObjectGetProperty(JSContextRef ctx, JSObjectRef jsObject, JSStringRef 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); + auto linkObjectSchema = obj->realm->config().schema->find(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)))); + 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(obj->row.get_linklist(prop->table_column)))); + auto arrayObjectSchema = obj->realm->config().schema->find(prop->object_type); + return RJSArrayCreate(ctx, new ObjectArray(obj->realm, *arrayObjectSchema, static_cast(obj->row.get_linklist(prop->table_column)))); } } @@ -185,12 +185,12 @@ template<> size_t RJSAccessor::to_object_index(JSContextRef ctx, SharedRealm &re return RJSGetInternal(object)->row.get_index(); } - ObjectSchema &object_schema = realm->config().schema->at(type); + auto object_schema = realm->config().schema->find(type); if (RJSIsValueArray(ctx, object)) { - object = RJSDictForPropertyArray(ctx, object_schema, object); + object = RJSDictForPropertyArray(ctx, *object_schema, object); } - Object child = Object::create(ctx, realm, object_schema, (JSValueRef)object, try_update); + Object child = Object::create(ctx, realm, *object_schema, (JSValueRef)object, try_update); return child.row.get_index(); } diff --git a/src/RJSRealm.mm b/src/RJSRealm.mm index f64e47e8..02dd49f4 100644 --- a/src/RJSRealm.mm +++ b/src/RJSRealm.mm @@ -24,9 +24,43 @@ #import "shared_realm.hpp" #import "object_accessor.hpp" +#import "realm_delegate.hpp" + +#import using namespace realm; +class RJSRealmDelegate : public RealmDelegate { +public: + typedef std::shared_ptr> NotificationFunction; + void add_notification(NotificationFunction ¬ification) { m_notifications.insert(notification); } + void remove_notification(NotificationFunction notification) { m_notifications.erase(notification); } + void remove_all_notifications() { m_notifications.clear(); } + std::set m_notifications; + + virtual void changes_available() { + for (NotificationFunction notification : m_notifications) { + (*notification)("RefreshRequiredNotification"); + } + } + + virtual void did_change(std::vector const& observers, + std::vector const& invalidated) { + for (NotificationFunction notification : m_notifications) { + (*notification)("DidChangeNotification"); + } + } + + virtual std::vector get_observed_rows() { + return std::vector(); + } + + virtual void will_change(std::vector const& observers, + std::vector const& invalidated) { + + } +}; + std::string writeablePathForFile(const std::string &fileName) { #if TARGET_OS_IPHONE // On iOS the Documents directory isn't user-visible, so put files there @@ -123,7 +157,9 @@ JSObjectRef RealmConstructor(JSContextRef ctx, JSObjectRef constructor, size_t a *jsException = RJSMakeError(ctx, "Invalid arguments when constructing 'Realm'"); return NULL; } - return RJSWrapObject(ctx, RJSRealmClass(), new SharedRealm(Realm::get_shared_realm(config))); + SharedRealm *realm = new SharedRealm(Realm::get_shared_realm(config)); + (*realm)->m_delegate = std::make_unique(); + return RJSWrapObject(ctx, RJSRealmClass(), realm); } catch (std::exception &ex) { if (jsException) { @@ -218,7 +254,7 @@ JSValueRef RealmCreateObject(JSContextRef ctx, JSObjectRef function, JSObjectRef JSObjectRef object = RJSValidatedValueToObject(ctx, arguments[1]); if (RJSIsValueArray(ctx, arguments[1])) { - object = RJSDictForPropertyArray(ctx, object_schema->second, object); + object = RJSDictForPropertyArray(ctx, *object_schema, object); } bool update = false; @@ -226,7 +262,7 @@ JSValueRef RealmCreateObject(JSContextRef ctx, JSObjectRef function, JSObjectRef update = RJSValidatedValueToBool(ctx, arguments[2]); } - return RJSObjectCreate(ctx, Object::create(ctx, sharedRealm, object_schema->second, object, update)); + return RJSObjectCreate(ctx, Object::create(ctx, sharedRealm, *object_schema, object, update)); } catch (std::exception &exp) { if (jsException) { @@ -292,7 +328,7 @@ JSValueRef RealmDeleteAll(JSContextRef ctx, JSObjectRef function, JSObjectRef th } for (auto objectSchema : *realm->config().schema) { - ObjectStore::table_for_object_type(realm->read_group(), objectSchema.first)->clear(); + ObjectStore::table_for_object_type(realm->read_group(), objectSchema.name)->clear(); } return NULL; } @@ -332,7 +368,7 @@ JSValueRef RealmWrite(JSContextRef ctx, JSObjectRef function, JSObjectRef thisOb namespace realm { struct Notification { JSGlobalContextRef ctx; - Realm::NotificationFunction func; + RJSRealmDelegate::NotificationFunction func; }; } @@ -343,7 +379,7 @@ JSValueRef RealmAddNotification(JSContextRef ctx, JSObjectRef function, JSObject JSObjectRef user_function = RJSValidatedValueToObject(ctx, arguments[0]); SharedRealm realm = *RJSGetInternal(thisObject); JSGlobalContextRef gCtx = JSGlobalContextRetain(JSContextGetGlobalContext(ctx)); - Realm::NotificationFunction func = std::make_shared>([=](std::string notification_name) { + RJSRealmDelegate::NotificationFunction func = std::make_shared>([=](std::string notification_name) { JSValueRef arguments[2]; arguments[0] = thisObject; arguments[1] = RJSValueForString(gCtx, notification_name); @@ -353,8 +389,8 @@ JSValueRef RealmAddNotification(JSContextRef ctx, JSObjectRef function, JSObject throw RJSException(gCtx, ex); } }); - realm->add_notification(func); + static_cast(realm->m_delegate.get())->add_notification(func); return RJSWrapObject(ctx, RJSNotificationClass(), new Notification { gCtx, func }); } catch (std::exception &exp) { diff --git a/src/RJSResults.mm b/src/RJSResults.mm index c1ffe118..43a142f9 100644 --- a/src/RJSResults.mm +++ b/src/RJSResults.mm @@ -87,7 +87,12 @@ JSValueRef SortByProperty(JSContextRef ctx, JSObjectRef function, JSObjectRef th JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string className) { TableRef table = ObjectStore::table_for_object_type(realm->read_group(), className); - return RJSWrapObject(ctx, RJSResultsClass(), new Results(realm, realm->config().schema->at(className), table->where())); + auto object_schema = realm->config().schema->find(className); + if (object_schema == realm->config().schema->end()) { + throw std::runtime_error("Object type '" + className + "' not present in Realm."); + return NULL; + } + return RJSWrapObject(ctx, RJSResultsClass(), new Results(realm, *object_schema, table->where())); } @@ -97,14 +102,14 @@ JSObjectRef RJSResultsCreate(JSContextRef ctx, SharedRealm realm, std::string cl TableRef table = ObjectStore::table_for_object_type(realm->read_group(), className); Query query = table->where(); Schema &schema = *realm->config().schema; - ObjectSchema &object_schema = realm->config().schema->at(className); + auto object_schema = realm->config().schema->find(className); @try { - RLMUpdateQueryWithPredicate(&query, [NSPredicate predicateWithFormat:@(queryString.c_str())], schema, object_schema); + RLMUpdateQueryWithPredicate(&query, [NSPredicate predicateWithFormat:@(queryString.c_str())], schema, *object_schema); } @catch(NSException *ex) { throw std::runtime_error(ex.description.UTF8String); } - return RJSWrapObject(ctx, RJSResultsClass(), new Results(realm, object_schema, std::move(query))); + return RJSWrapObject(ctx, RJSResultsClass(), new Results(realm, *object_schema, std::move(query))); } diff --git a/src/RJSSchema.mm b/src/RJSSchema.mm index 17ddc727..cc77c80c 100644 --- a/src/RJSSchema.mm +++ b/src/RJSSchema.mm @@ -162,14 +162,14 @@ static inline ObjectSchema RJSParseObjectSchema(JSContextRef ctx, JSObjectRef ob } realm::Schema RJSParseSchema(JSContextRef ctx, JSObjectRef jsonObject) { - Schema schema; + std::vector schema; size_t length = RJSValidatedArrayLength(ctx, jsonObject); for (unsigned int i = 0; i < length; i++) { JSObjectRef jsonObjectSchema = RJSValidatedObjectAtIndex(ctx, jsonObject, i); ObjectSchema objectSchema = RJSParseObjectSchema(ctx, jsonObjectSchema); - schema[objectSchema.name] = std::move(objectSchema); + schema.emplace_back(std::move(objectSchema)); } - return schema; + return Schema(schema); } diff --git a/src/RJSUtil.mm b/src/RJSUtil.mm index a6eadf49..4ee353a4 100644 --- a/src/RJSUtil.mm +++ b/src/RJSUtil.mm @@ -467,7 +467,7 @@ realm::Property *get_property_from_key_path(realm::Schema &schema, realm::Object } if (prop->object_type.length()) { - desc = schema.at(prop->object_type); + desc = *schema.find(prop->object_type); } prevPath = path; start = end + 1; diff --git a/src/object-store/object_store.hpp b/src/object-store/object_store.hpp index f38524f8..3908077a 100644 --- a/src/object-store/object_store.hpp +++ b/src/object-store/object_store.hpp @@ -19,6 +19,7 @@ #ifndef REALM_OBJECT_STORE_HPP #define REALM_OBJECT_STORE_HPP +#include "schema.hpp" #include "object_schema.hpp" #include "property.hpp"