1 | CouchDB back-end
|
2 | ----------------
|
3 |
|
4 | ### Back-end for a regular (static) DB such as provisioning
|
5 |
|
6 | - `db_uri` refers to a database URI.
|
7 | - `view_for` refers to a view object or a function that returns a view object (based on a requested key). A view object contains `view.map` (the map function as a function), `view.app`,and `view.name`, which all refer to the same view. If `view_for` is `null`, the `_all_docs` "identity" "view" is used.
|
8 |
|
9 | Changes are not computed for views where the `view_for` parameter is a function. (See below for the reason.) This could be worked-around by providing a database-to-view mapper that records the outcome of the view in a new database (and we are asked to monitor that database). (But notice that regular CouchDB databases are not suitable for this, since they can't directly handle non-string ids, and more importantly, cannot deal with duplicated keys/ids either.)
|
10 |
|
11 | couchdb_backend = (db_uri,view_for,fromJS,use_lru) ->
|
12 |
|
13 | the_db = new CouchDB db_uri, use_lru
|
14 |
|
15 | semantic = semantic_for the_db, fromJS
|
16 |
|
17 | get_key = (key) ->
|
18 | the_db.get(key).catch -> null
|
19 |
|
20 | Document changes
|
21 |
|
22 | changes = the_db.changes include_docs:true
|
23 | .multicast()
|
24 |
|
25 | Changeset for wandering-country-view/all (or other view)
|
26 |
|
27 | view_changes = switch view_for? and typeof view_for
|
28 |
|
29 | For a static `view_for` object, we apply the `.map` function locally to each modified document,
|
30 | therefor dynamically computing the outcome of the view. (CouchDB does the same thing on its side,
|
31 | so if we need to reconnect we can query the CouchDB view and obtain the same results.)
|
32 |
|
33 | when 'object'
|
34 | changes_view view_for.map, changes
|
35 | .multicast()
|
36 |
|
37 | else
|
38 | most.empty()
|
39 |
|
40 | We do not provide support for view changes for `view_for` functions.
|
41 |
|
42 | The reason this is a bad idea is that the view to use is decided based on the keys
|
43 | (see below for `.app` and `.name`), but the keys are _generated_ by the very
|
44 | same `map` function we're trying to select. (If this wasn't the case, the results would be
|
45 | inconsistent between the data returned by CouchDB, and the data generated by the function.)
|
46 | In details: to use this feature, you would have to provide a function would have to know
|
47 | how to reliably predict which keys will be returned by which ids (in other words it would
|
48 | be able to pre-compute the outcome of the `map` function).
|
49 |
|
50 | Also, we do not provide support for view changes for aggregate views (`count`, `range` etc.).
|
51 |
|
52 | On initial subscription we convert the key into a stream, using the server-side (CouchDB-stored) view.
|
53 |
|
54 | view_key = switch view_for? and typeof view_for
|
55 |
|
56 | when false
|
57 | (key) ->
|
58 | view_as_stream db_uri, null, '_all_docs', key
|
59 |
|
60 | when 'object' # there is only one DB, or the view is named the same in all DBs
|
61 | (key) ->
|
62 | view_as_stream db_uri, view_for.app, view_for.name, key
|
63 |
|
64 | when 'function'
|
65 | (key) ->
|
66 | view = view_for key
|
67 | return most.emtpy() unless view?
|
68 | view_as_stream db_uri, view.app, view.name, key
|
69 |
|
70 | else
|
71 | throw new Error 'view_for must be object or function'
|
72 |
|
73 | build_backend {changes, view_changes, semantic, get_key, view_key, fromJS}
|
74 |
|
75 | module.exports = couchdb_backend
|
76 |
|
77 | changes_view = require './util/changes-view'
|
78 | view_as_stream = require './util/view'
|
79 | most = require 'most'
|
80 | CouchDB = require './util/db'
|
81 | semantic_for = require './util/semantic-for'
|
82 | build_backend = require './util/build-backend'
|
83 |
|
84 | FIXME: figure out the pattern to push in bulk
|
85 |
|
86 | The semantic really is 'UPDATE', not 'OVERWRITE'
|
87 | → we could either do bulk-get / bulk-put (aka `_all_docs` and `_bulk_docs`),
|
88 | → or use an [update function](http://docs.couchdb.org/en/2.1.1/api/ddoc/render.html#db-design-design-doc-update-update-name)
|
89 | For now the code (above) does single GET/PUT on updates.
|