I want to get a sequential invoice number from iCloud using CloudKit, Swift 4.2+ and iOS 11+.
I have never done this with iCloud. Not sure what is the best way to go.
This number will be written into a PDF document which will be saved back to the public iCloud database.
Predicates are limited. I don't think I can use max(number). Obviously no SQL options.
I'm thinking about using notifications to update each device when a number is used and store that locally. But can I trust that? Or do I create another server just to get a unique number?
Not sure if I can use a query with a limit of 1 and sorted by date and then prefill the records with potential numbers (see code below) or just have one record which is updated each time?
func getNextInvoiceNumber() {
let predicate = NSPredicate(format: "status == %@", "unused")
let query = CKQuery(recordType: "Sequence", predicate: predicate)
query.sortDescriptors = [NSSortDescriptor(key: "sequenceNumber", ascending: true)]
let operation = CKQueryOperation(query: query)
operation.resultsLimit = 1
operation.recordFetchedBlock = { (record) in
DispatchQueue.main.async {
let invoiceNumber = record["sequenceNumber"]
// Update the Record so that it is not used again using CKModifyRecordsOperation
record["status"] = "used" // do I also set recordName because it must be unique?
// save this record back to iCloud so it can't be used again
// if I can save it successfully I can use it
self.saveUsedInvoiceNumber(record: record) // will need to retry this in case someone got this number before my save
// Write a valid invoiceNumber to the PDF
self.addInvoiceNumberToDocument(number: invoiceNumber as! Double) // prob move to completion handler from above
}
}
CKContainer.default().publicCloudDatabase.add(operation)
}
func saveUsedInvoiceNumber(record: CKRecord) {
// CKModifyRecordsOperation(...)
//
}
func addInvoiceNumberToDocument(number: Double) {
// write invoice Number to the PDF file and save to disk
// save PDF file to iCloud
}
I am mindful of the potential for conflict with multiple transactions and concurrent users.
Any suggestions on ways you've handled this in iCloud?