Major overhaul to request builders to support multiple argument types
diff --git a/helpers/build.js b/helpers/build.js
new file mode 100644
index 0000000..911666c
--- /dev/null
+++ b/helpers/build.js
@@ -0,0 +1,191 @@
+'use strict'
+
+var urljoin = require('url-join'),
+    config = require('./config'),
+    cb = require('./cb'),
+    helpers = require('./'),
+    UsergridQuery = require('../lib/query'),
+    UsergridEntity = require('../lib/entity'),
+    ok = require('objectkit'),
+    _ = require('underscore')
+
+module.exports = {
+    url: function(options) {
+        return urljoin(
+            config.baseUrl,
+            options.client.orgId,
+            options.client.appId,
+            options.type, (typeof options.uuidOrName === 'string' ? options.uuidOrName : "")
+        )
+    },
+    GET: function(client, args) {
+
+        /* GET supports the following constructor patterns:
+
+        client.GET('type', 'uuidOrName', optionalCallback)
+        client.GET('type', optionalCallback)
+        client.GET(query, optionalCallback)
+        client.GET({
+            query: query, // takes precedence
+            type: type, // required only if query not defined
+            uuid: uuid, // will be set to nameOrUuid on init (priority)
+            name: name, // will be set to nameOrUuid on init (if no uuid specified)
+            nameOrUuid: nameOrUuid // the definitive key for name or uuid
+        }, optionalCallback)
+
+        */
+
+        var options = {
+            client: client,
+            method: 'GET'
+        }
+
+        if (typeof args[0] === 'object' && !(args[0] instanceof UsergridQuery)) {
+            _.extend(options, args[0])
+        }
+
+        options.callback = helpers.cb(_.last(args.filter(function(property) {
+            return typeof property === 'function'
+        })))
+
+        options.type = options.type || (args[0] instanceof UsergridQuery ? args[0]._type : args[0])
+        options.query = options.query || (args[0] instanceof UsergridQuery ? args[0] : undefined)
+        options.uuidOrName = _.last([options.uuidOrName, options.uuid, options.name, args[1]].filter(function(property) {
+            return (property)
+        }))
+
+        return options
+    },
+    PUT: function(client, args) {
+
+        /* PUT supports the following constructor patterns:
+
+        client.PUT('type', 'uuidOrName', bodyObject, optionalCallback)
+        client.PUT('type', bodyObject, optionalCallback) // if no uuid, will create a new record
+        client.PUT(bodyObjectOrEntity, optionalCallback) // if no uuid, will create a new record; must include type
+        client.PUT(query, bodyObjectOrEntity, optionalCallback) // will update all entities matching query
+        client.PUT(entity, optionalCallback)
+        client.PUT({
+            *entity = alias to body*
+            query: query, // takes precedence over type/body
+            type: type, // required only if query not defined
+            body: bodyObject or bodyObjectOrEntity, // if includes type, type will be inferred from body
+            *uuid, name* = alias to nameOrUuid*
+            nameOrUuid: nameOrUuid // the definitive key for name or uuid
+        }, optionalCallback)
+
+        */
+
+        var options = {
+            client: client,
+            method: 'PUT'
+        }
+
+        if (typeof args[0] === 'object' && !(args[0] instanceof UsergridEntity) && !(args[0] instanceof UsergridQuery)) {
+            _.extend(options, args[0])
+        }
+
+        options.callback = helpers.cb(_.last(args.filter(function(property) {
+            return typeof property === 'function'
+        })))
+
+        options.body = _.first([options.entity, options.body, args[2], args[1], args[0]].filter(function(property) {
+            return typeof property === 'object' && !(property instanceof UsergridQuery)
+        }))
+
+        if (typeof options.body !== 'object') {
+            throw new Error('"body" parameter is required when making a PUT request')
+        }
+
+        options.uuidOrName = _.first([options.nameOrUuid, options.uuid, options.name, options.body.uuid, args[2], args[1], args[0]].filter(function(property) {
+            return typeof property === 'string'
+        }))
+
+        options.type = options.type || (args[0] instanceof UsergridQuery ? args[0]._type : options.body.type || args[0])
+        options.query = options.query || (args[0] instanceof UsergridQuery ? args[0] : undefined)
+
+        return options
+    },
+
+    POST: function(client, args) {
+
+        /* POST supports the following constructor patterns:
+
+        client.POST('type', bodyObjectOrArray, optionalCallback)
+        client.POST(bodyObjectOrArray, optionalCallback) // must include type in body
+        client.POST(entityOrEntities, optionalCallback)
+        client.POST({
+            *entity, entities = alias to body*
+            type: type, // required if type is not inferred
+            body: bodyObjectOrArray or entityOrEntities, // if the first entity includes type, type will be inferred from body
+        }, optionalCallback)
+
+        */
+
+        var options = {
+            client: client,
+            method: 'POST'
+        }
+
+        if (typeof args[0] === 'object' && !(args[0] instanceof UsergridEntity)) {
+            _.extend(options, args[0])
+        }
+
+        options.callback = helpers.cb(_.last(args.filter(function(property) {
+            return typeof property === 'function'
+        })))
+
+        options.body = _.first([options.entities, options.entity, options.body, args[1], args[0]].filter(function(property) {
+            return property instanceof Array && typeof property[0] === 'object' || typeof property === 'object'
+        }))
+        if (typeof options.body !== 'object') {
+            throw new Error('"body" parameter is required when making a POST request')
+        }
+        options.body = options.body instanceof Array ? options.body : [options.body]
+        options.type = options.type || (typeof args[0] === 'string' ? args[0] : options.body[0].type)
+
+        return options
+    },
+    DELETE: function(client, args) {
+
+        /* DELETE supports the following constructor patterns:
+
+        client.DELETE('type', 'uuidOrName', optionalCallback)
+        client.DELETE(entity, optionalCallback) // must include type in body
+        client.DELETE(query, optionalCallback)
+        client.DELETE({
+            *uuid, name* = alias to nameOrUuid*
+            uuidOrName: uuidOrName,
+            type: type, // required if type is not inferred
+            query: query // takes precedence over type/uuid
+        }, optionalCallback)
+
+        */
+
+        var options = {
+            client: client,
+            method: 'DELETE'
+        }
+
+        if (typeof args[0] === 'object' && !(args[0] instanceof UsergridQuery)) {
+            _.extend(options, args[0])
+        }
+
+        options.callback = helpers.cb(_.last(args.filter(function(property) {
+            return typeof property === 'function'
+        })))
+
+        options.type = options.type || (args[0] instanceof UsergridQuery ? args[0]._type : args[0])
+        options.entity = options.entity || (args[0] instanceof UsergridEntity ? args[0] : undefined)
+        options.query = options.query || (args[0] instanceof UsergridQuery ? args[0] : undefined)
+        options.uuidOrName = _.first([options.uuidOrName, options.uuid, options.name, ok(options).getIfExists('entity.uuid'), args[1]].filter(function(property) {
+            return (typeof property === 'string')
+        }))
+
+        if (typeof options.uuidOrName !== 'string' && options.query === undefined) {
+            throw new Error('"uuidOrName" parameter or "query" is required when making a DELETE request')
+        }
+
+        return options
+    }
+}
\ No newline at end of file
diff --git a/helpers/buildUrl.js b/helpers/buildUrl.js
deleted file mode 100644
index 1acdf5e..0000000
--- a/helpers/buildUrl.js
+++ /dev/null
@@ -1,15 +0,0 @@
-'use strict'
-
-var urljoin = require('url-join'),
-    config = require('./config')
-
-function buildUrl(options) {
-    return urljoin(
-        config.baseUrl,
-        options.client.orgId,
-        options.client.appId,
-        options.type, (typeof options.uuidOrName === 'string') ? options.uuidOrName : ""
-    )
-}
-
-module.exports = buildUrl
\ No newline at end of file
diff --git a/helpers/config.js b/helpers/config.js
index cbf7efc..9fb5d8d 100644
--- a/helpers/config.js
+++ b/helpers/config.js
@@ -1,7 +1,6 @@
 'use strict'
 
-var _ = require('underscore')
-
+var _ = require('lodash')
 _.mixin(require('underscore.string'))
 
 if (/mocha$/i.test(process.argv[1])) {
diff --git a/helpers/index.js b/helpers/index.js
index 7fe5b91..4b08822 100644
--- a/helpers/index.js
+++ b/helpers/index.js
@@ -1,18 +1,15 @@
 var mutability = require('./mutability'),
     cb = require('./cb'),
-    buildUrl = require('./buildUrl'),
+    build = require('./build'),
     userAgent = require('./userAgent'),
-    is = require('./is'),
     query = require('./query'),
-    config = require('./config')
+    config = require('./config'),
+    _ = require('lodash')
 
-module.exports = {
-    setReadOnly: mutability.setReadOnly,
-    setWritable: mutability.setWritable,
+module.exports = _.extend(module.exports, {
     cb: cb,
-    buildUrl: buildUrl,
+    build: build,
     userAgent: userAgent,
-    is: is,
     query: query,
     config: config
-}
\ No newline at end of file
+}, mutability)
\ No newline at end of file
diff --git a/helpers/is.js b/helpers/is.js
deleted file mode 100644
index a9157f1..0000000
--- a/helpers/is.js
+++ /dev/null
@@ -1,13 +0,0 @@
-'use strict'
-
-module.exports = {
-    numeric: function(n) {
-        return !isNaN(parseFloat(n)) && isFinite(n)
-    },
-    uuid: function(s) {
-        return (/([a-f\d]{8}(-[a-f\d]{4}){3}-[a-f\d]{12}?)/i).test(s)
-    },
-    bool: function(b) {
-        return typeof(b) === "boolean"
-    }
-}
\ No newline at end of file
diff --git a/helpers/mutability.js b/helpers/mutability.js
index 9800e1d..69c06f7 100644
--- a/helpers/mutability.js
+++ b/helpers/mutability.js
@@ -2,42 +2,38 @@
 
 var ok = require('objectkit')
 
-function setReadOnly(obj, key) {
-    if (typeof obj[key] === 'array') {
-        return obj[key].forEach(function(k) {
-            setReadOnly(obj, k)
-        })
-    } else if (typeof obj[key] === 'object') {
-        return Object.freeze(obj[key])
-    } else if (typeof obj === 'object' && key === undefined) {
-        return Object.freeze(obj)
-    } else if (ok(obj).has(key)) {
-        return Object.defineProperty(obj, key, {
-            configurable: false,
-            writable: false
-        })
-    } else {
-        return obj
-    }
-}
-
-function setWritable(obj, key) {
-    // Note that once Object.freeze is called on an object, it cannot be unfrozen
-    if (typeof obj[key] === 'array') {
-        return obj[key].forEach(function(k) {
-            setWritable(obj, k)
-        })
-    } else if (ok(obj).has(key)) {
-        return Object.defineProperty(obj, key, {
-            configurable: true,
-            writable: true
-        })
-    } else {
-        return obj
-    }
-}
-
 module.exports = {
-    setReadOnly: setReadOnly,
-    setWritable: setWritable
+    setReadOnly: function(obj, key) {
+        if (typeof obj[key] === 'array') {
+            return obj[key].forEach(function(k) {
+                setReadOnly(obj, k)
+            })
+        } else if (typeof obj[key] === 'object') {
+            return Object.freeze(obj[key])
+        } else if (typeof obj === 'object' && key === undefined) {
+            return Object.freeze(obj)
+        } else if (ok(obj).has(key)) {
+            return Object.defineProperty(obj, key, {
+                configurable: false,
+                writable: false
+            })
+        } else {
+            return obj
+        }
+    },
+    setWritable: function(obj, key) {
+        // Note that once Object.freeze is called on an object, it cannot be unfrozen
+        if (typeof obj[key] === 'array') {
+            return obj[key].forEach(function(k) {
+                setWritable(obj, k)
+            })
+        } else if (ok(obj).has(key)) {
+            return Object.defineProperty(obj, key, {
+                configurable: true,
+                writable: true
+            })
+        } else {
+            return obj
+        }
+    }
 }
\ No newline at end of file
diff --git a/helpers/query.js b/helpers/query.js
index 18a630c..9a40f33 100644
--- a/helpers/query.js
+++ b/helpers/query.js
@@ -1,10 +1,12 @@
 'use strict'
 
-var is = require('./is'),
-    util = require('util')
+var util = require('util'),
+    _ = require('lodash')
+
+_.mixin(require('lodash-uuid'))
 
 module.exports = {
     useQuotesIfRequired: function(value) {
-        return (is.numeric(value) || is.uuid(value) || is.bool(value)) ? value : util.format("'%s'", value)
+        return (_.isFinite(value) || _.isUuid(value) || _.isBoolean(value) || _.isObject(value) || _.isArray(value)) ? value : util.format("'%s'", value)
     }
 }
\ No newline at end of file
diff --git a/lib/client.js b/lib/client.js
index 3328634..b65eb04 100644
--- a/lib/client.js
+++ b/lib/client.js
@@ -1,9 +1,11 @@
 'use strict'
 
 var UsergridRequest = require('./request'),
+    UsergridQuery = require('./query'),
+    UsergridEntity = require('./entity'),
     request = require('request'),
-    config = require('../helpers/config'),
     helpers = require('../helpers'),
+    config = helpers.config,
     UsergridAppAuth = require('./appAuth'),
     _ = require('underscore')
 
@@ -50,48 +52,20 @@
     })
 }
 
-UsergridClient.prototype.GET = function(type, uuidOrName, callback) {
-    return new UsergridRequest({
-        client: this,
-        method: 'GET',
-        type: type,
-        uuidOrName: typeof uuidOrName === 'string' ? uuidOrName : undefined
-    }, callback || uuidOrName)
+UsergridClient.prototype.GET = function() {
+    return new UsergridRequest(helpers.build.GET(this, Array.prototype.slice.call(arguments)))
 }
 
-UsergridClient.prototype.PUT = function(type, uuidOrName, body, callback) {
-    if (typeof uuidOrName !== 'string') {
-        throw new Error('"uuidOrName" parameter is required when making a PUT request')
-    }
-    return new UsergridRequest({
-        client: this,
-        method: 'PUT',
-        type: type,
-        uuidOrName: typeof uuidOrName === 'string' ? uuidOrName : undefined,
-        body: typeof body === 'object' ? body : typeof uuidOrName === 'object' ? uuidOrName : undefined
-    }, callback || body || uuidOrName)
+UsergridClient.prototype.PUT = function() {
+    return new UsergridRequest(helpers.build.PUT(this, Array.prototype.slice.call(arguments)))
 }
 
-UsergridClient.prototype.POST = function(type, uuidOrName, body, callback) {
-    return new UsergridRequest({
-        client: this,
-        method: 'POST',
-        type: type,
-        uuidOrName: typeof uuidOrName === 'string' ? uuidOrName : undefined,
-        body: typeof body === 'object' ? body : typeof uuidOrName === 'object' ? uuidOrName : undefined
-    }, callback || body || uuidOrName)
+UsergridClient.prototype.POST = function() {
+    return new UsergridRequest(helpers.build.POST(this, Array.prototype.slice.call(arguments)))
 }
 
 UsergridClient.prototype.DELETE = function(type, uuidOrName, callback) {
-    if (typeof uuidOrName !== 'string') {
-        throw new Error('"uuidOrName" parameter is required when making a DELETE request')
-    }
-    return new UsergridRequest({
-        client: this,
-        method: 'DELETE',
-        type: type,
-        uuidOrName: typeof uuidOrName === 'string' ? uuidOrName : undefined
-    }, callback || uuidOrName)
+    return new UsergridRequest(helpers.build.DELETE(this, Array.prototype.slice.call(arguments)))
 }
 
 UsergridClient.prototype.setAppAuth = function(options) {
@@ -113,7 +87,7 @@
     options.type = 'token'
     options.client = self
     request({
-        uri: helpers.buildUrl(options),
+        uri: helpers.build.url(options),
         headers: helpers.userAgent,
         body: {
             grant_type: 'client_credentials',
diff --git a/lib/entity.js b/lib/entity.js
index 2ba4efb..84c838d 100644
--- a/lib/entity.js
+++ b/lib/entity.js
@@ -1,12 +1,21 @@
 'use strict'
 
-var _ = require('underscore'),
-    helpers = require('../helpers'),
-    ok = require('objectkit')
+var helpers = require('../helpers'),
+    ok = require('objectkit'),
+    _ = require('underscore')
 
-var UsergridEntity = function(object) {
+var UsergridEntity = function(obj) {
     var self = this
-    _.extend(self, object)
+
+    if (!obj) {
+        throw new Error('A UsergridEntity object was initialized using an empty argument')
+    }
+
+    _.extend(self, obj)
+
+    if (typeof self.type !== 'string') {
+        throw new Error('"type" (or "collection") parameter is required when initializing a UsergridEntity object')
+    }
 
     Object.defineProperty(self, 'isUser', {
         get: function() {
diff --git a/lib/query.js b/lib/query.js
index dcdad93..e661271 100644
--- a/lib/query.js
+++ b/lib/query.js
@@ -8,13 +8,15 @@
 
 var UsergridQuery = function(type) {
 
+    var self = this
+
     var query = '',
         queryString,
         sort,
         __nextIsNot = false
 
     // builder pattern
-    var self = {
+    _.extend(self, {
         type: function(value) {
             self._type = value
             return self
@@ -87,7 +89,7 @@
         orJoin: function() {
             return (query.length > 0 && !_(query).endsWith('or')) ? util.format('%s or', query) : query
         }
-    }
+    })
 
     // required properties
     self._type = self._type || type
diff --git a/lib/request.js b/lib/request.js
index fbc6d21..f7b0cc1 100644
--- a/lib/request.js
+++ b/lib/request.js
@@ -3,14 +3,17 @@
 var request = require('request'),
     helpers = require('../helpers'),
     UsergridResponse = require('../lib/response'),
+    UsergridQuery = require('../lib/query'),
     util = require('util'),
     _ = require('underscore')
 
-var UsergridRequest = function(options, callback) {
-    callback = helpers.cb(callback)
+var UsergridRequest = function(options) {
+    options.callback = helpers.cb(options.callback)
+
     if (typeof options.type !== 'string') {
         throw new Error('"type" (or "collection") parameter is required when making a request')
     }
+
     var headers = helpers.userAgent
 
     if (options.client.appAuth && options.client.appAuth.isTokenValid) {
@@ -18,15 +21,20 @@
             authorization: util.format("Bearer %s", options.client.appAuth.token)
         })
     }
-    request(helpers.buildUrl(options), {
+
+    request(helpers.build.url(options), {
         headers: headers,
         body: options.body,
         json: true,
-        method: options.method
+        method: options.method,
+        qs: (options.query instanceof UsergridQuery) ? {
+            ql: options.query._ql,
+            limit: options.query._limit
+        } : undefined
     }, function(error, response) {
-        response = new UsergridResponse(response)
-        callback(error, response)
+        options.callback(error, new UsergridResponse(response))
     })
+
 }
 
 module.exports = UsergridRequest
\ No newline at end of file
diff --git a/lib/response.js b/lib/response.js
index 5f6340d..181341e 100644
--- a/lib/response.js
+++ b/lib/response.js
@@ -5,7 +5,7 @@
     UsergridUser = require('./user.js'),
     UsergridResponseError = require('./responseError.js'),
     helpers = require('../helpers'),
-    _ = require('underscore')
+    _ = require('lodash')
 
 _.mixin(require('underscore.string'))
 
@@ -13,18 +13,23 @@
     if (!response) {
         return
     } else if (ok(response.body).has('entities')) {
+
         var entities = response.body.entities.map(function(en) {
+
             var entity = new UsergridEntity(en)
-            return (entity.isUser) ? new UsergridUser(entity) : entity
+            if (entity.isUser) {
+                entity = new UsergridUser(entity)
+            }
+            return entity
         })
         _.extend(response, {
-            metadata: _.clone(response.body),
+            metadata: _.cloneDeep(response.body),
             entities: entities
         })
         delete response.metadata.entities
         response.first = _.first(entities) || undefined
         response.entity = response.first
-        response.last = _.last(entities) || undefined
+        response.last = _.last(entities) || undefined   
         if (ok(response).getIfExists('metadata.path') === '/users') {
             response.user = response.first
             response.users = response.entities
diff --git a/lib/user.js b/lib/user.js
index 36b0253..4deea07 100644
--- a/lib/user.js
+++ b/lib/user.js
@@ -3,19 +3,18 @@
 var UsergridEntity = require('./entity'),
     helpers = require('../helpers'),
     ok = require('objectkit'),
-    _ = require('underscore'),
-    util = require('util')
+    util = require('util'),
+    _ = require('underscore')
 
-var UsergridUser = function(object) {
+var UsergridUser = function(obj) {
 
-    if (!ok(object).has('email') && !ok(object).has('username')) {
-        // This is not a user entity
-        return object
+    if (!ok(obj).has('email') && !ok(obj).has('username')) {
+        // This is not a user entity, let's try to initalize a standard UsergridEntity
+        throw new Error('"email" or "username" property is required when initializing a UsergridUser object')
     }
 
     var self = this
-    _.extend(self, object, UsergridEntity)
-    UsergridEntity.call(self)
+    _.extend(self, UsergridEntity.call(self, obj))
     helpers.setWritable(self, 'name')
     return self
 }
diff --git a/package.json b/package.json
index 36ed335..38ebe86 100644
--- a/package.json
+++ b/package.json
@@ -1,43 +1,46 @@
 {
-  "author": "Brandon Shelley",
-  "dependencies": {
-    "async": "latest",
-    "objectkit": "latest",
-    "request": "latest",
-    "underscore": "latest",
-    "underscore.inflection": "latest",
-    "underscore.string": "latest",
-    "url-join": "latest",
-    "volos-analytics-apigee": "latest",
-    "volos-analytics-common": "latest",
-    "volos-analytics-memory": "latest",
-    "volos-cache-apigee": "latest",
-    "volos-cache-memory": "latest",
-    "volos-cache-redis": "latest",
-    "volos-oauth-apigee": "latest",
-    "volos-oauth-redis": "latest",
-    "volos-quota-apigee": "latest",
-    "volos-quota-memory": "latest",
-    "volos-quota-redis": "latest"
-  },
-  "description": "The official Node.js SDK for Usergrid",
-  "devDependencies": {
-    "grunt": "latest",
-    "grunt-codacy": "latest",
-    "grunt-mocha-test": "latest",
-    "mocha-lcov-reporter": "latest",
-    "codacy-coverage": "latest",
-    "should": "latest",
-    "mocha": "latest"
-  },
-  "keywords": [],
-  "license": "MIT",
-  "main": "app.js",
-  "name": "usergrid",
-  "private": false,
-  "scripts": {
-    "start": "node app.js",
-    "test": "mocha tests"
-  },
-  "version": "2.0.0"
-}
+    "author": "Brandon Shelley",
+    "dependencies": {
+        "async": "latest",
+        "lodash": "latest",
+        "lodash-inflection": "latest",
+        "lodash-uuid": "latest",
+        "objectkit": "latest",
+        "request": "latest",
+        "underscore": "latest",
+        "underscore.inflection": "latest",
+        "underscore.string": "latest",
+        "url-join": "latest",
+        "volos-analytics-apigee": "latest",
+        "volos-analytics-common": "latest",
+        "volos-analytics-memory": "latest",
+        "volos-cache-apigee": "latest",
+        "volos-cache-memory": "latest",
+        "volos-cache-redis": "latest",
+        "volos-oauth-apigee": "latest",
+        "volos-oauth-redis": "latest",
+        "volos-quota-apigee": "latest",
+        "volos-quota-memory": "latest",
+        "volos-quota-redis": "latest"
+    },
+    "description": "The official Node.js SDK for Usergrid",
+    "devDependencies": {
+        "codacy-coverage": "latest",
+        "grunt": "latest",
+        "grunt-codacy": "latest",
+        "grunt-mocha-test": "latest",
+        "mocha": "latest",
+        "mocha-lcov-reporter": "latest",
+        "should": "latest"
+    },
+    "keywords": [],
+    "license": "MIT",
+    "main": "app.js",
+    "name": "usergrid",
+    "private": false,
+    "scripts": {
+        "start": "node app.js",
+        "test": "mocha tests"
+    },
+    "version": "2.0.0"
+}
\ No newline at end of file
diff --git a/tests/lib/client.test.js b/tests/lib/client.test.js
index 20c71ad..d748fd3 100644
--- a/tests/lib/client.test.js
+++ b/tests/lib/client.test.js
@@ -1,11 +1,18 @@
 'use strict'
 
 var should = require('should'),
-    config = require('../../helpers/config'),
+    config = require('../../helpers').config,
     UsergridClient = require('../../lib/client'),
-    UsergridAppAuth = require('../../lib/appAuth')
+    UsergridEntity = require('../../lib/entity'),
+    UsergridQuery = require('../../lib/query'),
+    UsergridAppAuth = require('../../lib/appAuth'),
+    _ = require('underscore')
 
-var _uuid = null
+_.mixin(require('lodash-uuid'))
+
+var _uuid,
+    _slow = 500,
+    _timeout = 4000
 
 describe('initialization', function() {
     it('should fail to initialize without an orgId and appId', function() {
@@ -38,10 +45,10 @@
 })
 
 describe('GET()', function() {
+    this.slow(_slow)
+    this.timeout(_timeout)
 
-    this.slow(1000)
-    this.timeout(6000)
-    var response, client
+    var response, client, query
     before(function(done) {
         client = new UsergridClient(config)
         client.GET(config.testCollection, function(err, usergridResponse) {
@@ -74,11 +81,27 @@
     it('response.last should exist and have a valid uuid', function() {
         response.last.should.be.an.Object().with.property('uuid').with.a.lengthOf(36)
     })
+
+    it('each entity should match the search criteria when passing a UsergridQuery object', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        client = new UsergridClient(config)
+        query = new UsergridQuery(config.testCollection).eq('color', 'black')
+
+        client.GET(query, function(err, usergridResponse) {
+            usergridResponse.entities.forEach(function(entity) {
+                entity.should.be.an.Object().with.property('color').equal('black')
+            })
+            done()
+        })
+    })
 })
 
 describe('POST()', function() {
 
-    this.slow(1000)
+    this.slow(_slow)
     this.timeout(3000)
 
     var response, client
@@ -113,12 +136,104 @@
     it('response.entity.author should equal "Sir Arthur Conan Doyle"', function() {
         response.entity.should.have.property('author').equal('Sir Arthur Conan Doyle')
     })
+
+    it('should support creating an entity by passing a UsergridEntity object', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        var entity = new UsergridEntity({
+            type: config.testCollection,
+            restaurant: "Dino's Deep Dish",
+            cuisine: "pizza"
+        })
+
+        client.POST(entity, function(err, usergridResponse) {
+            usergridResponse.entity.should.be.an.Object().with.property('restaurant').equal(entity.restaurant)
+            done()
+        })
+    })
+
+    it('should support creating an entity by passing type and a body object', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        client.POST(config.testCollection, {
+            restaurant: "Dino's Deep Dish",
+            cuisine: "pizza"
+        }, function(err, usergridResponse) {
+            usergridResponse.entity.should.be.an.Object().with.property('restaurant').equal("Dino's Deep Dish")
+            done()
+        })
+    })
+
+    it('should support creating an entity by passing a body object that includes type', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        client.POST({
+            type: config.testCollection,
+            restaurant: "Dino's Deep Dish",
+            cuisine: "pizza"
+        }, function(err, usergridResponse) {
+            usergridResponse.entity.should.be.an.Object().with.property('restaurant').equal("Dino's Deep Dish")
+            done()
+        })
+    })
+
+    it('should support creating an entity by passing an array of UsergridEntity objects', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        var entities = [
+            new UsergridEntity({
+                type: config.testCollection,
+                restaurant: "Dino's Deep Dish",
+                cuisine: "pizza"
+            }), new UsergridEntity({
+                type: config.testCollection,
+                restaurant: "Chipotle",
+                cuisine: "mexican"
+            })
+        ]
+
+        client.POST(entities, function(err, usergridResponse) {
+            usergridResponse.entities.forEach(function(entity) {
+                entity.should.be.an.Object().with.property('restaurant').equal(entity.restaurant)
+            })
+            done()
+        })
+    })
+
+    it('should support creating an entity by passing a preformatted POST builder object', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        var options = {
+            type: config.testCollection,
+            body: {
+                restaurant: "Chipotle",
+                cuisine: "mexican"
+            }
+        }
+
+        client.POST(options, function(err, usergridResponse) {
+            usergridResponse.entities.forEach(function(entity) {
+                entity.should.be.an.Object().with.property('restaurant').equal(entity.restaurant)
+            })
+            done()
+        })
+    })
 })
 
 describe('PUT()', function() {
 
-    this.slow(1000)
-    this.timeout(3000)
+    this.slow(_slow)
+    this.timeout(_timeout)
 
     var response, client
     before(function(done) {
@@ -133,30 +248,134 @@
 
     it('should not fail when a callback function is not passed', function() {
         // note: this test will NOT fail gracefully inside the Mocha event chain
-        client.PUT(config.testCollection, _uuid)
+        client.PUT(config.testCollection, _uuid, {})
     })
 
     it('should return a 200 ok', function() {
         response.statusCode.should.equal(200)
     })
 
-    it('response.entities should be an array', function() {
+    it('response.entities should be an array with a single entity', function() {
         response.entities.should.be.an.Array().with.a.lengthOf(1)
     })
 
-    it('response.entity should exist and its uuid should the uuid from the previous POST requets', function() {
+    it('response.entity should exist and its uuid should the uuid from the previous POST request', function() {
         response.entity.should.be.an.Object().with.property('uuid').equal(_uuid)
     })
 
-    it('response.entity.narrator should equal "Peter Doyle"', function() {
+    it('response.entity.narrator should be updated to "Peter Doyle"', function() {
         response.entity.should.have.property('narrator').equal('Peter Doyle')
     })
+
+    it('should create a new entity when no uuid or name is passed', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        var newEntity = new UsergridEntity({
+            type: config.testCollection,
+            author: 'Frank Mills'
+        })
+
+        client.PUT(newEntity, function(err, usergridResponse) {
+            usergridResponse.entity.should.be.an.Object()
+            usergridResponse.entity.should.have.property('uuid').with.a.lengthOf(36)
+            usergridResponse.entity.should.have.property('author').equal('Frank Mills')
+            usergridResponse.entity.created.should.equal(usergridResponse.entity.modified)
+            done()
+        })
+    })
+
+    it('should support updating the entity by passing a UsergridEntity object', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        var updateEntity = _.extend(response.entity, {
+            publisher: {
+                name: "George Newns",
+                date: "14 October 1892",
+                country: "United Kingdom"
+            }
+        })
+
+        client.PUT(updateEntity, function(err, usergridResponse) {
+            usergridResponse.entity.should.be.an.Object().with.property('publisher').deepEqual(updateEntity.publisher)
+            done()
+        })
+    })
+
+    it('should support updating an entity by passing type and a body object', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        client.PUT(config.testCollection, {
+            uuid: response.entity.uuid,
+            updateByPassingTypeAndBody: true
+        }, function(err, usergridResponse) {
+            usergridResponse.entity.should.be.an.Object().with.property('updateByPassingTypeAndBody').equal(true)
+            done()
+        })
+    })
+
+    it('should support updating an entity by passing a body object that includes type', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        client.PUT(config.testCollection, {
+            type: config.testCollection,
+            uuid: response.entity.uuid,
+            updateByPassingBodyIncludingType: true
+        }, function(err, usergridResponse) {
+            usergridResponse.entity.should.be.an.Object().with.property('updateByPassingBodyIncludingType').equal(true)
+            done()
+        })
+    })
+
+    it('should support updating a set of entities by passing an UsergridQuery object', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        var query = new UsergridQuery(config.testCollection).eq('cuisine', 'pizza').limit(2)
+        var body = {
+            testUuid: _.uuid()
+        }
+
+        client.PUT(query, body, function(err, usergridResponse) {
+            usergridResponse.entities.forEach(function(entity) {
+                entity.should.be.an.Object().with.property('testUuid').equal(body.testUuid)
+            })
+            done()
+        })
+    })
+
+    it('should support updating an entity by passing a preformatted PUT builder object', function(done) {
+
+        this.slow(_slow)
+        this.timeout(_timeout)
+
+        var options = {
+            uuidOrName: response.entity.uuid,
+            type: config.testCollection,
+            body: {
+                relatedUuid: _.uuid()
+            }
+        }
+
+        client.PUT(options, function(err, usergridResponse) {
+            usergridResponse.entity.should.be.an.Object().with.property('relatedUuid').equal(options.body.relatedUuid)
+            done()
+        })
+    })
 })
 
 describe('DELETE()', function() {
 
-    this.slow(1000)
-    this.timeout(6000)
+    this.slow(_slow)
+    this.timeout(_timeout)
 
     var response, client
     before(function(done) {
@@ -189,12 +408,96 @@
             response.error.name.should.equal('entity_not_found')
         })
     }
+
+    it('should support deleting an entity by passing a UsergridEntity object', function(done) {
+
+        this.slow(_slow + 1000)
+        this.timeout(_timeout + 1000)
+
+        var entity = new UsergridEntity({
+            type: config.testCollection,
+            command: "CTRL+ALT+DEL"
+        })
+
+        client.POST(entity, function(err, usergridResponse) {
+            client.DELETE(usergridResponse.entity, function() {
+                client.GET(config.testCollection, usergridResponse.entity.uuid, function(err, delResponse) {
+                    delResponse.error.name.should.equal((config.target === '1.0') ? 'service_resource_not_found' : 'entity_not_found')
+                    done()
+                })
+            })
+        })
+    })
+
+    it('should support deleting an entity by passing type and uuid', function(done) {
+
+        this.slow(_slow + 1000)
+        this.timeout(_timeout + 1000)
+
+        var body = {
+            command: "CTRL+ALT+DEL"
+        }
+
+        client.POST(config.testCollection, body, function(err, usergridResponse) {
+            client.DELETE(config.testCollection, usergridResponse.entity.uuid, function() {
+                client.GET(config.testCollection, usergridResponse.entity.uuid, function(err, delResponse) {
+                    delResponse.error.name.should.equal((config.target === '1.0') ? 'service_resource_not_found' : 'entity_not_found')
+                    done()
+                })
+            })
+        })
+    })
+
+    it('should support deleting multiple entities by passing a UsergridQuery object', function(done) {
+
+        this.slow(_slow + 1000)
+        this.timeout(_timeout + 1000)
+
+        var entity = new UsergridEntity({
+            type: config.testCollection,
+            command: "CMD+TAB"
+        })
+
+        var query = new UsergridQuery(config.testCollection).eq('command', 'CMD+TAB')
+
+        client.POST([entity, entity, entity, entity], function(err, usergridResponse) {
+            client.DELETE(query, function() {
+                client.GET(query, function(err, delResponse) {
+                    delResponse.entities.should.be.an.Array().with.lengthOf(0)
+                    done()
+                })
+            })
+        })
+    })
+
+    it('should support deleting an entity by passing a preformatted DELETE builder object', function(done) {
+
+        this.slow(_slow + 1000)
+        this.timeout(_timeout + 1000)
+
+        var options = {
+            type: config.testCollection,
+            body: {
+                restaurant: "IHOP",
+                cuisine: "breakfast"
+            }
+        }
+
+        client.POST(options, function(err, usergridResponse) {
+            client.DELETE(_.extend(options, {uuid: usergridResponse.entity.uuid}), function() {
+                client.GET(config.testCollection, usergridResponse.entity.uuid, function(err, delResponse) {
+                    delResponse.error.name.should.equal((config.target === '1.0') ? 'service_resource_not_found' : 'entity_not_found')
+                    done()
+                })
+            })
+        })
+    })
 })
 
 describe('authenticateApp()', function() {
 
-    this.slow(1000)
-    this.timeout(6000)
+    this.slow(_slow)
+    this.timeout(_timeout)
 
     var response, token, client
     before(function(done) {
diff --git a/tests/lib/query.test.js b/tests/lib/query.test.js
index 1f9ab9b..6b3d298 100644
--- a/tests/lib/query.test.js
+++ b/tests/lib/query.test.js
@@ -1,7 +1,9 @@
 'use strict'
 
 var should = require('should'),
-    UsergridQuery = require('../../lib/query')
+    UsergridQuery = require('../../lib/query'),
+    UsergridClient = require('../../lib/client'),
+    config = require('../../helpers').config
 
 describe('_type', function() {
     it('_type should equal "cats" when passing "type" as a parameter to UsergridQuery', function() {
diff --git a/tests/lib/response.test.js b/tests/lib/response.test.js
index ee04173..ee2b43d 100644
--- a/tests/lib/response.test.js
+++ b/tests/lib/response.test.js
@@ -1,7 +1,7 @@
 'use strict'
 
 var should = require('should'),
-    config = require('../../helpers/config'),
+    config = require('../../helpers').config,
     UsergridClient = require('../../lib/client'),
     UsergridEntity = require('../../lib/entity'),
     UsergridUser = require('../../lib/user'),
@@ -84,15 +84,24 @@
     this.slow(1000)
     this.timeout(6000)
 
+    var user
+
     it('response.user should be a UsergridUser object and have a valid uuid matching the first object in response.users', function(done) {
         client.setAppAuth(config.clientId, config.clientSecret, config.tokenTtl)
         client.authenticateApp(function(err) {
             client.GET('users', function(err, usergridResponse) {
-                usergridResponse.user.should.be.an.instanceof(UsergridUser).with.property('uuid').equal(_.first(usergridResponse.users).uuid)
+                user = usergridResponse.user
+                user.should.be.an.instanceof(UsergridUser).with.property('uuid').equal(_.first(usergridResponse.entities).uuid)
                 done()
             })
         })
     })
+
+    it('response.user should also be a UsergridEntity object', function(done) {
+        user.isUser.should.be.true()
+        user.should.be.an.instanceof(UsergridEntity)
+        done()
+    })
 })
 
 describe('entities', function() {
diff --git a/tests/lib/responseError.test.js b/tests/lib/responseError.test.js
index 0d92cf6..c00dcba 100644
--- a/tests/lib/responseError.test.js
+++ b/tests/lib/responseError.test.js
@@ -1,7 +1,7 @@
 'use strict'
 
 var should = require('should'),
-    config = require('../../helpers/config'),
+    config = require('../../helpers').config,
     UsergridClient = require('../../lib/client'),
     UsergridResponseError = require('../../lib/responseError')
 
diff --git a/tests/lib/usergrid.test.js b/tests/lib/usergrid.test.js
index 817ee6b..59ce575 100644
--- a/tests/lib/usergrid.test.js
+++ b/tests/lib/usergrid.test.js
@@ -1,7 +1,7 @@
 'use strict'
 
 var should = require('should'),
-    config = require('../../helpers/config'),
+    config = require('../../helpers').config,
     Usergrid = require('../../usergrid'),
     UsergridClient = require('../../lib/client'),
     util = require('util'),