const char* JS_server_ahuacatl[] = { "////////////////////////////////////////////////////////////////////////////////", "/// @brief Ahuacatl, internal query functions ", "///", "/// @file", "///", "/// DISCLAIMER", "///", "/// Copyright 2010-2012 triagens GmbH, Cologne, Germany", "///", "/// 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.", "///", "/// Copyright holder is triAGENS GmbH, Cologne, Germany", "///", "/// @author Jan Steemann", "/// @author Copyright 2012, triAGENS GmbH, Cologne, Germany", "////////////////////////////////////////////////////////////////////////////////", "", "var internal = require(\"internal\");", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief type weight used for sorting and comparing", "////////////////////////////////////////////////////////////////////////////////", "", "var AHUACATL_TYPEWEIGHT_NULL = 0;", "var AHUACATL_TYPEWEIGHT_BOOL = 1;", "var AHUACATL_TYPEWEIGHT_NUMBER = 2;", "var AHUACATL_TYPEWEIGHT_STRING = 4;", "var AHUACATL_TYPEWEIGHT_LIST = 8;", "var AHUACATL_TYPEWEIGHT_DOCUMENT = 16;", "", "// -----------------------------------------------------------------------------", "// --SECTION-- helper functions", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief throw a runtime exception", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_THROW (error, data) {", " var err = new ArangoError", "", " err.errorNum = error.code;", " if (data) {", " err.errorMessage = error.message.replace(/%s/, data);", " }", " else {", " err.errorMessage = error.message;", " }", "", " throw err;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief find an index of a certain type for a collection", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_INDEX (collection, indexTypes) {", " var indexes = collection.getIndexesNL();", "", " for (var i = 0; i < indexes.length; ++i) {", " var index = indexes[i];", "", " for (var j = 0; j < indexTypes.length; ++j) {", " if (index.type == indexTypes[j]) {", " return index.id;", " }", " }", " }", "", " return null;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief normalize a value for comparison, sorting etc.", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_NORMALIZE (value) {", " if (value === null || value === undefined) {", " return null;", " }", " if (typeof(value) !== \"object\") {", " return value;", " }", "", " if (Array.isArray(value)) {", " var result = [ ];", " var length = value.length;", " for (var i = 0; i < length; ++i) {", " result.push(AHUACATL_NORMALIZE(value[i]));", " }", " ", " return result;", " } ", " else {", " var attributes = [ ];", " for (var attribute in value) {", " if (!value.hasOwnProperty(attribute)) {", " continue;", " }", " attributes.push(attribute);", " }", " attributes.sort();", "", " var result = { };", " var length = attributes.length;", " for (var i = 0; i < length; ++i) {", " result[attributes[i]] = AHUACATL_NORMALIZE(value[attributes[i]]);", " }", "", " return result;", " }", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief clone an object", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_CLONE (obj) {", " if (obj == null) {", " return obj;", " }", "", " if (typeof(obj) != \"object\") {", " return obj;", " }", "", " if (Array.isArray(obj)) {", " var copy = [];", " var length = obj.length;", " for (var i = 0; i < length; ++i) {", " copy[i] = AHUACATL_CLONE(obj[i]);", " }", " return copy;", " }", "", " if (obj instanceof Object) {", " var copy = {};", " for (var attr in obj) {", " if (obj.hasOwnProperty(attr)) {", " copy[attr] = AHUACATL_CLONE(obj[attr]);", " }", " }", " return copy;", " }", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief validate function call argument", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_ARG_CHECK (actualValue, expectedType, functionName) {", " if (AHUACATL_TYPEWEIGHT(actualValue) !== expectedType) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, functionName);", " }", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief call a function", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_FCALL (name, parameters) {", " return name.apply(null, parameters);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief return the numeric value or undefined if it is out of range", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_NUMERIC_VALUE (value) {", " if (isNaN(value) || !isFinite(value)) {", " return null;", " }", "", " return value;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief fix a value for a comparison", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_FIX (value) {", " if (value === undefined) {", " return null;", " }", "", " return value;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get the name for a type", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_TYPENAME (value) {", " switch (value) {", " case AHUCATL_TYPEWEIGHT_BOOL:", " return 'boolean';", " case AHUCATL_TYPEWEIGHT_NUMBER:", " return 'number';", " case AHUCATL_TYPEWEIGHT_STRING:", " return 'string';", " case AHUCATL_TYPEWEIGHT_LIST:", " return 'list';", " case AHUCATL_TYPEWEIGHT_DOCUMENT:", " return 'document';", " case AHUCATL_TYPEWEIGHT_NULL:", " default:", " return 'null';", " }", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get the sort type of an operand", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_TYPEWEIGHT (value) {", " if (value === undefined || value === null) {", " return AHUACATL_TYPEWEIGHT_NULL;", " }", "", " if (Array.isArray(value)) {", " return AHUACATL_TYPEWEIGHT_LIST;", " }", "", " switch (typeof(value)) {", " case 'boolean':", " return AHUACATL_TYPEWEIGHT_BOOL;", " case 'number':", " if (isNaN(value) || !isFinite(value)) {", " // not a number => undefined", " return AHUACATL_TYPEWEIGHT_NULL; ", " }", " return AHUACATL_TYPEWEIGHT_NUMBER;", " case 'string':", " return AHUACATL_TYPEWEIGHT_STRING;", " case 'object':", " return AHUACATL_TYPEWEIGHT_DOCUMENT;", " }", "", " return AHUACATL_TYPEWEIGHT_NULL;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get the keys of an array or object in a comparable way", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_KEYS (value, doSort) {", " var keys = [];", " ", " if (Array.isArray(value)) {", " var n = value.length;", " for (var j = 0; j < n; ++j) {", " keys.push(j);", " }", " }", " else {", " for (var k in value) {", " if (value.hasOwnProperty(k)) {", " keys.push(k);", " }", " }", "", " if (doSort) {", " // object keys need to be sorted by names", " keys.sort();", " }", " }", "", " return keys;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get the keys of an array or object in a comparable way", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_KEYLIST (lhs, rhs) {", " var keys = [];", " ", " if (Array.isArray(lhs)) {", " // lhs & rhs are lists", " var n;", " if (lhs.length > rhs.length) {", " n = lhs.length;", " }", " else {", " n = rhs.length;", " }", " for (var j = 0; j < n; ++j) {", " keys.push(j);", " }", " return keys;", " }", "", " // lhs & rhs are arrays", " var k;", " for (k in lhs) {", " keys.push(k);", " }", " for (k in rhs) {", " if (lhs.hasOwnProperty(k)) {", " continue;", " }", " keys.push(k);", " }", "", " // object keys need to be sorted by names", " keys.sort();", "", " return keys;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get an indexed value from an array or document (e.g. users[3])", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GET_INDEX (value, index) {", " if (AHUACATL_TYPEWEIGHT(value) == AHUACATL_TYPEWEIGHT_NULL) {", " return null;", " }", " ", " if (AHUACATL_TYPEWEIGHT(value) != AHUACATL_TYPEWEIGHT_LIST &&", " AHUACATL_TYPEWEIGHT(value) != AHUACATL_TYPEWEIGHT_DOCUMENT) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_LIST_EXPECTED);", " }", "", " var result = value[index];", "", " if (AHUACATL_TYPEWEIGHT(result) === AHUACATL_TYPEWEIGHT_NULL) {", " return null;", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get an attribute from a document (e.g. users.name)", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_DOCUMENT_MEMBER (value, attributeName) {", " if (AHUACATL_TYPEWEIGHT(value) == AHUACATL_TYPEWEIGHT_NULL) {", " return null;", " }", "", " if (AHUACATL_TYPEWEIGHT(value) != AHUACATL_TYPEWEIGHT_DOCUMENT) {", " return null;", " }", "", " var result = value[attributeName];", "", " if (AHUACATL_TYPEWEIGHT(result) === AHUACATL_TYPEWEIGHT_NULL) {", " return null;", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief assert that a value is a list, fail otherwise", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_LIST (value) {", " if (AHUACATL_TYPEWEIGHT(value) !== AHUACATL_TYPEWEIGHT_LIST) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_LIST_EXPECTED);", " }", "", " return value;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get all documents from the specified collection", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GET_DOCUMENTS (collection) {", " return internal.db[collection].ALL_NL(0, null).documents;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get documents from the specified collection using the primary index", "/// (single index value)", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GET_DOCUMENTS_PRIMARY (collection, idx, id) {", " try {", " return [ internal.db[collection].document_nl(id) ];", " }", " catch (e) {", " return [ ];", " }", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get documents from the specified collection using the primary index", "/// (multiple index values)", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GET_DOCUMENTS_PRIMARY_LIST (collection, idx, values) {", " var result = [ ];", "", " for (var i in values) {", " var id = values[i];", " try {", " var d = internal.db[collection].document_nl(id);", " result.push(d);", " }", " catch (e) {", " }", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get documents from the specified collection using a hash index", "/// (single index value)", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GET_DOCUMENTS_HASH (collection, idx, example) {", " return internal.db[collection].BY_EXAMPLE_HASH_NL(idx, example).documents;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get documents from the specified collection using a hash index", "/// (multiple index values)", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GET_DOCUMENTS_HASH_LIST (collection, idx, attribute, values) {", " var result = [ ];", "", " for (var i in values) {", " var value = values[i];", " var example = { };", "", " example[attribute] = value;", "", " var documents = internal.db[collection].BY_EXAMPLE_HASH_NL(idx, example).documents;", " for (var j in documents) {", " result.push(documents[j]);", " }", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get documents from the specified collection using a bitarray", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GET_DOCUMENTS_BITARRAY (collection, idx, example) {", " return internal.db[collection].BY_CONDITION_BITARRAY(idx, example).documents;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get documents from the specified collection using a bitarray", "/// (multiple index values) TODO: replace by 'IN index operator'", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GET_DOCUMENTS_BITARRAY_LIST (collection, idx, attribute, values) {", " var result = [ ];", "", " for (var i in values) {", " var value = values[i];", " var example = { };", "", " example[attribute] = value;", "", " var documents = internal.db[collection].BY_EXAMPLE_BITARRAY(idx, example).documents;", " for (var j in documents) {", " result.push(documents[j]);", " }", " }", "", " return result;", "}", "", "", "", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get documents from the specified collection using a skiplist", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GET_DOCUMENTS_SKIPLIST (collection, idx, example) {", " return internal.db[collection].BY_CONDITION_SKIPLIST_NL(idx, example).documents;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get documents from the specified collection using a skiplist", "/// (multiple index values)", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GET_DOCUMENTS_SKIPLIST_LIST (collection, idx, attribute, values) {", " var result = [ ];", "", " for (var i in values) {", " var value = values[i];", " var example = { };", "", " example[attribute] = value;", "", " var documents = internal.db[collection].BY_EXAMPLE_SKIPLIST_NL(idx, example).documents;", " for (var j in documents) {", " result.push(documents[j]);", " }", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get names of all collections", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_COLLECTIONS () {", " var collections = internal.db._collections();", " var result = [ ];", "", " for (var i = 0; i < collections.length; ++i) {", " result.push({ \"_id\" : collections[i]._id, \"name\" : collections[i].name() });", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- logical operations", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief execute ternary operator", "///", "/// the condition operand must be a boolean value, returns either the truepart", "/// or the falsepart ", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_TERNARY_OPERATOR (condition, truePart, falsePart) {", " if (AHUACATL_TYPEWEIGHT(condition) !== AHUACATL_TYPEWEIGHT_BOOL) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_INVALID_LOGICAL_VALUE);", " }", "", " if (condition) {", " return truePart;", " }", " return falsePart;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform logical and", "///", "/// both operands must be boolean values, returns a boolean, uses short-circuit", "/// evaluation", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_LOGICAL_AND (lhs, rhs) {", " if (AHUACATL_TYPEWEIGHT(lhs) !== AHUACATL_TYPEWEIGHT_BOOL ||", " AHUACATL_TYPEWEIGHT(rhs) !== AHUACATL_TYPEWEIGHT_BOOL) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_INVALID_LOGICAL_VALUE);", " }", "", " if (!lhs) {", " return false;", " }", "", " return rhs;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform logical or", "///", "/// both operands must be boolean values, returns a boolean, uses short-circuit", "/// evaluation", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_LOGICAL_OR (lhs, rhs) {", " if (AHUACATL_TYPEWEIGHT(lhs) !== AHUACATL_TYPEWEIGHT_BOOL ||", " AHUACATL_TYPEWEIGHT(rhs) !== AHUACATL_TYPEWEIGHT_BOOL) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_INVALID_LOGICAL_VALUE);", " }", " ", " if (lhs) {", " return true;", " }", "", " return rhs;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform logical negation", "///", "/// the operand must be a boolean values, returns a boolean", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_LOGICAL_NOT (lhs) {", " if (AHUACATL_TYPEWEIGHT(lhs) !== AHUACATL_TYPEWEIGHT_BOOL) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_INVALID_LOGICAL_VALUE);", " }", "", " return !lhs;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- comparison operations", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform equality check ", "///", "/// returns true if the operands are equal, false otherwise", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_EQUAL (lhs, rhs) {", " var leftWeight = AHUACATL_TYPEWEIGHT(lhs);", " var rightWeight = AHUACATL_TYPEWEIGHT(rhs);", "", " if (leftWeight != rightWeight) {", " return false;", " }", "", " // lhs and rhs have the same type", "", " if (leftWeight >= AHUACATL_TYPEWEIGHT_LIST) {", " // arrays and objects", " var keys = AHUACATL_KEYLIST(lhs, rhs);", "", " for (var i in keys) {", " var key = keys[i];", " var result = AHUACATL_RELATIONAL_EQUAL(lhs[key], rhs[key]);", " if (result === false) {", " return result;", " }", " }", " return true;", " }", "", " // primitive type", " if (AHUACATL_TYPEWEIGHT(lhs) === AHUACATL_TYPEWEIGHT_NULL) {", " lhs = null;", " }", " if (AHUACATL_TYPEWEIGHT(rhs) === AHUACATL_TYPEWEIGHT_NULL) {", " rhs = null;", " }", "", " if (leftWeight === AHUACATL_TYPEWEIGHT_STRING) {", " return COMPARE_STRING(lhs, rhs) == 0;", " }", "", " return (lhs === rhs);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform inequality check ", "///", "/// returns true if the operands are unequal, false otherwise", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_UNEQUAL (lhs, rhs) {", " var leftWeight = AHUACATL_TYPEWEIGHT(lhs);", " var rightWeight = AHUACATL_TYPEWEIGHT(rhs);", " ", " if (leftWeight != rightWeight) {", " return true;", " }", "", " // lhs and rhs have the same type", "", " if (leftWeight >= AHUACATL_TYPEWEIGHT_LIST) {", " // arrays and objects", " var keys = AHUACATL_KEYLIST(lhs, rhs);", "", " for (var i in keys) {", " var key = keys[i];", " var result = AHUACATL_RELATIONAL_UNEQUAL(lhs[key], rhs[key]);", " if (result === true) {", " return result;", " }", " }", "", " return false;", " }", "", " // primitive type", " if (AHUACATL_TYPEWEIGHT(lhs) === AHUACATL_TYPEWEIGHT_NULL) {", " lhs = null;", " }", " if (AHUACATL_TYPEWEIGHT(rhs) === AHUACATL_TYPEWEIGHT_NULL) {", " rhs = null;", " }", "", " if (leftWeight === AHUACATL_TYPEWEIGHT_STRING) {", " return COMPARE_STRING(lhs, rhs) != 0;", " }", "", " return (lhs !== rhs);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform greater than check (inner function)", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_GREATER_REC (lhs, rhs) {", " var leftWeight = AHUACATL_TYPEWEIGHT(lhs);", " var rightWeight = AHUACATL_TYPEWEIGHT(rhs);", " ", " if (leftWeight > rightWeight) {", " return true;", " }", " if (leftWeight < rightWeight) {", " return false;", " }", "", " // lhs and rhs have the same type", "", " if (leftWeight >= AHUACATL_TYPEWEIGHT_LIST) {", " // arrays and objects", " var keys = AHUACATL_KEYLIST(lhs, rhs);", "", " for (var i in keys) {", " var key = keys[i];", " var result = AHUACATL_RELATIONAL_GREATER_REC(lhs[key], rhs[key]);", " if (result !== null) {", " return result;", " }", " }", " ", " return null;", " }", "", " // primitive type", " if (AHUACATL_TYPEWEIGHT(lhs) === AHUACATL_TYPEWEIGHT_NULL) {", " lhs = null;", " }", " if (AHUACATL_TYPEWEIGHT(rhs) === AHUACATL_TYPEWEIGHT_NULL) {", " rhs = null;", " }", "", " if (leftWeight === AHUACATL_TYPEWEIGHT_STRING) {", " return COMPARE_STRING(lhs, rhs) > 0;", " }", "", " if (lhs === rhs) {", " return null;", " }", "", " return (lhs > rhs);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform greater than check ", "///", "/// returns true if the left operand is greater than the right operand", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_GREATER (lhs, rhs) {", " var result = AHUACATL_RELATIONAL_GREATER_REC(lhs, rhs);", "", " if (result === null) {", " result = false;", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform greater equal check (inner function)", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_GREATEREQUAL_REC (lhs, rhs) {", " var leftWeight = AHUACATL_TYPEWEIGHT(lhs);", " var rightWeight = AHUACATL_TYPEWEIGHT(rhs);", " ", " if (leftWeight > rightWeight) {", " return true;", " }", " if (leftWeight < rightWeight) {", " return false;", " }", "", " // lhs and rhs have the same type", "", " if (leftWeight >= AHUACATL_TYPEWEIGHT_LIST) {", " // arrays and objects", " var keys = AHUACATL_KEYLIST(lhs, rhs);", "", " for (var i in keys) {", " var key = keys[i];", " var result = AHUACATL_RELATIONAL_GREATEREQUAL_REC(lhs[key], rhs[key]);", " if (result !== null) {", " return result;", " }", " }", " ", " return null;", " }", "", " // primitive type", " if (AHUACATL_TYPEWEIGHT(lhs) === AHUACATL_TYPEWEIGHT_NULL) {", " lhs = null;", " }", " if (AHUACATL_TYPEWEIGHT(rhs) === AHUACATL_TYPEWEIGHT_NULL) {", " rhs = null;", " }", "", " if (leftWeight === AHUACATL_TYPEWEIGHT_STRING) {", " return COMPARE_STRING(lhs, rhs) >= 0;", " }", "", " if (lhs === rhs) {", " return null;", " }", "", " return (lhs >= rhs);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform greater equal check ", "///", "/// returns true if the left operand is greater or equal to the right operand", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_GREATEREQUAL (lhs, rhs) {", " var result = AHUACATL_RELATIONAL_GREATEREQUAL_REC(lhs, rhs);", "", " if (result === null) {", " result = true;", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform less than check (inner function)", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_LESS_REC (lhs, rhs) {", " var leftWeight = AHUACATL_TYPEWEIGHT(lhs);", " var rightWeight = AHUACATL_TYPEWEIGHT(rhs);", " ", " if (leftWeight < rightWeight) {", " return true;", " }", " if (leftWeight > rightWeight) {", " return false;", " }", "", " // lhs and rhs have the same type", "", " if (leftWeight >= AHUACATL_TYPEWEIGHT_LIST) {", " // arrays and objects", " var keys = AHUACATL_KEYLIST(lhs, rhs);", "", " for (var i in keys) {", " var key = keys[i];", " var result = AHUACATL_RELATIONAL_LESS_REC(lhs[key], rhs[key]);", " if (result !== null) {", " return result;", " }", " }", " ", " return null;", " }", "", " // primitive type", " if (AHUACATL_TYPEWEIGHT(lhs) === AHUACATL_TYPEWEIGHT_NULL) {", " lhs = null;", " }", " if (AHUACATL_TYPEWEIGHT(rhs) === AHUACATL_TYPEWEIGHT_NULL) {", " rhs = null;", " }", "", " if (leftWeight === AHUACATL_TYPEWEIGHT_STRING) {", " return COMPARE_STRING(lhs, rhs) < 0;", " }", "", " if (lhs === rhs) {", " return null;", " }", "", " return (lhs < rhs);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform less than check ", "///", "/// returns true if the left operand is less than the right operand", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_LESS (lhs, rhs) {", " var result = AHUACATL_RELATIONAL_LESS_REC(lhs, rhs);", "", " if (result === null) {", " result = false;", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform less equal check (inner function)", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_LESSEQUAL_REC (lhs, rhs) {", " var leftWeight = AHUACATL_TYPEWEIGHT(lhs);", " var rightWeight = AHUACATL_TYPEWEIGHT(rhs);", " ", " if (leftWeight < rightWeight) {", " return true;", " }", " if (leftWeight > rightWeight) {", " return false;", " }", "", " // lhs and rhs have the same type", "", " if (leftWeight >= AHUACATL_TYPEWEIGHT_LIST) {", " // arrays and objects", " var keys = AHUACATL_KEYLIST(lhs, rhs);", "", " for (var i in keys) {", " var key = keys[i];", " var result = AHUACATL_RELATIONAL_LESSEQUAL_REC(lhs[key], rhs[key]);", " if (result !== null) {", " return result;", " }", " }", "", " return null;", " }", " ", " // primitive type", " if (AHUACATL_TYPEWEIGHT(lhs) === AHUACATL_TYPEWEIGHT_NULL) {", " lhs = null;", " }", " if (AHUACATL_TYPEWEIGHT(rhs) === AHUACATL_TYPEWEIGHT_NULL) {", " rhs = null;", " }", " ", " if (leftWeight === AHUACATL_TYPEWEIGHT_STRING) {", " return COMPARE_STRING(lhs, rhs) <= 0;", " }", " ", " if (lhs === rhs) {", " return null;", " }", "", " return (lhs <= rhs);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform less equal check ", "///", "/// returns true if the left operand is less or equal to the right operand", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_LESSEQUAL (lhs, rhs) {", " var result = AHUACATL_RELATIONAL_LESSEQUAL_REC(lhs, rhs);", "", " if (result === null) {", " result = true;", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform comparison", "///", "/// returns -1 if the left operand is less than the right operand, 1 if it is", "/// greater, 0 if both operands are equal", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_CMP (lhs, rhs) {", " var leftWeight = AHUACATL_TYPEWEIGHT(lhs);", " var rightWeight = AHUACATL_TYPEWEIGHT(rhs);", " ", " if (leftWeight < rightWeight) {", " return -1;", " }", " if (leftWeight > rightWeight) {", " return 1;", " }", "", " // lhs and rhs have the same type", "", " if (leftWeight >= AHUACATL_TYPEWEIGHT_LIST) {", " // arrays and objects", " var keys = AHUACATL_KEYLIST(lhs, rhs);", "", " for (var i in keys) {", " var key = keys[i];", " var result = AHUACATL_RELATIONAL_CMP(lhs[key], rhs[key]);", " if (result !== 0) {", " return result;", " }", " }", " ", " return 0;", " }", "", " // primitive type", " if (AHUACATL_TYPEWEIGHT(lhs) === AHUACATL_TYPEWEIGHT_NULL) {", " lhs = null;", " }", " if (AHUACATL_TYPEWEIGHT(rhs) === AHUACATL_TYPEWEIGHT_NULL) {", " rhs = null;", " }", "", " if (leftWeight === AHUACATL_TYPEWEIGHT_STRING) {", " return COMPARE_STRING(lhs, rhs);", " }", "", " if (lhs < rhs) {", " return -1;", " }", " ", " if (lhs > rhs) {", " return 1;", " }", "", " return 0;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform in list check ", "///", "/// returns true if the left operand is contained in the right operand", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_RELATIONAL_IN (lhs, rhs) {", " var leftWeight = AHUACATL_TYPEWEIGHT(lhs);", " var rightWeight = AHUACATL_TYPEWEIGHT(rhs);", " ", " if (rightWeight !== AHUACATL_TYPEWEIGHT_LIST) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_LIST_EXPECTED);", " }", "", " var numRight = rhs.length;", " for (var i = 0; i < numRight; ++i) {", " if (AHUACATL_RELATIONAL_EQUAL(lhs, rhs[i])) {", " return true;", " }", " }", "", " return false;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- arithmetic operations", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform unary plus operation", "///", "/// the operand must be numeric or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_UNARY_PLUS (value) {", " if (AHUACATL_TYPEWEIGHT(value) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE);", " }", "", " var result = AHUACATL_NUMERIC_VALUE(value);", " if (AHUACATL_TYPEWEIGHT(result) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_NUMBER_OUT_OF_RANGE);", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform unary minus operation", "///", "/// the operand must be numeric or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_UNARY_MINUS (value) {", " if (AHUACATL_TYPEWEIGHT(value) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE);", " }", "", " var result = AHUACATL_NUMERIC_VALUE(-value);", " if (AHUACATL_TYPEWEIGHT(result) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_NUMBER_OUT_OF_RANGE);", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform artithmetic plus", "///", "/// both operands must be numeric or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_ARITHMETIC_PLUS (lhs, rhs) { ", " if (AHUACATL_TYPEWEIGHT(lhs) !== AHUACATL_TYPEWEIGHT_NUMBER ||", " AHUACATL_TYPEWEIGHT(rhs) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE);", " }", "", " var result = AHUACATL_NUMERIC_VALUE(lhs + rhs);", " if (AHUACATL_TYPEWEIGHT(result) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_NUMBER_OUT_OF_RANGE);", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform artithmetic minus", "///", "/// both operands must be numeric or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_ARITHMETIC_MINUS (lhs, rhs) {", " if (AHUACATL_TYPEWEIGHT(lhs) !== AHUACATL_TYPEWEIGHT_NUMBER ||", " AHUACATL_TYPEWEIGHT(rhs) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE);", " }", "", " var result = AHUACATL_NUMERIC_VALUE(lhs - rhs);", " if (AHUACATL_TYPEWEIGHT(result) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_NUMBER_OUT_OF_RANGE);", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform artithmetic multiplication", "///", "/// both operands must be numeric or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_ARITHMETIC_TIMES (lhs, rhs) {", " if (AHUACATL_TYPEWEIGHT(lhs) !== AHUACATL_TYPEWEIGHT_NUMBER ||", " AHUACATL_TYPEWEIGHT(rhs) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE);", " }", "", " var result = AHUACATL_NUMERIC_VALUE(lhs * rhs);", " if (AHUACATL_TYPEWEIGHT(result) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_NUMBER_OUT_OF_RANGE);", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform artithmetic division", "///", "/// both operands must be numeric or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_ARITHMETIC_DIVIDE (lhs, rhs) {", " if (AHUACATL_TYPEWEIGHT(lhs) !== AHUACATL_TYPEWEIGHT_NUMBER ||", " AHUACATL_TYPEWEIGHT(rhs) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE);", " }", " ", " if (rhs == 0) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_DIVISION_BY_ZERO);", " }", "", " var result = AHUACATL_NUMERIC_VALUE(lhs / rhs);", " if (AHUACATL_TYPEWEIGHT(result) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_NUMBER_OUT_OF_RANGE);", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform artithmetic modulus", "///", "/// both operands must be numeric or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_ARITHMETIC_MODULUS (lhs, rhs) {", " if (AHUACATL_TYPEWEIGHT(lhs) !== AHUACATL_TYPEWEIGHT_NUMBER ||", " AHUACATL_TYPEWEIGHT(rhs) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_INVALID_ARITHMETIC_VALUE);", " }", "", " if (rhs == 0) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_DIVISION_BY_ZERO);", " }", "", " var result = AHUACATL_NUMERIC_VALUE(lhs % rhs);", " if (AHUACATL_TYPEWEIGHT(result) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_NUMBER_OUT_OF_RANGE);", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- string functions", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform string concatenation", "///", "/// all operands must be strings or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_STRING_CONCAT () {", " var result = '';", "", " for (var i in arguments) {", " var element = arguments[i];", "", " if (AHUACATL_TYPEWEIGHT(element) === AHUACATL_TYPEWEIGHT_NULL) {", " continue;", " }", "", " AHUACATL_ARG_CHECK(element, AHUACATL_TYPEWEIGHT_STRING, \"CONCAT\");", "", " result += element;", " }", "", " return result; ", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief perform string concatenation using a separator character", "///", "/// all operands must be strings or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_STRING_CONCAT_SEPARATOR () {", " var separator;", " var found = false;", " var result = '';", "", " for (var i in arguments) {", " var element = arguments[i];", "", " if (i > 0 && AHUACATL_TYPEWEIGHT(element) === AHUACATL_TYPEWEIGHT_NULL) {", " continue;", " }", " ", " AHUACATL_ARG_CHECK(element, AHUACATL_TYPEWEIGHT_STRING, \"CONCAT_SEPARATOR\");", "", " if (i == 0) {", " separator = element;", " continue;", " }", " else if (found) {", " result += separator;", " }", "", " found = true;", "", " result += element;", " }", "", " return result; ", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief return the length of a string in characters (not bytes)", "///", "/// the input operand must be a string or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_STRING_LENGTH (value) {", " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"STRING_LENGTH\");", "", " return value.length;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief convert a string to lower case", "///", "/// the input operand must be a string or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_STRING_LOWER (value) {", " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"LOWER\");", "", " return value.toLowerCase();", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief convert a string to upper case", "///", "/// the input operand must be a string or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_STRING_UPPER (value) {", " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"UPPER\");", "", " return value.toUpperCase();", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief return a substring of the string", "///", "/// the input operand must be a string or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_STRING_SUBSTRING (value, offset, count) {", " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"SUBSTRING\");", " AHUACATL_ARG_CHECK(offset, AHUACATL_TYPEWEIGHT_NUMBER, \"SUBSTRING\");", "", " return value.substr(offset, count);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief searches a substring in a string", "///", "/// the two input operands must be strings or this function will fail", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_STRING_CONTAINS (value, search) {", " AHUACATL_ARG_CHECK(value, AHUACATL_TYPEWEIGHT_STRING, \"CONTAINS\");", " AHUACATL_ARG_CHECK(search, AHUACATL_TYPEWEIGHT_STRING, \"CONTAINS\");", "", " if (search.length == 0) {", " return false;", " }", "", " return value.indexOf(search) != -1;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- typecast functions", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief cast to a bool", "///", "/// the operand can have any type, always returns a bool", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_CAST_BOOL (value) {", " switch (AHUACATL_TYPEWEIGHT(value)) {", " case AHUACATL_TYPEWEIGHT_NULL:", " return false;", " case AHUACATL_TYPEWEIGHT_BOOL:", " return value;", " case AHUACATL_TYPEWEIGHT_NUMBER:", " return (value != 0);", " case AHUACATL_TYPEWEIGHT_STRING: ", " return (value !== '');", " case AHUACATL_TYPEWEIGHT_LIST:", " return (value.length > 0);", " case AHUACATL_TYPEWEIGHT_DOCUMENT:", " return (AHUACATL_KEYS(value, false).length > 0);", " }", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief cast to a number", "///", "/// the operand can have any type, always returns a number", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_CAST_NUMBER (value) {", " switch (AHUACATL_TYPEWEIGHT(value)) {", " case AHUACATL_TYPEWEIGHT_NULL:", " case AHUACATL_TYPEWEIGHT_LIST:", " case AHUACATL_TYPEWEIGHT_DOCUMENT:", " return 0.0;", " case AHUACATL_TYPEWEIGHT_BOOL:", " return (value ? 1 : 0);", " case AHUACATL_TYPEWEIGHT_NUMBER:", " return value;", " case AHUACATL_TYPEWEIGHT_STRING:", " var result = parseFloat(value);", " return ((AHUACATL_TYPEWEIGHT(result) === AHUACATL_TYPEWEIGHT_NUMBER) ? result : 0);", " }", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief cast to a string", "///", "/// the operand can have any type, always returns a string", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_CAST_STRING (value) {", " switch (AHUACATL_TYPEWEIGHT(value)) {", " case AHUACATL_TYPEWEIGHT_STRING:", " return value;", " case AHUACATL_TYPEWEIGHT_NULL:", " return 'null';", " case AHUACATL_TYPEWEIGHT_BOOL:", " return (value ? 'true' : 'false');", " case AHUACATL_TYPEWEIGHT_NUMBER:", " case AHUACATL_TYPEWEIGHT_LIST:", " case AHUACATL_TYPEWEIGHT_DOCUMENT:", " return value.toString();", " }", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- typecheck functions", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief test if value is of type null", "///", "/// returns a bool", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_IS_NULL (value) {", " return (AHUACATL_TYPEWEIGHT(value) === AHUACATL_TYPEWEIGHT_NULL);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief test if value is of type bool", "///", "/// returns a bool", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_IS_BOOL (value) {", " return (AHUACATL_TYPEWEIGHT(value) === AHUACATL_TYPEWEIGHT_BOOL);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief test if value is of type number", "///", "/// returns a bool", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_IS_NUMBER (value) {", " return (AHUACATL_TYPEWEIGHT(value) === AHUACATL_TYPEWEIGHT_NUMBER);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief test if value is of type string", "///", "/// returns a bool", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_IS_STRING (value) {", " return (AHUACATL_TYPEWEIGHT(value) === AHUACATL_TYPEWEIGHT_STRING);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief test if value is of type list", "///", "/// returns a bool", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_IS_LIST (value) {", " return (AHUACATL_TYPEWEIGHT(value) === AHUACATL_TYPEWEIGHT_LIST);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief test if value is of type document", "///", "/// returns a bool", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_IS_DOCUMENT (value) {", " return (AHUACATL_TYPEWEIGHT(value) === AHUACATL_TYPEWEIGHT_DOCUMENT);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- numeric functions", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief integer closest to value, not greater than value", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_NUMBER_FLOOR (value) {", " if (!AHUACATL_IS_NUMBER(value)) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"FLOOR\");", " }", " ", " return Math.floor(value);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief integer closest to value and not less than value", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_NUMBER_CEIL (value) {", " if (!AHUACATL_IS_NUMBER(value)) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"CEIL\");", " }", " ", " return Math.ceil(value);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief integer closest to value ", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_NUMBER_ROUND (value) {", " if (!AHUACATL_IS_NUMBER(value)) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"ROUND\");", " }", " ", " return Math.round(value);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief absolute value", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_NUMBER_ABS (value) {", " if (!AHUACATL_IS_NUMBER(value)) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"ABS\");", " }", " ", " return Math.abs(value);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief a random value between 0 and 1", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_NUMBER_RAND () {", " return Math.random();", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- high level query functions", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief sort the results", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_SORT (value, sortFunction) {", " AHUACATL_LIST(value);", " ", " var n = value.length;", " if (n > 0) {", " value.sort(sortFunction);", " }", "", " return value;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief group the results", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GROUP (value, sortFunction, groupFunction, into) {", " AHUACATL_LIST(value);", "", " var n = value.length;", " if (n == 0) {", " return [ ];", " }", "", " AHUACATL_SORT(value, sortFunction);", "", " var result = [ ];", " var currentGroup = undefined;", " var oldGroup = undefined;", " ", " for (var i = 0; i < n; ++i) {", " var row = value[i];", " var groupValue = groupFunction(row);", "", " if (AHUACATL_RELATIONAL_UNEQUAL(oldGroup, groupValue)) {", " oldGroup = AHUACATL_CLONE(groupValue);", "", " if (currentGroup) {", " result.push(AHUACATL_CLONE(currentGroup));", " }", " ", " currentGroup = groupValue;", " if (into) {", " currentGroup[into] = [ ];", " }", " }", "", " if (into) {", " currentGroup[into].push(AHUACATL_CLONE(row));", " }", " }", "", " if (currentGroup) {", " result.push(AHUACATL_CLONE(currentGroup));", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief limit the number of results", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_LIMIT (value, offset, count) {", " AHUACATL_LIST(value);", "", " if (count < 0) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_NUMBER_OUT_OF_RANGE);", " }", "", " return value.slice(offset, offset + count);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- list processing functions", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get the length of a list", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_LENGTH () {", " var value = arguments[0];", "", " AHUACATL_LIST(value);", "", " return value.length;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get the first element of a list", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_FIRST () {", " var value = arguments[0];", "", " AHUACATL_LIST(value);", "", " if (value.length == 0) {", " return null;", " }", "", " return value[0];", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief get the last element of a list", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_LAST () {", " var value = arguments[0];", "", " AHUACATL_LIST(value);", "", " if (value.length == 0) {", " return null;", " }", "", " return value[value.length - 1];", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief reverse the elements in a list", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_REVERSE () {", " var value = arguments[0];", "", " AHUACATL_LIST(value);", "", " return value.reverse();", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief return a list of unique elements from the list", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_UNIQUE () {", " var value = arguments[0];", "", " AHUACATL_LIST(value);", "", " var length = value.length;", " var keys = { };", " for (var i = 0; i < length; ++i) {", " var normalized = AHUACATL_NORMALIZE(value[i]);", " keys[JSON.stringify(normalized)] = normalized;", " }", "", " var result = [];", " for (var i in keys) {", " result.push(keys[i]);", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief create the union (all) of all arguments", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_UNION () {", " var result = [ ];", "", " for (var i in arguments) {", " var element = arguments[i];", "", " if (AHUACATL_TYPEWEIGHT(element) !== AHUACATL_TYPEWEIGHT_LIST) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"UNION\");", " }", "", " for (var k in element) {", " if (!element.hasOwnProperty(k)) {", " continue;", " }", "", " result.push(element[k]);", " }", " }", "", " return result; ", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief maximum of all values", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_MAX () {", " var result = null;", " var value = arguments[0];", "", " AHUACATL_LIST(value);", "", " for (var i in value) {", " var currentValue = value[i];", " ", " if (AHUACATL_TYPEWEIGHT(currentValue) === AHUACATL_TYPEWEIGHT_NULL) {", " continue;", " }", "", " if (result === null || AHUACATL_RELATIONAL_GREATER(currentValue, result)) {", " result = currentValue;", " }", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief minimum of all values", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_MIN () {", " var result = null;", " var value = arguments[0];", "", " AHUACATL_LIST(value);", "", " for (var i in value) {", " var currentValue = value[i];", " ", " if (AHUACATL_TYPEWEIGHT(currentValue) === AHUACATL_TYPEWEIGHT_NULL) {", " continue;", " }", " ", " if (result === null || AHUACATL_RELATIONAL_LESS(currentValue, result)) {", " result = currentValue;", " }", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief sum of all values", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_SUM () {", " var result = null;", " var value = arguments[0];", "", " AHUACATL_LIST(value);", "", " for (var i in value) {", " var currentValue = value[i];", " ", " if (AHUACATL_TYPEWEIGHT(currentValue) === AHUACATL_TYPEWEIGHT_NULL) {", " continue;", " }", "", " if (AHUACATL_TYPEWEIGHT(currentValue) !== AHUACATL_TYPEWEIGHT_NUMBER) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"SUM\");", " }", " ", " if (result === null) {", " result = currentValue;", " }", " else {", " result += currentValue;", " }", " }", "", " return AHUACATL_NUMERIC_VALUE(result);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- geo functions", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief return at most documents near a certain point", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GEO_NEAR () {", " var collection = arguments[0];", " var latitude = arguments[1];", " var longitude = arguments[2];", " var limit = arguments[3];", " var distanceAttribute = arguments[4];", "", " var idx = AHUACATL_INDEX(internal.db[collection], [ \"geo1\", \"geo2\" ]); ", " if (idx == null) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_GEO_INDEX_MISSING, collection);", " }", "", " var result = internal.db[collection].NEAR_NL(idx, latitude, longitude, limit);", " if (distanceAttribute == null) {", " return result.documents;", " }", "", " // inject distances", " var documents = result.documents;", " var distances = result.distances;", " var n = documents.length;", " for (var i = 0; i < n; ++i) {", " documents[i][distanceAttribute] = distances[i];", " }", "", " return documents;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief return documents within around a certain point", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GEO_WITHIN () {", " var collection = arguments[0];", " var latitude = arguments[1];", " var longitude = arguments[2];", " var radius = arguments[3];", " var distanceAttribute = arguments[4];", "", " var idx = AHUACATL_INDEX(internal.db[collection], [ \"geo1\", \"geo2\" ]); ", " if (idx == null) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_GEO_INDEX_MISSING, collection);", " }", "", " var result = internal.db[collection].WITHIN_NL(idx, latitude, longitude, radius);", " if (distanceAttribute == null) {", " return result.documents;", " }", "", " // inject distances", " var documents = result.documents;", " var distances = result.distances;", " var n = documents.length;", " for (var i = 0; i < n; ++i) {", " documents[i][distanceAttribute] = distances[i];", " }", "", " return documents;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- graph functions", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief find all paths through a graph", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GRAPH_PATHS () {", " var vertices = arguments[0];", " var edgeCollection = arguments[1];", " var direction = arguments[2] != undefined ? arguments[2] : \"outbound\";", " var followCycles = arguments[3] ? arguments[3] : false;", "", " var minLength = 0;", " var maxLength = 10;", " var searchDirection;", "", " AHUACATL_LIST(vertices);", "", " // validate arguments", " if (direction == \"outbound\") {", " searchDirection = 1;", " }", " else if (direction == \"inbound\") {", " searchDirection = 2;", " }", " else if (direction == \"any\") {", " searchDirection = 3;", " maxLength = 3;", " }", " else {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"PATHS\");", " }", "", " if (minLength < 0 || maxLength < 0 || minLength > maxLength) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"PATHS\");", " }", "", " var searchAttributes = { ", " \"edgeCollection\" : internal.db[edgeCollection],", " \"minLength\" : minLength, ", " \"maxLength\" : maxLength, ", " \"direction\" : searchDirection,", " \"followCycles\" : followCycles,", " };", "", " // TODO: restrict allEdges to edges with certain _from values etc.", "", " var result = [ ];", " var n = vertices.length;", " for (var i = 0; i < n; ++i) {", " var vertex = vertices[i];", " var visited = { };", " visited[vertex._id] = true;", " var connected = AHUACATL_GRAPH_SUBNODES(searchAttributes, vertex._id, visited, [ ], [ vertex ], 0);", " for (j = 0; j < connected.length; ++j) {", " result.push(connected[j]);", " }", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief find all paths through a graph, internal part called recursively", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_GRAPH_SUBNODES (searchAttributes, vertexId, visited, edges, vertices, level) {", " var result = [ ];", "", " if (level >= searchAttributes.minLength) {", " result.push({ ", " \"vertices\" : vertices, ", " \"edges\" : edges,", " \"source\" : vertices[0],", " \"destination\" : vertices[vertices.length - 1],", " });", " }", "", " if (level + 1 > searchAttributes.maxLength) {", " return result;", " }", "", " var subEdges;", "", " if (searchAttributes.direction == 1) {", " subEdges = searchAttributes.edgeCollection.outEdges(vertexId);", " }", " else if (searchAttributes.direction == 2) {", " subEdges = searchAttributes.edgeCollection.inEdges(vertexId);", " }", " else if (searchAttributes.direction == 3) {", " subEdges = searchAttributes.edgeCollection.edges(vertexId);", " }", "", " for (var i = 0; i < subEdges.length; ++i) {", " var subEdge = subEdges[i];", " var targets = [ ];", "", " if (searchAttributes.direction & 1) {", " targets.push(subEdge._to);", " }", " if (searchAttributes.direction & 2) {", " targets.push(subEdge._from);", " }", "", " for (var j = 0; j < targets.length; ++j) {", " var targetId = targets[j];", " ", " if (!searchAttributes.followCycles) {", " if (visited[targetId]) {", " continue;", " }", " visited[targetId] = true;", " }", "", " var clonedEdges = AHUACATL_CLONE(edges);", " var clonedVertices = AHUACATL_CLONE(vertices);", " clonedEdges.push(subEdge);", " clonedVertices.push(internal.db._document_nl(targetId));", " ", " var connected = AHUACATL_GRAPH_SUBNODES(searchAttributes, targetId, AHUACATL_CLONE(visited), clonedEdges, clonedVertices, level + 1);", " for (k = 0; k < connected.length; ++k) {", " result.push(connected[k]);", " }", "", " if (!searchAttributes.followCycles) {", " delete visited[targetId];", " }", " }", " }", "", " return result;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "// -----------------------------------------------------------------------------", "// --SECTION-- misc functions", "// -----------------------------------------------------------------------------", "", "////////////////////////////////////////////////////////////////////////////////", "/// @addtogroup Ahuacatl", "/// @{", "////////////////////////////////////////////////////////////////////////////////", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief return value if it's not null, otherwise return alternative", "///", "/// the operands can have any type", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_NOT_NULL (value, alternative) {", " if (AHUACATL_TYPEWEIGHT(value) === AHUACATL_TYPEWEIGHT_NULL) {", " return alternative;", " }", "", " return value;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief check whether a document has an attribute", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_HAS () {", " var element = arguments[0];", " var name = arguments[1];", " ", " if (AHUACATL_TYPEWEIGHT(element) === AHUACATL_TYPEWEIGHT_NULL) {", " return false;", " }", "", " if (AHUACATL_TYPEWEIGHT(element) !== AHUACATL_TYPEWEIGHT_DOCUMENT) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"HAS\");", " }", "", " return element.hasOwnProperty(name);", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief merge all arguments", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_MERGE () {", " var result = { };", "", " for (var i in arguments) {", " var element = arguments[i];", "", " if (AHUACATL_TYPEWEIGHT(element) !== AHUACATL_TYPEWEIGHT_DOCUMENT) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FUNCTION_ARGUMENT_TYPE_MISMATCH, \"MERGE\");", " }", "", " for (var k in element) {", " if (!element.hasOwnProperty(k)) {", " continue;", " }", "", " result[k] = element[k];", " }", " }", "", " return result; ", "}", "", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief passthru the argument", "///", "/// this function is marked as non-deterministic so its argument withstands", "/// query optimisation. this function can be used for testing", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_PASSTHRU () {", " var value = arguments[0];", "", " return value;", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @brief always fail", "///", "/// this function is non-deterministic so it is not executed at query ", "/// optimisation time. this function can be used for testing", "////////////////////////////////////////////////////////////////////////////////", "", "function AHUACATL_FAIL () {", " var message = arguments[0];", "", " if (AHUACATL_TYPEWEIGHT(message) === AHUACATL_TYPEWEIGHT_STRING) {", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FAIL_CALLED, message);", " }", "", " AHUACATL_THROW(internal.errors.ERROR_QUERY_FAIL_CALLED, \"\");", "}", "", "////////////////////////////////////////////////////////////////////////////////", "/// @}", "////////////////////////////////////////////////////////////////////////////////", "", "//__end__" };