Signal-iOS/SignalServiceKit/src/Storage/TSYapDatabaseObject.m
2019-10-11 09:31:35 -03:00

272 lines
9.3 KiB
Objective-C

//
// Copyright (c) 2019 Open Whisper Systems. All rights reserved.
//
#import "TSYapDatabaseObject.h"
#import "SSKEnvironment.h"
#import <SignalServiceKit/SignalServiceKit-Swift.h>
NS_ASSUME_NONNULL_BEGIN
// This macro is only intended to be used within TSYapDatabaseObject.
#define OWSAssertCanReadYDB() \
do { \
if (!self.databaseStorage.canReadFromYdb) { \
OWSLogError(@"storageMode: %@.", SSKFeatureFlags.storageModeDescription); \
OWSLogError( \
@"StorageCoordinatorState: %@.", NSStringFromStorageCoordinatorState(self.storageCoordinator.state)); \
switch (SSKFeatureFlags.storageModeStrictness) { \
case StorageModeStrictnessFail: \
OWSFail(@"Unexpected YDB read."); \
break; \
case StorageModeStrictnessFailDebug: \
OWSFailDebug(@"Unexpected YDB read."); \
break; \
case StorageModeStrictnessLog: \
OWSLogError(@"Unexpected YDB read."); \
break; \
} \
} \
} while (NO)
// This macro is only intended to be used within TSYapDatabaseObject.
#define OWSAssertCanWriteYDB() \
do { \
if (!self.databaseStorage.canWriteToYdb) { \
OWSLogError(@"storageMode: %@.", SSKFeatureFlags.storageModeDescription); \
OWSLogError( \
@"StorageCoordinatorState: %@.", NSStringFromStorageCoordinatorState(self.storageCoordinator.state)); \
switch (SSKFeatureFlags.storageModeStrictness) { \
case StorageModeStrictnessFail: \
OWSFail(@"Unexpected YDB write."); \
break; \
case StorageModeStrictnessFailDebug: \
OWSFailDebug(@"Unexpected YDB write."); \
break; \
case StorageModeStrictnessLog: \
OWSLogError(@"Unexpected YDB write."); \
break; \
} \
} \
} while (NO)
#pragma mark -
@interface TSYapDatabaseObject ()
@property (atomic, nullable) NSNumber *grdbId;
@end
#pragma mark -
@implementation TSYapDatabaseObject
- (instancetype)init
{
return [self initWithUniqueId:[[NSUUID UUID] UUIDString]];
}
- (instancetype)initWithUniqueId:(NSString *)uniqueId
{
self = [super init];
if (!self) {
return self;
}
if (uniqueId.length > 0) {
_uniqueId = uniqueId;
} else {
OWSFailDebug(@"Invalid uniqueId.");
_uniqueId = [[NSUUID UUID] UUIDString];
}
return self;
}
- (instancetype)initWithGrdbId:(int64_t)grdbId uniqueId:(NSString *)uniqueId
{
self = [super init];
if (!self) {
return self;
}
if (uniqueId.length > 0) {
_uniqueId = uniqueId;
} else {
OWSFailDebug(@"Invalid uniqueId.");
_uniqueId = [[NSUUID UUID] UUIDString];
}
_grdbId = @(grdbId);
return self;
}
- (nullable instancetype)initWithCoder:(NSCoder *)coder
{
self = [super initWithCoder:coder];
if (!self) {
return self;
}
if (_uniqueId.length < 1) {
OWSFailDebug(@"Invalid uniqueId.");
_uniqueId = [[NSUUID UUID] UUIDString];
}
return self;
}
- (SDSDatabaseStorage *)databaseStorage
{
return SDSDatabaseStorage.shared;
}
+ (SDSDatabaseStorage *)databaseStorage
{
return SDSDatabaseStorage.shared;
}
- (StorageCoordinator *)storageCoordinator
{
return SSKEnvironment.shared.storageCoordinator;
}
+ (StorageCoordinator *)storageCoordinator
{
return SSKEnvironment.shared.storageCoordinator;
}
+ (NSString *)collection
{
return NSStringFromClass([self class]);
}
#pragma mark -
- (void)ydb_saveWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssertCanWriteYDB();
if (!self.shouldBeSaved) {
OWSLogDebug(@"Skipping save for %@.", [self class]);
return;
}
[transaction setObject:self forKey:self.uniqueId inCollection:[[self class] collection]];
}
- (void)ydb_removeWithTransaction:(YapDatabaseReadWriteTransaction *)transaction
{
OWSAssertCanWriteYDB();
[transaction removeObjectForKey:self.uniqueId inCollection:[[self class] collection]];
}
+ (void)ydb_enumerateCollectionObjectsWithTransaction:(YapDatabaseReadTransaction *)transaction
usingBlock:(void (^)(id object, BOOL *stop))block
{
OWSAssertCanReadYDB();
// Ignoring most of the YapDB parameters, and just passing through the ones we usually use.
void (^yapBlock)(NSString *key, id object, id metadata, BOOL *stop)
= ^void(NSString *key, id object, id metadata, BOOL *stop) {
block(object, stop);
};
[transaction enumerateRowsInCollection:[self collection] usingBlock:yapBlock];
}
+ (nullable instancetype)ydb_fetchObjectWithUniqueID:(NSString *)uniqueID
transaction:(YapDatabaseReadTransaction *)transaction
{
OWSAssertCanReadYDB();
return [transaction objectForKey:uniqueID inCollection:[self collection]];
}
#pragma mark Reload
- (void)ydb_reloadWithTransaction:(YapDatabaseReadTransaction *)transaction
{
OWSAssertCanReadYDB();
[self ydb_reloadWithTransaction:transaction ignoreMissing:NO];
}
- (void)ydb_reloadWithTransaction:(YapDatabaseReadTransaction *)transaction ignoreMissing:(BOOL)ignoreMissing
{
OWSAssertCanReadYDB();
TSYapDatabaseObject *latest = [[self class] ydb_fetchObjectWithUniqueID:self.uniqueId transaction:transaction];
if (!latest) {
if (!ignoreMissing) {
OWSFailDebug(@"`latest` was unexpectedly nil");
}
return;
}
[self setValuesForKeysWithDictionary:latest.dictionaryValue];
}
#pragma mark -
- (BOOL)shouldBeSaved
{
return YES;
}
+ (BOOL)shouldBeIndexedForFTS
{
return NO;
}
#pragma mark - Write Hooks
- (void)anyWillInsertWithTransaction:(SDSAnyWriteTransaction *)transaction
{
// Do nothing.
}
- (void)anyDidInsertWithTransaction:(SDSAnyWriteTransaction *)transaction
{
// Do nothing.
}
- (void)anyWillUpdateWithTransaction:(SDSAnyWriteTransaction *)transaction
{
// Do nothing.
}
- (void)anyDidUpdateWithTransaction:(SDSAnyWriteTransaction *)transaction
{
// Do nothing.
}
- (void)anyWillRemoveWithTransaction:(SDSAnyWriteTransaction *)transaction
{
// Do nothing.
}
- (void)anyDidRemoveWithTransaction:(SDSAnyWriteTransaction *)transaction
{
// Do nothing.
}
#pragma mark - SDSRecordDelegate
- (void)updateRowId:(int64_t)rowId
{
if (self.grdbId != nil) {
OWSAssertDebug(self.grdbId.longLongValue == rowId);
OWSFailDebug(@"grdbId set more than once.");
}
self.grdbId = @(rowId);
}
@end
NS_ASSUME_NONNULL_END