paulcarey-relaxdb 0.3.0 → 0.3.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/README.textile +13 -9
- data/Rakefile +1 -1
- data/lib/relaxdb/document.rb +6 -4
- data/lib/relaxdb/net_http_server.rb +61 -0
- data/lib/relaxdb/server.rb +3 -60
- data/lib/relaxdb/taf2_curb_server.rb +62 -0
- data/lib/relaxdb.rb +8 -0
- data/readme.rb +8 -7
- data/spec/document_spec.rb +25 -5
- data/spec/spec_helper.rb +17 -0
- data/spec/spec_models.rb +1 -0
- metadata +3 -1
data/README.textile
CHANGED
@@ -1,8 +1,11 @@
|
|
1
1
|
h3. What's New?
|
2
2
|
|
3
|
-
|
3
|
+
* 2009-04-19
|
4
|
+
** Defaults to taf2-curb, falling back to Net/HTTP if it taf2-curb can't be loaded. Thanks to "Fred Cheung":http://www.spacevatican.org/2009/4/13/fun-with-ruby-http-clients.
|
5
|
+
** For those interested in using RelaxDB with an ETag based cache, "look here":http://github.com/fcheung/relaxdb/commit/1d9acfd5f6b3c23da0d275252b6a6e064865440e
|
4
6
|
|
5
|
-
|
7
|
+
* 2009-03-31
|
8
|
+
** RelaxDB 0.3 released - compatible with CouchDB 0.9.
|
6
9
|
|
7
10
|
h2. Overview
|
8
11
|
|
@@ -102,17 +105,18 @@ puts ix.sender.name # prints sofa, a single CouchDB request made
|
|
102
105
|
|
103
106
|
idup = i.dup
|
104
107
|
i.save!
|
105
|
-
idup.save
|
108
|
+
idup.save # conflict printed
|
106
109
|
|
107
110
|
# Saving with and without validations
|
108
111
|
|
109
|
-
i = Invite.new :sender => sofa, :
|
110
|
-
i.save! rescue :ok # save! throws an exception on validation failure or conflict
|
111
|
-
i.save # returns false rather than throwing an exception
|
112
|
-
puts i.errors.inspect # {:recipient=>"invalid:"}
|
112
|
+
i = Invite.new :sender => sofa, :event_name => "CouchCamp"
|
113
113
|
|
114
|
-
i.
|
115
|
-
i.save
|
114
|
+
i.save! rescue :ok # save! throws an exception on validation failure or conflict
|
115
|
+
i.save # returns false rather than throwing an exception
|
116
|
+
puts i.errors.inspect # prints {:recipient=>"invalid:"}
|
117
|
+
|
118
|
+
i.validation_skip_list << :recipient # Any and all validations may be skipped
|
119
|
+
i.save # succeeds
|
116
120
|
|
117
121
|
</code>
|
118
122
|
</pre>
|
data/Rakefile
CHANGED
data/lib/relaxdb/document.rb
CHANGED
@@ -141,7 +141,7 @@ module RelaxDB
|
|
141
141
|
# Only set instance variables on creation - object references are resolved on demand
|
142
142
|
|
143
143
|
# If the variable name ends in _at, _on or _date try to convert it to a Time
|
144
|
-
if [/_at$/, /_on$/, /_date$/].inject(nil) { |i, r| i ||= (key =~ r) }
|
144
|
+
if [/_at$/, /_on$/, /_date$/, /_time$/].inject(nil) { |i, r| i ||= (key =~ r) }
|
145
145
|
val = Time.parse(val).utc rescue val
|
146
146
|
end
|
147
147
|
|
@@ -210,7 +210,7 @@ module RelaxDB
|
|
210
210
|
end
|
211
211
|
|
212
212
|
def pre_save
|
213
|
-
|
213
|
+
set_timestamps
|
214
214
|
return false unless validates?
|
215
215
|
return false unless before_save
|
216
216
|
true
|
@@ -300,11 +300,13 @@ module RelaxDB
|
|
300
300
|
end
|
301
301
|
alias_method :id, :to_param
|
302
302
|
|
303
|
-
def
|
304
|
-
if
|
303
|
+
def set_timestamps
|
304
|
+
if new_document? && respond_to?(:created_at)
|
305
305
|
# Don't override it if it's already been set
|
306
306
|
@created_at = Time.now if @created_at.nil?
|
307
307
|
end
|
308
|
+
|
309
|
+
@updated_at = Time.now if respond_to?(:updated_at)
|
308
310
|
end
|
309
311
|
|
310
312
|
def create_or_get_proxy(klass, relationship, opts=nil)
|
@@ -0,0 +1,61 @@
|
|
1
|
+
module RelaxDB
|
2
|
+
|
3
|
+
class Server
|
4
|
+
|
5
|
+
def initialize(host, port)
|
6
|
+
@host = host
|
7
|
+
@port = port
|
8
|
+
end
|
9
|
+
|
10
|
+
def delete(uri)
|
11
|
+
request(Net::HTTP::Delete.new(uri))
|
12
|
+
end
|
13
|
+
|
14
|
+
def get(uri)
|
15
|
+
request(Net::HTTP::Get.new(uri))
|
16
|
+
end
|
17
|
+
|
18
|
+
def put(uri, json)
|
19
|
+
req = Net::HTTP::Put.new(uri)
|
20
|
+
req["content-type"] = "application/json"
|
21
|
+
req.body = json
|
22
|
+
request(req)
|
23
|
+
end
|
24
|
+
|
25
|
+
def post(uri, json)
|
26
|
+
req = Net::HTTP::Post.new(uri)
|
27
|
+
req["content-type"] = "application/json"
|
28
|
+
req.body = json
|
29
|
+
request(req)
|
30
|
+
end
|
31
|
+
|
32
|
+
def request(req)
|
33
|
+
res = Net::HTTP.start(@host, @port) {|http|
|
34
|
+
http.request(req)
|
35
|
+
}
|
36
|
+
if (not res.kind_of?(Net::HTTPSuccess))
|
37
|
+
handle_error(req, res)
|
38
|
+
end
|
39
|
+
res
|
40
|
+
end
|
41
|
+
|
42
|
+
def to_s
|
43
|
+
"http://#{@host}:#{@port}/"
|
44
|
+
end
|
45
|
+
|
46
|
+
private
|
47
|
+
|
48
|
+
def handle_error(req, res)
|
49
|
+
msg = "#{res.code}:#{res.message}\nMETHOD:#{req.method}\nURI:#{req.path}\n#{res.body}"
|
50
|
+
begin
|
51
|
+
klass = RelaxDB.const_get("HTTP_#{res.code}")
|
52
|
+
e = klass.new(msg)
|
53
|
+
rescue
|
54
|
+
e = RuntimeError.new(msg)
|
55
|
+
end
|
56
|
+
|
57
|
+
raise e
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
end
|
data/lib/relaxdb/server.rb
CHANGED
@@ -3,64 +3,6 @@ module RelaxDB
|
|
3
3
|
class HTTP_404 < StandardError; end
|
4
4
|
class HTTP_409 < StandardError; end
|
5
5
|
class HTTP_412 < StandardError; end
|
6
|
-
|
7
|
-
class Server
|
8
|
-
|
9
|
-
def initialize(host, port)
|
10
|
-
@host = host
|
11
|
-
@port = port
|
12
|
-
end
|
13
|
-
|
14
|
-
def delete(uri)
|
15
|
-
request(Net::HTTP::Delete.new(uri))
|
16
|
-
end
|
17
|
-
|
18
|
-
def get(uri)
|
19
|
-
request(Net::HTTP::Get.new(uri))
|
20
|
-
end
|
21
|
-
|
22
|
-
def put(uri, json)
|
23
|
-
req = Net::HTTP::Put.new(uri)
|
24
|
-
req["content-type"] = "application/json"
|
25
|
-
req.body = json
|
26
|
-
request(req)
|
27
|
-
end
|
28
|
-
|
29
|
-
def post(uri, json)
|
30
|
-
req = Net::HTTP::Post.new(uri)
|
31
|
-
req["content-type"] = "application/json"
|
32
|
-
req.body = json
|
33
|
-
request(req)
|
34
|
-
end
|
35
|
-
|
36
|
-
def request(req)
|
37
|
-
res = Net::HTTP.start(@host, @port) {|http|
|
38
|
-
http.request(req)
|
39
|
-
}
|
40
|
-
if (not res.kind_of?(Net::HTTPSuccess))
|
41
|
-
handle_error(req, res)
|
42
|
-
end
|
43
|
-
res
|
44
|
-
end
|
45
|
-
|
46
|
-
def to_s
|
47
|
-
"http://#{@host}:#{@port}/"
|
48
|
-
end
|
49
|
-
|
50
|
-
private
|
51
|
-
|
52
|
-
def handle_error(req, res)
|
53
|
-
msg = "#{res.code}:#{res.message}\nMETHOD:#{req.method}\nURI:#{req.path}\n#{res.body}"
|
54
|
-
begin
|
55
|
-
klass = RelaxDB.const_get("HTTP_#{res.code}")
|
56
|
-
e = klass.new(msg)
|
57
|
-
rescue
|
58
|
-
e = RuntimeError.new(msg)
|
59
|
-
end
|
60
|
-
|
61
|
-
raise e
|
62
|
-
end
|
63
|
-
end
|
64
6
|
|
65
7
|
class CouchDB
|
66
8
|
|
@@ -97,8 +39,9 @@ module RelaxDB
|
|
97
39
|
def replicate_db(source, target)
|
98
40
|
@logger.info("Replicating from #{source} to #{target}")
|
99
41
|
create_db_if_non_existant target
|
100
|
-
|
101
|
-
|
42
|
+
# Manual JSON encoding to allow for dbs containing a '/'
|
43
|
+
data = %Q({"source":"#{source}","target":"#{target}"})
|
44
|
+
@server.post("/_replicate", data)
|
102
45
|
end
|
103
46
|
|
104
47
|
def delete(path=nil)
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module RelaxDB
|
2
|
+
|
3
|
+
class Server
|
4
|
+
class Response
|
5
|
+
attr_reader :body
|
6
|
+
def initialize body
|
7
|
+
@body = body
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def initialize(host, port)
|
12
|
+
@host, @port = host, port
|
13
|
+
end
|
14
|
+
|
15
|
+
def delete(uri)
|
16
|
+
request(uri, 'delete'){ |c| c.http_delete}
|
17
|
+
end
|
18
|
+
|
19
|
+
def get(uri)
|
20
|
+
request(uri, 'get'){ |c| c.http_get}
|
21
|
+
end
|
22
|
+
|
23
|
+
def put(uri, json)
|
24
|
+
request(uri, 'put') do |c|
|
25
|
+
c.headers['content-type'] = 'application/json'
|
26
|
+
c.http_put json
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def post(uri, json)
|
31
|
+
request(uri, 'post') do |c|
|
32
|
+
c.headers['content-type'] = 'application/json'
|
33
|
+
c.http_post json
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
def request(uri, method)
|
38
|
+
c = Curl::Easy.new "http://#{@host}:#{@port}#{uri}"
|
39
|
+
yield c
|
40
|
+
|
41
|
+
if c.response_code < 200 || c.response_code >= 300
|
42
|
+
status_line = c.header_str.split('\r\n').first
|
43
|
+
msg = "#{c.response_code}:#{status_line}\nMETHOD:#{method}\nURI:#{uri}\n#{c.body_str}"
|
44
|
+
begin
|
45
|
+
klass = RelaxDB.const_get("HTTP_#{c.response_code}")
|
46
|
+
e = klass.new(msg)
|
47
|
+
rescue
|
48
|
+
e = RuntimeError.new(msg)
|
49
|
+
end
|
50
|
+
|
51
|
+
raise e
|
52
|
+
end
|
53
|
+
Response.new c.body_str
|
54
|
+
end
|
55
|
+
|
56
|
+
def to_s
|
57
|
+
"http://#{@host}:#{@port}/"
|
58
|
+
end
|
59
|
+
|
60
|
+
end
|
61
|
+
|
62
|
+
end
|
data/lib/relaxdb.rb
CHANGED
@@ -15,6 +15,14 @@ $:.unshift(File.dirname(__FILE__)) unless
|
|
15
15
|
|
16
16
|
require 'relaxdb/validators'
|
17
17
|
|
18
|
+
begin
|
19
|
+
gem 'taf2-curb'
|
20
|
+
require 'curb'
|
21
|
+
require 'relaxdb/taf2_curb_server'
|
22
|
+
rescue LoadError
|
23
|
+
require 'relaxdb/net_http_server'
|
24
|
+
end
|
25
|
+
|
18
26
|
require 'relaxdb/all_delegator'
|
19
27
|
require 'relaxdb/belongs_to_proxy'
|
20
28
|
require 'relaxdb/design_doc'
|
data/readme.rb
CHANGED
@@ -66,14 +66,15 @@ puts ix.sender.name # prints sofa, a single CouchDB request made
|
|
66
66
|
|
67
67
|
idup = i.dup
|
68
68
|
i.save!
|
69
|
-
idup.save
|
69
|
+
idup.save # conflict printed
|
70
70
|
|
71
71
|
# Saving with and without validations
|
72
72
|
|
73
|
-
i = Invite.new :sender => sofa, :
|
74
|
-
i.save! rescue :ok # save! throws an exception on validation failure or conflict
|
75
|
-
i.save # returns false rather than throwing an exception
|
76
|
-
puts i.errors.inspect # {:recipient=>"invalid:"}
|
73
|
+
i = Invite.new :sender => sofa, :event_name => "CouchCamp"
|
77
74
|
|
78
|
-
i.
|
79
|
-
i.save
|
75
|
+
i.save! rescue :ok # save! throws an exception on validation failure or conflict
|
76
|
+
i.save # returns false rather than throwing an exception
|
77
|
+
puts i.errors.inspect # prints {:recipient=>"invalid:"}
|
78
|
+
|
79
|
+
i.validation_skip_list << :recipient # Any and all validations may be skipped
|
80
|
+
i.save # succeeds
|
data/spec/document_spec.rb
CHANGED
@@ -80,12 +80,32 @@ describe RelaxDB::Document do
|
|
80
80
|
p.save
|
81
81
|
end
|
82
82
|
|
83
|
-
it "should set created_at
|
84
|
-
|
85
|
-
|
86
|
-
|
83
|
+
it "should set created_at on first save only" do
|
84
|
+
ts = Time.now
|
85
|
+
p = Post.new
|
86
|
+
|
87
|
+
created_at = p.save.created_at
|
88
|
+
created_at.should be_close(ts, 1)
|
89
|
+
|
90
|
+
roll_clock_forward(60) do
|
91
|
+
created_at = p.save.created_at
|
92
|
+
created_at.should be_close(ts, 1)
|
93
|
+
end
|
87
94
|
end
|
88
95
|
|
96
|
+
it "should set updated_at on each save" do
|
97
|
+
ts = Time.now
|
98
|
+
p = Primitives.new
|
99
|
+
|
100
|
+
updated_at = p.save.updated_at
|
101
|
+
updated_at.should be_close(ts, 1)
|
102
|
+
|
103
|
+
roll_clock_forward(60) do
|
104
|
+
updated_at = p.save.updated_at
|
105
|
+
updated_at.should be_close(Time.at(ts.to_i + 60), 1)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
89
109
|
it "should set created_at when first saved unless supplied to the constructor" do
|
90
110
|
back_then = Time.now - 1000
|
91
111
|
p = Post.new(:created_at => back_then).save
|
@@ -185,7 +205,7 @@ describe RelaxDB::Document do
|
|
185
205
|
|
186
206
|
it "should prevent the object from being resaved" do
|
187
207
|
p = Atom.new.save.destroy!
|
188
|
-
|
208
|
+
# Exepcted failure - see http://issues.apache.org/jira/browse/COUCHDB-292
|
189
209
|
lambda { p.save! }.should raise_error
|
190
210
|
end
|
191
211
|
|
data/spec/spec_helper.rb
CHANGED
@@ -42,3 +42,20 @@ def create_base_db
|
|
42
42
|
require File.dirname(__FILE__) + '/spec_models.rb'
|
43
43
|
puts "Created relaxdb_spec_base"
|
44
44
|
end
|
45
|
+
|
46
|
+
def roll_clock_forward(distance)
|
47
|
+
Time.meta_class.instance_eval do
|
48
|
+
define_method(:future_now) do
|
49
|
+
standard_now + distance
|
50
|
+
end
|
51
|
+
alias_method :standard_now, :now
|
52
|
+
alias_method :now, :future_now
|
53
|
+
begin
|
54
|
+
yield
|
55
|
+
rescue => e
|
56
|
+
raise e
|
57
|
+
ensure
|
58
|
+
alias_method :now, :standard_now
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
data/spec/spec_models.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: paulcarey-relaxdb
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.3.
|
4
|
+
version: 0.3.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Paul Carey
|
@@ -64,6 +64,7 @@ files:
|
|
64
64
|
- lib/relaxdb/extlib.rb
|
65
65
|
- lib/relaxdb/has_many_proxy.rb
|
66
66
|
- lib/relaxdb/has_one_proxy.rb
|
67
|
+
- lib/relaxdb/net_http_server.rb
|
67
68
|
- lib/relaxdb/paginate_params.rb
|
68
69
|
- lib/relaxdb/paginator.rb
|
69
70
|
- lib/relaxdb/query.rb
|
@@ -71,6 +72,7 @@ files:
|
|
71
72
|
- lib/relaxdb/relaxdb.rb
|
72
73
|
- lib/relaxdb/server.rb
|
73
74
|
- lib/relaxdb/uuid_generator.rb
|
75
|
+
- lib/relaxdb/taf2_curb_server.rb
|
74
76
|
- lib/relaxdb/validators.rb
|
75
77
|
- lib/relaxdb/view_object.rb
|
76
78
|
- lib/relaxdb/view_result.rb
|