summaryrefslogtreecommitdiffstats
path: root/vendor/github.com/gopackage/ddp/collection.go
diff options
context:
space:
mode:
Diffstat (limited to 'vendor/github.com/gopackage/ddp/collection.go')
-rw-r--r--vendor/github.com/gopackage/ddp/collection.go245
1 files changed, 245 insertions, 0 deletions
diff --git a/vendor/github.com/gopackage/ddp/collection.go b/vendor/github.com/gopackage/ddp/collection.go
new file mode 100644
index 00000000..f417e68a
--- /dev/null
+++ b/vendor/github.com/gopackage/ddp/collection.go
@@ -0,0 +1,245 @@
+package ddp
+
+// ----------------------------------------------------------------------
+// Collection
+// ----------------------------------------------------------------------
+
+type Update map[string]interface{}
+type UpdateListener interface {
+ CollectionUpdate(collection, operation, id string, doc Update)
+}
+
+// Collection managed cached collection data sent from the server in a
+// livedata subscription.
+//
+// It would be great to build an entire mongo compatible local store (minimongo)
+type Collection interface {
+
+ // FindOne queries objects and returns the first match.
+ FindOne(id string) Update
+ // FindAll returns a map of all items in the cache - this is a hack
+ // until we have time to build out a real minimongo interface.
+ FindAll() map[string]Update
+ // AddUpdateListener adds a channel that receives update messages.
+ AddUpdateListener(listener UpdateListener)
+
+ // livedata updates
+ added(msg Update)
+ changed(msg Update)
+ removed(msg Update)
+ addedBefore(msg Update)
+ movedBefore(msg Update)
+ init() // init informs the collection that the connection to the server has begun/resumed
+ reset() // reset informs the collection that the connection to the server has been lost
+}
+
+// NewMockCollection creates an empty collection that does nothing.
+func NewMockCollection() Collection {
+ return &MockCache{}
+}
+
+// NewCollection creates a new collection - always KeyCache.
+func NewCollection(name string) Collection {
+ return &KeyCache{name, make(map[string]Update), nil}
+}
+
+// KeyCache caches items keyed on unique ID.
+type KeyCache struct {
+ // The name of the collection
+ Name string
+ // items contains collection items by ID
+ items map[string]Update
+ // listeners contains all the listeners that should be notified of collection updates.
+ listeners []UpdateListener
+ // TODO(badslug): do we need to protect from multiple threads
+}
+
+func (c *KeyCache) added(msg Update) {
+ id, fields := parseUpdate(msg)
+ if fields != nil {
+ c.items[id] = fields
+ c.notify("create", id, fields)
+ }
+}
+
+func (c *KeyCache) changed(msg Update) {
+ id, fields := parseUpdate(msg)
+ if fields != nil {
+ item, ok := c.items[id]
+ if ok {
+ for key, value := range fields {
+ item[key] = value
+ }
+ c.items[id] = item
+ c.notify("update", id, item)
+ }
+ }
+}
+
+func (c *KeyCache) removed(msg Update) {
+ id, _ := parseUpdate(msg)
+ if len(id) > 0 {
+ delete(c.items, id)
+ c.notify("remove", id, nil)
+ }
+}
+
+func (c *KeyCache) addedBefore(msg Update) {
+ // for keyed cache, ordered commands are a noop
+}
+
+func (c *KeyCache) movedBefore(msg Update) {
+ // for keyed cache, ordered commands are a noop
+}
+
+// init prepares the collection for data updates (called when a new connection is
+// made or a connection/session is resumed).
+func (c *KeyCache) init() {
+ // TODO start to patch up the current data with fresh server state
+}
+
+func (c *KeyCache) reset() {
+ // TODO we should mark the collection but maintain it's contents and then
+ // patch up the current contents with the new contents when we receive them.
+ //c.items = nil
+ c.notify("reset", "", nil)
+}
+
+// notify sends a Update to all UpdateListener's which should never block.
+func (c *KeyCache) notify(operation, id string, doc Update) {
+ for _, listener := range c.listeners {
+ listener.CollectionUpdate(c.Name, operation, id, doc)
+ }
+}
+
+// FindOne returns the item with matching id.
+func (c *KeyCache) FindOne(id string) Update {
+ return c.items[id]
+}
+
+// FindAll returns a dump of all items in the collection
+func (c *KeyCache) FindAll() map[string]Update {
+ return c.items
+}
+
+// AddUpdateListener adds a listener for changes on a collection.
+func (c *KeyCache) AddUpdateListener(listener UpdateListener) {
+ c.listeners = append(c.listeners, listener)
+}
+
+// OrderedCache caches items based on list order.
+// This is a placeholder, currently not implemented as the Meteor server
+// does not transmit ordered collections over DDP yet.
+type OrderedCache struct {
+ // ranks contains ordered collection items for ordered collections
+ items []interface{}
+}
+
+func (c *OrderedCache) added(msg Update) {
+ // for ordered cache, key commands are a noop
+}
+
+func (c *OrderedCache) changed(msg Update) {
+
+}
+
+func (c *OrderedCache) removed(msg Update) {
+
+}
+
+func (c *OrderedCache) addedBefore(msg Update) {
+
+}
+
+func (c *OrderedCache) movedBefore(msg Update) {
+
+}
+
+func (c *OrderedCache) init() {
+
+}
+
+func (c *OrderedCache) reset() {
+
+}
+
+// FindOne returns the item with matching id.
+func (c *OrderedCache) FindOne(id string) Update {
+ return nil
+}
+
+// FindAll returns a dump of all items in the collection
+func (c *OrderedCache) FindAll() map[string]Update {
+ return map[string]Update{}
+}
+
+// AddUpdateListener does nothing.
+func (c *OrderedCache) AddUpdateListener(ch UpdateListener) {
+}
+
+// MockCache implements the Collection interface but does nothing with the data.
+type MockCache struct {
+}
+
+func (c *MockCache) added(msg Update) {
+
+}
+
+func (c *MockCache) changed(msg Update) {
+
+}
+
+func (c *MockCache) removed(msg Update) {
+
+}
+
+func (c *MockCache) addedBefore(msg Update) {
+
+}
+
+func (c *MockCache) movedBefore(msg Update) {
+
+}
+
+func (c *MockCache) init() {
+
+}
+
+func (c *MockCache) reset() {
+
+}
+
+// FindOne returns the item with matching id.
+func (c *MockCache) FindOne(id string) Update {
+ return nil
+}
+
+// FindAll returns a dump of all items in the collection
+func (c *MockCache) FindAll() map[string]Update {
+ return map[string]Update{}
+}
+
+// AddUpdateListener does nothing.
+func (c *MockCache) AddUpdateListener(ch UpdateListener) {
+}
+
+// parseUpdate returns the ID and fields from a DDP Update document.
+func parseUpdate(up Update) (ID string, Fields Update) {
+ key, ok := up["id"]
+ if ok {
+ switch id := key.(type) {
+ case string:
+ updates, ok := up["fields"]
+ if ok {
+ switch fields := updates.(type) {
+ case map[string]interface{}:
+ return id, Update(fields)
+ default:
+ // Don't know what to do...
+ }
+ }
+ return id, nil
+ }
+ }
+ return "", nil
+}