mirror of
https://github.com/status-im/realm-js.git
synced 2025-02-04 10:43:29 +00:00
refact cocoa to use c++ table creation apis
This commit is contained in:
parent
4994428e63
commit
a54d2216f9
82
object_schema.cpp
Normal file
82
object_schema.cpp
Normal file
@ -0,0 +1,82 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2014 Realm Inc.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "object_schema.hpp"
|
||||
#include "object_store.hpp"
|
||||
|
||||
using namespace realm;
|
||||
using namespace std;
|
||||
|
||||
ObjectSchema::ObjectSchema(realm::Group *group, std::string name) : name(name) {
|
||||
TableRef table = ObjectStore::table_for_object_type(group, name);
|
||||
size_t count = table->get_column_count();
|
||||
for (size_t col = 0; col < count; col++) {
|
||||
Property property;
|
||||
property.name = table->get_column_name(col).data();
|
||||
property.type = (PropertyType)table->get_column_type(col);
|
||||
property.is_indexed = table->has_search_index(col);
|
||||
property.is_primary = false;
|
||||
property.table_column = col;
|
||||
if (property.type == PropertyTypeObject || property.type == PropertyTypeArray) {
|
||||
// set link type for objects and arrays
|
||||
realm::TableRef linkTable = table->get_link_target(col);
|
||||
property.object_type = ObjectStore::class_for_table_name(linkTable->get_name().data());
|
||||
}
|
||||
else {
|
||||
property.object_type = "";
|
||||
}
|
||||
properties.push_back(property);
|
||||
}
|
||||
|
||||
primary_key = realm::ObjectStore::get_primary_key_for_object(group, name);
|
||||
if (primary_key.length()) {
|
||||
auto primary_key_iter = primary_key_property();
|
||||
if (primary_key_iter == properties.end()) {
|
||||
std::vector<std::string> errors;
|
||||
errors.push_back("No property matching primary key '" + primary_key + "'");
|
||||
throw ObjectStoreValidationException(errors, name);
|
||||
}
|
||||
primary_key_iter->is_primary = true;
|
||||
}
|
||||
}
|
||||
|
||||
std::vector<Property>::iterator ObjectSchema::property_for_name(std::string name) {
|
||||
auto iter = properties.begin();
|
||||
while (iter < properties.end()) {
|
||||
if (iter->name == name) {
|
||||
return iter;
|
||||
}
|
||||
iter++;
|
||||
}
|
||||
return iter;
|
||||
}
|
||||
|
||||
std::vector<ObjectSchema> ObjectSchema::object_schema_from_group(realm::Group *group) {
|
||||
// generate object schema and class mapping for all tables in the realm
|
||||
unsigned long numTables = group->size();
|
||||
vector<ObjectSchema> object_schema;
|
||||
|
||||
for (unsigned long i = 0; i < numTables; i++) {
|
||||
std::string name = ObjectStore::class_for_table_name(group->get_table_name(i).data());
|
||||
if (name.length()) {
|
||||
object_schema.push_back(ObjectSchema(group, name));
|
||||
}
|
||||
}
|
||||
|
||||
return object_schema;
|
||||
}
|
49
object_schema.hpp
Normal file
49
object_schema.hpp
Normal file
@ -0,0 +1,49 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2014 Realm Inc.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __realm__object_schema__
|
||||
#define __realm__object_schema__
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "property.hpp"
|
||||
#include <realm/group.hpp>
|
||||
|
||||
namespace realm {
|
||||
class ObjectSchema {
|
||||
public:
|
||||
ObjectSchema() {}
|
||||
ObjectSchema(Group *group, std::string name);
|
||||
|
||||
static std::vector<ObjectSchema> object_schema_from_group(Group *group);
|
||||
|
||||
std::string name;
|
||||
std::vector<Property> properties;
|
||||
std::string primary_key;
|
||||
|
||||
std::vector<Property>::iterator property_for_name(std::string name);
|
||||
std::vector<Property>::iterator primary_key_property() {
|
||||
return property_for_name(primary_key);
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<ObjectSchema> ObjectSchemaRef;
|
||||
}
|
||||
|
||||
#endif /* defined(__realm__object_schema__) */
|
204
object_store.cpp
204
object_store.cpp
@ -19,6 +19,7 @@
|
||||
#include "object_store.hpp"
|
||||
|
||||
using namespace realm;
|
||||
using namespace std;
|
||||
|
||||
const char * const c_metadataTableName = "metadata";
|
||||
const char * const c_versionColumnName = "version";
|
||||
@ -30,7 +31,9 @@ const size_t c_primaryKeyObjectClassColumnIndex = 0;
|
||||
const char * const c_primaryKeyPropertyNameColumnName = "pk_property";
|
||||
const size_t c_primaryKeyPropertyNameColumnIndex = 1;
|
||||
|
||||
const uint64_t ObjectStore::NotVersioned = std::numeric_limits<uint64_t>::max();
|
||||
const string c_object_table_name_prefix = "class_";
|
||||
|
||||
const uint64_t ObjectStore::NotVersioned = numeric_limits<uint64_t>::max();
|
||||
|
||||
bool ObjectStore::has_metadata_tables(realm::Group *group) {
|
||||
return group->get_table(c_primaryKeyTableName) && group->get_table(c_metadataTableName);
|
||||
@ -102,3 +105,202 @@ void ObjectStore::set_primary_key_for_object(realm::Group *group, StringData obj
|
||||
}
|
||||
}
|
||||
|
||||
string ObjectStore::class_for_table_name(string table_name) {
|
||||
if (table_name.compare(0, 6, c_object_table_name_prefix) == 0) {
|
||||
return table_name.substr(6, table_name.length()-6);
|
||||
}
|
||||
return string();
|
||||
}
|
||||
|
||||
string ObjectStore::table_name_for_class(string class_name) {
|
||||
return c_object_table_name_prefix + class_name;
|
||||
}
|
||||
|
||||
realm::TableRef ObjectStore::table_for_object_type(realm::Group *group, StringData object_type) {
|
||||
return group->get_table(table_name_for_class(object_type));
|
||||
}
|
||||
|
||||
realm::TableRef ObjectStore::table_for_object_type_create_if_needed(realm::Group *group, StringData object_type, bool &created) {
|
||||
return group->get_or_add_table(table_name_for_class(object_type), &created);
|
||||
}
|
||||
|
||||
std::vector<std::string> ObjectStore::validate_and_update_column_mapping(realm::Group *group, ObjectSchema &target_schema) {
|
||||
vector<string> validation_errors;
|
||||
ObjectSchema table_schema(group, target_schema.name);
|
||||
|
||||
// check to see if properties are the same
|
||||
for (auto current_prop = table_schema.properties.begin(); current_prop != table_schema.properties.end(); current_prop++) {
|
||||
auto target_prop = target_schema.property_for_name(current_prop->name);
|
||||
|
||||
if (target_prop == target_schema.properties.end()) {
|
||||
validation_errors.push_back("Property '" + current_prop->name + "' is missing from latest object model.");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (current_prop->type != target_prop->type) {
|
||||
validation_errors.push_back("Property types for '" + target_prop->name + "' property do not match. " +
|
||||
"Old type '" + string_for_property_type(current_prop->type) +
|
||||
"', new type '" + string_for_property_type(target_prop->type) + "'");
|
||||
continue;
|
||||
}
|
||||
if (current_prop->type == PropertyTypeObject || target_prop->type == PropertyTypeArray) {
|
||||
if (current_prop->object_type != target_prop->object_type) {
|
||||
validation_errors.push_back("Target object type for property '" + current_prop->name + "' does not match. " +
|
||||
"Old type '" + current_prop->object_type +
|
||||
"', new type '" + target_prop->object_type + "'.");
|
||||
}
|
||||
}
|
||||
if (current_prop->is_primary != target_prop->is_primary) {
|
||||
if (current_prop->is_primary) {
|
||||
validation_errors.push_back("Property '" + current_prop->name + "' is no longer a primary key.");
|
||||
}
|
||||
else {
|
||||
validation_errors.push_back("Property '" + current_prop->name + "' has been made a primary key.");
|
||||
}
|
||||
}
|
||||
|
||||
// create new property with aligned column
|
||||
target_prop->table_column = current_prop->table_column;
|
||||
}
|
||||
|
||||
// check for new missing properties
|
||||
for (auto target_iter = target_schema.properties.begin(); target_iter != target_schema.properties.end(); target_iter++) {
|
||||
if (table_schema.property_for_name(target_iter->name) == table_schema.properties.end()) {
|
||||
validation_errors.push_back("Property '" + target_iter->name + "' has been added to latest object model.");
|
||||
}
|
||||
}
|
||||
|
||||
return validation_errors;
|
||||
}
|
||||
|
||||
static inline bool property_has_changed(Property &p1, Property &p2) {
|
||||
return p1.type != p2.type || p1.name != p2.name || p1.object_type != p2.object_type;
|
||||
}
|
||||
|
||||
// set references to tables on targetSchema and create/update any missing or out-of-date tables
|
||||
// if update existing is true, updates existing tables, otherwise validates existing tables
|
||||
// NOTE: must be called from within write transaction
|
||||
static inline bool create_tables(realm::Group *group, ObjectStore::Schema target_schema, bool update_existing) {
|
||||
// create metadata tables if neded
|
||||
bool changed = realm::ObjectStore::create_metadata_tables(group);
|
||||
|
||||
// first pass to create missing tables
|
||||
vector<ObjectSchema *> to_update;
|
||||
for (size_t i = 0; i < target_schema.size(); i++) {
|
||||
ObjectSchema *object_schema = target_schema[i].get();
|
||||
bool created = false;
|
||||
ObjectStore::table_for_object_type_create_if_needed(group, object_schema->name, created);
|
||||
|
||||
// we will modify tables for any new objectSchema (table was created) or for all if update_existing is true
|
||||
if (update_existing || created) {
|
||||
to_update.push_back(object_schema);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// second pass adds/removes columns for out of date tables
|
||||
for (size_t i = 0; i < to_update.size(); i++) {
|
||||
ObjectSchema *target_schema = to_update[i];
|
||||
TableRef table = ObjectStore::table_for_object_type(group, target_schema->name);
|
||||
|
||||
ObjectSchema current_schema(group, target_schema->name);
|
||||
vector<Property> &target_props = target_schema->properties;
|
||||
|
||||
// add missing columns
|
||||
for (auto target_prop = target_props.begin(); target_prop < target_props.end(); target_prop++) {
|
||||
auto current_prop = current_schema.property_for_name(target_prop->name);
|
||||
|
||||
// add any new properties (new name or different type)
|
||||
if (current_prop == current_schema.properties.end() || property_has_changed(*current_prop, *target_prop)) {
|
||||
switch (target_prop->type) {
|
||||
// for objects and arrays, we have to specify target table
|
||||
case PropertyTypeObject:
|
||||
case PropertyTypeArray: {
|
||||
realm::TableRef link_table = ObjectStore::table_for_object_type(group, target_prop->object_type);
|
||||
target_prop->table_column = table->add_column_link(realm::DataType(target_prop->type), target_prop->name, *link_table);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
target_prop->table_column = table->add_column(realm::DataType(target_prop->type), target_prop->name);
|
||||
break;
|
||||
}
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// remove extra columns
|
||||
vector<Property> reverse_props = current_schema.properties;
|
||||
std::sort(reverse_props.begin(), reverse_props.end(), [](Property &i, Property &j){ return (j.table_column < i.table_column); });
|
||||
for (auto iter = reverse_props.begin(); iter != reverse_props.end(); iter++) {
|
||||
auto target_prop_iter = target_schema->property_for_name(iter->name);
|
||||
if (target_prop_iter == target_props.end() || property_has_changed(*iter, *target_prop_iter)) {
|
||||
table->remove_column(iter->table_column);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
// update table metadata
|
||||
if (target_schema->primary_key.length()) {
|
||||
// if there is a primary key set, check if it is the same as the old key
|
||||
if (!current_schema.primary_key.length() || current_schema.primary_key != target_schema->primary_key) {
|
||||
realm::ObjectStore::set_primary_key_for_object(group, target_schema->name, target_schema->primary_key);
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
else if (current_schema.primary_key.length()) {
|
||||
// there is no primary key, so if there was one nil out
|
||||
realm::ObjectStore::set_primary_key_for_object(group, target_schema->name, "");
|
||||
changed = true;
|
||||
}
|
||||
}
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
bool ObjectStore::is_migration_required(realm::Group *group, uint64_t new_version) {
|
||||
uint64_t old_version = get_schema_version(group);
|
||||
if (old_version > new_version && old_version != realm::ObjectStore::NotVersioned) {
|
||||
throw ObjectStoreException(ObjectStoreException::RealmVersionGreaterThanSchemaVersion);
|
||||
}
|
||||
return old_version != new_version;
|
||||
}
|
||||
|
||||
|
||||
bool ObjectStore::update_realm_with_schema(realm::Group *group,
|
||||
uint64_t version,
|
||||
Schema schema,
|
||||
MigrationFunction migration) {
|
||||
// Recheck the schema version after beginning the write transaction as
|
||||
// another process may have done the migration after we opened the read
|
||||
// transaction
|
||||
bool migrating = is_migration_required(group, version);
|
||||
|
||||
// create tables
|
||||
bool changed = create_tables(group, schema, migrating);
|
||||
for (size_t i = 0; i < schema.size(); i++) {
|
||||
ObjectSchema *target_schema = schema[i].get();
|
||||
TableRef table = table_for_object_type(group, target_schema->name);
|
||||
|
||||
// read-only realms may be missing tables entirely
|
||||
if (table) {
|
||||
auto errors = validate_and_update_column_mapping(group, *target_schema);
|
||||
if (errors.size()) {
|
||||
throw ObjectStoreValidationException(errors, target_schema->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (!migrating) {
|
||||
return changed;
|
||||
}
|
||||
|
||||
// apply the migration block if provided and there's any old data
|
||||
// to be migrated
|
||||
if (get_schema_version(group) != realm::ObjectStore::NotVersioned) {
|
||||
migration();
|
||||
}
|
||||
|
||||
set_schema_version(group, version);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -20,6 +20,7 @@
|
||||
#define __realm__object_store__
|
||||
|
||||
#include <realm/group.hpp>
|
||||
#include "object_schema.hpp"
|
||||
|
||||
namespace realm {
|
||||
class ObjectStore {
|
||||
@ -28,25 +29,74 @@ namespace realm {
|
||||
static const uint64_t NotVersioned;
|
||||
|
||||
// check if the realm already has all metadata tables
|
||||
static bool has_metadata_tables(realm::Group *group);
|
||||
static bool has_metadata_tables(Group *group);
|
||||
|
||||
// create any metadata tables that don't already exist
|
||||
// must be in write transaction to set
|
||||
// returns true if it actually did anything
|
||||
static bool create_metadata_tables(realm::Group *group);
|
||||
static bool create_metadata_tables(Group *group);
|
||||
|
||||
// get the last set schema version
|
||||
static uint64_t get_schema_version(realm::Group *group);
|
||||
static uint64_t get_schema_version(Group *group);
|
||||
|
||||
// set a new schema version
|
||||
static void set_schema_version(realm::Group *group, uint64_t version);
|
||||
static void set_schema_version(Group *group, uint64_t version);
|
||||
|
||||
// get primary key property name for object type
|
||||
static StringData get_primary_key_for_object(realm::Group *group, StringData object_type);
|
||||
static StringData get_primary_key_for_object(Group *group, StringData object_type);
|
||||
|
||||
// sets primary key property for object type
|
||||
// must be in write transaction to set
|
||||
static void set_primary_key_for_object(realm::Group *group, StringData object_type, StringData primary_key);
|
||||
static void set_primary_key_for_object(Group *group, StringData object_type, StringData primary_key);
|
||||
|
||||
// verify a target schema against its table, setting the table_column property on each schema object
|
||||
// returns array of validation errors
|
||||
static std::vector<std::string> validate_and_update_column_mapping(Group *group, ObjectSchema &target_schema);
|
||||
|
||||
// get the table used to store object of objectClass
|
||||
static std::string table_name_for_class(std::string class_name);
|
||||
static std::string class_for_table_name(std::string table_name);
|
||||
static realm::TableRef table_for_object_type(Group *group, StringData object_type);
|
||||
static realm::TableRef table_for_object_type_create_if_needed(Group *group, StringData object_type, bool &created);
|
||||
|
||||
static bool is_migration_required(realm::Group *group, uint64_t new_version);
|
||||
|
||||
// updates a Realm to a given target schema/version creating tables as necessary
|
||||
// returns if any changes were made
|
||||
// passed in schema ar updated with the correct column mapping
|
||||
// optionally runs migration function/lambda if schema is out of date
|
||||
// NOTE: must be performed within a write transaction
|
||||
typedef std::function<void()> MigrationFunction;
|
||||
typedef std::vector<ObjectSchemaRef> Schema;
|
||||
static bool update_realm_with_schema(Group *group,
|
||||
uint64_t version,
|
||||
Schema schema,
|
||||
MigrationFunction migration);
|
||||
};
|
||||
|
||||
class ObjectStoreException : public std::exception {
|
||||
public:
|
||||
enum Kind {
|
||||
// thrown when calling update_realm_to_schema and the realm version is greater than the given version
|
||||
RealmVersionGreaterThanSchemaVersion,
|
||||
};
|
||||
ObjectStoreException(Kind kind) : m_kind(kind) {}
|
||||
ObjectStoreException::Kind kind() { return m_kind; }
|
||||
|
||||
private:
|
||||
Kind m_kind;
|
||||
};
|
||||
|
||||
class ObjectStoreValidationException : public std::exception {
|
||||
public:
|
||||
ObjectStoreValidationException(std::vector<std::string> validation_errors, std::string object_type) :
|
||||
m_validation_errors(validation_errors), m_object_type(object_type) {}
|
||||
std::vector<std::string> validation_errors() { return m_validation_errors; }
|
||||
std::string object_type() { return m_object_type; }
|
||||
|
||||
private:
|
||||
std::vector<std::string> m_validation_errors;
|
||||
std::string m_object_type;
|
||||
};
|
||||
}
|
||||
|
||||
|
21
property.cpp
Normal file
21
property.cpp
Normal file
@ -0,0 +1,21 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2014 Realm Inc.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#include "property.hpp"
|
||||
|
||||
using namespace realm;
|
85
property.hpp
Normal file
85
property.hpp
Normal file
@ -0,0 +1,85 @@
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// Copyright 2014 Realm Inc.
|
||||
//
|
||||
// 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
|
||||
//
|
||||
// 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.
|
||||
//
|
||||
////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef __realm__property__
|
||||
#define __realm__property__
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace realm {
|
||||
enum PropertyType {
|
||||
/** Integer type: NSInteger, int, long, Int (Swift) */
|
||||
PropertyTypeInt = 0,
|
||||
/** Boolean type: BOOL, bool, Bool (Swift) */
|
||||
PropertyTypeBool = 1,
|
||||
/** Float type: CGFloat (32bit), float, Float (Swift) */
|
||||
PropertyTypeFloat = 9,
|
||||
/** Double type: CGFloat (64bit), double, Double (Swift) */
|
||||
PropertyTypeDouble = 10,
|
||||
/** String type: NSString, String (Swift) */
|
||||
PropertyTypeString = 2,
|
||||
/** Data type: NSData */
|
||||
PropertyTypeData = 4,
|
||||
/** Any type: id, **not supported in Swift** */
|
||||
PropertyTypeAny = 6,
|
||||
/** Date type: NSDate */
|
||||
PropertyTypeDate = 7,
|
||||
/** Object type. See [Realm Models](http://realm.io/docs/cocoa/latest/#models) */
|
||||
PropertyTypeObject = 12,
|
||||
/** Array type. See [Realm Models](http://realm.io/docs/cocoa/latest/#models) */
|
||||
PropertyTypeArray = 13,
|
||||
};
|
||||
|
||||
class Property {
|
||||
public:
|
||||
std::string name;
|
||||
PropertyType type;
|
||||
std::string object_type;
|
||||
bool is_primary;
|
||||
bool is_indexed;
|
||||
|
||||
size_t table_column;
|
||||
};
|
||||
|
||||
static inline const char *string_for_property_type(PropertyType type) {
|
||||
switch (type) {
|
||||
case PropertyTypeString:
|
||||
return "string";
|
||||
case PropertyTypeInt:
|
||||
return "int";
|
||||
case PropertyTypeBool:
|
||||
return "bool";
|
||||
case PropertyTypeDate:
|
||||
return "date";
|
||||
case PropertyTypeData:
|
||||
return "data";
|
||||
case PropertyTypeDouble:
|
||||
return "double";
|
||||
case PropertyTypeFloat:
|
||||
return "float";
|
||||
case PropertyTypeAny:
|
||||
return "any";
|
||||
case PropertyTypeObject:
|
||||
return "object";
|
||||
case PropertyTypeArray:
|
||||
return "array";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endif /* defined__realm__property__ */
|
Loading…
x
Reference in New Issue
Block a user