docs: function( collectionID, key, data) {
              collectionID = collectionID.toLowerCase();
              var deferred = q.defer();
  
              // acquire a connection from the pool
              db.getClient().then( function(dbClient) {
                  if ( !dbClient ) {
                      throw Error("Failed to acquire sqlite client");
                  }
  
                  // do any necessary dynamic schema syncs, if its supported
                  schemaSyncer.prepCollection(collectionID).then( function() {
                      if ( typeof data !== "object" ) {
                          // the data is a primitive
                          // therefore its a table with a single column, whose value is that primitive
                      } else if ( data && !data['_id'] ) {
                          // the data is an object
                          data._id = key;
                      }
                  })
                  .then( function() {
                      return expandIfNecessary(collectionID, schemaSyncer.getTableSchema(collectionID), key, data);
                  })
  
                  // start a transaction using the acquired db connection
                  .then( function() {
                      return startTx(dbClient);
                  })
  
                  // first try an update
                  .then( function() {
                      var sql = sqlAdaptor.createUpdateSQL(collectionID, data, key);
                      return query(dbClient, sql).then(
                          // success
                          function(dbResult) {
                              var r = dbResult.results();
                              return q.resolve(r.rowCount >= 1);
                          },
  
                          // error
                          function(e) {
                              return rollbackTx(dbClient, e).finally( function() {
                                  deferred.reject(e);
                              });
                          }
                      );
                  })
  
                  // if the update fails (because this requires an insert), try to insert the data
                  .then( function(updated) {
                      if (updated ) {
                          // we're done
                          return q.resolve(data);
                      } else {
                          // otherwise do insert
                          var sql = sqlAdaptor.createInsertSQL(collectionID, data, key);
                          return query(dbClient, sql).then(
                              // success
                              function(dbResult) {
                                  var r = dbResult.results();
                                  if (r.rowCount < 1 ) {
                                      dbClient.release();
                                      throwError("failed to insert");
                                  }
                                  return q.resolve(data);
                              },
  
                              // error
                              function(e) {
                                  return rollbackTx(dbClient, e).finally( function() {
                                      deferred.reject(e);
                                  });
                              }
                          );
                      }
                  })
  
                  // commit the transaction if no problems are encountered, this should also close the acquired db client
                  // and return it to the connection pool
                  .then( function(r) {
                      return commitTx(dbClient).then( function() {
                          deferred.resolve(r);
                      });
                  })
  
                  // ultimately rollback if there is any upstream thrown exception caught
                  .catch(function(e) {
                      return rollbackTx(dbClient, e).finally( function() {
                          deferred.reject(e);
                      });
                  })
  
                  // always try to release the client, if it exists
                  .finally(function() {
                      if ( dbClient ) {
                          dbClient.release();
                      }
                  });
              })
              // failed to acquire the client
              .fail( function(e) {
                  deferred.reject(e);
              });
  
              return deferred.promise;
          }