#import <Foundation/Foundation.h>

@class YapDatabaseConnection;

/**
 * Welcome to YapDatabase!
 *
 * The project page has a wealth of documentation if you have any questions.
 * https://github.com/yapstudios/YapDatabase
 *
 * If you're new to the project you may want to visit the wiki.
 * https://github.com/yapstudios/YapDatabase/wiki
 * 
 * Transactions represent atomic access to a database.
 * There are two types of transactions:
 * - Read-Only transactions
 * - Read-Write transactions
 *
 * Once a transaction is started, all data access within the transaction from that point forward until completion
 * represents an atomic "snapshot" of the current state of the database. For example, if a read-write operation
 * occurs in parallel with a read-only transaction, the read-only transaction won't see the changes made by
 * the read-write operation. But once the read-write operation completes, all transactions started from that point
 * forward will see the changes.
 *
 * You first create and configure a YapDatabase instance.
 * Then you can spawn one or more connections to the database file.
 * Each connection allows you to execute transactions in a serial fashion.
 * For concurrent access, you can create multiple connections,
 * and execute transactions on each connection simulataneously.
 *
 * Concurrency is straight-forward. Here are the rules:
 *
 * - You can have multiple connections.
 * - Every connection is thread-safe.
 * - You can have multiple read-only transactions simultaneously without blocking.
 *   (Each simultaneous transaction would be going through a separate connection.)
 * - You can have multiple read-only transactions and a single read-write transaction simultaneously without blocking.
 *   (Each simultaneous transaction would be going through a separate connection.)
 * - There can only be a single transaction per connection at a time.
 *   (Transactions go through a per-connection serial queue.)
 * - There can only be a single read-write transaction at a time.
 *   (Read-write transactions go through a per-database serial queue.)
**/

/**
 * A YapDatabaseReadTransaction encompasses a single read-only database transaction.
 * You can execute multiple operations within a single transaction.
 *
 * A transaction allows you to safely access the database as needed in a thread-safe and optimized manner.
**/
@interface YapDatabaseReadTransaction : NSObject

/**
 * Transactions are light-weight objects created by connections.
 *
 * Connections are the parent objects of transactions.
 * Connections own the transaction objects.
 *
 * Transactions store nearly all their state in the parent connection object.
 * This reduces the memory requirements for transactions objects,
 * and reduces the overhead associated in creating them.
**/
@property (nonatomic, unsafe_unretained, readonly) YapDatabaseConnection *connection;

/**
 * The userInfo property allows arbitrary info to be associated with the transaction.
 * This propery is not used by YapDatabaseTransaction in any way.
 * 
 * Keep in mind that transactions are short lived objects.
 * Each transaction is a new/different transaction object.
**/
@property (nonatomic, strong, readwrite) id userInfo;

#pragma mark Count

/**
 * Returns the total number of collections.
 * Each collection may have 1 or more key/object pairs.
**/
- (NSUInteger)numberOfCollections;

/**
 * Returns the total number of keys in the given collection.
 * Returns zero if the collection doesn't exist (or all key/object pairs from the collection have been removed).
**/
- (NSUInteger)numberOfKeysInCollection:(NSString *)collection;

/**
 * Returns the total number of key/object pairs in the entire database (including all collections).
**/
- (NSUInteger)numberOfKeysInAllCollections;

#pragma mark List

/**
 * Returns a list of all collection names.
**/
- (NSArray *)allCollections;

/**
 * Returns a list of all keys in the given collection.
**/
- (NSArray *)allKeysInCollection:(NSString *)collection;

#pragma mark Object & Metadata

/**
 * Object access.
 * Objects are automatically deserialized using database's configured deserializer.
**/
- (id)objectForKey:(NSString *)key inCollection:(NSString *)collection;

/**
 * Returns whether or not the given key/collection exists in the database.
**/
- (BOOL)hasObjectForKey:(NSString *)key inCollection:(NSString *)collection;

/**
 * Provides access to both object and metadata in a single call.
 *
 * @return YES if the key exists in the database. NO otherwise, in which case both object and metadata will be nil.
**/
- (BOOL)getObject:(id *)objectPtr metadata:(id *)metadataPtr forKey:(NSString *)key inCollection:(NSString *)collection;

/**
 * Provides access to the metadata.
 * This fetches directly from the metadata dictionary stored in memory, and thus never hits the disk.
**/
- (id)metadataForKey:(NSString *)key inCollection:(NSString *)collection;

#pragma mark Primitive

/**
 * Primitive access.
 * This method is available in-case you have a need to fetch the raw serializedObject from the database.
 * 
 * This method is slower than objectForKey:inCollection:, since that method makes use of the objectCache.
 * In contrast, this method always fetches the raw data from disk.
 * 
 * @see objectForKey:inCollection:
**/
- (NSData *)serializedObjectForKey:(NSString *)key inCollection:(NSString *)collection;

/**
 * Primitive access.
 * This method is available in-case you have a need to fetch the raw serializedMetadata from the database.
 * 
 * This method is slower than metadataForKey:inCollection:, since that method makes use of the metadataCache.
 * In contrast, this method always fetches the raw data from disk.
 *
 * @see metadataForKey:inCollection:
**/
- (NSData *)serializedMetadataForKey:(NSString *)key inCollection:(NSString *)collection;

/**
 * Primitive access.
 * This method is available in-case you have a need to fetch the raw serialized forms from the database.
 *
 * This method is slower than getObject:metadata:forKey:inCollection:, since that method makes use of the caches.
 * In contrast, this method always fetches the raw data from disk.
 *
 * @see getObject:metadata:forKey:inCollection:
**/
- (BOOL)getSerializedObject:(NSData **)serializedObjectPtr
         serializedMetadata:(NSData **)serializedMetadataPtr
                     forKey:(NSString *)key
               inCollection:(NSString *)collection;

#pragma mark Enumerate

/**
 * Fast enumeration over all the collections in the database.
 * 
 * This uses a "SELECT collection FROM database" operation,
 * and then steps over the results invoking the given block handler.
**/
- (void)enumerateCollectionsUsingBlock:(void (^)(NSString *collection, BOOL *stop))block;

/**
 * This method is rarely needed, but may be helpful in certain situations.
 * 
 * This method may be used if you have the key, but not the collection for a particular item.
 * Please note that this is not the ideal situation.
 * 
 * Since there may be numerous collections for a given key, this method enumerates all possible collections.
**/
- (void)enumerateCollectionsForKey:(NSString *)key usingBlock:(void (^)(NSString *collection, BOOL *stop))block;

/**
 * Fast enumeration over all keys in the given collection.
 *
 * This uses a "SELECT key FROM database WHERE collection = ?" operation,
 * and then steps over the results invoking the given block handler.
**/
- (void)enumerateKeysInCollection:(NSString *)collection
                       usingBlock:(void (^)(NSString *key, BOOL *stop))block;

/**
 * Fast enumeration over all keys in the given collection.
 *
 * This uses a "SELECT collection, key FROM database" operation,
 * and then steps over the results invoking the given block handler.
**/
- (void)enumerateKeysInAllCollectionsUsingBlock:(void (^)(NSString *collection, NSString *key, BOOL *stop))block;

/**
 * Fast enumeration over all keys and associated metadata in the given collection.
 * 
 * This uses a "SELECT key, metadata FROM database WHERE collection = ?" operation and steps over the results.
 * 
 * If you only need to enumerate over certain items (e.g. keys with a particular prefix),
 * consider using the alternative version below which provides a filter,
 * allowing you to skip the deserialization step for those items you're not interested in.
 * 
 * Keep in mind that you cannot modify the collection mid-enumeration (just like any other kind of enumeration).
**/
- (void)enumerateKeysAndMetadataInCollection:(NSString *)collection
                                  usingBlock:(void (^)(NSString *key, id metadata, BOOL *stop))block;

/**
 * Fast enumeration over all keys and associated metadata in the given collection.
 *
 * From the filter block, simply return YES if you'd like the block handler to be invoked for the given key.
 * If the filter block returns NO, then the block handler is skipped for the given key,
 * which avoids the cost associated with deserializing the object.
 * 
 * Keep in mind that you cannot modify the collection mid-enumeration (just like any other kind of enumeration).
**/
- (void)enumerateKeysAndMetadataInCollection:(NSString *)collection
                                  usingBlock:(void (^)(NSString *key, id metadata, BOOL *stop))block
                                  withFilter:(BOOL (^)(NSString *key))filter;



/**
 * Fast enumeration over all key/metadata pairs in all collections.
 * 
 * This uses a "SELECT metadata FROM database ORDER BY collection ASC" operation, and steps over the results.
 * 
 * If you only need to enumerate over certain objects (e.g. keys with a particular prefix),
 * consider using the alternative version below which provides a filter,
 * allowing you to skip the deserialization step for those objects you're not interested in.
 * 
 * Keep in mind that you cannot modify the database mid-enumeration (just like any other kind of enumeration).
**/
- (void)enumerateKeysAndMetadataInAllCollectionsUsingBlock:
                                        (void (^)(NSString *collection, NSString *key, id metadata, BOOL *stop))block;

/**
 * Fast enumeration over all key/metadata pairs in all collections.
 *
 * This uses a "SELECT metadata FROM database ORDER BY collection ASC" operation and steps over the results.
 * 
 * From the filter block, simply return YES if you'd like the block handler to be invoked for the given key.
 * If the filter block returns NO, then the block handler is skipped for the given key,
 * which avoids the cost associated with deserializing the object.
 *
 * Keep in mind that you cannot modify the database mid-enumeration (just like any other kind of enumeration).
 **/
- (void)enumerateKeysAndMetadataInAllCollectionsUsingBlock:
                                        (void (^)(NSString *collection, NSString *key, id metadata, BOOL *stop))block
                             withFilter:(BOOL (^)(NSString *collection, NSString *key))filter;

/**
 * Fast enumeration over all objects in the database.
 *
 * This uses a "SELECT key, object from database WHERE collection = ?" operation, and then steps over the results,
 * deserializing each object, and then invoking the given block handler.
 *
 * If you only need to enumerate over certain objects (e.g. keys with a particular prefix),
 * consider using the alternative version below which provides a filter,
 * allowing you to skip the serialization step for those objects you're not interested in.
**/
- (void)enumerateKeysAndObjectsInCollection:(NSString *)collection
                                 usingBlock:(void (^)(NSString *key, id object, BOOL *stop))block;

/**
 * Fast enumeration over objects in the database for which you're interested in.
 * The filter block allows you to decide which objects you're interested in.
 *
 * From the filter block, simply return YES if you'd like the block handler to be invoked for the given key.
 * If the filter block returns NO, then the block handler is skipped for the given key,
 * which avoids the cost associated with deserializing the object.
**/
- (void)enumerateKeysAndObjectsInCollection:(NSString *)collection
                                 usingBlock:(void (^)(NSString *key, id object, BOOL *stop))block
                                 withFilter:(BOOL (^)(NSString *key))filter;

/**
 * Enumerates all key/object pairs in all collections.
 * 
 * The enumeration is sorted by collection. That is, it will enumerate fully over a single collection
 * before moving onto another collection.
 * 
 * If you only need to enumerate over certain objects (e.g. subset of collections, or keys with a particular prefix),
 * consider using the alternative version below which provides a filter,
 * allowing you to skip the serialization step for those objects you're not interested in.
**/
- (void)enumerateKeysAndObjectsInAllCollectionsUsingBlock:
                                            (void (^)(NSString *collection, NSString *key, id object, BOOL *stop))block;

/**
 * Enumerates all key/object pairs in all collections.
 * The filter block allows you to decide which objects you're interested in.
 *
 * The enumeration is sorted by collection. That is, it will enumerate fully over a single collection
 * before moving onto another collection.
 * 
 * From the filter block, simply return YES if you'd like the block handler to be invoked for the given
 * collection/key pair. If the filter block returns NO, then the block handler is skipped for the given pair,
 * which avoids the cost associated with deserializing the object.
**/
- (void)enumerateKeysAndObjectsInAllCollectionsUsingBlock:
                                            (void (^)(NSString *collection, NSString *key, id object, BOOL *stop))block
                                 withFilter:(BOOL (^)(NSString *collection, NSString *key))filter;

/**
 * Fast enumeration over all rows in the database.
 *
 * This uses a "SELECT key, data, metadata from database WHERE collection = ?" operation,
 * and then steps over the results, deserializing each object & metadata, and then invoking the given block handler.
 *
 * If you only need to enumerate over certain rows (e.g. keys with a particular prefix),
 * consider using the alternative version below which provides a filter,
 * allowing you to skip the serialization step for those rows you're not interested in.
**/
- (void)enumerateRowsInCollection:(NSString *)collection
                       usingBlock:(void (^)(NSString *key, id object, id metadata, BOOL *stop))block;

/**
 * Fast enumeration over rows in the database for which you're interested in.
 * The filter block allows you to decide which rows you're interested in.
 *
 * From the filter block, simply return YES if you'd like the block handler to be invoked for the given key.
 * If the filter block returns NO, then the block handler is skipped for the given key,
 * which avoids the cost associated with deserializing the object & metadata.
**/
- (void)enumerateRowsInCollection:(NSString *)collection
                       usingBlock:(void (^)(NSString *key, id object, id metadata, BOOL *stop))block
                       withFilter:(BOOL (^)(NSString *key))filter;

/**
 * Enumerates all rows in all collections.
 * 
 * The enumeration is sorted by collection. That is, it will enumerate fully over a single collection
 * before moving onto another collection.
 * 
 * If you only need to enumerate over certain rows (e.g. subset of collections, or keys with a particular prefix),
 * consider using the alternative version below which provides a filter,
 * allowing you to skip the serialization step for those objects you're not interested in.
**/
- (void)enumerateRowsInAllCollectionsUsingBlock:
                            (void (^)(NSString *collection, NSString *key, id object, id metadata, BOOL *stop))block;

/**
 * Enumerates all rows in all collections.
 * The filter block allows you to decide which objects you're interested in.
 *
 * The enumeration is sorted by collection. That is, it will enumerate fully over a single collection
 * before moving onto another collection.
 * 
 * From the filter block, simply return YES if you'd like the block handler to be invoked for the given
 * collection/key pair. If the filter block returns NO, then the block handler is skipped for the given pair,
 * which avoids the cost associated with deserializing the object.
**/
- (void)enumerateRowsInAllCollectionsUsingBlock:
                            (void (^)(NSString *collection, NSString *key, id object, id metadata, BOOL *stop))block
                 withFilter:(BOOL (^)(NSString *collection, NSString *key))filter;

/**
 * Enumerates over the given list of keys (unordered).
 *
 * This method is faster than fetching individual items as it optimizes cache access.
 * That is, it will first enumerate over items in the cache and then fetch items from the database,
 * thus optimizing the cache and reducing query size.
 *
 * If any keys are missing from the database, the 'metadata' parameter will be nil.
 *
 * IMPORTANT:
 * Due to cache optimizations, the items may not be enumerated in the same order as the 'keys' parameter.
**/
- (void)enumerateMetadataForKeys:(NSArray *)keys
                    inCollection:(NSString *)collection
             unorderedUsingBlock:(void (^)(NSUInteger keyIndex, id metadata, BOOL *stop))block;

/**
 * Enumerates over the given list of keys (unordered).
 *
 * This method is faster than fetching individual items as it optimizes cache access.
 * That is, it will first enumerate over items in the cache and then fetch items from the database,
 * thus optimizing the cache and reducing query size.
 *
 * If any keys are missing from the database, the 'object' parameter will be nil.
 *
 * IMPORTANT:
 * Due to cache optimizations, the items may not be enumerated in the same order as the 'keys' parameter.
**/
- (void)enumerateObjectsForKeys:(NSArray *)keys
                   inCollection:(NSString *)collection
            unorderedUsingBlock:(void (^)(NSUInteger keyIndex, id object, BOOL *stop))block;

/**
 * Enumerates over the given list of keys (unordered).
 *
 * This method is faster than fetching individual items as it optimizes cache access.
 * That is, it will first enumerate over items in the cache and then fetch items from the database,
 * thus optimizing the cache and reducing query size.
 *
 * If any keys are missing from the database, the 'object' and 'metadata' parameter will be nil.
 *
 * IMPORTANT:
 * Due to cache optimizations, the items may not be enumerated in the same order as the 'keys' parameter.
**/
- (void)enumerateRowsForKeys:(NSArray *)keys
                inCollection:(NSString *)collection
         unorderedUsingBlock:(void (^)(NSUInteger keyIndex, id object, id metadata, BOOL *stop))block;

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark Extensions
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

/**
 * Returns an extension transaction corresponding to the extension type registered under the given name.
 * If the extension has not yet been opened, it is done so automatically.
 *
 * @return
 *     A subclass of YapDatabaseExtensionTransaction,
 *     according to the type of extension registered under the given name.
 * 
 * One must register an extension with the database before it can be accessed from within connections or transactions.
 * After registration everything works automatically using just the registered extension name.
 *
 * @see [YapDatabase registerExtension:withName:]
**/
- (id)extension:(NSString *)extensionName;
- (id)ext:(NSString *)extensionName; // <-- Shorthand (same as extension: method)

@end

////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#pragma mark -
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

@interface YapDatabaseReadWriteTransaction : YapDatabaseReadTransaction

/**
 * Under normal circumstances, when a read-write transaction block completes,
 * the changes are automatically committed. If, however, something goes wrong and
 * you'd like to abort and discard all changes made within the transaction,
 * then invoke this method.
 * 
 * You should generally return (exit the transaction block) after invoking this method.
 * Any changes made within the the transaction before and after invoking this method will be discarded.
**/
- (void)rollback;

/**
 * The YapDatabaseModifiedNotification is posted following a readwrite transaction which made changes.
 * 
 * These notifications are used in a variety of ways:
 * - They may be used as a general notification mechanism to detect changes to the database.
 * - They may be used by extensions to post change information.
 *   For example, YapDatabaseView will post the index changes, which can easily be used to animate a tableView.
 * - They are integrated into the architecture of long-lived transactions in order to maintain a steady state.
 *
 * Thus it is recommended you integrate your own notification information into this existing notification,
 * as opposed to broadcasting your own separate notification.
 * 
 * For more information, and code samples, please see the wiki article:
 * https://github.com/yapstudios/YapDatabase/wiki/YapDatabaseModifiedNotification
**/
@property (nonatomic, strong, readwrite) id yapDatabaseModifiedNotificationCustomObject;

#pragma mark Object & Metadata

/**
 * Sets the object for the given key/collection.
 * The object is automatically serialized using the database's configured objectSerializer.
 *
 * If you pass nil for the object, then this method will remove the row from the database (if it exists).
 * This method implicitly sets the associated metadata to nil.
 * 
 * @param object
 *   The object to store in the database.
 *   This object is automatically serialized using the database's configured objectSerializer.
 * 
 * @param key
 *   The lookup key.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   This value should not be nil. If a nil key is passed, then this method does nothing.
 * 
 * @param collection
 *   The lookup collection.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   If a nil collection is passed, then the collection is implicitly the empty string (@"").
**/
- (void)setObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection;

/**
 * Sets the object & metadata for the given key/collection.
 *
 * If you pass nil for the object, then this method will remove the row from the database (if it exists).
 * 
 * @param object
 *   The object to store in the database.
 *   This object is automatically serialized using the database's configured objectSerializer.
 * 
 * @param key
 *   The lookup key.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   This value should not be nil. If a nil key is passed, then this method does nothing.
 * 
 * @param collection
 *   The lookup collection.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   If a nil collection is passed, then the collection is implicitly the empty string (@"").
 * 
 * @param metadata
 *   The metadata to store in the database.
 *   This metadata is automatically serialized using the database's configured metadataSerializer.
 *   The metadata is optional. You can pass nil for the metadata is unneeded.
 *   If non-nil then the metadata is also written to the database (metadata is also persistent).
**/
- (void)setObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection withMetadata:(id)metadata;

/**
 * Sets the object & metadata for the given key/collection.
 * 
 * If you pass nil for the object, then this method will remove the row from the database (if it exists).
 *
 * This method allows for a bit of optimization if you happen to already have a serialized version of
 * the object and/or metadata. For example, if you downloaded an object in serialized form,
 * and you still have the raw serialized NSData, then you can use this method to skip the serialization step
 * when storing the object to the database.
 *
 * @param object
 *   The object to store in the database.
 *   This object is automatically serialized using the database's configured objectSerializer.
 *
 * @param key
 *   The lookup key.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   This value should not be nil. If a nil key is passed, then this method does nothing.
 *
 * @param collection
 *   The lookup collection.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   If a nil collection is passed, then the collection is implicitly the empty string (@"").
 *
 * @param metadata
 *   The metadata to store in the database.
 *   This metadata is automatically serialized using the database's configured metadataSerializer.
 *   The metadata is optional. You can pass nil for the metadata is unneeded.
 *   If non-nil then the metadata is also written to the database (metadata is also persistent).
 * 
 * @param preSerializedObject
 *   This value is optional.
 *   If non-nil then the object serialization step is skipped, and this value is used instead.
 *   It is assumed that preSerializedObject is equal to what we would get if we ran the object through
 *   the database's configured objectSerializer.
 * 
 * @param preSerializedMetadata
 *   This value is optional.
 *   If non-nil then the metadata serialization step is skipped, and this value is used instead.
 *   It is assumed that preSerializedMetadata is equal to what we would get if we ran the metadata through
 *   the database's configured metadataSerializer.
 *
 * The preSerializedObject is only used if object is non-nil.
 * The preSerializedMetadata is only used if metadata is non-nil.
**/
- (void)setObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection
                                                    withMetadata:(id)metadata
                                                serializedObject:(NSData *)preSerializedObject
                                              serializedMetadata:(NSData *)preSerializedMetadata;

/**
 * If a row with the given key/collection exists, then replaces the object for that row with the new value.
 * 
 * It only replaces the object. The metadata for the row doesn't change.
 * If there is no row in the database for the given key/collection then this method does nothing.
 * 
 * If you pass nil for the object, then this method will remove the row from the database (if it exists).
 * 
 * @param object
 *   The object to store in the database.
 *   This object is automatically serialized using the database's configured objectSerializer.
 * 
 * @param key
 *   The lookup key.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   This value should not be nil. If a nil key is passed, then this method does nothing.
 * 
 * @param collection
 *   The lookup collection.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   If a nil collection is passed, then the collection is implicitly the empty string (@"").
**/
- (void)replaceObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection;

/**
 * If a row with the given key/collection exists, then replaces the object for that row with the new value.
 *
 * It only replaces the object. The metadata for the row doesn't change.
 * If there is no row in the database for the given key/collection then this method does nothing.
 *
 * If you pass nil for the object, then this method will remove the row from the database (if it exists).
 * 
 * This method allows for a bit of optimization if you happen to already have a serialized version of
 * the object and/or metadata. For example, if you downloaded an object in serialized form,
 * and you still have the raw serialized NSData, then you can use this method to skip the serialization step
 * when storing the object to the database.
 *
 * @param object
 *   The object to store in the database.
 *   This object is automatically serialized using the database's configured objectSerializer.
 *
 * @param key
 *   The lookup key.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   This value should not be nil. If a nil key is passed, then this method does nothing.
 *
 * @param collection
 *   The lookup collection.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   If a nil collection is passed, then the collection is implicitly the empty string (@"").
 *
 * @param preSerializedObject
 *   This value is optional.
 *   If non-nil then the object serialization step is skipped, and this value is used instead.
 *   It is assumed that preSerializedObject is equal to what we would get if we ran the object through
 *   the database's configured objectSerializer.
**/
- (void)replaceObject:(id)object forKey:(NSString *)key inCollection:(NSString *)collection
                                                withSerializedObject:(NSData *)preSerializedObject;

/**
 * If a row with the given key/collection exists, then replaces the metadata for that row with the new value.
 * 
 * It only replaces the metadata. The object for the row doesn't change.
 * If there is no row in the database for the given key/collection then this method does nothing.
 * 
 * If you pass nil for the metadata, any metadata previously associated with the key/collection is removed.
 * 
 * @param metadata
 *   The metadata to store in the database.
 *   This metadata is automatically serialized using the database's configured metadataSerializer.
 *
 * @param key
 *   The lookup key.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   This value should not be nil. If a nil key is passed, then this method does nothing.
 * 
 * @param collection
 *   The lookup collection.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   If a nil collection is passed, then the collection is implicitly the empty string (@"").
**/
- (void)replaceMetadata:(id)metadata forKey:(NSString *)key inCollection:(NSString *)collection;

/**
 * If a row with the given key/collection exists, then replaces the metadata for that row with the new value.
 *
 * It only replaces the metadata. The object for the row doesn't change.
 * If there is no row in the database for the given key/collection then this method does nothing.
 *
 * If you pass nil for the metadata, any metadata previously associated with the key/collection is removed.
 *
 * This method allows for a bit of optimization if you happen to already have a serialized version of
 * the object and/or metadata. For example, if you downloaded an object in serialized form,
 * and you still have the raw serialized NSData, then you can use this method to skip the serialization step
 * when storing the object to the database.
 * 
 * @param metadata
 *   The metadata to store in the database.
 *   This metadata is automatically serialized using the database's configured metadataSerializer.
 *
 * @param key
 *   The lookup key.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   This value should not be nil. If a nil key is passed, then this method does nothing.
 *
 * @param collection
 *   The lookup collection.
 *   The <collection, key> tuple is used to uniquely identify the row in the database.
 *   If a nil collection is passed, then the collection is implicitly the empty string (@"").
 * 
 * @param preSerializedMetadata
 *   This value is optional.
 *   If non-nil then the metadata serialization step is skipped, and this value is used instead.
 *   It is assumed that preSerializedMetadata is equal to what we would get if we ran the metadata through
 *   the database's configured metadataSerializer.
**/
- (void)replaceMetadata:(id)metadata forKey:(NSString *)key inCollection:(NSString *)collection
                                                  withSerializedMetadata:(NSData *)preSerializedMetadata;

#pragma mark Touch

/**
 * You can touch an object if you want to mark it as updated without actually writing any changes to disk.
 *
 * For example:
 *
 *   You have a BNBook object in your database.
 *   One of the properties of the book object is a URL pointing to an image for the front cover of the book.
 *   This image gets changed on the server. Thus the UI representation of the book needs to be updated
 *   to reflect the updated image on the server. You realize that all your views are already listening for
 *   YapDatabaseModified notifications, so if you update the object in the database then all your views are
 *   already wired to update the UI appropriately. However, the actual object itself didn't change. So while
 *   there technically isn't any reason to update the object on disk, doing so would be the easiest way to
 *   keep the UI up-to-date. So what you really want is a way to "mark" the object as updated, without actually
 *   incurring the overhead of rewriting it to disk.
 *
 * And this is exactly what the touch methods were designed for.
 * It won't actually cause the object to get rewritten to disk.
 * However, it will mark the object as "updated" within the YapDatabaseModified notification,
 * so any UI components listening for changes will see this object as updated, and can update as appropriate.
 *
 * The touchObjectForKey:inCollection: method is similar to calling setObject:forKey:inCollection:withMetadata:,
 * and passing the object & metadata that already exists for the key. But without the overhead of fetching the items,
 * or re-writing the items to disk.
 *
 * The touchMetadataForKey: method is similar to calling replaceMetadata:forKey:,
 * and passing the metadata that already exists for the key. But without the overhead of fetching the metadata,
 * or re-writing the metadata to disk.
 * 
 * Note: It is safe to touch objects during enumeration.
 * Normally, altering the database while enumerating it will result in an exception (just like altering an array
 * while enumerating it). However, it's safe to touch objects during enumeration.
**/
- (void)touchObjectForKey:(NSString *)key inCollection:(NSString *)collection;
- (void)touchMetadataForKey:(NSString *)key inCollection:(NSString *)collection;

#pragma mark Remove

/**
 * Deletes the database row with the given key/collection.
 *
 * This method is automatically called if you invoke
 * setObject:forKey:collection: and pass a nil object.
**/
- (void)removeObjectForKey:(NSString *)key inCollection:(NSString *)collection;

/**
 * Deletes the database rows with the given keys in the given collection.
**/
- (void)removeObjectsForKeys:(NSArray *)keys inCollection:(NSString *)collection;

/**
 * Deletes every key/object pair from the given collection.
 * No trace of the collection will remain afterwards.
**/
- (void)removeAllObjectsInCollection:(NSString *)collection;

/**
 * Removes every key/object pair in the entire database (from all collections).
**/
- (void)removeAllObjectsInAllCollections;

@end
