arkenstone-open 3.0.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.
Files changed (45) hide show
  1. checksums.yaml +7 -0
  2. data/.github/workflows/codacy-analysis.yml +46 -0
  3. data/.gitignore +19 -0
  4. data/.rubocop.yml +5 -0
  5. data/.ruby-version +1 -0
  6. data/.travis.yml +16 -0
  7. data/Gemfile +21 -0
  8. data/Gemfile.lock +101 -0
  9. data/LICENSE.txt +11 -0
  10. data/README.md +87 -0
  11. data/Rakefile +36 -0
  12. data/arkenstone.gemspec +27 -0
  13. data/lib/arkenstone/associations/resources.rb +76 -0
  14. data/lib/arkenstone/associations.rb +389 -0
  15. data/lib/arkenstone/document.rb +289 -0
  16. data/lib/arkenstone/enumerable/query_list.rb +20 -0
  17. data/lib/arkenstone/errors/no_url_error.rb +14 -0
  18. data/lib/arkenstone/helpers.rb +18 -0
  19. data/lib/arkenstone/network/env.rb +19 -0
  20. data/lib/arkenstone/network/hook.rb +74 -0
  21. data/lib/arkenstone/network/network.rb +72 -0
  22. data/lib/arkenstone/query_builder.rb +84 -0
  23. data/lib/arkenstone/queryable.rb +38 -0
  24. data/lib/arkenstone/timestamps.rb +25 -0
  25. data/lib/arkenstone/validation/validation_error.rb +34 -0
  26. data/lib/arkenstone/validation/validations.rb +192 -0
  27. data/lib/arkenstone/version.rb +5 -0
  28. data/lib/arkenstone.rb +22 -0
  29. data/test/associations/test_document_overrides.rb +50 -0
  30. data/test/associations/test_has_and_belongs_to_many.rb +80 -0
  31. data/test/dummy/app/models/association.rb +35 -0
  32. data/test/dummy/app/models/superuser.rb +8 -0
  33. data/test/dummy/app/models/user.rb +10 -0
  34. data/test/spec_helper.rb +16 -0
  35. data/test/test_arkenstone.rb +354 -0
  36. data/test/test_arkenstone_hook_inheritance.rb +39 -0
  37. data/test/test_associations.rb +327 -0
  38. data/test/test_enumerables.rb +36 -0
  39. data/test/test_environment.rb +14 -0
  40. data/test/test_helpers.rb +18 -0
  41. data/test/test_hooks.rb +104 -0
  42. data/test/test_query_builder.rb +163 -0
  43. data/test/test_queryable.rb +59 -0
  44. data/test/test_validations.rb +197 -0
  45. metadata +133 -0
@@ -0,0 +1,327 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class AssociationsTest < Test::Unit::TestCase
6
+ def setup
7
+ @model = AssociatedUser.new
8
+ @model.id = 100
9
+ @dummy_things = [{ 'id' => 100, 'name' => 'test' }, { 'id' => 200, 'name' => 'dummy data' }]
10
+
11
+ stub_request(:get, "#{AssociatedUser.arkenstone_url}100/things").to_return do |_req|
12
+ { body: @dummy_things.to_json }
13
+ end
14
+
15
+ stub_request(:get, "#{AssociatedUser.arkenstone_url}100/roles").to_return(body: '')
16
+
17
+ @dummy_resource = { 'id' => 50, 'name' => 'Resource 1' }
18
+ stub_request(:get, "#{AssociatedUser.arkenstone_url}100/resource").to_return do |_req|
19
+ if @dummy_resource.nil?
20
+ { status: 200 }
21
+ else
22
+ { body: @dummy_resource.to_json }
23
+ end
24
+ end
25
+ end
26
+
27
+ def test_associations_dont_clobber_existing_methods
28
+ AssociatedUser.add_association_method 'test_method' do
29
+ 'replaced'
30
+ end
31
+ model = AssociatedUser.new
32
+ assert(model.test_method == 'on AssociatedUser')
33
+ # model = UserWithMethods.new
34
+ # assert(model.things == 'on UserWithMethods')
35
+ end
36
+
37
+ def test_has_many_creates_child_array
38
+ assert(AssociatedUser.method_defined?(:things))
39
+ assert(@model.things.nil? == false)
40
+ assert(@model.things != [])
41
+ assert(@model.things.count == 2)
42
+
43
+ assert(@model.roles == [])
44
+ end
45
+
46
+ def test_has_many_creates_cached_method
47
+ assert(AssociatedUser.method_defined?(:cached_things))
48
+ assert(@model.cached_things.count == 2)
49
+ end
50
+
51
+ def test_has_many_creates_add_child
52
+ stub_request(:post, "#{AssociatedUser.arkenstone_url}100/things").to_return do |_req|
53
+ @dummy_things << { 'id' => 500, 'name' => 'new thing' }
54
+ { status: 200 }
55
+ end
56
+ assert(AssociatedUser.method_defined?(:add_thing))
57
+ new_thing = Thing.new
58
+ new_thing.name = 'new thing'
59
+ new_thing.id = 500
60
+ @model.add_thing new_thing
61
+ assert(@model.cached_things.count == 3)
62
+ end
63
+
64
+ def test_has_many_creates_remove_child
65
+ stub_request(:delete, "#{AssociatedUser.arkenstone_url}100/things/100").to_return do |_req|
66
+ @dummy_things = [{ 'id' => 200, 'name' => 'dummy data' }]
67
+ { status: 200 }
68
+ end
69
+
70
+ assert(AssociatedUser.method_defined?(:remove_thing))
71
+ bad_thing = Thing.new
72
+ bad_thing.id = 100
73
+ @model.remove_thing bad_thing
74
+ assert(@model.cached_things.count == 1)
75
+ assert(@model.cached_things[0].id == 200)
76
+ end
77
+
78
+ def test_has_one_creates_a_cached_object
79
+ assert(AssociatedUser.method_defined?('cached_resource'))
80
+ assert(!@model.cached_resource.nil?)
81
+ end
82
+
83
+ def test_has_one_creates_a_uncached_object
84
+ assert(AssociatedUser.method_defined?('resource'))
85
+ assert(@model.resource.id == 50)
86
+ end
87
+
88
+ def test_has_one_creates_a_setter
89
+ new_values = { id: 75, name: 'new resource' }
90
+ stub_request(:post, "#{AssociatedUser.arkenstone_url}100/resource").to_return(body: '')
91
+
92
+ assert(AssociatedUser.method_defined?('resource='))
93
+ new_resource = Resource.build new_values
94
+ @model.resource = new_resource
95
+ @dummy_resource = new_resource
96
+ assert(@model.resource.id == 75)
97
+ end
98
+
99
+ def test_has_one_can_delete_an_association
100
+ stub_request(:delete, "#{AssociatedUser.arkenstone_url}100/resource/50").to_return(status: 200)
101
+ @model.resource = nil
102
+ @dummy_resource = nil
103
+ assert(@model.resource.nil?)
104
+ end
105
+
106
+ def test_associations_uses_the_same_namespace
107
+ eval %(
108
+ module Foo
109
+ class Bar
110
+ include Arkenstone::Document
111
+ end
112
+
113
+ class MyClass
114
+ include Arkenstone::Document
115
+ url "http://example.com/myclasses/"
116
+
117
+ attributes :id, :name
118
+
119
+ has_many :bars
120
+ end
121
+ end
122
+ )
123
+ stub_request(:get, "#{Foo::MyClass.arkenstone_url}100/bars").to_return(body: '')
124
+ model = Foo::MyClass.new
125
+ model.id = 100
126
+ result = model.bars
127
+ assert(!result.nil?)
128
+ end
129
+
130
+ def test_assoications_handles_405
131
+ eval %(
132
+ module Foo
133
+ class Bar
134
+ include Arkenstone::Document
135
+ end
136
+
137
+ class MyClass
138
+ include Arkenstone::Document
139
+ url "http://example.com/myclasses/"
140
+
141
+ attributes :id, :name
142
+
143
+ has_one :bar
144
+ end
145
+ end
146
+ )
147
+ stub_request(:get, "#{Foo::MyClass.arkenstone_url}100/bar").to_return(status: '405', body: 'ERROR')
148
+ model = Foo::MyClass.new
149
+ model.id = 100
150
+ result = model.bar
151
+ assert(result == [])
152
+ end
153
+
154
+ def test_belongs_to_association
155
+ eval %(
156
+ module Foo
157
+ class Bar
158
+ include Arkenstone::Document
159
+ url 'http://example.com/bar'
160
+
161
+ attributes :id
162
+ belongs_to :freezer
163
+ end
164
+
165
+ class Freezer
166
+ include Arkenstone::Document
167
+ url 'http://example.com/freezer'
168
+
169
+ attributes :id, :age
170
+ has_many :bars
171
+ end
172
+ end
173
+ )
174
+
175
+ stub_request(:post, "#{Foo::Freezer.arkenstone_url}/").to_return(status: '200', body: { id: 1 }.to_json)
176
+ stub_request(:post, "#{Foo::Bar.arkenstone_url}/").to_return(status: '200', body: { id: 1, freezer_id: 1 }.to_json)
177
+
178
+ freezer = Foo::Freezer.create({ age: 30 })
179
+ bar = Foo::Bar.create({ freezer: })
180
+
181
+ stub_request(:get, "#{Foo::Freezer.arkenstone_url}/1").to_return(status: 200, body: freezer.to_json)
182
+
183
+ assert_equal(freezer.id, bar.freezer_id)
184
+ assert_equal(freezer.to_json, bar.freezer.to_json)
185
+ assert_equal(bar.cached_freezer.id, freezer.id)
186
+ end
187
+
188
+ def test_has_and_belongs_to_many
189
+ # Pending Test
190
+
191
+ return true
192
+ eval %(
193
+ module Foo
194
+ class Bar
195
+ include Arkenstone::Document
196
+ url 'http://example.com/bar'
197
+
198
+ attributes :id
199
+ has_and_belongs_to_many :freezers
200
+ end
201
+
202
+ class Freezer
203
+ include Arkenstone::Document
204
+ url 'http://example.com/freezer'
205
+
206
+ attributes :id, :age
207
+ has_and_belongs_to_many :bars
208
+ end
209
+ end
210
+ )
211
+
212
+ stub_request(:post, "#{Foo::Freezer.arkenstone_url}/").to_return(status: '200',
213
+ body: {
214
+ id: 1, bar_ids: []
215
+ }.to_json)
216
+ stub_request(:post, "#{Foo::Bar.arkenstone_url}/").to_return(status: '200',
217
+ body: {
218
+ id: 1, freezer_ids: [1]
219
+ }.to_json)
220
+
221
+ freezer = Foo::Freezer.create({ age: 30 })
222
+ bar = Foo::Bar.create({ freezers: [freezer] })
223
+
224
+ stub_request(:get, "#{Foo::Freezer.arkenstone_url}/1").to_return(status: 200,
225
+ body: freezer.merge({ bar_ids: [bar.id] }).to_json)
226
+ stub_request(:get, "#{Foo::Bar.arkenstone_url}/1").to_return(status: 200,
227
+ body: bar.merge({ freezer_ids: [freezer.id] }).to_json)
228
+
229
+ assert(bar.freezer_ids.include?(freezer.id))
230
+ assert(freezer.bar_ids.include?(bar.id))
231
+
232
+ freezer = Foo::Freezer.find(1)
233
+ bar = Foo::Bar.find(1)
234
+
235
+ assert_equal(1, freezer.bars.length)
236
+ assert_equal(1, bar.freezers.length)
237
+
238
+ found_freezer = bar.freezers.first
239
+ found_bar = freezer.bars.first
240
+
241
+ assert_equal(freezer.to_json, found_freezer.to_json)
242
+ assert_equal(bar.to_json, found_bar.to_json)
243
+ end
244
+
245
+ def test_handles_nested_json
246
+ eval %(
247
+ module Foo
248
+ class Bar
249
+ include Arkenstone::Document
250
+ url 'http://example.com/bar'
251
+
252
+ attributes :id
253
+ belongs_to :freezer
254
+ end
255
+
256
+ class Freezer
257
+ include Arkenstone::Document
258
+ url 'http://example.com/freezer'
259
+
260
+ attributes :id, :age
261
+ has_many :bars
262
+ end
263
+ end
264
+ )
265
+
266
+ stub_request(:post, "#{Foo::Freezer.arkenstone_url}/").to_return(status: '200', body: { id: 1 }.to_json)
267
+ stub_request(:post, "#{Foo::Bar.arkenstone_url}/").to_return(status: '200', body: { id: 1, freezer_id: 1 }.to_json)
268
+
269
+ freezer = Foo::Freezer.create({ age: 30 })
270
+ bar = Foo::Bar.create({ freezer: })
271
+
272
+ stub_request(:get, "#{Foo::Freezer.arkenstone_url}/1").to_return(status: 200,
273
+ body: {
274
+ id: 1, age: 30, bars: [{ id: 1 }]
275
+ }.to_json)
276
+ stub_request(:get, "#{Foo::Freezer.arkenstone_url}/1/bars").to_return(status: 200, body: [{ id: 1 }].to_json)
277
+
278
+ freezer = Foo::Freezer.find(freezer.id)
279
+
280
+ assert(freezer.bars)
281
+ assert(freezer.bar_ids)
282
+ assert(freezer.bar_ids.include?(bar.id))
283
+ end
284
+
285
+ def test_allows_custom_url
286
+ eval %(
287
+ class Tool
288
+ include Arkenstone::Document
289
+ attributes :name
290
+ url 'http://example.com/tools'
291
+ end
292
+
293
+ class Garage
294
+ include Arkenstone::Document
295
+ attributes :address
296
+ url 'http://example.com/garages'
297
+
298
+ has_many :tools, model_name: 'derps'
299
+ end
300
+ )
301
+ stub_request(:get,
302
+ "#{Garage.arkenstone_url}/10/derps").to_return(body: [{ name: 'test' }, { name: 'other' }].to_json)
303
+ g = Garage.new
304
+ g.id = 10
305
+ tools = g.tools
306
+ assert_equal(2, tools.count)
307
+ end
308
+
309
+ def test_has_many_custom_class
310
+ eval %(
311
+ class Organization
312
+ include Arkenstone::Document
313
+ attributes :name
314
+ url 'http://example.com/organizations'
315
+
316
+ has_many :child_organizations, class_name: :organization, model_name: 'descendents'
317
+ end
318
+ )
319
+ url = "#{Organization.arkenstone_url}/10/descendents"
320
+ children = [{ name: 'child 1' }, { name: 'child 2' }]
321
+ stub_request(:get, url).to_return(body: children.to_json)
322
+ parent = Organization.new
323
+ parent.id = 10
324
+ child_orgs = parent.child_organizations
325
+ assert_equal(2, child_orgs.count)
326
+ end
327
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class EnumerableTests < Test::Unit::TestCase
6
+ def test_json_returns_attributes_of_elements
7
+ eval %(
8
+ class EnumerableElement
9
+ include Arkenstone::Document
10
+
11
+ attributes :name, :id
12
+ end
13
+ )
14
+ dummy = EnumerableElement.new
15
+ dummy.name = 'test'
16
+ dummy.id = 100
17
+
18
+ dummy2 = EnumerableElement.new
19
+ dummy2.name = 'test2'
20
+ dummy2.id = 101
21
+
22
+ list = Arkenstone::QueryList.new [dummy, dummy2]
23
+ result = list.to_json
24
+ assert_equal(result, '[{"name":"test","id":100},{"name":"test2","id":101}]')
25
+ end
26
+
27
+ def test_initialize_takes_array
28
+ list = Arkenstone::QueryList.new [10, 20]
29
+ assert_equal([10, 20], list)
30
+ end
31
+
32
+ def test_initialize_takes_element
33
+ list = Arkenstone::QueryList.new 'test'
34
+ assert_equal ['test'], list
35
+ end
36
+ end
@@ -0,0 +1,14 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class ArkenstoneEnvTest < Test::Unit::TestCase
6
+ def setup
7
+ @env = Arkenstone::Environment.new url: 'http://example.com', verb: :get
8
+ end
9
+
10
+ def test_env_takes_hash_to_init
11
+ assert(@env.url == 'http://example.com')
12
+ assert(@env.verb == :get)
13
+ end
14
+ end
@@ -0,0 +1,18 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class HelpersTest < Test::Unit::TestCase
6
+ def test_full_url
7
+ eval %(
8
+ class FooTest
9
+ include Arkenstone::Document
10
+ include Arkenstone::Helpers
11
+
12
+ url 'http://example.com'
13
+ end
14
+ )
15
+
16
+ assert_equal('http://example.com/', FooTest.full_url(FooTest.arkenstone_url))
17
+ end
18
+ end
@@ -0,0 +1,104 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class RequestHook < Arkenstone::Hook
6
+ attr_accessor :called
7
+
8
+ def before_request(_req)
9
+ @called = true
10
+ end
11
+ end
12
+
13
+ class ResponseHook < Arkenstone::Hook
14
+ attr_accessor :called
15
+
16
+ def after_complete(_resp)
17
+ @called = true
18
+ end
19
+ end
20
+
21
+ class ArkenstoneHookTest < Test::Unit::TestCase
22
+ def test_hook_called_before_request
23
+ request_hook = RequestHook.new
24
+ User.add_hook request_hook
25
+ assert(User.arkenstone_hooks.count == 1)
26
+ stub_request(:get, "#{User.arkenstone_url}1").to_return(body: '{}')
27
+ User.find(1)
28
+ assert(request_hook.called, 'hook was not called')
29
+ end
30
+
31
+ def test_hook_called_after_complete
32
+ resp_hook = ResponseHook.new
33
+ User.add_hook resp_hook
34
+ stub_request(:get, "#{User.arkenstone_url}1").to_return(body: '{}')
35
+ User.find(1)
36
+ assert(resp_hook.called, 'response hook was not called')
37
+ end
38
+
39
+ def test_has_hooks
40
+ eval %(
41
+ class BaseThing
42
+ include Arkenstone::Document
43
+ add_hook RequestHook.new
44
+ end
45
+ )
46
+ assert_equal(true, Arkenstone::Hook.has_hooks?(BaseThing))
47
+ end
48
+
49
+ def test_has_hooks_via_inheritance
50
+ eval %(
51
+ class BaseThing
52
+ include Arkenstone::Document
53
+ add_hook RequestHook.new
54
+ end
55
+
56
+ class ChildThing < BaseThing
57
+ inherit_hooks
58
+ end
59
+
60
+ )
61
+ assert_equal(true, Arkenstone::Hook.has_hooks?(ChildThing))
62
+ end
63
+
64
+ def test_has_hooks_negative
65
+ eval %(
66
+ class NoHooks
67
+ end
68
+ )
69
+ assert_equal(false, Arkenstone::Hook.has_hooks?(NoHooks))
70
+ end
71
+
72
+ def test_all_hooks_for_class_verifies_inherit_hooks
73
+ eval %(
74
+ class BaseThing
75
+ include Arkenstone::Document
76
+ add_hook ResponseHook.new
77
+ end
78
+
79
+ class ChildThing < BaseThing
80
+ add_hook RequestHook.new
81
+ end
82
+ )
83
+ assert_equal(1, Arkenstone::Hook.all_hooks_for_class(ChildThing).count)
84
+ end
85
+
86
+ def test_all_hooks_for_class_walks_the_inheritance_chain
87
+ eval %(
88
+ class BaseBaseThing
89
+ include Arkenstone::Document
90
+ add_hook ResponseHook.new
91
+ end
92
+
93
+ class DerpChildThing < BaseBaseThing
94
+ add_hook RequestHook.new
95
+ inherit_hooks
96
+ end
97
+ )
98
+ assert_equal(2, Arkenstone::Hook.all_hooks_for_class(DerpChildThing).count)
99
+ end
100
+
101
+ def teardown
102
+ User.arkenstone_hooks = []
103
+ end
104
+ end
@@ -0,0 +1,163 @@
1
+ # frozen_string_literal: true
2
+
3
+ require 'spec_helper'
4
+
5
+ class QueryBuilderTest < Test::Unit::TestCase
6
+ def setup
7
+ @builder = Arkenstone::QueryBuilder.new
8
+ end
9
+
10
+ def test_build_find_with_one_param
11
+ json = @builder.build do
12
+ {
13
+ foo: 'foo'
14
+ }
15
+ end
16
+
17
+ assert_equal '{"foo":"foo"}', json
18
+ end
19
+
20
+ def test_build_find_in
21
+ json = @builder.build do
22
+ {
23
+ foo: _in(%w[foo bar])
24
+ }
25
+ end
26
+ assert_equal '{"foo":{"$in":["foo","bar"]}}', json
27
+ end
28
+
29
+ def test_query_find_comparison
30
+ json = @builder.build do
31
+ {
32
+ foo: _gt(500)
33
+ }
34
+ end
35
+ assert_equal '{"foo":{"$gt":500}}', json
36
+ end
37
+
38
+ def test_query_complex_find
39
+ json = @builder.build do
40
+ {
41
+ foo: 'foo',
42
+ bar: _in(%w[foo bar]),
43
+ baz: _gt(400)
44
+ }
45
+ end
46
+ assert_equal '{"foo":"foo","bar":{"$in":["foo","bar"]},"baz":{"$gt":400}}', json
47
+ end
48
+
49
+ def test_query_and
50
+ json = @builder.build do
51
+ _and(
52
+ { foo: 'foo' },
53
+ { bar: 'bar' }
54
+ )
55
+ end
56
+ assert_equal '{"$and":[{"foo":"foo"},{"bar":"bar"}]}', json
57
+ end
58
+
59
+ def test_query_and_with_gt
60
+ json = @builder.build do
61
+ _and(
62
+ { foo: _gt(200) },
63
+ { foo: _lt(300) }
64
+ )
65
+ end
66
+ assert_equal '{"$and":[{"foo":{"$gt":200}},{"foo":{"$lt":300}}]}', json
67
+ end
68
+
69
+ def test_include
70
+ json = @builder.build do
71
+ _include %w[Foo Bar]
72
+ {
73
+ foo: 'foo'
74
+ }
75
+ end
76
+ assert_equal '{"$include":["Foo","Bar"],"foo":"foo"}', json
77
+ end
78
+
79
+ def test_limit
80
+ json = @builder.build do
81
+ _limit 5
82
+ {
83
+ foo: 'foo'
84
+ }
85
+ end
86
+ assert_equal '{"$limit":5,"foo":"foo"}', json
87
+ end
88
+
89
+ def test_complex_include_with_booleans
90
+ json = @builder.build do
91
+ _include %w[DocDataElement Document]
92
+ _or(
93
+ _and(
94
+ { 'DocDataElement.Name' => 'AccountNumber' },
95
+ { 'Value' => '123456' }
96
+ ),
97
+ _and(
98
+ { 'DocDataElement.Name' => 'Zip' },
99
+ { 'Value' => '55555' }
100
+ )
101
+ )
102
+ end
103
+ assert_equal '{"$include":["DocDataElement","Document"],"$or":[{"$and":[{"DocDataElement.Name":"AccountNumber"},{"Value":"123456"}]},{"$and":[{"DocDataElement.Name":"Zip"},{"Value":"55555"}]}]}',
104
+ json
105
+ end
106
+
107
+ def test_query_not
108
+ json = @builder.build do
109
+ _or(
110
+ _and(
111
+ { foo: _gt(200) },
112
+ { bar: 'bar' }
113
+ ),
114
+ _not(
115
+ { baz: 'derp' }
116
+ )
117
+ )
118
+ end
119
+ assert_equal '{"$or":[{"$and":[{"foo":{"$gt":200}},{"bar":"bar"}]},{"$not":[{"baz":"derp"}]}]}', json
120
+ end
121
+
122
+ def test_query_or
123
+ json = @builder.build do
124
+ _or(
125
+ { foo: _gt(200) },
126
+ { bar: 'bar' }
127
+ )
128
+ end
129
+ assert_equal '{"$or":[{"foo":{"$gt":200}},{"bar":"bar"}]}', json
130
+ end
131
+
132
+ def test_query_complex_and
133
+ json = @builder.build do
134
+ _or(
135
+ _and(
136
+ { foo: _gt(200) },
137
+ { bar: 'bar' }
138
+ ),
139
+ _and(
140
+ { derp: 'derp' }
141
+ )
142
+ )
143
+ end
144
+ assert_equal '{"$or":[{"$and":[{"foo":{"$gt":200}},{"bar":"bar"}]},{"$and":[{"derp":"derp"}]}]}', json
145
+ end
146
+
147
+ def test_query_is_idempotent
148
+ json = @builder.build do
149
+ _and(
150
+ { foo: _gt(200) },
151
+ { bar: 'bar' }
152
+ )
153
+ end
154
+ assert_equal '{"$and":[{"foo":{"$gt":200}},{"bar":"bar"}]}', json
155
+ json = @builder.build do
156
+ _and(
157
+ { foo: _gt(200) },
158
+ { derp: 'derp derp' }
159
+ )
160
+ end
161
+ assert_equal '{"$and":[{"foo":{"$gt":200}},{"derp":"derp derp"}]}', json
162
+ end
163
+ end