UNPKG

built.io

Version:

SDK for Built.io Backend

1,408 lines (1,347 loc) 61 kB
var R = require('ramda'); var utility = require('./utilities/utility'); var objectCons = require('./object'); var instanceMethodBuilder = require('./utilities/instanceMethodBuilder')(); var md5 = require("blueimp-md5").md5; var when = require('when'); var Built = require('./built'); var node = require("./node") /* Transforms that can be applied on query response */ var SDK_TRANSFORM = 'SDK_TRANSFORM'; var BACKBONE_TRANSFORM = 'BACKBONE_TRANSFORM'; var JSON_TRANSFORM = 'JSON_TRANSFORM'; /** * @class Query * @classdesc * A class that defines a query on Built.io Backend * @instance * @description * Constructs a query with initial query conditions * @param {object} conditions Plain JavaScript object specifying conditions * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query * .where('username','John') * .exec() * .then(function(objects){ * // objects having username field with value 'John' * }); * @return {Query} */ var queryCons = module.exports = R.curry(function(app,cls,headers,cachePolicy,data) { var returnObj = { app: app, cls: cls, headers: headers, cachePolicy:cachePolicy, data: data || {} } return instanceMethodBuilder.build(module.exports,returnObj); }) var getConditions = module.exports.getConditions = R.prop('data'); instanceMethodBuilder.define('getConditions',1); var getQueryObj = module.exports.getQueryObj = R.compose(R.prop('query'),getConditions) instanceMethodBuilder.define('getQueryObj',1); module.exports.getTransform = R.compose(R.prop('transform'),R.prop('data')); instanceMethodBuilder.define('getTransform',1); /** * Returns the result as an array of plain JavaScript objects * @function toJSON * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query * .toJSON() * .exec() * .then(function(objects){ * // array of plain javascript objects * console.log(objects); * }); * @return {Query} */ module.exports.toJSON = function(query){ var newConds = R.mixin({},getConditions(query)); newConds['transform'] = JSON_TRANSFORM; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); } instanceMethodBuilder.define('toJSON',1); /** * Returns the result as a Backbone collection * @function toBackbone * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query * .toBackbone() * .exec() * .then(function(res){ * console.log(res); // Backbone collection * }); * @return {Query} */ module.exports.toBackbone = function(query){ var newConds = R.mixin({},getConditions(query)); newConds['transform'] = BACKBONE_TRANSFORM; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); } instanceMethodBuilder.define('toBackbone',1); /** * Set a header in query * @function setHeader * @param {String} header The header key * @param {String} value The header value * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.setHeader('My-Custom-Header','MyValue'); * @return {Query} */ var setHeader = module.exports.setHeader = R.curry(function(header,value,query) { //setHeader var existingHeaders = query.headers; var newHeader = R.mixin({},existingHeaders); newHeader[header] = value; return queryCons(query.app,query.cls,newHeader,query.cachePolicy,getConditions(query)); }); instanceMethodBuilder.define('setHeader',3); /** * Removes a header from a query * @function removeHeader * @param {String} header The header that needs to be removed * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.removeHeader('My-Custom-Header'); * @return {Query} */ var removeHeader = module.exports.removeHeader = R.curry(function(header,query) { var existingHeaders = query.header; var newHeader = R.mixin({},existingHeaders); delete newHeader[header]; return queryCons(query.app,query.cls,newHeader,query.cachePolicy,getConditions(query)); }); instanceMethodBuilder.define('removeHeader',2); /** * Sets the master key for a query * @function setMasterKey * @param {String} masterKey The master key value * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.setMasterKey('blt111sample24a6b'); * @return {Query} */ module.exports.setMasterKey = setHeader('master_key') instanceMethodBuilder.define('setMasterKey',2); /** * Removes the master key from Query * @function removeMasterKey * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.removeMasterKey(); * @return {Query} */ module.exports.removeMasterKey = removeHeader('master_key'); instanceMethodBuilder.define('removeMasterKey',1); /** * Gets the header object for this query * @function getHeaders * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * var headers = query.getHeaders(); * @return {object} */ module.exports.getHeaders = function(query) { return query.headers; } instanceMethodBuilder.define('getHeaders',1); module.exports.getCombinedHeaders = function(query) { var Cls = require('./class'); var clsHeaders = Cls.getCombinedHeaders(query.cls); var combinedHeaders = R.mixin(clsHeaders.headers,query.headers) return combinedHeaders; } instanceMethodBuilder.define('getCombinedHeaders',1); var existsHelper = R.curry(function(bool,field_uid,query){ var newConds = R.mixin({},getConditions(query)); var newQuery = R.mixin({},getQueryObj(query)); newQuery[field_uid] = { $exists : bool }; newConds.query = newQuery; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }); /** * Gets all the object in which a value exists for a given field. i.e. Any object which has a value of 'undefined' for that field is filtered. * @function exists * @param {String} field_uid The field whose value is to be checked * @memberof Query * @instance * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * // Fetches all the objects that have have a value for "name" field * query * .exists('name'); * .exec() * .then(function(objects){ * console.log(objects[0].toJSON()) * }); * @return {Query} */ module.exports.exists = existsHelper(true); instanceMethodBuilder.define('exists',2); /** * Gets all the object in which a value does not exists for a given field. i.e. Any object which has a value other than 'undefined' for that field is rejected. * @function doesNotExists * @param {String} field_uid The field whose value is to be checked * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * // Fetches all the objects that don't have a value for "name" field * query = query.doesNotExists('name'); * query.exec() * .then(function(objects){ * }); * @return {Query} */ module.exports.doesNotExists = existsHelper(false); instanceMethodBuilder.define('doesNotExists',2); var selectionHelper = R.curry(function(selectString,field_uid,queryObj,pickFieldUid,query){ var newConds = R.mixin({},getConditions(query)); var newQuery = R.mixin({},getQueryObj(query)); newQuery[field_uid] = utility.keyValue(selectString,{ query : getConditions(queryObj).query, class_uid : queryObj.cls.uid, key : pickFieldUid }); newConds.query = newQuery; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }); /** * Fires a select query on another class and gets objects that pass the query conditions. Similar to 'Joins' in relational databases like SQL. * @function select * @param {String} primaryKey Field in base class which should be used in join. * @param {Query} query Query to be fired on the referred class. * @param {String} foriegnKey Field in referred class which should be used in join. * @instance * @memberof Query * @example * // Example statement: Consider a class Person which has a reference field 'location', which refers to 'Address' class. * // You should execute the below given query to retrieve all persons who live in 'Mumbai'; * * //First lets create a query which retrieves all objects of 'Address' class having 'city' as 'Mumbai'. * * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var queryOnAddressCls = Built.App('blt5d4sample2633b').Class('address').Query() * .where('city', 'Mumbai'); * * // Now we can create a select query for retriving all persons from 'Person' class whoses location is 'Mumbai'. * * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * // 'location' field contains uid of the address object whose city field is Mumbai * .select('location', queryOnAddressCls, 'uid') * .exec() * .then(function(objects){ * // Fetches all person who live in Mumbai. * }); * @return {Query} */ module.exports.select = selectionHelper('$select'); instanceMethodBuilder.define('select',4); /** * Fires a select query on another class and gets objects that do not pass the query conditions. Similar to 'Joins' in relational databases like SQL. * @function dontSelect * @param {String} primaryKey Field in base class which should be used in join. * @param {Query} query Query to be fired on the referred class. * @param {String} foriegnKey Field in referred class which should be used in join. * @instance * @memberof Query * @example * // Example statement: Consider a class Person which has a reference field 'location', which refers to 'Address' class. * // You should execute the below given query to retrieve all persons who do not live in 'Mumbai'; * * // First lets create a query which retrieves all objects of 'Address' class having 'city' as 'Mumbai'. * * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var queryOnAddressCls = Built.App('blt5d4sample2633b').Class('address').Query() * .where('city', 'Mumbai'); * * // Now we can create a select query for retriving all persons from 'Person' class whoses location is not 'Mumbai'. * * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * //'location' field contains uid of the address object whose city field anything other than Mumbai. * .dontSelect('location', queryOnAddressCls, 'uid') * .exec() * .then(function(objects){ * // Fetches all person who don't live in Mumbai. * }); * @return {Query} */ module.exports.dontSelect = selectionHelper('$dont_select'); instanceMethodBuilder.define('dontSelect',4); /** * Gets the objects that match the where condition * @function where * @param {String} key The key * @param {String} value The value * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.where('name','Super Project #41!'); * query * .exec() * .then(function(objects){ * //fetches all the objects whose name is 'Super Project #41!' * }); * @return {Query} */ module.exports.where = R.curry(function(key,value,query) { var newConds = R.mixin({},getConditions(query)); var newQuery = R.mixin({},getQueryObj(query)); // to make it like mongoSDK if(utility.isPlainObject(key)){ newQuery = R.mixin(newQuery, key) } else{ newQuery[key] = value; } newConds.query = newQuery; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }) instanceMethodBuilder.define('where',3, [null]); /** * Custom query parameter can be sent * @function addQueryParams * @param {String} key Query parameter name. * @param {String} value Query parameter value. * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * var query = query.addQueryParams('Custom_Query_Parameter','Custom_Value'); * query.exec() * .then(function(objects){ * // Objects that pass the query condtion * }); * @instance * @memberof Query * @return {Query} */ var addQueryParams = module.exports.addQueryParams = R.curry(function(key,value,query){ var newConds = R.mixin({},getConditions(query)); newConds[key] = value; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }); instanceMethodBuilder.define('addQueryParams',3); /** * Includes the count of the number of objects returned along with the actual objects in response * @function includeCount * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.includeCount(); * @return {Query} */ module.exports.includeCount = addQueryParams('include_count',true); instanceMethodBuilder.define('includeCount',1); /** * Gets only the count of the number of objects that pass the query condition * @function count * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.count(); * query.exec() * .then(function(count){ * // count of the number of objects fetched * }) * @return {Query} */ module.exports.count = addQueryParams('count',true); instanceMethodBuilder.define('count',1); /** * By default, when a object is fetched referenced object's uids are returned in response. Using this method you can * retrieve the reference object itself. * @function include * @param {Array} field_Uids Array of reference field uids whose actual referenced object is to be included * @instance * @memberof Query * @example * //<b> Consider a Bugs class has a reference field "project" which is referring to Project class.</b> * //<b> This function would include all objects that are referred by "project" field</b> * * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'bugs' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('bugs').Query(); * query = query.include(['project']); * @return {Query} */ module.exports.include = addQueryParams('include'); instanceMethodBuilder.define('include',2); /** * Skip 'n' number of objects * @function skip * @param {Number} number The number of objects to be skipped * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.skip(5); * @return {Query} */ module.exports.skip = addQueryParams('skip'); instanceMethodBuilder.define('skip',2); /** * Limits the response to contain only 'n' number of objects * @function limit * @param {Number} number The number of objects to be limited * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * // Would return only five objects even if more than five objects pass the condition * query = query.limit(5); * @return {Query} */ module.exports.limit = addQueryParams('limit'); instanceMethodBuilder.define('limit',2); /** * Includes owner information for each object in the response * @function includeOwner * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.includeOwner(); * @return {Query} */ module.exports.includeOwner = addQueryParams('include_owner',true); instanceMethodBuilder.define('includeOwner',1); /** * Include the schema in response * @function includeSchema * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.includeSchema(); * @return {Query} */ module.exports.includeSchema = addQueryParams('include_schema',true); instanceMethodBuilder.define('includeSchema',1); /** * Includes all unpublished objects of a class * @function includeDrafts * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.includeDrafts(); * @return {Query} */ module.exports.includeDrafts = addQueryParams('include_unpublished',true); instanceMethodBuilder.define('includeDrafts',1); /** * Includes only unpublished objects of a class * @function onlyDrafts * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backend * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.onlyDrafts(); * @return {Query} */ module.exports.onlyDrafts = function(query){ var incDraftQuery = query.includeDrafts(); var newConds = R.mixin({},getConditions(incDraftQuery)); var newQuery = R.mixin({},getQueryObj(incDraftQuery)); newQuery['published'] = false; newConds.query = newQuery; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); } instanceMethodBuilder.define('onlyDrafts',1); var inQueryHelper = R.curry(function(operator,field_uid,queryObj,query){ var newConds = R.mixin({},getConditions(query)); var newQuery = R.mixin({},getQueryObj(query)); newQuery[field_uid] = utility.keyValue(operator,getQueryObj(queryObj)); //eg {"$in_query": {"author": "James"}} newConds.query = newQuery; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }); /** * Applies query on the referenced class' objects and fetches all objects from the referring(base) class which referred to these filtered out referenced objects * @function inQuery * @param {String} field_uid The uid of reference field * @param {Query} queryObj The query that should be applied on the referenced class' objects * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query returns a 'Query' constructor * // 'project' is a uid of a class on Built.io Backend * // 'bugs' is a uid of a class on Built.io Backed * * // Consider class Bugs has a reference field 'project' which refers the Project class * * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('bugs').Query(); * * // Query which would be applied on Project class * var whereQuery = query.where('name','Super Project #41!'); * * var inQuery = query.inQuery('project', whereQuery); * inQuery * .exec() * .then(function(res){ * //Returns all objects from Bugs class whose 'project' field references to Project class objects that have name as 'Super Project #41!' * }); * @instance * @memberof Query * @return {Query} */ module.exports.inQuery = inQueryHelper('$in_query'); instanceMethodBuilder.define('inQuery',3); /** * Applies query conditions on referenced class' objects and fetches all objects from the referring class that did not refer to these objects * @function notInQuery * @param {String} field_uid The uid of reference field * @param {Query} queryObj Query object containing the query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query returns a 'Query' constructor * // 'bugs' is a uid of a class on Built.io Backed * // Consider class Bugs has a reference field 'project' which refers the Project class * * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('project').Query(); * * // Query which would be applied on Project class * var whereQuery = query.where('name','Super Project #41!'); * * var inQuery = query.notInQuery('project',whereQuery); * inQuery.exec().then(function(res){ * //Returns all objects from Bugs class whose 'project' field references to Project class objects that don't have name as 'Super Project #41!' * }); * @instance * @memberof Query * @return {Query} */ module.exports.notInQuery = inQueryHelper('$nin_query'); instanceMethodBuilder.define('notInQuery',3); /** * Gets all the objects that match the regular expression * @function matches * @param {String} field_uid The field on which the regular expression is applied * @param {String} regex The regular expression * @param {String} options Options for regular expression (Optional Defaults to 'i') * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('project').Query(); * // Fetches all objects whose name start with 'abc' * query = query.matches('name','^abc'); * @return {Query} */ module.exports.matches = R.curry(function(field_uid,regex,options,query){ var newConds = R.mixin({},getConditions(query)); var newQuery = R.mixin({},getQueryObj(query)); newQuery[field_uid] ={ '$regex' : regex, '$options':options } newConds.query = newQuery; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }); instanceMethodBuilder.define('matches',4,['i']); /** * Fetches all the objects that are within a specified location * @function withinLocation * @param {Array} locations Can be an array of Built.Location instances or an array of object uids whose location is to be used. (Atleast three locations are required) * @instance * @memberof Query * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * * var location1 = Built.Location(60,80); * var location2 = Built.Location(41,90); * var location3 = Built.Location(52,72); * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.withinLocation([location1, location2, location3]); * @return {Query} */ module.exports.withinLocation = R.curry(function(locations,query){ var newConds = R.mixin({},getConditions(query)); var newQuery = R.mixin({},getQueryObj(query)); if(utility.isArray(locations)){ if(locations.length < 3){ throw new Error("Minimum 3 locations or objectUids required"); } var withInLoc = locations.map(function(loc) { if (loc.data) { return [loc.toJSON().longitude, loc.toJSON().latitude]; } else if(utility.isString(loc)) { return {object: loc} } else { throw new Error('Invalid parameter'+loc); } }) }else{ throw new Error('Locations should be a Array'); } newQuery['$within'] = withInLoc; newConds.query = newQuery; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }); instanceMethodBuilder.define('withinLocation',2); /** * Gets the objects that have its field value matching the contents of array * @function containedIn * @param {String} uid The field's uid * @param {Array} array The array against which the field value will be compared * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query returns a 'Query' constructor * // 'project' is a uid of a class on Built.io Backed * var app = Built.App('blt5d4sample2633b'); * var Query = app.Class('project').Query; * var query = Query(); * query = query.containedIn('severity',["Show Stopper","Critical"]) * query.exec() * .then(function(query){ * // Fetches all objects that have severity as "Show Stopper" or "Critical" * }); * @return {Query} */ module.exports.containedIn = R.curry(function(key, array, query) { var newConds = R.mixin({},getConditions(query)); var newQuery = R.mixin({},getQueryObj(query)); if(!utility.isArray(array)){ array = [array]; } newQuery[key] = { "$in": array }; newConds.query = newQuery; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }) instanceMethodBuilder.define('containedIn',3); /** * Gets the objects that don't have its field value matching the contents of array * @function notContainedIn * @param {String} uid The field's uid * @param {Array} array The array against which the field value will be compared * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query returns a 'Query' constructor * // 'project' is a uid of a class on Built.io Backed@example * var app = Built.App('blt5d4sample2633b'); * var Query = app.Class('project').Query; * var query = Query(); * query = query.notContainedIn('severity',["Show Stopper","Critical"]) * query.exec() * .then(function(query){ * // Fetches all objects which don't have severity as "Show Stopper" or "Critical" * }); * @return {Query} */ module.exports.notContainedIn = R.curry(function(uid,array,query) { var newConds = R.mixin({},getConditions(query)); var newQuery = R.mixin({},getQueryObj(query)); if(!utility.isArray(array)){ array = [array]; } newQuery[uid] = { "$nin": array }; newConds.query = newQuery; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }) instanceMethodBuilder.define('notContainedIn',3); /** * Gets the objects in ascending order * @function ascending * @param {String} uid Uid of the field based on which the ordering should be done * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query returns a 'Query' constructor * // 'project' is a uid of a class on Built.io Backed * var app = Built.App('blt5d4sample2633b'); * var Query = app.Class('project').Query; * var query = Query(); * query = query.ascending('name'); * @return {Query} */ module.exports.ascending = addQueryParams('asc'); instanceMethodBuilder.define('ascending',2); /** * Gets the objects in descending order * @function descending * @param {String} uid Uid of the field based on which the ordering should be done * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query returns a 'Query' constructor * // 'project' is a uid of a class on Built.io Backed * var app = Built.App('blt5d4sample2633b'); * var Query = app.Class('project').Query; * var query = Query(); * query = query.descending('name'); * @return {Query} */ module.exports.descending = addQueryParams('desc'); instanceMethodBuilder.define('descending',2); var andOrHelper = R.curry(function(str,queryArray,query){ var newConds = R.mixin({},getConditions(query)); var newQuery = R.mixin({},getQueryObj(query)); newQuery[str] = []; for (var i = 0; i < queryArray.length; i++) { var tempQuery = getConditions(queryArray[i]); newQuery[str].push(tempQuery.query); newConds = R.mixin(newConds, tempQuery) }; newConds.query = newQuery; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }); /** * Combines all the queries together using AND operator * @function and * @param {Array} queryArray Array of query objects * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('project').Query(); * var query1 = query.where('name','Super Project #41!'); * var query2 = query.where('description','Small description'); * var queryArray = [query1,query2]; * var andQuery = query.and(queryArray); * @instance * @memberof Query * @return {Query} */ module.exports.and = andOrHelper('$and'); instanceMethodBuilder.define('and',2); /** * Combines all the queries together using OR operator * @function or * @param {Array} queryArray Array of Query objects containing conditions * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('project').Query(); * var query1 = query.where('name','Super Project #41!'); * var query2 = query.where('description','Small description'); * var queryArray = [query1,query2]; * var orQuery = query.or(queryArray); * @return {Query} */ module.exports.or = andOrHelper('$or'); instanceMethodBuilder.define('or',2); var equalityHelper = R.curry(function(operator,field_uid,value,query){ var newConds = R.mixin({},getConditions(query)); var newQuery = R.mixin({},getQueryObj(query)); newQuery[field_uid] = utility.keyValue(operator,value); newConds.query = newQuery; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }); /** * Gets all the objects that have its field_uid's value greater than the given value * @function greaterThan * @param {String} field_uid The uid of the field that needs to be compared * @param {Number} value A numeric value * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'milestone' is a uid of a class on Built.io Backed * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('milestone').Query(); * query.greaterThan('end_date',new Date()); * @return {Query} */ module.exports.greaterThan = equalityHelper('$gt'); instanceMethodBuilder.define('greaterThan',3); /** * Gets all the objects that have its field_uid's value greater than or equal to the given value * @function greaterThanOrEqualTo * @param {String} field_uid The uid of the field that needs to be compared * @param {Number} value A numeric value * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'milestone' is a uid of a class on Built.io Backed * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('milestone').Query(); * query.greaterThanOrEqualTo('end_date',new Date()); * @return {Query} */ module.exports.greaterThanOrEqualTo = equalityHelper('$gte'); instanceMethodBuilder.define('greaterThanOrEqualTo',3); /** * Gets all the objects that have its field_uid's value less than the given value * @function lessThan * @param {String} field_uid The uid of the field that needs to be compared * @param {Number} value A numeric value * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'milestone' is a uid of a class on Built.io Backed * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('milestone').Query(); * query.lessThan('end_date',new Date()); * @return {Query} */ module.exports.lessThan = equalityHelper('$lt'); instanceMethodBuilder.define('lessThan',3); /** * Gets all the objects that have its field_uid's value less than or equal to the given value * @function lessThanOrEqualTo * @param {String} field_uid The uid of the field that needs to be compared * @param {Number} value A numeric value * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'milestone' is a uid of a class on Built.io Backed * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('milestone').Query(); * query.lessThanOrEqualTo('end_date',new Date()); * @return {Query} */ module.exports.lessThanOrEqualTo = equalityHelper('$lte'); instanceMethodBuilder.define('lessThanOrEqualTo',3); /** * Gets all the object that have its field_uid's value not equal to the given value * @function notEqualTo * @param {String} field_uid The uid of the field that needs to be compared * @param {Number} value A numeric value * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'milestone' is a uid of a class on Built.io Backed * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('milestone').Query(); * query.notEqualTo('end_date',new Date()); * @return {Query} */ module.exports.notEqualTo = equalityHelper('$ne'); instanceMethodBuilder.define('notEqualTo',3); /** * Sets the a cache policy for this query * @function setCachePolicy * @param {Number} value A numeric value * @throws new Error("Invalid cache policy"); * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * query = query.setCachePolicy(Built.CachePolicy.CACHE_ELSE_NETWORK); * @return {Query} */ module.exports.setCachePolicy = R.curry(function(cachePolicy,query){ if(query.app.validateCachePolicy(cachePolicy)) return queryCons(query.app,query.cls,query.headers,cachePolicy,getConditions(query)); else throw new Error("Invalid cache policy"); }); instanceMethodBuilder.define('setCachePolicy',2); var setInCache = R.curry(function (key,value){ if(utility.isLocalStroageAvaliable()) { try{ localStorage.setItem(key,JSON.stringify(value)) } catch(e){ if(!e.stack) console.log("built.io sdk | Cache Error", e) } } return value; }); var deltaHelper = R.curry(function(type,date,query){ if(date instanceof Date) date = date.toISOString(); var newConds = R.mixin({},getConditions(query)); var newDelta = R.mixin({},newConds.delta); newDelta[type] = date; newConds['delta'] = newDelta; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); }); /** * Gets the objects that were created on or after the given date * @function deltaCreatedFrom * @param {Date|String} date Instance of Date or a string in the following format 'YYYY-MM-DD' * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * * //<b>Example demonstrate method accepting a formated string as date. </b> * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * var query = query.deltaCreatedFrom('2014-09-02'); * query.exec() * .then(function(object)({ * // object.created is array of all objects that * // were created on or after the given date * })); * * //<b>Example demonstrate method accepting a date instance.</b> * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * var query = query.deltaCreatedFrom(new Date()); * query.exec() * .then(function(object)({ * // object.created is array of all objects that * // were created on or after the given date * })); * @return {Query} */ var deltaCreatedFrom = module.exports.deltaCreatedFrom = deltaHelper("created_at"); instanceMethodBuilder.define('deltaCreatedFrom',2); /** * Gets the objects that were updated on or after the given date * @function deltaUpdatedFrom * @param {Date|String} date Instance of date or a string in the following format 'YYYY-MM-DD'. * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * * //<b>Example demonstrate method accepting a formated string as date. </b> * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * var query = query.deltaUpdatedFrom('2014-09-02'); * query.exec() * .then(function(object)({ * // object.updated is array of all objects that were updated on * //or after the given date * })); * * //<b>Example demonstrate method accepting a date instance.</b> * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * var query = query.deltaUpdatedFrom(new Date()); * query.exec() * .then(function(object)({ * // object.updated is array of all objects that were updated on * //or after the given date * })); * @return {Query} */ var deltaUpdatedFrom = module.exports.deltaUpdatedFrom = deltaHelper("updated_at"); instanceMethodBuilder.define('deltaUpdatedFrom',2); /** * Gets the objects which were deleted on or after the given date * @function deltaDeletedFrom * @param {Date|String} date Instance of Date or a string in the following format 'YYYY-MM-DD' * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * * //<b>Example demonstrate method accepting a formated string as date. </b> * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * var query = query.deltaDeletedFrom('2014-09-02'); * query.exec() * .then(function(object)({ * // object.deleted is array of all objects that were deleted on or * // after the given date * })); * * //<b>Example demonstrate method accepting a date instance.</b> * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * var query = query.deltaDeletedFrom(new Date()); * query.exec() * .then(function(object)({ * // object.deleted is array of all objects that were deleted on or * // after the given date * })); * @return {Query} */ var deltaDeletedFrom = module.exports.deltaDeletedFrom = deltaHelper("deleted_at"); instanceMethodBuilder.define('deltaDeletedFrom',2); /** * Get the objects which were created, updated or deleted on or after the given date * @function deltaAll * @param {Date|String} date Instance of Date or a string in the following format 'YYYY-MM-DD' * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * //<b>Example demonstrate method accepting a formated string as date. </b> * var query = query.deltaAll('2014-09-02'); * query.exec() * .then(function(object)({ * // object.created //is a array of all object that were created on or after the given date. * // object.updated //is a array of all object that were update on or after the given date. * // object.deleted //is a array of all object that were deleted on or after the given date. * })); * //<b>Example demonstrate method accepting a date instance.</b> * var query = Built.App('blt5d4sample2633b').Class('project').Query(); * var query = query.deltaAll(new Date()); * @return {Query} */ module.exports.deltaAll = deltaHelper("ALL"); instanceMethodBuilder.define('deltaAll',2); var objectWrapper = R.curry(function(query, response) { var objCons = query.cls.ObjectCons; var keys = Object.keys(response); var objs = response.objects; var transform = query.getTransform(); var transformFn = sdkTransformer(objCons); // Applies the appropriate object transformer switch(transform){ case BACKBONE_TRANSFORM : transformFn = backboneTransformer(objCons); // Curried its first arguement break; case JSON_TRANSFORM : transformFn = jsonTransformer; break; } if (keys.length > 1) { var returnArray = []; returnArray.push(handleResponseObjects(objs, transformFn)); if (response.schema) returnArray.push(response.schema); if (response.count) returnArray.push(response.count); return returnArray; } else { if (utility.isNumber(objs)) return objs else return handleResponseObjects(objs, transformFn); } }); function handleResponseObjects(objs,transformFn) { if (utility.isArray(objs)) { return transformFn(objs); } else{ return constructDelta(objs, transformFn); } } function constructDelta(obj, transformFn) { var deltaObj = {}; if (obj.created_at) deltaObj["created"] = transformFn(obj.created_at); if (obj.deleted_at) deltaObj["deleted"] = transformFn(obj.deleted_at); if (obj.updated_at) deltaObj["updated"] = transformFn(obj.updated_at); return deltaObj; } var sdkTransformer = R.curry(function(objCons,objArray) { return objArray.map(function(obj){ return objCons({},{},obj,{}); }); }); var backboneTransformer = R.curry(function(objCons,objArray){ var sdkObjects = sdkTransformer(objCons, objArray); var backboneCollection = objCons.BackboneCollection({ objects: sdkObjects }); return backboneCollection; }); function jsonTransformer(objArray){ return objArray; } /** * Executes the query * @function exec * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('project').Query({ * name:'John' * }); * //<b>Normal Query</b> * query.exec() * .then(function(objects)({ * // Fetches all objects having name John * })); * * //<b>Query containing query.includeCount() </b> * query * .includeCount() * .exec() * .spread(function(objects,count)({ * //"objects" is array of objects return. * //"count" is the number of objects returned. * })); * //<b>Query containing query.includeCount() and query.includeSchema() </b> * query * .includeCount() * .includeSchema() * .exec() * .spread(function(objects,schema,count)({ * //"objects" is array of objects returned. * //"count" is the number of objects returned. * })); * //<b>Query containing query.count()</b> * query * .count(); * .exec() * .then(function(count)({ * //Count is the number of objects returned. * })); * * //<b>When a query consists of a delta parameter, the response is plain javascript object with keys for each delta</b> * var app = Built.App('blt5d4sample2633b'); * var query = app.Class('project').Query({ * name:'John' * }); * query.deltaCreatedFrom(new Date()) * .exec() * .then(function(result)({ * // result.created is array of all objects that were created on or * // after the given date * })); * * //<b>When an query is following Built.CachePolicy.CACHE_THEN_NETWORK the ouput structure is as follows</b> * query.setCachePolicy(Built.CachePolicy.CACHE_THEN_NETWORK); * var result = query.exec(); // This is the only use case where exec returns an object and not a promise. * * //object.cache is a promise that is resloved when data is avaliable through cache. * result.cache.then(function(objects){ * // objects is array of SDK objects * }); * * //object.network is a promise that is resloved when data is avaliable through network. * result.network.then(function(objects){ * // objects is array of SDK objects * }); * * // object.both is a function that accepts a callback which is executed twice, * // once when the data is avaliable through cache and then again when its avaliable through network. * result.both(function(error,data){ * // error is the network error. * }); * @return {Promise<Variable>} */ module.exports.exec = function(query) { var hashKey = getHashFor(getQueryGist(query)); var curriedSetInCache = setInCache(hashKey); var curriedObjectWrapper = objectWrapper(query); switch(query.cachePolicy){ case Built.CachePolicy.ONLY_NETWORK: return getFromNetwork(query) .then(curriedObjectWrapper); break; case Built.CachePolicy.CACHE_ELSE_NETWORK: return getFromCache(hashKey) .then(curriedObjectWrapper) .catch(function(){ return getFromNetwork(query) .then(curriedSetInCache) .then(curriedObjectWrapper); }); break; case Built.CachePolicy.NETWORK_ELSE_CACHE: return getFromNetwork(query) .then(curriedSetInCache) .then(curriedObjectWrapper) .catch(function(networkError){ return getFromCache(hashKey) .then(curriedObjectWrapper) .catch(function(){ throw networkError; }) }); break; case Built.CachePolicy.CACHE_THEN_NETWORK: var bothCallback = function() {} return { cache : getFromCache(hashKey) .then(curriedObjectWrapper) .then(function(cacheData){ bothCallback(null, cacheData); return cacheData; }), network : getFromNetwork(query) .then(curriedSetInCache) .then(curriedObjectWrapper) .then(function(networkData){ bothCallback(null,networkData); return networkData; }) .catch(function(error){ bothCallback(error,null); }), both : function(cb) {bothCallback=cb} } break; } } instanceMethodBuilder.define('exec',1); /** * Whenever you execute a query that contains some dynamic field, it generates a new hashkey everytime. * Using this method, you can restrict the query from creating a new hashkey whenever it is executed. * It blacklists the given fields, and returns the same hashkey everytime. * @function setBlacklist * @param {Array} fieldUidArray Array of field uid's which are to be blacklisted * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * * //<b>Example demonstrate method accepting a updated_at field. </b> * var query = Built.App('blt5d4sample2633b') * .setCachePolicy(Built.CachePolicy.CACHE_ELSE_NETWORK) * .Class('project').Query(); * var query = query * .lessThan('updated_at', new Date()) * .setBlacklist(['updated_at']); * var result = project.exec(); * * result.cache.then(function(objects){ * // objects from cache * }); * * result.network.then(function(objects){ * // objects from network * }); * @return {Query} */ module.exports.setBlacklist = function(array, query) { if(!utility.isArray(array)){ throw new Error("Expected 'Array' found '"+ typeof(array)+"'") } var newConds = R.mixin({},getConditions(query)); newConds['blacklists'] = array; return queryCons(query.app,query.cls,query.headers,query.cachePolicy,newConds); } instanceMethodBuilder.define('setBlacklist',2); /** * Get the array of all the Blacklisted fields * @function getBlacklist * @instance * @memberof Query * @example * // 'blt5d4sample2633b' is a dummy Application API key * // 'Class('class_name').Query() returns a 'Query' instance * // 'project' is a uid of a class on Built.io Backed * * //<b>Example demonstrate method accepting a updated_at field. </b> * var query = Built.App('blt5d4sample2633b') * .setCachePolicy(Built.CachePolicy.CACHE_ELSE_NETWORK) * .Class('project').Query(); * var query = query * .lessThan('updated_at', new Date()) *