You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@couchdb.apache.org by dc...@apache.org on 2012/11/19 01:21:14 UTC
git commit: Docs: work on design doc section and commonJS
Updated Branches:
refs/heads/docs de2b2bbf4 -> de6dc7150
Docs: work on design doc section and commonJS
Project: http://git-wip-us.apache.org/repos/asf/couchdb/repo
Commit: http://git-wip-us.apache.org/repos/asf/couchdb/commit/de6dc715
Tree: http://git-wip-us.apache.org/repos/asf/couchdb/tree/de6dc715
Diff: http://git-wip-us.apache.org/repos/asf/couchdb/diff/de6dc715
Branch: refs/heads/docs
Commit: de6dc7150887efa1654275caead1b06cab774341
Parents: de2b2bb
Author: Dave Cottlehuber <dc...@apache.org>
Authored: Mon Nov 19 01:08:06 2012 +0100
Committer: Dave Cottlehuber <dc...@apache.org>
Committed: Mon Nov 19 01:13:28 2012 +0100
----------------------------------------------------------------------
share/doc/build/Makefile.am | 1 +
share/doc/src/commonjs.rst | 8 +-
share/doc/src/ddocs.rst | 101 ++++----
share/doc/src/index.rst | 2 +-
share/doc/src/query-servers.rst | 480 +++++++++++++++++++++++++++++++++
share/doc/src/queryservers.rst | 482 ----------------------------------
6 files changed, 537 insertions(+), 537 deletions(-)
----------------------------------------------------------------------
http://git-wip-us.apache.org/repos/asf/couchdb/blob/de6dc715/share/doc/build/Makefile.am
----------------------------------------------------------------------
diff --git a/share/doc/build/Makefile.am b/share/doc/build/Makefile.am
index 15b0ed1..6044392 100644
--- a/share/doc/build/Makefile.am
+++ b/share/doc/build/Makefile.am
@@ -160,6 +160,7 @@ src_files = \
../src/intro.rst \
../src/json-structure.rst \
../src/os-daemons.rst \
+ ../query-servers.rst \
../src/range.rst \
../src/release.rst \
../src/replication.rst \
http://git-wip-us.apache.org/repos/asf/couchdb/blob/de6dc715/share/doc/src/commonjs.rst
----------------------------------------------------------------------
diff --git a/share/doc/src/commonjs.rst b/share/doc/src/commonjs.rst
index ff31095..49ccaa6 100644
--- a/share/doc/src/commonjs.rst
+++ b/share/doc/src/commonjs.rst
@@ -15,9 +15,9 @@
CommonJS support for map functions
==================================
-CommonJS support allows you to use CommonJS notation inside map and
-reduce functions, but only of libraries that are stored inside the views
-part of the design doc.
+CommonJS support allows you to use `CommonJS notation <http://commonjs.org/specs>`_
+inside map and reduce functions, but only of libraries that are stored
+inside the views part of the design doc.
So you could continue to access CommonJS code in design\_doc.foo, from
your list functions etc, but we'd add the ability to require CommonJS
@@ -54,5 +54,3 @@ A sample design doc (taken from the test suite in Futon) is below:
The ``require()`` statement is relative to the design document, but
anything loaded form outside of ``views/lib`` will fail.
-
-.. _CommonJS: http://commonjs.org/specs
http://git-wip-us.apache.org/repos/asf/couchdb/blob/de6dc715/share/doc/src/ddocs.rst
----------------------------------------------------------------------
diff --git a/share/doc/src/ddocs.rst b/share/doc/src/ddocs.rst
index 89fa62c..368f49e 100644
--- a/share/doc/src/ddocs.rst
+++ b/share/doc/src/ddocs.rst
@@ -18,12 +18,12 @@
Design Docs
===========
-In this section we'll show how to write design document in context of the
+In this section we'll show how to write design documents, using the built-in
:ref:`JavaScript Query Server <queryserver_js>`.
-But before we start to write our first function, take a look at the list of
-common objects that will be used during our code journey - we'll made big deal
-with them for each function:
+But before we start to write our first function, let's take a look at the list
+of common objects that will be used during our code journey - we'll be using
+them extensively within each function:
- :ref:`Database information object <dbinfo_object>`
- :ref:`Request object <request_object>`
@@ -48,9 +48,9 @@ Map functions
:param doc: Processed document object.
-Map functions should take a single argument as document object and emits pair
-values also known as `key` and `value`. Since JavaScript doesn't support
-generators and ``yield`` statement it got emulated via :func:`emit`:
+Map functions should take a single argument as document object and optionally
+emits paired values also known as `key` and `value`. Since JavaScript
+doesn't support generators and ``yield`` statement it is emulated via :func:`emit`:
.. code-block:: javascript
@@ -65,19 +65,19 @@ generators and ``yield`` statement it got emulated via :func:`emit`:
In this example the map function produces documents view by tag if they
has `tags` attribute as array and `type` attribute with "post" value. Note that
-:func:`emit` function could be called for multiple times, so same document
+:func:`emit` function could be called multiple times, so the same document
will be available by several `keys`.
Also keep in mind that each document is *sealed* to prevent situation when one
-map function changes document state and the other one received his modified
+map function changes document state and the other one received a modified
version.
-Yes, as was mentioned above, map function doesn't executes alone. Instead of
-that each document is processed by group of map functions from all views of
+For efficiency reasons, documents are passed to a group of map functions -
+each document is processed by group of map functions from all views of
related design document. This means that if you trigger index update for one
-view in ddoc, all others will get up-to-dated too.
+view in ddoc, all others will get updated too.
-Since `1.1.0` release `map` function gains support for
+Since `1.1.0` release `map` function supports
:ref:`CommonJS <commonjs>` modules and access to :func:`require` function.
.. _reducefun:
@@ -95,13 +95,13 @@ Reduce and rereduce functions
:return: Reduces `values`
Reduce functions takes two required arguments of keys and values lists - the
-result of the related map function - and optional third one which signs if
+result of the related map function - and optional third one which indicates if
`rereduce` mode is active or not. `Rereduce` is using for additional reduce
values list, so when it is ``true`` there is no information about related `keys`
(first argument is ``null``).
Note, that if produced result by `reduce` function is longer than initial
-values list then an Query Server error will be raised. However, this behavior
+values list then a Query Server error will be raised. However, this behavior
could be disabled by setting ``reduce_limit`` config option to ``false``:
.. code-block:: ini
@@ -111,7 +111,8 @@ could be disabled by setting ``reduce_limit`` config option to ``false``:
While disabling ``reduce_limit`` might be useful for debug proposes, remember,
that main task of reduce functions is to *reduce* mapped result, not to make it
-even bigger.
+even bigger. Generally, your reduce function should converge rapidly to a single
+value - which could be an array or similar object.
Also CouchDB has three built-in reduce functions. These are implemented in
Erlang and run right inside CouchDB, so they are much faster than the equivalent
@@ -151,21 +152,22 @@ JavaScript below:
}
}
-.. note:: **Why reduce functions has no support of CommonJS modules?**
+.. note:: **Why don't reduce functions support CommonJS modules?**
- While `map` functions has limited access to stored modules through
+ While `map` functions have limited access to stored modules through
:func:`require` function there is no such feature for `reduce` functions.
The reason lies deep inside in mechanism how `map` and `reduce` functions
are processed by Query Server. Let's take a look on `map` functions first:
#. CouchDB sends all `map` functions for processed design document to
Query Server.
- #. Query Server handles them one by one, compiles and puts into inner stack.
- #. After all `map` functions had been proceeded, CouchDB starts to send
- reamain documents to index one by one.
- #. Query Server handles document object and apply to him every function from
- inner stack. Their emitted result joins into single array and pulls back
- to CouchDB.
+ #. Query Server handles them one by one, compiles and puts them onto an
+ internal stack.
+ #. After all `map` functions had been processed, CouchDB will send the
+ remaining documents to index one by one.
+ #. The Query Server receives the document object and applies it to every function
+ from the stack. The emitted results are then joined into a single array and sent
+ back to CouchDB.
Now let's see how `reduce` functions are handled:
@@ -176,10 +178,10 @@ JavaScript below:
lists. Reduced result sends back to CouchDB.
As you may note, `reduce` functions been applied in single shot while
- `map` ones are applies in iterative way per each document. This means that
- it's possible for `map` functions to precompile CommonJS library and use it
- during whole view processing, but for `reduce` functions it will be
- compiled again and again for each view result reducing which may leads to
+ `map` ones are applied in an iterative way per each document. This means that
+ it's possible for `map` functions to precompile CommonJS libraries and use them
+ during the entire view processing, but for `reduce` functions it will be
+ compiled again and again for each view result reduction, which will lead to
performance degradation (`reduce` function are already does hard work to make
large result smaller).
@@ -198,7 +200,8 @@ Show functions
:rtype: object or string
Show functions are used to represent documents in various formats, commonly as
-HTML page with nicer formatting.
+HTML page with nicer formatting. They can also be used to run server-side functions
+without requiring a pre-existing document.
Basic example of show function could be:
@@ -248,7 +251,7 @@ and even files (this one is CouchDB logo):
}
}
-But what if you need to represent data in different formats by single function?
+But what if you need to represent data in different formats via a single function?
Functions :func:`registerType` and :func:`provides` are your the best friends in
that question:
@@ -299,8 +302,8 @@ that question:
This function may return `html`, `json` , `xml` or our custom `text json` format
representation of same document object with same processing rules. Probably,
-the `xml` provider in our function needs in more care to handle nested objects
-and keys with invalid characters, but you've got the idea!
+the `xml` provider in our function needs more care to handle nested objects
+correctly, and keys with invalid characters, but you've got the idea!
.. seealso::
@@ -325,9 +328,9 @@ List functions
:rtype: string
While :ref:`showfun` are used to customize document presentation, :ref:`listfun`
-are used for same propose, but against :ref:`viewfun` result.
+are used for same purpose, but against :ref:`viewfun` results.
-Next list function formats view and represent in as very simple HTML page:
+The next list function formats view and represents it as a very simple HTML page:
.. code-block:: javascript
@@ -351,9 +354,9 @@ Next list function formats view and represent in as very simple HTML page:
send('</table></body></html>');
}
-Probably, you'd better to think about templates, styles and more other things to
-show data in more nicer way, but this is good point to start from. Note, that
-you may use there :func:`registerType` and :func:`provides` functions in same
+Templates and styles could obviously be used to present data in a nicer
+fashion, but this is an excellent starting point. Note that you may also
+use :func:`registerType` and :func:`provides` functions in the same
way as for :ref:`showfun`!
.. seealso::
@@ -436,13 +439,13 @@ formats, but more correctly to say, they *filters* :ref:`changes feed<changes>`.
Classic filters
---------------
-By default changes feed emits all database documents changes. But if you're
-waiting for some special changes this is not optimal to process each record.
+By default the changes feed emits all database documents changes. But if you're
+waiting for some special changes, processing all documents is inefficient.
Filters are special design document functions that allows changes feed to emit
-only specific documents that passed filter rules.
+only specific documents that pass filter rules.
-Lets assume that our database is mailbox and we need to to handle only new mails
+Lets assume that our database is a mailbox and we need to to handle only new mails
(documents with status `new`) events. Assuming that, our filter function
will looks like next one:
@@ -534,7 +537,7 @@ systems.
View filters
------------
-View filters are the same as classic one with one small difference: they uses
+View filters are the same as above, with one small difference: they use
views `map` function instead to `filter` one to process the changes feed. Each
time when a key-value pair could be emitted, a change is returned. This allows
to avoid creating filter functions that are mostly does same works as views.
@@ -546,8 +549,8 @@ To use them just specify `_view` value for ``filter`` parameter and
.. note::
- Since view filters are uses `map` functions as filter they couldn't
- have dynamic behavior since :ref:`request object<request_object>` is not
+ Since view filters uses `map` functions as filters, they can't show any
+ dynamic behavior since :ref:`request object<request_object>` is not
available.
.. seealso::
@@ -573,11 +576,11 @@ Validate document update functions
:throws: ``forbidden`` error to gracefully prevent document storing.
-To perform validate operations on document saving there is special design
+To perform validate operations on document saving there is a special design
function type called `validate_doc_update`.
-Instead of thousands words take a look on next good example of validate
-function - this function is uses in ``_design/_auth`` ddoc from `_users`
+Instead of thousands words take a look at the next example of validate
+function - this function is used in ``_design/_auth`` ddoc from `_users`
database to control users documents required field set and modification
permissions:
@@ -709,8 +712,8 @@ permissions:
.. note::
- The ``return`` statement used only for function exiting and it doesn't
- controls validation process.
+ The ``return`` statement used only for function, it has no impact on
+ the validation process.
.. seealso::
http://git-wip-us.apache.org/repos/asf/couchdb/blob/de6dc715/share/doc/src/index.rst
----------------------------------------------------------------------
diff --git a/share/doc/src/index.rst b/share/doc/src/index.rst
index 5712d7c..b7591d3 100644
--- a/share/doc/src/index.rst
+++ b/share/doc/src/index.rst
@@ -33,7 +33,7 @@ Contents:
config_reference
replication
ddocs
- queryservers
+ query-servers
commonjs
errors
changes
http://git-wip-us.apache.org/repos/asf/couchdb/blob/de6dc715/share/doc/src/query-servers.rst
----------------------------------------------------------------------
diff --git a/share/doc/src/query-servers.rst b/share/doc/src/query-servers.rst
new file mode 100644
index 0000000..c6f3a74
--- /dev/null
+++ b/share/doc/src/query-servers.rst
@@ -0,0 +1,480 @@
+.. 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.
+
+.. default-domain:: js
+
+=============
+Query servers
+=============
+
+.. _queryserver_js:
+
+JavaScript
+==========
+
+.. note:: While every design function has access to all JavaScript objects,
+ the table below describes appropriate usage cases. For example,
+ you may use :func:`emit` in :ref:`listfun`, but :func:`getRow` is not permitted during :ref:`mapfun`.
+
++--------------------------------+---------------------------------------------+
+| JS Function | Reasonable to use in design doc functions |
++================================+=============================================+
+| :func:`emit` | :ref:`mapfun` |
++--------------------------------+---------------------------------------------+
+| :func:`getRow` | :ref:`listfun` |
++--------------------------------+---------------------------------------------+
+| :data:`JSON` | any |
++--------------------------------+---------------------------------------------+
+| :func:`isArray` | any |
++--------------------------------+---------------------------------------------+
+| :func:`log` | any |
++--------------------------------+---------------------------------------------+
+| :func:`provides` | :ref:`showfun`, :ref:`listfun` |
++--------------------------------+---------------------------------------------+
+| :func:`registerType` | :ref:`showfun`, :ref:`listfun` |
++--------------------------------+---------------------------------------------+
+| :func:`require` | every except :ref:`reducefun` |
++--------------------------------+---------------------------------------------+
+| :func:`send` | :ref:`listfun` |
++--------------------------------+---------------------------------------------+
+| :func:`start` | :ref:`listfun` |
++--------------------------------+---------------------------------------------+
+| :func:`sum` | any |
++--------------------------------+---------------------------------------------+
+| :func:`toJSON` | any |
++--------------------------------+---------------------------------------------+
+
+Design functions context
+------------------------
+
+Each design function executes within special context of predefined objects,
+modules and functions:
+
+
+.. function:: emit(key, value)
+
+ Puts `key`-`value` pair into inner stack for further passing to CouchDB
+ when map function is done.
+
+ :param key: View's key.
+ :param value: Associated value with `key`.
+
+ .. code-block:: javascript
+
+ function(doc){
+ emit(doc._id, doc._rev);
+ }
+
+
+.. function:: getRow()
+
+ Extracts next row from the related view result.
+
+ :return: View result row
+ :rtype: object
+
+ .. code-block:: javascript
+
+ function(head, req){
+ send('[');
+ row = getRow();
+ if (row){
+ send(toJSON(row));
+ while(row = getRow()){
+ send(',');
+ send(toJSON(row));
+ }
+ }
+ return ']';
+ }
+
+
+.. data:: JSON
+
+ `JSON2 <https://git-wip-us.apache.org/repos/asf?p=couchdb.git;a=blob;f=share/server/json2.js>`_
+ object.
+
+
+.. function:: isArray(obj)
+
+ Helper to check is provided value `array` or not
+
+ :param obj: Any Javascript value
+ :return: ``true`` is `obj` is `array` typed, ``false`` otherwise.
+ :rtype: boolean
+
+
+.. function:: log(message)
+
+ :param message: Message to log in at CouchDB `INFO` level.
+
+ .. code-block:: javascript
+
+ function(doc){
+ log('Procesing doc ' + doc['_id']);
+ emit(doc['_id'], null);
+ }
+
+ On map function run in CouchDB logs (e.g. at `/var/log/couchdb/couch.log`)
+ you may find next record:
+
+ .. code-block:: text
+
+ [Sat, 03 Nov 2012 17:38:02 GMT] [info] [<0.7543.0>] OS Process #Port<0.3289> Log :: Processing doc 8d300b86622d67953d102165dbe99467
+
+
+.. function:: provides(key, func)
+
+ Registers callable handler for specified MIME key.
+
+ :param key: MIME key previously defined by :func:`registerType`
+ :param func: MIME type handler.
+
+
+.. function:: registerType(key, *mimes)
+
+ Registers list of MIME types by associated `key`.
+
+ :param key: MIME types
+ :param mimes: MIME types enumeration.
+
+ Predefined mappings (`key`-`array`):
+
+ - **all**: ``*/*``
+ - **text**: ``text/plain; charset=utf-8``, ``txt``
+ - **html**: ``text/html; charset=utf-8``
+ - **xhtml**: ``application/xhtml+xml``, ``xhtml``
+ - **xml**: ``application/xml``, ``text/xml``, ``application/x-xml``
+ - **js**: ``text/javascript``, ``application/javascript``,
+ ``application/x-javascript``
+ - **css**: ``text/css``
+ - **ics**: ``text/calendar``
+ - **csv**: ``text/csv``
+ - **rss**: ``application/rss+xml``
+ - **atom**: ``application/atom+xml``
+ - **yaml**: ``application/x-yaml``, ``text/yaml``
+ - **multipart_form**: ``multipart/form-data``
+ - **url_encoded_form**: ``application/x-www-form-urlencoded``
+ - **json**: ``application/json``, ``text/x-json``
+
+
+.. function:: require(path)
+
+ Loads CommonJS module by specified `path`. Path shouldn't starts with slash.
+
+ :param path: CommonJS module path started from design document root.
+ :return: Exported statements.
+
+
+.. function:: send(chunk)
+
+ Sends a single string `chunk` in response.
+
+ :param chunk: Text chunk
+
+ .. code-block:: javascript
+
+ function(head, req){
+ send('Hello,');
+ send(' ');
+ send('Couch');
+ return !
+ }
+
+
+.. function:: start(init_resp)
+
+ Initiates chunked response. As an option, custom
+ :ref:`response <response_object>` object may be sent at this point.
+ For `list`-functions only!
+
+ .. note::
+ Only at this point list functions may set response `HTTP code` and
+ `headers`. Also, you need to run this function before :func:`send`,
+ :func:`getRow` or `return` statement or query server will implicitly call
+ this function with empty object (``{}``).
+
+ .. code-block:: javascript
+
+ function(head, req){
+ start({
+ "code": 302,
+ "headers": {
+ "Location": "http://couchdb.apache.org"
+ }
+ });
+ return "Relax!";
+ }
+
+
+.. function:: sum(arr)
+
+ Summarize `arr` items.
+
+ :param arr: Array of numbers.
+ :rtype: number
+
+
+.. function:: toJSON(obj)
+
+ Encodes `obj` to JSON string. Actually is a proxy to ``JSON.stringify``
+ method.
+
+ :param obj: JSON encodable object.
+ :return: JSON string.
+
+
+
+CommonJS Modules
+----------------
+
+`CommonJS Modules <http://wiki.commonjs.org/wiki/Modules/1.1.1>`_ is the one of
+major CouchDB feature introduced in 0.11.0 version that allows to create modular
+design functions without needs to duplicate a lot of same functionality.
+
+Example of CommonJS module that checks user permissions:
+
+.. code-block:: javascript
+
+ function user_context(userctx, secobj){
+ var is_admin = function(){
+ return userctx.indexOf('_admin') != -1;
+ }
+ var is_db_admin = function(){
+ if (is_admin() || !secobj){
+ return true;
+ }
+ if (secobj.admins.names.indexOf(userctx.name) != -1){
+ return true;
+ }
+ for (var idx in userctx.roles){
+ if (secobj.admins.roles.indexOf(userctx.roles[idx]) != -1){
+ return true;
+ }
+ }
+ return false;
+ }
+ var is_db_member = function(){
+ if (is_admin() || is_db_admin() || !secobj){
+ return true;
+ }
+ if (secobj.members.names.indexOf(userctx.name) != -1){
+ return true;
+ }
+ for (var idx in userctx.roles){
+ if (secobj.members.roles.indexOf(userctx.roles[idx]) != -1){
+ return true;
+ }
+ }
+ return false;
+ }
+ var has_all_roles = function(roles){
+ for (var idx in roles){
+ if (userctx.roles.indexOf(roles[idx]) == -1){
+ return false;
+ }
+ }
+ return true;
+ }
+ var has_any_role = function(roles){
+ for (var idx in roles){
+ if (userctx.roles.indexOf(roles[idx]) != -1){
+ return true;
+ }
+ }
+ return false;
+ }
+ return {
+ 'is_admin': is_admin,
+ 'is_db_admin': is_db_admin,
+ 'is_db_member': is_db_member,
+ 'has_all_roles': has_all_roles,
+ 'has_any_role': has_any_role
+ }
+ }
+
+ exports['user'] = user_context
+
+Each module has access to additional global variables:
+
+- **module** (`object`): Contains information about stored module.
+
+ - **id** (`string`): Module id that is actually JSON path in ddoc context.
+ - **current** (`code`): Compiled module code object.
+ - **parent** (`object`): Parent frame.
+ - **exports** (`object`): Export statements.
+
+- **exports** (`object`): Shortcut to ``module.exports`` object.
+
+Lets place module above within design document under `lib/validate` path.
+Now we could use it in our design functions:
+
+.. code-block:: javascript
+
+ function(newdoc, olddoc, userctx, secobj){
+ user = require('lib/validate').user(userctx, secobj);
+ if (user.is_admin()){
+ return true;
+ }
+ if (newdoc.author != olddoc.author){
+ throw({'forbidden': 'unable to update `author` field'});
+ }
+ }
+
+
+.. _queryserver_erlang:
+
+Erlang
+======
+
+.. warning::
+
+ Erlang query server runs out of sandbox feature like JavaScript has to!
+ This means, that Erlang code has full access to your OS, file system and
+ network which may leads to security issues. While Erlang functions are
+ faster than JavaScript ones, you need to be careful with running them,
+ especially if they wasn't written by your own hands.
+
+ Keep in mind: don't trust every code - review it first before running.
+
+
+.. note::
+
+ Due to security restriction, Erlang query server is disabled by default.
+ To enable it you'll need to edit your `local.ini` to include a
+ ``native_query_servers`` section:
+
+ .. code-block:: ini
+
+ [native_query_servers]
+ erlang = {couch_native_process, start_link, []}
+
+ And don't forget to restart CouchDB after that and use ``language: "erlang"``
+ property in your Erlang design documents.
+
+
+.. function:: Emit(Id, Value)
+
+ Emits `key`-`value` pair to view indexer process.
+
+ .. code-block:: erlang
+
+ fun({Doc}) ->
+ <<K,_/binary>> = proplists:get_value(<<"_rev">>, Doc, null),
+ V = proplists:get_value(<<"_id">>, Doc, null),
+ Emit(<<K>>, V)
+ end.
+
+
+.. function:: FoldRows(Fun, Acc)
+
+ Helper to iterate over all rows in list function.
+
+ :param Fun: Function object.
+ :param Acc: Previous returned value by `Fun`.
+
+ .. code-block:: erlang
+
+ fun(Head, {Req}) ->
+ Fun = fun({Row}, Acc) ->
+ Id = couch_util:get_value(<<"id">>, Row),
+ Send(list_to_binary(io_lib:format("Previous doc id: ~p~n", [Acc]))),
+ Send(list_to_binary(io_lib:format("Current doc id: ~p~n", [Id]))),
+ {ok, Id}
+ end,
+ FoldRows(Fun, nil),
+ ""
+ end.
+
+
+.. function:: GetRow()
+
+ Retrieves next row from related view result.
+
+ .. code-block:: erlang
+
+ %% FoldRows background implementation.
+ %% https://git-wip-us.apache.org/repos/asf?p=couchdb.git;a=blob;f=src/couchdb/couch_native_process.erl;hb=HEAD#l368
+ %%
+ foldrows(GetRow, ProcRow, Acc) ->
+ case GetRow() of
+ nil ->
+ {ok, Acc};
+ Row ->
+ case (catch ProcRow(Row, Acc)) of
+ {ok, Acc2} ->
+ foldrows(GetRow, ProcRow, Acc2);
+ {stop, Acc2} ->
+ {ok, Acc2}
+ end
+ end.
+
+.. function:: Log(Msg)
+
+ :param Msg: Message to log in at CouchDB `INFO` level.
+
+ .. code-block:: erlang
+
+ fun({Doc}) ->
+ <<K,_/binary>> = proplists:get_value(<<"_rev">>, Doc, null),
+ V = proplists:get_value(<<"_id">>, Doc, null),
+ Log(lists:flatten(io_lib:format("Hello from ~s doc!", [V]))),
+ Emit(<<K>>, V)
+ end.
+
+ On map function run in CouchDB logs (e.g. at `/var/log/couchdb/couch.log`)
+ you may find next record:
+
+ .. code-block:: text
+
+ [Sun, 04 Nov 2012 11:33:58 GMT] [info] [<0.9144.2>] Hello from 8d300b86622d67953d102165dbe99467 doc!
+
+
+.. function:: Send(Chunk)
+
+ Sends a single string `Chunk` in response.
+
+ .. code-block:: erlang
+
+ fun(Head, {Req}) ->
+ Send("Hello,"),
+ Send(" "),
+ Send("Couch"),
+ "!"
+ end.
+
+ Function above produces next response:
+
+ .. code-block:: text
+
+ Hello, Couch!
+
+
+.. function:: Start(Headers)
+
+ :param Headers: Proplist of :ref:`response object<response_object>`.
+
+ Initialize :ref:`listfun` response. At this point response code and headers
+ may be defined. For example, next function redirect to CouchDB web site:
+
+ .. code-block:: erlang
+
+ fun(Head, {Req}) ->
+ Start({[{<<"code">>, 302},
+ {<<"headers">>, {[
+ {<<"Location">>, <<"http://couchdb.apache.org">>}]
+ }}
+ ]}),
+ "Relax!"
+ end.
+
+
http://git-wip-us.apache.org/repos/asf/couchdb/blob/de6dc715/share/doc/src/queryservers.rst
----------------------------------------------------------------------
diff --git a/share/doc/src/queryservers.rst b/share/doc/src/queryservers.rst
deleted file mode 100644
index cfeee75..0000000
--- a/share/doc/src/queryservers.rst
+++ /dev/null
@@ -1,482 +0,0 @@
-.. 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.
-
-.. default-domain:: js
-
-=============
-Query servers
-=============
-
-.. _queryserver_js:
-
-JavaScript
-==========
-
-.. note::
- While every design function has access to all described there objects
- the table below describes reasonable usage cases. For example, you may
- use :func:`emit` in :ref:`listfun`, but this is useless while using
- :func:`getRow` in :ref:`mapfun` will made it broken.
-
-+--------------------------------+---------------------------------------------+
-| JS Function | Reasonable to use in design doc functions |
-+================================+=============================================+
-| :func:`emit` | :ref:`mapfun` |
-+--------------------------------+---------------------------------------------+
-| :func:`getRow` | :ref:`listfun` |
-+--------------------------------+---------------------------------------------+
-| :data:`JSON` | any |
-+--------------------------------+---------------------------------------------+
-| :func:`isArray` | any |
-+--------------------------------+---------------------------------------------+
-| :func:`log` | any |
-+--------------------------------+---------------------------------------------+
-| :func:`provides` | :ref:`showfun`, :ref:`listfun` |
-+--------------------------------+---------------------------------------------+
-| :func:`registerType` | :ref:`showfun`, :ref:`listfun` |
-+--------------------------------+---------------------------------------------+
-| :func:`require` | every except :ref:`reducefun` |
-+--------------------------------+---------------------------------------------+
-| :func:`send` | :ref:`listfun` |
-+--------------------------------+---------------------------------------------+
-| :func:`start` | :ref:`listfun` |
-+--------------------------------+---------------------------------------------+
-| :func:`sum` | any |
-+--------------------------------+---------------------------------------------+
-| :func:`toJSON` | any |
-+--------------------------------+---------------------------------------------+
-
-Design functions context
-------------------------
-
-Each design function executes within special context of predefined objects,
-modules and functions:
-
-
-.. function:: emit(key, value)
-
- Puts `key`-`value` pair into inner stack for further passing to CouchDB
- when map function is done.
-
- :param key: View's key.
- :param value: Associated value with `key`.
-
- .. code-block:: javascript
-
- function(doc){
- emit(doc._id, doc._rev);
- }
-
-
-.. function:: getRow()
-
- Extracts next row from the related view result.
-
- :return: View result row
- :rtype: object
-
- .. code-block:: javascript
-
- function(head, req){
- send('[');
- row = getRow();
- if (row){
- send(toJSON(row));
- while(row = getRow()){
- send(',');
- send(toJSON(row));
- }
- }
- return ']';
- }
-
-
-.. data:: JSON
-
- `JSON2 <https://git-wip-us.apache.org/repos/asf?p=couchdb.git;a=blob;f=share/server/json2.js>`_
- object.
-
-
-.. function:: isArray(obj)
-
- Helper to check is provided value `array` or not
-
- :param obj: Any Javascript value
- :return: ``true`` is `obj` is `array` typed, ``false`` otherwise.
- :rtype: boolean
-
-
-.. function:: log(message)
-
- :param message: Message to log in at CouchDB `INFO` level.
-
- .. code-block:: javascript
-
- function(doc){
- log('Procesing doc ' + doc['_id']);
- emit(doc['_id'], null);
- }
-
- On map function run in CouchDB logs (e.g. at `/var/log/couchdb/couch.log`)
- you may find next record:
-
- .. code-block:: text
-
- [Sat, 03 Nov 2012 17:38:02 GMT] [info] [<0.7543.0>] OS Process #Port<0.3289> Log :: Processing doc 8d300b86622d67953d102165dbe99467
-
-
-.. function:: provides(key, func)
-
- Registers callable handler for specified MIME key.
-
- :param key: MIME key previously defined by :func:`registerType`
- :param func: MIME type handler.
-
-
-.. function:: registerType(key, *mimes)
-
- Registers list of MIME types by associated `key`.
-
- :param key: MIME types
- :param mimes: MIME types enumeration.
-
- Predefined mappings (`key`-`array`):
-
- - **all**: ``*/*``
- - **text**: ``text/plain; charset=utf-8``, ``txt``
- - **html**: ``text/html; charset=utf-8``
- - **xhtml**: ``application/xhtml+xml``, ``xhtml``
- - **xml**: ``application/xml``, ``text/xml``, ``application/x-xml``
- - **js**: ``text/javascript``, ``application/javascript``,
- ``application/x-javascript``
- - **css**: ``text/css``
- - **ics**: ``text/calendar``
- - **csv**: ``text/csv``
- - **rss**: ``application/rss+xml``
- - **atom**: ``application/atom+xml``
- - **yaml**: ``application/x-yaml``, ``text/yaml``
- - **multipart_form**: ``multipart/form-data``
- - **url_encoded_form**: ``application/x-www-form-urlencoded``
- - **json**: ``application/json``, ``text/x-json``
-
-
-.. function:: require(path)
-
- Loads CommonJS module by specified `path`. Path shouldn't starts with slash.
-
- :param path: CommonJS module path started from design document root.
- :return: Exported statements.
-
-
-.. function:: send(chunk)
-
- Sends a single string `chunk` in response.
-
- :param chunk: Text chunk
-
- .. code-block:: javascript
-
- function(head, req){
- send('Hello,');
- send(' ');
- send('Couch');
- return !
- }
-
-
-.. function:: start(init_resp)
-
- Initiates chunked response. As an option, custom
- :ref:`response <response_object>` object may be sent at this point.
- For `list`-functions only!
-
- .. note::
- Only at this point list functions may set response `HTTP code` and
- `headers`. Also, you need to run this function before :func:`send`,
- :func:`getRow` or `return` statement or query server will implicitly call
- this function with empty object (``{}``).
-
- .. code-block:: javascript
-
- function(head, req){
- start({
- "code": 302,
- "headers": {
- "Location": "http://couchdb.apache.org"
- }
- });
- return "Relax!";
- }
-
-
-.. function:: sum(arr)
-
- Summarize `arr` items.
-
- :param arr: Array of numbers.
- :rtype: number
-
-
-.. function:: toJSON(obj)
-
- Encodes `obj` to JSON string. Actually is a proxy to ``JSON.stringify``
- method.
-
- :param obj: JSON encodable object.
- :return: JSON string.
-
-
-
-CommonJS Modules
-----------------
-
-`CommonJS Modules <http://wiki.commonjs.org/wiki/Modules/1.1.1>`_ is the one of
-major CouchDB feature introduced in 0.11.0 version that allows to create modular
-design functions without needs to duplicate a lot of same functionality.
-
-Example of CommonJS module that checks user permissions:
-
-.. code-block:: javascript
-
- function user_context(userctx, secobj){
- var is_admin = function(){
- return userctx.indexOf('_admin') != -1;
- }
- var is_db_admin = function(){
- if (is_admin() || !secobj){
- return true;
- }
- if (secobj.admins.names.indexOf(userctx.name) != -1){
- return true;
- }
- for (var idx in userctx.roles){
- if (secobj.admins.roles.indexOf(userctx.roles[idx]) != -1){
- return true;
- }
- }
- return false;
- }
- var is_db_member = function(){
- if (is_admin() || is_db_admin() || !secobj){
- return true;
- }
- if (secobj.members.names.indexOf(userctx.name) != -1){
- return true;
- }
- for (var idx in userctx.roles){
- if (secobj.members.roles.indexOf(userctx.roles[idx]) != -1){
- return true;
- }
- }
- return false;
- }
- var has_all_roles = function(roles){
- for (var idx in roles){
- if (userctx.roles.indexOf(roles[idx]) == -1){
- return false;
- }
- }
- return true;
- }
- var has_any_role = function(roles){
- for (var idx in roles){
- if (userctx.roles.indexOf(roles[idx]) != -1){
- return true;
- }
- }
- return false;
- }
- return {
- 'is_admin': is_admin,
- 'is_db_admin': is_db_admin,
- 'is_db_member': is_db_member,
- 'has_all_roles': has_all_roles,
- 'has_any_role': has_any_role
- }
- }
-
- exports['user'] = user_context
-
-Each module has access to additional global variables:
-
-- **module** (`object`): Contains information about stored module.
-
- - **id** (`string`): Module id that is actually JSON path in ddoc context.
- - **current** (`code`): Compiled module code object.
- - **parent** (`object`): Parent frame.
- - **exports** (`object`): Export statements.
-
-- **exports** (`object`): Shortcut to ``module.exports`` object.
-
-Lets place module above within design document under `lib/validate` path.
-Now we could use it in our design functions:
-
-.. code-block:: javascript
-
- function(newdoc, olddoc, userctx, secobj){
- user = require('lib/validate').user(userctx, secobj);
- if (user.is_admin()){
- return true;
- }
- if (newdoc.author != olddoc.author){
- throw({'forbidden': 'unable to update `author` field'});
- }
- }
-
-
-.. _queryserver_erlang:
-
-Erlang
-======
-
-.. warning::
-
- Erlang query server runs out of sandbox feature like JavaScript has to!
- This means, that Erlang code has full access to your OS, file system and
- network which may leads to security issues. While Erlang functions are
- faster than JavaScript ones, you need to be careful with running them,
- especially if they wasn't written by your own hands.
-
- Keep in mind: don't trust every code - review it first before running.
-
-
-.. note::
-
- Due to security restriction, Erlang query server is disabled by default.
- To enable it you'll need to edit your `local.ini` to include a
- ``native_query_servers`` section:
-
- .. code-block:: ini
-
- [native_query_servers]
- erlang = {couch_native_process, start_link, []}
-
- And don't forget to restart CouchDB after that and use ``language: "erlang"``
- property in your Erlang design documents.
-
-
-.. function:: Emit(Id, Value)
-
- Emits `key`-`value` pair to view indexer process.
-
- .. code-block:: erlang
-
- fun({Doc}) ->
- <<K,_/binary>> = proplists:get_value(<<"_rev">>, Doc, null),
- V = proplists:get_value(<<"_id">>, Doc, null),
- Emit(<<K>>, V)
- end.
-
-
-.. function:: FoldRows(Fun, Acc)
-
- Helper to iterate over all rows in list function.
-
- :param Fun: Function object.
- :param Acc: Previous returned value by `Fun`.
-
- .. code-block:: erlang
-
- fun(Head, {Req}) ->
- Fun = fun({Row}, Acc) ->
- Id = couch_util:get_value(<<"id">>, Row),
- Send(list_to_binary(io_lib:format("Previous doc id: ~p~n", [Acc]))),
- Send(list_to_binary(io_lib:format("Current doc id: ~p~n", [Id]))),
- {ok, Id}
- end,
- FoldRows(Fun, nil),
- ""
- end.
-
-
-.. function:: GetRow()
-
- Retrieves next row from related view result.
-
- .. code-block:: erlang
-
- %% FoldRows background implementation.
- %% https://git-wip-us.apache.org/repos/asf?p=couchdb.git;a=blob;f=src/couchdb/couch_native_process.erl;hb=HEAD#l368
- %%
- foldrows(GetRow, ProcRow, Acc) ->
- case GetRow() of
- nil ->
- {ok, Acc};
- Row ->
- case (catch ProcRow(Row, Acc)) of
- {ok, Acc2} ->
- foldrows(GetRow, ProcRow, Acc2);
- {stop, Acc2} ->
- {ok, Acc2}
- end
- end.
-
-.. function:: Log(Msg)
-
- :param Msg: Message to log in at CouchDB `INFO` level.
-
- .. code-block:: erlang
-
- fun({Doc}) ->
- <<K,_/binary>> = proplists:get_value(<<"_rev">>, Doc, null),
- V = proplists:get_value(<<"_id">>, Doc, null),
- Log(lists:flatten(io_lib:format("Hello from ~s doc!", [V]))),
- Emit(<<K>>, V)
- end.
-
- On map function run in CouchDB logs (e.g. at `/var/log/couchdb/couch.log`)
- you may find next record:
-
- .. code-block:: text
-
- [Sun, 04 Nov 2012 11:33:58 GMT] [info] [<0.9144.2>] Hello from 8d300b86622d67953d102165dbe99467 doc!
-
-
-.. function:: Send(Chunk)
-
- Sends a single string `Chunk` in response.
-
- .. code-block:: erlang
-
- fun(Head, {Req}) ->
- Send("Hello,"),
- Send(" "),
- Send("Couch"),
- "!"
- end.
-
- Function above produces next response:
-
- .. code-block:: text
-
- Hello, Couch!
-
-
-.. function:: Start(Headers)
-
- :param Headers: Proplist of :ref:`response object<response_object>`.
-
- Initialize :ref:`listfun` response. At this point response code and headers
- may be defined. For example, next function redirect to CouchDB web site:
-
- .. code-block:: erlang
-
- fun(Head, {Req}) ->
- Start({[{<<"code">>, 302},
- {<<"headers">>, {[
- {<<"Location">>, <<"http://couchdb.apache.org">>}]
- }}
- ]}),
- "Relax!"
- end.
-
-