UNPKG

firebase.fuel

Version:

experimental constructor with common firebase/geofire tasks

1,503 lines (1,213 loc) 63 kB
(function() { 'use strict'; angular .module('firebase.fuel.config', ['firebase.starter']); })(); (function() { 'use strict'; angular .module('firebase.fuel', ['firebase.fuel.config', 'firebase.fuel.services']); })(); (function() { 'use strict'; angular .module('firebase.fuel.services', ['firebase.fuel.utils', 'firebase.fuel.config']); })(); (function() { "use strict"; utilsFactory.$inject = ["$log", "$q", "inflector"]; angular.module("firebase.fuel.utils", ['platanus.inflector']) .factory("utils", utilsFactory); /** @ngInject */ function utilsFactory($log, $q, inflector) { var utils = { addTimeAtCreate: addTimeAtCreate, addTimeAtSave: addTimeAtSave, camelize: camelize, extendPath: extendPath, paramCheck: paramCheck, pluralize: pluralize, qWrap: qWrap, qAll: qAll, removeSlash: removeSlash, standardError: standardError, singularize: singularize, stringify: stringify, toArray: toArray }; return utils; function paramCheck(param, type, def) { switch (angular.isUndefined(param)) { case true: return def; case false: switch (type) { case "bool": return boolCheck(param); case "str": return strCheck(param); case "arr": return arrCheck(param); case "obj": return hashCheck(param); } break; } } function strCheck(str) { switch (angular.isString(str)) { case true: return str; case false: return invalidType(str); } } function arrCheck(arr) { switch (angular.isArray(arr)) { case true: return arr; case false: return invalidType(arr); } } function boolCheck(bool) { var accepted = [false, true]; switch (accepted.indexOf(bool)) { case -1: return invalidType(bool); default: return bool; } } function invalidType(type) { throw new Error("Invalid parameter type at: " + type); } function hashCheck(hash) { //TODO: iterate over keys and check for and remove unknowns return hash; } function camelize(str, flag) { return inflector.camelize(str, flag); } function singularize(str) { return inflector.singularize(str); } function pluralize(str) { return inflector.pluralize(str); } function qWrap(obj) { return $q.when(obj); } function qAll(x, y) { return $q.all([x, qWrap(y)]); } function standardError(err) { return $q.reject(err); } function removeSlash(path) { if (path[path.length - 1] === "/") { path = path.substring(0, path.length - 1); } if (path[0] === "/") { path = path.substring(1); } return path; } function flatten(arr) { var flatResults = arr.reduce(function(x, y) { return x.concat(y); }, []); return flatResults; } function toArray(param) { if (angular.isArray(param)) { return flatten(param); } else { return extendPath([], param); } } function stringify(arr) { if (angular.isArray(arr)) { arr = arr.join('/'); } return arr; } //TODO this only works if undefined is last item in array function extendPath(arr, id) { arr.push(id); arr = flatten(arr); var un = arr.indexOf(undefined); if (un > -1) { arr.splice(un, 1); } return arr; } function addTimeAtCreate(obj, createtime, updatetime) { obj[createtime] = timeStamp(); obj[updatetime] = timeStamp(); return obj; } function addTimeAtSave(obj, updatetime) { obj[updatetime] = timeStamp(); return obj; } function timeStamp() { return Firebase.ServerValue.TIMESTAMP; } } })(); (function() { "use strict"; /** @ngInject */ authObjFactory.$inject = ["fuelConfiguration"]; function authObjFactory(fuelConfiguration) { /** * @public * @return{Object} - $firebaseAuth service at the rootPath of your firebase */ return fuelConfiguration("auth"); } angular.module("firebase.fuel.services") .factory("fuelAuth", authObjFactory); })(); (function() { "use strict"; FuelConfigProvider.$inject = ["fireStarterProvider"]; angular.module('firebase.fuel.config') .provider('fuelConfiguration', FuelConfigProvider); /** * @public * @constructor * @see {@link https://github.com/bpietravalle/fireStarter} */ /** @ngInject */ function FuelConfigProvider(fireStarterProvider) { fuelProviderGet.$inject = ["fireStarter"]; var prov = this; prov.setRoot = function(val) { fireStarterProvider.setRoot(val); } prov.getRoot = function() { return fireStarterProvider.getRoot(); } prov.$get = fuelProviderGet; /** @ngInject */ function fuelProviderGet(fireStarter) { switch (angular.isString(prov.getRoot())) { case true: return function(type, path, options) { return fireStarter(type, path, options) }; case false: throw new Error("You must define a root url in your module's config block"); } } } })(); (function() { "use strict"; FirePathFactory.$inject = ["$timeout", "utils", "$q", "$log", "$injector", "fuelConfiguration"]; var FirePath; angular.module("firebase.fuel.services") .factory("firePath", FirePathFactory); /** @ngInject*/ function FirePathFactory($timeout, utils, $q, $log, $injector, fuelConfiguration) { return function(path, options) { var fb = new FirePath($timeout, utils, $q, $log, $injector, fuelConfiguration, path, options); fb = fb.construct(); return fb; }; } FirePath = function($timeout, utils, $q, $log, $injector, fuelConfiguration, path, options) { this._timeout = $timeout; this._utils = utils; this._q = $q; this._log = $log; this._injector = $injector; this._path = path; this._fuelConfiguration = fuelConfiguration; this._options = options; this._geofire = this._options.geofire }; FirePath.prototype = { construct: function() { var self = this; var fire = {}; reset(); fire.reset = reset; fire.root = root; fire.main = main; fire.mainRecordRef = mainRecordRef; fire.nestedArrayRef = nestedArrayRef; fire.nestedRecordRef = nestedRecordRef; fire.mainArray = mainArray; fire.mainRecord = mainRecord; fire.nestedArray = nestedArray; fire.nestedRecord = nestedRecord; fire.indexAf = indexAf; fire.buildFire = buildFire; fire._pathHistory = []; fire.base = getCurrentFirebase; fire.setBase = setCurrentFirebase; fire.ref = getCurrentRef; fire.path = getCurrentPath; fire.pathHistory = getPathHistory; fire.setCurrentRef = setCurrentRef; fire.inspect = inspect; switch (self._geofire) { case true: return angular.extend(fire, { geofirePath: geofirePath, geofireRef: geofireRef, makeGeofire: makeGeofire }); } function buildFire(type, path, flag) { switch (type) { case ("ref"): return buildRef(path); default: return buildAf(type, path, flag); } } function buildRef(path) { return self._timeout(function() { return self._fuelConfiguration("ref", path); }).then(setCurrentRef); } function buildAf(type, path, flag) { if (flag !== true) { path = buildRef(path); } return self._utils.qAll(path, type) .then(setCurrentRefAndReturn) .then(setCurrentFirebase) .catch(standardError); function setCurrentRefAndReturn(res) { return self._fuelConfiguration(res[1], res[0], true) } } /************ Relative Paths ****************/ function mainArrayPath() { return self._utils.toArray(self._path); } function mainRecordPath(id) { return self._utils.extendPath(mainArrayPath(), id); } function nestedArrayPath(recId, name) { return self._utils.extendPath(mainRecordPath(recId), name); } function nestedRecordPath(mainRecId, arrName, recId) { return self._utils.extendPath(nestedArrayPath(mainRecId, arrName), recId); } function geofirePath(path) { return mainRecordPath(path); } /*************** firebaseRefs ************/ function root() { return reset().root(); } function main() { return buildFire("ref", mainArrayPath()); } function mainRecordRef(id) { return buildFire("ref", mainRecordPath(id)); } function nestedArrayRef(recId, name) { return buildFire("ref", nestedArrayPath(recId, name)); } function nestedRecordRef(recId, name, id) { return buildFire("ref", nestedRecordPath(recId, name, id)); } function geofireRef(path) { return buildFire("ref", geofirePath(path)); } function reset() { return setCurrentRef(self._fuelConfiguration("ref", self._path)); } /*************** angularFire ************/ function mainArray() { return buildFire("array", mainArrayPath()); } function mainRecord(id) { return buildFire("object", mainRecordPath(id)); } function nestedArray(recId, name) { return buildFire("array", nestedArrayPath(recId, name)); } function nestedRecord(main, arr, rec) { return buildFire("object", nestedRecordPath(main, arr, rec)); } function indexAf(recId, name, type) { return buildFire(type, nestedArrayPath(recId, name)); } /*************** geoFire ***************/ function makeGeofire(path) { return buildFire("geo", geofirePath(path)); } /************ Absolute Paths ****************/ function getCurrentPath() { if (getCurrentRef()) { return getCurrentRef().toString(); } } function getCurrentRef() { return fire._ref; } function getCurrentFirebase() { return fire._base; } function setCurrentFirebase(base) { fire._base = base; return fire._base; } function setCurrentRef(res) { fire._ref = res; setCurrentPath(res.toString()); return fire._ref; } function setCurrentPath(path) { if (angular.isString(fire._path)) { setPathHistory(fire._path); } fire._path = path; return fire._path; } function setPathHistory(path) { fire._pathHistory.push(path); } function standardError(err) { return self._utils.standardError(err); } function getPathHistory() { return fire._pathHistory; } function inspect() { return self; } self._fire = fire; return self._fire; } }; }.call(this)); (function() { "use strict"; FuelFactory.$inject = ["$timeout", "utils", "firePath", "$q", "$log", "$injector"]; var Fuel; angular .module('firebase.fuel.services') .factory("fuel", FuelFactory); /** @ngInject */ function FuelFactory($timeout, utils, firePath, $q, $log, $injector) { /** * @constructor * @param{Array} path ["path", "to,"child","node"] * @param{Object} options - options hash - see below */ return function(path, options) { var fb = new Fuel($timeout, utils, firePath, $q, $log, $injector, path, options); return fb.construct(); }; } Fuel = function($timeout, utils, firePath, $q, $log, $injector, path, options) { this._timeout = $timeout; this._utils = utils; this._firePath = firePath; this._q = $q; this._log = $log; this._injector = $injector; this._path = path; this._options = this._utils.paramCheck(options, "obj", {}); this._pathOptions = {}; /*Core Options */ this._geofire = this._utils.paramCheck(this._options.geofire, "bool", false); this._gps = this._utils.paramCheck(this._options.gps, "bool", false); this._nestedArrays = this._utils.paramCheck(this._options.nestedArrays, "arr", []); this._session = this._utils.paramCheck(this._options.session, "bool", false); this._user = this._utils.paramCheck(this._options.user, "bool", false); this._timeStamp = this._utils.paramCheck(this._options.timeStamp, "bool", false); if (this._gps === true && this._geofire === true) { throw new Error("Invalid options. Please remove either 'gps' or 'geofire' from the options hash"); } if (this._user === true && this._geofire === true) { throw new Error("Invalid options Please remove 'user' or 'geofire' from your options hash."); } /****************** * Additional Config * *****************/ /* GPS & Geofire */ if (this._gps === true || this._geofire === true) { this._geofireNode = this._utils.paramCheck(this._options.geofireNode, "str", "geofire"); this._latitude = this._utils.paramCheck(this._options.latitude, "str", "lat"); this._longitude = this._utils.paramCheck(this._options.longitude, "str", "lon"); this._pathOptions.geofire = true; } if (this._geofire === true) { this._foreignKeys = this._utils.paramCheck(this._options.foreignKeys, "obj", {}); } if (this._gps === true) { this._addRecordKey = this._utils.paramCheck(this._options.addRecordKey, "bool", true); this._points = this._utils.paramCheck(this._options.points, "str", this._path); this._geofireIndex = this._utils.paramCheck(this._options.geofireIndex, "str", "locations"); this._geofireService = this._utils.paramCheck(this._options.geofireService, "str", "geofire"); this._geofireObject = this._injector.get(this._geofireService); } /* User & Session */ if (this._user === true || this._session === true) { this._uid = this._utils.paramCheck(this._options.uid, "bool", true); this._uidProperty = this._utils.paramCheck(this._options.uidProperty, "str", "uid"); } if (this._user === true) { this._userNode = this._utils.paramCheck(this._options.userNode, "str", "users"); this._userService = this._utils.paramCheck(this._options.userService, "str", this._utils.singularize(this._userNode)); this._userObject = this._injector.get(this._userService); this._customUserIndex = this._utils.paramCheck(this._options.customUserIndex, "bool", false); if (this._customUserIndex) { this._userIndexProp = this._options.userIndexProp || true; } this._session = true; } if (this._session === true) { this._sessionService = this._utils.paramCheck(this._options.sessionService, "str", "session"); this._sessionIdMethod = this._utils.paramCheck(this._options.sessionIdMethod, "str", "getId"); this._sessionObject = this._injector.get(this._sessionService); } if (this._timeStamp === true) { this._createTime = this._utils.paramCheck(this._options.createTime, "str", "createdAt"); this._updateTime = this._utils.paramCheck(this._options.updateTime, "str", "updatedAt"); } this._pathMaster = this._firePath(this._path, this._pathOptions); }; Fuel.prototype = { construct: function() { var self = this; var entity = {}; entity.base = getCurrentBase; entity.ref = getCurrentRef; entity.path = getCurrentPath; entity.inspect = inspect; entity.mainRef = mainRef; entity.mainArray = mainArray; entity.mainRecord = mainRecord; /*Queries*/ entity.load = load; entity.getRecord = getMainRecord; entity.queryByChild = queryByChild; entity.getIndexKeys = getIndexKeys; entity.bindTo = bindTo; /*Commands*/ entity.save = save; entity.addIndex = addIndex; entity.removeIndex = removeIndex; if (self._user !== true && self._gps !== true && self._geofire !== true) { entity.add = basicAdd; entity.remove = removeMainRecord; } if (self._user === true) { entity.loadUserRecords = loadUserRecords; } if (self._gps === true) { entity.geoQuery = geoQuery; entity.removeCoords = removeCoords; entity.setCoords = setCoords; entity.getCoords = getCoords; entity.getLocation = getLocationRecord; entity.addLocations = sendToGeofireToAdd; entity.removeLocations = sendToGeofireToRemove; if (self._addRecordKey === true) { entity.loadRecordLocations = sendToGeoFireToLoadLocations; } } if (self._user !== true && self._gps === true) { entity.add = createWithGps; entity.remove = removeWithGps; } if (self._user === true && self._gps !== true) { entity.add = createWithUser; entity.remove = removeWithUser; } if (self._user === true && self._gps === true) { entity.add = createWithUserAndGps; entity.remove = removeWithUserAndGps; } if (self._session === true) { entity.bindCurrent = bindCurrent; entity.current = current; entity.session = session; entity.sessionId = sessionId; } if (self._geofire === true) { entity.add = addLocations; entity.addRecordKey = addRecordKey; entity.geofire = makeGeofire; entity.get = getGeofire; entity.loadRecordLocations = loadRecordLocations; entity.query = queryGeofire; entity.remove = removeLocations; entity.set = setGeofire; } getCurrentRef(); switch (self._nestedArrays) { case []: break; default: return addNested(entity, self._nestedArrays); } /******************* * fireBaseRef Mngt * *******************/ /** * @public * @return{String} path of most recently created firebaseRef */ function getCurrentPath() { return self._pathMaster.path(); } /** * @public * @return{Object} most recently created firebaseRef */ function getCurrentRef() { return self._pathMaster.ref(); } /** * @public * @return{Object} most recently created angularFire/Geofire object|array */ function getCurrentBase() { return self._pathMaster.base(); } /** * @public * @return{Promise<Object>} - promise resolves to firebaseRef at the main node(ie rootPath/self._path) */ function mainRef() { return self._pathMaster.main(); } /** * @public * @return{Promise<Array>} - promise resolves to a $firebaseArray of the main node */ function mainArray() { return self._pathMaster.mainArray(); } /** * @public * @param{String} id - key of record you wish to retrieve * @return{Promise<Object>} - promise resolves to a $firebaseObject of the given main record */ function mainRecord(id) { return self._pathMaster.mainRecord(id); } /* Geofire Interface */ /** * @public * @param{String} path - child node of geofire node * @return{Promise<Object>} - promise resolves to a geofire object * */ function makeGeofire(path) { return self._pathMaster.makeGeofire(path); } /***************** * Main Methods * ***************/ /*Queries*/ /** * @public * @param{String} recId - id of main record * @param{String} arrName - name of index * @return{Promise<Array>} - promise resolves to ["keys","presently","in" "index"] */ function getIndexKeys(recId, arrName) { return indexAf(recId, arrName, "array") .then(loaded) .then(getKeys) .catch(standardError); function getKeys(res) { var arr = []; self._q.all(res.map(function(item) { arr.push(item.$id); })); return arr; } } /** * @public * @param{String} [id] - key of main record you wish to load; without id argument fn will load entire main array * @return{Promise<Object|Array>} - promise resolves to a $firebaseObject or $firebaseArray */ function load(id) { switch (angular.isUndefined(id)) { case true: return loadMainArray(); case false: return loadMainRecord(id); } } /** * @public * @param{String|Array} param - either "key" or [$firebaseArray,"key"] * @return{Promise<Object>} - promise resolves to the given $firebaseArray record */ function getMainRecord(param) { switch (angular.isArray(param)) { case true: return getRecord(param); case false: switch (angular.isString(param)) { case true: return loadArrayAndGet(param); case false: return standardError("Invalid type: must pass an array or string"); } } } /** * @public * @param{String} col - property name used in an 'orderByChild' query; * @param{String|Number|etc} val - value of child - ie arg of equalTo * @return{Promise<firebaseRef>} promise resolves to a firebaseRef the given query */ function queryByChild(col, val) { return qAll(mainRef(), [col, val]) .then(completeQuery) .catch(standardError); function completeQuery(res) { return res[0].orderByChild(res[1][0]).equalTo(res[1][1]); } } /* Commands */ /** * @public * @param{String} recId - key of main record - you can leave it undefined if you've * configured option hash to use your app's session object * @param{String} idxName - name of index * @param{String} key - foreign key to add to index * @param{Any} [val=true] - value to set at index - defaults to true * @return{Promise<Object>} promise resolves to the firebaseRef of the index */ function addIndex(recId, idxName, key, val) { if (!angular.isString(recId) && self._session === true) { recId = sessionId(); } return qAll(nestedArrayRef(recId, idxName), key) .then(completeAction) .catch(standardError); function completeAction(res) { if (!val) { val = true; } return self._timeout(function() { return qAll(res[0], res[0].child(res[1]).set(val)) }) .then(setReturnValueToFirst) .catch(standardError); } } /** * @public * @param{String} recId - key of main record - you can leave it undefined if you've * configured option hash to use your app's session object * @param{String} idxName - name of index * @param{String} key - foreign key to remove from index * @return{Promise<Object>} promise resolves to the firebaseRef of the index */ function removeIndex(recId, idxName, key) { if (!angular.isString(recId) && self._session === true) { recId = sessionId(); } return qAll(nestedArrayRef(recId, idxName), key) .then(completeAction) .catch(standardError); function completeAction(res) { return self._timeout(function() { return qAll(res[0], res[0].child(res[1]).set(null)) }) .then(setReturnValueToFirst) .catch(standardError); } } /** * @public * @param{String|Object} id either key of main record or the actual $firebaseObject * @param{Object} scope - $scope * @param{String} varName - variable name to bind object * @return{Promise<Object>} */ function bindTo(id, scope, varName) { switch (angular.isString(id)) { case true: return qAll(mainRecord(id), [scope, varName]) .then(bindObject) .catch(standardError) case false: return qAll(id, [scope, varName]) .then(bindObject) .catch(standardError); } } /** * @public * @param{Object} data - data object to persist to main array * @return{Promise<Object>} firebaseRef of newly added record */ function basicAdd(data) { return qAll(mainArray(), data) .then(add) .catch(standardError); } /** * @public * @param{String|Object|Array} param - pass the key, the $firebaseObject, or [$firebaseArray,record] * @return{Promise<Object>} - promise resolves to the firebaseRef of the removed record */ function removeMainRecord(param) { switch (angular.isString(param)) { case true: return mainRecord(param) .then(remove); default: return remove(param); } } /************ * GPS Option * ***********/ /** * @public * @param{Object} obj * * @param{Object|Array} obj.data locations to save * @param{String} [obj.path=self._points] child node for coordinates * @param{Object|String} [obj.id] if the main record already exists pass its firebaseRef or key and method will * add indexes * @param{String} [str] - key of main record to save as addRecordKey property * @return{Promise<Array>} promise resovles to an array of newly created location records or to location indexes */ function sendToGeofireToAdd(obj, str) { if (!obj.path) { obj.path = self._points; } switch (!obj.id) { case true: return self._geofireObject.add(obj.data, obj.path, str); default: return self._geofireObject.add(obj.data, obj.path, str) .then(setReturnVal) .then(addLocationIndices) .catch(standardError); } function setReturnVal(res) { var arr = [] arr.push(obj.id); arr.push(res); return arr; } } /** * @public * @param{Object} obj * @param{String} obj.id "mainRecordId" * @param{Boolean} [obj.flag=null] true if only wish to remove coordinates, otherwise leave undefined * @param{String} [obj.path=self._points] child node for coordinates * @param{Array<String>} [obj.locKeys] ["array","or","locationIds"] - optional * @return{Promise<Array>} [fireBaseRefs of removed main location records] */ function sendToGeofireToRemove(obj) { if (!obj.path) { obj.path = self._points; } if (!obj.flag) { obj.flag = null; } switch (!obj.locKeys) { case true: return getIndexKeys(obj.id, self._geofireIndex) .then(completeRemove) default: return completeRemove(obj.locKeys) .then(removeLocIndices) } function completeRemove(res) { return self._geofireObject.remove(res, obj.flag, obj.path); } function removeLocIndices(res) { return self._q.all(res.map(function(loc) { return removeIndex(obj.id, self._geofireIndex, loc.key()); })); } } /** * @public * @param{String} col - property name to query by * @param{String} id - key of record that you want to load locations of * @return{Promise<Array>} - promise resolves to a $firebaseArray * @summary load all locations associates with a given main record * */ function sendToGeoFireToLoadLocations(col, id) { return self._geofireObject.loadRecordLocations(col, id); } /** * @public * @param{String} key - record id * @param{Array} coords - [latitude,longitude] * @param{String} [pth=self._points] - name of child node to save coordinates at. * This defaults to name of the main node * @return{Promise<Object>} resolves to the firebaseRef of entire geofire node */ function setCoords(key, coords, pth) { if (!pth) { pth = self._points; } return self._geofireObject.set(key, coords, pth); } /** * @public * @param{String} key - id to lookup * @param{String} [pth=self._points] - name of child node to save coordinates at. * This defaults to name of the main node * @return{Promise<Array|Null>} resolves to the coordinates array or null if no record * is found */ function getCoords(key, pth) { if (!pth) { pth = self._points; } return self._geofireObject.get(key, pth); } /** * @public * @param{String} key - id to lookup * @param{String} [pth=self._points] - name of child node to save coordinates at. * This defaults to name of the main node * @return{Promise<Object>} resolves to the firebaseRef of entire geofire node * */ function removeCoords(key, pth) { if (!pth) { pth = self._points; } return self._geofireObject.remove(key, true, pth); } /** * @public * @param{Object} obj * @param{Number} obj.radius - radius of query * @param{Array<Number>} obj.center - [latitude,longitude] * @param{String} [pth=self._points] - name of child node to save coordinates at. * Defaults to name of main node * @return{Promise<Object>} geoquery object */ function geoQuery(obj, pth) { if (!pth) { pth = self._points; } return self._geofireObject.query(obj, pth); } /***************** * Geofire Option * ***************/ /** * @public * @param{Object|Array<Object>} locs - either data object to add or [data,objects,to,add] * @param{String} path- name of child node for coordinates-- also used for setting fkey property * @param{String} [fkey] - key of associated main record * to name of main node * @return{Array} firebaseRefs of newly created main location Array records */ function addLocations(locs, path, fkey) { var prop; if (!angular.isArray(locs)) { locs = [locs]; } if (angular.isString(fkey) && angular.isString(path)) { prop = self._foreignKeys[path]; } return self._q.all(locs.map(function(loc) { if (angular.isString(prop)) { loc[prop] = fkey; } return addFullLocationRecord(loc, path) .catch(standardError); })); } /** * @public * @param{String|Array<String>} keys -either key - if only one record or ["keys","of","records"] * @param{Boolean} flag true if only wish to remove coordinates, otherwise leave undefined * @return{Array} firebaseRefs of deleted record */ function removeLocations(keys, flag, path) { if (!angular.isArray(keys)) { keys = [keys]; } return self._q.all(keys.map(function(key) { return removeLocation(key, flag, path) .catch(standardError); })); } /** * @public * @param{String} col - property name to query by * @param{String} id - key of record that you want to load locations of * @return{Promise<Array>} - promise resolves to a $firebaseArray * @summary load all locations associates with a given main record */ function loadRecordLocations(col, id) { return currentRecordLocations(col, id) .then(wrapQuery) .then(loaded) .catch(standardError); } /** * @public * @param{String} key - id to lookup * @param{String} - name of child node to save coordinates at. * @return{Promise<Array|Null>} resolves to the coordinates array or null if no record * is found */ function getGeofire(key, path) { return qAll(makeGeofire(path), key) .then(getGeo) .catch(standardError); } /** * @public * @param{Object} obj * @param{Number} obj.radius - radius of query * @param{Array<Number>} obj.center - [latitude,longitude] * @param{String} - name of child node to save coordinates at. * @return{Promise<Object>} geoquery object */ function queryGeofire(data, path) { return qAll(makeGeofire(path), data) .then(queryGeo) .catch(standardError); } /** * @public * @param{String} key - id to lookup * @param{String} - name of child node to save coordinates at. * @return{Promise<Object>} resolves to the firebaseRef of entire geofire node * */ function removeGeofire(key, path) { return qAll(makeGeofire(path), key) .then(removeGeo) .catch(standardError); } /** * @public * @param{String} key - record id * @param{Array} coords - [latitude,longitude] * @param{String} path of child node to save coordinates at. * @return{Promise<Object>} resolves to the firebaseRef of entire geofire node */ function setGeofire(key, coords, path) { return qAll(makeGeofire(path), [key, coords]) .then(setGeo) .catch(standardError); } /** * @public * @param{String} path - key in geofire services' foreignKey's object used to identify * this record's property name - see discussion in README * @param{String} locKey - id of location record to lookup * @param{String} mainRecId - id of main record to persist to the associated locations * @summary this method adds a "mainRec" property to any locations added - the actual * name of the property is determined in the constructor's foreignKeys option. The value stored * is the main Record Id */ function addRecordKey(path, locKey, mainRecId) { var prop = self._foreignKeys[path]; switch (!angular.isString(prop)) { case true: throw new Error("Invalid key: Please check options defined for your Geofire service"); case false: return mainRef() .then(updateLocationRecord) .catch(standardError); } function updateLocationRecord(res) { return self._timeout(function() { var obj = {}; obj[prop] = mainRecId; return res.child(locKey).update(obj); }); } } /************* * User Option * ************/ /** * @public * @return{Promise<Array>} - promise resolves to a $firebaseArray * @summary load all main records associated with current User */ function loadUserRecords() { return currentUserRecords() .then(wrapQuery) .then(loaded) .catch(standardError); } /**************** * Session Option * ***************/ /** * @public * @param{Object} s - $scope object * @param{String} v - variable name to bind to * @summary - this is a helper method to bind the current record to the $scope object */ function bindCurrent(s, v) { return bindTo(sessionId(), s, v); } /** * @public * @return{Promise<Object>} -promise resolves to a $firebaseObject of the current record */ function current() { return mainRecord(sessionId()); } /** * @public * @return{Object} - returns your app's session service */ function session() { return self._sessionObject; } /** * @public * @return{String} - returns the current record id */ function sessionId() { return self._sessionObject[self._sessionIdMethod](); } /*********************************/ /* * Combo Methods */ /** * @public * @param{Object} data to save to user array - just saving key for now * @return{Array} [Promise(fireBaseRef at userIndex), firebaseRef(main record created)] * @summary save main record and to user index */ function createWithUser(data) { return createMainRecord(data, self._uid) .then(passKeyToUser) .catch(standardError); function passKeyToUser(res) { var prop; if (self._customUserIndex) { prop = data[self._userIndexProp]; } return qAll(addUserIndex(res.key(), prop), res); } } /** * @public * @param{String|Array} key of main record to remove or [fireBaseArray,record to remove] * @return{Array<Promise>} [Promise(fireBaseRef at userIndex), firebaseRef(main record removed)] * @summary remove main record and user index */ function removeWithUser(key) { return removeMainRecord(key) .then(passKeyToUser) .catch(standardError); function passKeyToUser(res) { return qAll(removeUserIndex(res.key()), res); } } /** * @public * @param{Object} rec - data object to persist to main Array * @param{Object|Array<Object>} loc - location object associated with record or * [locations,associated,with,record] * @return{Promise<Object>} promise resolves to firebaseRef of newly created main record * @summary This method creates a main record and records of associated locations. It also * adds a location index to the main record and adds the main records key to the location * records. */ function createWithGps(rec, loc) { var key; return createMainRecord(rec) .then(function(res) { if (self._addRecordKey) { key = res.key(); } return sendToGeofireToAdd({ data: loc }, key) .then(function(arr) { return [res, arr]; }) }) .then(addLocationIndexAndPassKey) .then(setReturnValueToSecond) .catch(standardError); function addLocationIndexAndPassKey(res) { return qAll(addLocationIndices(res), res[0]); } } /** * @public * @param{String} recId - id of main record * @return{Promise<Object>} promise resolves to firebaseRef of the removed main record * @summary This method removes a main record and any assocated locations */ function removeWithGps(recId) { return qAll(sendToGeofireToRemove({ id: recId }), recId) .then(removeMainRec) .catch(standardError); function removeMainRec(res) { return removeMainRecord(res[1]); } } /** * @public * @param{Object} rec to save to main array * @param{Object|Array} loc location data to persist- or [locations,to,persist] * @return{Promise<Object>} - Promise resolves to the firebaseRef of the newly created main record * @summary - This method adds a main record and records for any locations passed. It also * adds a location index at the main record, adds main record Id to each location record, and * adds an index in the current user's firebase node. */ function createWithUserAndGps(rec, loc) { var key; return createWithUser(rec) .then(function(res) { if (self._addRecordKey) { key = res[1].key(); } return sendToGeofireToAdd({ data: loc }, key) .then(function(arr) { return [res, arr]; }) }) .then(addLocationIndexAndPassKey) .then(setReturnValueToSecond) .catch(standardError); function addLocationIndexAndPassKey(res) { /*mainkey,geofire Obj*/ return self._q.all([addLocationIndices([res[0][1], res[1]]), res[0][1]]); } } /** * @public * @param{String} id key of location record to retrieve * @return{Promise<Object|Null>} - Promise resolves to the array record or null if not found */ function getLocationRecord(id) { return self._geofireObject .mainRecord(id) } /** * @public * @param{String} mainRecId - key of main record to remove * @param{Promise<Object>} - Promise resolves to the firebaseRef