paulcarey-relaxdb 0.3.0 → 0.3.1

Sign up to get free protection for your applications and to get access to all the features.
data/README.textile CHANGED
@@ -1,8 +1,11 @@
1
1
  h3. What's New?
2
2
 
3
- RelaxDB 0.3 released - compatible with CouchDB 0.9.
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
- Version 0.3 includes many breaking changes. Most notable are simplified view syntax changes and the requirement that a design doc be specified up front.
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 # conflict printed
108
+ idup.save # conflict printed
106
109
 
107
110
  # Saving with and without validations
108
111
 
109
- i = Invite.new :sender => sofa, :name => "daily show"
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.validation_skip_list << :recipient # Any and all validations may be skipped
115
- i.save # succeeds
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
@@ -4,7 +4,7 @@ require 'spec/rake/spectask'
4
4
 
5
5
  PLUGIN = "relaxdb"
6
6
  NAME = "relaxdb"
7
- GEM_VERSION = "0.3.0"
7
+ GEM_VERSION = "0.3.1"
8
8
  AUTHOR = "Paul Carey"
9
9
  EMAIL = "paul.p.carey@gmail.com"
10
10
  HOMEPAGE = "http://github.com/paulcarey/relaxdb/"
@@ -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
- set_created_at if new_document?
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 set_created_at
304
- if methods.include? "created_at"
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
@@ -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
- data = { "source" => source, "target" => target}
101
- @server.post("/_replicate", data.to_json)
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 # conflict printed
69
+ idup.save # conflict printed
70
70
 
71
71
  # Saving with and without validations
72
72
 
73
- i = Invite.new :sender => sofa, :name => "daily show"
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.validation_skip_list << :recipient # Any and all validations may be skipped
79
- i.save # succeeds
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
@@ -80,12 +80,32 @@ describe RelaxDB::Document do
80
80
  p.save
81
81
  end
82
82
 
83
- it "should set created_at when first saved" do
84
- now = Time.now
85
- created_at = Post.new.save.created_at
86
- now.should be_close(created_at, 1)
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
- # Exepcted failure - see http://issues.apache.org/jira/browse/COUCHDB-292
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
@@ -18,6 +18,7 @@ class Primitives < RelaxDB::Document
18
18
  property :true_bool
19
19
  property :false_bool
20
20
  property :created_at
21
+ property :updated_at
21
22
  property :empty
22
23
 
23
24
  view_by :num
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.0
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