{"id":986,"url":"https://github.com/danthorpe/YapDatabaseExtensions","last_synced_at":"2025-07-30T20:30:41.494Z","repository":{"id":30445925,"uuid":"33999429","full_name":"danthorpe/YapDatabaseExtensions","owner":"danthorpe","description":"YapDatabase extensions for use with Swift","archived":false,"fork":false,"pushed_at":"2018-03-02T00:05:42.000Z","size":3473,"stargazers_count":89,"open_issues_count":9,"forks_count":15,"subscribers_count":7,"default_branch":"development","last_synced_at":"2025-07-30T12:41:27.199Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Swift","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/danthorpe.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2015-04-15T14:40:31.000Z","updated_at":"2024-05-18T09:44:00.000Z","dependencies_parsed_at":"2022-07-24T16:47:07.062Z","dependency_job_id":null,"html_url":"https://github.com/danthorpe/YapDatabaseExtensions","commit_stats":null,"previous_names":[],"tags_count":25,"template":false,"template_full_name":null,"purl":"pkg:github/danthorpe/YapDatabaseExtensions","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danthorpe%2FYapDatabaseExtensions","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danthorpe%2FYapDatabaseExtensions/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danthorpe%2FYapDatabaseExtensions/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danthorpe%2FYapDatabaseExtensions/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/danthorpe","download_url":"https://codeload.github.com/danthorpe/YapDatabaseExtensions/tar.gz/refs/heads/development","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/danthorpe%2FYapDatabaseExtensions/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":267935131,"owners_count":24168267,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","status":"online","status_checked_at":"2025-07-30T02:00:09.044Z","response_time":70,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-01-05T20:15:36.327Z","updated_at":"2025-07-30T20:30:41.159Z","avatar_url":"https://github.com/danthorpe.png","language":"Swift","funding_links":[],"categories":["Database"],"sub_categories":["Getting Started","Other free courses","Linter"],"readme":"![](https://raw.githubusercontent.com/danthorpe/YapDatabaseExtensions/development/header.png)\n\n[![Build status](https://badge.buildkite.com/95784c169af7db5e36cefe146d5d3f3899c8339d46096a6349.svg)](https://buildkite.com/danthorpe/yapdatabaseextensions?branch=development)\n[![Coverage Status](https://coveralls.io/repos/github/danthorpe/YapDatabaseExtensions/badge.svg?branch=development)](https://coveralls.io/github/danthorpe/YapDatabaseExtensions?branch=development)\n[![CocoaPods Compatible](https://img.shields.io/cocoapods/v/YapDatabaseExtensions.svg)](https://img.shields.io/cocoapods/v/YapDatabaseExtensions.svg)\n[![CocoaPods Documentation](https://img.shields.io/cocoapods/metrics/doc-percent/YapDatabaseExtensions.svg?style=flat)](https://cocoapods.org/pods/YapDatabaseExtensions)\n[![Platform](https://img.shields.io/cocoapods/p/YapDatabaseExtensions.svg?style=flat)](http://cocoadocs.org/docsets/YapDatabaseExtensions)\n[![Carthage compatible](https://img.shields.io/badge/Carthage-compatible-4BC51D.svg?style=flat)](https://github.com/Carthage/Carthage)\n\n# YapDatabaseExtensions\n\nRead my introductory blog post about [YapDatabase \u0026 YapDatabaseExtensions](http://danthorpe.me/posts/yap-database.html), and a follow up on [YapDatabaseExtensions 2](http://danthorpe.me/posts/yapdatabaseextensions-two--the-swiftening.html).\n\nYapDatabaseExtensions is a suite of convenience APIs for working with [YapDatabase](https://github.com/yapstudios/YapDatabase). If you’re not familiar with YapDatabase, it’s a powerful key value database for iOS and Mac - [check it out](https://github.com/yapstudios/YapDatabase)!\n\n## Motivation\nWhile 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.\n\n## Value Types\nThe support for encoding and decoding value types, previously the `Saveable` and `Archiver` protocols, has been renamed and moved to their own project. [ValueCoding](https://github.com/danthorpe/ValueCoding) is a dependency of this framework (along with YapDatabase itself). See its [README](https://github.com/danthorpe/ValueCoding/blob/development/README.md) 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.\n\n## `Persistable`\nThis 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`).\n\n```swift\npublic protocol Identifiable {\n    typealias IdentifierType: CustomStringConvertible\n    var identifier: IdentifierType { get }\n}\n\npublic protocol Persistable: Identifiable {\n    static var collection: String { get }\n    var metadata: MetadataType? { get set }\n}\n``` \n\nThe `identifier` property allows the type to support an identifier type such as `NSUUID` or `Int`.\n\nWhile 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.\n\nThere 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`.\n\n### Metadata\nYapDatabase supports storing metadata alongside the primary object. YapDatabaseExtensions supports automatic reading and writing of metadata as an optional property of the `Persistable` type.\n\nBy 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.\n\nTo support a custom metadata type, just add the following to your `Persistable` type, e.g.:\n\n```swift\nstruct MyCustomValue: Persistable, ValueCoding {\n    typealias Coder = MyCustomValueCoder\n    static let collection = “MyCustomValues”\n    var metadata: MyCustomMetadata? = .None\n    let identifier: NSUUID\n}\n```\n\nwhere the type (`MyCustomMetadata` in the above snippet) implements either `NSCoding` or `ValueCoding`.\n\nWhen 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.\n\nNote that previous metadata protocols `ObjectMetadataPersistable` and `ValueMetadataPersistable` have been deprecated in favor of `Persistable`.\n\n## “Correct” Type Patterns\nBecause 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.\n\nTherefore, there are six valid `Persistable` type patterns as described in the table below:\n\nItem encoding | Metadata encoding | Pattern\n--------------|-------------------|------------------\n`NSCoding`    | `Void` Metadata   | Object\n`NSCoding`    | `NSCoding`        | ObjectWithObjectMetadata\n`NSCoding`    | `ValueCoding`     | ObjectWithValueMetadata\n`ValueCoding` | `Void` Metadata   | Value\n`ValueCoding` | `NSCoding`        | ValueWithObjectMetadata\n`ValueCoding` | `ValueCoding`     | ValueWithValueMetadata\n\n## Extension APIs\n\nYapDatabaseExtensions 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.\n\n### Functional API\n\nThe following “functional” APIs are available directly on the `YapDatabase` types.\n\n```swift\n// Get a YapDatabaseConnection\nlet connection = db.newConnection()\n\n// Write a single item\nconnection.write(item) \n\n// Write an array of items, using one transaction.\nconnection.write(items)\n\n// Write asynchronously\nconnection.asyncWrite(item) { print(“did finish writing”) }\nconnection.asyncWrite(items) { print(“did finish writing”) }\n\n// Create a write transaction block for multiple writes.\nconnection.write { transaction in\n    transaction.write(item)\n    transaction.write(items) \n}\n\n// Write many items asynchronously\nconnection.asyncWrite({ transaction in\n    transaction.write(item)\n    transaction.write(items) \n}, completion: { print(“did finish writing”) })\n```\n\nFor reading:\n\n```swift\nif let item: Item? = connection.readAtIndex(index) {\n  // etc\n}\n\nif let meta: Item.MetadataType? = connection.readMetadataAtIndex(index) {\n  // etc\n}\n\nlet items: [Item] = connection.readAtIndexes(indexes)\n\nif let item: Item? = connection.readByKey(index) {\n  // etc\n}\n\nlet items: [Item] = connection.readByKeys(keys)\n\nlet all: [Item] = connection.readAll()\n\nconnection.read { transaction in\n    let a: Item? = transaction.readAtIndex(index)\n    let b: Item? = transaction.readByKey(key)\n    let c: [Item] = transaction.readAtIndexes(indexes)\n    let d: [Item] = transaction.readByKeys(keys)\n    let all: [Item] = transaction.readAll()\n    let meta: [Item.MetadataType] = transaction.readMetadataAtIndexes(indexes)\n}\n```\n\n### `Persistable` API\n\nThe APIs all work on single or sequences of `Persistable` items. To write to the database:\n\n```swift\n// Use a YapDatabaseReadWriteTransaction.\nlet written = item.write(transaction)\n\n// Write synchronously using a YapDatabaseConnection.\nlet written = item.write(connection)\n\n// Write asynchronously using a YapDatabaseConnection.\nitem.asyncWrite(connection) { written in\n    print(“did finishing writing”)\n}\n\n// Return an NSOperation which will perform an sync write on a YapDatabaseConnection.\nlet write: NSOperation = item.write(connection)\n``` \n\nReading items from the database is a little different.\n\n```swift\n// Read using a YapDB.Index.\nif let item = Item.read(transaction).byIndex(index) {\n   // etc - item is correct type, no casting required.\n}\n\n// Read an array of items from an array of YapDB.Index(s)\nlet items = Item.read(transaction).atIndexes(indexes)\n\n// Read using a key\nif let item = Item.read(transaction).byKey(key) {\n   // etc - item is correct type, no casting required.\n}\n\n// Read an array of items from an array of String(s)\nlet items = Item.read(transaction).byKeys(keys)\n\nif let allItems = Item.read(transaction).all() {\n   // etc - an array of Item types.\n}\n\n// Get the Items which exist for the given keys, and return the [String] keys which are missing.\nlet (items, missingKeys) = Item.read(transaction).filterExisting(someKeys)\n``` \n\nSimilarly, to work directly on a `YapDatabaseConnection`, use the following:\n\n```swift\nif let item = Item.read(connection).byIndex(index) {\n   // etc - item is correct type, no casting required.\n}\n\nif let item = Item.read(connection).byKey(key) {\n   // etc - item is correct type, no casting required.\n}\n\nif let allItems = Item.read(connection).all() {\n   // etc - an array of Item types.\n}\n\nlet (items, missingKeys) = Item.read(connection).filterExisting(someKeys)\n```\n\n## Installation\n\nYapDatabaseExtensions is available through [CocoaPods](http://cocoapods.org). To install\nit, simply add the following line to your Podfile:\n\n```ruby\npod 'YapDatabaseExtensions'\n```\n\nIf you don’t want the extensions API on `Persistable`, integrate the Functional subspec like this:\n\n```ruby\npod 'YapDatabaseExtensions/Functional’\n```\n\n## API Documentation\n\nAPI documentation is available on [CocoaDocs.org](http://cocoadocs.org/docsets/YapDatabaseExtensions).\n\n## Developing\n\nTo start working in this repository’s `YapDatabaseExtensions.xcodeproj`, you’ll need to use [Carthage](https://github.com/Carthage/Carthage#installing-carthage) to download \u0026 build the project’s dependencies, with the commands `carthage checkout` and `carthage build`.\n\n## Author\n\nDaniel Thorpe, [@danthorpe](https://twitter.com/danthorpe)\n\n## License\n\nYapDatabaseExtensions is available under the MIT license. See the LICENSE file for more info.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanthorpe%2FYapDatabaseExtensions","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdanthorpe%2FYapDatabaseExtensions","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdanthorpe%2FYapDatabaseExtensions/lists"}