dl
Version:
DreamLab Libs
493 lines (428 loc) • 14.2 kB
JavaScript
/*jslint node: true */
'use strict';
var Long = require('long');
var OpalClient = require('../opal/OpalClient.js').OpalClient;
var Errors = require('./Errors.js');
var Nosqldb = function(datasource, timeout) {
if (timeout && timeout > 1) {
timeout = 1
}
this._datasource = datasource;
var rpcUrl = this._getRpcUrl(datasource);
this._nosqldbRpc = new OpalClient(rpcUrl, [
'get_metadata',
'insert',
'multi_insert',
'update',
'get',
'multi_get',
'get_range',
'remove',
'batch'
], timeout);
this._metadata = null;
this._timerId = setInterval(this._refreshMetadata.bind(this), 60 * 1000);
};
Nosqldb.prototype._getRpcUrl = function(datasource) {
var keyspace = datasource.split('.')[0];
return keyspace + '.nosqldb.onetapi.pl';
};
Nosqldb.prototype._getMetadata = function(refresh, callback) {
if (this._metadata && !refresh && callback) {
return callback(null, this._metadata);
}
console.log('Getting metadata');
var that = this;
this._nosqldbRpc.get_metadata([], function(err, res) {
if (err) {
console.error('Error while getting metadata: %s', err);
if (callback) {
return callback(err);
}
}
that._metadata = res;
if (callback) {
callback(null, that._metadata);
}
});
};
Nosqldb.prototype._refreshMetadata = function() {
this._getMetadata(true);
}
Nosqldb.prototype._encodeValue = function(value, typestring) {
if (value === null) {
return value;
}
var m = typestring.match(/(\w+)<([\w, ]+)>/);
if (typestring === 'timestamp') {
return value.getTime();
}
else if (typestring === 'bigint' || typestring === 'counter' || typestring === 'decimal') {
return value.toString();
}
else if (typestring === 'blob') {
return value.toString('hex');
}
else if (m) {
var collection = m[1];
var t = m[2];
var that = this;
if (collection === 'set' || collection === 'list') {
return value.map(function(v) {
return that._encodeValue(v, t);
});
}
else if (collection === 'map') {
var tSplit = t.split(', ');
var tK = tSplit[0];
var tV = tSplit[1];
var encodedMap = [];
for (var k in value) {
encodedMap.push([that._encodeValue(k, tK), that._encodeValue(value[k], tV)]);
}
return encodedMap;
}
}
return value;
};
Nosqldb.prototype._decodeValue = function(value, typestring) {
if (value === null) {
return value;
}
var m = typestring.match(/(\w+)<([\w, ]+)>/);
if (typestring === 'timestamp') {
return new Date(value);
}
else if (typestring === 'bigint' || typestring === 'counter') {
return Long.fromString(value, false);
}
else if (typestring === 'decimal') {
return parseFloat(value);
}
else if (typestring === 'blob') {
return new Buffer(value, 'hex');
}
else if (m) {
var collection = m[1];
var t = m[2];
var that = this;
if (collection === 'set' || collection === 'list') {
return value.map(function(v) {
return that._decodeValue(v, t);
});
}
else if (collection === 'map') {
var tSplit = t.split(', ');
var tK = tSplit[0];
var tV = tSplit[1];
var decodedMap = {};
value.forEach(function(item) {
decodedMap[that._decodeValue(item[0], tK)] = that._decodeValue(item[1], tV);
});
return decodedMap;
}
}
return value;
};
Nosqldb.prototype._encodeKey = function(table, key) {
if (!(key instanceof Array)) {
key = [key];
}
var tableMetadata = this._metadata.tables[table];
var encodedKey = [];
for (var i = 0; i < key.length; i++) {
var typestring = tableMetadata.primary_key[i]['typestring'];
encodedKey[i] = this._encodeValue(key[i], typestring);
}
return encodedKey;
};
Nosqldb.prototype._encodeColumns = function(table, columns) {
var tableMetadata = this._metadata.tables[table];
var encodedColumns = {};
for (var name in columns) {
var typestring = tableMetadata.columns[name]['typestring'];
encodedColumns[name] = this._encodeValue(columns[name], typestring);
}
return encodedColumns;
};
Nosqldb.prototype._encodeAssignments = function(table, assignments) {
var tableMetadata = this._metadata.tables[table];
var encodedAssignments = {};
for (var name in assignments) {
var typestring = tableMetadata.columns[name]['typestring'];
var operator = assignments[name][0];
var value = assignments[name][1];
var m = typestring.match(/(\w+)<([\w, ]+)>/);
if ((operator instanceof Array) && operator.length === 1 && m) {
var collection = m[1];
var t = m[2];
if (collection === 'list') {
value = this._encodeValue(value, t);
}
else if (collection === 'map') {
var tSplit = t.split(', ');
var tK = tSplit[0];
var tV = tSplit[1];
operator = [this._encodeValue(operator[0], tK)];
value = this._encodeValue(value, tV);
}
}
else {
value = this._encodeValue(value, typestring);
}
encodedAssignments[name] = [operator, value];
}
return encodedAssignments;
};
Nosqldb.prototype._handleError = function(err) {
switch(err.code) {
case Errors.INVALID_REQUEST:
return new Errors.InvalidRequest(err.message);
case Errors.REQUEST_ERROR:
return new Errors.RequestError(err.message);
case Errors.CONSISTENCY_ERROR:
return new Errors.ConsistencyError(err.message);
case Errors.CLUSTER_ERROR:
return new Errors.ClusterError(err.message);
case Errors.CONNECTION_ERROR:
return new Errors.ConnectionError(err.message);
default:
return err;
}
};
Nosqldb.prototype._decodeRow = function(table, row) {
var tableMetadata = this._metadata.tables[table];
for (var name in row) {
var typestring = tableMetadata.columns[name]['typestring'];
row[name] = this._decodeValue(row[name], typestring);
}
return row;
};
Nosqldb.prototype._handleResult = function(table, res) {
if (!res) {
return res;
}
var that = this;
if (res instanceof Array) {
return res.map(function decodeRow(row) {
return that._decodeRow(table, row);
});
}
return this._decodeRow(table, res);
};
Nosqldb.prototype.insert = function(table, key, columns, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
var ttl = options.ttl || null;
var consistency = options.consistency || 'default';
var that = this;
this._getMetadata(false, function(err) {
if (err) {
return callback(err);
}
key = that._encodeKey(table, key);
columns = that._encodeColumns(table, columns);
that._nosqldbRpc.insert([table, key, columns, ttl, consistency], function(err, res) {
if (err) {
return callback(that._handleError(err));
}
callback(null, null);
});
});
};
Nosqldb.prototype.multiInsert = function(items, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
var consistency = options.consistency || 'default';
var that = this;
this._getMetadata(false, function(err) {
if (err) {
return callback(err);
}
var encodedItems = items.map(function(item) {
return {
table: item.table,
key: that._encodeKey(item.table, item.key),
columns: that._encodeColumns(item.table, item.columns),
ttl: item.ttl
};
});
that._nosqldbRpc.multi_insert([encodedItems, consistency], function(err, res) {
if (err) {
return callback(that._handleError(err));
}
callback(null, null);
});
});
};
Nosqldb.prototype.update = function(table, key, assignments, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
var ttl = options.ttl || null;
var consistency = options.consistency || 'default';
var that = this;
this._getMetadata(false, function(err) {
if (err) {
return callback(err);
}
key = that._encodeKey(table, key);
assignments = that._encodeAssignments(table, assignments);
that._nosqldbRpc.update([table, key, assignments, ttl, consistency], function(err, res) {
if (err) {
return callback(that._handleError(err));
}
callback(null, null);
});
});
};
Nosqldb.prototype.get = function(table, key, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
var columns = options.columns || null;
var consistency = options.consistency || 'default';
var that = this;
this._getMetadata(false, function(err) {
if (err) {
return callback(err);
}
key = that._encodeKey(table, key);
that._nosqldbRpc.get([table, key, columns, consistency], function(err, res) {
if (err) {
return callback(that._handleError(err));
}
callback(null, that._handleResult(table, res));
});
});
};
Nosqldb.prototype.multiGet = function(items, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
var consistency = options.consistency || 'default';
var that = this;
this._getMetadata(false, function(err) {
if (err) {
return callback(err);
}
var encodedItems = items.map(function(item) {
return {
table: item.table,
key: that._encodeKey(item.table, item.key),
columns: item.columns
};
});
that._nosqldbRpc.multi_get([encodedItems, consistency], function(err, res) {
if (err) {
return callback(that._handleError(err));
}
var results = res.map(function(result, i) {
return that._handleResult(items[i].table, result);
});
callback(null, results);
});
});
};
Nosqldb.prototype.getRange = function(table, keyPrefix, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
var rangeLt = options.rangeLt || null;
var rangeLte = options.rangeLte || null;
var rangeGt = options.rangeGt || null;
var rangeGte = options.rangeGte || null;
var columns = options.columns || null;
var orderBy = options.orderBy || null;
var limit = options.limit || null;
var consistency = options.consistency || 'default';
var that = this;
this._getMetadata(false, function(err) {
if (err) {
return callback(err);
}
keyPrefix = that._encodeKey(table, keyPrefix);
that._nosqldbRpc.get_range([
table, keyPrefix,
rangeLt, rangeLte, rangeGt, rangeGte,
columns, orderBy, limit, consistency
], function(err, res) {
if (err) {
return callback(that._handleError(err));
}
callback(null, that._handleResult(table, res));
});
});
};
Nosqldb.prototype.remove = function(table, key, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
var columns = options.columns || null;
var consistency = options.consistency || 'default';
var that = this;
this._getMetadata(false, function(err) {
if (err) {
return callback(err);
}
key = that._encodeKey(table, key);
that._nosqldbRpc.remove([table, key, columns, consistency], function(err, res) {
if (err) {
return callback(that._handleError(err));
}
callback(null, null);
});
});
};
Nosqldb.prototype.batch = function(batch, options, callback) {
if (typeof options === 'function') {
callback = options;
options = {};
}
var consistency = options.consistency || 'default';
var that = this;
var operations = [];
this._getMetadata(false, function(err) {
if (err) {
return callback(err);
}
batch.operations.forEach(function(operation) {
var name = operation.name;
var params = operation.params;
if (name === 'insert') {
operations.push(['insert', [
params.table,
that._encodeKey(params.table, params.key),
that._encodeColumns(params.table, params.columns),
params.ttl
]]);
}
else if (name === 'remove') {
operations.push(['remove', [
params.table,
that._encodeKey(params.table, params.key),
params.columns
]]);
}
});
that._nosqldbRpc.batch([operations, consistency], function(err, res) {
if (err) {
return callback(that._handleError(err));
}
callback(null, null);
});
});
};
Nosqldb.prototype.destroy = function() {
clearInterval(this._timerId);
};
exports.Nosqldb = Nosqldb;