SkillAgentSearch skills...

Pring

Cloud Firestore model framework for iOS - Google

Install / Use

/learn @1amageek/Pring
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

⚠️ Pring is deprecated <br>

Please use 🧢 Ballcap 🧢<br>

Ballcap is new Cloud Firestore framework


<div style="text-align: center; width: 100%"> <img src="https://github.com/1amageek/Pring/blob/master/Pring.png" width="100%">

Version Platform Downloads

</div>

Please donate to continue development.

<img src="https://github.com/1amageek/pls_donate/blob/master/kyash.jpg" width="180">

https://github.com/1amageek/pring.ts

Pring <β>

Firestore model framework. The concept of Document and Collection has been added to Firestore. Pring defines the Scheme of the Document and enables type - safe programming. SubCollection can also be defined in Scheme.

Deep Dive into the Firebase

Please report issues here

Requirements ❗️

Installation ⚙

CocoaPods

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

Feature 🎊

☑️ You can define Firestore's Document scheme.<br> ☑️ Of course type safety.<br> ☑️ It seamlessly works with Firestore and Storage.<br> ☑️ You can easily associate subcollections.<br> ☑️ Support GeoPoint.<br>

Design 💻

Firestore Database Design

If you are going to use Firestore and make products, I recommend you to read it.

TODO ✅

Implementation

  • [x] Implement DataType that Firestore can handle
  • [x] Implement data management
  • [x] Implement custom DataType (Specification under consideration)
  • [x] Implement linkage with Firestorage
  • [x] Implement the NestedCollection feature
  • [x] Implement the ReferenceCollection feature
  • [x] Implement DataSource
  • [x] Implement Query-enabled DataSource (Specification under consideration)

Verification (Running Unit test)

  • [x] Verify the implementation of DataType that Firestore can handle
  • [x] Verify the implementation of data management
  • [x] Verify the implementation of custom DataType
  • [x] Verify cooperation with Firestorage
  • [x] Verify the implementation of the NestedCollection feature
  • [x] Verify the implementation of the ReferenceCollection feature
  • [x] Verify the implementation of Query-enabled DataSource

If you have a Feature Request, please post an issue.

Usage

For example..

@objcMembers
class User: Object {
    @objc enum UserType: Int {
        case normal
        case gold
        case premium        
    }
    dynamic var type: UserType = .normal
    dynamic var name: String?
    dynamic var thumbnail: File?
    dynamic var followers: ReferenceCollection<User> = []
    dynamic var items: NestedCollection<Item> = []
    
    // Custom property
    override func encode(_ key: String, value: Any?) -> Any? {
        if key == "type" {
            return self.type.rawValue
        }
        return nil
    }

    override func decode(_ key: String, value: Any?) -> Bool {
        if key == "type" {
            self.type = UserType(rawValue: value as! Int)
            return true
        }
        return false
    }
}
@objcMembers
class Item: Object {
    dynamic var thumbnail: File?
    dynamic var name: String? = "OWABIISHI"
}
// Set an arbitrary ID
let user: User = User(id: "ID")
user.save()
let userA: User = User()
userA.name = "userA"
userA.thumbnail = File(data: UIImageJPEGRepresentation(IMAGE, 0.3)!, mimeType: .jpeg)

let userB: User = User()
userB.name = "userB"
userB.thumbnail = File(data: UIImageJPEGRepresentation(IMAGE, 0.3)!, mimeType: .jpeg)

let item: Item = Item()
item.thumbnail = File(data: UIImageJPEGRepresentation(IMAGE, 0.3)!, mimeType: .jpeg)

userA.followers.insert(userB)
userA.items.insert(item)
userA.save()

Important❗️

Pring clearly separates save and update. This is to prevent unexpected overwriting. Pring provides three methods of initializing Object.

Initialization giving AutoID to Object

let user: User = User()

Initialization giving arbitrary ID

let user: User = User(id: "YOUR_ID") // isSaved false

Initialization when dealing with already saved Object

If you are dealing with an Object that has already been saved, please perform the following initialization. In case of this initialization can not save Please update.

let user: User = User(id: "YOUR_ID", value: [:]) // isSaved true

It is the developer's responsibility to manage the saved state of the Object.

Scheme

Pring inherits Object class and defines the Model. Pring supports many data types.

@objcMembers
class User: Object {
    dynamic var array: [String]                     = ["array"]
    dynamic var set: Set<String>                    = ["set"]
    dynamic var bool: Bool                          = true
    dynamic var binary: Data                        = "data".data(using: .utf8)!
    dynamic var file: File                          = File(data: UIImageJPEGRepresentation(UIImage(named: "")!, 1))
    dynamic var url: URL                            = URL(string: "https://firebase.google.com/")!
    dynamic var int: Int                            = Int.max
    dynamic var float: Double                       = Double.infinity
    dynamic var date: Date                          = Date(timeIntervalSince1970: 100)
    dynamic var geoPoint: GeoPoint                  = GeoPoint(latitude: 0, longitude: 0)
    dynamic var list: List<Group>                   = []    
    dynamic var dictionary: [String: Any]           = ["key": "value"]    
    dynamic var string: String                      = "string"
    
    let group: Reference<Group>                         = .init()
    let nestedCollection: NestedCollection<Item>             = []
    let referenceCollection: ReferenceCollection<User>  = []
}

| DataType | Description | |---|---| |Array|It is Array type.| |Set|It is Set type.In Firestore it is expressed as {"value": true}.| |Bool|It is a boolean value.| |File|It is File type. You can save large data files.| |URL|It is URL type. It is saved as string in Firestore.| |Int|It is Int type.| |Float|It is Float type. In iOS, it will be a 64 bit Double type.| |Date|It is Date type.| |GeoPoint|It is GeoPoint type.| |List|It is Object array type.| |Dictionary|It is a Dictionary type. Save the structural data.| |nestedCollection or referenceCollection|It is SubCollection type.| |String|It is String type.| |Reference|It is Reference type. It hold DocumentReference| |Null|It is Null type.| |Any|It is custom type. You can specify it as a custom type if it is a class that inherits from NSObject.|

⚠️ Bool Int Float Double are not supported optional type.

⚙️ Manage data

Save

Document can be saved only once.

let object: MyObject = MyObject()
object.save { (ref, error) in
   // completion
}

Retrieve

Retrieve document with ID.

MyObject.get(document!.id, block: { (document, error) in
    // do something
})

Update

Document has an update method. Be careful as it is different from Salada.

MyObject.get(document!.id, block: { (document, error) in
    document.string = "newString"
    document.update { error in
       // update
    }
})

Delete

Delete document with ID.

MyObject.get(document!.id, block: { (document, error) in
    document.delete()
})

Batched writes

let batch: WriteBatch = Firestore.firestore().batch()
batch.add(.save, object: userA)    //  ** File is not saved.
batch.add(.update, object: userB)
batch.add(.delete, object: userC)
batch.commit(completion: { (error) in
  // error handling
})

List

List can access the Object faster than NestedCollection. List holds data in Document, not SubCollection.

// save
let order: Order = Order()
do {
    let orderItem: OrderItem = OrderItem()
    orderItem.name = "aaaa"
    orderItem.price = 39
    order.items.append(orderItem)
}
do {
    let orderItem: OrderItem = OrderItem()
    orderItem.name = "bbb"
    orderItem.price = 21
    order.items.append(orderItem)
}
order.save()

Be sure to update the parent's object when updating data.

// update
Order.get("ORDER_ID") { (order, error) in
    order.items.first.name = "hoge"
    order.update()
}

📄 File

Pring has a File class because it seamlessly works with Firebase Storage.

Save

File is saved with Document Save at the same time.

let object: MyObject = MyObject()
object.thumbnailImage = File(data: PNG_DATA, mimeType: .png)
let tasks: [String: StorageUploadTask] = object.save { (ref, error) in

}

save method returns the StorageUploadTask that is set with the key. For details on how to use StorageUploadTask, refer to Firebase docs.

let task: StorageUploadTask = tasks["thumbnailImage"]

Get data

Get data with size.

let task: StorageDownloadTask = object.thumbnail.getData(100000, block: { (data, error) in
    // do something
})

Update

If the Document is already saved, please use update method. update method also returns StorageUploadTask. Running update

View on GitHub
GitHub Stars259
CategoryData
Updated2mo ago
Forks28

Languages

Swift

Security Score

100/100

Audited on Jan 8, 2026

No findings