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