dolly 3.0.0 → 3.1.2

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.
@@ -0,0 +1,273 @@
1
+ require 'test_helper'
2
+
3
+ class FooBar < BaseDolly
4
+ property :foo, :bar
5
+ property :with_default, default: 1
6
+ property :boolean, class_name: TrueClass, default: true
7
+ property :date, class_name: Date
8
+ property :time, class_name: Time
9
+ property :datetime, class_name: DateTime
10
+ property :is_nil, class_name: NilClass, default: nil
11
+
12
+ timestamps!
13
+ end
14
+
15
+ class FooBarTyped < BaseDolly
16
+ typed_model
17
+ end
18
+
19
+ class MangoTest < Test::Unit::TestCase
20
+ DB_BASE_PATH = "http://localhost:5984/test".freeze
21
+
22
+ def setup
23
+ data = {foo: 'Foo', bar: 'Bar', type: 'foo_bar'}
24
+
25
+ all_docs = [ {foo: 'Foo B', bar: 'Bar B', type: 'foo_bar'}, {foo: 'Foo A', bar: 'Bar A', type: 'foo_bar'}]
26
+
27
+ view_resp = build_view_response [data]
28
+ empty_resp = build_view_response []
29
+ not_found_resp = generic_response [{ key: "foo_bar/2", error: "not_found" }]
30
+ @multi_resp = build_view_response all_docs
31
+ @multi_type_resp = build_view_collation_response all_docs
32
+
33
+ build_request [["foo_bar","1"]], view_resp
34
+ build_request [["foo_bar","2"]], empty_resp
35
+ build_request [["foo_bar","1"],["foo_bar","2"]], @multi_resp
36
+
37
+ stub_request(:get, "#{query_base_path}?startkey=%22foo_bar%2F%22&endkey=%22foo_bar%2F%EF%BF%B0%22&include_docs=true").
38
+ to_return(body: @multi_resp.to_json)
39
+
40
+ stub_request(:get, "#{all_docs_path}?key=\"index_foo\"").
41
+ to_return(body: {
42
+ total_rows: 2,
43
+ offset: 0,
44
+ rows: [{
45
+ id: '_design/index_foo',
46
+ key: '_design/index_foo',
47
+ value: { rev: '1-c5457a0d26da85f15c4ad6bd739e441d' }
48
+ }]}.to_json)
49
+
50
+ stub_request(:get, "#{all_docs_path}?key=\"index_date\"").
51
+ to_return(body: {
52
+ total_rows: 2,
53
+ offset: 0,
54
+ rows: []}.to_json)
55
+ end
56
+
57
+ test '#find_by' do
58
+ #TODO: clean up all the fake request creation
59
+ resp = { docs: [{ foo: 'bar', id: "foo_bar/1"} ] }
60
+
61
+ stub_request(:post, query_base_path).
62
+ to_return(body: resp.to_json)
63
+
64
+ key = 'foo'
65
+ stub_request(:get, "#{all_docs_path}?key=\"_design/index_#{key}\"").
66
+ to_return(body: index_response(key).to_json)
67
+
68
+ assert_equal(FooBar.find_by(foo: 'bar').class, FooBar)
69
+ end
70
+
71
+ test '#find_by for a property that does not have an index' do
72
+ #TODO: clean up all the fake request creation
73
+ resp = { docs: [{ foo: 'bar', id: "foo_bar/1"} ] }
74
+ key = 'date'
75
+
76
+ stub_request(:post, query_base_path).
77
+ to_return(body: resp.to_json)
78
+
79
+ stub_request(:get, "#{all_docs_path}?key=\"_design/index_#{key}\"").
80
+ to_return(body: { rows: [] }.to_json)
81
+
82
+ assert_raise Dolly::IndexNotFoundError do
83
+ FooBar.find_by(date: Date.today)
84
+ end
85
+ end
86
+
87
+ test '#find_by with no returned data' do
88
+ resp = { docs: [] }
89
+
90
+ stub_request(:post, query_base_path).
91
+ to_return(body: resp.to_json)
92
+
93
+ key = 'foo'
94
+ stub_request(:get, "#{all_docs_path}?key=\"_design/index_#{key}\"").
95
+ to_return(body: index_response(key).to_json)
96
+
97
+ assert_equal(FooBar.find_by(foo: 'bar'), nil)
98
+ end
99
+
100
+ test '#find_doc_by' do
101
+ #TODO: clean up all the fake request creation
102
+ resp = { docs: [{ foo: 'bar', id: "foo_bar/1"} ] }
103
+
104
+ stub_request(:post, query_base_path).
105
+ to_return(body: resp.to_json)
106
+
107
+ key = 'foo'
108
+ stub_request(:get, "#{all_docs_path}?key=\"_design/index_#{key}\"").
109
+ to_return(body: index_response(key).to_json)
110
+
111
+ assert_equal(FooBar.find_doc_by(foo: 'bar').class, Hash)
112
+ end
113
+
114
+ test '#where' do
115
+ #TODO: clean up all the fake request creation
116
+ resp = { docs: [{ foo: 'bar', id: "foo_bar/1"} ] }
117
+
118
+ stub_request(:post, query_base_path).
119
+ to_return(body: resp.to_json)
120
+
121
+ key = 'foo'
122
+ stub_request(:get, "#{all_docs_path}?key=\"_design/index_#{key}\"").
123
+ to_return(body: index_response(key).to_json)
124
+
125
+ assert_equal(FooBar.where(foo: { eq: 'bar' }).map(&:class).uniq, [FooBar])
126
+ end
127
+
128
+ test '#where for a property that does not have an index' do
129
+ #TODO: clean up all the fake request creation
130
+ resp = { docs: [{ foo: 'bar', id: "foo_bar/1"} ] }
131
+
132
+ stub_request(:post, query_base_path).
133
+ to_return(body: resp.to_json)
134
+
135
+ key = 'date'
136
+ stub_request(:get, "#{all_docs_path}?key=\"_design/index_#{key}\"").
137
+ to_return(body: { rows: [] }.to_json)
138
+
139
+ assert_raise Dolly::IndexNotFoundError do
140
+ FooBar.where(date: Date.today)
141
+ end
142
+ end
143
+
144
+ test '#where with no returned data' do
145
+ resp = { docs: [] }
146
+
147
+ stub_request(:post, query_base_path).
148
+ to_return(body: resp.to_json)
149
+
150
+ key = 'foo'
151
+ stub_request(:get, "#{all_docs_path}?key=\"_design/index_#{key}\"").
152
+ to_return(body: index_response(key).to_json)
153
+
154
+ assert_equal(FooBar.where(foo: 'bar'), [])
155
+ end
156
+
157
+ test '#docs_where' do
158
+ #TODO: clean up all the fake request creation
159
+ resp = { docs: [{ foo: 'bar', id: "foo_bar/1"} ] }
160
+
161
+ stub_request(:post, query_base_path).
162
+ to_return(body: resp.to_json)
163
+
164
+ key = 'foo'
165
+ stub_request(:get, "#{all_docs_path}?key=\"_design/index_#{key}\"").
166
+ to_return(body: index_response(key).to_json)
167
+
168
+ assert_equal(FooBar.docs_where(foo: { eq: 'bar' }).map(&:class).uniq, [Hash])
169
+ end
170
+
171
+ test '#build_query' do
172
+ query = { and: [{ _id: { eq: 'foo_bar/1' } } , { foo: { eq: 'bar'}} ] }
173
+ opts = {}
174
+ expected = {"selector"=>{"$and"=>[{:_id=>{"$eq"=>"foo_bar/1"}}, {:foo=>{"$eq"=>"bar"}}]}}
175
+
176
+ assert_equal(FooBar.send(:build_query, query, opts), expected)
177
+ end
178
+
179
+ test '#build_query with options' do
180
+ query = { and: [{ _id: { eq: 'foo_bar/1' } } , { foo: { eq: 'bar'}} ] }
181
+ opts = { limit: 1, fields: ['foo']}
182
+ expected = {"selector"=>{"$and"=>[{:_id=>{"$eq"=>"foo_bar/1"}}, {:foo=>{"$eq"=>"bar"}}]}, limit: 1, fields: ['foo']}
183
+
184
+ assert_equal(FooBar.send(:build_query, query, opts), expected)
185
+ end
186
+
187
+ test '#build_selectors with invalid operator' do
188
+ query = { _id: { eeeq: 'foo_bar/1' } }
189
+
190
+ assert_raise Dolly::InvalidMangoOperatorError do
191
+ FooBar.send(:build_selectors, query)
192
+ end
193
+ end
194
+
195
+ test '#build_selectors with type operator' do
196
+ query = { _id: { type: "user" } }
197
+
198
+ assert_nothing_raised Dolly::InvalidMangoOperatorError do
199
+ FooBarTyped.send(:build_selectors, query)
200
+ end
201
+ end
202
+
203
+ test '#build_selectors with $type operator' do
204
+ query = { _id: { "$type" => "null" } }
205
+
206
+ assert_nothing_raised Dolly::InvalidMangoOperatorError do
207
+ FooBarTyped.send(:build_selectors, query)
208
+ end
209
+ end
210
+
211
+ private
212
+
213
+ def generic_response rows, count = 1
214
+ {total_rows: count, offset:0, rows: rows}
215
+ end
216
+
217
+ def build_view_response properties
218
+ rows = properties.map.with_index do |v, i|
219
+ {
220
+ id: "foo_bar/#{i}",
221
+ key: "foo_bar",
222
+ value: 1,
223
+ doc: {_id: "foo_bar/#{i}", _rev: SecureRandom.hex}.merge!(v)
224
+ }
225
+ end
226
+ generic_response rows, properties.count
227
+ end
228
+
229
+ def build_view_collation_response properties
230
+ rows = properties.map.with_index do |v, i|
231
+ id = i.zero? ? "foo_bar/#{i}" : "baz/#{i}"
232
+ {
233
+ id: id,
234
+ key: "foo_bar",
235
+ value: 1,
236
+ doc: {_id: id, _rev: SecureRandom.hex}.merge!(v)
237
+ }
238
+ end
239
+ generic_response rows, properties.count
240
+ end
241
+
242
+
243
+ def build_request keys, body, view_name = 'foo_bar'
244
+ query = "keys=#{CGI::escape keys.to_s.gsub(' ','')}&" unless keys&.empty?
245
+ stub_request(:get, "#{query_base_path}?#{query.to_s}include_docs=true").
246
+ to_return(body: body.to_json)
247
+ end
248
+
249
+ def query_base_path
250
+ "#{DB_BASE_PATH}/_find"
251
+ end
252
+
253
+ def all_docs_path
254
+ "#{DB_BASE_PATH}/_all_docs"
255
+ end
256
+
257
+ def build_save_request(obj)
258
+ stub_request(:put, "#{DB_BASE_PATH}/#{CGI.escape(obj.id)}").
259
+ to_return(body: {ok: true, id: obj.id, rev: "FF0000" }.to_json)
260
+ end
261
+
262
+ def index_response(key)
263
+ {
264
+ rows: [
265
+ {
266
+ id: "_design/index_#{key}",
267
+ key: "_design/index_#{key}",
268
+ value: { rev: '1-c5457a0d26da85f15c4ad6bd739e441d' }
269
+ }
270
+ ]
271
+ }
272
+ end
273
+ end
@@ -0,0 +1,18 @@
1
+ require 'test_helper'
2
+
3
+ class TestDoc < Dolly::Document
4
+ property :name, class_name: String
5
+ property :email, class_name: String
6
+ property :last_name, class_name: String
7
+ end
8
+
9
+ class PropertyManagerTest < Test::Unit::TestCase
10
+ test 'write_attribute with nil value' do
11
+ doc = TestDoc.new(name: 'name', last_name: nil, email: 'does not change')
12
+ assert_equal(doc.name, 'name')
13
+ doc.update_properties(name: nil)
14
+ assert_equal(doc.name, nil)
15
+ assert_equal(doc.last_name, nil)
16
+ assert_equal(doc.email, 'does not change')
17
+ end
18
+ end
data/test/test_helper.rb CHANGED
@@ -13,6 +13,7 @@ Dir["#{File.dirname(__FILE__)}/support/**/*.rb"].each { |f| require f }
13
13
 
14
14
  class Test::Unit::TestCase
15
15
  DEFAULT_DB = 'test'
16
+ DB_BASE_PATH = "http://localhost:5984/test".freeze
16
17
 
17
18
  setup :global_setup
18
19
 
@@ -28,4 +29,54 @@ class Test::Unit::TestCase
28
29
  def base_path
29
30
  %r{http://.*:5984/#{DEFAULT_DB}}
30
31
  end
32
+
33
+ def generic_response rows, count = 1
34
+ {total_rows: count, offset:0, rows: rows}
35
+ end
36
+
37
+ def build_view_response properties
38
+ rows = properties.map.with_index do |v, i|
39
+ {
40
+ id: "foo_bar/#{i}",
41
+ key: "foo_bar",
42
+ value: 1,
43
+ doc: {_id: "foo_bar/#{i}", _rev: SecureRandom.hex}.merge!(v)
44
+ }
45
+ end
46
+ generic_response rows, properties.count
47
+ end
48
+
49
+ def build_view_collation_response properties
50
+ rows = properties.map.with_index do |v, i|
51
+ id = i.zero? ? "foo_bar/#{i}" : "baz/#{i}"
52
+ {
53
+ id: id,
54
+ key: "foo_bar",
55
+ value: 1,
56
+ doc_type: id.split("/").first,
57
+ doc: {
58
+ _id: id, _rev: SecureRandom.hex
59
+ }.merge!(v)
60
+ }
61
+ end
62
+ generic_response rows, properties.count
63
+ end
64
+
65
+
66
+ def build_request keys, body, view_name = 'foo_bar'
67
+ query = "keys=#{CGI::escape keys.to_s.gsub(' ','')}&" unless keys&.empty?
68
+ stub_request(:get, "#{query_base_path}?#{query.to_s}include_docs=true").
69
+ to_return(body: body.to_json)
70
+ end
71
+
72
+ def query_base_path
73
+ "#{DB_BASE_PATH}/_all_docs"
74
+ end
75
+
76
+ def build_save_request(obj)
77
+ stub_request(:put, "#{DB_BASE_PATH}/#{CGI.escape(obj.id)}").
78
+ to_return(body: {ok: true, id: obj.id, rev: "FF0000" }.to_json)
79
+ end
31
80
  end
81
+
82
+ class BaseDolly < Dolly::Document; end
@@ -0,0 +1,27 @@
1
+ require 'test_helper'
2
+
3
+ class Foo < Dolly::Document
4
+ end
5
+
6
+ class ViewQueryTest < Test::Unit::TestCase
7
+
8
+ def setup
9
+ all_docs = [ {foo: 'Foo B', bar: 'Bar B', type: 'foo_bar'}, {foo: 'Foo A', bar: 'Bar A', type: 'foo_bar'}]
10
+ @multi_type_resp = build_view_collation_response all_docs
11
+
12
+ stub_request(:get, "http://localhost:5984/test/_design/doc/_view/id?include_docs=true").
13
+ to_return(body: @multi_type_resp.to_json)
14
+
15
+ end
16
+
17
+ test 'raw_view' do
18
+ assert_equal(Foo.raw_view('doc', 'id'), @multi_type_resp)
19
+ assert_equal(Foo.raw_view('doc', 'id')[:rows].any?, true)
20
+ assert_equal(Foo.raw_view('doc', 'id')[:total_rows].nil?, false)
21
+ end
22
+
23
+ test 'view_value' do
24
+ expected = @multi_type_resp[:rows].flat_map{|res| res[:value]}
25
+ assert_equal(Foo.view_value('doc', 'id'), expected)
26
+ end
27
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: dolly
3
3
  version: !ruby/object:Gem::Version
4
- version: 3.0.0
4
+ version: 3.1.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - javierg
8
- autorequire:
8
+ autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2019-06-20 00:00:00.000000000 Z
11
+ date: 2021-10-08 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: oj
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - ">="
25
25
  - !ruby/object:Gem::Version
26
26
  version: '0'
27
+ - !ruby/object:Gem::Dependency
28
+ name: curb
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - '='
32
+ - !ruby/object:Gem::Version
33
+ version: 0.9.8
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - '='
39
+ - !ruby/object:Gem::Version
40
+ version: 0.9.8
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -44,14 +58,14 @@ dependencies:
44
58
  requirements:
45
59
  - - "~>"
46
60
  - !ruby/object:Gem::Version
47
- version: '10.0'
61
+ version: '13.0'
48
62
  type: :development
49
63
  prerelease: false
50
64
  version_requirements: !ruby/object:Gem::Requirement
51
65
  requirements:
52
66
  - - "~>"
53
67
  - !ruby/object:Gem::Version
54
- version: '10.0'
68
+ version: '13.0'
55
69
  - !ruby/object:Gem::Dependency
56
70
  name: test-unit-full
57
71
  requirement: !ruby/object:Gem::Requirement
@@ -115,7 +129,10 @@ files:
115
129
  - lib/dolly/document_state.rb
116
130
  - lib/dolly/document_type.rb
117
131
  - lib/dolly/exceptions.rb
132
+ - lib/dolly/framework_helper.rb
118
133
  - lib/dolly/identity_properties.rb
134
+ - lib/dolly/mango.rb
135
+ - lib/dolly/mango_index.rb
119
136
  - lib/dolly/properties.rb
120
137
  - lib/dolly/property.rb
121
138
  - lib/dolly/property_manager.rb
@@ -126,19 +143,27 @@ files:
126
143
  - lib/dolly/request_header.rb
127
144
  - lib/dolly/timestamp.rb
128
145
  - lib/dolly/version.rb
146
+ - lib/dolly/view_query.rb
129
147
  - lib/railties/railtie.rb
148
+ - lib/refinements/hash_refinements.rb
130
149
  - lib/refinements/string_refinements.rb
131
150
  - lib/tasks/db.rake
132
151
  - test/bulk_document_test.rb
133
152
  - test/document_test.rb
153
+ - test/document_type_test.rb
134
154
  - test/dummy/config/initializers/filter_parameter_logging.rb
135
155
  - test/dummy/log/test.log
156
+ - test/inheritance_test.rb
157
+ - test/mango_index_test.rb
158
+ - test/mango_test.rb
159
+ - test/property_manager_test.rb
136
160
  - test/support/test.txt
137
161
  - test/test_helper.rb
162
+ - test/view_query_test.rb
138
163
  homepage: https://www.amco.me
139
164
  licenses: []
140
165
  metadata: {}
141
- post_install_message:
166
+ post_install_message:
142
167
  rdoc_options: []
143
168
  require_paths:
144
169
  - lib
@@ -153,15 +178,20 @@ required_rubygems_version: !ruby/object:Gem::Requirement
153
178
  - !ruby/object:Gem::Version
154
179
  version: '0'
155
180
  requirements: []
156
- rubyforge_project:
157
- rubygems_version: 2.6.13
158
- signing_key:
181
+ rubygems_version: 3.0.3
182
+ signing_key:
159
183
  specification_version: 4
160
184
  summary: will write something
161
185
  test_files:
162
186
  - test/dummy/config/initializers/filter_parameter_logging.rb
163
187
  - test/dummy/log/test.log
188
+ - test/inheritance_test.rb
189
+ - test/document_type_test.rb
190
+ - test/mango_index_test.rb
164
191
  - test/bulk_document_test.rb
192
+ - test/view_query_test.rb
193
+ - test/mango_test.rb
165
194
  - test/support/test.txt
166
195
  - test/test_helper.rb
167
196
  - test/document_test.rb
197
+ - test/property_manager_test.rb