640 lines
20 KiB
Objective-C
640 lines
20 KiB
Objective-C
#import "YapCollectionsDatabaseConnection.h"
|
|
#import "YapCollectionsDatabasePrivate.h"
|
|
|
|
#import "YapAbstractDatabasePrivate.h"
|
|
#import "YapCacheCollectionKey.h"
|
|
|
|
#import "YapDatabaseString.h"
|
|
#import "YapDatabaseLogging.h"
|
|
|
|
#if ! __has_feature(objc_arc)
|
|
#warning This file must be compiled with ARC. Use -fobjc-arc flag (or convert project to ARC).
|
|
#endif
|
|
|
|
/**
|
|
* Define log level for this file.
|
|
* See YapDatabaseLogging.h for more information.
|
|
**/
|
|
#if DEBUG
|
|
static const int ydbFileLogLevel = YDB_LOG_LEVEL_INFO;
|
|
#else
|
|
static const int ydbFileLogLevel = YDB_LOG_LEVEL_WARN;
|
|
#endif
|
|
|
|
|
|
@implementation YapCollectionsDatabaseConnection {
|
|
|
|
/* As defined in YapCollectionsDatabasePrivate.h :
|
|
|
|
@private
|
|
sqlite3_stmt *getCollectionCountStatement;
|
|
sqlite3_stmt *getKeyCountForCollectionStatement;
|
|
sqlite3_stmt *getKeyCountForAllStatement;
|
|
sqlite3_stmt *getCountForKeyStatement;
|
|
sqlite3_stmt *getDataForKeyStatement;
|
|
sqlite3_stmt *getMetadataForKeyStatement;
|
|
sqlite3_stmt *getAllForKeyStatement;
|
|
sqlite3_stmt *setAllForKeyStatement;
|
|
sqlite3_stmt *setMetaForKeyStatement;
|
|
sqlite3_stmt *removeForKeyStatement;
|
|
sqlite3_stmt *removeCollectionStatement;
|
|
sqlite3_stmt *removeAllStatement;
|
|
sqlite3_stmt *enumerateCollectionsStatement;
|
|
sqlite3_stmt *enumerateKeysInCollectionStatement;
|
|
sqlite3_stmt *enumerateMetadataInCollectionStatement;
|
|
sqlite3_stmt *enumerateMetadataInAllCollectionsStatement;
|
|
sqlite3_stmt *enumerateAllInCollectionStatement;
|
|
sqlite3_stmt *enumerateAllInAllCollectionsStatement;
|
|
|
|
*/
|
|
/* Defined in YapAbstractDatabasePrivate.h:
|
|
|
|
@protected
|
|
dispatch_queue_t connectionQueue;
|
|
void *IsOnConnectionQueueKey;
|
|
|
|
YapAbstractDatabase *database;
|
|
|
|
NSTimeInterval cacheLastWriteTimestamp;
|
|
|
|
@public
|
|
sqlite3 *db;
|
|
|
|
id objectCache; // Either NSMutableDictionary (if unlimited) or YapCache (if limited)
|
|
id metadataCache; // Either NSMutableDictionary (if unlimited) or YapCache (if limited)
|
|
|
|
NSUInteger objectCacheLimit; // Read-only by transaction. Use as consideration of whether to add to cache.
|
|
NSUInteger metadataCacheLimit; // Read-only by transaction. Use as consideration of whether to add to cache.
|
|
|
|
BOOL hasMarkedSqlLevelSharedReadLock; // Read-only by transaction. Use as consideration of whether to invoke method.
|
|
*/
|
|
}
|
|
|
|
- (void)dealloc
|
|
{
|
|
sqlite_finalize_null(&getCollectionCountStatement);
|
|
sqlite_finalize_null(&getKeyCountForCollectionStatement);
|
|
sqlite_finalize_null(&getKeyCountForAllStatement);
|
|
sqlite_finalize_null(&getCountForKeyStatement);
|
|
sqlite_finalize_null(&getDataForKeyStatement);
|
|
sqlite_finalize_null(&setMetaForKeyStatement);
|
|
sqlite_finalize_null(&setAllForKeyStatement);
|
|
sqlite_finalize_null(&removeForKeyStatement);
|
|
sqlite_finalize_null(&removeCollectionStatement);
|
|
sqlite_finalize_null(&removeAllStatement);
|
|
sqlite_finalize_null(&enumerateCollectionsStatement);
|
|
sqlite_finalize_null(&enumerateKeysInCollectionStatement);
|
|
sqlite_finalize_null(&enumerateMetadataInCollectionStatement);
|
|
sqlite_finalize_null(&enumerateMetadataInAllCollectionsStatement);
|
|
sqlite_finalize_null(&enumerateAllInCollectionStatement);
|
|
sqlite_finalize_null(&enumerateAllInAllCollectionsStatement);
|
|
}
|
|
|
|
/**
|
|
* Optional override hook from YapAbstractDatabaseConnection.
|
|
**/
|
|
- (void)_flushMemoryWithLevel:(int)level
|
|
{
|
|
[super _flushMemoryWithLevel:level];
|
|
|
|
if (level >= YapDatabaseConnectionFlushMemoryLevelModerate)
|
|
{
|
|
sqlite_finalize_null(&getCollectionCountStatement);
|
|
sqlite_finalize_null(&getKeyCountForAllStatement);
|
|
sqlite_finalize_null(&getCountForKeyStatement);
|
|
sqlite_finalize_null(&setMetaForKeyStatement);
|
|
sqlite_finalize_null(&removeForKeyStatement);
|
|
sqlite_finalize_null(&removeCollectionStatement);
|
|
sqlite_finalize_null(&removeAllStatement);
|
|
sqlite_finalize_null(&enumerateCollectionsStatement);
|
|
sqlite_finalize_null(&enumerateKeysInCollectionStatement);
|
|
sqlite_finalize_null(&enumerateMetadataInCollectionStatement);
|
|
sqlite_finalize_null(&enumerateMetadataInAllCollectionsStatement);
|
|
sqlite_finalize_null(&enumerateAllInCollectionStatement);
|
|
sqlite_finalize_null(&enumerateAllInAllCollectionsStatement);
|
|
}
|
|
|
|
if (level >= YapDatabaseConnectionFlushMemoryLevelFull)
|
|
{
|
|
sqlite_finalize_null(&getDataForKeyStatement);
|
|
sqlite_finalize_null(&setAllForKeyStatement);
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark Properties
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (YapCollectionsDatabase *)database
|
|
{
|
|
return (YapCollectionsDatabase *)database;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark Statements
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
- (sqlite3_stmt *)getCollectionCountStatement
|
|
{
|
|
if (getCollectionCountStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT COUNT(DISTINCT collection) AS NumberOfRows FROM \"database\";";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &getCollectionCountStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'getCollectionCountStatement': %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return getCollectionCountStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)getKeyCountForCollectionStatement
|
|
{
|
|
if (getKeyCountForCollectionStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT COUNT(*) AS NumberOfRows FROM \"database\" WHERE \"collection\" = ?;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &getKeyCountForCollectionStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'getKeyCountForCollectionStatement': %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return getKeyCountForCollectionStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)getKeyCountForAllStatement
|
|
{
|
|
if (getKeyCountForAllStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT COUNT(*) AS NumberOfRows FROM \"database\";";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &getKeyCountForAllStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'getKeyCountForAllStatement': %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return getKeyCountForAllStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)getCountForKeyStatement
|
|
{
|
|
if (getCountForKeyStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT COUNT(*) AS NumberOfRows FROM \"database\" WHERE \"collection\" = ? AND \"key\" = ?;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &getCountForKeyStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'getCountForKeyStatement': %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return getCountForKeyStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)getDataForKeyStatement
|
|
{
|
|
if (getDataForKeyStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT \"data\" FROM \"database\" WHERE \"collection\" = ? AND \"key\" = ?;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &getDataForKeyStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'getDataForKeyStatement'! %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return getDataForKeyStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)getMetadataForKeyStatement
|
|
{
|
|
if (getMetadataForKeyStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT \"metadata\" FROM \"database\" WHERE \"collection\" = ? AND \"key\" = ?;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &getMetadataForKeyStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'getMetadataForKeyStatement': %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return getMetadataForKeyStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)getAllForKeyStatement
|
|
{
|
|
if (getAllForKeyStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT \"data\", \"metadata\" FROM \"database\" WHERE \"collection\" = ? AND \"key\" = ?;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &getAllForKeyStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'getAllForKeyStatement': %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return getAllForKeyStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)setMetaForKeyStatement
|
|
{
|
|
if (setMetaForKeyStatement == NULL)
|
|
{
|
|
char *stmt = "UPDATE \"database\" SET \"metadata\" = ? WHERE \"collection\" = ? AND \"key\" = ?;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &setMetaForKeyStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'setMetaForKeyStatement'! %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return setMetaForKeyStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)setAllForKeyStatement
|
|
{
|
|
if (setAllForKeyStatement == NULL)
|
|
{
|
|
char *stmt = "INSERT OR REPLACE INTO \"database\""
|
|
" (\"collection\", \"key\", \"data\", \"metadata\") VALUES (?, ?, ?, ?);";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &setAllForKeyStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'setAllForKeyStatement'! %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return setAllForKeyStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)removeForKeyStatement
|
|
{
|
|
if (removeForKeyStatement == NULL)
|
|
{
|
|
char *stmt = "DELETE FROM \"database\" WHERE \"collection\" = ? AND \"key\" = ?;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &removeForKeyStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'removeForKeyStatement'! %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return removeForKeyStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)removeCollectionStatement
|
|
{
|
|
if (removeCollectionStatement == NULL)
|
|
{
|
|
char *stmt = "DELETE FROM \"database\" WHERE \"collection\" = ?;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &removeCollectionStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'removeAllStatement'! %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return removeCollectionStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)removeAllStatement
|
|
{
|
|
if (removeAllStatement == NULL)
|
|
{
|
|
char *stmt = "DELETE FROM \"database\";";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &removeAllStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'removeAllStatement'! %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return removeAllStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)enumerateCollectionsStatement
|
|
{
|
|
if (enumerateCollectionsStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT DISTINCT \"collection\" FROM \"database\";";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &enumerateCollectionsStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'enumerateCollectionsStatement'! %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return enumerateCollectionsStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)enumerateKeysInCollectionStatement
|
|
{
|
|
if (enumerateKeysInCollectionStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT \"key\" FROM \"database\" WHERE collection = ?;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &enumerateKeysInCollectionStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'enumerateKeysInCollectionStatement'! %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return enumerateKeysInCollectionStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)enumerateMetadataInCollectionStatement
|
|
{
|
|
if (enumerateMetadataInCollectionStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT \"key\", \"metadata\" FROM \"database\" WHERE collection = ?;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &enumerateMetadataInCollectionStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'enumerateMetadataInCollectionStatement'! %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return enumerateMetadataInCollectionStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)enumerateMetadataInAllCollectionsStatement
|
|
{
|
|
if (enumerateMetadataInAllCollectionsStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT \"collection\", \"key\", \"metadata\" FROM \"database\" ORDER BY \"collection\" ASC;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &enumerateMetadataInAllCollectionsStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'enumerateMetadataInAllCollectionsStatement'! %d %s",
|
|
status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return enumerateMetadataInAllCollectionsStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)enumerateAllInCollectionStatement
|
|
{
|
|
if (enumerateAllInCollectionStatement == NULL)
|
|
{
|
|
char *stmt = "SELECT \"key\", \"data\", \"metadata\" FROM \"database\" WHERE \"collection\" = ?;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &enumerateAllInCollectionStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'enumerateAllInCollectionStatement'! %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return enumerateAllInCollectionStatement;
|
|
}
|
|
|
|
- (sqlite3_stmt *)enumerateAllInAllCollectionsStatement
|
|
{
|
|
if (enumerateAllInAllCollectionsStatement == NULL)
|
|
{
|
|
char *stmt =
|
|
"SELECT \"collection\", \"key\", \"data\", \"metadata\""
|
|
" FROM \"database\""
|
|
" ORDER BY \"collection\" ASC;";
|
|
|
|
int status = sqlite3_prepare_v2(db, stmt, strlen(stmt)+1, &enumerateAllInAllCollectionsStatement, NULL);
|
|
if (status != SQLITE_OK)
|
|
{
|
|
YDBLogError(@"Error creating 'enumerateAllInAllCollectionsStatement'! %d %s", status, sqlite3_errmsg(db));
|
|
}
|
|
}
|
|
|
|
return enumerateAllInAllCollectionsStatement;
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark Access
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Read-only access to the database.
|
|
*
|
|
* The given block can run concurrently with sibling connections,
|
|
* regardless of whether the sibling connections are executing read-only or read-write transactions.
|
|
**/
|
|
- (void)readWithBlock:(void (^)(YapCollectionsDatabaseReadTransaction *))block
|
|
{
|
|
[super _readWithBlock:block];
|
|
}
|
|
|
|
/**
|
|
* Read-write access to the database.
|
|
*
|
|
* Only a single read-write block can execute among all sibling connections.
|
|
* Thus this method may block if another sibling connection is currently executing a read-write block.
|
|
**/
|
|
- (void)readWriteWithBlock:(void (^)(YapCollectionsDatabaseReadWriteTransaction *transaction))block
|
|
{
|
|
[super _readWriteWithBlock:block];
|
|
}
|
|
|
|
/**
|
|
* Read-only access to the database.
|
|
*
|
|
* The given block can run concurrently with sibling connections,
|
|
* regardless of whether the sibling connections are executing read-only or read-write transactions.
|
|
*
|
|
* This method is asynchronous.
|
|
**/
|
|
- (void)asyncReadWithBlock:(void (^)(YapCollectionsDatabaseReadTransaction *transaction))block
|
|
{
|
|
[super _asyncReadWithBlock:block completionBlock:NULL completionQueue:NULL];
|
|
}
|
|
|
|
/**
|
|
* Read-write access to the database.
|
|
*
|
|
* The given block can run concurrently with sibling connections,
|
|
* regardless of whether the sibling connections are executing read-only or read-write transactions.
|
|
*
|
|
* This method is asynchronous.
|
|
*
|
|
* An optional completion block may be used.
|
|
* The completionBlock will be invoked on the main thread (dispatch_get_main_queue()).
|
|
**/
|
|
- (void)asyncReadWithBlock:(void (^)(YapCollectionsDatabaseReadTransaction *transaction))block
|
|
completionBlock:(dispatch_block_t)completionBlock
|
|
{
|
|
[super _asyncReadWithBlock:block completionBlock:completionBlock completionQueue:NULL];
|
|
}
|
|
|
|
/**
|
|
* Read-write access to the database.
|
|
*
|
|
* The given block can run concurrently with sibling connections,
|
|
* regardless of whether the sibling connections are executing read-only or read-write transactions.
|
|
*
|
|
* This method is asynchronous.
|
|
*
|
|
* An optional completion block may be used.
|
|
* Additionally the dispatch_queue to invoke the completion block may also be specified.
|
|
* If NULL, dispatch_get_main_queue() is automatically used.
|
|
**/
|
|
- (void)asyncReadWithBlock:(void (^)(YapCollectionsDatabaseReadTransaction *transaction))block
|
|
completionBlock:(dispatch_block_t)completionBlock
|
|
completionQueue:(dispatch_queue_t)completionQueue
|
|
{
|
|
[super _asyncReadWithBlock:block completionBlock:completionBlock completionQueue:completionQueue];
|
|
}
|
|
|
|
/**
|
|
* Read-write access to the database.
|
|
*
|
|
* Only a single read-write block can execute among all sibling connections.
|
|
* Thus this method may block if another sibling connection is currently executing a read-write block.
|
|
*
|
|
* This method is asynchronous.
|
|
**/
|
|
- (void)asyncReadWriteWithBlock:(void (^)(YapCollectionsDatabaseReadWriteTransaction *transaction))block
|
|
{
|
|
[super _asyncReadWriteWithBlock:block completionBlock:NULL completionQueue:NULL];
|
|
}
|
|
|
|
/**
|
|
* Read-write access to the database.
|
|
*
|
|
* Only a single read-write block can execute among all sibling connections.
|
|
* Thus the execution of the block may be delayted if another sibling connection
|
|
* is currently executing a read-write block.
|
|
*
|
|
* This method is asynchronous.
|
|
*
|
|
* An optional completion block may be used.
|
|
* The completionBlock will be invoked on the main thread (dispatch_get_main_queue()).
|
|
**/
|
|
- (void)asyncReadWriteWithBlock:(void (^)(YapCollectionsDatabaseReadWriteTransaction *transaction))block
|
|
completionBlock:(dispatch_block_t)completionBlock
|
|
{
|
|
[super _asyncReadWriteWithBlock:block completionBlock:completionBlock completionQueue:NULL];
|
|
}
|
|
|
|
/**
|
|
* Read-write access to the database.
|
|
*
|
|
* Only a single read-write block can execute among all sibling connections.
|
|
* Thus the execution of the block may be delayted if another sibling connection
|
|
* is currently executing a read-write block.
|
|
*
|
|
* This method is asynchronous.
|
|
*
|
|
* An optional completion block may be used.
|
|
* Additionally the dispatch_queue to invoke the completion block may also be specified.
|
|
* If NULL, dispatch_get_main_queue() is automatically used.
|
|
**/
|
|
- (void)asyncReadWriteWithBlock:(void (^)(YapCollectionsDatabaseReadWriteTransaction *transaction))block
|
|
completionBlock:(dispatch_block_t)completionBlock
|
|
completionQueue:(dispatch_queue_t)completionQueue
|
|
{
|
|
[super _asyncReadWriteWithBlock:block completionBlock:completionBlock completionQueue:completionQueue];
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
#pragma mark States
|
|
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
|
|
|
/**
|
|
* Required method.
|
|
* Returns the proper type of transaction for this connection class.
|
|
**/
|
|
- (YapAbstractDatabaseTransaction *)newReadTransaction
|
|
{
|
|
return [[YapCollectionsDatabaseReadTransaction alloc] initWithConnection:self];
|
|
}
|
|
|
|
/**
|
|
* Required method.
|
|
* Returns the proper type of transaction for this connection class.
|
|
**/
|
|
- (YapAbstractDatabaseTransaction *)newReadWriteTransaction
|
|
{
|
|
return [[YapCollectionsDatabaseReadWriteTransaction alloc] initWithConnection:self];
|
|
}
|
|
|
|
/**
|
|
* We override this method to ensure our changeset variables are prepared for use.
|
|
**/
|
|
- (void)preReadWriteTransaction:(YapAbstractDatabaseTransaction *)transaction
|
|
{
|
|
[super preReadWriteTransaction:transaction];
|
|
|
|
if (changedKeys == nil) {
|
|
changedKeys = [[NSMutableSet alloc] init];
|
|
}
|
|
if (resetCollections == nil) {
|
|
resetCollections = [[NSMutableSet alloc] init];
|
|
}
|
|
allKeysRemoved = NO;
|
|
}
|
|
|
|
/**
|
|
* We override this method to reset our changeset variables.
|
|
**/
|
|
- (void)postReadWriteTransaction:(YapAbstractDatabaseTransaction *)transaction
|
|
{
|
|
[super postReadWriteTransaction:transaction];
|
|
|
|
[changedKeys removeAllObjects];
|
|
[resetCollections removeAllObjects];
|
|
}
|
|
|
|
/**
|
|
* Required method.
|
|
*
|
|
* This method is invoked from within the postReadWriteTransaction operations.
|
|
* This method is invoked before anything has been committed.
|
|
*
|
|
* If changes have been made, it should return a changeset dictionary.
|
|
* If no changes have been made, it should return nil.
|
|
*
|
|
* @see [YapAbstractDatabase cacheChangesetBlockFromChanges:]
|
|
**/
|
|
- (NSMutableDictionary *)changeset
|
|
{
|
|
if ([changedKeys count] > 0 || [resetCollections count] > 0 || allKeysRemoved)
|
|
{
|
|
NSMutableDictionary *changeset = [NSMutableDictionary dictionaryWithCapacity:4];
|
|
|
|
if ([changedKeys count] > 0)
|
|
[changeset setObject:[changedKeys copy] forKey:@"changedKeys"];
|
|
|
|
if ([resetCollections count] > 0)
|
|
[changeset setObject:[resetCollections copy] forKey:@"resetCollections"];
|
|
|
|
if (allKeysRemoved)
|
|
[changeset setObject:@(YES) forKey:@"allKeysRemoved"];
|
|
|
|
return changeset;
|
|
}
|
|
else
|
|
{
|
|
return nil;
|
|
}
|
|
}
|
|
|
|
@end
|