From 6c7a5967e5dae083bc9eef80bf3b7de7cc31ed5d Mon Sep 17 00:00:00 2001 From: Frank Celler Date: Fri, 2 Mar 2012 11:59:11 +0100 Subject: [PATCH] JS loader for avocsh --- V8/JSLoader.cpp | 175 ++++++++++++++ V8/JSLoader.h | 172 ++++++++++++++ js/client/js-client.h | 528 ++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 875 insertions(+) create mode 100644 V8/JSLoader.cpp create mode 100644 V8/JSLoader.h create mode 100644 js/client/js-client.h diff --git a/V8/JSLoader.cpp b/V8/JSLoader.cpp new file mode 100644 index 0000000000..67906e07b1 --- /dev/null +++ b/V8/JSLoader.cpp @@ -0,0 +1,175 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief source code loader +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2004-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 Dr. Frank Celler +/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#include "JSLoader.h" + +#include "Basics/MutexLocker.h" +#include "BasicsC/files.h" +#include "BasicsC/strings.h" +#include "Logger/Logger.h" +#include "V8/v8-utils.h" + +using namespace std; +using namespace triagens::basics; +using namespace triagens::avocado; + +// ----------------------------------------------------------------------------- +// --SECTION-- constructors and destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup AvocadoDB +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief constructs a loader +//////////////////////////////////////////////////////////////////////////////// + +JSLoader::JSLoader () + : _scripts(), + _directory(), + _lock() { +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- public methods +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup AvocadoDB +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +//////////////////////////////////////////////////////////////////////////////// +/// @brief gets the directory for scripts +//////////////////////////////////////////////////////////////////////////////// + +string const& JSLoader::getDirectory () const { + return _directory; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief sets the directory for scripts +//////////////////////////////////////////////////////////////////////////////// + +void JSLoader::setDirectory (string const& directory) { + MUTEX_LOCKER(_lock); + + _directory = directory; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief defines a new named script +//////////////////////////////////////////////////////////////////////////////// + +void JSLoader::defineScript (string const& name, string const& script) { + MUTEX_LOCKER(_lock); + + _scripts[name] = script; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief finds a named script +//////////////////////////////////////////////////////////////////////////////// + +string const& JSLoader::findScript (string const& name) { + MUTEX_LOCKER(_lock); + static string empty = ""; + + map::iterator i = _scripts.find(name); + + if (i != _scripts.end()) { + return i->second; + } + + if (! _directory.empty()) { + char* filename = TRI_Concatenate2File(_directory.c_str(), name.c_str()); + char* result = TRI_SlurpFile(filename); + + if (result == 0) { + LOGGER_ERROR << "cannot load file '" << filename << "': " << TRI_last_error(); + } + + TRI_FreeString(filename); + + if (result != 0) { + _scripts[name] = result; + TRI_FreeString(result); + return _scripts[name]; + } + } + + return empty; +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief loads a named script +//////////////////////////////////////////////////////////////////////////////// + +bool JSLoader::loadScript (v8::Persistent context, string const& name) { + v8::HandleScope scope; + + findScript(name); + + map::iterator i = _scripts.find(name); + + if (i == _scripts.end()) { + return false; + } + + return TRI_ExecuteStringVocBase(context, + v8::String::New(i->second.c_str()), + v8::String::New(name.c_str()), + false, + true); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @brief loads all scripts +//////////////////////////////////////////////////////////////////////////////// + +bool JSLoader::loadAllScripts (v8::Persistent context) { + if (_directory.empty()) { + return true; + } + + return TRI_LoadJavaScriptDirectory(context, _directory.c_str()); +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: diff --git a/V8/JSLoader.h b/V8/JSLoader.h new file mode 100644 index 0000000000..b0580bf94c --- /dev/null +++ b/V8/JSLoader.h @@ -0,0 +1,172 @@ +//////////////////////////////////////////////////////////////////////////////// +/// @brief source code loader +/// +/// @file +/// +/// DISCLAIMER +/// +/// Copyright 2004-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 Dr. Frank Celler +/// @author Copyright 2011-2012, triAGENS GmbH, Cologne, Germany +//////////////////////////////////////////////////////////////////////////////// + +#ifndef TRIAGENS_REST_SERVER_JSLOADER_H +#define TRIAGENS_REST_SERVER_JSLOADER_H 1 + +#include "Basics/Common.h" + +#include + +#include "Basics/Mutex.h" + +// ----------------------------------------------------------------------------- +// --SECTION-- class JSLoader +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup AvocadoDB +/// @{ +//////////////////////////////////////////////////////////////////////////////// + +namespace triagens { + namespace avocado { + +//////////////////////////////////////////////////////////////////////////////// +/// @brief JavaScript source code loader +//////////////////////////////////////////////////////////////////////////////// + + class JSLoader { + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- constructors and destructors +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup AvocadoDB +/// @{ +//////////////////////////////////////////////////////////////////////////////// + + public: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief constructs a loader +//////////////////////////////////////////////////////////////////////////////// + + JSLoader (); + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- public methods +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup AvocadoDB +/// @{ +//////////////////////////////////////////////////////////////////////////////// + + public: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief gets the directory for scripts +//////////////////////////////////////////////////////////////////////////////// + + string const& getDirectory () const; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief sets the directory for scripts +//////////////////////////////////////////////////////////////////////////////// + + void setDirectory (string const& directory); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief defines a new named script +//////////////////////////////////////////////////////////////////////////////// + + void defineScript (string const& name, string const& script); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief finds a named script +//////////////////////////////////////////////////////////////////////////////// + + string const& findScript (string const& name); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief loads a named script +//////////////////////////////////////////////////////////////////////////////// + + bool loadScript (v8::Persistent, string const& name); + +//////////////////////////////////////////////////////////////////////////////// +/// @brief loads all scripts +//////////////////////////////////////////////////////////////////////////////// + + bool loadAllScripts (v8::Persistent); + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +// ----------------------------------------------------------------------------- +// --SECTION-- private variables +// ----------------------------------------------------------------------------- + +//////////////////////////////////////////////////////////////////////////////// +/// @addtogroup AvocadoDB +/// @{ +//////////////////////////////////////////////////////////////////////////////// + + private: + +//////////////////////////////////////////////////////////////////////////////// +/// @brief all scripts +//////////////////////////////////////////////////////////////////////////////// + + std::map _scripts; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief script directory +//////////////////////////////////////////////////////////////////////////////// + + std::string _directory; + +//////////////////////////////////////////////////////////////////////////////// +/// @brief mutex for _scripts +//////////////////////////////////////////////////////////////////////////////// + + basics::Mutex _lock; + }; + } +} + +//////////////////////////////////////////////////////////////////////////////// +/// @} +//////////////////////////////////////////////////////////////////////////////// + +#endif + +// Local Variables: +// mode: outline-minor +// outline-regexp: "^\\(/// @brief\\|/// {@inheritDoc}\\|/// @addtogroup\\|// --SECTION--\\|/// @\\}\\)" +// End: diff --git a/js/client/js-client.h b/js/client/js-client.h new file mode 100644 index 0000000000..d32c4d2d56 --- /dev/null +++ b/js/client/js-client.h @@ -0,0 +1,528 @@ +static string JS_client_client = + "////////////////////////////////////////////////////////////////////////////////////\n" + "//\n" + "// global variables\n" + "//\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "var DEFAULT_QUERY_COLLECTION = \"query\";\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "//\n" + "// Helper functions\n" + "//\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function throwIfError (requestResult) {\n" + " \n" + " if (requestResult == undefined) { \n" + " throw \"Result is empty\";\n" + " }\n" + " \n" + " if (requestResult[\"error\"] != undefined && requestResult[\"error\"]) {\n" + " if (requestResult[\"errorMessage\"] == undefined) {\n" + " throw \"Unknown error\"; \n" + " }\n" + " throw requestResult[\"errorMessage\"];\n" + " } \n" + "}\n" + "\n" + "function help () {\n" + " print(\"--------------- HELP -----------------------------------------------\");\n" + " print(\"predefined objects:\");\n" + " print(\" advocado: AdvocadoConnection\");\n" + " print(\" db: AdvocadoDatabase\");\n" + " print(\"examples:\");\n" + " print(\" > db._collections(); list all collections\");\n" + " print(\" > db..all(); list all documents\");\n" + " print(\" > id = db..save({ ... }); save a document\");\n" + " print(\" > db..delete(<_id>); delete a document\");\n" + " print(\" > db..document(<_id>); get a document\");\n" + " print(\" > helpQueries(); query help\");\n" + " print(\" > exit\"); \n" + " print(\"--------------------------------------------------------------------\");\n" + "}\n" + "\n" + "function helpQueries () {\n" + " print(\"--------------- HELP -----------------------------------------------\");\n" + " print(\"create query template:\");\n" + " print(\" > qt1 = db.createQueryTemplate(\\\"select ...\\\"); simple query\");\n" + " print(\" > qt2 = db.createQueryTemplate( complex query\");\n" + " print(\" {query:\\\"select...\\\",\");\n" + " print(\" name:\\\"qname\\\",\");\n" + " print(\" collection:\\\"q\\\"\");\n" + " print(\" ... });\");\n" + " print(\" > qt3 = db.getQueryTemplate(\\\"4334:2334\\\"); query by id\");\n" + " print(\" > qt1.update(\\\"select ...\\\"); update\"); \n" + " print(\" > qt1.delete(\\\"4334:2334\\\"); delete\");\n" + " print(\"create query instance:\");\n" + " print(\" > qi1 = qt1.getInstance(); from tmplate\");\n" + " print(\" > qi2 = db.createQueryInstance(\\\"select...\\\"); without template\");\n" + " print(\" > qi2.bind(\\\"a\\\":\\\"b\\\")\");\n" + " print(\"execute query:\");\n" + " print(\" > cu1 = qi1.execute(); returns cursor\");\n" + " print(\"loop over all results:\");\n" + " print(\" > while (cu1.hasNext()) { print( cu1.next() ); }\");\n" + " print(\"--------------------------------------------------------------------\");\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "//\n" + "// AvocadoCollection\n" + "//\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AvocadoCollection (database, data) {\n" + " this._database = database;\n" + "\n" + " if (typeof data === \"string\") {\n" + " this.name = data;\n" + " }\n" + " else {\n" + " for (var i in data) {\n" + " this[i] = data[i];\n" + " }\n" + " }\n" + "}\n" + "\n" + "AvocadoCollection.prototype.all = function () {\n" + " var str = this._database._connection.get(\"/_api/documents/\" + encodeURIComponent(this.name));\n" + "\n" + " var requestResult = undefined;\n" + " if (str != undefined) {\n" + " requestResult = JSON.parse(str);\n" + " }\n" + " \n" + " throwIfError(requestResult);\n" + "\n" + " if (requestResult[\"documents\"] != undefined ) {\n" + " return requestResult[\"documents\"]; \n" + " }\n" + " return undefined;\n" + "}\n" + "\n" + "AvocadoCollection.prototype.document = function (id) {\n" + " var str = this._database._connection.get(\"/_api/document/\" + encodeURIComponent(this.name) + \"/\" + encodeURIComponent(id));\n" + " \n" + " var requestResult = undefined;\n" + " if (str != undefined) {\n" + " requestResult = JSON.parse(str);\n" + " }\n" + "\n" + " throwIfError(requestResult);\n" + " \n" + " if (requestResult[\"document\"] != undefined) {\n" + " return requestResult[\"document\"];\n" + " }\n" + " return requestResult;\n" + "}\n" + "\n" + "AvocadoCollection.prototype.save = function (data) { \n" + " var str = this._database._connection.post(\"/_api/document/\" + encodeURIComponent(this.name), JSON.stringify(data));\n" + " \n" + " var requestResult = undefined;\n" + " if (str != undefined) {\n" + " requestResult = JSON.parse(str);\n" + " }\n" + " \n" + " throwIfError(requestResult);\n" + " \n" + " if (requestResult[\"_id\"] != undefined) {\n" + " return requestResult[\"_id\"];\n" + " }\n" + " return requestResult;\n" + "}\n" + "\n" + "AvocadoCollection.prototype.delete = function (id) { \n" + " var str = this._database._connection.delete(\"/_api/document/\" + encodeURIComponent(this.name) + \"/\" + encodeURIComponent(id));\n" + " \n" + " var requestResult = undefined;\n" + " if (str != undefined) {\n" + " requestResult = JSON.parse(str);\n" + " }\n" + "\n" + " throwIfError(requestResult);\n" + " \n" + " return true;\n" + "}\n" + "\n" + "AvocadoCollection.prototype.update = function (id, data) { \n" + " var str = this._database._connection.put(\"/_api/document/\" + encodeURIComponent(this.name) + \"/\" + encodeURIComponent(id), JSON.stringify(data));\n" + " \n" + " var requestResult = undefined;\n" + " if (str != undefined) {\n" + " requestResult = JSON.parse(str);\n" + " }\n" + "\n" + " throwIfError(requestResult);\n" + "\n" + " return true;\n" + "}\n" + "\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "//\n" + "// QueryCursor\n" + "//\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function QueryCursor (database, data) {\n" + " this._database = database;\n" + " this.data = data;\n" + " this._hasNext = false;\n" + " this._hasMore = false;\n" + " this._pos = 0;\n" + " this._count = 0;\n" + " this._total = 0;\n" + " \n" + " if (data.result != undefined) {\n" + " this._count = data.result.length;\n" + " \n" + " if (this._pos < this._count) {\n" + " this._hasNext = true;\n" + " }\n" + " \n" + " if (data.hasMore != undefined && data.hasMore) {\n" + " this._hasMore = true;\n" + " } \n" + " }\n" + "}\n" + "\n" + "QueryCursor.prototype.hasNext = function () {\n" + " return this._hasNext;\n" + "}\n" + "\n" + "QueryCursor.prototype.next = function () {\n" + " if (!this._hasNext) {\n" + " throw \"No more results\";\n" + " }\n" + " \n" + " var result = this.data.result[this._pos];\n" + " this._pos++;\n" + " \n" + " if (this._pos == this._count) {\n" + " // reached last result\n" + " \n" + " this._hasNext = false;\n" + " this._pos = 0;\n" + " \n" + " if (this._hasMore) {\n" + " this._hasMore = false;\n" + " \n" + " // load more results \n" + " var str = this._database._connection.put(\"/_api/cursor/\"+ encodeURIComponent(this.data._id), \"\");\n" + "\n" + " var requestResult = undefined;\n" + " if (str != undefined) {\n" + " requestResult = JSON.parse(str);\n" + " }\n" + " \n" + " throwIfError(requestResult);\n" + " \n" + " this.data = requestResult;\n" + " this._count = requestResult.result.length;\n" + " \n" + " if (this._pos < this._count) {\n" + " this._hasNext = true;\n" + " }\n" + " \n" + " if (requestResult.hasMore != undefined && requestResult.hasMore) {\n" + " this._hasMore = true;\n" + " } \n" + " } \n" + " }\n" + " \n" + " return result;\n" + "}\n" + "\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "//\n" + "// QueryInstance\n" + "//\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function QueryInstance (database, data) {\n" + " this._database = database;\n" + " this.doCount = false;\n" + " this.bindVars = {};\n" + " \n" + " if (typeof data === \"string\") {\n" + " this.query = data;\n" + " }\n" + " else if (data instanceof QueryTemplate) {\n" + " this.queryTemplate = data;\n" + " if (data.document.query == undefined) {\n" + " data.load();\n" + " if (data.document.query == undefined) {\n" + " throw \"could not load query string\";\n" + " }\n" + " }\n" + " this.query = data.document.query;\n" + " } \n" + "}\n" + "\n" + "QueryInstance.prototype.bind = function (key, value) {\n" + " this.bindVars[key] = value;\n" + "}\n" + "\n" + "QueryInstance.prototype.setCount = function (bool) {\n" + " if (bool) {\n" + " this.doCount = true;\n" + " }\n" + " else {\n" + " this.doCount = false; \n" + " }\n" + "}\n" + "\n" + "QueryInstance.prototype.execute = function () {\n" + " var body = {\n" + " query : this.query,\n" + " count : this.doCount,\n" + " bindVars : this.bindVars\n" + " }\n" + " \n" + " var str = this._database._connection.post(\"/_api/cursor\", JSON.stringify(body));\n" + "\n" + " var requestResult = undefined;\n" + " if (str != undefined) {\n" + " requestResult = JSON.parse(str);\n" + " }\n" + " \n" + " throwIfError(requestResult);\n" + " \n" + " return new QueryCursor(this._database, requestResult);\n" + "}\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "//\n" + "// QueryTemplate\n" + "//\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function QueryTemplate (database, data) {\n" + " this._database = database;\n" + "\n" + " this.document = {\n" + " collection : DEFAULT_QUERY_COLLECTION\n" + " };\n" + " \n" + " if (typeof data === \"string\") {\n" + " this.document.query = data;\n" + " }\n" + " else { \n" + " if (data[\"query\"] != undefined) {\n" + " this.document.query = data[\"query\"];\n" + " }\n" + "\n" + " if (data[\"_id\"] != undefined) {\n" + " this.document._id = data[\"_id\"];\n" + " this._id = this.document._id;\n" + " }\n" + "\n" + " if (data[\"collection\"] != undefined) {\n" + " this.document.collection = data[\"collection\"];\n" + " } \n" + "\n" + " if (data[\"name\"] != undefined) {\n" + " this.document.name = data[\"name\"];\n" + " } \n" + "\n" + " // TODO additional attributes\n" + " }\n" + " \n" + " if (this.document.query == undefined && this.document._id == undefined) {\n" + " throw \"QueryTemplate needs query or _id.\";\n" + " }\n" + "}\n" + "\n" + "QueryTemplate.prototype.getInstance = function () {\n" + " if (this.document._id == undefined) {\n" + " throw \"no _id found\"; \n" + " }\n" + " \n" + " return new QueryInstance(this._database, this);\n" + "}\n" + "\n" + "QueryTemplate.prototype.update = function (data) {\n" + " if (this.document._id == undefined) {\n" + " throw \"no _id found\"; \n" + " }\n" + " \n" + " if (typeof data === \"string\") {\n" + " this.document.query = data;\n" + " }\n" + " else {\n" + " // update query or name \n" + " if (data[\"query\"] != undefined) {\n" + " this.document.query = data[\"query\"];\n" + " }\n" + "\n" + " if (data[\"name\"] != undefined) {\n" + " this.document.name = data[\"name\"];\n" + " } \n" + "\n" + " // TODO additional attributes\n" + " }\n" + " \n" + " var queryCollection = new AvocadoCollection(this._database, this.document.collection);\n" + " if (queryCollection.update(this.document._id, this.document)) {\n" + " return true;\n" + " }\n" + " \n" + " return false;\n" + "}\n" + "\n" + "QueryTemplate.prototype.delete = function () {\n" + " if (this.document._id == undefined) {\n" + " throw \"no _id found\"; \n" + " }\n" + "\n" + " var queryCollection = new AvocadoCollection(this._database, this.document.collection);\n" + " if (queryCollection.delete(this.document._id)) {\n" + " this.document = {};\n" + " return true;\n" + " }\n" + " \n" + " return false;\n" + "}\n" + "\n" + "QueryTemplate.prototype.load = function () {\n" + " if (this.document._id == undefined) {\n" + " throw \"QueryTemplate needs _id for loading\"; \n" + " }\n" + "\n" + " var coll = this.document.collection;\n" + " var queryCollection = new AvocadoCollection(this._database, coll);\n" + " var requestResult = queryCollection.document(this.document._id);\n" + " \n" + " if (requestResult != undefined) {\n" + "\n" + " if (requestResult.query == undefined) {\n" + " throw \"document is not a query\"; \n" + " }\n" + " // loaded\n" + " this.document = requestResult;\n" + " \n" + " if (this.document.collection == undefined) {\n" + " this.document.collection = coll;\n" + " }\n" + " \n" + " return true;\n" + " }\n" + " return false; \n" + "\n" + "}\n" + "\n" + "QueryTemplate.prototype.save = function () {\n" + " if (this.document._id != undefined) {\n" + " throw \"use update to save changes\"; \n" + " }\n" + " \n" + " var queryCollection = new AvocadoCollection(this._database, this.document.collection);\n" + " var requestResult = queryCollection.save(this.document);\n" + " \n" + " if (requestResult != undefined) {\n" + " // document saved\n" + " this.document._id = requestResult;\n" + " this._id = this.document._id;\n" + " return true;\n" + " }\n" + " \n" + " return false; \n" + "}\n" + "\n" + "\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "//\n" + "// AvocadoDatabase\n" + "//\n" + "////////////////////////////////////////////////////////////////////////////////\n" + "\n" + "function AvocadoDatabase (connection) {\n" + " this._connection = connection;\n" + " \n" + " // defaults\n" + " this.queryCollection = \"query\";\n" + " \n" + "}\n" + "\n" + "AvocadoDatabase.prototype._collections = function () {\n" + " var str = this._connection.get(\"/_api/collections\");\n" + " \n" + " var requestResult = undefined;\n" + " if (str != undefined) {\n" + " requestResult = JSON.parse(str);\n" + " }\n" + " \n" + " throwIfError(requestResult);\n" + " \n" + " if (requestResult[\"collections\"] != undefined) {\n" + " \n" + " // add all collentions to object\n" + " for (var i in requestResult[\"collections\"]) {\n" + " this[i] = new AvocadoCollection(this, requestResult[\"collections\"][i]);\n" + " }\n" + " \n" + " return requestResult[\"collections\"];\n" + " }\n" + " \n" + " return undefined;\n" + "}\n" + "\n" + "AvocadoDatabase.prototype._collection = function (id) {\n" + " var str = this._connection.get(\"/_api/collection/\" + encodeURIComponent(id));\n" + " \n" + " var requestResult = undefined;\n" + " if (str != undefined) {\n" + " requestResult = JSON.parse(str);\n" + " }\n" + " \n" + " throwIfError(requestResult);\n" + " \n" + " if (requestResult[\"name\"] != undefined) {\n" + " \n" + " this[requestResult[\"name\"]] = new AvocadoCollection(this, requestResult);\n" + " \n" + " return requestResult;\n" + " }\n" + " \n" + " return undefined;\n" + "}\n" + "\n" + "AvocadoDatabase.prototype.createQueryTemplate = function (queryData) { \n" + " var qt = new QueryTemplate(this, queryData);\n" + " if (qt.save()) {\n" + " return qt;\n" + " }\n" + " \n" + " return undefined;\n" + "}\n" + "\n" + "AvocadoDatabase.prototype.createQueryInstance = function (queryData) { \n" + " return new QueryInstance(this, queryData);\n" + "}\n" + "\n" + "AvocadoDatabase.prototype.getQueryTemplate = function (id) { \n" + " var qt = new QueryTemplate(this, {\"_id\" : id});\n" + " if (qt.load()) {\n" + " return qt;\n" + " }\n" + " \n" + " return undefined;\n" + "}\n" + "\n" + "\n" + "//\n" + "// default database\n" + "// \n" + "db = new AvocadoDatabase(avocado);\n" + "\n" + "//\n" + "// load collection data\n" + "// \n" + "\n" + "db._collections();\n" + "\n" + "help();\n" +;