vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.m in motion-yapper-0.0.1 vs vendor/Pods/YapDatabase/YapDatabase/Extensions/Views/YapDatabaseViewTransaction.m in motion-yapper-0.0.2
- old
+ new
@@ -23,10 +23,14 @@
static const int ydbLogLevel = YDB_LOG_LEVEL_WARN;
#else
static const int ydbLogLevel = YDB_LOG_LEVEL_WARN;
#endif
+#define ExtKey_classVersion @"classVersion"
+#define ExtKey_persistent @"persistent"
+#define ExtKey_version_deprecated @"version"
+#define ExtKey_versionTag @"versionTag"
/**
* The view is tasked with storing ordered arrays of keys.
* In doing so, it splits the array into "pages" of keys,
* and stores the pages in the database.
@@ -34,10 +38,17 @@
* And only the contents of a single page need be read to fetch a single key.
**/
#define YAP_DATABASE_VIEW_MAX_PAGE_SIZE 50
/**
+ * Declare that this class implements YapDatabaseExtensionTransaction_Hooks protocol.
+ * This is done privately, as the protocol is internal.
+**/
+@interface YapDatabaseViewTransaction () <YapDatabaseExtensionTransaction_Hooks>
+@end
+
+/**
* ARCHITECTURE OVERVIEW:
*
* A YapDatabaseView allows one to store a ordered array of collection/key tuples.
* Furthermore, groups are supported, which means there may be multiple ordered arrays of tuples, one per group.
*
@@ -73,10 +84,12 @@
@implementation YapDatabaseViewTransaction
- (id)initWithViewConnection:(YapDatabaseViewConnection *)inViewConnection
databaseTransaction:(YapDatabaseReadTransaction *)inDatabaseTransaction
{
+ YDBLogAutoTrace();
+
if ((self = [super init]))
{
viewConnection = inViewConnection;
databaseTransaction = inDatabaseTransaction;
@@ -102,74 +115,124 @@
* Return YES if completed successfully, or if already prepared.
* Return NO if some kind of error occured.
**/
- (BOOL)createIfNeeded
{
+ YDBLogAutoTrace();
+
+ int classVersion = YAP_DATABASE_VIEW_CLASS_VERSION;
+ BOOL isPersistent = [self isPersistentView];
+
+ NSString *versionTag = viewConnection->view->versionTag;
+
+ // Figure out what steps we need to take in order to register the view
+
BOOL needsCreateTables = NO;
+ BOOL oldIsPersistent = NO;
+ BOOL hasOldIsPersistent = NO;
+
+ NSString *oldVersionTag = nil;
+
// Check classVersion (the internal version number of YapDatabaseView implementation)
- int oldClassVersion = [self intValueForExtensionKey:@"classVersion"];
- int classVersion = YAP_DATABASE_VIEW_CLASS_VERSION;
+ int oldClassVersion = 0;
+ BOOL hasOldClassVersion = [self getIntValue:&oldClassVersion forExtensionKey:ExtKey_classVersion];
- if (oldClassVersion != classVersion)
+ if (!hasOldClassVersion)
+ {
needsCreateTables = YES;
+ }
+ else if (oldClassVersion != classVersion)
+ {
+ [self dropTablesForOldClassVersion:oldClassVersion];
+ needsCreateTables = YES;
+ }
// Check persistence.
// Need to properly transition from persistent to non-persistent, and vice-versa.
- BOOL oldIsPersistent = NO;
- BOOL hasOldIsPersistent = [self getBoolValue:&oldIsPersistent forExtensionKey:@"persistent"];
-
- BOOL isPersistent = [self isPersistentView];
-
- if (hasOldIsPersistent && (oldIsPersistent != isPersistent))
+ if (!needsCreateTables || hasOldClassVersion)
{
- [[viewConnection->view class]
- dropTablesForRegisteredName:[self registeredName]
- withTransaction:(YapDatabaseReadWriteTransaction *)databaseTransaction];
+ hasOldIsPersistent = [self getBoolValue:&oldIsPersistent forExtensionKey:ExtKey_persistent];
- needsCreateTables = YES;
+ if (hasOldIsPersistent && oldIsPersistent && !isPersistent)
+ {
+ [[viewConnection->view class]
+ dropTablesForRegisteredName:[self registeredName]
+ withTransaction:(YapDatabaseReadWriteTransaction *)databaseTransaction];
+ }
+
+ if (!hasOldIsPersistent || (oldIsPersistent != isPersistent))
+ {
+ needsCreateTables = YES;
+ }
+ else if (!isPersistent)
+ {
+ // We always have to create & populate the tables for non-persistent views.
+ // Even when re-registering from previous app launch.
+ needsCreateTables = YES;
+
+ oldVersionTag = [self stringValueForExtensionKey:ExtKey_versionTag];
+ }
}
// Create or re-populate if needed
if (needsCreateTables)
{
// First time registration
- [self dropTablesForOldClassVersion:oldClassVersion];
-
if (![self createTables]) return NO;
if (![self populateView]) return NO;
- [self setIntValue:classVersion forExtensionKey:@"classVersion"];
+ if (!hasOldClassVersion || (oldClassVersion != classVersion)) {
+ [self setIntValue:classVersion forExtensionKey:ExtKey_classVersion];
+ }
- [self setBoolValue:isPersistent forExtensionKey:@"persistent"];
+ if (!hasOldIsPersistent || (oldIsPersistent != isPersistent)) {
+ [self setBoolValue:isPersistent forExtensionKey:ExtKey_persistent];
+ }
- int userSuppliedConfigVersion = viewConnection->view->version;
- [self setIntValue:userSuppliedConfigVersion forExtensionKey:@"version"];
+ if (![oldVersionTag isEqualToString:versionTag]) {
+ [self setStringValue:versionTag forExtensionKey:ExtKey_versionTag];
+ }
}
else
{
// Check user-supplied config version.
// We may need to re-populate the database if the groupingBlock or sortingBlock changed.
- int oldVersion = [self intValueForExtensionKey:@"version"];
- int newVersion = viewConnection->view->version;
+ oldVersionTag = [self stringValueForExtensionKey:ExtKey_versionTag];
- if (oldVersion != newVersion)
+ BOOL hasOldVersion_deprecated = NO;
+ if (oldVersionTag == nil)
{
- if (![self populateView]) return NO;
+ int oldVersion_deprecated = 0;
+ hasOldVersion_deprecated = [self getIntValue:&oldVersion_deprecated
+ forExtensionKey:ExtKey_version_deprecated];
- [self setIntValue:newVersion forExtensionKey:@"version"];
+ if (hasOldVersion_deprecated)
+ {
+ oldVersionTag = [NSString stringWithFormat:@"%d", oldVersion_deprecated];
+ }
}
- if (!hasOldIsPersistent)
+ if (![oldVersionTag isEqualToString:versionTag])
{
- [self setBoolValue:isPersistent forExtensionKey:@"persistent"];
+ if (![self populateView]) return NO;
+
+ [self setStringValue:versionTag forExtensionKey:ExtKey_versionTag];
+
+ if (hasOldVersion_deprecated)
+ [self removeValueForExtensionKey:ExtKey_version_deprecated];
}
+ else if (hasOldVersion_deprecated)
+ {
+ [self removeValueForExtensionKey:ExtKey_version_deprecated];
+ [self setStringValue:versionTag forExtensionKey:ExtKey_versionTag];
+ }
}
return YES;
}
@@ -182,10 +245,12 @@
* Return YES if completed successfully, or if already prepared.
* Return NO if some kind of error occured.
**/
- (BOOL)prepareIfNeeded
{
+ YDBLogAutoTrace();
+
if (viewConnection->group_pagesMetadata_dict && viewConnection->pageKey_group_dict)
{
// Already prepared
return YES;
}
@@ -426,10 +491,12 @@
return !error;
}
- (void)dropTablesForOldClassVersion:(int)oldClassVersion
{
+ YDBLogAutoTrace();
+
if (oldClassVersion == 1)
{
// In version 2, we switched from 'view_name_key' to 'view_name_map'.
// The old table stored key->pageKey mappings.
// The new table stores rowid->pageKey mappings.
@@ -471,10 +538,12 @@
}
}
- (BOOL)createTables
{
+ YDBLogAutoTrace();
+
if ([self isPersistentView])
{
sqlite3 *db = databaseTransaction->connection->db;
NSString *mapTableName = [self mapTableName];
@@ -554,19 +623,24 @@
}
}
- (BOOL)populateView
{
+ YDBLogAutoTrace();
+
// Remove everything from the database
[self removeAllRowids];
// Initialize ivars
- viewConnection->group_pagesMetadata_dict = [[NSMutableDictionary alloc] init];
- viewConnection->pageKey_group_dict = [[NSMutableDictionary alloc] init];
+ if (viewConnection->group_pagesMetadata_dict == nil)
+ viewConnection->group_pagesMetadata_dict = [[NSMutableDictionary alloc] init];
+ if (viewConnection->pageKey_group_dict == nil)
+ viewConnection->pageKey_group_dict = [[NSMutableDictionary alloc] init];
+
// Enumerate the existing rows in the database and populate the view
__unsafe_unretained YapDatabaseView *view = viewConnection->view;
BOOL groupingNeedsObject = view->groupingBlockType == YapDatabaseViewBlockTypeWithObject ||
@@ -583,41 +657,51 @@
BOOL needsObject = groupingNeedsObject || sortingNeedsObject;
BOOL needsMetadata = groupingNeedsMetadata || sortingNeedsMetadata;
NSString *(^getGroup)(NSString *collection, NSString *key, id object, id metadata);
- getGroup = ^(NSString *collection, NSString *key, id object, id metadata){
-
- if (view->groupingBlockType == YapDatabaseViewBlockTypeWithKey)
- {
+
+ if (view->groupingBlockType == YapDatabaseViewBlockTypeWithKey)
+ {
+ getGroup = ^(NSString *collection, NSString *key, id object, id metadata){
+
__unsafe_unretained YapDatabaseViewGroupingWithKeyBlock groupingBlock =
(YapDatabaseViewGroupingWithKeyBlock)view->groupingBlock;
return groupingBlock(collection, key);
- }
- else if (view->groupingBlockType == YapDatabaseViewBlockTypeWithObject)
- {
+ };
+ }
+ else if (view->groupingBlockType == YapDatabaseViewBlockTypeWithObject)
+ {
+ getGroup = ^(NSString *collection, NSString *key, id object, id metadata){
+
__unsafe_unretained YapDatabaseViewGroupingWithObjectBlock groupingBlock =
(YapDatabaseViewGroupingWithObjectBlock)view->groupingBlock;
return groupingBlock(collection, key, object);
- }
- else if (view->groupingBlockType == YapDatabaseViewBlockTypeWithMetadata)
- {
+ };
+ }
+ else if (view->groupingBlockType == YapDatabaseViewBlockTypeWithMetadata)
+ {
+ getGroup = ^(NSString *collection, NSString *key, id object, id metadata){
+
__unsafe_unretained YapDatabaseViewGroupingWithMetadataBlock groupingBlock =
(YapDatabaseViewGroupingWithMetadataBlock)view->groupingBlock;
return groupingBlock(collection, key, metadata);
- }
- else
- {
+ };
+ }
+ else
+ {
+ getGroup = ^(NSString *collection, NSString *key, id object, id metadata){
+
__unsafe_unretained YapDatabaseViewGroupingWithRowBlock groupingBlock =
(YapDatabaseViewGroupingWithRowBlock)view->groupingBlock;
return groupingBlock(collection, key, object, metadata);
- }
- };
+ };
+ }
int flags = (YapDatabaseViewChangedObject | YapDatabaseViewChangedMetadata);
if (needsObject && needsMetadata)
{
@@ -859,10 +943,59 @@
}
return YES;
}
+- (void)repopulateView
+{
+ YDBLogAutoTrace();
+
+ // Code overview:
+ //
+ // We could simply run the usual algorithm.
+ // That is, enumerate over every item in the database, and run pretty much the same code as
+ // in the handleUpdateObject:forCollectionKey:withMetadata:rowid:.
+ // However, this causes a potential issue where the sortingBlock will be invoked with items that
+ // no longer exist in the given group.
+ //
+ // Instead we're going to find a way around this.
+ // That way the sortingBlock works in a manner we're used to.
+ //
+ // Here's the algorithm overview:
+ //
+ // - Insert remove ops for every row & group
+ // - Remove all items from the database tables
+ // - Flush the group_pagesMetadata_dict (and related ivars)
+ // - Set the reset flag (for internal notification creation)
+ // - And then run the normal populate routine, with one exceptione handled by the isRepopulate flag.
+ //
+ // The changeset mechanism will automatically consolidate all changes to the minimum.
+
+ for (NSString *group in viewConnection->group_pagesMetadata_dict)
+ {
+ // We must add the changes in reverse order.
+ // Either that, or the change index of each item would have to be zero,
+ // because a YapDatabaseViewRowChange records the index at the moment the change happens.
+
+ [self enumerateRowidsInGroup:group
+ withOptions:NSEnumerationReverse
+ usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop)
+ {
+ YapCollectionKey *collectionKey = [databaseTransaction collectionKeyForRowid:rowid];
+
+ [viewConnection->changes addObject:
+ [YapDatabaseViewRowChange deleteKey:collectionKey inGroup:group atIndex:index]];
+ }];
+
+ [viewConnection->changes addObject:[YapDatabaseViewSectionChange deleteGroup:group]];
+ }
+
+ isRepopulate = YES;
+ [self populateView];
+ isRepopulate = NO;
+}
+
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Accessors
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
/**
@@ -1227,11 +1360,11 @@
- (NSUInteger)indexForRowid:(int64_t)rowid inGroup:(NSString *)group withPageKey:(NSString *)pageKey
{
// Calculate the offset of the corresponding page within the group.
NSUInteger pageOffset = 0;
- NSMutableArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
+ NSArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
for (YapDatabaseViewPageMetadata *pageMetadata in pagesMetadataForGroup)
{
if ([pageMetadata->pageKey isEqualToString:pageKey])
{
@@ -1257,11 +1390,11 @@
return pageOffset + indexWithinPage;
}
- (BOOL)getRowid:(int64_t *)rowidPtr atIndex:(NSUInteger)index inGroup:(NSString *)group
{
- NSMutableArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
+ NSArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
NSUInteger pageOffset = 0;
for (YapDatabaseViewPageMetadata *pageMetadata in pagesMetadataForGroup)
{
if ((index < (pageOffset + pageMetadata->count)) && (pageMetadata->count > 0))
@@ -1291,11 +1424,11 @@
// if (count > 0)
// return [self getRowid:rowidPtr atIndex:(count-1) inGroup:group];
// else
// return nil;
- NSMutableArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
+ NSArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
__block int64_t rowid = 0;
__block BOOL found = NO;
[pagesMetadataForGroup enumerateObjectsWithOptions:NSEnumerationReverse
@@ -1373,11 +1506,11 @@
[viewConnection->mapCache setObject:pageKey forKey:@(rowid)];
// Add change to log
[viewConnection->changes addObject:
- [YapDatabaseViewSectionChange insertGroup:group]];
+ [YapDatabaseViewSectionChange insertGroup:group]];
[viewConnection->changes addObject:
[YapDatabaseViewRowChange insertKey:collectionKey inGroup:group atIndex:0]];
[viewConnection->mutatedGroups addObject:group];
@@ -1625,66 +1758,58 @@
if (view->sortingBlockType == YapDatabaseViewBlockTypeWithKey)
{
__unsafe_unretained YapDatabaseViewSortingWithKeyBlock sortingBlock =
(YapDatabaseViewSortingWithKeyBlock)view->sortingBlock;
- NSString *anotherKey = nil;
- NSString *anotherCollection = nil;
- [databaseTransaction getKey:&anotherKey collection:&anotherCollection forRowid:anotherRowid];
+ YapCollectionKey *another = [databaseTransaction collectionKeyForRowid:anotherRowid];
return sortingBlock(group, collectionKey.collection, collectionKey.key,
- anotherCollection, anotherKey);
+ another.collection, another.key);
}
else if (view->sortingBlockType == YapDatabaseViewBlockTypeWithObject)
{
__unsafe_unretained YapDatabaseViewSortingWithObjectBlock sortingBlock =
(YapDatabaseViewSortingWithObjectBlock)view->sortingBlock;
- NSString *anotherKey = nil;
- NSString *anotherCollection = nil;
+ YapCollectionKey *another = nil;
id anotherObject = nil;
- [databaseTransaction getKey:&anotherKey
- collection:&anotherCollection
- object:&anotherObject
- forRowid:anotherRowid];
+ [databaseTransaction getCollectionKey:&another
+ object:&anotherObject
+ forRowid:anotherRowid];
return sortingBlock(group, collectionKey.collection, collectionKey.key, object,
- anotherCollection, anotherKey, anotherObject);
+ another.collection, another.key, anotherObject);
}
else if (view->sortingBlockType == YapDatabaseViewBlockTypeWithMetadata)
{
__unsafe_unretained YapDatabaseViewSortingWithMetadataBlock sortingBlock =
(YapDatabaseViewSortingWithMetadataBlock)view->sortingBlock;
- NSString *anotherKey = nil;
- NSString *anotherCollection = nil;
+ YapCollectionKey *another = nil;
id anotherMetadata = nil;
- [databaseTransaction getKey:&anotherKey
- collection:&anotherCollection
- metadata:&anotherMetadata
- forRowid:anotherRowid];
+ [databaseTransaction getCollectionKey:&another
+ metadata:&anotherMetadata
+ forRowid:anotherRowid];
return sortingBlock(group, collectionKey.collection, collectionKey.key, metadata,
- anotherCollection, anotherKey, anotherMetadata);
+ another.collection, another.key, anotherMetadata);
}
else
{
__unsafe_unretained YapDatabaseViewSortingWithRowBlock sortingBlock =
(YapDatabaseViewSortingWithRowBlock)view->sortingBlock;
- NSString *anotherKey = nil;
- NSString *anotherCollection = nil;
+ YapCollectionKey *another = nil;
id anotherObject = nil;
id anotherMetadata = nil;
- [databaseTransaction getKey:&anotherKey
- collection:&anotherCollection
- object:&anotherObject
- metadata:&anotherMetadata
- forRowid:anotherRowid];
+ [databaseTransaction getCollectionKey:&another
+ object:&anotherObject
+ metadata:&anotherMetadata
+ forRowid:anotherRowid];
return sortingBlock(group, collectionKey.collection, collectionKey.key, object, metadata,
- anotherCollection, anotherKey, anotherObject, anotherMetadata);
+ another.collection, another.key, anotherObject, anotherMetadata);
}
};
NSComparisonResult cmp;
@@ -1948,12 +2073,14 @@
YDBLogVerbose(@"Removing collection(%@) key(%@) from page(%@) at index(%lu)",
collectionKey.collection, collectionKey.key, page, (unsigned long)indexWithinPage);
// Add change to log
+ NSUInteger indexWithinGroup = pageOffset + indexWithinPage;
+
[viewConnection->changes addObject:
- [YapDatabaseViewRowChange deleteKey:collectionKey inGroup:group atIndex:(pageOffset + indexWithinPage)]];
+ [YapDatabaseViewRowChange deleteKey:collectionKey inGroup:group atIndex:indexWithinGroup]];
[viewConnection->mutatedGroups addObject:group];
// Update page (by removing key from array)
@@ -2063,11 +2190,11 @@
{
[page removeRowidAtIndex:i];
numRemoved++;
[viewConnection->changes addObject:
- [YapDatabaseViewRowChange deleteKey:collectionKey inGroup:group atIndex:(pageOffset + i)]];
+ [YapDatabaseViewRowChange deleteKey:collectionKey inGroup:group atIndex:(pageOffset + i)]];
}
}
[viewConnection->mutatedGroups addObject:group];
@@ -2144,14 +2271,16 @@
{
[mapTableTransaction removeAllObjects];
[pageTableTransaction removeAllObjects];
[pageMetadataTableTransaction removeAllObjects];
}
-
+
for (NSString *group in viewConnection->group_pagesMetadata_dict)
{
- [viewConnection->changes addObject:[YapDatabaseViewSectionChange resetGroup:group]];
+ if (!isRepopulate) {
+ [viewConnection->changes addObject:[YapDatabaseViewSectionChange resetGroup:group]];
+ }
[viewConnection->mutatedGroups addObject:group];
}
[viewConnection->group_pagesMetadata_dict removeAllObjects];
[viewConnection->pageKey_group_dict removeAllObjects];
@@ -2427,11 +2556,11 @@
* This method is only called if within a readwrite transaction.
*
* Extensions may implement it to perform any "cleanup" before the changeset is requested.
* Remember, the changeset is requested before the commitTransaction method is invoked.
**/
-- (void)preCommitReadWriteTransaction
+- (void)prepareChangeset
{
YDBLogAutoTrace();
// During the readwrite transaction we do nothing to enforce the pageSize restriction.
// Multiple modifications during a transaction make it non worthwhile.
@@ -2512,11 +2641,11 @@
hasDirtyLink = YES;
}
else
{
NSString *group = [self groupForPageKey:pageKey];
- NSMutableArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
+ NSArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
for (YapDatabaseViewPageMetadata *pm in pagesMetadataForGroup)
{
if ([pm->pageKey isEqualToString:pageKey])
{
@@ -2863,12 +2992,12 @@
pageMetadata = [viewConnection->dirtyLinks objectForKey:pageKey];
if (pageMetadata == nil)
{
NSString *group = [self groupForPageKey:pageKey];
- NSMutableArray *pagesMetadataForGroup =
- [viewConnection->group_pagesMetadata_dict objectForKey:group];
+ NSArray *pagesMetadataForGroup =
+ [viewConnection->group_pagesMetadata_dict objectForKey:group];
for (YapDatabaseViewPageMetadata *pm in pagesMetadataForGroup)
{
if ([pm->pageKey isEqualToString:pageKey])
{
@@ -2979,19 +3108,21 @@
/**
* YapDatabase extension hook.
* This method is invoked by a YapDatabaseReadWriteTransaction as a post-operation-hook.
**/
- (void)handleInsertObject:(id)object
- forKey:(NSString *)key
- inCollection:(NSString *)collection
+ forCollectionKey:(YapCollectionKey *)collectionKey
withMetadata:(id)metadata
rowid:(int64_t)rowid
{
YDBLogAutoTrace();
__unsafe_unretained YapDatabaseView *view = viewConnection->view;
+ __unsafe_unretained NSString *collection = collectionKey.collection;
+ __unsafe_unretained NSString *key = collectionKey.key;
+
// Invoke the grouping block to find out if the object should be included in the view.
NSString *group = nil;
NSSet *allowedCollections = view->options.allowedCollections;
@@ -3034,12 +3165,10 @@
else
{
// Add key to view.
// This was an insert operation, so we know the key wasn't already in the view.
- YapCollectionKey *collectionKey = [[YapCollectionKey alloc] initWithCollection:collection key:key];
-
int flags = (YapDatabaseViewChangedObject | YapDatabaseViewChangedMetadata);
[self insertRowid:rowid
collectionKey:collectionKey
object:object
@@ -3053,22 +3182,21 @@
/**
* YapDatabase extension hook.
* This method is invoked by a YapDatabaseReadWriteTransaction as a post-operation-hook.
**/
- (void)handleUpdateObject:(id)object
- forKey:(NSString *)key
- inCollection:(NSString *)collection
+ forCollectionKey:(YapCollectionKey *)collectionKey
withMetadata:(id)metadata
rowid:(int64_t)rowid
{
YDBLogAutoTrace();
- NSParameterAssert(key != nil);
- NSParameterAssert(collection != nil);
-
__unsafe_unretained YapDatabaseView *view = viewConnection->view;
+ __unsafe_unretained NSString *collection = collectionKey.collection;
+ __unsafe_unretained NSString *key = collectionKey.key;
+
// Invoke the grouping block to find out if the object should be included in the view.
NSString *group = nil;
NSSet *allowedCollections = view->options.allowedCollections;
@@ -3101,12 +3229,10 @@
(YapDatabaseViewGroupingWithRowBlock)view->groupingBlock;
group = groupingBlock(collection, key, object, metadata);
}
}
-
- YapCollectionKey *collectionKey = [[YapCollectionKey alloc] initWithCollection:collection key:key];
if (group == nil)
{
// Remove key from view (if needed).
// This was an update operation, so the key may have previously been in the view.
@@ -3132,23 +3258,174 @@
/**
* YapDatabase extension hook.
* This method is invoked by a YapDatabaseReadWriteTransaction as a post-operation-hook.
**/
-- (void)handleUpdateMetadata:(id)metadata
- forKey:(NSString *)key
- inCollection:(NSString *)collection
- withRowid:(int64_t)rowid
+- (void)handleReplaceObject:(id)object forCollectionKey:(YapCollectionKey *)collectionKey withRowid:(int64_t)rowid
{
YDBLogAutoTrace();
__unsafe_unretained YapDatabaseView *view = viewConnection->view;
- YapCollectionKey *collectionKey = [[YapCollectionKey alloc] initWithCollection:collection key:key];
+ __unsafe_unretained NSString *collection = collectionKey.collection;
+ __unsafe_unretained NSString *key = collectionKey.key;
// Invoke the grouping block to find out if the object should be included in the view.
+ id metadata = nil;
+ NSString *group = nil;
+
+ if (view->groupingBlockType == YapDatabaseViewBlockTypeWithKey ||
+ view->groupingBlockType == YapDatabaseViewBlockTypeWithMetadata)
+ {
+ // Grouping is based on the key or metadata.
+ // Neither have changed, and thus the group hasn't changed.
+
+ NSString *pageKey = [self pageKeyForRowid:rowid];
+ group = [self groupForPageKey:pageKey];
+
+ if (group == nil)
+ {
+ // Nothing to do.
+ // The key wasn't previously in the view, and still isn't in the view.
+ lastHandledGroup = group;
+ return;
+ }
+
+ if (view->sortingBlockType == YapDatabaseViewBlockTypeWithKey ||
+ view->sortingBlockType == YapDatabaseViewBlockTypeWithMetadata)
+ {
+ // Nothing has moved because the group hasn't changed and
+ // nothing has changed that relates to sorting.
+
+ int flags = YapDatabaseViewChangedObject;
+ NSUInteger existingIndex = [self indexForRowid:rowid inGroup:group withPageKey:pageKey];
+
+ [viewConnection->changes addObject:
+ [YapDatabaseViewRowChange updateKey:collectionKey changes:flags inGroup:group atIndex:existingIndex]];
+ }
+ else
+ {
+ // Sorting is based on the object, which has changed.
+ // So the sort order may possibly have changed.
+
+ // From previous if statement (above) we know:
+ // sortingBlockType is object or row (object+metadata)
+
+ if (view->sortingBlockType == YapDatabaseViewBlockTypeWithRow)
+ {
+ // Need the metadata for the sorting block
+ metadata = [databaseTransaction metadataForCollectionKey:collectionKey withRowid:rowid];
+ }
+
+ int flags = YapDatabaseViewChangedObject;
+
+ [self insertRowid:rowid
+ collectionKey:collectionKey
+ object:object
+ metadata:metadata
+ inGroup:group withChanges:flags isNew:NO];
+ }
+ }
+ else
+ {
+ // Grouping is based on object or row (object+metadata).
+ // Invoke groupingBlock to see what the new group is.
+
+ NSSet *allowedCollections = view->options.allowedCollections;
+
+ if (!allowedCollections || [allowedCollections containsObject:collection])
+ {
+ if (view->groupingBlockType == YapDatabaseViewBlockTypeWithObject)
+ {
+ __unsafe_unretained YapDatabaseViewGroupingWithObjectBlock groupingBlock =
+ (YapDatabaseViewGroupingWithObjectBlock)view->groupingBlock;
+
+ group = groupingBlock(collection, key, object);
+ }
+ else
+ {
+ __unsafe_unretained YapDatabaseViewGroupingWithRowBlock groupingBlock =
+ (YapDatabaseViewGroupingWithRowBlock)view->groupingBlock;
+
+ metadata = [databaseTransaction metadataForCollectionKey:collectionKey withRowid:rowid];
+ group = groupingBlock(collection, key, object, metadata);
+ }
+ }
+
+ if (group == nil)
+ {
+ // The key is not included in the view.
+ // Remove key from view (if needed).
+
+ [self removeRowid:rowid collectionKey:collectionKey];
+ }
+ else
+ {
+ if (view->sortingBlockType == YapDatabaseViewBlockTypeWithKey ||
+ view->sortingBlockType == YapDatabaseViewBlockTypeWithMetadata)
+ {
+ // Sorting is based on the key or metadata, neither of which has changed.
+ // So if the group hasn't changed, then the sort order hasn't changed.
+
+ NSString *existingPageKey = [self pageKeyForRowid:rowid];
+ NSString *existingGroup = [self groupForPageKey:existingPageKey];
+
+ if ([group isEqualToString:existingGroup])
+ {
+ // Nothing left to do.
+ // The group didn't change, and the sort order cannot change (because the object didn't change).
+
+ int flags = YapDatabaseViewChangedObject;
+ NSUInteger existingIndex = [self indexForRowid:rowid inGroup:group withPageKey:existingPageKey];
+
+ [viewConnection->changes addObject:
+ [YapDatabaseViewRowChange updateKey:collectionKey
+ changes:flags
+ inGroup:group
+ atIndex:existingIndex]];
+
+ lastHandledGroup = group;
+ return;
+ }
+ }
+
+ if (metadata == nil && (view->sortingBlockType == YapDatabaseViewBlockTypeWithMetadata ||
+ view->sortingBlockType == YapDatabaseViewBlockTypeWithRow ))
+ {
+ // Need the metadata for the sorting block
+ metadata = [databaseTransaction metadataForCollectionKey:collectionKey withRowid:rowid];
+ }
+
+ int flags = YapDatabaseViewChangedObject;
+
+ [self insertRowid:rowid
+ collectionKey:collectionKey
+ object:object
+ metadata:metadata
+ inGroup:group withChanges:flags isNew:NO];
+ }
+ }
+
+ lastHandledGroup = group;
+}
+
+/**
+ * YapDatabase extension hook.
+ * This method is invoked by a YapDatabaseReadWriteTransaction as a post-operation-hook.
+**/
+- (void)handleReplaceMetadata:(id)metadata forCollectionKey:(YapCollectionKey *)collectionKey withRowid:(int64_t)rowid
+{
+ YDBLogAutoTrace();
+
+ __unsafe_unretained YapDatabaseView *view = viewConnection->view;
+
+ __unsafe_unretained NSString *collection = collectionKey.collection;
+ __unsafe_unretained NSString *key = collectionKey.key;
+
+ // Invoke the grouping block to find out if the object should be included in the view.
+
id object = nil;
NSString *group = nil;
if (view->groupingBlockType == YapDatabaseViewBlockTypeWithKey ||
view->groupingBlockType == YapDatabaseViewBlockTypeWithObject)
@@ -3188,11 +3465,11 @@
// sortingBlockType is metadata or objectAndMetadata
if (view->sortingBlockType == YapDatabaseViewBlockTypeWithRow)
{
// Need the object for the sorting block
- object = [databaseTransaction objectForKey:key inCollection:collection withRowid:rowid];
+ object = [databaseTransaction objectForCollectionKey:collectionKey withRowid:rowid];
}
int flags = YapDatabaseViewChangedMetadata;
[self insertRowid:rowid
@@ -3221,11 +3498,11 @@
else
{
__unsafe_unretained YapDatabaseViewGroupingWithRowBlock groupingBlock =
(YapDatabaseViewGroupingWithRowBlock)view->groupingBlock;
- object = [databaseTransaction objectForKey:key inCollection:collection withRowid:rowid];
+ object = [databaseTransaction objectForCollectionKey:collectionKey withRowid:rowid];
group = groupingBlock(collection, key, object, metadata);
}
}
if (group == nil)
@@ -3267,11 +3544,11 @@
if (object == nil && (view->sortingBlockType == YapDatabaseViewBlockTypeWithObject ||
view->sortingBlockType == YapDatabaseViewBlockTypeWithRow ))
{
// Need the object for the sorting block
- object = [databaseTransaction objectForKey:key inCollection:collection withRowid:rowid];
+ object = [databaseTransaction objectForCollectionKey:collectionKey withRowid:rowid];
}
int flags = YapDatabaseViewChangedMetadata;
[self insertRowid:rowid
@@ -3287,11 +3564,11 @@
/**
* YapDatabase extension hook.
* This method is invoked by a YapDatabaseReadWriteTransaction as a post-operation-hook.
**/
-- (void)handleTouchObjectForKey:(NSString *)key inCollection:(NSString *)collection withRowid:(int64_t)rowid
+- (void)handleTouchObjectForCollectionKey:(YapCollectionKey *)collectionKey withRowid:(int64_t)rowid
{
YDBLogAutoTrace();
// Almost the same as touchRowForKey:inCollection:
@@ -3299,11 +3576,10 @@
if (pageKey)
{
NSString *group = [self groupForPageKey:pageKey];
NSUInteger index = [self indexForRowid:rowid inGroup:group withPageKey:pageKey];
- YapCollectionKey *collectionKey = [[YapCollectionKey alloc] initWithCollection:collection key:key];
int flags = (YapDatabaseViewChangedObject | YapDatabaseViewChangedMetadata);
[viewConnection->changes addObject:
[YapDatabaseViewRowChange updateKey:collectionKey changes:flags inGroup:group atIndex:index]];
}
@@ -3311,11 +3587,11 @@
/**
* YapDatabase extension hook.
* This method is invoked by a YapDatabaseReadWriteTransaction as a post-operation-hook.
**/
-- (void)handleTouchMetadataForKey:(NSString *)key inCollection:(NSString *)collection withRowid:(int64_t)rowid
+- (void)handleTouchMetadataForCollectionKey:(YapCollectionKey *)collectionKey withRowid:(int64_t)rowid
{
YDBLogAutoTrace();
// Almost the same as touchMetadatForKey:inCollection:
@@ -3330,11 +3606,10 @@
if (pageKey)
{
NSString *group = [self groupForPageKey:pageKey];
NSUInteger index = [self indexForRowid:rowid inGroup:group withPageKey:pageKey];
- YapCollectionKey *collectionKey = [[YapCollectionKey alloc] initWithCollection:collection key:key];
int flags = YapDatabaseViewChangedMetadata;
[viewConnection->changes addObject:
[YapDatabaseViewRowChange updateKey:collectionKey changes:flags inGroup:group atIndex:index]];
}
@@ -3343,19 +3618,14 @@
/**
* YapDatabase extension hook.
* This method is invoked by a YapDatabaseReadWriteTransaction as a post-operation-hook.
**/
-- (void)handleRemoveObjectForKey:(NSString *)key inCollection:(NSString *)collection withRowid:(int64_t)rowid
+- (void)handleRemoveObjectForCollectionKey:(YapCollectionKey *)collectionKey withRowid:(int64_t)rowid
{
YDBLogAutoTrace();
- NSParameterAssert(key != nil);
- NSParameterAssert(collection != nil);
-
- YapCollectionKey *collectionKey = [[YapCollectionKey alloc] initWithCollection:collection key:key];
-
[self removeRowid:rowid collectionKey:collectionKey];
}
/**
* YapDatabase extension hook.
@@ -3363,12 +3633,10 @@
**/
- (void)handleRemoveObjectsForKeys:(NSArray *)keys inCollection:(NSString *)collection withRowids:(NSArray *)rowids
{
YDBLogAutoTrace();
- NSParameterAssert(collection != nil);
-
NSUInteger count = [keys count];
NSMutableDictionary *keyMappings = [NSMutableDictionary dictionaryWithCapacity:count];
for (NSUInteger i = 0; i < count; i++)
{
@@ -3477,24 +3745,22 @@
inGroup:(NSString *)group
{
int64_t rowid = 0;
if ([self getRowid:&rowid atIndex:index inGroup:group])
{
- NSString *collection = nil;
- NSString *key = nil;
- BOOL found = [databaseTransaction getKey:&key collection:&collection forRowid:rowid];
-
- if (collectionPtr) *collectionPtr = collection;
- if (keyPtr) *keyPtr = key;
- return found;
+ YapCollectionKey *ck = [databaseTransaction collectionKeyForRowid:rowid];
+ if (ck)
+ {
+ if (collectionPtr) *collectionPtr = ck.collection;
+ if (keyPtr) *keyPtr = ck.key;
+ return YES;
+ }
}
- else
- {
- if (collectionPtr) *collectionPtr = nil;
- if (keyPtr) *keyPtr = nil;
- return NO;
- }
+
+ if (collectionPtr) *collectionPtr = nil;
+ if (keyPtr) *keyPtr = nil;
+ return NO;
}
- (BOOL)getFirstKey:(NSString **)keyPtr collection:(NSString **)collectionPtr inGroup:(NSString *)group
{
return [self getKey:keyPtr collection:collectionPtr atIndex:0 inGroup:group];
@@ -3503,24 +3769,22 @@
- (BOOL)getLastKey:(NSString **)keyPtr collection:(NSString **)collectionPtr inGroup:(NSString *)group
{
int64_t rowid = 0;
if ([self getLastRowid:&rowid inGroup:group])
{
- NSString *collection = nil;
- NSString *key = nil;
- BOOL found = [databaseTransaction getKey:&key collection:&collection forRowid:rowid];
-
- if (collectionPtr) *collectionPtr = collection;
- if (keyPtr) *keyPtr = key;
- return found;
+ YapCollectionKey *ck = [databaseTransaction collectionKeyForRowid:rowid];
+ if (ck)
+ {
+ if (collectionPtr) *collectionPtr = ck.collection;
+ if (keyPtr) *keyPtr = ck.key;
+ return YES;
+ }
}
- else
- {
- if (collectionPtr) *collectionPtr = nil;
- if (keyPtr) *keyPtr = nil;
- return NO;
- }
+
+ if (collectionPtr) *collectionPtr = nil;
+ if (keyPtr) *keyPtr = nil;
+ return NO;
}
- (NSString *)collectionAtIndex:(NSUInteger)index inGroup:(NSString *)group
{
NSString *collection = nil;
@@ -3589,11 +3853,11 @@
group = [self groupForPageKey:pageKey];
// Calculate the offset of the corresponding page within the group.
NSUInteger pageOffset = 0;
- NSMutableArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
+ NSArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
for (YapDatabaseViewPageMetadata *pageMetadata in pagesMetadataForGroup)
{
if ([pageMetadata->pageKey isEqualToString:pageKey])
{
@@ -3643,11 +3907,11 @@
if (group == nil || block == NULL || invalidBlockType)
{
return NSMakeRange(NSNotFound, 0);
}
- NSMutableArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
+ NSArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
NSUInteger count = 0;
for (YapDatabaseViewPageMetadata *pageMetadata in pagesMetadataForGroup)
{
count += pageMetadata->count;
@@ -3681,52 +3945,47 @@
if (blockType == YapDatabaseViewBlockTypeWithKey)
{
__unsafe_unretained YapDatabaseViewFindWithKeyBlock findBlock =
(YapDatabaseViewFindWithKeyBlock)block;
- NSString *key = nil;
- NSString *collection = nil;
- [databaseTransaction getKey:&key collection:&collection forRowid:rowid];
+ YapCollectionKey *ck = [databaseTransaction collectionKeyForRowid:rowid];
- return findBlock(collection, key);
+ return findBlock(ck.collection, ck.key);
}
else if (blockType == YapDatabaseViewBlockTypeWithObject)
{
__unsafe_unretained YapDatabaseViewFindWithObjectBlock findBlock =
(YapDatabaseViewFindWithObjectBlock)block;
- NSString *key = nil;
- NSString *collection = nil;
+ YapCollectionKey *ck = nil;
id object = nil;
- [databaseTransaction getKey:&key collection:&collection object:&object forRowid:rowid];
+ [databaseTransaction getCollectionKey:&ck object:&object forRowid:rowid];
- return findBlock(collection, key, object);
+ return findBlock(ck.collection, ck.key, object);
}
else if (blockType == YapDatabaseViewBlockTypeWithMetadata)
{
__unsafe_unretained YapDatabaseViewFindWithMetadataBlock findBlock =
(YapDatabaseViewFindWithMetadataBlock)block;
- NSString *key = nil;
- NSString *collection = nil;
+ YapCollectionKey *ck = nil;
id metadata = nil;
- [databaseTransaction getKey:&key collection:&collection metadata:&metadata forRowid:rowid];
+ [databaseTransaction getCollectionKey:&ck metadata:&metadata forRowid:rowid];
- return findBlock(collection, key, metadata);
+ return findBlock(ck.collection, ck.key, metadata);
}
else
{
__unsafe_unretained YapDatabaseViewFindWithRowBlock findBlock =
(YapDatabaseViewFindWithRowBlock)block;
- NSString *key = nil;
- NSString *collection = nil;
+ YapCollectionKey *ck = nil;
id object = nil;
id metadata = nil;
- [databaseTransaction getKey:&key collection:&collection object:&object metadata:&metadata forRowid:rowid];
+ [databaseTransaction getCollectionKey:&ck object:&object metadata:&metadata forRowid:rowid];
- return findBlock(collection, key, object, metadata);
+ return findBlock(ck.collection, ck.key, object, metadata);
}
};
NSUInteger loopCount = 0;
@@ -3813,15 +4072,13 @@
{
if (block == NULL) return;
[self enumerateRowidsInGroup:group usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
- NSString *key = nil;
- NSString *collection = nil;
- [databaseTransaction getKey:&key collection:&collection forRowid:rowid];
+ YapCollectionKey *ck = [databaseTransaction collectionKeyForRowid:rowid];
- block(collection, key, index, stop);
+ block(ck.collection, ck.key, index, stop);
}];
}
- (void)enumerateKeysInGroup:(NSString *)group
withOptions:(NSEnumerationOptions)options
@@ -3829,15 +4086,13 @@
{
if (block == NULL) return;
[self enumerateRowidsInGroup:group withOptions:options usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
- NSString *key = nil;
- NSString *collection = nil;
- [databaseTransaction getKey:&key collection:&collection forRowid:rowid];
+ YapCollectionKey *ck = [databaseTransaction collectionKeyForRowid:rowid];
- block(collection, key, index, stop);
+ block(ck.collection, ck.key, index, stop);
}];
}
- (void)enumerateKeysInGroup:(NSString *)group
withOptions:(NSEnumerationOptions)options
@@ -3847,17 +4102,15 @@
if (block == NULL) return;
[self enumerateRowidsInGroup:group
withOptions:options
range:range
- usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
+ usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop)
+ {
+ YapCollectionKey *ck = [databaseTransaction collectionKeyForRowid:rowid];
- NSString *key = nil;
- NSString *collection = nil;
- [databaseTransaction getKey:&key collection:&collection forRowid:rowid];
-
- block(collection, key, index, stop);
+ block(ck.collection, ck.key, index, stop);
}];
}
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Private API
@@ -3871,11 +4124,11 @@
[viewConnection->mutatedGroups removeObject:group]; // mutation during enumeration protection
__block BOOL stop = NO;
NSUInteger pageOffset = 0;
- NSMutableArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
+ NSArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
for (YapDatabaseViewPageMetadata *pageMetadata in pagesMetadataForGroup)
{
YapDatabaseViewPage *page = [self pageForPageKey:pageMetadata->pageKey];
@@ -3916,15 +4169,15 @@
if (forwardEnumeration)
index = 0;
else
index = [self numberOfKeysInGroup:group] - 1;
- NSMutableArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
+ NSArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
[pagesMetadataForGroup enumerateObjectsWithOptions:options
- usingBlock:^(id pageMetadataObj, NSUInteger outerIdx, BOOL *outerStop){
-
+ usingBlock:^(id pageMetadataObj, NSUInteger outerIdx, BOOL *outerStop)
+ {
__unsafe_unretained YapDatabaseViewPageMetadata *pageMetadata =
(YapDatabaseViewPageMetadata *)pageMetadataObj;
YapDatabaseViewPage *page = [self pageForPageKey:pageMetadata->pageKey];
@@ -3956,11 +4209,11 @@
{
if (block == NULL) return;
NSEnumerationOptions options = (inOptions & NSEnumerationReverse); // We only support NSEnumerationReverse
- NSMutableArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
+ NSArray *pagesMetadataForGroup = [viewConnection->group_pagesMetadata_dict objectForKey:group];
// Helper block to fetch the pageOffset for some page.
NSUInteger (^pageOffsetForPageMetadata)(YapDatabaseViewPageMetadata *inPageMetadata);
pageOffsetForPageMetadata = ^ NSUInteger (YapDatabaseViewPageMetadata *inPageMetadata){
@@ -3983,12 +4236,12 @@
__block BOOL stop = NO;
__block BOOL startedRange = NO;
__block NSUInteger keysLeft = range.length;
[pagesMetadataForGroup enumerateObjectsWithOptions:options
- usingBlock:^(id pageMetadataObj, NSUInteger pageIndex, BOOL *outerStop){
-
+ usingBlock:^(id pageMetadataObj, NSUInteger pageIndex, BOOL *outerStop)
+ {
__unsafe_unretained YapDatabaseViewPageMetadata *pageMetadata =
(YapDatabaseViewPageMetadata *)pageMetadataObj;
NSUInteger pageOffset = pageOffsetForPageMetadata(pageMetadata);
NSRange pageRange = NSMakeRange(pageOffset, pageMetadata->count);
@@ -4199,10 +4452,86 @@
}
}
}
}
+/**
+ * This method allows you to change the groupingBlock and/or sortingBlock on-the-fly.
+ *
+ * Note: You must pass a different versionTag, or this method does nothing.
+**/
+- (void)setGroupingBlock:(YapDatabaseViewGroupingBlock)inGroupingBlock
+ groupingBlockType:(YapDatabaseViewBlockType)inGroupingBlockType
+ sortingBlock:(YapDatabaseViewSortingBlock)inSortingBlock
+ sortingBlockType:(YapDatabaseViewBlockType)inSortingBlockType
+ versionTag:(NSString *)inVersionTag
+{
+ YDBLogAutoTrace();
+
+ NSAssert(inGroupingBlock != NULL, @"Invalid grouping block");
+ NSAssert(inSortingBlock != NULL, @"Invalid grouping block");
+
+ NSAssert(inGroupingBlockType == YapDatabaseViewBlockTypeWithKey ||
+ inGroupingBlockType == YapDatabaseViewBlockTypeWithObject ||
+ inGroupingBlockType == YapDatabaseViewBlockTypeWithMetadata ||
+ inGroupingBlockType == YapDatabaseViewBlockTypeWithRow,
+ @"Invalid grouping block type");
+
+ NSAssert(inSortingBlockType == YapDatabaseViewBlockTypeWithKey ||
+ inSortingBlockType == YapDatabaseViewBlockTypeWithObject ||
+ inSortingBlockType == YapDatabaseViewBlockTypeWithMetadata ||
+ inSortingBlockType == YapDatabaseViewBlockTypeWithRow,
+ @"Invalid sorting block type");
+
+ if (!databaseTransaction->isReadWriteTransaction)
+ {
+ YDBLogWarn(@"%@ - Method only allowed in readWrite transaction", THIS_METHOD);
+ return;
+ }
+
+ NSString *newVersionTag = inVersionTag ? [inVersionTag copy] : @"";
+
+ __unsafe_unretained YapDatabaseView *view = viewConnection->view;
+
+ if ([view->versionTag isEqualToString:newVersionTag])
+ {
+ YDBLogWarn(@"%@ - versionTag didn't change, so not updating view", THIS_METHOD);
+ return;
+ }
+
+ view->groupingBlock = inGroupingBlock;
+ view->groupingBlockType = inGroupingBlockType;
+ view->sortingBlock = inSortingBlock;
+ view->sortingBlockType = inSortingBlockType;
+
+ view->versionTag = newVersionTag;
+
+ [self repopulateView];
+ [self setStringValue:newVersionTag forExtensionKey:ExtKey_versionTag];
+
+ // Notify any extensions dependent upon this one that we repopulated.
+
+ NSString *registeredName = [self registeredName];
+ NSDictionary *extensionDependencies = databaseTransaction->connection->extensionDependencies;
+
+ [extensionDependencies enumerateKeysAndObjectsUsingBlock:^(id key, id obj, BOOL *stop){
+
+ __unsafe_unretained NSString *extName = (NSString *)key;
+ __unsafe_unretained NSSet *extDependencies = (NSSet *)obj;
+
+ if ([extDependencies containsObject:registeredName])
+ {
+ YapDatabaseExtensionTransaction *extTransaction = [databaseTransaction ext:extName];
+
+ if ([extTransaction respondsToSelector:@selector(viewDidRepopulate:)])
+ {
+ [(id <YapDatabaseViewDependency>)extTransaction viewDidRepopulate:registeredName];
+ }
+ }
+ }];
+}
+
@end
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -4217,15 +4546,13 @@
// We could use getKey:collection:object:forRowid: at this point.
// But in most cases the object is going to be in the objectCache.
// So it's likely faster to fetch just the key first.
// And if the cache misses then we're still using a fetch based on the rowid.
- NSString *key = nil;
- NSString *collection = nil;
- [databaseTransaction getKey:&key collection:&collection forRowid:rowid];
+ YapCollectionKey *ck = [databaseTransaction collectionKeyForRowid:rowid];
- return [databaseTransaction objectForKey:key inCollection:collection withRowid:rowid];
+ return [databaseTransaction objectForCollectionKey:ck withRowid:rowid];
}
else
{
return nil;
}
@@ -4245,15 +4572,13 @@
// We could use getKey:collection:object:forRowid: at this point.
// But in most cases the object is going to be in the objectCache.
// So it's likely faster to fetch just the key first.
// And if the cache misses then we're still using a fetch based on the rowid.
- NSString *key = nil;
- NSString *collection = nil;
- [databaseTransaction getKey:&key collection:&collection forRowid:rowid];
+ YapCollectionKey *ck = [databaseTransaction collectionKeyForRowid:rowid];
- return [databaseTransaction objectForKey:key inCollection:collection withRowid:rowid];
+ return [databaseTransaction objectForCollectionKey:ck withRowid:rowid];
}
else
{
return nil;
}
@@ -4270,16 +4595,15 @@
{
if (block == NULL) return;
[self enumerateRowidsInGroup:group usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
- NSString *key = nil;
- NSString *collection = nil;
+ YapCollectionKey *ck = nil;
id metadata = nil;
- [databaseTransaction getKey:&key collection:&collection metadata:&metadata forRowid:rowid];
+ [databaseTransaction getCollectionKey:&ck metadata:&metadata forRowid:rowid];
- block(collection, key, metadata, index, stop);
+ block(ck.collection, ck.key, metadata, index, stop);
}];
}
- (void)enumerateKeysAndMetadataInGroup:(NSString *)group
withOptions:(NSEnumerationOptions)options
@@ -4288,18 +4612,17 @@
{
if (block == NULL) return;
[self enumerateRowidsInGroup:group
withOptions:options
- usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
-
- NSString *key = nil;
- NSString *collection = nil;
+ usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop)
+ {
+ YapCollectionKey *ck = nil;
id metadata = nil;
- [databaseTransaction getKey:&key collection:&collection metadata:&metadata forRowid:rowid];
+ [databaseTransaction getCollectionKey:&ck metadata:&metadata forRowid:rowid];
- block(collection, key, metadata, index, stop);
+ block(ck.collection, ck.key, metadata, index, stop);
}];
}
- (void)enumerateKeysAndMetadataInGroup:(NSString *)group
withOptions:(NSEnumerationOptions)options
@@ -4310,18 +4633,17 @@
if (block == NULL) return;
[self enumerateRowidsInGroup:group
withOptions:options
range:range
- usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
-
- NSString *key = nil;
- NSString *collection = nil;
+ usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop)
+ {
+ YapCollectionKey *ck = nil;
id metadata = nil;
- [databaseTransaction getKey:&key collection:&collection metadata:&metadata forRowid:rowid];
+ [databaseTransaction getCollectionKey:&ck metadata:&metadata forRowid:rowid];
- block(collection, key, metadata, index, stop);
+ block(ck.collection, ck.key, metadata, index, stop);
}];
}
/**
* The following methods are equivalent to invoking the enumerateKeysInGroup:... methods,
@@ -4334,16 +4656,15 @@
{
if (block == NULL) return;
[self enumerateRowidsInGroup:group usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
- NSString *key = nil;
- NSString *collection = nil;
+ YapCollectionKey *ck = nil;
id object = nil;
- [databaseTransaction getKey:&key collection:&collection object:&object forRowid:rowid];
+ [databaseTransaction getCollectionKey:&ck object:&object forRowid:rowid];
- block(collection, key, object, index, stop);
+ block(ck.collection, ck.key, object, index, stop);
}];
}
- (void)enumerateKeysAndObjectsInGroup:(NSString *)group
withOptions:(NSEnumerationOptions)options
@@ -4352,18 +4673,17 @@
{
if (block == NULL) return;
[self enumerateRowidsInGroup:group
withOptions:options
- usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
-
- NSString *key = nil;
- NSString *collection = nil;
+ usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop)
+ {
+ YapCollectionKey *ck = nil;
id object = nil;
- [databaseTransaction getKey:&key collection:&collection object:&object forRowid:rowid];
+ [databaseTransaction getCollectionKey:&ck object:&object forRowid:rowid];
- block(collection, key, object, index, stop);
+ block(ck.collection, ck.key, object, index, stop);
}];
}
- (void)enumerateKeysAndObjectsInGroup:(NSString *)group
withOptions:(NSEnumerationOptions)options
@@ -4374,18 +4694,17 @@
if (block == NULL) return;
[self enumerateRowidsInGroup:group
withOptions:options
range:range
- usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
-
- NSString *key = nil;
- NSString *collection = nil;
+ usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop)
+ {
+ YapCollectionKey *ck = nil;
id object = nil;
- [databaseTransaction getKey:&key collection:&collection object:&object forRowid:rowid];
+ [databaseTransaction getCollectionKey:&ck object:&object forRowid:rowid];
- block(collection, key, object, index, stop);
+ block(ck.collection, ck.key, object, index, stop);
}];
}
- (void)enumerateRowsInGroup:(NSString *)group
usingBlock:
@@ -4393,17 +4712,16 @@
{
if (block == NULL) return;
[self enumerateRowidsInGroup:group usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
- NSString *key = nil;
- NSString *collection = nil;
+ YapCollectionKey *ck = nil;
id object = nil;
id metadata = nil;
- [databaseTransaction getKey:&key collection:&collection object:&object metadata:&metadata forRowid:rowid];
+ [databaseTransaction getCollectionKey:&ck object:&object metadata:&metadata forRowid:rowid];
- block(collection, key, object, metadata, index, stop);
+ block(ck.collection, ck.key, object, metadata, index, stop);
}];
}
- (void)enumerateRowsInGroup:(NSString *)group
withOptions:(NSEnumerationOptions)options
@@ -4412,19 +4730,18 @@
{
if (block == NULL) return;
[self enumerateRowidsInGroup:group
withOptions:options
- usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
-
- NSString *key = nil;
- NSString *collection = nil;
+ usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop)
+ {
+ YapCollectionKey *ck = nil;
id object = nil;
id metadata = nil;
- [databaseTransaction getKey:&key collection:&collection object:&object metadata:&metadata forRowid:rowid];
-
- block(collection, key, object, metadata, index, stop);
+ [databaseTransaction getCollectionKey:&ck object:&object metadata:&metadata forRowid:rowid];
+
+ block(ck.collection, ck.key, object, metadata, index, stop);
}];
}
- (void)enumerateRowsInGroup:(NSString *)group
withOptions:(NSEnumerationOptions)options
@@ -4435,19 +4752,18 @@
if (block == NULL) return;
[self enumerateRowidsInGroup:group
withOptions:options
range:range
- usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop) {
-
- NSString *key = nil;
- NSString *collection = nil;
+ usingBlock:^(int64_t rowid, NSUInteger index, BOOL *stop)
+ {
+ YapCollectionKey *ck = nil;
id object = nil;
id metadata = nil;
- [databaseTransaction getKey:&key collection:&collection object:&object metadata:&metadata forRowid:rowid];
+ [databaseTransaction getCollectionKey:&ck object:&object metadata:&metadata forRowid:rowid];
- block(collection, key, object, metadata, index, stop);
+ block(ck.collection, ck.key, object, metadata, index, stop);
}];
}
@end
@@ -4456,36 +4772,177 @@
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@implementation YapDatabaseViewTransaction (Mappings)
/**
+ * Performance boost.
+ * If the object isn't in the cache, having the rowid makes for a faster fetch from sqlite.
+**/
+- (BOOL)getRowid:(int64_t *)rowidPtr
+ collectionKey:(YapCollectionKey **)collectionKeyPtr
+ forRow:(NSUInteger)row
+ inSection:(NSUInteger)section
+ withMappings:(YapDatabaseViewMappings *)mappings
+{
+ if (mappings)
+ {
+ NSString *group = nil;
+ NSUInteger index = 0;
+
+ if ([mappings getGroup:&group index:&index forRow:row inSection:section])
+ {
+ int64_t rowid = 0;
+ if ([self getRowid:&rowid atIndex:index inGroup:group])
+ {
+ if (collectionKeyPtr)
+ {
+ YapCollectionKey *ck = [databaseTransaction collectionKeyForRowid:rowid];
+ *collectionKeyPtr = ck;
+ }
+
+ if (rowidPtr) *rowidPtr = rowid;
+ return YES;
+ }
+ }
+ }
+
+ if (rowidPtr) *rowidPtr = 0;
+ if (collectionKeyPtr) *collectionKeyPtr = nil;
+ return NO;
+}
+
+/**
* Gets the key & collection at the given indexPath, assuming the given mappings are being used.
* Returns NO if the indexPath is invalid, or the mappings aren't initialized.
* Otherwise returns YES, and sets the key & collection ptr (both optional).
**/
- (BOOL)getKey:(NSString **)keyPtr
collection:(NSString **)collectionPtr
atIndexPath:(NSIndexPath *)indexPath
withMappings:(YapDatabaseViewMappings *)mappings
{
- if (indexPath && mappings)
+ if (indexPath == nil)
{
- NSString *group = nil;
- NSUInteger index = 0;
+ if (keyPtr) *keyPtr = nil;
+ if (collectionPtr) *collectionPtr = nil;
- if ([mappings getGroup:&group index:&index forIndexPath:indexPath])
- {
- return [self getKey:keyPtr collection:collectionPtr atIndex:index inGroup:group];
- }
+ return NO;
}
- if (keyPtr) *keyPtr = nil;
- if (collectionPtr) *collectionPtr = nil;
- return NO;
+#if TARGET_OS_IPHONE
+ NSUInteger section = indexPath.section;
+ NSUInteger row = indexPath.row;
+#else
+ NSUInteger section = [indexPath indexAtPosition:0];
+ NSUInteger row = [indexPath indexAtPosition:1];
+#endif
+
+ YapCollectionKey *ck = nil;
+ BOOL result = [self getRowid:NULL
+ collectionKey:&ck
+ forRow:row
+ inSection:section
+ withMappings:mappings];
+
+ if (keyPtr) *keyPtr = ck.key;
+ if (collectionPtr) *collectionPtr = ck.collection;
+
+ return result;
}
/**
+ * Gets the key & collection at the given row & section, assuming the given mappings are being used.
+ * Returns NO if the row or section is invalid, or the mappings aren't initialized.
+ * Otherwise returns YES, and sets the key & collection ptr (both optional).
+**/
+- (BOOL)getKey:(NSString **)keyPtr
+ collection:(NSString **)collectionPtr
+ forRow:(NSUInteger)row
+ inSection:(NSUInteger)section
+ withMappings:(YapDatabaseViewMappings *)mappings
+{
+ YapCollectionKey *ck = nil;
+ BOOL result = [self getRowid:NULL
+ collectionKey:&ck
+ forRow:row
+ inSection:section
+ withMappings:mappings];
+
+ if (keyPtr) *keyPtr = ck.key;
+ if (collectionPtr) *collectionPtr = ck.collection;
+
+ return result;
+}
+
+/**
+ * Gets the object at the given indexPath, assuming the given mappings are being used.
+ *
+ * Equivalent to invoking:
+ *
+ * NSString *collection, *key;
+ * if ([[transaction ext:@"myView"] getKey:&key collection:&collection atIndexPath:indexPath withMappings:mappings]) {
+ * object = [transaction objectForKey:key inCollection:collection];
+ * }
+**/
+- (id)objectAtIndexPath:(NSIndexPath *)indexPath withMappings:(YapDatabaseViewMappings *)mappings
+{
+ if (indexPath == nil)
+ {
+ return nil;
+ }
+
+#if TARGET_OS_IPHONE
+ NSUInteger section = indexPath.section;
+ NSUInteger row = indexPath.row;
+#else
+ NSUInteger section = [indexPath indexAtPosition:0];
+ NSUInteger row = [indexPath indexAtPosition:1];
+#endif
+
+ id object = nil;
+
+ int64_t rowid = 0;
+ YapCollectionKey *ck = nil;
+
+ if ([self getRowid:&rowid collectionKey:&ck forRow:row inSection:section withMappings:mappings])
+ {
+ object = [databaseTransaction objectForCollectionKey:ck withRowid:rowid];
+ }
+
+ return object;
+}
+
+/**
+ * Gets the object at the given indexPath, assuming the given mappings are being used.
+ *
+ * Equivalent to invoking:
+ *
+ * NSString *collection, *key;
+ * if ([[transaction ext:@"view"] getKey:&key
+ * collection:&collection
+ * forRow:row
+ * inSection:section
+ * withMappings:mappings]) {
+ * object = [transaction objectForKey:key inCollection:collection];
+ * }
+**/
+- (id)objectAtRow:(NSUInteger)row inSection:(NSUInteger)section withMappings:(YapDatabaseViewMappings *)mappings
+{
+ id object = nil;
+
+ int64_t rowid = 0;
+ YapCollectionKey *ck = nil;
+
+ if ([self getRowid:&rowid collectionKey:&ck forRow:row inSection:section withMappings:mappings])
+ {
+ object = [databaseTransaction objectForCollectionKey:ck withRowid:rowid];
+ }
+
+ return object;
+}
+
+/**
* Fetches the indexPath for the given {collection, key} tuple, assuming the given mappings are being used.
* Returns nil if the {collection, key} tuple isn't included in the view + mappings.
**/
- (NSIndexPath *)indexPathForKey:(NSString *)key
inCollection:(NSString *)collection
@@ -4498,8 +4955,32 @@
{
return [mappings indexPathForIndex:index inGroup:group];
}
return nil;
+}
+
+/**
+ * Fetches the row & section for the given {collection, key} tuple, assuming the given mappings are being used.
+ * Returns NO if the {collection, key} tuple isn't included in the view + mappings.
+ * Otherwise returns YES, and sets the row & section (both optional).
+**/
+- (BOOL)getRow:(NSUInteger *)rowPtr
+ section:(NSUInteger *)sectionPtr
+ forKey:(NSString *)key
+ inCollection:(NSString *)collection
+ withMappings:(YapDatabaseViewMappings *)mappings
+{
+ NSString *group = nil;
+ NSUInteger index = 0;
+
+ if ([self getGroup:&group index:&index forKey:key inCollection:collection])
+ {
+ return [mappings getRow:rowPtr section:sectionPtr forIndex:index inGroup:group];
+ }
+
+ if (rowPtr) *rowPtr = 0;
+ if (sectionPtr) *sectionPtr = 0;
+ return NO;
}
@end