| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146 |
- "use strict";
- // TODO: Look into merging with ExpressionContext and possibly ObjectCtx.
- /**
- * The state used as input and working space for Expressions.
- * @class Variables
- * @namespace mungedb-aggregate.pipeline.expressions
- * @module mungedb-aggregate
- * @constructor
- */
- var Variables = module.exports = function Variables(numVars, root){
- if (arguments.length === 0) numVars = 0; // This is only for expressions that use no variables (even ROOT).
- if (typeof numVars !== "number") throw new Error("numVars must be a Number");
- this._root = root || {};
- this._rest = numVars === 0 ? null : new Array(numVars);
- this._numVars = numVars;
- }, klass = Variables, proto = klass.prototype;
- klass.uassertValidNameForUserWrite = function uassertValidNameForUserWrite(varName) {
- // System variables users allowed to write to (currently just one)
- if (varName === "CURRENT") {
- return;
- }
- if (!varName)
- throw new Error("empty variable names are not allowed; uassert code 16866");
- var firstCharIsValid = (varName[0] >= "a" && varName[0] <= "z") ||
- (varName[0] & "\x80"); // non-ascii
- if (!firstCharIsValid)
- throw new Error("'" + varName + "' starts with an invalid character for a user variable name; uassert code 16867");
- for (var i = 1, l = varName.length; i < l; i++) {
- var charIsValid = (varName[i] >= 'a' && varName[i] <= 'z') ||
- (varName[i] >= 'A' && varName[i] <= 'Z') ||
- (varName[i] >= '0' && varName[i] <= '9') ||
- (varName[i] == '_') ||
- (varName[i] & '\x80'); // non-ascii
- if (!charIsValid)
- throw new Error("'" + varName + "' contains an invalid character " +
- "for a variable name: '" + varName[i] + "'; uassert code 16868");
- }
- };
- klass.uassertValidNameForUserRead = function uassertValidNameForUserRead(varName) {
- if (!varName)
- throw new Error("empty variable names are not allowed; uassert code 16869");
- var firstCharIsValid = (varName[0] >= "a" && varName[0] <= "z") ||
- (varName[0] >= "A" && varName[0] <= "Z") ||
- (varName[0] & "\x80"); // non-ascii
- if (!firstCharIsValid)
- throw new Error("'" + varName + "' starts with an invalid character for a variable name; uassert code 16870");
- for (var i = 1, l = varName.length; i < l; i++) {
- var charIsValid = (varName[i] >= "a" && varName[i] <= "z") ||
- (varName[i] >= "A" && varName[i] <= "Z") ||
- (varName[i] >= "0" && varName[i] <= "9") ||
- (varName[i] == "_") ||
- (varName[i] & "\x80"); // non-ascii
- if (!charIsValid)
- throw new Error("'" + varName + "' contains an invalid character " +
- "for a variable name: '" + varName[i] + "'; uassert code 16871");
- }
- };
- /**
- * Inserts a value with the given id
- * @method setValue
- * @param id {Number} The index where the value is stored in the _rest Array
- * @param value {Value} The value to store
- */
- proto.setValue = function setValue(id, value) {
- if (typeof id !== "number") throw new Error("id must be a Number");
- if (id === klass.ROOT_ID) throw new Error("can't use Variables#setValue to set ROOT; massert code 17199");
- if (id >= this._numVars) throw new Error("Assertion error");
- this._rest[id] = value;
- };
- /**
- * Get the value at the given id
- * @method getValue
- * @param id {Number} The index where the value was stored
- * @return {Value} The value
- */
- proto.getValue = function getValue(id) {
- if (typeof id !== "number") throw new Error("id must be a Number");
- if (id === klass.ROOT_ID)
- return this._root;
- if (id >= this._numVars) throw new Error("Assertion error");
- return this._rest[id];
- };
- /**
- * Get the value for id if it's a document
- * @method getDocument
- * @param id {Number} The index where the document was stored
- * @return {Object} The document
- */
- proto.getDocument = function getDocument(id) {
- if (typeof id !== "number") throw new Error("id must be a Number");
- if (id === klass.ROOT_ID)
- return this._root;
- if (id >= this._numVars) throw new Error("Assertion error");
- var value = this._rest[id];
- if (value instanceof Object && value.constructor === Object)
- return value;
- return {};
- };
- klass.ROOT_ID = -1;
- /**
- * Use this instead of setValue for setting ROOT
- * @method setRoot
- * @parameter root {Document} The root variable
- */
- proto.setRoot = function setRoot(root){
- if (!(root instanceof Object && root.constructor === Object)) throw new Error("Assertion failure");
- this._root = root;
- };
- /**
- * Clears the root variable
- * @method clearRoot
- */
- proto.clearRoot = function clearRoot(){
- this._root = {};
- };
- /**
- * Gets the root variable
- * @method getRoot
- * @return {Document} the root variable
- */
- proto.getRoot = function getRoot(){
- return this._root;
- };
|