couchrest 0.35 → 0.36

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,180 @@
1
+ require 'time'
2
+ require 'bigdecimal'
3
+ require 'bigdecimal/util'
4
+ require File.join(File.dirname(__FILE__), '..', 'more', 'property')
5
+
6
+ class Time
7
+ # returns a local time value much faster than Time.parse
8
+ def self.mktime_with_offset(string)
9
+ string =~ /(\d{4})[\-|\/](\d{2})[\-|\/](\d{2})[T|\s](\d{2}):(\d{2}):(\d{2})([\+|\s|\-])*(\d{2}):?(\d{2})/
10
+ # $1 = year
11
+ # $2 = month
12
+ # $3 = day
13
+ # $4 = hours
14
+ # $5 = minutes
15
+ # $6 = seconds
16
+ # $7 = time zone direction
17
+ # $8 = tz difference
18
+ # utc time with wrong TZ info:
19
+ time = mktime($1, RFC2822_MONTH_NAME[$2.to_i - 1], $3, $4, $5, $6, $7)
20
+ tz_difference = ("#{$7 == '-' ? '+' : '-'}#{$8}".to_i * 3600)
21
+ time + tz_difference + zone_offset(time.zone)
22
+ end
23
+ end
24
+
25
+ module CouchRest
26
+ module More
27
+ module Typecast
28
+
29
+ def typecast_value(value, klass, init_method)
30
+ return nil if value.nil?
31
+
32
+ if value.instance_of?(klass) || klass.to_s == 'Object'
33
+ value
34
+ elsif ['String', 'TrueClass', 'Integer', 'Float', 'BigDecimal', 'DateTime', 'Time', 'Date', 'Class'].include?(klass.to_s)
35
+ send('typecast_to_'+klass.to_s.downcase, value)
36
+ else
37
+ # Allow the init_method to be defined as a Proc for advanced conversion
38
+ init_method.is_a?(Proc) ? init_method.call(value) : klass.send(init_method, value)
39
+ end
40
+ end
41
+
42
+ protected
43
+
44
+ # Typecast a value to an Integer
45
+ def typecast_to_integer(value)
46
+ value.kind_of?(Integer) ? value : typecast_to_numeric(value, :to_i)
47
+ end
48
+
49
+ # Typecast a value to a String
50
+ def typecast_to_string(value)
51
+ value.to_s
52
+ end
53
+
54
+ # Typecast a value to a true or false
55
+ def typecast_to_trueclass(value)
56
+ if value.kind_of?(Integer)
57
+ return true if value == 1
58
+ return false if value == 0
59
+ elsif value.respond_to?(:to_s)
60
+ return true if %w[ true 1 t ].include?(value.to_s.downcase)
61
+ return false if %w[ false 0 f ].include?(value.to_s.downcase)
62
+ end
63
+ value
64
+ end
65
+
66
+ # Typecast a value to a BigDecimal
67
+ def typecast_to_bigdecimal(value)
68
+ return value if value.kind_of?(BigDecimal)
69
+
70
+ if value.kind_of?(Integer)
71
+ value.to_s.to_d
72
+ else
73
+ typecast_to_numeric(value, :to_d)
74
+ end
75
+ end
76
+
77
+ # Typecast a value to a Float
78
+ def typecast_to_float(value)
79
+ return value if value.kind_of?(Float)
80
+ typecast_to_numeric(value, :to_f)
81
+ end
82
+
83
+ # Match numeric string
84
+ def typecast_to_numeric(value, method)
85
+ if value.respond_to?(:to_str)
86
+ if value.to_str =~ /\A(-?(?:0|[1-9]\d*)(?:\.\d+)?|(?:\.\d+))\z/
87
+ $1.send(method)
88
+ else
89
+ value
90
+ end
91
+ elsif value.respond_to?(method)
92
+ value.send(method)
93
+ else
94
+ value
95
+ end
96
+ end
97
+
98
+ # Typecasts an arbitrary value to a DateTime.
99
+ # Handles both Hashes and DateTime instances.
100
+ def typecast_to_datetime(value)
101
+ return value if value.kind_of?(DateTime)
102
+
103
+ if value.is_a?(Hash)
104
+ typecast_hash_to_datetime(value)
105
+ else
106
+ DateTime.parse(value.to_s)
107
+ end
108
+ rescue ArgumentError
109
+ value
110
+ end
111
+
112
+ # Typecasts an arbitrary value to a Date
113
+ # Handles both Hashes and Date instances.
114
+ def typecast_to_date(value)
115
+ return value if value.kind_of?(Date)
116
+
117
+ if value.is_a?(Hash)
118
+ typecast_hash_to_date(value)
119
+ else
120
+ Date.parse(value.to_s)
121
+ end
122
+ rescue ArgumentError
123
+ value
124
+ end
125
+
126
+ # Typecasts an arbitrary value to a Time
127
+ # Handles both Hashes and Time instances.
128
+ def typecast_to_time(value)
129
+ return value if value.kind_of?(Time)
130
+
131
+ if value.is_a?(Hash)
132
+ typecast_hash_to_time(value)
133
+ else
134
+ Time.mktime_with_offset(value.to_s)
135
+ end
136
+ rescue ArgumentError
137
+ value
138
+ rescue TypeError
139
+ value
140
+ end
141
+
142
+ # Creates a DateTime instance from a Hash with keys :year, :month, :day,
143
+ # :hour, :min, :sec
144
+ def typecast_hash_to_datetime(value)
145
+ DateTime.new(*extract_time(value))
146
+ end
147
+
148
+ # Creates a Date instance from a Hash with keys :year, :month, :day
149
+ def typecast_hash_to_date(value)
150
+ Date.new(*extract_time(value)[0, 3])
151
+ end
152
+
153
+ # Creates a Time instance from a Hash with keys :year, :month, :day,
154
+ # :hour, :min, :sec
155
+ def typecast_hash_to_time(value)
156
+ Time.local(*extract_time(value))
157
+ end
158
+
159
+ # Extracts the given args from the hash. If a value does not exist, it
160
+ # uses the value of Time.now.
161
+ def extract_time(value)
162
+ now = Time.now
163
+
164
+ [:year, :month, :day, :hour, :min, :sec].map do |segment|
165
+ typecast_to_numeric(value.fetch(segment, now.send(segment)), :to_i)
166
+ end
167
+ end
168
+
169
+ # Typecast a value to a Class
170
+ def typecast_to_class(value)
171
+ return value if value.kind_of?(Class)
172
+ ::CouchRest.constantize(value.to_s)
173
+ rescue NameError
174
+ value
175
+ end
176
+
177
+ end
178
+ end
179
+ end
180
+
@@ -37,7 +37,7 @@ module CouchRest
37
37
 
38
38
  def call(target)
39
39
  value = target.validation_property_value(field_name)
40
- property = target.validation_property(field_name)
40
+ property = target.validation_property(field_name.to_s)
41
41
  return true if present?(value, property)
42
42
 
43
43
  error_message = @options[:message] || default_error(property)
@@ -66,7 +66,7 @@ module CouchRest
66
66
  # Returns false for other property types.
67
67
  # Returns false for non-properties.
68
68
  def boolean_type?(property)
69
- property ? property.type == TrueClass : false
69
+ property ? property.type == 'Boolean' : false
70
70
  end
71
71
 
72
72
  end # class RequiredFieldValidator
@@ -46,137 +46,74 @@ describe CouchRest do
46
46
  it "should parse just a dbname" do
47
47
  db = CouchRest.parse "my-db"
48
48
  db[:database].should == "my-db"
49
- db[:host].should == "127.0.0.1:5984"
49
+ db[:host].should == "http://127.0.0.1:5984"
50
50
  end
51
51
  it "should parse a host and db" do
52
52
  db = CouchRest.parse "127.0.0.1/my-db"
53
53
  db[:database].should == "my-db"
54
- db[:host].should == "127.0.0.1"
55
- end
56
- it "should parse a host and db with http" do
57
- db = CouchRest.parse "https://127.0.0.1/my-db"
58
- db[:database].should == "my-db"
59
- db[:host].should == "127.0.0.1"
60
- end
61
- it "should parse a host with a port and db" do
62
- db = CouchRest.parse "127.0.0.1:5555/my-db"
63
- db[:database].should == "my-db"
64
- db[:host].should == "127.0.0.1:5555"
65
- end
66
- it "should parse a host with a port and db with http" do
67
- db = CouchRest.parse "http://127.0.0.1:5555/my-db"
68
- db[:database].should == "my-db"
69
- db[:host].should == "127.0.0.1:5555"
70
- end
71
- it "should parse a host with a port and db with https" do
72
- db = CouchRest.parse "https://127.0.0.1:5555/my-db"
73
- db[:database].should == "my-db"
74
- db[:host].should == "127.0.0.1:5555"
75
- end
76
- it "should parse just a host" do
77
- db = CouchRest.parse "http://127.0.0.1:5555/"
78
- db[:database].should be_nil
79
- db[:host].should == "127.0.0.1:5555"
80
- end
81
- it "should parse just a host with https" do
82
- db = CouchRest.parse "https://127.0.0.1:5555/"
83
- db[:database].should be_nil
84
- db[:host].should == "127.0.0.1:5555"
85
- end
86
- it "should parse just a host no slash" do
87
- db = CouchRest.parse "http://127.0.0.1:5555"
88
- db[:host].should == "127.0.0.1:5555"
89
- db[:database].should be_nil
90
- end
91
- it "should parse just a host no slash and https" do
92
- db = CouchRest.parse "https://127.0.0.1:5555"
93
- db[:host].should == "127.0.0.1:5555"
94
- db[:database].should be_nil
95
- end
96
- it "should get docid" do
97
- db = CouchRest.parse "127.0.0.1:5555/my-db/my-doc"
98
- db[:database].should == "my-db"
99
- db[:host].should == "127.0.0.1:5555"
100
- db[:doc].should == "my-doc"
101
- end
102
- it "should get docid with http" do
103
- db = CouchRest.parse "http://127.0.0.1:5555/my-db/my-doc"
104
- db[:database].should == "my-db"
105
- db[:host].should == "127.0.0.1:5555"
106
- db[:doc].should == "my-doc"
107
- end
108
- it "should get docid with https" do
109
- db = CouchRest.parse "https://127.0.0.1:5555/my-db/my-doc"
110
- db[:database].should == "my-db"
111
- db[:host].should == "127.0.0.1:5555"
112
- db[:doc].should == "my-doc"
113
- end
114
- it "should parse a host and db" do
115
- db = CouchRest.parse "127.0.0.1/my-db"
116
- db[:database].should == "my-db"
117
- db[:host].should == "127.0.0.1"
54
+ db[:host].should == "http://127.0.0.1"
118
55
  end
119
56
  it "should parse a host and db with http" do
120
57
  db = CouchRest.parse "http://127.0.0.1/my-db"
121
58
  db[:database].should == "my-db"
122
- db[:host].should == "127.0.0.1"
59
+ db[:host].should == "http://127.0.0.1"
123
60
  end
124
61
  it "should parse a host and db with https" do
125
62
  db = CouchRest.parse "https://127.0.0.1/my-db"
126
63
  db[:database].should == "my-db"
127
- db[:host].should == "127.0.0.1"
64
+ db[:host].should == "https://127.0.0.1"
128
65
  end
129
66
  it "should parse a host with a port and db" do
130
67
  db = CouchRest.parse "127.0.0.1:5555/my-db"
131
68
  db[:database].should == "my-db"
132
- db[:host].should == "127.0.0.1:5555"
69
+ db[:host].should == "http://127.0.0.1:5555"
133
70
  end
134
71
  it "should parse a host with a port and db with http" do
135
72
  db = CouchRest.parse "http://127.0.0.1:5555/my-db"
136
73
  db[:database].should == "my-db"
137
- db[:host].should == "127.0.0.1:5555"
74
+ db[:host].should == "http://127.0.0.1:5555"
138
75
  end
139
76
  it "should parse a host with a port and db with https" do
140
- db = CouchRest.parse "http://127.0.0.1:5555/my-db"
77
+ db = CouchRest.parse "https://127.0.0.1:5555/my-db"
141
78
  db[:database].should == "my-db"
142
- db[:host].should == "127.0.0.1:5555"
79
+ db[:host].should == "https://127.0.0.1:5555"
143
80
  end
144
81
  it "should parse just a host" do
145
82
  db = CouchRest.parse "http://127.0.0.1:5555/"
146
83
  db[:database].should be_nil
147
- db[:host].should == "127.0.0.1:5555"
84
+ db[:host].should == "http://127.0.0.1:5555"
148
85
  end
149
86
  it "should parse just a host with https" do
150
87
  db = CouchRest.parse "https://127.0.0.1:5555/"
151
88
  db[:database].should be_nil
152
- db[:host].should == "127.0.0.1:5555"
89
+ db[:host].should == "https://127.0.0.1:5555"
153
90
  end
154
91
  it "should parse just a host no slash" do
155
92
  db = CouchRest.parse "http://127.0.0.1:5555"
156
- db[:host].should == "127.0.0.1:5555"
93
+ db[:host].should == "http://127.0.0.1:5555"
157
94
  db[:database].should be_nil
158
95
  end
159
96
  it "should parse just a host no slash and https" do
160
97
  db = CouchRest.parse "https://127.0.0.1:5555"
161
- db[:host].should == "127.0.0.1:5555"
98
+ db[:host].should == "https://127.0.0.1:5555"
162
99
  db[:database].should be_nil
163
100
  end
164
101
  it "should get docid" do
165
102
  db = CouchRest.parse "127.0.0.1:5555/my-db/my-doc"
166
103
  db[:database].should == "my-db"
167
- db[:host].should == "127.0.0.1:5555"
104
+ db[:host].should == "http://127.0.0.1:5555"
168
105
  db[:doc].should == "my-doc"
169
106
  end
170
107
  it "should get docid with http" do
171
108
  db = CouchRest.parse "http://127.0.0.1:5555/my-db/my-doc"
172
109
  db[:database].should == "my-db"
173
- db[:host].should == "127.0.0.1:5555"
110
+ db[:host].should == "http://127.0.0.1:5555"
174
111
  db[:doc].should == "my-doc"
175
112
  end
176
113
  it "should get docid with https" do
177
114
  db = CouchRest.parse "https://127.0.0.1:5555/my-db/my-doc"
178
115
  db[:database].should == "my-db"
179
- db[:host].should == "127.0.0.1:5555"
116
+ db[:host].should == "https://127.0.0.1:5555"
180
117
  db[:doc].should == "my-doc"
181
118
  end
182
119
  end
@@ -185,7 +122,7 @@ describe CouchRest do
185
122
  it "should be possible without an explicit CouchRest instantiation" do
186
123
  db = CouchRest.database "http://127.0.0.1:5984/couchrest-test"
187
124
  db.should be_an_instance_of(CouchRest::Database)
188
- db.host.should == "127.0.0.1:5984"
125
+ db.host.should == "http://127.0.0.1:5984"
189
126
  end
190
127
  # TODO add https support (need test environment...)
191
128
  # it "should work with https" # do
@@ -703,12 +703,12 @@ describe CouchRest::Database do
703
703
  end
704
704
  end
705
705
 
706
- describe "replicating a database" do
706
+ describe "simply replicating a database" do
707
707
  before do
708
708
  @db.save_doc({'_id' => 'test_doc', 'some-value' => 'foo'})
709
- @other_db = @cr.database 'couchrest-test-replication'
709
+ @other_db = @cr.database REPLICATIONDB
710
710
  @other_db.delete! rescue nil
711
- @other_db = @cr.create_db 'couchrest-test-replication'
711
+ @other_db = @cr.create_db REPLICATIONDB
712
712
  end
713
713
 
714
714
  describe "via pulling" do
@@ -733,6 +733,53 @@ describe CouchRest::Database do
733
733
  end
734
734
  end
735
735
  end
736
+
737
+ describe "continuously replicating a database" do
738
+ before do
739
+ @db.save_doc({'_id' => 'test_doc', 'some-value' => 'foo'})
740
+ @other_db = @cr.database REPLICATIONDB
741
+ @other_db.delete! rescue nil
742
+ @other_db = @cr.create_db REPLICATIONDB
743
+ end
744
+
745
+ describe "via pulling" do
746
+ before do
747
+ @other_db.replicate_from @db, true
748
+ end
749
+
750
+ it "contains the document from the original database" do
751
+ sleep(1) # Allow some time to replicate
752
+ doc = @other_db.get('test_doc')
753
+ doc['some-value'].should == 'foo'
754
+ end
755
+
756
+ it "contains documents saved after replication initiated" do
757
+ @db.save_doc({'_id' => 'test_doc_after', 'some-value' => 'bar'})
758
+ sleep(1) # Allow some time to replicate
759
+ doc = @other_db.get('test_doc_after')
760
+ doc['some-value'].should == 'bar'
761
+ end
762
+ end
763
+
764
+ describe "via pushing" do
765
+ before do
766
+ @db.replicate_to @other_db, true
767
+ end
768
+
769
+ it "copies the document to the other database" do
770
+ sleep(1) # Allow some time to replicate
771
+ doc = @other_db.get('test_doc')
772
+ doc['some-value'].should == 'foo'
773
+ end
774
+
775
+ it "copies documents saved after replication initiated" do
776
+ @db.save_doc({'_id' => 'test_doc_after', 'some-value' => 'bar'})
777
+ sleep(1) # Allow some time to replicate
778
+ doc = @other_db.get('test_doc_after')
779
+ doc['some-value'].should == 'bar'
780
+ end
781
+ end
782
+ end
736
783
 
737
784
  describe "creating a database" do
738
785
  before(:each) do
@@ -769,5 +816,25 @@ describe CouchRest::Database do
769
816
 
770
817
  end
771
818
 
819
+ describe "searching a database" do
820
+ before(:each) do
821
+ search_function = { 'defaults' => {'store' => 'no', 'index' => 'analyzed_no_norms'},
822
+ 'index' => "function(doc) { ret = new Document(); ret.add(doc['name'], {'field':'name'}); ret.add(doc['age'], {'field':'age'}); return ret; }" }
823
+ @db.save_doc({'_id' => '_design/search', 'fulltext' => {'people' => search_function}})
824
+ @db.save_doc({'_id' => 'john', 'name' => 'John', 'age' => '31'})
825
+ @db.save_doc({'_id' => 'jack', 'name' => 'Jack', 'age' => '32'})
826
+ @db.save_doc({'_id' => 'dave', 'name' => 'Dave', 'age' => '33'})
827
+ end
828
+
829
+ it "should be able to search a database using couchdb-lucene" do
830
+ if couchdb_lucene_available?
831
+ result = @db.search('search/people', :q => 'name:J*')
832
+ doc_ids = result['rows'].collect{ |row| row['id'] }
833
+ doc_ids.size.should == 2
834
+ doc_ids.should include('john')
835
+ doc_ids.should include('jack')
836
+ end
837
+ end
838
+ end
772
839
 
773
840
  end