DanBrooker / Data

Data Framework for Swift; Uses YapDatabase not CoreData

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Data.swift

Build Status Carthage compatible Cocoapods Compatible License Platform

Data.swift is a Swift (2.0) framework for working with data models.

Data.swift is built on the fantastic YapDatabase which is built on Sqlite3

Swift 1.2 can be found on branch swift1.2

It aims to have the following attributes:

  • Threadsafe
  • Typesafe
  • Tested
  • Protocols not Inheritance

Getting started

Cocoapods

platform :ios, '8.0'
use_frameworks!

pod 'Data', git: 'https://github.com/DanBrooker/Data'

Carthage

YapDatabase now has a framework, I just need to add it :D

Setup

Import Data module

import Data

Data.Model is simple protocol which requires a uid:String property and a means to archive and unarchive an object

class YourModel : Data.Model {
  let uid: String   // Required property

  init() {
    self.uid = "A UID OF YOUR CHOOSING"
  }

  // Required init
  required init(archive: Archive) {
    uid = archive["uid"] as! String
  }

  // Required archive property, [String: AnyObject]
  var archive : Archive {
      return ["uid": uid]
  }
}

struct YourStruct : Data.Model {
  let uid: String   // Required property

  init() {
    self.uid = "A UID OF YOUR CHOOSING"
  }

  // Required init
  init(archive: Archive) {
    uid = archive["uid"] as! String
  }

  // Required archive property, [String: AnyObject]
  var archive : Archive {
      return ["uid": uid]
  }
}

Basics

Created a data store

let store = YapStore()

Add

let model = YourModel()
store.append(model)

Find

let model: YourModel = store.find(modelsUID)

Filter

let models: [YourModel] =  store.filter({ $0.someProperty > 0 })

All

let models: [YourModel] =  store.all()

Count

let count =  store.count(YourModel.self)

Update

Update is important because your object is not being observed for changes and therefore once your done changing a object you will need to save it

store.update(model)

Delete

store.remove(model)

Delete all

store.truncate(YourModel.self)

Next step

Now that you've got the basics

Querying

public struct Query<T : Model> {
  let filter: ( (element: T) -> Bool )?
  let window: Range<Int>?
  let order: ( (a: T, b: T) -> Bool )?
}

A simple query for all YourModel objects

let query = Query<YourModel>()

A more complex query

Filter models based on enabled being true, limited to the first 20 elements and ordered by property

let query = Query<YourModel>(
    filter: { $0.enabled == true },
    window: 0..<20,
    order:  { $0.property > $1.property }
  )

Notifications

Options:

a) You can observe the following notifications for changes

  • "dataStoreAdded"

Not actually called yet, cannot distinguish between modified and added currently

  • "dataStoreModified"
  • "dataStoreRemoved"

b) And this is the best option use Collection<T> collections

Collections

Collection<T> is a drop in replacement for Array with the added benefit of being persistent and automatically updating when someone changes an object in the underlying data store

let query = Query<YourModel>()
let data: Collection<YourModel> = Data(query: query, store: store)

See querying above for more information about populating Collection<T> with a query

Tableview helpers

Collection<T> has a delegate DataDelegate and it generates some very useful callbacks for UITableViews

extension ViewController: DataDelegate {

    func beginUpdates() {
        tableView.beginUpdates()
    }

    func endUpdates() {
        tableView.endUpdates()
    }

    func objectAdded(indexPaths: [NSIndexPath]) {
        tableView.insertRowsAtIndexPaths(indexPaths, withRowAnimation: .Automatic)
    }

    func objectRemoved(indexPaths: [NSIndexPath]) {
        tableView.deleteRowsAtIndexPaths(indexPaths, withRowAnimation: .Automatic)
    }

    func objectUpdated(indexPaths: [NSIndexPath]) {
        tableView.reloadRowsAtIndexPaths(indexPaths, withRowAnimation: .Automatic)
    }

}

Key-Value Store

YapDatabase is actually a key-value store, or more correctly a hash of hashes.

You can therefore just store arbitrary key-values if you need to

// Set
store.setObjectForKey(object, forKey:"key")
// Get
let object : ObjectType = store.objectForKey("key")

Indexes - WIP

Basic indexes are working but the API is not solidified yet Aggregate index filtering not yet supported

Setup Indexes, once per model

struct TestModel: Data.Model {

  let text: String

  //.. init and archive functions removed for this example

  // function used to index properties
  func indexes() -> [Index] {
      return [
          Index(key: "text", value: text)
      ]
  }
}

let example = TestModel(uid: "doesn't matter")
store.index(example)

Indexable types String, Int Double, Float, Bool

Find

var unique: TestModel? = store.find("enabled", value: true)

Filter

var enabled: [TestModel] = store.filter("enabled", value: true)

Search

sqlite full text search. reference

You need to setup indexes to use search. Only searches TEXT columns

struct Tweet: Data.Model {

  let text: String
  let authorName: String

  //.. init and archive functions removed for this example

  // function used to index properties
  func indexes() -> [Index] {
      return [
          Index(key: "text", value: text),
          Index(key: "authorName", value: authorName)
      ]
  }
}

let example = Tweet(uid: "doesn't matter", text: "also doesn't matter", authorName: "anon")
store.index(example)

Search using various methods

var results : [Tweet] = store.search(string: "yapdatabase")                 // Basic Keyword Search
    results           = store.search(phrase: "yapdatabase is good")         // Exact Phrase
    results           = store.search(string: "authorName:draconisNZ")       // Only Search Property
    results           = store.search(string: "^yap")                        // Starts with
    results           = store.search(string: "yap*"                         // Wildcard
    results           = store.search(string: "'yapdatabase OR yapdatabse'") // OR
    results           = store.search(string: "'tweet NOT storm'")           // NOT
    results           = store.search(string: "'tweet NEAR/2 storm'")        // Keywords are within '2' tokens of each other

TODO

  • Transactions and mutiple model reads/writes

  • Secondary index aggregation i.e. OR and AND

  • iOS9 Core Spotlight

  • Query should use indexes

  • Relationships (Delete rules), Implicit and Explict

  • Search snippets and return results across models if required

  • Metadata helpers for things like caching table row height

  • Tableview sections with Collection<>, also CollectionView

  • Data syncing - CloudKit, Dropbox ...

License

Data.swift is released under an MIT license. See LICENSE for more information.

About

Data Framework for Swift; Uses YapDatabase not CoreData

License:MIT License


Languages

Language:Swift 97.5%Language:Ruby 1.5%Language:Objective-C 1.0%