lib/ruote/couch/database.rb in ruote-couch-2.1.10 vs lib/ruote/couch/database.rb in ruote-couch-2.1.11

- old
+ new

@@ -37,16 +37,12 @@ attr_reader :type attr_reader :couch - def initialize (host, port, type, name) + def initialize (host, port, type, name, opts={}) - #opts = { :re_put_ok => re_put_ok } - opts = {} - #opts[:timeout] = TODO - @couch = Rufus::Jig::Couch.new(host, port, name, opts) @couch.put('.') unless @couch.get('.') @type = type @@ -77,33 +73,53 @@ #p [ :del, doc['_id'], Thread.current.object_id.to_s[-3..-1], r.nil? ] Thread.pass # without this, test/functional/ct_0 fails after 1 to 10 runs... r + + rescue Rufus::Jig::TimeoutError => te + true end + # The get_many used by msgs, configurations and variables. + # def get_many (key, opts) - rs = @couch.get("_all_docs?include_docs=true#{query_options(opts)}") + return query('_all_docs?include_docs=true') if ( ! key) && opts.size < 1 - rs = rs['rows'].collect { |e| e['doc'] } + is = ids - rs = rs.select { |doc| doc['_id'].match(key) } if key - # naive... + return is.length if opts[:count] - rs.select { |doc| ! doc['_id'].match(/^\_design\//) } - end + is = is.reverse if opts[:descending] - DESIGN_DOC_REGEX = /^\_design\// + if key + keys = Array(key).map { |k| k.is_a?(String) ? "!#{k}" : k } + is = is.select { |i| Ruote::StorageBase.key_match?(keys, i) } + end + skip = opts[:skip] || 0 + limit = opts[:limit] || is.length + + is = is[skip, limit] + + query_by_post('_all_docs?include_docs=true', is) + + # TODO + # maybe _count come be of use here + # http://wiki.apache.org/couchdb/Built-In_Reduce_Functions + end + # Returns a sorted list of the ids of all the docs in this database. # def ids - rs = @couch.get('_all_docs') - - rs['rows'].collect { |r| r['id'] }.reject { |i| i.match(DESIGN_DOC_REGEX) } + @couch.get('_all_docs')['rows'].collect { |r| + r['id'] + }.reject { |i| + DESIGN_DOC_REGEX.match(i) + } end def dump s = "=== #{@type} ===\n" @@ -114,22 +130,26 @@ s2 << " #{k} => #{e[k].inspect}\n" end end end - #def shutdown - # @couch.close - #end - # jig > 0.1.17 is OK without that + # Makes sure to close the HTTP connection down. + # + def shutdown + @couch.close + end + # Deletes all the documents in this database. # def purge! + @couch.http.cache.clear @couch.get('_all_docs')['rows'].each do |row| + next if row['id'].match(/^\_design\//) doc = { '_id' => row['id'], '_rev' => row['value']['rev'] } - @couch.delete(doc) unless doc['_id'].match(/^\_design\//) + @couch.delete(doc) end # # which is faster than # #@couch.delete('.') @@ -142,64 +162,74 @@ def prepare # nothing to do for a index-less database end - # (for now, the only option is :limit) + # These options are known and passed to CouchDB. # + QUERY_OPTIONS = [ :skip, :limit, :descending ] + + # :limit and :skip support + # def query_options (opts) - opts = opts.select { |k, v| [ :limit, :skip ].include?(k) && v != nil } + opts = opts.select { |k, v| QUERY_OPTIONS.include?(k) && v != nil } s = opts.collect { |k, v| "#{k}=#{v}" }.join('&') s.length > 0 ? "&#{s}" : '' end + # Used by #get_many and #ids when filtering design documents out of + # '_all_docs'. + # + DESIGN_DOC_REGEX = /^\_design\// + + def filter_design_docs (docs) + + docs.reject { |d| DESIGN_DOC_REGEX.match(d['_id']) } + end + def query (uri) rs = @couch.get(uri) - rs['rows'].collect { |e| e['doc'] } + filter_design_docs(rs['rows'].collect { |e| e['doc'] }) end def query_by_post (uri, keys) keys = { 'keys' => keys } rs = @couch.post(uri, keys) - rs['rows'].collect { |e| e['doc'] }.uniq + filter_design_docs(rs['rows'].collect { |e| e['doc'] }.uniq) end end # # A Couch database with a by_wfid view. # class WfidIndexedDatabase < Database + # The get_many used by errors, expressions and schedules. + # def get_many (key, opts) - if key && m = key.source.match(/!?(.+)\$$/) - # let's use the couch view... + return super(key, opts) unless key.is_a?(String) - query( - "_design/ruote/_view/by_wfid?key=%22#{m[1]}%22" + - "&include_docs=true#{query_options(opts)}") + # key is a wfid - else - # let's use the naive default implementation - - super - end + query("_design/ruote/_view/by_wfid?key=%22#{key}%22&include_docs=true") end # Used by WorkitemDatabase#query # def by_wfid (wfid) - get_many(/!#{wfid}$/, {}) + #get_many(/!#{wfid}$/, {}) + get_many(wfid, {}) end # Returns the design document that goes with this class of database # def self.design_doc @@ -213,12 +243,16 @@ { '_id' => '_design/ruote', 'views' => { 'by_wfid' => { - 'map' => - 'function (doc) { if (doc.fei) emit(doc.fei.wfid, null); }' + 'map' => %{ + function (doc) { + if (doc.wfid) emit(doc.wfid, null); + else if (doc.fei) emit(doc.fei.wfid, null); + } + } } } } end @@ -276,11 +310,10 @@ if criteria.empty? && (wfid.nil? ^ pname.nil?) return by_participant(pname) if pname return by_wfid(wfid) # if wfid end - return get_many(nil, {}).collect { |hwi| Ruote::Workitem.new(hwi) } \ - if criteria.empty? + return get_many(nil, {}) if criteria.empty? cr = criteria.collect { |fname, fvalue| { fname => fvalue } } opts = { :skip => offset, :limit => limit }