built.io
Version:
SDK for Built.io Backend
575 lines (550 loc) • 17.8 kB
JavaScript
var R = require('ramda');
var utility = require('./utilities/utility');
var instanceMethodBuilder = require('./utilities/instanceMethodBuilder')();
var Built = require('./built');
var dummyString = "$dummy"
/**
* @class Group
* @classdesc
* A Group is special type of field in Built.io Backend. The reason its named such is that its a set of fields grouped together.
* Each group field has its own schema and can contain sub-groups.
* @instance
* @description This should be used to represent a 'group field' in your class.
* This representation can then be passed to methods that accept a Built.Group structure as argument.
* @param {String} fieldUid The Uid of the field in your class schema.
* @param {object|Built.Group|Built.GroupMultiple} data Can be 1] Plain JavaScript object representing intial values 2] Instance of Built.Group (sub-group) 3] Instance of Built.GroupMultiple (sub-group)
* @example
* <h3><u>Constructor accepting Plain JavaScript Object</u></h3>
* var person = Built.Group('person', {
* name: 'John',
* age: 22
* });
* <h3><u>Constructor accepting instance of Built.Group</u></h3>
* // To construct structure in which a group field contains a sub-group use syntax shown below
* var address = Built.Group('address', {
* city: 'Mumbai',
* state: 'Maharashtra'
* });
* var person = Built.Group('person', address);
* console.log(person.toJSON())
* @return {Group}
*/
var groupCons = module.exports = R.curry(function(field, value) {
var data = {}
if(!utility.isObject(value) || utility.isArray(value)){
throw new Error("Expected JavaScript Object found '"+ typeof(value)+"'")
}
// If value is Built.Group or Built.GroupMultiple we need to Deserialize
if (value.toJSON) {
value = value.toJSON()
}
// Deserializing sub structure(Example a property could be assigned a Built.Upsert object)
// value = utility.deserializeObject(value)
value = JSON.parse(JSON.stringify(value))
data[field] = value;
var returnObj = {
data : data,
field : field,
_isGroup : true,
toJSON : function() {
if(field === dummyString){
return data[field]
}
return data
}
}
return instanceMethodBuilder.build(module.exports, returnObj)
})
/**
* Use this method to add a new key value pair in group.
* <p class="text-danger">
* [Does not modify the Class Schema]
* </p>
* @memberof Group
* @function set
* @param {String} key The key for the new property
* @param {String} value Value for the new property
* @instance
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* var group = Built.Group('person', {
* name: 'John'
* })
* group = group.set('age', 22)
* @return {Group}
*/
module.exports.set = R.curry(function(key, value, group){
var newGroupField = getMixinedObject({}, group)
newGroupField[key] = value
return groupCons(group.field, newGroupField);
});
instanceMethodBuilder.define('set', 3)
/**
* Gets the data for the given property
* @memberof Group
* @function get
* @param {String} property The property whose data is to be fetched
* @instance
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* var group = Built.Group('person', {
* name: 'John'
* })
* console.log(group.get('name'))
* @return {variable}
*/
module.exports.get = R.curry(function(grpField, group){
if(group.field === dummyString){
return group.toJSON()[grpField]
}
var data = group.toJSON()
return data[group.field][grpField]
});
instanceMethodBuilder.define('get', 2)
/**
* To set multiple key value pair in group use this method.
* <p class="text-danger">
* [Does not modify the Class Schema]
* </p>
* @memberof Group
* @function assign
* @param {object} data Plain JavaScript object containing the new parameters
* @instance
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* var group = Built.Group('person', {
* name: 'John'
* })
* group = group.assign({
* age: 22,
* gender: 'Male'
* })
@return {Group}
*/
module.exports.assign = R.curry(function(jsObj, group){
var newGroupField = getMixinedObject({}, group)
newGroupField = R.mixin(jsObj, newGroupField)
return groupCons(group.field, newGroupField);
});
instanceMethodBuilder.define('assign', 2)
/**
* To delete a property from group
* <p class="text-danger">
* [Does not modify the Class Schema]
* </p>
* @memberof Group
* @function remove
* @param {String} key Key of the property to be removed
* @instance
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* var group = Built.Group('person', {
* name: 'John',
* age: 22
* })
* group = group.remove('age')
* @return {Group}
*/
module.exports.remove = R.curry(function(key, group){
var newGroupField = getMixinedObject({}, group);
if(newGroupField[key])
delete newGroupField[key]
return groupCons(group.field, newGroupField);
})
instanceMethodBuilder.define('remove', 2)
var pushPullHelper = R.curry(function(operation,key, value, index, group) {
// Value can be instance of GroupMultiple
if(value.toJSON){
value = value.toJSON()[key]
}
//index = "" indicated append operation
if(index !== "" && !utility.isNumber(index)){
throw new Error('Index value inappropriate');
}
//operation can be PUSH or PULL
var ops = utility.keyValue(key, utility.keyValue(operation, {
data : value,
index : index
}));
var mixedObject = getMixinedObject(ops, group)
return groupCons(group.field, mixedObject);
})
var referenceHelper = R.curry(function(fieldUid, value, group){
// deserilizing all objects if any are present
value = JSON.parse(JSON.stringify(value))
var mixedObject = getMixinedObject({}, group)
mixedObject[fieldUid] = value
return groupCons(group.field, mixedObject)
})
/**
* Assigns referenced object's uids to a reference field of an object
* @function setReference
* @param {String} field_uid The uid of the field whose references are to be set
* @param {String | Array} refValue Single uid/SDK object or Array of uids/SDK objects
* @throws new Error('new Error('Uid not found'))
* @instance
* @memberof Group
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* // 'Class('class_name').Object returns an 'Object' constructor
* // 'project' is a uid of a class on Built.io Backend
* var Project = Built.App('blt5d4sample2633b').Class('project').Object;
* var project = Project();
*
* var pm = Built.Group('project_manager', [{
* name: 'John',
* age: 32
* }])
*
* pm = pm.setReference("departments", ["blt124sample2122l", "blt311sample2324G"])
*
* project
* .addGroup(pm)
* .save()
* .then(function(project) {
* console.log(project.toJSON())
* })
@return {Group}
*/
module.exports.setReference = R.curry(function(fieldUid, refValue, group) {
var finalValue = refValue
// For multiple
if(utility.isArray(refValue)){
//check whether it is array of built objects
if(refValue[0] && refValue[0].app){
finalValue = []
for (var i = 0; i < refValue.length; i++) {
if(!refValue[i].getUid()){
throw new Error('Uid not found');
}
finalValue.push(refValue[i].getUid());
}
}
} else {
if(refValue.app)
finalValue = refValue.getUid()
}
return referenceHelper(fieldUid, finalValue, group)
});
instanceMethodBuilder.define('setReference',3);
/**
* Fires a query on Built.io Backend and the object that fulfills the query condition is assigned in the reference field.
* Note: 'query' should be such that only one object should satisfy it, as Built.io Backend doesn't allow multipe references to be set using a 'query'
* @function setReferenceWhere
* @memberof Group
* @param {String} field_uid The uid of the reference field
* @param {object} query JavaScript object specifying the conditions
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* // 'Class('class_name').Object returns an 'Object' constructor
* // 'project' is a uid of a class on Built.io Backend
* var Project = Built.App('blt5d4sample2633b').Class('project').Object;
* var project = Project();
*
* var pm = Built.Group('project_manager', [{
* name: 'John',
* age: 32
* }])
*
* pm = pm.setReferenceWhere("departments", {
* department_type:"type2"
* })
*
* project
* .addGroup(pm)
* .save()
* .then(function(project) {
* console.log(project.toJSON())
* })
@return {Group}
*/
module.exports.setReferenceWhere = R.curry(function(fieldUid, conditions, group){
var whereClause = {
WHERE: conditions
}
return referenceHelper(fieldUid, whereClause, group)
})
instanceMethodBuilder.define('setReferenceWhere', 3)
/**
* This method will first create object(s) in referred class and then assigns its uids in the base class's referring field.
* Example: Consider you have a reference field 'project' in class 'Bugs' class. This method would first create object(s) in 'Project' class
* and then assign its 'uids' in 'Bugs' class's reference field 'project'.
* @function setReferenceWithObject
* @memberof Group
* @param {String} field_uid The uid of the reference field or "." delimated string for 'group' fields as shown in example
* @param {Object | Array} refObjs JSON object or an array of plain JavaScript objects or SDK object(s)
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* // 'Class('class_name').Object returns an 'Object' constructor
* // 'project' is a uid of a class on Built.io Backend
* var Project = Built.App('blt5d4sample2633b').Class('project').Object;
* var project = Project();
*
* var pm = Built.Group('project_manager', [{
* name: 'John',
* age: 32
* }])
*
* pm = pm.setReferenceWithObject("departments", [{
* name:'Department A',
* department_type: "type1"
* },{
* name: "Department B",
* department_type: "type2"
* }])
*
* project
* .addGroup(pm)
* .save()
* .then(function(project) {
* console.log(project.toJSON())
* })
@return {Group}
*/
module.exports.setReferenceWithObject = R.curry(function(fieldUid, refValue, group) {
var finalValue = refValue
if(utility.isArray(refValue)){
if(refValue[0] && refValue[0].app){ //check whether it is array of built objects
finalValue = []
for (var i = 0; i < refValue.length; i++) {
finalValue.push(refValue[i].toJSON());
}
}
} else {
if(refValue.app)
finalValue = refValue.toJSON()
}
return referenceHelper(fieldUid, finalValue, group)
});
instanceMethodBuilder.define('setReferenceWithObject',3);
/**
* Use this method to perfom a upsert(update else insert) operation on reference field.
* @function upsertForReference
* @memberof Group
* @param {String} field_uid Reference uid on which UPSERT is to be performed
* @param {Built.Upsert} upsert Instance of Built.Upsert
* @instance
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* // 'Class('class_name').Object returns an 'Object' constructor
* // 'project' is a uid of a class on Built.io Backend
* var Project = Built.App('blt5d4sample2633b').Class('project').Object;
* var project = Project();
*
* // Creating instance of Built.Upsert to represent the upsert scenarios
* var upsertDep = Built.Upsert([{
* condition:{
* name: "Department A1"
* },
* replacement:{
* name: "Department A",
* department_type: "type1"
* }
* },{
* condition:{
* name: "Department B1"
* },
* replacement:{
* name: "Department B",
* department_type: "type1"
* }
* }]);
*
* var pm = Built.Group('project_manager', {
* name: 'John',
* age: 32
* });
*
* pm = pm.upsertForReference('departments', upsertDep)
*
* project
* .addGroup(pm)
* .save()
* .then(function(project) {
* console.log(project.toJSON())
* })
@return {Group}
*/
module.exports.upsertForReference = referenceHelper
instanceMethodBuilder.define('upsertForReference', 3)
/**
* Pushes a value in the multiple field. The method ensures push operation to be atmoic
* @memberof Group
* @function pushValue
* @param {String} fieldUid The uid of the field in which push operation needs to be performed
* @param {object|Built.Group|Built.GroupMultiple} value Value that needs to be pushed
* @instance
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* // 'address' is field in person group which is marked multiple
* var person = Built.Group('person', {
* name: 'John',
* age: 22
* })
* person = person.pushValue('address',["Mumbai"])
*
* //Consider 'person' class has a group field which is marked multiple
* //to push a new value in this field follow the example shown below
* var person = Built.Group('person', {
* name: 'John',
* age: 22
* })
* var addressGrp = Built.Group("address",{
* city: 'Mumbai',
* state: 'Maharashtra'
* })
* person.pushValue("address", addressGrp)
* @return {Group}
*/
module.exports.pushValue = function(key, value, group){
return pushPullHelper("PUSH", key, value, "", group)
}
instanceMethodBuilder.define('pushValue', 3)
/**
* Updates a value in the multiple field. The method ensures update operation to be atmoic
* @memberof Group
* @function updateValueAtIndex
* @param {String} fieldUid The uid of the field in which update operation needs to be performed
* @param {object|Built.Group|Built.GroupMultiple} value Value that needs to be updated
* @param {Number} index Index at which update should be performed
* @instance
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* // 'address' is field in person group which is marked multiple
* var person = Built.Group('person', {
* name: 'John',
* age: 22
* })
* person = person.updateValueAtIndex('address',["Mumbai"], 2)
*
* //Consider 'person' class has a group field which is marked multiple
* //to push a new value in this field follow the example shown below
* var person = Built.Group('person', {
* name: 'John',
* age: 22
* })
* var addressGrp = Built.Group("address",{
* city: 'Mumbai',
* state: 'Maharashtra'
* })
* person.updateValueAtIndex("address", addressGrp, 2)
* @return {Group}
*/
module.exports.updateValueAtIndex = function(key, value, index, group){
return pushPullHelper("UPDATE", key, value, index, group)
}
instanceMethodBuilder.define('updateValueAtIndex', 4)
/**
* Adds a sub-group under the current group.
* @memberof Group
* @function addGroup
* @param {Built.Group|Built.GroupMultiple} group Instance of Buillt.Group or Built.GroupMultiple
* @instance
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* var person = Built.Group('person', {
* name: 'John',
* age: 22
* })
* var address = Built.Group('address',{
* city: 'Mumbai',
* area: 20000
* })
* person = person.addGroup(address)
* @return {Group}
*/
module.exports.addGroup = function (anotherGrp, group) {
var mixedObject = getMixinedObject(anotherGrp.toJSON(), group)
return groupCons(group.field, mixedObject)
}
instanceMethodBuilder.define('addGroup', 2)
/**
* Pulls a matching value from the multiple field. The method ensures pull operation to be atmoic
* @memberof Group
* @function pullValue
* @param {String} fieldUid The uid of the field in which push operation needs to be performed
* @param {object|Built.Group|Built.GroupMultiple} conditions Value that needs to be pulled
* @instance
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* // 'address' is field in person group which is marked multiple
* var person = Built.Group('person', {
* name: 'John',
* age: 22
* })
* person = person.pullValue('address',["Mumbai"])
*
* //Consider 'person' class has a group field which is marked multiple
* //to pull a value from this field follow the example shown below
* var person = Built.Group('person', {
* name: 'John',
* age: 22
* })
* var addressGrp = Built.Group("address",{
* city: 'Mumbai',
* state: 'Maharashtra'
* })
* person.pullValue("address", addressGrp)
* @return {Group}
*/
module.exports.pullValue = function(key, value, group){
return pushPullHelper("PULL", key, value, "", group)
}
instanceMethodBuilder.define('pullValue', 3)
/**
* Pulls a value from the multiple field at a given index. The method ensures pull operation to be atmoic
* @memberof Group
* @function pullValueAtIndex
* @param {String} fieldUid The uid of the field in which push operation needs to be performed
* @param {Number} index Index from which a value needs to be pulled
* @instance
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* // 'address' is field in person group which is marked multiple
* var person = Built.Group('person', {
* name: 'John',
* age: 22
* })
* person = person.pullValueAtIndex('address', 1)
* @return {Group}
*/
module.exports.pullValueAtIndex = function(key, index, group){
return pushPullHelper('PULL',key,"",index, group);
}
instanceMethodBuilder.define('pullValueAtIndex', 3)
/**
* Wraps a sub-group in Built.Group construct and returns it
* @memberof Group
* @function getGroupForKey
* @param {field} fieldUid The uid of the sub group field
* @instance
* @example
* // 'blt5d4sample2633b' is a dummy Application API key
* // 'address' is a sub-group in person group.
* var person = Built.Group('person', {
* name: 'John',
* age: 22,
* address: {
* city: "Mumbai",
* state: "Maharasthra"
* }
* })
*
* var addressGrp = person.getGroupForKey("address")
* console.log(addressGrp.toJSON())
* @return {Group}
*/
module.exports.getGroupForKey = function(key, group){
var mixedData = getMixinedObject({}, group)
if(!mixedData[key])
throw new Error("Key not found in group")
if(utility.isArray(mixedData[key]))
return Built.GroupMultiple(key, mixedData[key])
else
return groupCons(key, mixedData[key])
}
instanceMethodBuilder.define('getGroupForKey', 2)
function getMixinedObject(toBeMixed, group){
toBeMixed = toBeMixed || {}
return R.mixin(toBeMixed, group.data[group.field]);
}