Collections

Carbond Collections provide a high-level abstraction for defining Endpoints that behave like a collection of resources. When you define a Collection you may define the following methods:

  • insert(obj, reqCtx)
  • find(query, reqCtx)
  • update(query, update, reqCtx)
  • remove(query, reqCtx)
  • saveObject(obj, reqCtx)
  • findObject(id, reqCtx)
  • updateObject(id, update, reqCtx)
  • removeObject(id, reqCtx)

Which results in the following tree of Endpoints and Operations:

  • /<collection>
    • POST which maps to insert
    • GET which maps to find
    • PATCH which maps to update
    • DELETE which maps to remove
  • /<collection>/:_id
    • PUT which maps to saveObject
    • GET which maps to findObject
    • PATCH which maps to updateObject
    • DELETE which maps to removeObject

When defining a Collection, it is not required that all methods be implemented. Instead, only methods that are defined will be enabled. For example, here is a collection that only defines the insert method:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
var path = require('path')

var carbon = require('carbon-io')

var __ = carbon.fibers.__(module)
var _o = carbon.bond._o(module)
var o = carbon.atom.o(module)

__(function() {
  module.exports = o.main({
    _type: carbon.carbond.Service,
    port: 8888,
    dbUri: _o('env:CARBONIO_TEST_DB_URI') || "mongodb://localhost:27017/mydb",
    endpoints: {
      feedback: o({
        _type: carbon.carbond.collections.Collection,
        // POST /feedback
        insert: function(obj) {
          var col = this.service.db.getCollection(path.basename(this.path))
          return col.insertObject(obj)
        },
      })
    }
  })
})

Creating Collections

Collection endpoints can be created either by creating an instance of Collection (most common) or by sub-classing (as with the MongoDBCollection class).

The following sections describe at a high-level how each operation should be implemented (note, if an error condition arises, the appropriate HttpError should be thrown).

insert

The insert method should take the object passed to it as an argument and save that object to the backing datastore. If idGenerator is defined, the object will have its _id field prepopulated, otherwise, insert should generate, or delegate the generation of, the _id field and update the object. It should return the object (updated to include the _id if appropriate) that was inserted.

find

The find method should take the query object passed to it, interrogate the backing datastore, and return the list of resources that satisfy the query. Query modifiers (e.g., limit and skip) should be accessed via the reqCtx parameter.

update

The update method should take the query object and update object passed to it, update all resources in the backing datastore as appropriate, and return an object of the form {"n": <integer>} indicating how many resources were updated . Query/update modifiers (e.g., multi) should be accessed via the reqCtx parameter.

remove

The remove method should take the query object and remove all matching resources from the backing datastore. It should then return a document of the form {"n": <integer>} indicating how many resources were removed. Query modifiers (e.g., single) should be accessed via the reqCtx parameter.

saveObject

The saveObject method should take the object passed to it (already populated with the appropriate _id) and save it to the backing datastore. If the resource replaced another resource that existed with that _id, false should be returned. Otherwise, true should be returned to indicate a new resource was created for the _id.

findObject

The findObject method should take the id parameter passed to it and query the backing datastore for the resource with that id. If the resource exists, the object representing the resource should be returned. Otherwise, null or undefined can be returned to indicate that no resource was found matching that id.

updateObject

The updateObject method should take the id and update object passed to it, update the resource identified by id if present, and return the object representing the resource if it existed. If not, null or undefined can be returned to indicate that the resource was not found.

removeObject

The removeObject method should take the id parameter passed to it, remove the resource identified bu id, and return the object representing the resource that was removed if it was present. Otherwise, null or undefined can be returned to indicate that the resource was not fount

Enabling / disabling operations

While omitting an operation’s method is enough to disable it (i.e. simply not defining an insert method will cause the collection to not support inserts), you may also explicitly enable / disable Collection operations via the enabled property. This is useful for temporarily diabling an operation or when instantiating or sub-classing Collections that support default implementations for all Collection operations, such as MongoDBCollection.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
__(function() {
  module.exports = o.main({
    _type: carbon.carbond.Service,
    port: 8888,
    dbUri: _o('env:CARBONIO_TEST_DB_URI') || "mongodb://localhost:27017/mydb",
    endpoints: {
      feedback: o({
        _type: carbon.carbond.collections.Collection,
        enabled: {
          insert: false, // insert is disabled even though it is defined below
          find: true,
          '*': false,
        },
        insert: function(obj) {
          /*
           * implementation...
           */
        },
        find: function(query) {
          /*
           * implementation...
           */
        }
      })
    }
  })
})

Access control

In addition to enabling / disabling operations, you may also gate operations via access control policies (see: access control).