lib/ruote/couch/database.rb in ruote-couch-2.1.4 vs lib/ruote/couch/database.rb in ruote-couch-2.1.5
- old
+ new
@@ -20,13 +20,18 @@
# THE SOFTWARE.
#
# Made in Japan.
#++
+require 'cgi'
+
module Ruote::Couch
+ #
+ # A database corresponds to a Couch database (not a Couch server).
+ #
class Database
attr_reader :type
def initialize (host, port, type, name, re_put_ok=true)
@@ -60,24 +65,18 @@
@couch.delete(doc)
end
def get_many (key, opts)
- os = if l = opts[:limit]
- "&limit=#{l}"
- else
- ''
- end
+ rs = @couch.get("_all_docs?include_docs=true#{query_options(opts)}")
- rs = @couch.get("_all_docs?include_docs=true#{os}")
-
rs = rs['rows'].collect { |e| e['doc'] }
rs = rs.select { |doc| doc['_id'].match(key) } if key
# naive...
- rs
+ rs.select { |doc| ! doc['_id'].match(/^\_design\//) }
end
# Returns a sorted list of the ids of all the docs in this database.
#
def ids
@@ -124,31 +123,143 @@
def prepare
# nothing to do for a index-less database
end
+
+ # (for now, the only option is :limit)
+ #
+ def query_options (opts)
+
+ if l = opts[:limit]
+ "&limit=#{l}"
+ else
+ ''
+ end
+ end
+
+ def query (uri)
+
+ rs = @couch.get(uri)
+
+ rs['rows'].collect { |e| e['doc'] }
+ end
end
+ #
+ # A Couch database with a by_wfid view.
+ #
class WfidIndexedDatabase < Database
- #DESIGN_DOC_TEMPLATE = %{
- # {
- # "_id": "_design/ruote",
- # "version": 0,
- #
- # "views": {
- # "by_type": {
- # "map": "function (doc) { emit(doc.type, doc); }"
- # }
- # }
- # }
- #}.strip
+ def get_many (key, opts)
+ if key && m = key.source.match(/!?(.+)\$$/)
+ # let's use the couch view...
+
+ query(
+ "_design/ruote/_view/by_wfid?key=%22#{m[1]}%22" +
+ "&include_docs=true#{query_options(opts)}")
+
+ else
+ # let's use the naive default implementation
+
+ super
+ end
+ end
+
protected
+ def design_doc
+
+ {
+ '_id' => '_design/ruote',
+ 'views' => {
+ 'by_wfid' => {
+ 'map' =>
+ 'function (doc) { if (doc.fei) emit(doc.fei.wfid, null); }'
+ }
+ }
+ }
+ end
+
def prepare
- # TODO
+ d = @couch.get('_design/ruote')
+ @couch.delete(d) if d
+ @couch.put(design_doc)
+ end
+ end
+
+ #
+ # A Couch database with a by_wfid view and a by_field view.
+ #
+ class WorkitemDatabase < WfidIndexedDatabase
+
+ # This method is called by CouchStorage#by_field
+ #
+ def by_field (field, value=nil, opts={})
+
+ field = { field => value } if value
+ field = CGI.escape(Rufus::Json.encode(field))
+
+ query(
+ "_design/ruote/_view/by_field?key=#{field}" +
+ "&include_docs=true#{query_options(opts)}")
+ end
+
+ # This method is called by CouchStorage#by_participant
+ #
+ def by_participant (name, opts={})
+
+ query(
+ "_design/ruote/_view/by_participant_name?key=%22#{name}%22" +
+ "&include_docs=true#{query_options(opts)}")
+ end
+
+ protected
+
+ def design_doc
+
+ doc = super
+
+ # NOTE : with 'by_field', for a workitem with N fields there are
+ # currently 2 * N rows generated per workitem.
+ #
+ # Why not restrict { field => value } keys to only fields whose value
+ # is a string, a boolean or null ? I have the impression that querying
+ # for field whose value is 'complex' (array or hash) is not necessary
+ # (though sounding crazy useful).
+
+ doc['views']['by_field'] = {
+ 'map' => %{
+ function(doc) {
+ if (doc.fields) {
+ for (var field in doc.fields) {
+
+ emit(field, null);
+
+ var k = {};
+ k[field] = doc.fields[field]
+ emit(k, null);
+ //
+ // have to use that k trick...
+ // else the field is named 'field'
+ }
+ }
+ }
+ }
+ }
+ doc['views']['by_participant_name'] = {
+ 'map' => %{
+ function (doc) {
+ if (doc.participant_name) {
+ emit(doc.participant_name, null);
+ }
+ }
+ }
+ }
+
+ doc
end
end
end