built.io
Version:
SDK for Built.io Backend
1,408 lines (1,347 loc) • 61 kB
JavaScript
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())
*