siegesmund / SwiftDDP

A Meteor client, written in Swift
MIT License
145 stars 60 forks source link

Inserting an object with a subclass of AbstractCollection #13

Closed AlexCatch closed 8 years ago

AlexCatch commented 8 years ago

I followed the code at the bottom of the readme and successfully managed to get the collection reading out in an Array.

The issue came when trying to insert an object, I found that the .insert() method of the collection was not there.

How can I insert a new object in the collection which is a subclass of AbstractCollection and have it sync with the backend? Here is my code for the subclass

class NotesCollection: AbstractCollection {
    var notes = [Note!]()

    var collection: String = "Notes"
    var text: String!
    var creationDate: String!

    override init(name: String) {
        super.init(name: name)
    }

    override func documentWasAdded(collection: String, id: String, fields: NSDictionary?) {
        let note = Note(id: id, fields: fields)
        notes.append(note)

    }

    override func documentWasRemoved(collection: String, id: String) {
        if let index = notes.indexOf({ note in return note!._id! == id }) {
            notes[index] = nil
        }
    }

    override func documentWasChanged(collection: String, id: String, fields: NSDictionary?, cleared: [String]?) {
        var note: Note!
        if let index = notes.indexOf({ note in return note!._id == id }) {
            note = notes[index]
            note.update(fields)
            notes[index] = note
        }
    }
}

Sorry if this is a stupid question.

Thanks, Alex

siegesmund commented 8 years ago

Definitely not a stupid question :).

So, you're correct that there isn't a built-in method in AbstractCollection. This is because AbstractCollection is intended as a building block to create collections with any datastore and operations that affect data on both the client and server side have to be written with regard to the datastore that you're using on the client side. For example, with insertion, you'd presumably want to insert your object into your client-side database, call the server-side insert method, then reverse your client-side insertion if the server-side insertion failed (because, for example, you aren't authorized to insert on this collection). That code logic is different depending on whether you use Core Data, Realm, or a plain old array to store your data client-side.

The MeteorCollection class holds documents that are subclasses of MeteorDocument. It stores these documents in an array. It's insert method looks like this:

public func insert(document: T) {

       // save the document to the built-in documents array
        documents[document._id] = document
        collectionSetDidChange() // send a notification that the set has changed

        // now try to insert the document on the server, but remove it if the attempt fails
        client.insert(self.name, document: [document.fields()]) { result, error in

            if error != nil {
                self.documents[document._id] = nil
                self.collectionSetDidChange()
                log.error("\(error!)")
            }

        }

    } 

To see more in-depth examples of how this might work in practice, have a look at either one of the Todos examples, or the MeteorCollection class.

If this is still hazy, let me know.