view blocks flow
This commit is contained in:
parent
54a0afdf8e
commit
254eb20161
|
@ -5,8 +5,9 @@ module CouchRest
|
||||||
class Database
|
class Database
|
||||||
attr_reader :server, :host, :name, :root
|
attr_reader :server, :host, :name, :root
|
||||||
|
|
||||||
# Create a CouchRest::Database adapter for the supplied CouchRest::Server and database name.
|
# Create a CouchRest::Database adapter for the supplied CouchRest::Server
|
||||||
#
|
# and database name.
|
||||||
|
#
|
||||||
# ==== Parameters
|
# ==== Parameters
|
||||||
# server<CouchRest::Server>:: database host
|
# server<CouchRest::Server>:: database host
|
||||||
# name<String>:: database name
|
# name<String>:: database name
|
||||||
|
@ -40,7 +41,9 @@ module CouchRest
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# POST a temporary view function to CouchDB for querying. This is not recommended, as you don't get any performance benefit from CouchDB's materialized views. Can be quite slow on large databases.
|
# POST a temporary view function to CouchDB for querying. This is not
|
||||||
|
# recommended, as you don't get any performance benefit from CouchDB's
|
||||||
|
# materialized views. Can be quite slow on large databases.
|
||||||
def temp_view funcs, params = {}
|
def temp_view funcs, params = {}
|
||||||
keys = params.delete(:keys)
|
keys = params.delete(:keys)
|
||||||
funcs = funcs.merge({:keys => keys}) if keys
|
funcs = funcs.merge({:keys => keys}) if keys
|
||||||
|
@ -48,7 +51,8 @@ module CouchRest
|
||||||
JSON.parse(RestClient.post(url, funcs.to_json, {"Content-Type" => 'application/json'}))
|
JSON.parse(RestClient.post(url, funcs.to_json, {"Content-Type" => 'application/json'}))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Query a CouchDB view as defined by a <tt>_design</tt> document. Accepts paramaters as described in http://wiki.apache.org/couchdb/HttpViewApi
|
# Query a CouchDB view as defined by a <tt>_design</tt> document. Accepts
|
||||||
|
# paramaters as described in http://wiki.apache.org/couchdb/HttpViewApi
|
||||||
def view name, params = {}, &block
|
def view name, params = {}, &block
|
||||||
keys = params.delete(:keys)
|
keys = params.delete(:keys)
|
||||||
url = CouchRest.paramify_url "#{@root}/_view/#{name}", params
|
url = CouchRest.paramify_url "#{@root}/_view/#{name}", params
|
||||||
|
@ -56,6 +60,7 @@ module CouchRest
|
||||||
CouchRest.post(url, {:keys => keys})
|
CouchRest.post(url, {:keys => keys})
|
||||||
else
|
else
|
||||||
if block_given?
|
if block_given?
|
||||||
|
puts "streamer"
|
||||||
@streamer.view(name, params, &block)
|
@streamer.view(name, params, &block)
|
||||||
else
|
else
|
||||||
CouchRest.get url
|
CouchRest.get url
|
||||||
|
@ -89,7 +94,12 @@ module CouchRest
|
||||||
JSON.parse(RestClient.put(uri, file, options))
|
JSON.parse(RestClient.put(uri, file, options))
|
||||||
end
|
end
|
||||||
|
|
||||||
# Save a document to CouchDB. This will use the <tt>_id</tt> field from the document as the id for PUT, or request a new UUID from CouchDB, if no <tt>_id</tt> is present on the document. IDs are attached to documents on the client side because POST has the curious property of being automatically retried by proxies in the event of network segmentation and lost responses.
|
# Save a document to CouchDB. This will use the <tt>_id</tt> field from
|
||||||
|
# the document as the id for PUT, or request a new UUID from CouchDB, if
|
||||||
|
# no <tt>_id</tt> is present on the document. IDs are attached to
|
||||||
|
# documents on the client side because POST has the curious property of
|
||||||
|
# being automatically retried by proxies in the event of network
|
||||||
|
# segmentation and lost responses.
|
||||||
def save doc
|
def save doc
|
||||||
if doc['_attachments']
|
if doc['_attachments']
|
||||||
doc['_attachments'] = encode_attachments(doc['_attachments'])
|
doc['_attachments'] = encode_attachments(doc['_attachments'])
|
||||||
|
@ -107,7 +117,8 @@ module CouchRest
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
# POST an array of documents to CouchDB. If any of the documents are missing ids, supply one from the uuid cache.
|
# POST an array of documents to CouchDB. If any of the documents are
|
||||||
|
# missing ids, supply one from the uuid cache.
|
||||||
def bulk_save docs
|
def bulk_save docs
|
||||||
ids, noids = docs.partition{|d|d['_id']}
|
ids, noids = docs.partition{|d|d['_id']}
|
||||||
uuid_count = [noids.length, @server.uuid_batch_count].max
|
uuid_count = [noids.length, @server.uuid_batch_count].max
|
||||||
|
@ -118,13 +129,15 @@ module CouchRest
|
||||||
CouchRest.post "#{@root}/_bulk_docs", {:docs => docs}
|
CouchRest.post "#{@root}/_bulk_docs", {:docs => docs}
|
||||||
end
|
end
|
||||||
|
|
||||||
# DELETE the document from CouchDB that has the given <tt>_id</tt> and <tt>_rev</tt>.
|
# DELETE the document from CouchDB that has the given <tt>_id</tt> and
|
||||||
|
# <tt>_rev</tt>.
|
||||||
def delete doc
|
def delete doc
|
||||||
slug = CGI.escape(doc['_id'])
|
slug = CGI.escape(doc['_id'])
|
||||||
CouchRest.delete "#{@root}/#{slug}?rev=#{doc['_rev']}"
|
CouchRest.delete "#{@root}/#{slug}?rev=#{doc['_rev']}"
|
||||||
end
|
end
|
||||||
|
|
||||||
# DELETE the database itself. This is not undoable and could be rather catastrophic. Use with care!
|
# DELETE the database itself. This is not undoable and could be rather
|
||||||
|
# catastrophic. Use with care!
|
||||||
def delete!
|
def delete!
|
||||||
CouchRest.delete @root
|
CouchRest.delete @root
|
||||||
end
|
end
|
||||||
|
|
|
@ -302,6 +302,9 @@ module CouchRest
|
||||||
|
|
||||||
self.meta_class.instance_eval do
|
self.meta_class.instance_eval do
|
||||||
define_method method_name do |*args|
|
define_method method_name do |*args|
|
||||||
|
# block = args.pop if args.last.is_a?(Proc)
|
||||||
|
block = nil
|
||||||
|
puts "block" if block_given?
|
||||||
query = opts.merge(args[0] || {})
|
query = opts.merge(args[0] || {})
|
||||||
query[:raw] = true if query[:reduce]
|
query[:raw] = true if query[:reduce]
|
||||||
unless design_doc_fresh
|
unless design_doc_fresh
|
||||||
|
@ -309,7 +312,7 @@ module CouchRest
|
||||||
end
|
end
|
||||||
raw = query.delete(:raw)
|
raw = query.delete(:raw)
|
||||||
view_name = "#{design_doc_slug}/#{method_name}"
|
view_name = "#{design_doc_slug}/#{method_name}"
|
||||||
fetch_view_with_docs(view_name, query, raw)
|
fetch_view_with_docs(view_name, query, raw, &block)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -319,28 +322,38 @@ module CouchRest
|
||||||
database.get("_design/#{design_doc_slug}")
|
database.get("_design/#{design_doc_slug}")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
# Dispatches to any named view.
|
||||||
|
def view name, query={}, &block
|
||||||
|
name = name.to_s
|
||||||
|
view_name = "#{design_doc_slug}/#{name}"
|
||||||
|
puts view_name
|
||||||
|
fetch_view_with_docs(view_name, query, true, &block)
|
||||||
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
||||||
def fetch_view_with_docs name, opts, raw=false
|
def fetch_view_with_docs name, opts, raw=false, &block
|
||||||
|
|
||||||
if raw
|
if raw
|
||||||
fetch_view name, opts
|
fetch_view name, opts, &block
|
||||||
else
|
else
|
||||||
begin
|
begin
|
||||||
view = fetch_view name, opts.merge({:include_docs => true})
|
view = fetch_view name, opts.merge({:include_docs => true}), &block
|
||||||
view['rows'].collect{|r|new(r['doc'])}
|
view['rows'].collect{|r|new(r['doc'])} if view
|
||||||
rescue
|
rescue
|
||||||
# fallback for old versions of couchdb that don't
|
# fallback for old versions of couchdb that don't
|
||||||
# have include_docs support
|
# have include_docs support
|
||||||
view = fetch_view name, opts
|
view = fetch_view name, opts, &block
|
||||||
view['rows'].collect{|r|new(database.get(r['id']))}
|
view['rows'].collect{|r|new(database.get(r['id']))} if view
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
def fetch_view view_name, opts
|
def fetch_view view_name, opts, &block
|
||||||
retryable = true
|
retryable = true
|
||||||
begin
|
begin
|
||||||
database.view(view_name, opts)
|
puts "block" if block
|
||||||
|
database.view(view_name, opts, &block)
|
||||||
# the design doc could have been deleted by a rouge process
|
# the design doc could have been deleted by a rouge process
|
||||||
rescue RestClient::ResourceNotFound => e
|
rescue RestClient::ResourceNotFound => e
|
||||||
if retryable
|
if retryable
|
||||||
|
|
|
@ -6,15 +6,21 @@ module CouchRest
|
||||||
end
|
end
|
||||||
|
|
||||||
# Stream a view, yielding one row at a time. Shells out to <tt>curl</tt> to keep RAM usage low when you have millions of rows.
|
# Stream a view, yielding one row at a time. Shells out to <tt>curl</tt> to keep RAM usage low when you have millions of rows.
|
||||||
def view name, params = nil
|
def view name, params = nil, &block
|
||||||
urlst = /^_/.match(name) ? "#{@db.root}/#{name}" : "#{@db.root}/_view/#{name}"
|
urlst = /^_/.match(name) ? "#{@db.root}/#{name}" : "#{@db.root}/_view/#{name}"
|
||||||
url = CouchRest.paramify_url urlst, params
|
url = CouchRest.paramify_url urlst, params
|
||||||
|
first = nil
|
||||||
IO.popen("curl --silent #{url}") do |view|
|
IO.popen("curl --silent #{url}") do |view|
|
||||||
view.gets # discard header
|
first = view.gets # discard header
|
||||||
while row = parse_line(view.gets)
|
# puts first
|
||||||
yield row
|
while line = view.gets
|
||||||
|
# puts line
|
||||||
|
row = parse_line(line)
|
||||||
|
block.call row
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
# parse_line(line)
|
||||||
|
first
|
||||||
end
|
end
|
||||||
|
|
||||||
private
|
private
|
||||||
|
|
|
@ -122,7 +122,8 @@ describe CouchRest::Database do
|
||||||
rs = @db.view('first/test', :include_docs => true) do |row|
|
rs = @db.view('first/test', :include_docs => true) do |row|
|
||||||
rows << row
|
rows << row
|
||||||
end
|
end
|
||||||
rows.length.should == 3
|
rows.length.should == 4
|
||||||
|
rs.should == 'a parsed thing. not that easy.'
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -419,17 +419,36 @@ describe CouchRest::Model do
|
||||||
@db = @cr.create_db(TESTDB) rescue nil
|
@db = @cr.create_db(TESTDB) rescue nil
|
||||||
Course.new(:title => 'aaa').save
|
Course.new(:title => 'aaa').save
|
||||||
Course.new(:title => 'bbb').save
|
Course.new(:title => 'bbb').save
|
||||||
|
Course.new(:title => 'ddd').save
|
||||||
|
Course.new(:title => 'eee').save
|
||||||
end
|
end
|
||||||
it "should make the design doc upon first query" do
|
it "should make the design doc upon first query" do
|
||||||
Course.by_title
|
Course.by_title
|
||||||
doc = Course.design_doc
|
doc = Course.design_doc
|
||||||
doc['views']['all']['map'].should include('Course')
|
doc['views']['all']['map'].should include('Course')
|
||||||
end
|
end
|
||||||
|
it "should can query via view" do
|
||||||
|
# register methods with method-missing, for local dispatch. method
|
||||||
|
# missing lookup table, no heuristics.
|
||||||
|
view = Course.view :by_title
|
||||||
|
designed = Course.by_title :raw => true
|
||||||
|
view.should == designed
|
||||||
|
end
|
||||||
it "should get them" do
|
it "should get them" do
|
||||||
rs = Course.by_title
|
rs = Course.by_title
|
||||||
rs.length.should == 2
|
rs.length.should == 4
|
||||||
end
|
end
|
||||||
end
|
it "should yield" do
|
||||||
|
courses = []
|
||||||
|
puts "Course.view(:by_title)"
|
||||||
|
rs = Course.by_title # remove me
|
||||||
|
Course.view(:by_title) do |course|
|
||||||
|
# puts "course"
|
||||||
|
courses << course
|
||||||
|
end
|
||||||
|
courses[0]["key"].should =='aaa'
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
describe "a ducktype view" do
|
describe "a ducktype view" do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/spec_helper'
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
||||||
|
|
||||||
describe CouchRest::FileManager do
|
describe CouchRest::FileManager do
|
||||||
before(:all) do
|
before(:all) do
|
|
@ -0,0 +1,26 @@
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<title>Generated CouchApp</title>
|
||||||
|
<link rel="stylesheet" href="screen.css" type="text/css">
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<h1>Generated CouchApp</h1>
|
||||||
|
<ul id="view"></ul>
|
||||||
|
</body>
|
||||||
|
<script src="/_utils/script/json2.js"></script>
|
||||||
|
<script src="/_utils/script/jquery.js?1.2.6"></script>
|
||||||
|
<script src="/_utils/script/jquery.couch.js?0.8.0"></script>
|
||||||
|
<script type="text/javascript" charset="utf-8">
|
||||||
|
$(function() {
|
||||||
|
var dbname = document.location.href.split('/')[3];
|
||||||
|
var design = unescape(document.location.href.split('/')[4]).split('/')[1];
|
||||||
|
var DB = $.couch.db(dbname);
|
||||||
|
DB.view(design+"/example",{success: function(json) {
|
||||||
|
$("#view").html(json.rows.map(function(row) {
|
||||||
|
return '<li>'+row.key+'</li>';
|
||||||
|
}).join(''));
|
||||||
|
}});
|
||||||
|
});
|
||||||
|
</script>
|
||||||
|
</html>
|
|
@ -0,0 +1,8 @@
|
||||||
|
// an example map function, emits the doc id
|
||||||
|
// and the list of keys it contains
|
||||||
|
|
||||||
|
function(doc) {
|
||||||
|
var k, keys = []
|
||||||
|
for (k in doc) keys.push(k);
|
||||||
|
emit(doc._id, keys);
|
||||||
|
};
|
|
@ -0,0 +1,10 @@
|
||||||
|
// example reduce function to count the
|
||||||
|
// number of rows in a given key range.
|
||||||
|
|
||||||
|
function(keys, values, rereduce) {
|
||||||
|
if (rereduce) {
|
||||||
|
return sum(values);
|
||||||
|
} else {
|
||||||
|
return values.length;
|
||||||
|
}
|
||||||
|
};
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/spec_helper'
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
||||||
|
|
||||||
describe CouchRest::Pager do
|
describe CouchRest::Pager do
|
||||||
before(:all) do
|
before(:all) do
|
|
@ -1,4 +1,4 @@
|
||||||
require File.dirname(__FILE__) + '/spec_helper'
|
require File.dirname(__FILE__) + '/../../spec_helper'
|
||||||
|
|
||||||
describe CouchRest::Streamer do
|
describe CouchRest::Streamer do
|
||||||
before(:all) do
|
before(:all) do
|
||||||
|
@ -17,7 +17,7 @@ describe CouchRest::Streamer do
|
||||||
@streamer.view("_all_docs") do |row|
|
@streamer.view("_all_docs") do |row|
|
||||||
count += 1
|
count += 1
|
||||||
end
|
end
|
||||||
count.should == 1000
|
count.should == 1001
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
Loading…
Reference in a new issue