Giter Club home page Giter Club logo

couchbase-lite-swift-coder's Introduction

CouchbaseLiteSwiftCoder

License

An experiment using Swift's Encoder/Decoder to develop data model for Couchbase Lite Swift.

Requirements

  • CouchbaseLiteSwift 2.8+

Platforms

  • iOS (9.0+) and macOS (10.11+)
  • XCode 12+

Supported Data Types

  • String
  • Numbers
  • Boolean
  • Date
  • Data
  • Blob
  • CBLCodable (CBLEncodable and CBLDecodable)
  • Array of the types above

Future Features

  • Support More Data Types
  • Support Document Relationship

Installation

Swift Package Manager

dependencies: [
    .package(url: "https://github.com/couchbaselabs/couchbase-lite-swift-coder.git")
]

Usage

Import Modules

import CouchbaseLiteSwift
import CouchbaseLiteSwiftCoder

There are two ways of using CouchbaseLiteSwiftCoder.

#1: Use CBLEncoder and CBLDecoder

CouchbaseLiteSwiftCoder provides CBLEncoder and CBLDecoder class for encoding model objects to Couchbase Lite's MutableDocument objects that can be used to save into the database and for encoding model objects from Couchbase Lite's Document objects respectively.

When definding the model struct or class, there are three protocols that can be used: CBLEncodable for encoding only, CBLDecodable or decoding only, and CBLCodable for both encoding and decoding.

Example

// Define Student model:
struct Student: CBLCodable {
    var name: String
    var grade: Int
}

// Encode a model object to a MutableDocument:
let student1 = Student(name: "James", grade: 1)
let encoder = CBLEncoder()
let doc1 = try encoder.encode(student1)

// Decode a model object from a Document object:
let doc2 = try self.db.document(withID: "student2")
let decoder = CBLDecoder()
let student2 = try decoder.decode(Person.self, from: doc2) 

When using the CBLEncoder or CBLDecoder, after the model object is encoded or decoded, the model object is independent from its companion MutableDocument or Document object. Application code takes responsibility to manage the relationship between the model and the document object.

#2: Use DocumentCodable

As we would want to associate the model object and its document object from which the model object is deocded so that the model object will have the right version of the document to be encoded into when saving the model object into the database. A better way to define the model struct or class is to implement DocumentCodable protocol (there is also DocumentEncodable and DocumentDecoable protocol only for encoding and decoding respectively).

When implementing DocumentCodable, an additional document property of MutableDocument type is required. It's important to note that the document property is not a part of the properties to be encoded or decoded. In order to ignore the document property from being encoded and decoded, the CodingKeys enum needs to be defined to list all of the encoding/decoding keys.

In additon to the DocumentCodable protocol, a set of extensions method to Couchbase Lite's Database and Document API has been defined to allow the model objects to be easily retrived from the database or saved into the database.

Example

Defining Model

struct Employee: DocumentCodable {
    // Required
    var document: MutableDocument!
    
    // Model Properties
    var name: String
    var dob: Date?
    var address: Address?
    var contacts: [Person]?
	
    // Required Coding Keys for ignoring document property
    enum CodingKeys: String, CodingKey {
        case name
        case dob
        case address
        case contacts
    }
    
    // Constructor
    // Note: The id parameter is for specifying a document id
    init(id: String? = nil, name: String) {
        self.document = MutableDocument(id: id)
        self.name = name
    }
}

struct Person: CBLCodable {
    var name: String
    var phone: String
}

struct Address: CBLCodable {
    let street: String
}

Note: Only the top level is required to implement DocumentCodable protocol; the nested model can just implement CBLCodable protocol.

Save model object into database

// Create an employee object
var employee = Employee(name: "Jimmy")
employee.dob = dob
employee.address = Address(street: "1 Main Street")
employee.contacts = [Person(name: "Jackson", phone: "650-123-4567")]

// Save 
try employee.save(into: self.db)

Get model object from database

let employee = try self.db.document(withID: "emp1", as: Employee.self)

Query Results Decoding

In addition to encoding and decoding document API, two extensions to decode the model object from the query's result or to decode an array of model objects from the query's result set are defined.

Example

// Query
let results = try QueryBuilder
	.select(
		SelectResult.property("name"),
		SelectResult.property("address"),
		SelectResult.property("dob"),
		SelectResult.property("contacts"),
		SelectResult.property("photo"))
	.from(DataSource.database(self.db))
	.execute()

// Decode
let employees = try results.decode(Employee.self)

API

Encoder and Decoder API

CBLEncoder

func encode<T: CBLEncodable>(_ value: T) throws -> MutableDocument

func encode<T: CBLEncodable>(_ value: T, for documentID: String) throws -> MutableDocument

func encode<T: CBLEncodable>(_ value: T, into document: MutableDocument) throws -> MutableDocument

CBLDecoder

func decode<T: CBLDecodable>(_ type: T.Type, from document: Document) throws -> T

func decode<T: CBLDecodable>(_ type: T.Type, from result: Result) throws -> T

CBLCodable

public protocol CBLEncodable: Encodable { }

protocol CBLDecodable: Decodable { }

typealias CBLCodable = CBLEncodable & CBLDecodable

DocumentDecodable API

DocumentDecodable

public protocol DocumentฺEncodable: CBLEncodable {
    var document: MutableDocument! { get set }
}

public protocol DocumentDecodable: CBLDecodable {
    mutating func decoded(for document: Document)
}

public protocol DocumentCodable: DocumentฺEncodable, DocumentDecodable { }

DocumentCodable Extension

mutating func save(into database: Database) throws

Couchbase Lite API Extension

Database

func document<T: DocumentDecodable>(withID id: String, as type: T.Type) throws -> T?

func saveDocument<T: DocumentฺEncodable>(_ encodable: T) throws

Document

func decode<T: DocumentDecodable>(as type: T.Type) throws -> T

Result

func decode<T: CBLDecodable>(as type: T.Type) throws -> T

ResultSet

func decode<T: CBLDecodable>(as type: T.Type) throws -> [T]

couchbase-lite-swift-coder's People

Contributors

danieltarazona avatar marcblanchet avatar pasin avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

couchbase-lite-swift-coder's Issues

decoding null values not working

decoding a null value fails.
browsing the code seems to show that all decodeNil() implementations return false all the time.
func decodeNil(forKey key: Key) throws -> Bool {
return false
}

Object decoded from query unable to resave into database

I've run into an issue where if I query the database and decode the results my objects have all their data and behave as expected. If I then change a variable and try object.save(into: db) it fails. If instead I get the object with the db.document(withID: as: object.self) method the object can be saved no issues. Maybe this is expected? Or is it expected to be able to modify objects collected from queries?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.