basho-riak-client-covs
Version:
Basho's officially supported NodeJS client for Riak
317 lines (273 loc) • 9.54 kB
JavaScript
/**
*
* Copyright 2014-present Basho Technologies, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
'use strict';
var CommandBase = require('../commandbase');
var inherits = require('util').inherits;
var Joi = require('joi');
var ByteBuffer = require('bytebuffer');
var utils = require('../../utils');
/**
* Provides the Update Set class, its builder, and its response.
* @module CRDT
*/
/**
* @class UpdateSetBase
* @constructor
* @param {Object} options The options to use for this command.
* @param {String} options.bucketType The bucket type in riak.
* @param {String} options.bucket The bucket in riak.
* @param {String} [options.key] The key for the set you want to store. Riak will generate one if not set.
* @param {Buffer} [options.context] The context from a previous fetch. Required for remove operations.
* @param {Boolean} [options.returnBody=true] Return the set.
* @param {Boolean} [options.setsAsBuffers=false] Return the set as an array of Buffers rather than strings.
* @param {Number} [options.w] The W value to use.
* @param {Number} [options.dw] The DW value to use.
* @param {Number} [options.pw] The PW value to use.
* @param {Number} [options.timeout] Set a timeout for this command.
* @param {Function} callback Rhe callback to be executed when the operation completes.
* @param {String} callback.err An error message. Will ne null if no error.
* @param {Object} callback.response The response from Riak. will be null if returnBody is not set.
* @param {String} callback.response.generatedKey If no key was supplied, Riak will generate and return one here.
* @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the set.
* @param {String[]|Buffer[]} callback.response.values An array holding the values in the set. String by default, Buffers if setsAsBuffers was used.
* @param {Object} callback.data additional error data. Will be null if no error.
* @extends CommandBase
*/
function UpdateSetBase(options, callback) {
CommandBase.call(this, 'DtUpdateReq', 'DtUpdateResp', callback);
this.validateOptions(options, schema);
}
inherits(UpdateSetBase, CommandBase);
function pbuf(self, prop) {
return new Buffer(self.options[prop]);
}
function bufferize(thing) {
if (utils.isString(thing)) {
return new Buffer(thing);
}
else if (Buffer.isBuffer(thing)) {
return thing;
}
else if (ByteBuffer.isByteBuffer(thing)) {
return thing.toBuffer();
}
throw new Error("Couldn't bufferize " + (typeof thing) + " " + thing);
}
function buflist(list) {
var newList = [];
var len = list.length;
for (var i = 0; i < len; i++) {
newList[i] = bufferize(list[i]);
}
return newList;
}
UpdateSetBase.prototype.constructDtOp = function() {
throw new Error('Not Implemented');
};
UpdateSetBase.prototype.constructPbRequest = function() {
var protobuf = this.getPbReqBuilder();
// namespace
protobuf.setType(pbuf(this, 'bucketType'));
protobuf.setBucket(pbuf(this, 'bucket'));
if (this.options.key) {
protobuf.setKey(pbuf(this, 'key'));
}
// operation
var dt_op = this.constructDtOp();
protobuf.setOp(dt_op);
// quorum
protobuf.setW(this.options.w);
protobuf.setDw(this.options.dw);
protobuf.setPw(this.options.pw);
// options
protobuf.setReturnBody(this.options.returnBody);
protobuf.setTimeout(this.options.timeout);
protobuf.setContext(this.options.context);
return protobuf;
};
UpdateSetBase.prototype.getUpdateRespValues = function(dtUpdateResp) {
throw new Error('Not Implemented');
};
UpdateSetBase.prototype.onSuccess = function(dtUpdateResp) {
var response = null;
// dtUpdateResp will be null if returnBody is not set
if (dtUpdateResp) {
var key = null;
if (dtUpdateResp.getKey()) {
key = dtUpdateResp.getKey().toString('utf8');
}
var values = this.getUpdateRespValues(dtUpdateResp);
var valuesToReturn = new Array(values.length);
var i;
for (i = 0; i < values.length; i++) {
if (this.options.setsAsBuffers) {
valuesToReturn[i] = values[i].toBuffer();
} else {
valuesToReturn[i] = values[i].toString('utf8');
}
}
response = {
generatedKey: key,
context: dtUpdateResp.getContext() ? dtUpdateResp.getContext().toBuffer() : null,
values: valuesToReturn
};
}
this._callback(null, response);
return true;
};
var schema = Joi.object().keys({
//namespace
bucket: Joi.string().required(),
// bucket type is required since default probably shouldn't have a
// datatype associated with it
bucketType: Joi.string().required(),
// key is optional because Riak can generate one
key: Joi.binary().default(null).optional(),
context: Joi.default(null).optional(),
//quorum
w: Joi.number().default(null).optional(),
dw: Joi.number().default(null).optional(),
pw: Joi.number().default(null).optional(),
//options
returnBody: Joi.boolean().default(true).optional(),
timeout: Joi.number().default(null).optional(),
setsAsBuffers: Joi.boolean().default(false).optional(),
});
/**
* @class UpdateSetBase.Builder
* @constructor
*/
function Builder() {}
/**
* Set the callback.
* @method withCallback
* @param {Function} callback the callback to be executed when the operation completes.
* @param {String} callback.err An error message. Will ne null if no error.
* @param {Object} callback.response The response from Riak. will be null if returnBody is not set.
* @param {String} callback.response.generatedKey If no key was supplied, Riak will generate and return one here.
* @param {Buffer} callback.response.context An opaque context to be used in any subsequent modification of the set.
* @param {String[]|Buffer[]} callback.response.values An array holding the values in the set. String by default, Buffers if setsAsBuffers was used.
*/
utils.bb(Builder, 'callback');
/**
* Set the bucket type.
* @method withBucketType
* @param {String} bucketType the bucket type in riak
* @chainable
*/
utils.bb(Builder, 'bucketType');
/**
* Set the bucket.
* @method withBucket
* @param {String} bucket the bucket in Riak
* @chainable
*/
utils.bb(Builder, 'bucket');
/**
* Set the key.
* If this is not set one will be generated by and returned from Riak
* @method withKey
* @param {String} key the key in riak.
* @chainable
*/
utils.bb(Builder, 'key');
/**
* Set the causal context. The context is necessary for set removals. It is
* an opaque field, and should not be parsed or modified.
* @method withContext
* @param {ByteBuffer} context the causal context
* @chainable
*/
utils.bb(Builder, 'context');
/**
* Return sets as arrays of Buffers rather than strings.
* By default the contents of sets are converted to strings. Setting this
* to true will cause this not to occur and the raw bytes returned
* as Buffer objects.
* @method withSetsAsBuffers
* @param {Boolean} setsAsBuffers true to not convert set contents to strings.
* @chainable
*/
utils.bb(Builder, 'setsAsBuffers');
/**
* Set the W value.
* If not set the bucket default is used.
* @method withW
* @param {Number} w the W value.
* @chainable
*/
utils.bb(Builder, 'w');
/**
* Set the DW value.
* If not set the bucket default is used.
* @method withDw
* @param {Number} dw the DW value.
* @chainable
*/
utils.bb(Builder, 'dw');
/**
* Set the PW value.
* If not set the bucket default is used.
* @method withPw
* @param {Number} pw the PW value.
* @chainable
*/
utils.bb(Builder, 'pw');
/**
* Set the return_body value.
* If true, the callback is passed the contents of the set after the update.
* @method withReturnBody
* @param {Boolean} returnBody the return_body value.
* @chainable
*/
utils.bb(Builder, 'returnBody');
/**
* Set the basic_quorum value.
* The parameter controls whether a read request should return early in
* some fail cases.
* E.g. If a quorum of nodes has already
* returned notfound/error, don't wait around for the rest.
* @method withBasicQuorum
* @param {Boolean} useBasicQuorum the basic_quorum value.
* @chainable
*/
utils.bb(Builder, 'useBasicQuorum');
/**
* Set a timeout for this operation.
* @method withTimeout
* @param {Number} timeout a timeout in milliseconds.
* @chainable
*/
utils.bb(Builder, 'timeout');
/**
* The values you wish to add to this set.
* @method withAdditions
* @param {String[]|Buffer[]} additions The values to add.
* @chainable
*/
utils.bb(Builder, 'additions');
/**
* The values you wish to remove from this set.
* __Note:__ when performing removals a context must be provided.
* @method withRemovals
* @param {String[]|Buffer[]} removals The values to remove.
* @chainable
*/
utils.bb(Builder, 'removals');
module.exports = UpdateSetBase;
module.exports.Builder = Builder;
module.exports.buflist = buflist;