UNPKG

rethinkdbdash

Version:

A Node.js driver for RethinkDB with promises and a connection pool

1,428 lines (1,281 loc) 104 kB
var Promise = require('bluebird'); var protodef = require(__dirname+'/protodef.js'); var termTypes = protodef.Term.TermType; var Error = require(__dirname+'/error.js'); var helper = require(__dirname+'/helper.js'); var ReadableStream = require(__dirname+'/stream.js'); var WritableStream = require(__dirname+'/writable_stream.js'); var TransformStream = require(__dirname+'/transform_stream.js'); function Term(r, value, error) { var self = this; var term = function(field) { if (Term.prototype._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} Term.prototype._arity(_args, 1, '(...)', self); } return term.bracket(field); } helper.changeProto(term, self); if (value === undefined) { term._query = []; } else { term._query = value; } term._r = r; // Keep a reference to r for global settings if (error !== undefined) { term._error = error; term._frames = []; } return term; } // run([connection][, options][, callback]) Term.prototype.run = function(connection, options, callback) { var self = this; if (self._error != null) { var error = new Error.ReqlRuntimeError(self._error, self._query, {b: self._frames}); return Promise.reject(error); } if (helper.isPlainObject(connection) && (typeof connection._isConnection === 'function') && (connection._isConnection() === true)) { if (typeof options === 'function') { callback = options; options = {}; } else { if (!helper.isPlainObject(options)) options = {}; } if (connection._isOpen() !== true) { return new Promise(function(resolve, reject) { reject(new Error.ReqlDriverError('`run` was called with a closed connection', self._query).setOperational()); }); } var p = new Promise(function(resolve, reject) { var token = connection._getToken(); var query = [protodef.Query.QueryType.START]; query.push(self._query); var _options = {}; var sendOptions = false; if (connection.db != null) { sendOptions = true; _options.db = self._r.db(connection.db)._query; } if (self._r.arrayLimit != null) { sendOptions = true; _options[self._translateArgs['arrayLimit']] = self._r.arrayLimit; }; var keepGoing = true; // we need it just to avoir calling resolve/reject multiple times helper.loopKeys(options, function(options, key) { if (keepGoing === true) { if ((key === 'readMode') || (key === 'durability') || (key === 'db') || (key === 'noreply') || (key === 'arrayLimit') || (key === 'profile') || (key === 'minBatchRows') || (key === 'maxBatchRows') || (key === 'maxBatchBytes') || (key === 'maxBatchSeconds') || (key === 'firstBatchScaledownFactor')) { sendOptions = true; if (key === 'db') { _options[key] = self._r.db(options[key])._query; } else if (self._translateArgs.hasOwnProperty(key)) { _options[self._translateArgs[key]] = new Term(self._r).expr(options[key])._query; } else { _options[key] = new Term(self._r).expr(options[key])._query; } } else if ((key !== 'timeFormat') && (key !== 'groupFormat') && (key !== 'binaryFormat') && (key !== 'cursor') && (key !== 'readable') && (key !== 'writable') && (key !== 'transform') && (key !== 'stream') && (key !== 'highWaterMark')) { reject(new Error.ReqlDriverError('Unrecognized option `'+key+'` in `run`. Available options are readMode <string>, durability <string>, noreply <bool>, timeFormat <string>, groupFormat: <string>, profile <bool>, binaryFormat <bool>, cursor <bool>, stream <bool>')); keepGoing = false; } } }); if (keepGoing === false) { connection.emit('release'); return // The promise was rejected in the loopKeys } if (sendOptions === true) { query.push(_options); } connection._send(query, token, resolve, reject, self._query, options); }).nodeify(callback); } else { var poolMaster = self._r.getPoolMaster(); // if self._r is defined, so is self._r.getPool() if (!poolMaster) { throw new Error.ReqlDriverError('`run` was called without a connection and no pool has been created', self._query); } else { if (typeof connection === 'function') { // run(callback); callback = connection; options = {}; } else if (helper.isPlainObject(connection)) { // run(options[, callback]) callback = options; options = connection; } else { options = {}; } var p = new Promise(function(resolve, reject) { poolMaster.getConnection().then(function(connection) { var token = connection._getToken(); var query = [protodef.Query.QueryType.START]; query.push(self._query); var _options = {}; var sendOptions = false; if (connection.db != null) { sendOptions = true; _options.db = self._r.db(connection.db)._query; } if (self._r.arrayLimit != null) { sendOptions = true; _options[self._translateArgs['arrayLimit']] = self._r.arrayLimit; }; var keepGoing = true; helper.loopKeys(options, function(options, key) { if (keepGoing === true) { if ((key === 'readMode') || (key === 'durability') || (key === 'db') || (key === 'noreply') || (key === 'arrayLimit') || (key === 'profile') || (key === 'minBatchRows') || (key === 'maxBatchRows') || (key === 'maxBatchBytes') || (key === 'maxBatchSeconds') || (key === 'firstBatchScaledownFactor')) { sendOptions = true; if (key === 'db') { _options[key] = self._r.db(options[key])._query; } else if (self._translateArgs.hasOwnProperty(key)) { _options[self._translateArgs[key]] = new Term(self._r).expr(options[key])._query } else { _options[key] = new Term(self._r).expr(options[key])._query } } else if ((key !== 'timeFormat') && (key !== 'groupFormat') && (key !== 'binaryFormat') && (key !== 'cursor') && (key !== 'readable') && (key !== 'writable') && (key !== 'transform') && (key !== 'stream') && (key !== 'highWaterMark')) { setTimeout( function() { reject(new Error.ReqlDriverError('Unrecognized option `'+key+'` in `run`. Available options are readMode <string>, durability <string>, noreply <bool>, timeFormat <string>, groupFormat: <string>, profile <bool>, binaryFormat <string>, cursor <bool>, stream <bool>')); }, 0); keepGoing = false; return false; } } }); if (keepGoing === false) { connection.emit('release'); return // The promise was rejected in the loopKeys } if (sendOptions === true) { query.push(_options); } connection._send(query, token, resolve, reject, self._query, options); }).error(function(error) { reject(error); }); }).nodeify(callback); } } //if (options.noreply) return self; // Do not return a promise if the user ask for no reply. return p; } Term.prototype.toStream = function(connection, options) { if (helper.isPlainObject(connection) && (typeof connection._isConnection === 'function') && (connection._isConnection() === true)) { if (helper.isPlainObject(options) === false) { options = {}; } if (options.readable === true) { return this._toReadableStream(connection, options); } else if (options.writable === true) { return this._toWritableStream(connection, options); } else if (options.transform === true) { return this._toTransformStream(connection, options); } else { return this._toReadableStream(connection, options); } } else { options = connection; if (helper.isPlainObject(options) === false) { options = {}; } if (options.readable === true) { return this._toReadableStream(options); } else if (options.writable === true) { return this._toWritableStream(options); } else if (options.transform === true) { return this._toTransformStream(options); } else { return this._toReadableStream(options); } } } Term.prototype._toReadableStream = function(connection, options) { var stream; var _options = {}; if (helper.isPlainObject(connection) && (typeof connection._isConnection === 'function') && (connection._isConnection() === true)) { //toStream make sure that options is an object helper.loopKeys(options, function(obj, key) { _options[key] = obj[key]; }); _options.cursor = true; stream = new ReadableStream(_options); this.run(connection, _options).then(function(cursor) { stream._setCursor(cursor); return null; }).error(function(error) { stream.emit('error', error); }); } else { helper.loopKeys(connection, function(obj, key) { _options[key] = obj[key]; }); _options.cursor = true; stream = new ReadableStream(_options); this.run(_options).then(function(cursor) { stream._setCursor(cursor); return null; }).error(function(error) { stream.emit('error', error); }); } return stream; } Term.prototype._toWritableStream = function(connection, options) { if (this._query[0] !== termTypes.TABLE) { throw new Error.ReqlDriverError('Cannot create a writable stream on something else than a table.'); } if (helper.isPlainObject(connection) && (typeof connection._isConnection === 'function') && (connection._isConnection() === true)) { return new WritableStream(this, options, connection); } else { return new WritableStream(this, connection); } } Term.prototype._toTransformStream = function(connection, options) { if (this._query[0] !== termTypes.TABLE) { throw new Error.ReqlDriverError('Cannot create a writable stream on something else than a table.'); } if (helper.isPlainObject(connection) && (typeof connection._isConnection === 'function') && (connection._isConnection() === true)) { return new TransformStream(this, options, connection); } else { return new TransformStream(this, connection); } } // Manipulating databases Term.prototype.dbCreate = function(db) { // Check for arity is done in r.prototype.dbCreate this._noPrefix(this, 'dbCreate'); var term = new Term(this._r); term._query.push(termTypes.DB_CREATE); var args = [new Term(this._r).expr(db)._query] term._fillArgs(args); return term; } Term.prototype.dbDrop = function(db) { this._noPrefix(this, 'dbDrop'); var term = new Term(this._r); term._query.push(termTypes.DB_DROP); var args = [new Term(this._r).expr(db)._query] term._fillArgs(args); return term; } Term.prototype.dbList = function() { this._noPrefix(this, 'dbList'); var term = new Term(this._r); term._query.push(termTypes.DB_LIST) return term; } // Manipulating Tables Term.prototype.tableCreate = function(table, options) { var self = this; if (self._fastArityRange(arguments.length, 1, 2) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 1, 2, 'tableCreate', self); } var term = new Term(self._r); term._query.push(termTypes.TABLE_CREATE) var args = []; if (Array.isArray(self._query) && (self._query.length > 0)) { args.push(self); // Push db } args.push(new Term(self._r).expr(table)) term._fillArgs(args); if (helper.isPlainObject(options)) { // Check for non valid key helper.loopKeys(options, function(obj, key) { if ((key !== 'primaryKey') && (key !== 'durability') && (key !== 'shards') && (key !== 'replicas') && (key !== 'primaryReplicaTag')) { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `tableCreate`', self._query, 'Available options are primaryKey <string>, durability <string>, shards <number>, replicas <number/object>, primaryReplicaTag <object>'); } }); term._query.push(new Term(self._r).expr(translateOptions(options))._query); } return term; } Term.prototype.tableDrop = function(table) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'tableDrop', this); } var term = new Term(this._r); term._query.push(termTypes.TABLE_DROP) var args = []; if (!Array.isArray(this._query) || (this._query.length > 0)) { args.push(this); // push db } args.push(new Term(this._r).expr(table)) term._fillArgs(args); return term; } Term.prototype.tableList = function() { if (this._fastArity(arguments.length, 0) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 0, 'tableList', this); } var term = new Term(this._r); term._query.push(termTypes.TABLE_LIST); var args = []; if (!Array.isArray(this._query) || (this._query.length > 0)) { args.push(this); } term._fillArgs(args); return term; } Term.prototype.indexList = function() { if (this._fastArity(arguments.length, 0) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 0, 'indexList', this); } var term = new Term(this._r); term._query.push(termTypes.INDEX_LIST); var args = [this]; term._fillArgs(args); return term; } Term.prototype.indexCreate = function(name, fn, options) { if (this._fastArityRange(arguments.length, 1, 3) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 1, 3, 'indexCreate', this); } if ((options == null) && (helper.isPlainObject(fn))) { options = fn; fn = undefined; } var term = new Term(this._r); term._query.push(termTypes.INDEX_CREATE); var args = [this]; args.push(new Term(this._r).expr(name)); if (typeof fn !== 'undefined') args.push(new Term(this._r).expr(fn)._wrap()); term._fillArgs(args); if (helper.isPlainObject(options)) { // There is no need to translate here helper.loopKeys(options, function(obj, key) { if ((key !== 'multi') && (key !== 'geo')) { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `indexCreate`', self._query, 'Available option is multi <bool> and geo <bool>'); } }); term._query.push(new Term(this._r).expr(options)._query); } return term; } Term.prototype.indexDrop = function(name) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'indexDrop', this); } var term = new Term(this._r); term._query.push(termTypes.INDEX_DROP); var args = [this, new Term(this._r).expr(name)]; term._fillArgs(args); return term; } Term.prototype.indexStatus = function() { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} var term = new Term(this._r); term._query.push(termTypes.INDEX_STATUS); var args = [this]; for(var i=0; i<_args.length; i++) { args.push(new Term(this._r).expr(_args[i])) } term._fillArgs(args); return term; } Term.prototype.indexWait = function() { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} var term = new Term(this._r); term._query.push(termTypes.INDEX_WAIT); var args = [this]; for(var i=0; i<_args.length; i++) { args.push(new Term(this._r).expr(_args[i])) } term._fillArgs(args); return term; } Term.prototype.indexRename = function(oldName, newName, options) { var self = this; if (self._fastArityRange(arguments.length, 2, 3) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 2, 3, 'indexRename', self); } var term = new Term(this._r); term._query.push(termTypes.INDEX_RENAME); var args = [this, new Term(this._r).expr(oldName), new Term(this._r).expr(newName)]; term._fillArgs(args); if (helper.isPlainObject(options)) { helper.loopKeys(options, function(obj, key) { if (key !== 'overwrite') { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `indexRename`', self._query, 'Available options are overwrite <bool>'); } }); term._query.push(new Term(self._r).expr(translateOptions(options))._query); } return term; } Term.prototype.changes = function(options) { var self = this; if (self._fastArityRange(arguments.length, 0, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 0, 1, 'changes', self); } var term = new Term(self._r); term._query.push(termTypes.CHANGES); var args = [self]; term._fillArgs(args); if (helper.isPlainObject(options)) { helper.loopKeys(options, function(obj, key) { if ((key !== 'squash') && (key !== 'includeStates') && (key !== 'includeTypes') && (key !== 'includeInitial') && (key !== 'includeOffsets')) { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `changes`', self._query, 'Available options are squash <bool>, includeInitial <bool>, includeStates <bool>, includeOffsets <bool>, includeTypes <bool>'); } }); term._query.push(new Term(self._r).expr(translateOptions(options))._query); } return term; } // Writing data Term.prototype.insert = function(documents, options) { var self = this; if (self._fastArityRange(arguments.length, 1, 2) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 1, 2, 'insert', self); } var term = new Term(self._r); term._query.push(termTypes.INSERT); var args = [self, new Term(self._r).expr(documents)]; term._fillArgs(args); if (helper.isPlainObject(options)) { helper.loopKeys(options, function(obj, key) { if ((key !== 'returnChanges') && (key !== 'durability') && (key !== 'conflict')) { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `insert`', self._query, 'Available options are returnChanges <bool>, durability <string>, conflict <string>'); } }); term._query.push(new Term(self._r).expr(translateOptions(options))._query); } return term; } Term.prototype.update = function(newValue, options) { var self = this; if (self._fastArityRange(arguments.length, 1, 2) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 1, 2, 'update', self); } var term = new Term(self._r); term._query.push(termTypes.UPDATE); var args = [self, new Term(self._r).expr(newValue)._wrap()]; term._fillArgs(args); if (helper.isPlainObject(options)) { helper.loopKeys(options, function(obj, key) { if ((key !== 'returnChanges') && (key !== 'durability') && (key !== 'nonAtomic')) { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `update`', self._query, 'Available options are returnChanges <bool>, durability <string>, nonAtomic <bool>'); } }); term._query.push(new Term(self._r).expr(translateOptions(options))._query); } return term; } Term.prototype.replace = function(newValue, options) { var self = this; if (self._fastArityRange(arguments.length, 1, 2) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 1, 2, 'replace', self); } var term = new Term(self._r); term._query.push(termTypes.REPLACE); var args = [self, new Term(self._r).expr(newValue)._wrap()]; term._fillArgs(args); if (helper.isPlainObject(options)) { helper.loopKeys(options, function(obj, key) { if ((key !== 'returnChanges') && (key !== 'durability') && (key !== 'nonAtomic')) { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `replace`', self._query, 'Available options are returnChanges <bool>, durability <string>, nonAtomic <bool>'); } }); term._query.push(new Term(self._r).expr(translateOptions(options))._query); } return term; } Term.prototype.delete = function(options) { var self = this; if (self._fastArityRange(arguments.length, 1, 2) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 0, 1, 'delete', self); } var term = new Term(self._r); term._query.push(termTypes.DELETE); var args = [self]; term._fillArgs(args); if (helper.isPlainObject(options)) { helper.loopKeys(options, function(obj, key) { if ((key !== 'returnChanges') && (key !== 'durability')) { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `delete`', self._query, 'Available options are returnChanges <bool>, durability <string>'); } }); term._query.push(new Term(self._r).expr(translateOptions(options))._query); } return term; } Term.prototype.sync = function() { if (this._fastArity(arguments.length, 0) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 0, 'sync', this); } var term = new Term(this._r); term._query.push(termTypes.SYNC) var args = [this._query]; term._fillArgs(args); return term; } // Selecting data Term.prototype.db = function(db) { this._noPrefix(this, 'db'); if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'db', this); } var term = new Term(this._r); term._query.push(termTypes.DB) var args = [new Term(this._r).expr(db)]; term._fillArgs(args); return term; } Term.prototype.table = function(table, options) { var self = this; if (self._fastArityRange(arguments.length, 1, 2) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 1, 2, 'table', self); } var term = new Term(self._r); term._query.push(termTypes.TABLE) var args = []; if (Array.isArray(self._query) && (self._query.length > 0)) { args.push(self); } args.push(new Term(self._r).expr(table)) term._fillArgs(args); if (helper.isPlainObject(options)) { helper.loopKeys(options, function(obj, key) { if (key !== 'readMode') { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `table`', self._query, 'Available option is readMode <string>'); } }); term._query.push(new Term(self._r).expr(translateOptions(options))._query); } return term; } Term.prototype.get = function(primaryKey) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'get', this); } var term = new Term(this._r); term._query.push(termTypes.GET); var args = [this, new Term(this._r).expr(primaryKey)] term._fillArgs(args); return term; } Term.prototype.getAll = function() { // We explicitly _args here, so fastArityRange is not useful var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} var term = new Term(this._r); term._query.push(termTypes.GET_ALL); var args = []; args.push(this); for(var i=0; i<_args.length-1; i++) { args.push(new Term(this._r).expr(_args[i])) } if ((_args.length > 0) && (helper.isPlainObject(_args[_args.length-1])) && (_args[_args.length-1].index !== undefined)) { term._fillArgs(args); term._query.push(new Term(this._r).expr(translateOptions(_args[_args.length-1]))._query); } else if (_args.length > 0) { args.push(new Term(this._r).expr(_args[_args.length-1])) term._fillArgs(args); } else { term._fillArgs(args); } return term; } Term.prototype.between = function(start, end, options) { var self = this; if (self._fastArityRange(arguments.length, 2, 3) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 2, 3, 'between', self); } var term = new Term(self._r); term._query.push(termTypes.BETWEEN); var args = [self, new Term(self._r).expr(start), new Term(self._r).expr(end)] term._fillArgs(args); if (helper.isPlainObject(options)) { helper.loopKeys(options, function(obj, key) { if ((key !== 'index') && (key !== 'leftBound') && (key !== 'rightBound')){ throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `between`', self._query, 'Available options are index <string>, leftBound <string>, rightBound <string>'); } }); term._query.push(new Term(self._r).expr(translateOptions(options))._query); } return term; } Term.prototype.minval = function() { var term = new Term(this._r); term._query.push(termTypes.MINVAL); return term; } Term.prototype.maxval = function() { var term = new Term(this._r); term._query.push(termTypes.MAXVAL); return term; } Term.prototype.filter = function(filter, options) { var self = this; if (self._fastArityRange(arguments.length, 1, 2) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 1, 2, 'filter', self); } var term = new Term(self._r); term._query.push(termTypes.FILTER); var args = [self, new Term(self._r).expr(filter)._wrap()] term._fillArgs(args); if (helper.isPlainObject(options)) { helper.loopKeys(options, function(obj, key) { if (key !== 'default') { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `filter`', self._query, 'Available option is filter'); } }) term._query.push(new Term(self._r).expr(translateOptions(options))._query); } return term; } // Joins Term.prototype.innerJoin = function(sequence, predicate) { if (this._fastArity(arguments.length, 2) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 2, 'innerJoin', this); } var term = new Term(this._r); term._query.push(termTypes.INNER_JOIN); var args = [this._query]; args.push(new Term(this._r).expr(sequence)._query); args.push(new Term(this._r).expr(predicate)._wrap()._query); term._fillArgs(args); return term; } Term.prototype.outerJoin = function(sequence, predicate) { if (this._fastArity(arguments.length, 2) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 2, 'outerJoin', this); } var term = new Term(this._r); term._query.push(termTypes.OUTER_JOIN); var args = [this]; args.push(new Term(this._r).expr(sequence)); args.push(new Term(this._r).expr(predicate)._wrap()); term._fillArgs(args); return term; } Term.prototype.eqJoin = function(rightKey, sequence, options) { var self = this; if (self._fastArityRange(arguments.length, 2, 3) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 2, 3, 'eqJoin', self); } var term = new Term(self._r); term._query.push(termTypes.EQ_JOIN); var args = [self]; args.push(new Term(self._r).expr(rightKey)._wrap()); args.push(new Term(self._r).expr(sequence)); term._fillArgs(args); if (helper.isPlainObject(options)) { helper.loopKeys(options, function(obj, key) { if ((key !== 'index') && (key !== 'ordered')) { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `eqJoin`', self._query, 'Available options are index <string>, ordered <boolean>'); } }) term._query.push(new Term(self._r).expr(translateOptions(options))._query); } return term; } Term.prototype.zip = function() { if (this._fastArity(arguments.length, 0) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 0, 'zip', this); } var term = new Term(this._r); term._query.push(termTypes.ZIP); var args = [this]; term._fillArgs(args); return term; } // Transformation Term.prototype.map = function() { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 1, Infinity, 'map', this); var term = new Term(this._r); term._query.push(termTypes.MAP); var args = []; if (!Array.isArray(this._query) || (this._query.length > 0)) { args.push(this); } for(var i=0; i<_args.length-1; i++) { args.push(new Term(this._r).expr(_args[i])) } // Make sure that we don't push undefined if no argument is passed to map, // in which case the server will handle the case and return an error. if (_args.length> 0) { args.push(new Term(this._r).expr(_args[_args.length-1])._wrap()) } term._fillArgs(args); return term; } Term.prototype.withFields = function() { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 1, Infinity, 'withFields', this); var term = new Term(this._r); term._query.push(termTypes.WITH_FIELDS); var args = [this]; for(var i=0; i<_args.length; i++) { args.push(new Term(this._r).expr(_args[i])) } term._fillArgs(args); return term; } Term.prototype.concatMap = function(transformation) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'concatMap', this); } var term = new Term(this._r); term._query.push(termTypes.CONCAT_MAP); var args = [this]; args.push(new Term(this._r).expr(transformation)._wrap()) term._fillArgs(args); return term; } Term.prototype.orderBy = function() { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 1, Infinity, 'orderBy', this); var term = new Term(this._r); term._query.push(termTypes.ORDER_BY); var args = [this]; for(var i=0; i<_args.length-1; i++) { if ((_args[i] instanceof Term) && ((_args[i]._query[0] === termTypes.DESC) || (_args[i]._query[0] === termTypes.ASC))) { args.push(new Term(this._r).expr(_args[i])) } else { args.push(new Term(this._r).expr(_args[i])._wrap()) } } // We actually don't need to make the difference here, but... if ((_args.length > 0) && (helper.isPlainObject(_args[_args.length-1])) && (_args[_args.length-1].index !== undefined)) { term._fillArgs(args); term._query.push(new Term(this._r).expr(translateOptions(_args[_args.length-1]))._query); } else { if ((_args[_args.length-1] instanceof Term) && ((_args[_args.length-1]._query[0] === termTypes.DESC) || (_args[_args.length-1]._query[0] === termTypes.ASC))) { args.push(new Term(this._r).expr(_args[_args.length-1])) } else { args.push(new Term(this._r).expr(_args[_args.length-1])._wrap()) } term._fillArgs(args); } return term; } Term.prototype.desc = function(field) { this._noPrefix(this, 'desc'); if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'desc', this); } var term = new Term(this._r); term._query.push(termTypes.DESC) var args = [new Term(this._r).expr(field)._wrap()]; term._fillArgs(args); return term; } Term.prototype.asc = function(field) { this._noPrefix(this, 'asc'); if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'asc', this); } var term = new Term(this._r); term._query.push(termTypes.ASC) var args = [new Term(this._r).expr(field)._wrap()]; term._fillArgs(args); return term; } Term.prototype.skip = function(value) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'skip', this); } var term = new Term(this._r); term._query.push(termTypes.SKIP) var args = [this, new Term(this._r).expr(value)] term._fillArgs(args); return term; } Term.prototype.limit = function(value) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'limit', this); } var term = new Term(this._r); term._query.push(termTypes.LIMIT) var args = [this, new Term(this._r).expr(value)] term._fillArgs(args); return term; } Term.prototype.slice = function(start, end, options) { if (this._fastArityRange(arguments.length, 1, 2) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 1, 3, 'slice', this); } var term = new Term(this._r); term._query.push(termTypes.SLICE); var args = []; args.push(this); args.push(new Term(this._r).expr(start)); if ((end !== undefined) && (options !== undefined)) { args.push(new Term(this._r).expr(end)); term._fillArgs(args); term._query.push(new Term(this._r).expr(translateOptions(options))._query); } else if ((end !== undefined) && (options === undefined)) { if (helper.isPlainObject(end) === false) { args.push(new Term(this._r).expr(end)); term._fillArgs(args); } else { term._fillArgs(args); term._query.push(new Term(this._r).expr(translateOptions(end))._query); } } else { // end and options are both undefined term._fillArgs(args); } return term; } Term.prototype.nth = function(value) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'nth', this); } var term = new Term(this._r); term._query.push(termTypes.NTH) var args = [this._query, new Term(this._r).expr(value)] term._fillArgs(args); return term; } Term.prototype.offsetsOf = function(predicate) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'indexesOf', this); } var term = new Term(this._r); term._query.push(termTypes.OFFSETS_OF) var args = [this, new Term(this._r).expr(predicate)._wrap()]; term._fillArgs(args); return term; } Term.prototype.indexesOf = Term.prototype.offsetsOf; Term.prototype.isEmpty = function() { if (this._fastArity(arguments.length, 0) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 0, 'isEmpty', this); } var term = new Term(this._r); term._query.push(termTypes.IS_EMPTY) var args = [this]; term._fillArgs(args); return term; } Term.prototype.union = function() { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} var term = new Term(this._r); term._query.push(termTypes.UNION) var args = []; if (!Array.isArray(this._query) || (this._query.length > 0)) { args.push(this); } for(var i=0; i<_args.length-1; i++) { args.push(new Term(this._r).expr(_args[i])) } if ((_args.length > 1) && (helper.isPlainObject(_args[_args.length-1])) && (_args[_args.length-1].interleave !== undefined)) { term._fillArgs(args); term._query.push(new Term(this._r).expr(translateOptions(_args[_args.length-1]))._query); } else if (_args.length > 0) { args.push(new Term(this._r).expr(_args[_args.length-1])) term._fillArgs(args); } return term; } Term.prototype.sample = function(size) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'sample', this); } var term = new Term(this._r); term._query.push(termTypes.SAMPLE) var args = [this, new Term(this._r).expr(size)]; term._fillArgs(args); return term; } // Aggregations Term.prototype.reduce = function(func) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'reduce', this); } var term = new Term(this._r); term._query.push(termTypes.REDUCE) var args = [this, new Term(this._r).expr(func)._wrap()]; term._fillArgs(args); return term; } Term.prototype.count = function(filter) { if (this._fastArityRange(arguments.length, 0, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 0, 1, 'count', this); } var term = new Term(this._r); term._query.push(termTypes.COUNT); var args = []; args.push(this); if (filter !== undefined) { args.push(new Term(this._r).expr(filter)._wrap()) } term._fillArgs(args); return term; } Term.prototype.distinct = function(options) { var self= this; if (self._fastArityRange(arguments.length, 0, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} self._arityRange(_args, 0, 1, 'distinct', self); } var term = new Term(self._r); term._query.push(termTypes.DISTINCT) var args = [self]; term._fillArgs(args); if (helper.isPlainObject(options)) { var keepGoing = true; helper.loopKeys(options, function(obj, key) { if ((keepGoing === true) && (key !== 'index')) { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `distinct`', self._query, 'Available option is index: <string>'); keepGoing = false; } }); if (keepGoing === true) { term._query.push(new Term(self._r).expr(translateOptions(options))._query); } } return term; } Term.prototype.group = function() { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} var self = this; self._arityRange(_args, 1, Infinity, 'group', self); var term = new Term(self._r); term._query.push(termTypes.GROUP); var args = [self]; for(var i=0; i<_args.length-1; i++) { args.push(new Term(self._r).expr(_args[i])._wrap()) } if (_args.length > 0) { if (helper.isPlainObject(_args[_args.length-1])) { helper.loopKeys(_args[_args.length-1], function(obj, key) { if ((key !== 'index') && (key !== 'multi')) { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `group`', self._query, 'Available options are index: <string>, multi <boolean>'); } }); term._fillArgs(args); term._query.push(new Term(self._r).expr(translateOptions(_args[_args.length-1]))._query); } else { args.push(new Term(self._r).expr(_args[_args.length-1])._wrap()) term._fillArgs(args); } } else { term._fillArgs(args); } return term; } Term.prototype.split = function(separator, max) { if (this._fastArityRange(arguments.length, 0, 2) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 0, 2, 'split', this); } var term = new Term(this._r); term._query.push(termTypes.SPLIT) var args = [this]; if (separator !== undefined) { args.push(new Term(this._r).expr(separator)) if (max !== undefined) { args.push(new Term(this._r).expr(max)) } } term._fillArgs(args); return term; } Term.prototype.ungroup = function() { if (this._fastArity(arguments.length, 0) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 0, 'ungroup', this); } var term = new Term(this._r); term._query.push(termTypes.UNGROUP) var args = [this._query]; term._fillArgs(args); return term; } Term.prototype.contains = function() { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 1, Infinity, 'contains', this); var term = new Term(this._r); term._query.push(termTypes.CONTAINS) var args = [this._query]; for(var i=0; i<_args.length; i++) { args.push(new Term(this._r).expr(_args[i])._wrap()) } term._fillArgs(args); return term; } Term.prototype.sum = function(field) { if (this._fastArityRange(arguments.length, 0, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 0, 1, 'sum', this); } var term = new Term(this._r); term._query.push(termTypes.SUM); var args = [this]; if (field !== undefined) { args.push(new Term(this._r).expr(field)._wrap()) } term._fillArgs(args); return term; } Term.prototype.avg = function(field) { if (this._fastArityRange(arguments.length, 0, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 0, 1, 'avg', this); } var term = new Term(this._r); term._query.push(termTypes.AVG) var args = [this]; if (field !== undefined) { args.push(new Term(this._r).expr(field)._wrap()) } term._fillArgs(args); return term; } Term.prototype.min = function(field) { if (this._fastArityRange(arguments.length, 0, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 0, 1, 'min', this); } var term = new Term(this._r); term._query.push(termTypes.MIN) var args = [this]; if (field !== undefined) { if (helper.isPlainObject(field)) { term._fillArgs(args); term._query.push(new Term(this._r).expr(translateOptions(field))._query); } else { args.push(new Term(this._r).expr(field)._wrap()); term._fillArgs(args); } } else { term._fillArgs(args); } return term; } Term.prototype.max = function(field) { if (this._fastArityRange(arguments.length, 0, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 0, 1, 'max', this); } var term = new Term(this._r); term._query.push(termTypes.MAX) var args = [this]; if (field !== undefined) { if (helper.isPlainObject(field)) { term._fillArgs(args); term._query.push(new Term(this._r).expr(translateOptions(field))._query); } else { args.push(new Term(this._r).expr(field)._wrap()) term._fillArgs(args); } } else { term._fillArgs(args); } return term; } Term.prototype.fold = function(base, func, options) { if (this._fastArityRange(arguments.length, 2, 3) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 2, 3, 'range', this); } var term = new Term(this._r); term._query.push(termTypes.FOLD) var args = [this, new Term(this._r).expr(base), new Term(this._r).expr(func)._wrap()]; term._fillArgs(args); if (helper.isPlainObject(options)) { helper.loopKeys(options, function(obj, key) { if ((key !== 'emit') && (key !== 'finalEmit')) { throw new Error.ReqlDriverError('Unrecognized option `'+key+'` in `fold`. Available options are emit <function>, finalEmit <function>'); } }); term._query.push(new Term(this._r).expr(translateOptions(options))._query); } return term; } // Document manipulation Term.prototype.row = function() { this._noPrefix(this, 'row'); if (this._fastArity(arguments.length, 0) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 0, 'r.row', this); } var term = new Term(this._r); term._query.push(termTypes.IMPLICIT_VAR) return term; } Term.prototype.pluck = function() { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 1, Infinity, 'pluck', this); var term = new Term(this._r); term._query.push(termTypes.PLUCK) var args = [this]; for(var i=0; i<_args.length; i++) { args.push(new Term(this._r).expr(_args[i])) } term._fillArgs(args); return term; } Term.prototype.without = function() { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 1, Infinity, 'without', this); var term = new Term(this._r); term._query.push(termTypes.WITHOUT) var args = [this]; for(var i=0; i<_args.length; i++) { args.push(new Term(this._r).expr(_args[i])) } term._fillArgs(args); return term; } Term.prototype.merge = function(arg) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arityRange(_args, 1, Infinity, 'merge', this); var term = new Term(this._r); term._query.push(termTypes.MERGE) var args = [this]; for(var i=0; i<_args.length; i++) { args.push(new Term(this._r).expr(_args[i])._wrap()) } term._fillArgs(args); return term; } Term.prototype.literal = function(obj) { this._noPrefix(this, 'literal'); // The test for arity is performed in r.literal var term = new Term(this._r); term._query.push(termTypes.LITERAL); if (arguments.length > 0) { var args = [new Term(this._r).expr(obj)]; term._fillArgs(args); } return term; } Term.prototype.append = function(value) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'append', this); } var term = new Term(this._r); term._query.push(termTypes.APPEND) var args = [this, new Term(this._r).expr(value)]; term._fillArgs(args); return term; } Term.prototype.prepend = function(value) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'prepend', this); } var term = new Term(this._r); term._query.push(termTypes.PREPEND) var args = [this, new Term(this._r).expr(value)]; term._fillArgs(args); return term; } Term.prototype.difference = function(other) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'difference', this); } var term = new Term(this._r); term._query.push(termTypes.DIFFERENCE) var args = [this, new Term(this._r).expr(other)]; term._fillArgs(args); return term; } Term.prototype.setInsert = function(other) { if (this._fastArity(arguments.length, 1) === false) { var _len = arguments.length;var _args = new Array(_len); for(var _i = 0; _i < _len; _i++) {_args[_i] = arguments[_i];} this._arity(_args, 1, 'setInsert', this); } var term = new Term(this._r); term._query.push(termTypes.SET_INSERT) var args = [this, new Term(this._r).expr(other)]; term._fillArgs(args); return term; } Term.prototype.setUnion = function(other) { if (this._fastArity(arguments.length, 1) === false) {