Code Monkey home page Code Monkey logo

salada's Introduction

Version Platform Downloads

Salada 🍐

Salad is a Model for Firebase database. It can handle Snapshot of Firebase easily.

Make a Model with Salada

  • You no longer need to create a server.
  • You no longer need to make a mock.
  • It operates in real time.
  • You can create a reactive UI.

Requirements ❗️

Installation ⚙

  • Insert pod 'Salada' to your Podfile.
  • Run pod install.

Usage 👀

Model

Model of the definition is very simple. To inherit the Object.

class User: Object {

    dynamic var name: String?
    dynamic var age: Int = 0
    dynamic var gender: String?
    dynamic var groups: Set<String> = []
    dynamic var items: [String] = []
    dynamic var url: URL?
    dynamic var birth: Date?
    dynamic var thumbnail: File?
    dynamic var followers: Relation<User> = []
}

When you want to create a property that you want to ignore.

// Group
class Group: Object {
    dynamic var name: String?
    dynamic var users: Set<String> = []
}

Property

Property are four that can be specified in Salada.

Property Description
String Simple string.
Number(Int, UInt, Double ...) Simple number.
URL URL
Date date
Array<String> Array of strings.
Set <String> Array of strings. Set is used in relationships.
Reation<Object> Reference
[String: Any] Object
AnyObject Use encode, decode function.

⚠️ Bool, Int, Float, and Double are not supported optional types.

Save and Update

Do not forget to change the database rules.

{
  "rules": {
    ".read": true,
    ".write": true
  }
}
// This rule is dangerous. Please change the rules according to the model

https://firebase.google.com/docs/database/security/

The new model is stored in the save() or save(completion: ((NSError?, FIRDatabaseReference) -> Void)?). It is updated automatically when you change the property Model that has already been saved.

let group: Group = Group()
group.name = "iOS Development Team"
group.save { (error, ref) in

    do {
        let user: User = User()
        user.name = "john appleseed"
        user.gender = "man"
        user.age = 22
        user.items = ["Book", "Pen"]
        user.groups.insert(ref.key)
        user.save({ (error, ref) in
            group.users.insert(ref.key) // It is updated automatically
        })
    }

    do {
        let user: User = User()
        user.name = "Marilyn Monroe"
        user.gender = "woman"
        user.age = 34
        user.items = ["Rip"]
        user.groups.insert(ref.key)
        user.save({ (error, ref) in
            group.users.insert(ref.key) // It is updated automatically
        })
    }

}

Retrieving Data

  • observeSingle(eventType: FIRDataEventType, block: ([Tsp]) -> Void)
  • observeSingle(id: String, eventType: FIRDataEventType, block: (Tsp) -> Void)
User.observeSingle(FIRDataEventType.Value) { (users) in
    users.forEach({ (user) in
        // do samething
        if let groupId: String = user.groups.first {
            Group.observeSingle(groupId, eventType: .Value, block: { (group) in
                // do samething
            })
        }
    })
}

Remove Data

if let groupId: String = user.groups.first {
    Group.observeSingle(groupId, eventType: .Value, block: { (group) in
        group.remove()
    })
}

Custom Property

class User: Salada.Object {

    override class var _version: String {
        return "v1"
    }

    dynamic var name: String?
    dynamic var age: Int = 0
    dynamic var gender: String?
    dynamic var groups: Set<String> = []
    dynamic var items: [String] = []
    dynamic var location: CLLocation?
    dynamic var url: URL?
    dynamic var birth: Date?
    dynamic var thumbnail: File?
    dynamic var cover: File?
    dynamic var type: UserType = .first

    var tempName: String?

    override var ignore: [String] {
        return ["tempName"]
    }

    override func encode(_ key: String, value: Any?) -> Any? {
        if key == "location" {
            if let location = self.location {
                return ["latitude": location.coordinate.latitude, "longitude": location.coordinate.longitude]
            }
        } else if key == "type" {
            return self.type.rawValue as AnyObject?
        }
        return nil
    }

    override func decode(_ key: String, value: Any?) -> Any? {
        if key == "location" {
            if let location: [String: Double] = value as? [String: Double] {
                self.location = CLLocation(latitude: location["latitude"]!, longitude: location["longitude"]!)
                return self.location
            }
        } else if key == "type" {
            if let type: Int = value as? Int {
                self.type = UserType(rawValue: type)!
                return self.type
            }
        }
        return nil
    }
}

Upload file

You can easily save the file if you use the File. File saves the File in FirebaseStorage.

Do not forget to change the storage rules.

let user: User = User()
let image: UIImage = UIImage(named: "Salada")!
let data: NSData = UIImagePNGRepresentation(image)!
let thumbnail: File = File(data: data, mimeType: .jpeg)
user.thumbnail = thumbnail
user.save({ (error, ref) in
    // do something
})
let image: UIImage = #imageLiteral(resourceName: "salada")
let data: Data = UIImageJPEGRepresentation(image, 1)!
let file: File = File(data: data, mimeType: .jpeg)
item.file = file
let task: FIRStorageUploadTask = item.file?.save(completion: { (metadata, error) in
    if let error = error {
        print(error)
        return
    }
})

Download file

Download of File is also available through the File.

guard let user: User = self.datasource?.objectAtIndex(indexPath.item) else { return }
user.thumbnail?.dataWithMaxSize(1 * 2000 * 2000, completion: { (data, error) in
    if let error: NSError = error {
        print(error)
        return
    }
    cell.imageView?.image = UIImage(data: data!)
    cell.setNeedsLayout()
})

FirebaseUI makes it even easier to access.

# Only pull in FirebaseUI Storage features
pod 'FirebaseUI/Storage', '~> 3.0'
User.observeSingle(friend, eventType: .value, block: { (user) in
    if let user: User = user as? User {
        if let ref: FIRStorageReference = user.thumbnail?.ref {
            cell.imageView.sd_setImage(with: ref, placeholderImage: #imageLiteral(resourceName: "account_placeholder"))
        }
    }
 })

Relationship

Please use Relation to create a relationship between models. It can be defined by inheriting Relation class.

class Follower: Relation<User> {
    override class var _name: String {
        return "follower"
    }
}
class User: Object {
    let followers: Follower = []
}

Data Source

See SaladBar.

For example

// ViewController Sample

var dataSource: DataSource<User>?

override func viewDidLoad() {
    super.viewDidLoad()
    
    let options: Options = Options()
    options.limit = 10
    options.sortDescirptors = [NSSortDescriptor(key: "age", ascending: false)]
    self.dataSource = DataSource(reference: User.databaseRef, options: options, block: { [weak self](changes) in
        guard let tableView: UITableView = self?.tableView else { return }
        
        switch changes {
        case .initial:
            tableView.reloadData()
        case .update(let deletions, let insertions, let modifications):
            tableView.beginUpdates()
            tableView.insertRows(at: insertions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
            tableView.deleteRows(at: deletions.map { IndexPath(row: $0, section: 0) }, with: .automatic)
            tableView.reloadRows(at: modifications.map { IndexPath(row: $0, section: 0) }, with: .automatic)
            tableView.endUpdates()
        case .error(let error):
            print(error)
        }
    })
}
// TableViewDatasource
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    return self.dataSource?.count ?? 0
}

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
    let cell: TableViewCell = tableView.dequeueReusableCell(withIdentifier: "TableViewCell", for: indexPath) as! TableViewCell
    configure(cell, atIndexPath: indexPath)
    return cell
}

func configure(_ cell: TableViewCell, atIndexPath indexPath: IndexPath) {
    cell.disposer = self.dataSource?.observeObject(at: indexPath.item, block: { (user) in
        cell.imageView?.contentMode = .scaleAspectFill
        cell.textLabel?.text = user?.name
    })
}

private func tableView(_ tableView: UITableView, didEndDisplaying cell: TableViewCell, forRowAt indexPath: IndexPath) {
    cell.disposer?.dispose()
}

func tableView(_ tableView: UITableView, canPerformAction action: Selector, forRowAt indexPath: IndexPath, withSender sender: Any?) -> Bool {
    return true
}

func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
    if editingStyle == .delete {
        self.dataSource?.removeObject(at: indexPath.item, cascade: true, block: { (key, error) in
            if let error: Error = error {
                print(error)
            }
        })
    }
}

Observe

You can receive data changes through observation.
And easy to manage observation using Disposer.

class ViewController: UIViewController {
    private var disposer: Disposer<User>?

    override func viewDidLoad() {
        super.viewDidLoad()
        disposer = User.observe(userID, eventType: .value) { user in
             //...
        }
    }

    deinit {
        // ... auto remove observe internal disposer when it deinitialized.
        // or manually and clearly dispose
        // disposer?.dispose()
    }
}

Salada has Disposer, AnyDisposer and NoDisposer.
See details: Disposer.swift

Reference

  • Salada Firebase model framework.
  • Tong Tong is library for using ElasticSearch with Swift.
  • dressing Dressing provides the functionality of CloudFunctions to connect Firebase and ElasticSearch.

Contributing

We welcome any contributions. See the CONTRIBUTING file for how to get involved.

Saladaは日本製です。日本人のコントリビューター大歓迎🎉

salada's People

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  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

salada's Issues

Carthage Support

Hi! Nice OSS!

I want to install by Carthage, do you have any plan to support?

Thanks.

Pod Request

Hey,

This is a great tool. Very well done. We need to make it a pod to update it automatically. What do you say?

Thank you,

Value of type 'StorageMetadata' has no member 'downloadURL'

In File.swift l.130 return self.metadata?.downloadURL() , the above error has occurred.

   /// DownloadURL
    public var downloadURL: URL? {
        if let url: URL = self._downloadURL {
            return url
        }
        return self.metadata?.downloadURL()
    }

What should I change this code?

Swift4.2 typealias Error in DataSource

Salada+DataSource.swift

line 329

extension Datasource: Collection {
    
    typealias Element = String // Error
    public typealias Element = String // OK
    
    public var startIndex: Int {
        return 0
    }
    ....
}

How to update data?

Hello!
First of all thanks for framework.

In your readme you wrote how to manage data, except the updating, only adding... When I'm trying to pass the tutorial, the fatal error shown -> I tried to save the data AGAIN..
I have one user and one project. User is already in DB, but project will be only created in future. I'm adding the Project, adding user to Project, but when I trying to add a project to user, it warns me in fatal manner, cause the user is already saved.. Of course it's saved :D

let project = Project()
        project.title = "New Project"
        let colors = GradientColors().getRandomGradient()
        project.color1 = colors.0
        project.color2 = colors.1
        project.icon = "heart"
        project.save { (_, _) in
            do {
                Auth.User.current({ (user) in
                    project.users?.insert(user!)
                    user?.projects?.insert(project)
                    user?.save({ (ref, error) in
                        
                    })
                })
            }
        }

fatalError("[Salada.Object] *** error: (type(of: self)) has already been saved.")

Why is image file not saving in Firebase Storage ?

So basically, I try to save a picture into my storage, then save the picture name/url into database.

        let postObject = PostModel()
        postObject.title = title
        postObject.imageTitle = returningImageData(image: imageTitle)
        postObject.content = content
        postObject.save { (ref, error) in
            if error != nil {
                print(error?.localizedDescription)
            }
        }

and I got the name and save into the database working successfully. But when I try to download the file, it won't recognize the file name.

let imageURL = storageRef.child("1489699076238")
        imageURL.downloadURL { (url, error) in
            if error != nil {
                print(error?.localizedDescription)
            } else {
                print("\n\n\nURL: \(url!)")
            }
        }

encode is not called when updating.

this is the example.

// object
class Item: Object {
    @objc dynamic var location:CLLocation!
    
    override func encode(_ key: String, value: Any?) -> Any? {
        if(key == "location"){
            return ["latitude": location.coordinate.latitude, "longitude": location.coordinate.longitude]
       }
        return nil
    }
} 
   // called encode.
    let i = Item()
    i.location = CLLocation(latitude: 0, longitude: 0)
    i.save()  // called encode.
    
   // update
    Item.observeSingle(.value) { (items) in
            items.forEach({ (item) in
                // error. not called encode.
                item.location = CLLocation(latitude: 123, longitude: 123)
            })
        }

this is error messaage.

'InvalidFirebaseData', reason: '(updateChildValues:withCompletionBlock:) Cannot store object of type CLLocation at . Can only store objects of type NSNumber, NSString, NSDictionary, and NSArray.'

I want encode to be called when updating.

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.