YapDatabase extensions for use with Swift

Overview

Build status Coverage Status CocoaPods Compatible CocoaPods Documentation Platform Carthage compatible

YapDatabaseExtensions

Read my introductory blog post about YapDatabase & YapDatabaseExtensions, and a follow up on YapDatabaseExtensions 2.

YapDatabaseExtensions is a suite of convenience APIs for working with YapDatabase. If you’re not familiar with YapDatabase, it’s a powerful key value database for iOS and Mac - check it out!

Motivation

While YapDatabase is great, it’s lacking some out of the box convenience and Swift support. In particular, YapDatabase works heavily with AnyObject types, which is fine for Objective-C but means no type fidelity with Swift. Similarly saving value types like structs or enums in YapDatabase is problematic. This framework has evolved through 2015 to tackle these issues.

Value Types

The support for encoding and decoding value types, previously the Saveable and Archiver protocols, has been renamed and moved to their own project. ValueCoding is a dependency of this framework (along with YapDatabase itself). See its README for more info. However, essentially, if you used this project before version 2.1, you’ll need to rename some types - and Xcode should present Fix It options. Saveable is now ValueCoding, its nested type, previously ArchiverType is now Coder, and this type must conform to a protocol, previously Archiver, now CodingType. See how they were all mixed up? Now fixed.

Persistable

This protocol expresses what is required to support reading from and writing to YapDatabase. Objects are referenced inside the database with a key (a String) inside a collection (also a String).

public protocol Identifiable {
    typealias IdentifierType: CustomStringConvertible
    var identifier: IdentifierType { get }
}

public protocol Persistable: Identifiable {
    static var collection: String { get }
    var metadata: MetadataType? { get set }
}

The identifier property allows the type to support an identifier type such as NSUUID or Int.

While not a requirement of YapDatabase, for these extensions, it is required that values of the same type are stored in the same collection - it is a static property.

There is also a YapDB.Index struct which composes the key and collection into a single type. This is used internally for all access methods. Properties defined in an extension on Persistable provide access to key and index.

Metadata

YapDatabase supports storing metadata alongside the primary object. YapDatabaseExtensions supports automatic reading and writing of metadata as an optional property of the Persistable type.

By default, all types which conform to Persistable, will get a MetadataType of Void which is synthesized by default. Therefore if you do not want or need a metadata type, there is nothing to do.

To support a custom metadata type, just add the following to your Persistable type, e.g.:

struct MyCustomValue: Persistable, ValueCoding {
    typealias Coder = MyCustomValueCoder
    static let collection = “MyCustomValues”
    var metadata: MyCustomMetadata? = .None
    let identifier: NSUUID
}

where the type (MyCustomMetadata in the above snippet) implements either NSCoding or ValueCoding.

When creating a new item, set the metadata property before saving the item to the database. YapDatabaseExtensions will then save the metadata inside YapDatabase correctly. There is no need to encode the metadata inside the primary object. When reading objects which have a valid MetadataType, YapDatabaseExtensions will automatically read, decode and set the item’s metadata before returning the item.

Note that previous metadata protocols ObjectMetadataPersistable and ValueMetadataPersistable have been deprecated in favor of Persistable.

“Correct” Type Patterns

Because the generic protocols, ValueCoding and CodingType have self-reflective properties, they must be correctly implemented for the APIs to be available. This means that the equality ValueCoding.Coder.ValueType == Self must be met. The APIs are all composed with this represented in their generic where clauses. This means that if your ValueCoding type is not the ValueType of its Coder, your code will not compile.

Therefore, there are six valid Persistable type patterns as described in the table below:

Item encoding Metadata encoding Pattern
NSCoding Void Metadata Object
NSCoding NSCoding ObjectWithObjectMetadata
NSCoding ValueCoding ObjectWithValueMetadata
ValueCoding Void Metadata Value
ValueCoding NSCoding ValueWithObjectMetadata
ValueCoding ValueCoding ValueWithValueMetadata

Extension APIs

YapDatabaseExtensions provides two styles of API. The functional API works on YapDatabase types, YapDatabaseReadTransaction, YapDatabaseReadWriteTransaction and YapDatabaseConnection. The persistable API works on your Persistable types directly, and receives the YapDatabase type as arguments.

Functional API

The following “functional” APIs are available directly on the YapDatabase types.

// Get a YapDatabaseConnection
let connection = db.newConnection()

// Write a single item
connection.write(item) 

// Write an array of items, using one transaction.
connection.write(items)

// Write asynchronously
connection.asyncWrite(item) { print(“did finish writing”) }
connection.asyncWrite(items) { print(“did finish writing”) }

// Create a write transaction block for multiple writes.
connection.write { transaction in
    transaction.write(item)
    transaction.write(items) 
}

// Write many items asynchronously
connection.asyncWrite({ transaction in
    transaction.write(item)
    transaction.write(items) 
}, completion: { print(“did finish writing”) })

For reading:

if let item: Item? = connection.readAtIndex(index) {
  // etc
}

if let meta: Item.MetadataType? = connection.readMetadataAtIndex(index) {
  // etc
}

let items: [Item] = connection.readAtIndexes(indexes)

if let item: Item? = connection.readByKey(index) {
  // etc
}

let items: [Item] = connection.readByKeys(keys)

let all: [Item] = connection.readAll()

connection.read { transaction in
    let a: Item? = transaction.readAtIndex(index)
    let b: Item? = transaction.readByKey(key)
    let c: [Item] = transaction.readAtIndexes(indexes)
    let d: [Item] = transaction.readByKeys(keys)
    let all: [Item] = transaction.readAll()
    let meta: [Item.MetadataType] = transaction.readMetadataAtIndexes(indexes)
}

Persistable API

The APIs all work on single or sequences of Persistable items. To write to the database:

// Use a YapDatabaseReadWriteTransaction.
let written = item.write(transaction)

// Write synchronously using a YapDatabaseConnection.
let written = item.write(connection)

// Write asynchronously using a YapDatabaseConnection.
item.asyncWrite(connection) { written in
    print(“did finishing writing”)
}

// Return an NSOperation which will perform an sync write on a YapDatabaseConnection.
let write: NSOperation = item.write(connection)

Reading items from the database is a little different.

// Read using a YapDB.Index.
if let item = Item.read(transaction).byIndex(index) {
   // etc - item is correct type, no casting required.
}

// Read an array of items from an array of YapDB.Index(s)
let items = Item.read(transaction).atIndexes(indexes)

// Read using a key
if let item = Item.read(transaction).byKey(key) {
   // etc - item is correct type, no casting required.
}

// Read an array of items from an array of String(s)
let items = Item.read(transaction).byKeys(keys)

if let allItems = Item.read(transaction).all() {
   // etc - an array of Item types.
}

// Get the Items which exist for the given keys, and return the [String] keys which are missing.
let (items, missingKeys) = Item.read(transaction).filterExisting(someKeys)

Similarly, to work directly on a YapDatabaseConnection, use the following:

if let item = Item.read(connection).byIndex(index) {
   // etc - item is correct type, no casting required.
}

if let item = Item.read(connection).byKey(key) {
   // etc - item is correct type, no casting required.
}

if let allItems = Item.read(connection).all() {
   // etc - an array of Item types.
}

let (items, missingKeys) = Item.read(connection).filterExisting(someKeys)

Installation

YapDatabaseExtensions is available through CocoaPods. To install it, simply add the following line to your Podfile:

pod 'YapDatabaseExtensions'

If you don’t want the extensions API on Persistable, integrate the Functional subspec like this:

pod 'YapDatabaseExtensions/Functional’

API Documentation

API documentation is available on CocoaDocs.org.

Developing

To start working in this repository’s YapDatabaseExtensions.xcodeproj, you’ll need to use Carthage to download & build the project’s dependencies, with the commands carthage checkout and carthage build.

Author

Daniel Thorpe, @danthorpe

License

YapDatabaseExtensions is available under the MIT license. See the LICENSE file for more info.

Comments
  • Be smarter about when to write metadata

    Be smarter about when to write metadata

    • [x] Only write the metadata if its set and it is not equal to any existing metadata for the index.
    • [x] Remove any stored metadata if the property is .None.
    • [ ] Test coverage
    opened by danthorpe 15
  • Minor reorganizations in YapDatabaseExtensions.swift

    Minor reorganizations in YapDatabaseExtensions.swift

    These changes are minor, opinion-based reorganizations with no functional change; thus this PR may be closed with no hard feelings if this code churn is undesirable.

    • https://github.com/danthorpe/YapDatabaseExtensions/commit/d21165b3479f4abd7ef891dc113f83de05cf6459 separates YapDB.Index's Hashable and CustomStringConvertible implementations; they're not really related and it took me a moment to realize there wasn't a reason for them to be grouped together like that.

    • https://github.com/danthorpe/YapDatabaseExtensions/commit/8df385e2d9f69c98480946253c03802aaf1b5699 groups free functions operating on Persistables alongside the Persistable protocol definition, as so:

    opened by cdzombak 12
  • Questions around reading, updating and metadata.

    Questions around reading, updating and metadata.

    Hey Dan

    Thanks for the awesome work on the extensions! Excited about moving allot of my data layer over to structs.

    I have a couple of questions if you have the time?

    Reading

    I have a User struct, see below for its implementation, it adopts the Persistable protocol.

    How do I best go about cleanly reading records by key? I thought something like this would do the trick but seems to complain about ambiguous reference to member.

    let user: User? = User.readByKey("1")
    
    Updating

    This is more of a general question as how you approach updating records in your database, do you normally pull out an existing record, create a new struct based on that and then write the new struct to the database with the existing key?

    Metadata

    I could not seem to find a way to set the default Void metadata on the user struct. This seems wrong?

    var metadata: NSNumber? {
        return .None
    }
    
    User
    import Foundation
    import ValueCoding
    import YapDatabaseExtensions
    
    struct User: Equatable {
    
        // MARK: - Internal Properties
    
        let ID: Int
    
        let name: String
    
        // MARK: - Private Properties
    
        // MARK: - Initializers
    
        init(ID: Int, name: String) {
            self.ID = ID
            self.name = name
        }
    
        // MARK: - Internal Methods
    
        // MARK: - Private Methods
    }
    
    extension User: ValueCoding {
    
        // MARK: - ValueCoding
    
        typealias Coder = UserCoder
    }
    
    extension User: Persistable {
    
        var identifier: Identifier {
            return "\(ID)"
        }
    
        static var collection: String {
            return "Users"
        }
    
        var metadata: NSNumber? {
            return .None
        }
    }
    
    func == (lhs: User, rhs: User) -> Bool {
        return lhs.ID == rhs.ID
    }
    
    question 
    opened by pnicholls 10
  • Refactor read & write APIs, including support for external Metadata

    Refactor read & write APIs, including support for external Metadata

    I'm making some changes to the read and write APIs, following on from my first attempt in #39. They are as follows:

    There are 6 different kinds of "types" which are supported, as before, for clarification these are:

    | Description | Encoding Style | Metadata Encoding Style | | --- | --- | --- | | Object with no metadata | NSCoding | N/A | | Object with Object metadata | NSCoding | NSCoding | | Object with Value metadata | NSCoding | Saveable | | Value with no metadata | Saveable | N/A | | Value with Object metadata | Saveable | NSCoding | | Value with Value metadata | Saveable | Saveable |

    The APIs are only available when your types correctly implement one of these 6 patterns, and the changes being introduced which uses constrained protocol extensions make writing these APIs far less error prone as I only need to write the where constraint once for each combination.

    So, here's what they look like, I'm gonna use Foo as my Persistable type, and you should assume that it could be any of the above 6 patterns.

    Reading

    If you have a YapDatabaseConnection...

    connection.read { transaction in
    
        // Get an optional Foo by YapDB.Index
        if let foo = Foo.read(transaction).atIndex(anIndex) {
            // etc
        }
    
        // Get an optional Foo by key (String)
        if let foo = Foo.read(transaction).byKey(aKey) {
            // etc
        }
    
        // this is [Foo], could be empty, count could be less than someIndexes
        let foos = Foo.read(transaction).atIndexes(someIndexes)
    
        // this is [Foo], could be empty, and count could be less than someKeys
        let foos2 = Foo.read(transaction).atKeys(someKeys)
    
        // Get all the Foo items in the db, as [Foo], could be empty.
        let foos3 = Foo.read(transaction).all()
    
        // Get the [Foo] objects which exist for the given keys, and return the [String] keys which are missing.
        let (foos4, missingKeys) = Foo.read(transaction).filterExisting(someKeys)
    }
    

    But you can also perform the same functionality directly with a connection too.

    if let foo = Foo.read(connection).atIndex(anIndex) {
        // etc
    }
    if let foo = Foo.read(connection).byKey(aKey) {
        // etc
    }
    let foos = Foo.read(connection).atIndexes(someIndexes)
    let foos2 = Foo.read(connection).atKeys(someKeys)
    let foos3 = Foo.read(connection).all()
    let (foos4, missingKeys) = Foo.read(connection).filterExisting(someKeys)
    

    The same APIs but with YapDatabase instances now exist only internally to prevent poor programming practices. They are used internally for unit testing.

    Writing

    If you have a YapDatabaseConnection...

    let foo = Foo() 
    let foos = Set([Foo(), Foo(), Foo()])
    
    connection.write { transaction in 
        // write one item at a time
        foo.write.on(transaction)
        // write a SequenceType of items
        foos.write.on(transaction)
    }
    

    Alternatively, to perform writes in the same transaction, but directly on a connection, you can do....

    // Write synchronously using the connection.
    foo.write.sync(connection)
    foos.write.sync(connection)
    
    // Write asynchronously using the connection.
    foo.write.async(connection) { print("finished writing") }
    foos.write.async(connection) { print("finished writing") }
    
    // Return an NSOperation which will perform the write using the connection
    queue.addOperation(foo.write.operation(connection))
    queue.addOperation(foos.write.operation(connection))
    

    this is handy if you only have a single item or single array of items to write - which is probably the most common scenario.

    Note also that these APIs do not have return values. Previously the write() function would return the item being written, however this is fairly redundant and would have made the implementation impossible/much harder :).

    Framework consumers cannot write directly to YapDatabase instances now, although internally there is a .to(database) API for unit testing.

    But what about metadata?

    This PR will deprecate ObjectMetadataPersistable and ValueMetadataPersistable which are both replaced by MetadataPersistable which is:

    public protocol MetadataPersistable: Persistable {
        typealias MetadataType
        var metadata: MetadataType? { get set }
    }
    

    For types which implement MetadataPersistable, when writing, YapDatabaseExtensions will write the metadata property (if it exists) to YapDatabase. When reading, YapDatabaseExtensions will set the property (if it exists in the database) before returning the item. This is the best and ideal behavior, as you get optional metadata types and no additional storage costs. Although there are no constraints on MetadataType in the protocol, it must implement either NSCoding or Saveable for the extensions to perform as expected.

    Original issue discussions

    Looking for some input here from uses who have metadata types associated with their models. How do you define your models? Do you save the metadata inside the model in addition to having YapDatabase save it as metadata? If not, how would you like to read your models and/or metadata?

    This is how I've previously used YapDatabase's metadata functionality: (which might not be what you assumed).

    struct Foo: ValueMetadataPersistable {
    
        struct Metadata {
              let created: NSDate
              let modified: NSDate?
        }
    
        let metadata: Metadata
    }  
    
    1. the MetadataType is a nested type within my model type .i.e. Foo.Metadata.
    2. the metadata is a property of the model - which means I would archive it inside the model object - meaning that there is no need to "read" it in addition to reading the model itself.

    The reason for this approach is that, I think this is how YapDatabase is designed to work - when you read objects for key, you get back the object, you can retrieve the metadata separately using another API. The purpose is to provide quicker (separate caches & presumably less decoding effort) access to the metadata of objects in extensions such as YapDatabase Views etc. When you write models to the database, the object and metadata is written in the same call. So, in other words the cost of having faster access to that metadata is that YapDatabase will effectively store it twice, once as part of the model and then again in a metadata only blob.

    If you follow the above approach, there is no explicit need to read (model & metadata) because the model includes the metadata. However, you may wish to read only the metadata, in which case try readMetadataAtIndex: functions. Although I can add in the PR other functions like readMetadata(key: String) functions.

    Okay, so after discussions below, I'm gonna add functionality for "external metadata" which means that it is only stored inside YapDatabase - potentially, renaming/replacing the current metadata based protocols

    protocol ValueMetadata: Persistable {
        typealias MetadataType: Saveable
    
       var metadata: MetadataType? { get set }
    }
    

    with updates to read and write functions which will automatically store metadata (if set) during a write, and will set the property (if available) when reading.

    opened by danthorpe 10
  • Metadata should be read/write capable independently

    Metadata should be read/write capable independently

    Currently I can write my Item without writing its Metadata by setting the metadata property to nil, there's no way to conversely write the Metadata without also writing the Item.

    There also doesn't appear to be a way to read either one without reading them both. This may seem odd, given that my original request was that I wanted to be able to read them together, which I now can, but I'd still like to be able to read them separately if needed.

    Neither of these are really that big of a deal and may just be me prematurely optimizing, but as I'm refactoring my code to use the new API these have come up and I thought I'd run them by you.

    opened by aranasaurus 6
  • Minor inline documentation & README improvements

    Minor inline documentation & README improvements

    While reviewing the code, I found a few places where the inline documentation could be clearer; and I also wanted to note the getting-started steps with Carthage in case other devs who check out this repo aren't already familiar.

    opened by cdzombak 4
  • Restore API for functions

    Restore API for functions

    The only problem with adding functions directly to YapDatabaseReadWriteTransaction (etc) is that every function needs to be generic. This can be a bit of a problem as this is the generic where clause for value types with value type metadata..

    extension Readable
        where
        ItemType: Saveable,
        ItemType: MetadataPersistable,
        ItemType.ArchiverType: NSCoding,
        ItemType.ArchiverType.ValueType == ItemType,
        ItemType.MetadataType: Saveable,
        ItemType.MetadataType.ArchiverType: NSCoding,
        ItemType.MetadataType.ArchiverType.ValueType == ItemType.MetadataType {
    

    which is very verbose and error prone - although less so now that the protocol types are relatively stable.

    So, there are a couple of options which might work as alternatives.

    1. Similar to the Read and Write structures, we could wrap YapDatabaseReadWriteTransaction, YapDatabaseConnection inside a generic type, which then has generic methods for read & write. e.g.

      if let person: Person = transaction.read.byKey(key) {
         // etc
      }
      

      which is probably the best, although not sure that this is possible.

    2. ~~Add a generic ItemType to the facade protocols ReadTransactionType etc and then define the functions in protocol extensions?~~ This will work - but don't think that it'll be possible to have the YapDatabase types then conform to the protocols. - correct, not a viable solution.

    I think it's going to have to be fully generic functions. But the can be added to the facade protocols which is better for testing at least. Anyway, so the APIs are as follows...

    let item: Item? = transaction.readAtIndex(index)
    let item: Item? = transaction.readByKey(key)
    let items: [Item] = transaction.readAtIndexes(indexes)
    let items: [Item] = transaction.readByKeys(keys)
    
    let item: Item? = connection.readAtIndex(index)
    let item: Item? = connection.readByKey(key)
    let items: [Item] = connection.readAtIndexes(indexes)
    let items: [Item] = connection.readByKeys(keys)
    
    transaction.write(item)
    transaction.write(items)
    connection.write(item)
    connection.write(items)
    connection.asyncWrite(item) { print("did write") }
    connection.asyncWrite(items) { print("did write") }
    
    transaction.remove(item)
    transaction.remove(items)
    connection.remove(item)
    connection.remove(items)
    connection.asyncRemove(item) { print("did remove") }
    connection.asyncRemove(items) { print("did remove") }
    

    where Item is one of the following type patterns:

    • [ ] NSCoding class with no metadata
    • [x] NSCoding class with NSCoding class metadata
    • [x] NSCoding class with Saveable value metadata
    • [ ] Saveable value with no metadata
    • [x] Saveable value with NSCoding class metadata
    • [x] Saveable value with Saveable value metadata

    Notes:

    1. Not going to provide a functional transaction.readAll() -> Use the Persistable extension for this.
    opened by danthorpe 4
  • Correct the spelling of CocoaPods in README

    Correct the spelling of CocoaPods in README

    This pull requests corrects the spelling of CocoaPods 🤓 https://github.com/CocoaPods/shared_resources/tree/master/media

    Created with cocoapods-readme.

    opened by ReadmeCritic 2
  • Group

    Group "functional" and "persistable" APIs under one header in README

    When reading the README, I found it strange that the paragraph

    There are also two styles of API. The functional API works on YapDatabase types, …

    was under the “Correct Type Patterns” header.

    This minor change resolves that confusion, IMO, by introducing a new header above that paragraph and bumping the Functional and Persistable API headers down to h3 from h2.

    opened by cdzombak 2
  • Code comments still refer to Saveable in a few places

    Code comments still refer to Saveable in a few places

    YapDatabaseExtensions.swift was where I found a couple, but thought it'd be a good idea to flag it in an issue and do a search through the rest of the files when someone gets a chance.

    documentation 
    opened by aranasaurus 2
  • Is using newConnection() for all APIs performant in all situations?

    Is using newConnection() for all APIs performant in all situations?

    Hi! Great work abstracting YapDB!

    I'm wondering if using newConnection() for all exposed API calls is performant, as YapDatabase recommends to keep connections around for caching reasons.

    I generally cache the connections in properties from where I'm accessing YapDB; Usually one for readonly operations which will have sync readonly calls, another one for readwrite operations which will have asynchronous calls.

    Have you tried this in a big application and experienced any issues?

    opened by DarthMike 2
  • ValueCoding Errors

    ValueCoding Errors

    I'm using Xcode 8.0/Swift3

    I used Cocoapods to install YapDatabaseExtensions, along with it ValueCoding was installed. The ValueCoding.swift has 12 or so compiler errors. Most are complaining about >> Use of undeclared type 'Generator' and Value of type 'S' has no member 'flatMap'

    How do I fix this? Thank you

    opened by Mopar440 1
  • Swift 3 support

    Swift 3 support

    Hi Dan,

    You mentioned a Swift 3 port was in progress a while ago. My team's Swift 3 port is currently blocked by YapDatabaseExtensions, so if there's any way I can help with the this port, please let me know.

    opened by JimRoepcke 4
  • Feature/separate value and metadata

    Feature/separate value and metadata

    Dan, thanks for making YapDatabaseExtensions!

    This PR contains some sutble but signficant changes I consider important for improving the performance and flexibility of this framework.

    Metadata changes

    This PR improves the handling metadata by YapDatabaseExtensions. I see there have been some previous attempts at reforming the metadata handling but none had been merged yet. I hope this solution is found to be acceptable.

    The var metadata property and associatedtype MetadataType as been removed from the Persistable protocol.

    YapDatabase does not place a constraint on the types of metadata that can be associated with values, and this is a useful feature. Having a single MetadataType per Persistable type reduced this flexibility.

    An important performance design aspect of metadata in YapDatabase is the ability able to read and write it independently of the value. Unfortunately, with the current design, when you have a Persistable with a MetadataType, all reads will do an extra read for the metadata and then set the metadata on the value. This means twice the number of reads (even when the metadata isn't needed after the read) and creating a copy of the value when value types are used, as value types are immutable. If one used objects for their Yap values they'd have to make them mutable which isn't compatible with Yap's sharing policy. In practice, values and metadata do tend to be written together, but for reads the opposite is true.

    It is still possible to read/write a value and a metadata at the same time - the methods in the "With[Object|Value]Metadata" files have been renamed to have "with metadata" in the name. For example, write is now writeWithMetadata. These "with metadata" methods take and return a YapItem<Value, Metadata>, which is a simple new struct akin to a tuple, containing the value, metadata and their associated type information since it's generic. This is preferable to a tuple because anonymous tuple types cannot be extended, while structs obviously can. By using this type-rich YapItem, the desirable type-safety features in YapDatabaseExtensions are not impacted.

    Additional changes

    Additionally, the methods that query for multiple YapDB.Index (such as readAtIndexes) no longer flatMap the return value, so it is now easy to determine which YapDB.Index were not found in the database. If one doesn't need this information they can easily flatMap the return value.

    How to test

    All tests have been updated and pass.

    I merged danthorpe:development into my branch just before submitting this PR. It merged with no conflicts.

    opened by JimRoepcke 3
  • Separation of metadata from object data at save time?

    Separation of metadata from object data at save time?

    This is definitely a question, not a bug report, so read accordingly :)

    I've recently been re-structuring my data a bit so that I have the fields that I sort on in the Metadata and everything else in the object data. Reading https://github.com/yapstudios/YapDatabase/wiki/Views#initialization-tips suggests that is the recommended way to avoid unnecessary recalculation of the sortings. The problem I'm running into is that because YapDatabaseExtensions writes the metadata every time it writes an object, even if that metadata hasn't changed, every time I write an object the database my sort blocks are being run, even though I haven't updated their sort-able properties.

    My question is, am I missing something? Is there a way that I can accomplish this with YapDatabaseExtensions or is this an approach that it's just not designed for?

    question 
    opened by aranasaurus 9
Releases(2.5.0)
  • 2.5.0(Mar 27, 2016)

  • 2.4.0(Mar 25, 2016)

    2.4.0

    1. [YDB-73, YDB-77]: Improvements to README and documentation. Thanks @cdzombak!
    2. [YDB-74]: Improvements to CI & automation.
    3. [YDB-78]: Annotations the code base with MARK: -. Thanks again @cdzombak.
    4. [YDB-81]: Corrects the spelling of CocoaPods - thanks @ReadmeCritic!
    5. [YDB-83]: Switches CI scripts to use scan and update the Cartfile to point directly at YapDatabase.
    6. [YDB-82]: Updates CI pipeline to support Swift 2.1 & Swift 2.2 based branches.

    Sorry this all took so long to get released - kinda dropped off my radar. Thanks to @cdzombak for improving the overall readability of the codebase!

    Source code(tar.gz)
    Source code(zip)
  • 2.3.0(Nov 11, 2015)

    2.3.0

    1. [YDB-70, YDB-71]: Changes necessary for compatibility with YapDatabase 2.7.4 which added sub-module support for most extensions.
    • Currently this version is not available via CocoaPods, as I'm waiting for a new version of YapDatabase to be released.
    Source code(tar.gz)
    Source code(zip)
  • 2.2.0(Oct 21, 2015)

    2.2.0

    1. [YDB-55]: Removes some leftover references to Saveable.
    2. [YDB-58]: Fixes support for Metadata, removes MetadataPersistable entirely.
    3. [YDB-56]: Adds readMetadataAtIndex functional API.
    4. [YDB-57]: Adds readAll functional API
    5. [YDB-59]: Updates APIs to use SequenceType instead of Array.
    6. [YDB-60]: Fixes documentation issues.
    7. [YDB-61]: Makes async completion block arguments optional, default to .None.
    8. [YDB-62]: Restores the return value behavior of the write functional API.
    9. [YDB-64]: Adds missing sequence type for value with value metadata pattern. Somehow missed this earlier.
    10. [YDB-65]: Adds a small Curried API, which returns closures accepting transactions.
    11. [YDB-66]: Updates the Persistable write API - no longer needs an intermediary generic type. Has correct return values.

    Thanks a lot to Ryan (@aranasaurus) for helping me with all these changes - effectively a rewrite of the whole framework.

    Source code(tar.gz)
    Source code(zip)
  • 2.1.0(Oct 11, 2015)

    2.1.0

    This is a a pretty big release, with some breaking changes to be aware of. The significant changes are:

    ValueCoding

    The Saveable (and associated) protocol(s) have been removed from the project. They have been renamed to be clearer and moved into their own project/pod called ValueCoding. See #48.

    New API

    There is now a new read/write/remove "property" API available to types which implement Persistable. In addition, now metadata is correctly supported in YapDatabase. The single MetadataPersistable protocol allows for optional metadata which does not need to be encoded into the primary object. See #42

    OS X

    Hello Mac OS X developers! The project and podspec now correctly builds OS X frameworks. See #43.

    Quality

    I've been working really hard to make sure that the code is well tested, feel free to browse the tests. But, I've also got code coverage reports working with new Xcode 7 coverage data, on CodeCov. Currently coverage is 80%, but all APIs are tested. The YapDB nested types for views, queries, filters etc are poorly tested at the moment (~ 25%). Also, documentation needs a bit a bit more work, but it's steadily improving. See #44, #47.

    Full change log:

    1. [YDB-42]: Refactors read & write API, correctly supporting metadata.
    2. [YDB-43]: Makes project cross-platform (iOS & Mac OS)
    3. [YDB-44]: Enables code coverage reporting with CodeCov.io, see reports here.
    4. [YDB-45]: Adds back functional API.
    5. [YDB-47]: Updates README.
    6. [YDB-48]: Removes Saveable, created ValueCoding as a standalone project and new dependency.
    Source code(tar.gz)
    Source code(zip)
  • 2.0.0(Sep 16, 2015)

    2.0.0

    Release for Swift 2.0.

    There are some changes in 2.0.0.

    Improved Syntax for archiving & unarchiving

    Thanks to protocol extensions in Swift 2.0, your types which implement Saveable and Persistable will now get some convenience APIs for free:

    static func unarchive(object: AnyObject?) -> Self?
    static func unarchive(objects: [AnyObject]) -> [Self]
    static func archive(value: Self?) -> AnyObject?
    static func archive(values: [Self]) -> [AnyObject]
    

    This means, that previously with Swift 1.2, code would look like this:

    if let person: Person = valueFromArchive(object) {
        println("Unarchived person: \(person.name)")
    }
    

    But with Swift 2.0, it now looks like this...

    if let person = Person.unarchive(object) {
        print("Unarchived person: \(person.name)")
    }
    

    The README and docs will be updated over this week as the dust settles.

    Source code(tar.gz)
    Source code(zip)
  • 1.8.0(Sep 15, 2015)

    1.8.0

    1. [YDB-36]: Sets the required version of BrightFutures to the latest for Swift 1.2, which is 2.0.1.
    2. [YDB-37]: Sets the required version of PromiseKit to the latest for Swift 1.2, which is 2.2.1 (as submitted to CocoaPods).

    Also updates to latest version of YapDatabase, which is version 2.7, which introduced breaking changes to View block types.

    Source code(tar.gz)
    Source code(zip)
  • 1.7.0(Sep 1, 2015)

    1.7.0

    1. [YDB-25]: Adds YapDB.Search to aid with running FTS queries. An example of using this will be forthcoming (probably after Swift 2.0 has settled). But essentially, you can initialize it with your db, an array of YapDB.Fetch values (which should be views) and a string mapper. Then execute usingTerm(term: String) with the search term supplied by the user to run the search.
    2. [YDB-26]: Adds some missing default parameters for the YapDB.SecondaryIndex wrapper.
    3. [YDB-27]: Removes an explicit unwrap which could cause a crash if pattern matching against value types.
    4. [YDB-29]: Adds support to YapDatabaseConnection for writeBlockOperation (NSBlockOperation), write and remove APIs. This is great if you want to perform a number of writes of different types in the same transaction inside of an NSOperation based architecture, as you can do:
    queue.addOperation(connection.writeBlockOperation { transaction in 
        transaction.write(foo)
        transaction.write(bar)
        transaction.remove(bat)
    })
    

    If you're using my Operations framework, as these operations are NSBlockOperations, use ComposedOperation to attach conditions or observers. E.g.

    let write = ComposedOperation(connection.writeBlockOperation { transaction in 
        transaction.write(foo)
        transaction.write(bar)
        transaction.remove(bat)
    })
    write.addCondition(UserConfirmationCondition()) // etc etc
    queue.addOperation(write)
    
    1. [YDB-30]: Expands the YapDB.Mappings type to support the full YapDatabaseViewMappings gamut.
    2. [YDB-31]: Silences a warning in the removeAtIndexes API.
    Source code(tar.gz)
    Source code(zip)
  • 1.6.0(Aug 9, 2015)

    1.6.0

    1. [YDB-22]: Adds YapDB.Fetch.Index which wraps YapDatabaseSecondaryIndex extension.
    2. [YDB-23]: Fixes a crash which has been observed in some cases in a Release configuration where writing a value type can fail to get the type’s Archiver.
    3. [YDB-24]: Just cleans up some of the code.
    Source code(tar.gz)
    Source code(zip)
  • 1.5.0(Jun 10, 2015)

    1.5.0

    1. [YDB-19]: Implements Saveable on YapDB.Index. This makes it easier to store references between YapDatabase objects. In general this is preferable to storing references as let fooId: Foo.IdentifierType.
    2. [YDB-21]: Restructures the project. The framework is now in an Xcode project in framework, with its associated unit tests in place. This is in preparation for Xcode 7, to get code coverage of the framework. The Example has been moved to examples/iOS, although it doesn’t really do much, except provide some models.
    Source code(tar.gz)
    Source code(zip)
  • 1.4.0(May 22, 2015)

  • 1.3.0(May 6, 2015)

    1.3.0

    1. [YAP-1]: Adds API to access metadata. Fixes a bug writing items with metadata using connection or database instances.
    2. [YAP-15]: Improves the code documentation significantly. Updates the README.
    Source code(tar.gz)
    Source code(zip)
  • 1.2.0(Apr 24, 2015)

    1. [YAP-6]: Improves the code documentation significantly. Updates the README.
    2. [YAP-8]: Provides wrappers for YapDatabase View Extensions.
    3. [YAP-12]: Improves and adds to the test coverage. Fixes an oversight where keys and indexes were not uniqued before accessing the database.
    Source code(tar.gz)
    Source code(zip)
Owner
Daniel Thorpe
Daniel Thorpe
TypedDefaults is a utility library to type-safely use NSUserDefaults.

TypedDefaults TypedDefaults is a utility library to type-safely use NSUserDefaults. Motivation The talk Keep Calm and Type Erase On by Gwendolyn Westo

Kazunobu Tasaka 110 Feb 6, 2022
Why not use UserDefaults to store Codable objects 😉

tl;dr You love Swift's Codable protocol and use it everywhere, who doesn't! Here is an easy and very light way to store and retrieve -reasonable amoun

Omar Albeik 452 Oct 17, 2022
CoreDataCloudKitShare - Learn how to use Core Data CloudKit

Sharing Core Data Objects Between iCloud Users Implement the flow to share data

null 3 Feb 10, 2022
A fast, pure swift MongoDB driver based on Swift NIO built for Server Side Swift

A fast, pure swift MongoDB driver based on Swift NIO built for Server Side Swift. It features a great API and a battle-tested core. Supporting both MongoDB in server and embedded environments.

null 646 Dec 10, 2022
SQLite.swift - A type-safe, Swift-language layer over SQLite3.

SQLite.swift provides compile-time confidence in SQL statement syntax and intent.

Stephen Celis 8.7k Jan 3, 2023
🧡 SQLiteOrm-Swift is an ORM library for SQLite3 built with Swift 5

?? Easy to use SQLite ORM library written with Swift

Yevgeniy Zakharov 25 Oct 6, 2022
ObjectBox Swift - persisting your Swift objects superfast and simple

ObjectBox Swift ObjectBox is a superfast, light-weight object persistence framework. This Swift API seamlessly persists objects on-device for iOS and

ObjectBox 380 Dec 19, 2022
Shows the issue with swift using an ObjC class which has a property from a swift package.

SwiftObjCSwiftTest Shows the issue with swift using an ObjC class which has a property from a swift package. The Swift class (created as @objc derived

Scott Little 0 Nov 8, 2021
Ios-App-ication-Swift - A simple iOS application made in Xcode using Swift

?? iPhone Calculator A simple iOS application made in Xcode using Swift. This ap

Kushal Shingote 1 Feb 2, 2022
Save-the-dot-project-swift - Save the dot project with swift

Save the Dot Apple introduced UIViewPropertyAnimator for iOS 10. We can use this

Kushal Shingote 2 Feb 8, 2022
The Swift Package Index is the place to find Swift packages!

The Swift Package Index helps you make better decisions about the dependencies you use in your apps. The Swift Package Index is a search engine for pa

Swift Package Index 389 Dec 22, 2022
A stand-alone Swift wrapper around the mongo-c client library, enabling access to MongoDB servers.

This package is deprecated in favour of the official Mongo Swift Driver. We advise users to switch to that pack

PerfectlySoft Inc. 54 Jul 9, 2022
Elegant library to manage the interactions between view and model in Swift

An assistant to manage the interactions between view and model ModelAssistant is a mediator between the view and model. This framework is tailored to

Seyed Samad Gholamzadeh 28 Jan 29, 2022
CRUD is an object-relational mapping (ORM) system for Swift 4+.

CRUD is an object-relational mapping (ORM) system for Swift 4+. CRUD takes Swift 4 Codable types and maps them to SQL database tables. CRUD can create tables based on Codable types and perform inserts and updates of objects in those tables. CRUD can also perform selects and joins of tables, all in a type-safe manner.

PerfectlySoft Inc. 61 Nov 18, 2022
CoreXLSX is a Excel spreadsheet (XLSX) format parser written in pure Swift

CoreXLSX Excel spreadsheet (XLSX) format parser written in pure Swift CoreXLSX is a library focused on representing the low-level structure of the XML

null 684 Dec 21, 2022
Solutions to LeetCode by Swift

LeetCode by Swift LeetCode Online Judge is a website containing many algorithm questions. Most of them are real interview questions of Google, Faceboo

Soap 4.5k Jan 5, 2023
Super lightweight DB written in Swift.

Use of value types is recommended and we define standard values, simple structured data, application state and etc. as struct or enum. Pencil makes us store these values more easily.

Naruki Chigira 88 Oct 22, 2022
YapDB is a collection/key/value store with a plugin architecture. It's built atop sqlite, for Swift & objective-c developers.

YapDatabase is a collection/key/value store and so much more. It's built atop sqlite, for Swift & Objective-C developers, targeting macOS, iOS, tvOS &

Yap Studios 3.3k Dec 29, 2022
CoreData/Realm sweet wrapper written in Swift

What is SugarRecord? SugarRecord is a persistence wrapper designed to make working with persistence solutions like CoreData in a much easier way. Than

Modo 2.1k Dec 9, 2022