An amazing project that generates micro reports from tournament results
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

415 lines
12 KiB

////////////////////////////////////////////////////////////////////////////
//
// 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.
//
////////////////////////////////////////////////////////////////////////////
#import "RLMObject_Private.hpp"
#import "RLMAccessor.h"
#import "RLMArray.h"
#import "RLMCollection_Private.hpp"
#import "RLMObjectBase_Private.h"
#import "RLMObjectSchema_Private.hpp"
#import "RLMObjectStore.h"
#import "RLMProperty.h"
#import "RLMQueryUtil.hpp"
#import "RLMRealm_Private.hpp"
#import "RLMSchema_Private.h"
#import "collection_notifications.hpp"
#import "object.hpp"
@interface RLMPropertyChange ()
@property (nonatomic, readwrite, strong) NSString *name;
@property (nonatomic, readwrite, strong, nullable) id previousValue;
@property (nonatomic, readwrite, strong, nullable) id value;
@end
// We declare things in RLMObject which are actually implemented in RLMObjectBase
// for documentation's sake, which leads to -Wunimplemented-method warnings.
// Other alternatives to this would be to disable -Wunimplemented-method for this
// file (but then we could miss legitimately missing things), or declaring the
// inherited things in a category (but they currently aren't nicely grouped for
// that).
@implementation RLMObject
// synthesized in RLMObjectBase
@dynamic invalidated, realm, objectSchema;
#pragma mark - Designated Initializers
- (instancetype)init {
return [super init];
}
- (instancetype)initWithValue:(id)value schema:(RLMSchema *)schema {
return [super initWithValue:value schema:schema];
}
- (instancetype)initWithRealm:(__unsafe_unretained RLMRealm *const)realm schema:(RLMObjectSchema *)schema {
return [super initWithRealm:realm schema:schema];
}
#pragma mark - Convenience Initializers
- (instancetype)initWithValue:(id)value {
return [super initWithValue:value schema:RLMSchema.partialPrivateSharedSchema];
}
#pragma mark - Class-based Object Creation
+ (instancetype)createInDefaultRealmWithValue:(id)value {
return (RLMObject *)RLMCreateObjectInRealmWithValue([RLMRealm defaultRealm], [self className], value, RLMUpdatePolicyError);
}
+ (instancetype)createInRealm:(RLMRealm *)realm withValue:(id)value {
return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyError);
}
+ (instancetype)createOrUpdateInDefaultRealmWithValue:(id)value {
return [self createOrUpdateInRealm:[RLMRealm defaultRealm] withValue:value];
}
+ (instancetype)createOrUpdateModifiedInDefaultRealmWithValue:(id)value {
return [self createOrUpdateModifiedInRealm:[RLMRealm defaultRealm] withValue:value];
}
+ (instancetype)createOrUpdateInRealm:(RLMRealm *)realm withValue:(id)value {
RLMVerifyHasPrimaryKey(self);
return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyUpdateAll);
}
+ (instancetype)createOrUpdateModifiedInRealm:(RLMRealm *)realm withValue:(id)value {
RLMVerifyHasPrimaryKey(self);
return (RLMObject *)RLMCreateObjectInRealmWithValue(realm, [self className], value, RLMUpdatePolicyUpdateChanged);
}
#pragma mark - Subscripting
- (id)objectForKeyedSubscript:(NSString *)key {
return RLMObjectBaseObjectForKeyedSubscript(self, key);
}
- (void)setObject:(id)obj forKeyedSubscript:(NSString *)key {
RLMObjectBaseSetObjectForKeyedSubscript(self, key, obj);
}
#pragma mark - Getting & Querying
+ (RLMResults *)allObjects {
return RLMGetObjects(RLMRealm.defaultRealm, self.className, nil);
}
+ (RLMResults *)allObjectsInRealm:(__unsafe_unretained RLMRealm *const)realm {
return RLMGetObjects(realm, self.className, nil);
}
+ (RLMResults *)objectsWhere:(NSString *)predicateFormat, ... {
va_list args;
va_start(args, predicateFormat);
RLMResults *results = [self objectsWhere:predicateFormat args:args];
va_end(args);
return results;
}
+ (RLMResults *)objectsWhere:(NSString *)predicateFormat args:(va_list)args {
return [self objectsWithPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]];
}
+ (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat, ... {
va_list args;
va_start(args, predicateFormat);
RLMResults *results = [self objectsInRealm:realm where:predicateFormat args:args];
va_end(args);
return results;
}
+ (RLMResults *)objectsInRealm:(RLMRealm *)realm where:(NSString *)predicateFormat args:(va_list)args {
return [self objectsInRealm:realm withPredicate:[NSPredicate predicateWithFormat:predicateFormat arguments:args]];
}
+ (RLMResults *)objectsWithPredicate:(NSPredicate *)predicate {
return RLMGetObjects(RLMRealm.defaultRealm, self.className, predicate);
}
+ (RLMResults *)objectsInRealm:(RLMRealm *)realm withPredicate:(NSPredicate *)predicate {
return RLMGetObjects(realm, self.className, predicate);
}
+ (instancetype)objectForPrimaryKey:(id)primaryKey {
return RLMGetObject(RLMRealm.defaultRealm, self.className, primaryKey);
}
+ (instancetype)objectInRealm:(RLMRealm *)realm forPrimaryKey:(id)primaryKey {
return RLMGetObject(realm, self.className, primaryKey);
}
#pragma mark - Other Instance Methods
- (BOOL)isEqualToObject:(RLMObject *)object {
return [object isKindOfClass:RLMObject.class] && RLMObjectBaseAreEqual(self, object);
}
- (RLMNotificationToken *)addNotificationBlock:(RLMObjectChangeBlock)block {
return RLMObjectAddNotificationBlock(self, ^(NSArray<NSString *> *propertyNames,
NSArray *oldValues, NSArray *newValues, NSError *error) {
if (error) {
block(false, nil, error);
}
else if (!propertyNames) {
block(true, nil, nil);
}
else {
auto properties = [NSMutableArray arrayWithCapacity:propertyNames.count];
for (NSUInteger i = 0, count = propertyNames.count; i < count; ++i) {
auto prop = [RLMPropertyChange new];
prop.name = propertyNames[i];
prop.previousValue = RLMCoerceToNil(oldValues[i]);
prop.value = RLMCoerceToNil(newValues[i]);
[properties addObject:prop];
}
block(false, properties, nil);
}
});
}
+ (NSString *)className {
return [super className];
}
#pragma mark - Default values for schema definition
+ (NSArray *)indexedProperties {
return @[];
}
+ (NSDictionary *)linkingObjectsProperties {
return @{};
}
+ (NSDictionary *)defaultPropertyValues {
return nil;
}
+ (NSString *)primaryKey {
return nil;
}
+ (NSArray *)ignoredProperties {
return nil;
}
+ (NSArray *)requiredProperties {
return @[];
}
@end
@implementation RLMDynamicObject
+ (BOOL)shouldIncludeInDefaultSchema {
return NO;
}
- (id)valueForUndefinedKey:(NSString *)key {
return RLMDynamicGetByName(self, key, false);
}
- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
RLMDynamicValidatedSet(self, key, value);
}
@end
@implementation RLMWeakObjectHandle {
realm::Row _row;
RLMClassInfo *_info;
Class _objectClass;
}
- (instancetype)initWithObject:(RLMObjectBase *)object {
if (!(self = [super init])) {
return nil;
}
_row = object->_row;
_info = object->_info;
_objectClass = object.class;
return self;
}
- (RLMObjectBase *)object {
RLMObjectBase *object = RLMCreateManagedAccessor(_objectClass, _info->realm, _info);
object->_row = std::move(_row);
return object;
}
- (id)copyWithZone:(__unused NSZone *)zone {
RLMWeakObjectHandle *copy = [[RLMWeakObjectHandle alloc] init];
copy->_row = _row;
copy->_info = _info;
copy->_objectClass = _objectClass;
return copy;
}
@end
static bool treatFakeObjectAsRLMObject = false;
void RLMSetTreatFakeObjectAsRLMObject(BOOL flag) {
treatFakeObjectAsRLMObject = flag;
}
BOOL RLMIsObjectOrSubclass(Class klass) {
if (RLMIsKindOfClass(klass, RLMObjectBase.class)) {
return YES;
}
if (treatFakeObjectAsRLMObject) {
static Class FakeObjectClass = NSClassFromString(@"FakeObject");
return RLMIsKindOfClass(klass, FakeObjectClass);
}
return NO;
}
BOOL RLMIsObjectSubclass(Class klass) {
auto isSubclass = [](Class class1, Class class2) {
class1 = class_getSuperclass(class1);
return RLMIsKindOfClass(class1, class2);
};
if (isSubclass(class_getSuperclass(klass), RLMObjectBase.class)) {
return YES;
}
if (treatFakeObjectAsRLMObject) {
static Class FakeObjectClass = NSClassFromString(@"FakeObject");
return isSubclass(klass, FakeObjectClass);
}
return NO;
}
@interface RLMObjectNotificationToken : RLMCancellationToken
@end
@implementation RLMObjectNotificationToken {
@public
realm::Object _object;
}
@end
RLMNotificationToken *RLMObjectAddNotificationBlock(RLMObjectBase *obj, RLMObjectNotificationCallback block) {
if (!obj->_realm) {
@throw RLMException(@"Only objects which are managed by a Realm support change notifications");
}
[obj->_realm verifyNotificationsAreSupported:true];
struct {
void (^block)(NSArray<NSString *> *, NSArray *, NSArray *, NSError *);
RLMObjectBase *object;
NSArray<NSString *> *propertyNames = nil;
NSArray *oldValues = nil;
bool deleted = false;
void populateProperties(realm::CollectionChangeSet const& c) {
if (propertyNames) {
return;
}
if (!c.deletions.empty()) {
deleted = true;
return;
}
if (c.columns.empty()) {
return;
}
auto properties = [NSMutableArray new];
for (size_t i = 0; i < c.columns.size(); ++i) {
if (c.columns[i].empty()) {
continue;
}
if (auto prop = object->_info->propertyForTableColumn(i)) {
[properties addObject:prop.name];
}
}
if (properties.count) {
propertyNames = properties;
}
}
NSArray *readValues(realm::CollectionChangeSet const& c) {
if (c.empty()) {
return nil;
}
populateProperties(c);
if (!propertyNames) {
return nil;
}
auto values = [NSMutableArray arrayWithCapacity:propertyNames.count];
for (NSString *name in propertyNames) {
id value = [object valueForKey:name];
if (!value || [value isKindOfClass:[RLMArray class]]) {
[values addObject:NSNull.null];
}
else {
[values addObject:value];
}
}
return values;
}
void before(realm::CollectionChangeSet const& c) {
@autoreleasepool {
oldValues = readValues(c);
}
}
void after(realm::CollectionChangeSet const& c) {
@autoreleasepool {
auto newValues = readValues(c);
if (deleted) {
block(nil, nil, nil, nil);
}
else if (newValues) {
block(propertyNames, oldValues, newValues, nil);
}
propertyNames = nil;
oldValues = nil;
}
}
void error(std::exception_ptr err) {
@autoreleasepool {
try {
rethrow_exception(err);
}
catch (...) {
NSError *error = nil;
RLMRealmTranslateException(&error);
block(nil, nil, nil, error);
}
}
}
} callback{block, obj};
realm::Object object(obj->_realm->_realm, *obj->_info->objectSchema, obj->_row);
auto token = [[RLMObjectNotificationToken alloc] initWithToken:object.add_notification_callback(callback) realm:obj->_realm];
token->_object = std::move(object);
return token;
}
@implementation RLMPropertyChange
@end