Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 17 additions & 25 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@ public protocol Identifiable {

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

Expand All @@ -41,26 +40,11 @@ While not a requirement of YapDatabase, for these extensions, it is required tha
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.
YapDatabase supports storing metadata alongside the primary object. YapDatabaseExtensions supports optional reading and writing of metadata alongside a `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.
Your custom metadata types must conform to either `NSCoding` or `ValueCoding`.

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

```swift
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`.
In this version of YapDatabaseExtensions, metadata has been removed from `Persistable`, and all reads and writes of metadata must be done explicitly. Additionally, since the `MetadataType` is decoupled from the `Persistable` type, a single `Persistable` type can use many different types of metadata, as appropriate. When you want to read or write a value and it's metadata together, you use the "withMetadata" variants of the API, which accept and return `YapItem<Value, Metadata>` values. `YapItem` is basically a slightly nicer wrapper than a Swift tuple, which can be extended, unlike anonymous tuple types.

## “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.
Expand All @@ -69,10 +53,10 @@ Therefore, there are six valid `Persistable` type patterns as described in the t

Item encoding | Metadata encoding | Pattern
--------------|-------------------|------------------
`NSCoding` | `Void` Metadata | Object
`NSCoding` | No Metadata | Object
`NSCoding` | `NSCoding` | ObjectWithObjectMetadata
`NSCoding` | `ValueCoding` | ObjectWithValueMetadata
`ValueCoding` | `Void` Metadata | Value
`ValueCoding` | No Metadata | Value
`ValueCoding` | `NSCoding` | ValueWithObjectMetadata
`ValueCoding` | `ValueCoding` | ValueWithValueMetadata

Expand Down Expand Up @@ -118,7 +102,7 @@ if let item: Item? = connection.readAtIndex(index) {
// etc
}

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

Expand All @@ -138,7 +122,7 @@ connection.read { transaction in
let c: [Item] = transaction.readAtIndexes(indexes)
let d: [Item] = transaction.readByKeys(keys)
let all: [Item] = transaction.readAll()
let meta: [Item.MetadataType] = transaction.readMetadataAtIndexes(indexes)
let meta: [MetadataType] = transaction.readMetadataAtIndexes(indexes)
}
```

Expand Down Expand Up @@ -166,10 +150,17 @@ Reading items from the database is a little different.

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

// Read value and metadata using a YapDB.Index.
if let item: YapItem<Item, MetadataType>? = Item.read(transaction).withMetadataAtIndex(index) {
// etc - item is a correct type, no casting required.
// item.value contains the value
// item.metadata contains the metadata, wrapped in an Optional
}

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

Expand All @@ -192,7 +183,7 @@ let (items, missingKeys) = Item.read(transaction).filterExisting(someKeys)
Similarly, to work directly on a `YapDatabaseConnection`, use the following:

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

Expand Down Expand Up @@ -233,6 +224,7 @@ To start working in this repository’s `YapDatabaseExtensions.xcodeproj`, you
## Author

Daniel Thorpe, [@danthorpe](https://twitter.com/danthorpe)
Jim Roepcke, [@JimRoepcke](https://twitter.com/JimRoepcke)

## License

Expand Down
3 changes: 1 addition & 2 deletions Sources/Curried_ObjectWithNoMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import ValueCoding
// MARK: - Persistable

extension Persistable where
Self: NSCoding,
Self.MetadataType == Void {
Self: NSCoding {

/**
Returns a closure which, given a read transaction will return
Expand Down
46 changes: 26 additions & 20 deletions Sources/Curried_ObjectWithObjectMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,7 @@ import ValueCoding
// MARK: - Persistable

extension Persistable where
Self: NSCoding,
Self.MetadataType: NSCoding {
Self: NSCoding {

/**
Returns a closure which, given a read transaction will return
Expand All @@ -22,10 +21,11 @@ extension Persistable where
- parameter index: a YapDB.Index
- returns: a (ReadTransaction) -> Self? closure.
*/
public static func readAtIndex<
ReadTransaction where
ReadTransaction: ReadTransactionType>(index: YapDB.Index) -> ReadTransaction -> Self? {
return { $0.readAtIndex(index) }
public static func readWithMetadataAtIndex<
ReadTransaction, Metadata where
ReadTransaction: ReadTransactionType,
Metadata: NSCoding>(index: YapDB.Index) -> ReadTransaction -> YapItem<Self, Metadata>? {
return { $0.readWithMetadataAtIndex(index) }
}

/**
Expand All @@ -35,12 +35,13 @@ extension Persistable where
- parameter indexes: a SequenceType of YapDB.Index values
- returns: a (ReadTransaction) -> [Self] closure.
*/
public static func readAtIndexes<
Indexes, ReadTransaction where
public static func readWithMetadataAtIndexes<
Indexes, ReadTransaction, Metadata where
Indexes: SequenceType,
Indexes.Generator.Element == YapDB.Index,
ReadTransaction: ReadTransactionType>(indexes: Indexes) -> ReadTransaction -> [Self] {
return { $0.readAtIndexes(indexes) }
ReadTransaction: ReadTransactionType,
Metadata: NSCoding>(indexes: Indexes) -> ReadTransaction -> [YapItem<Self, Metadata>] {
return { $0.readWithMetadataAtIndexes(indexes) }
}

/**
Expand All @@ -50,10 +51,11 @@ extension Persistable where
- parameter key: a String
- returns: a (ReadTransaction) -> Self? closure.
*/
public static func readByKey<
ReadTransaction where
ReadTransaction: ReadTransactionType>(key: String) -> ReadTransaction -> Self? {
return { $0.readByKey(key) }
public static func readWithMetadataByKey<
ReadTransaction, Metadata where
ReadTransaction: ReadTransactionType,
Metadata: NSCoding>(key: String) -> ReadTransaction -> YapItem<Self, Metadata>? {
return { $0.readWithMetadataByKey(key) }
}

/**
Expand All @@ -63,12 +65,13 @@ extension Persistable where
- parameter keys: a SequenceType of String values
- returns: a (ReadTransaction) -> [Self] closure.
*/
public static func readByKeys<
Keys, ReadTransaction where
public static func readWithMetadataByKeys<
Keys, ReadTransaction, Metadata where
Keys: SequenceType,
Keys.Generator.Element == String,
ReadTransaction: ReadTransactionType>(keys: Keys) -> ReadTransaction -> [Self] {
return { $0.readAtIndexes(Self.indexesWithKeys(keys)) }
ReadTransaction: ReadTransactionType,
Metadata: NSCoding>(keys: Keys) -> ReadTransaction -> [YapItem<Self, Metadata>] {
return { $0.readWithMetadataAtIndexes(Self.indexesWithKeys(keys)) }
}

/**
Expand All @@ -78,7 +81,10 @@ extension Persistable where
- warning: Be aware that this will capure `self`.
- returns: a (WriteTransaction) -> Self closure
*/
public func write<WriteTransaction: WriteTransactionType>() -> WriteTransaction -> Self {
return { $0.write(self) }
public func writeWithMetadata<
WriteTransaction, Metadata where
WriteTransaction: WriteTransactionType,
Metadata: NSCoding>(metadata: Metadata? = nil) -> WriteTransaction -> YapItem<Self, Metadata> {
return { $0.writeWithMetadata(YapItem(self, metadata)) }
}
}
58 changes: 36 additions & 22 deletions Sources/Curried_ObjectWithValueMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,7 @@ import ValueCoding
// MARK: - Persistable

extension Persistable where
Self: NSCoding,
Self.MetadataType: ValueCoding,
Self.MetadataType.Coder: NSCoding,
Self.MetadataType.Coder.ValueType == Self.MetadataType {
Self: NSCoding {

/**
Returns a closure which, given a read transaction will return
Expand All @@ -24,10 +21,13 @@ extension Persistable where
- parameter index: a YapDB.Index
- returns: a (ReadTransaction) -> Self? closure.
*/
public static func readAtIndex<
ReadTransaction where
ReadTransaction: ReadTransactionType>(index: YapDB.Index) -> ReadTransaction -> Self? {
return { $0.readAtIndex(index) }
public static func readWithMetadataAtIndex<
ReadTransaction, Metadata where
ReadTransaction: ReadTransactionType,
Metadata: ValueCoding,
Metadata.Coder: NSCoding,
Metadata.Coder.ValueType == Metadata>(index: YapDB.Index) -> ReadTransaction -> YapItem<Self, Metadata>? {
return { $0.readWithMetadataAtIndex(index) }
}

/**
Expand All @@ -37,12 +37,15 @@ extension Persistable where
- parameter indexes: a SequenceType of YapDB.Index values
- returns: a (ReadTransaction) -> [Self] closure.
*/
public static func readAtIndexes<
Indexes, ReadTransaction where
public static func readWithMetadataAtIndexes<
Indexes, ReadTransaction, Metadata where
Indexes: SequenceType,
Indexes.Generator.Element == YapDB.Index,
ReadTransaction: ReadTransactionType>(indexes: Indexes) -> ReadTransaction -> [Self] {
return { $0.readAtIndexes(indexes) }
ReadTransaction: ReadTransactionType,
Metadata: ValueCoding,
Metadata.Coder: NSCoding,
Metadata.Coder.ValueType == Metadata>(indexes: Indexes) -> ReadTransaction -> [YapItem<Self, Metadata>] {
return { $0.readWithMetadataAtIndexes(indexes) }
}

/**
Expand All @@ -52,10 +55,13 @@ extension Persistable where
- parameter key: a String
- returns: a (ReadTransaction) -> Self? closure.
*/
public static func readByKey<
ReadTransaction where
ReadTransaction: ReadTransactionType>(key: String) -> ReadTransaction -> Self? {
return { $0.readByKey(key) }
public static func readWithMetadataByKey<
ReadTransaction, Metadata where
ReadTransaction: ReadTransactionType,
Metadata: ValueCoding,
Metadata.Coder: NSCoding,
Metadata.Coder.ValueType == Metadata>(key: String) -> ReadTransaction -> YapItem<Self, Metadata>? {
return { $0.readWithMetadataByKey(key) }
}

/**
Expand All @@ -65,12 +71,15 @@ extension Persistable where
- parameter keys: a SequenceType of String values
- returns: a (ReadTransaction) -> [Self] closure.
*/
public static func readByKeys<
Keys, ReadTransaction where
public static func readWithMetadataByKeys<
Keys, ReadTransaction, Metadata where
Keys: SequenceType,
Keys.Generator.Element == String,
ReadTransaction: ReadTransactionType>(keys: Keys) -> ReadTransaction -> [Self] {
return { $0.readAtIndexes(Self.indexesWithKeys(keys)) }
ReadTransaction: ReadTransactionType,
Metadata: ValueCoding,
Metadata.Coder: NSCoding,
Metadata.Coder.ValueType == Metadata>(keys: Keys) -> ReadTransaction -> [YapItem<Self, Metadata>] {
return { $0.readWithMetadataAtIndexes(Self.indexesWithKeys(keys)) }
}

/**
Expand All @@ -80,7 +89,12 @@ extension Persistable where
- warning: Be aware that this will capure `self`.
- returns: a (WriteTransaction) -> Self closure
*/
public func write<WriteTransaction: WriteTransactionType>() -> WriteTransaction -> Self {
return { $0.write(self) }
public func writeWithMetadata<
WriteTransaction, Metadata where
WriteTransaction: WriteTransactionType,
Metadata: ValueCoding,
Metadata.Coder: NSCoding,
Metadata.Coder.ValueType == Metadata>(metadata: Metadata? = nil) -> WriteTransaction -> YapItem<Self, Metadata> {
return { $0.writeWithMetadata(YapItem(self, metadata)) }
}
}
3 changes: 1 addition & 2 deletions Sources/Curried_ValueWithNoMetadata.swift
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,7 @@ import ValueCoding
extension Persistable where
Self: ValueCoding,
Self.Coder: NSCoding,
Self.Coder.ValueType == Self,
Self.MetadataType == Void {
Self.Coder.ValueType == Self {

/**
Returns a closure which, given a read transaction will return
Expand Down
Loading