CloudCore

  • Undocumented

    See more

    Declaration

    Objective-C

    @interface YapDatabaseCloudCore : YapDatabaseExtension
    
    - (instancetype)initWithVersionTag:(nullable NSString *)versionTag
                               options:(nullable YapDatabaseCloudCoreOptions *)options;
    
    @property (nonatomic, copy, readonly) NSString *versionTag;
    
    @property (nonatomic, copy, readonly) YapDatabaseCloudCoreOptions *options;
    
    #pragma mark General Configuration
    
    + (YDBCloudCoreOperationSerializer)defaultOperationSerializer;
    + (YDBCloudCoreOperationDeserializer)defaultOperationDeserializer;
    
    - (BOOL)setOperationSerializer:(YDBCloudCoreOperationSerializer)serializer
                      deserializer:(YDBCloudCoreOperationDeserializer)deserializer;
    
    @property (nonatomic, strong, readonly) YDBCloudCoreOperationSerializer operationSerializer;
    @property (nonatomic, strong, readonly) YDBCloudCoreOperationDeserializer operationDeserializer;
    
    
    #pragma mark Pipelines
    
    /**
     * Returns the default pipeline.
     * That is, the pipeline that operations are automatically added to if the `operation.pipeline` value
     * is nil, or doesn't match any registered pipelines.
     *
     * Note that every YDBCloudCore instance MUST have a defaultPipeline.
     * Without a defaultPipeline, attempts to register the extension (with YapDatabase) will fail.
     * So this value is safely nonnull after the extension is registered.
     */
    - (nullable YapDatabaseCloudCorePipeline *)defaultPipeline;
    
    /**
     * Returns the registered pipeline with the given name.
     * If no pipeline is registered under the given name, returns nil.
     */
    - (nullable YapDatabaseCloudCorePipeline *)pipelineWithName:(NSString *)name;
    
    /**
     * Attempts to register the given pipeline.
     * 
     * All pipelines MUST be registered BEFORE the extension itself is registered with the database.
     * 
     * The given pipeline may be in a suspended or non-suspended state.
     * Pipelines are fully capable of queueing work until they are resumed, or until network access is restored.
     *
     * During registration, the given pipeline will automatically have its suspendCount incremented in accordance
     * with the suspendCount of this instance. That is, YapDatabaseCloudCore has suspend/resume methods that automatically
     * invoke the corresponding suspend/resume methods of every registered pipeline. Thus if you have invoked
     * [YapDatabaseCloudCore suspend] twice (and thus it currently has a suspendCount of 2), then during registration
     * of the pipeline, the pipeline's suspendCount will be incremented by 2. This means you can separate your
     * management of suspending/resuming the extension with setting up & installing your pipeline(s). And you need not
     * worry about suspendCount mismanagement concerning this particlar situation.
     *
     * @return YES if the registration was successful, NO otherwise.
     */
    - (BOOL)registerPipeline:(YapDatabaseCloudCorePipeline *)pipeline;
    
    /**
     * Returns all the registered pipelines.
     */
    - (NSArray<YapDatabaseCloudCorePipeline *> *)registeredPipelines;
    
    /**
     * Returns all the registered pipeline names.
     */
    - (NSArray<NSString *> *)registeredPipelineNames;
    
    
    #pragma mark Suspend & Resume
    
    /**
     * Each pipeline has its own suspendCount, and suspend/resume methods.
     * The methods of this class allow you to invoke the suspend/resume method of every registered pipeline.
     */
    
    /**
     * Returns whether or not the suspendCount is non-zero.
     *
     * Remember that each pipeline has its own suspendCount, and suspend/resume methods.
     * So even if the extension isn't suspended as a whole, an individual pipeline may be.
     */
    @property (atomic, readonly) BOOL isSuspended;
    
    /**
     * Returns whether or not the suspendCount is non-zero.
     *
     * Remember that each pipeline has its own suspendCount, and suspend/resume methods.
     * So even if the extension isn't suspended as a whole, an individual pipeline may be.
     */
    @property (atomic, readonly) NSUInteger suspendCount;
    
    /**
     * Invokes the suspend method of every registerd pipeline, and also increments the local suspendCount.
     */
    - (NSUInteger)suspend;
    - (NSUInteger)suspendWithCount:(NSUInteger)suspendCountIncrement;
    
    /**
     * Invokes the resume method of every registerd pipeline, and also decrements the local suspendCount.
     */
    - (NSUInteger)resume;
    
    @end

    Swift

    class YapDatabaseCloudCore : YapDatabaseExtension
  • Undocumented

    See more

    Declaration

    Objective-C

    @interface YapDatabaseCloudCoreOptions : NSObject <NSCopying>
    
    /**
     * Allows you to enforce which type of operations are allowed for this instance.
     * 
     * This is primarily helpful for:
     * - subclasses of YapDatabaseCloudCore, in order to enforce certain types of supported classes
     * - as a debugging tool, especially when transitioning to a different operation class
     *
     * The default value is nil.
     */
    @property (nonatomic, copy, readwrite, nullable) NSSet *allowedOperationClasses;
    
    /**
     * YapDatabaseCloudCore supports storing various "tags" related to cloud syncing, such as eTag values.
     *
     * You may find this useful.
     * Or you may find it more convenient to store such values directly in your objects.
     *
     * The default value is NO (disabled).
     */
    @property (nonatomic, assign, readwrite) BOOL enableTagSupport;
    
    /**
     * YapDatabaseCloudCore supports tracking the association between items in the database & URI's in the cloud.
     * That is, it contains various logic to store a many-to-many mapping of:
     *
     * (local collection/key tuple) <-> (cloudURI)
     *
     * The default value is NO (disabled).
     */
    @property (nonatomic, assign, readwrite) BOOL enableAttachDetachSupport;
    
    @end

    Swift

    class YapDatabaseCloudCoreOptions : NSObject, NSCopying
  • Undocumented

    See more

    Declaration

    Objective-C

    @interface YapDatabaseCloudCoreTransaction : YapDatabaseExtensionTransaction
    
    #pragma mark Operation Handling
    
    /**
     * Allows you to queue an operation to be executed automatically by the appropriate pipeline.
     * This may be used as an alternative to creating an operation from within the YapDatabaseCloudCoreHandler.
     *
     * @param operation
     *   The operation to be added to the pipeline's queue.
     *   The operation.pipeline property specifies which pipeline to use.
     *   The operation will be added to a new graph for the current commit.
     *
     * @return
     *   NO if the operation isn't properly configured for use.
     */
    - (BOOL)addOperation:(YapDatabaseCloudCoreOperation *)operation;
    
    /**
     * Allows you to insert an operation into an existing graph.
     *
     * For example, say an operation in the currently executing graph (graphIdx = 0) fails due to some conflict.
     * And to resolve the conflict you need to:
     * - execute a different (new operation)
     * - and then re-try the failed operation
     *
     * What you can do is create & insert the new operation (into graphIdx zero).
     * And modify the old operation to depend on the new operation (@see 'modifyOperation').
     *
     * The dependency graph will automatically be recalculated using the inserted operation.
     *
     * @param operation
     *   The operation to be inserted into the pipeline's queue.
     *   The operation.pipeline property specifies which pipeline to use.
     *   The operation will be inserted into the graph corresponding to the graphIdx parameter.
     *
     * @param graphIdx
     *   The graph index for the corresponding pipeline.
     *   The currently executing graph index is always zero, which is the most common value.
     *
     * @return
     *   NO if the operation isn't properly configured for use.
     */
    - (BOOL)insertOperation:(YapDatabaseCloudCoreOperation *)operation inGraph:(NSInteger)graphIdx;
    
    /**
     * Replaces the existing operation with the new version.
     * 
     * The dependency graph will automatically be recalculated using the new operation version.
     *
     * @return
     *   NO if the operation isn't properly configured for use.
     */
    - (BOOL)modifyOperation:(YapDatabaseCloudCoreOperation *)operation;
    
    /**
     * This method MUST be invoked in order to mark an operation as complete.
     * 
     * Until an operation is marked as completed or skipped,
     * the pipeline will act as if the operation is still in progress.
     * And the only way to mark an operation as complete or skipped,
     * is to use either the `completeOperationWithUUID:` or one of the skipOperation methods.
     * These methods allow the system to remove the operation from its internal sqlite table.
     */
    - (void)completeOperationWithUUID:(NSUUID *)operationUUID;
    - (void)completeOperationWithUUID:(NSUUID *)operationUUID inPipeline:(nullable NSString *)pipelineName;
    
    /**
     * Use these methods to skip/abort operations.
     * 
     * Until an operation is marked as completed or skipped,
     * the pipeline will act as if the operation is still in progress.
     * And the only way to mark an operation as complete or skipped,
     * is to use either the `completeOperationWithUUID:` or one of the skipOperation methods.
     * These methods allow the system to remove the operation from its internal sqlite table.
     */
    - (void)skipOperationWithUUID:(NSUUID *)operationUUID;
    - (void)skipOperationWithUUID:(NSUUID *)operationUUID inPipeline:(nullable NSString *)pipelineName;
    
    - (void)skipOperationsPassingTest:(BOOL (NS_NOESCAPE^)(YapDatabaseCloudCorePipeline *pipeline,
                                                           YapDatabaseCloudCoreOperation *operation,
                                                           NSUInteger graphIdx, BOOL *stop))testBlock;
    
    - (void)skipOperationsInPipeline:(NSString *)pipeline
                         passingTest:(BOOL (NS_NOESCAPE^)(YapDatabaseCloudCoreOperation *operation,
                                                          NSUInteger graphIdx, BOOL *stop))testBlock;
    
    /**
     * Returns ALL dependencies for the given operation,
     * calculated by recursively visiting dependencies of dependecies.
     */
    - (NSSet<NSUUID*> *)recursiveDependenciesForOperation:(YapDatabaseCloudCoreOperation *)operation;
    
    #pragma mark Operation Searching
    
    /**
     * Searches for an operation with the given UUID.
     * 
     * @return The corresponding operation, if found. Otherwise nil.
     */
    - (nullable YapDatabaseCloudCoreOperation *)operationWithUUID:(NSUUID *)uuid;
    
    /**
     * Searches for an operation with the given UUID and pipeline.
     * If you know the pipeline, this method is a bit more efficient than 'operationWithUUID'.
     * 
     * @return The corresponding operation, if found. Otherwise nil.
     */
    - (nullable YapDatabaseCloudCoreOperation *)operationWithUUID:(NSUUID *)uuid
                                                       inPipeline:(nullable NSString *)pipelineName;
    
    /**
     * Fetches the graph index that corresponds to newly added operations.
     * That is, operations that are added during this commit (read-write transaction).
     *
     * This may be useful if you need to find and modify operations added during the current read/write transaction.
     *
     * @return
     *   The index of the graph that will contain newly added operations from this commit.
     *   Or NSNotFound if the pipeline isn't found.
     */
    - (NSUInteger)graphForAddedOperationsInPipeline:(NSString *)pipelineName;
    
    /**
     * @param operation
     *   The operation to search for.
     *   The operation.pipeline property specifies which pipeline to use.
     *
     * @return
     *   The index of the graph that contains the given operation.
     *   Or NSNotFound if a graph isn't found.
     */
    - (NSUInteger)graphForOperation:(YapDatabaseCloudCoreOperation *)operation;
    
    /**
     * Enumerates the queued operations.
     * 
     * This is useful for finding operation.
     * For example, you might use this to search for an upload operation with a certain cloudURI.
     *
     * Note:
     *   An identical method is available in YapDatabaseCloudCorePipeline.
     *   So a transaction isn't required to search for operations.
     *
     *   The only difference with this methods is, within the context of a read-write transaction,
     *   it will include added, inserted and modified operations.
     *   For example, if an operation has been modified within the read-write transaction,
     *   then you'll see the uncommitted modified version of the operation when enumerating.
      */
    - (void)enumerateOperationsUsingBlock:(void (NS_NOESCAPE^)(YapDatabaseCloudCorePipeline *pipeline,
                                                               YapDatabaseCloudCoreOperation *operation,
                                                               NSUInteger graphIdx, BOOL *stop))enumBlock;
    /**
     * Enumerates the queued operations in a particluar pipeline.
     *
     * This is useful for finding operation.
     * For example, you might use this to search for an upload operation with a certain cloudURI.
     *
     * Note:
     *   An identical method is available in YapDatabaseCloudCorePipeline.
     *   So a transaction isn't required to search for operations.
     *
     *   The only difference with this methods is, within the context of a read-write transaction,
     *   it will include added, inserted and modified operations.
     *   For example, if an operation has been modified within the read-write transaction,
     *   then you'll see the uncommitted modified version of the operation when enumerating.
     */
    - (void)enumerateOperationsInPipeline:(NSString *)pipeline
                          usingBlock:(void (NS_NOESCAPE^)(YapDatabaseCloudCoreOperation *operation,
                                                          NSUInteger graphIdx, BOOL *stop))enumBlock;
    
    /**
     * Enumerates only those operations that have been added during this commit.
     * 
     * That is, the operations added via the `addOperation:` method,
     * within the current readWriteTransaction.
     */
    - (void)enumerateAddedOperationsUsingBlock:(void (NS_NOESCAPE^)(YapDatabaseCloudCorePipeline *pipeline,
                                                                    YapDatabaseCloudCoreOperation *operation,
                                                                    NSUInteger graphIdx, BOOL *stop))enumBlock;
    /**
     * Enumerates only those operations that have been added during this commit.
     *
     * That is, the operations added via the `addOperation:` method,
     * within the current readWriteTransaction.
     */
    - (void)enumerateAddedOperationsInPipeline:(NSString *)pipeline
                                    usingBlock:(void (NS_NOESCAPE^)(YapDatabaseCloudCoreOperation *operation,
                                                                    NSUInteger graphIdx, BOOL *stop))enumBlock;
    
    #pragma mark Tag Support
    
    /**
     * Returns the currently set tag for the given key/identifier tuple.
     *
     * @param key
     *   A unique identifier for the resource.
     *   E.g. the cloudURI for a remote file.
     *
     * @param identifier
     *   The type of tag being stored.
     *   E.g. "eTag", "globalFileID"
     *   If nil, the identifier is automatically converted to the empty string.
     *
     * @return
     *   The most recently assigned tag.
     */
    - (nullable id)tagForKey:(NSString *)key withIdentifier:(nullable NSString *)identifier;
    
    /**
     * Allows you to update the current tag value for the given key/identifier tuple.
     * 
     * @param tag
     *   The tag to store.
     *
     *   The following classes are supported:
     *   - NSString
     *   - NSNumber
     *   - NSData
     * 
     * @param key
     *   A unique identifier for the resource.
     *   E.g. the cloudURI for a remote file.
     * 
     * @param identifier
     *   The type of tag being stored.
     *   E.g. "eTag", "globalFileID"
     *   If nil, the identifier is automatically converted to the empty string.
     * 
     * If the given tag is nil, the effect is the same as invoking removeTagForKey:withIdentifier:.
     * If the given tag is an unsupported class, throws an exception.
     */
    - (void)setTag:(nullable id)tag forKey:(NSString *)key withIdentifier:(nullable NSString *)identifier;
    
    /**
     * Allows you to enumerate the current set of <identifier, tag> tuples associated with the given key.
     */
    - (void)enumerateTagsForKey:(NSString *)key
                      withBlock:(void (^NS_NOESCAPE)(NSString *identifier, id tag, BOOL *stop))block;
    
    /**
     * Removes the tag for the given key/identifier tuple.
     * 
     * Note that this method only removes the specific key+identifier value.
     * If there are other tags with the same key, but different identifier, then those values will remain.
     * To remove all such values, use removeAllTagsForKey.
     *
     * @param key
     *   A unique identifier for the resource.
     *   E.g. the cloudURI for a remote file.
     * 
     * @param identifier
     *   The type of tag being stored.
     *   E.g. "eTag", "globalFileID"
     *   If nil, the identifier is automatically converted to the empty string.
     * 
     * @see removeAllTagsForCloudURI
     */
    - (void)removeTagForKey:(NSString *)key withIdentifier:(nullable NSString *)identifier;
    
    /**
     * Removes all tags with the given key (matching any identifier).
     */
    - (void)removeAllTagsForKey:(NSString *)key;
    
    #pragma mark Attach / Detach Support
    
    /**
     * The attach/detach mechanism works in a manner similar to retain/release.
     *
     * That is, when you attach a (local) collection/key tuple to a (remote) URI, it increments the "retainCount"
     * for the URI. And when you detach the collection/key tuple, then the "retainCount" for the URI is decremented.
     * 
     * Here are the rules:
     *
     * - You can attach a single collection/key tuple to multiple URIs.
     * - A single URI can be "retained" by multiple collection/key tuples.
     *   
     *   Thus there is a many-to-many mapping between collection/key tuples and URIs.
     *
     * - Attaching a collection/key tuple to the same URI multiple times only increments the retain count once.
     * - The same is true of detaching multiple times.
     * 
     *   In other words, when the attach method runs, it first checks to see if the {collection/key <-> URI} mapping
     *   already exists. If it does, then the attach request does nothing.
     *   And similarly, when the detach method runs, it first checks to see if the {collection/key <-> URI} mapping
     *   exists. And if it doesn't, then the detach request does nothing.
     * 
     * - An attempt to attach a collection/key tuple that doesn't exist will be queued for the duration
     *   of the readWriteTransaction.
     * - The attach will then automatically take place (take effect) when the corresponding collection/key is inserted
     *   (within the same readWriteTransaction).
     * 
     *   Thus you can issue an attach request immediately before the corresponding insert of the object.
     * 
     * This method only works if within a readWriteTrasaction.
     * Invoking this method from within a read-only transaction will throw an exception.
     *
     * @param cloudURI
     *   The URI for a remote file / record.
     *   This is typically the relative path of the file on the cloud server.
     *   E.g. "/documents/foo.bar"
     *   
     *   Note: The exact format of URI's is defined by the cloud domain. For example:
     *   - Dropbox may use a relative URL format. (/documents/foo.bar)
     *   - Apple's CloudKit may use URIs based upon CKRecordID.
     *
     * @param key
     *   The key of the row in YapDatabase
     *
     * @param collection
     *   The collection of the row in YapDatabase
     */
    - (void)attachCloudURI:(NSString *)cloudURI
                    forKey:(NSString *)key
              inCollection:(nullable NSString *)collection;
    
    /**
     * @param cloudURI
     *   The URI for a remote file / record.
     *   This is typically the relative path of the file on the cloud server.
     *   E.g. "/documents/foo.bar"
     *
     *   Note: The exact format of URI's is defined by the cloud domain. For example:
     *   - Dropbox may use a relative URL format. (/documents/foo.bar)
     *   - Apple's CloudKit may use URIs based upon CKRecordID.
     *
     * @param key
     *   The key of the row in YapDatabase
     * 
     * @param collection
     *   The collection of the row in YapDatabase
     * 
     * Important: This method only works if within a readWriteTrasaction.
     * Invoking this method from within a read-only transaction will throw an exception.
     */
    - (void)detachCloudURI:(NSString *)cloudURI
                    forKey:(NSString *)key
              inCollection:(nullable NSString *)collection;
    
    /**
     * Allows you to enumerate the <collection, key> tuples attached to the given cloudURI.
     *
     * If a <collection, key> has been attached to the cloudURI, but the corresponding object hasn't been
     * added to the database yet, the pending flag will be set to YES.
     */
    - (void)enumerateAttachedForCloudURI:(NSString *)cloudURI
                              usingBlock:(void (NS_NOESCAPE^)(NSString *key, NSString *collection, BOOL pending, BOOL *stop))block;
    
    /**
     * Allows you to enumerate all attached cloudURI's for the given <collection, key> tuple.
     */
    - (void)enumerateAttachedForKey:(NSString *)key
                         collection:(nullable NSString *)collection
                         usingBlock:(void (NS_NOESCAPE^)(NSString *cloudURI, BOOL *stop))block;
    
    @end

    Swift

    class YapDatabaseCloudCoreTransaction : YapDatabaseExtensionTransaction
  • This is the base class for concrete subclasses such as FileOperations & RecordOperations.

    Do not directly create instances of this class. Instead create instances of concrete subclass.

    See more

    Declaration

    Objective-C

    @interface YapDatabaseCloudCoreOperation : NSObject <NSCoding, NSCopying>

    Swift

    class YapDatabaseCloudCoreOperation : NSObject, NSCoding, NSCopying
  • A pipeline represents a queue of operations for syncing with a cloud server. It operates by managing a series of graphs.

    Generally speaking, a graph is all the cloud operations that were generated in a single commit (for a specific pipeline). Within the graph are the various operations with their different dependencies & priorities. The operations within a graph will be executed in accordance with the set dependencies & priorities.

    The pipeline manages executing the operations within each graph.

    See more

    Declaration

    Objective-C

    @interface YapDatabaseCloudCorePipeline : NSObject

    Swift

    class YapDatabaseCloudCorePipeline : NSObject
  • Every pipeline must have a delegate, which is responsible for performing the operations in the pipeline queue.

    See more

    Declaration

    Objective-C

    @protocol YapDatabaseCloudCorePipelineDelegate

    Swift

    protocol YapDatabaseCloudCorePipelineDelegate
  • A graph contains all the cloud operations that were generated in a single commit (for a specific pipeline). Within the graph are the various operations with their different dependencies & priorities.

    The graph is in charge of managing the execution order of the operations in accordance with the set dependencies & priorities.

    Declaration

    Objective-C

    @interface YapDatabaseCloudCoreGraph : NSObject

    Swift

    class YapDatabaseCloudCoreGraph : NSObject