georedis
Version:
Super fast geo queries.
197 lines (140 loc) • 5.37 kB
JavaScript
var NativeInterface = require('./lib/interfaceNative');
var EmulatedInterface = require('./lib/interfaceEmulated');
var QueuedInterface = require('./lib/interfaceQueued');
var randomId = require('./lib/util/helper').randomId;
var nativeCommands = ['info', 'geoadd', 'geohash', 'geopos', 'geodist', 'georadius', 'georadiusbymember'];
// main constructor
function GeoSet(options) {
options = options || {};
this.zset = options.zset || 'geo:locations';
this.parentGeoSet = options.parentGeoSet || null;
}
GeoSet.prototype.getClientInterface = function() {
return this.parentGeoSet ? this.parentGeoSet.clientInterface : this.clientInterface;
};
// initialization
GeoSet.prototype.initialize = function(client, options) {
options = options || {};
this.zset = options.zset ? options.zset : 'geo:locations';
setInterface(this, client, options.nativeGeo);
return this;
};
// managing sets
GeoSet.prototype.addSet = function(setName) {
return new GeoSet({
zset: this.zset + ':' + (setName || 'subset_' + randomId()),
parentGeoSet: this.parentGeoSet || this
});
};
GeoSet.prototype.deleteSet = function(setName, callBack) {
this.getClientInterface().del(this.zset + ':' + setName, callBack);
};
GeoSet.prototype.delete = function(callBack) {
this.getClientInterface().del(this.zset, callBack);
};
// adding locations
GeoSet.prototype.addLocation = function(locationName, point, callBack) {
this.getClientInterface().geoadd(locationName, point, this.zset, callBack);
};
GeoSet.prototype.addLocations = function(locationSet, callBack) {
this.getClientInterface().geoadd_multi(locationSet, this.zset, callBack);
};
// Calculations
GeoSet.prototype.distance = function(locationNameA, locationNameB, options, callBack) {
if (typeof options === 'function') {
callBack = options;
options = {};
} else {
options = options || {};
}
this.getClientInterface().geodist(locationNameA, locationNameB, options.units, this.zset, callBack);
};
// updating locations (same methods as add, existing locations get updated)
GeoSet.prototype.updateLocation = GeoSet.prototype.addLocation;
GeoSet.prototype.updateLocations = GeoSet.prototype.addLocations;
// removing locations
GeoSet.prototype.removeLocation = function(locationName, callBack) {
this.getClientInterface().zrem([locationName], this.zset, callBack);
};
GeoSet.prototype.removeLocations = function(locationNameArray, callBack) {
this.getClientInterface().zrem(locationNameArray, this.zset, callBack);
};
// querying location positions
GeoSet.prototype.location = function(locationName, callBack) {
this.getClientInterface().geopos([locationName], this.zset, callBack);
};
GeoSet.prototype.locations = function(locationNameArray, callBack) {
this.getClientInterface().geopos_multi(locationNameArray, this.zset, callBack);
};
// querying location geohashes
GeoSet.prototype.getGeohash = function(locationName, callBack) {
this.getClientInterface().geohash([locationName], this.zset, callBack);
};
GeoSet.prototype.getGeohashes = function(locationNameArray, callBack) {
this.getClientInterface().geohashes(locationNameArray, this.zset, callBack);
};
// querying nearby locations
GeoSet.prototype.radius = function(location, radius, options, callBack) {
if (typeof options === 'function') {
callBack = options;
options = {};
} else {
options = options || {};
}
if (typeof location === 'string') {
this.getClientInterface().georadiusbymember(location, radius, options, this.zset, callBack);
} else {
this.getClientInterface().georadius(location, radius, options, this.zset, callBack);
}
};
GeoSet.prototype.nearby = function(location, distance, options, callBack) {
if (typeof options === 'function') {
callBack = options;
options = {};
} else {
options = options || {};
}
if (typeof location === 'string') {
this.getClientInterface().nearbymember(location, distance, options, this.zset, callBack);
} else {
this.getClientInterface().nearby(location, distance, options, this.zset, callBack);
}
};
// interface config
function setInterface(geoSet, client, nativeGeo) {
var queuedInterface = new QueuedInterface(client);
if (nativeGeo === true) {
geoSet.clientInterface = new NativeInterface(client);
return;
} else if (nativeGeo === false) {
geoSet.clientInterface = new EmulatedInterface(client);
return;
}
geoSet.clientInterface = queuedInterface;
checkNativeInterface(queuedInterface, geoSet, client);
}
function checkNativeInterface(queuedInterface, geoSet, client) {
try {
client.send_command('command', nativeCommands, function(err, response) {
if (!err && hasNativeCommands(response)) {
geoSet.clientInterface = queuedInterface.drain(new NativeInterface(client));
} else {
geoSet.clientInterface = queuedInterface.drain(new EmulatedInterface(client));
}
});
} catch (err) {
geoSet.clientInterface = queuedInterface.drain(new EmulatedInterface(client));
}
}
function hasNativeCommands(response) {
if (Array.isArray(response) && response.length === nativeCommands.length - 1) {
for (var i = 0; i < response.length; i++) {
if (!response[i]) {
return false;
}
}
return true;
}
return false;
}
module.exports = exports = new GeoSet();