| .. 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` | any, except :ref:`reducefun` | |
| +--------------------------------+---------------------------------------------+ |
| | :func:`send` | :ref:`listfun` | |
| +--------------------------------+---------------------------------------------+ |
| | :func:`start` | :ref:`listfun` | |
| +--------------------------------+---------------------------------------------+ |
| | :func:`sum` | any | |
| +--------------------------------+---------------------------------------------+ |
| | :func:`toJSON` | any | |
| +--------------------------------+---------------------------------------------+ |
| |
| Design functions context |
| ------------------------ |
| |
| Each design function executes in a special context of predefined objects, |
| modules and functions: |
| |
| |
| .. function:: emit(key, value) |
| |
| Emits a `key`-`value` pair for further processing by CouchDB after the map |
| function is done. |
| |
| :param key: The view key |
| :param value: The `key`'s associated value |
| |
| .. code-block:: javascript |
| |
| function(doc){ |
| emit(doc._id, doc._rev); |
| } |
| |
| |
| .. function:: getRow() |
| |
| Extracts the next row from a 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) |
| |
| A helper function to check if the provided value is an `Array`. |
| |
| :param obj: Any Javascript value |
| :return: ``true`` if `obj` is `Array`-typed, ``false`` otherwise |
| :rtype: boolean |
| |
| |
| .. function:: log(message) |
| |
| Log a message to the CouchDB log (at the `INFO` level). |
| |
| :param message: Message to be logged |
| |
| .. code-block:: javascript |
| |
| function(doc){ |
| log('Procesing doc ' + doc['_id']); |
| emit(doc['_id'], null); |
| } |
| |
| After the map function has run, the following line can be found in CouchDB |
| logs (e.g. at `/var/log/couchdb/couch.log`): |
| |
| .. 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 a specified `path`. The path should not start with |
| a slash. |
| |
| :param path: A 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, a custom |
| :ref:`response <response_object>` object may be sent at this point. |
| For `list`-functions only! |
| |
| .. note:: |
| |
| list functions may set the `HTTP response code` and `headers` by calling |
| this function. This function must be called before :func:`send`, |
| :func:`getRow` or a `return` statement; otherwise, the query server will |
| implicitly call this function with the empty object (``{}``). |
| |
| .. code-block:: javascript |
| |
| function(head, req){ |
| start({ |
| "code": 302, |
| "headers": { |
| "Location": "http://couchdb.apache.org" |
| } |
| }); |
| return "Relax!"; |
| } |
| |
| |
| .. function:: sum(arr) |
| |
| Sum `arr`'s items. |
| |
| :param arr: Array of numbers |
| :rtype: number |
| |
| |
| .. function:: toJSON(obj) |
| |
| Encodes `obj` to JSON string. This is an alias for the ``JSON.stringify`` |
| method. |
| |
| :param obj: JSON encodable object |
| :return: JSON string |
| |
| .. _commonjs: |
| |
| CommonJS Modules |
| ---------------- |
| |
| Support for `CommonJS Modules <http://wiki.commonjs.org/wiki/Modules/1.1.1>`_ |
| (introduced in CouchDB 0.11.0) allows you to create modular design functions |
| without the need for duplication of functionality. |
| |
| Here's a CommonJS module that checks user permissions: |
| |
| .. code-block:: javascript |
| |
| function user_context(userctx, secobj) { |
| var is_admin = function() { |
| return userctx.indexOf('_admin') != -1; |
| } |
| return {'is_admin': is_admin} |
| } |
| |
| exports['user'] = user_context |
| |
| Each module has access to additional global variables: |
| |
| - **module** (`object`): Contains information about the stored module |
| |
| - **id** (`string`): The module id; a JSON path in ddoc context |
| - **current** (`code`): Compiled module code object |
| - **parent** (`object`): Parent frame |
| - **exports** (`object`): Export statements |
| |
| - **exports** (`object`): Shortcut to the ``module.exports`` object |
| |
| The CommonJS module can be added to a design document, like so: |
| |
| .. code-block:: javascript |
| |
| { |
| "views": { |
| "lib": { |
| "security": "function user_context(userctx, secobj) { ... }" |
| }, |
| "validate_doc_update": "function(newdoc, olddoc, userctx, secobj) { |
| user = require('lib/security').user(userctx, secobj); |
| return user.is_admin(); |
| }" |
| }, |
| "_id": "_design/test" |
| } |
| |
| Modules paths are relative to the design document's ``views`` object, but |
| modules can only be loaded from the object referenced via ``lib``. The |
| ``lib`` structure can still be used for view functions as well, by simply |
| storing view functions at e.g. ``views.lib.map``, ``views.lib.reduce``, etc. |
| |
| .. _queryserver_erlang: |
| |
| Erlang |
| ====== |
| |
| .. warning:: |
| |
| Unlike the JavaScript query server, the Erlang query server does not |
| run in a sandbox. This means Erlang code has full access to your OS, |
| filesystem and network, which may lead to security issues. While Erlang |
| functions are faster than JavaScript ones, you need to be careful |
| about running them, especially if they were written by someone else. |
| |
| |
| .. note:: |
| |
| Due to security restrictions, the Erlang query server is disabled by |
| default. To enable it, you 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, []} |
| |
| Don't forget to restart CouchDB after updating the configuration, and |
| use the ``language: "erlang"`` property in your Erlang design documents. |
| |
| |
| .. function:: Emit(Id, Value) |
| |
| Emits `key`-`value` pairs 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 a list function. |
| |
| :param Fun: Function object. |
| :param Acc: The value previously returned 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 the next row from a 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: Log a message at the `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. |
| |
| After the map function has run, the following line can be found in |
| CouchDB logs (e.g. at `/var/log/couchdb/couch.log`): |
| |
| .. 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. |
| |
| The function above produces the following 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, this function redirects to the CouchDB web site: |
| |
| .. code-block:: erlang |
| |
| fun(Head, {Req}) -> |
| Start({[{<<"code">>, 302}, |
| {<<"headers">>, {[ |
| {<<"Location">>, <<"http://couchdb.apache.org">>}] |
| }} |
| ]}), |
| "Relax!" |
| end. |