couchbase-orm 1.1.1 → 2.0.0
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.
- checksums.yaml +4 -4
- data/.github/workflows/test.yml +45 -0
- data/.gitignore +2 -0
- data/.travis.yml +3 -2
- data/CODEOWNERS +1 -0
- data/Gemfile +5 -3
- data/README.md +237 -31
- data/ci/run_couchbase.sh +22 -0
- data/couchbase-orm.gemspec +26 -20
- data/lib/couchbase-orm/active_record_compat.rb +92 -0
- data/lib/couchbase-orm/associations.rb +119 -0
- data/lib/couchbase-orm/base.rb +143 -166
- data/lib/couchbase-orm/changeable.rb +512 -0
- data/lib/couchbase-orm/connection.rb +28 -8
- data/lib/couchbase-orm/encrypt.rb +48 -0
- data/lib/couchbase-orm/error.rb +17 -2
- data/lib/couchbase-orm/inspectable.rb +37 -0
- data/lib/couchbase-orm/json_schema/json_validation_error.rb +13 -0
- data/lib/couchbase-orm/json_schema/loader.rb +47 -0
- data/lib/couchbase-orm/json_schema/validation.rb +18 -0
- data/lib/couchbase-orm/json_schema/validator.rb +45 -0
- data/lib/couchbase-orm/json_schema.rb +9 -0
- data/lib/couchbase-orm/json_transcoder.rb +27 -0
- data/lib/couchbase-orm/locale/en.yml +5 -0
- data/lib/couchbase-orm/n1ql.rb +133 -0
- data/lib/couchbase-orm/persistence.rb +61 -52
- data/lib/couchbase-orm/proxies/bucket_proxy.rb +36 -0
- data/lib/couchbase-orm/proxies/collection_proxy.rb +52 -0
- data/lib/couchbase-orm/proxies/n1ql_proxy.rb +40 -0
- data/lib/couchbase-orm/proxies/results_proxy.rb +23 -0
- data/lib/couchbase-orm/railtie.rb +6 -17
- data/lib/couchbase-orm/relation.rb +249 -0
- data/lib/couchbase-orm/strict_loading.rb +21 -0
- data/lib/couchbase-orm/timestamps/created.rb +20 -0
- data/lib/couchbase-orm/timestamps/updated.rb +21 -0
- data/lib/couchbase-orm/timestamps.rb +15 -0
- data/lib/couchbase-orm/types/array.rb +32 -0
- data/lib/couchbase-orm/types/date.rb +9 -0
- data/lib/couchbase-orm/types/date_time.rb +14 -0
- data/lib/couchbase-orm/types/encrypted.rb +17 -0
- data/lib/couchbase-orm/types/nested.rb +43 -0
- data/lib/couchbase-orm/types/timestamp.rb +18 -0
- data/lib/couchbase-orm/types.rb +20 -0
- data/lib/couchbase-orm/utilities/enum.rb +13 -1
- data/lib/couchbase-orm/utilities/has_many.rb +72 -36
- data/lib/couchbase-orm/utilities/ignored_properties.rb +15 -0
- data/lib/couchbase-orm/utilities/index.rb +18 -20
- data/lib/couchbase-orm/utilities/properties_always_exists_in_document.rb +16 -0
- data/lib/couchbase-orm/utilities/query_helper.rb +148 -0
- data/lib/couchbase-orm/utils.rb +25 -0
- data/lib/couchbase-orm/version.rb +1 -1
- data/lib/couchbase-orm/views.rb +38 -41
- data/lib/couchbase-orm.rb +44 -9
- data/lib/ext/query_n1ql.rb +124 -0
- data/lib/rails/generators/couchbase_orm/config/templates/couchbase.yml +3 -2
- data/spec/associations_spec.rb +219 -50
- data/spec/base_spec.rb +296 -14
- data/spec/collection_proxy_spec.rb +29 -0
- data/spec/connection_spec.rb +27 -0
- data/spec/couchbase-orm/active_record_compat_spec.rb +24 -0
- data/spec/couchbase-orm/changeable_spec.rb +16 -0
- data/spec/couchbase-orm/json_schema/validation_spec.rb +23 -0
- data/spec/couchbase-orm/json_schema/validator_spec.rb +13 -0
- data/spec/couchbase-orm/timestamps_spec.rb +85 -0
- data/spec/couchbase-orm/timestamps_spec_models.rb +36 -0
- data/spec/empty-json-schema/.gitkeep +0 -0
- data/spec/enum_spec.rb +34 -0
- data/spec/has_many_spec.rb +101 -54
- data/spec/index_spec.rb +13 -9
- data/spec/json-schema/JsonSchemaBaseTest.json +19 -0
- data/spec/json-schema/entity_snakecase.json +20 -0
- data/spec/json-schema/loader_spec.rb +42 -0
- data/spec/json-schema/specific_path.json +20 -0
- data/spec/json_schema_spec.rb +178 -0
- data/spec/n1ql_spec.rb +193 -0
- data/spec/persistence_spec.rb +49 -9
- data/spec/relation_nested_spec.rb +88 -0
- data/spec/relation_spec.rb +430 -0
- data/spec/support.rb +16 -8
- data/spec/type_array_spec.rb +52 -0
- data/spec/type_encrypted_spec.rb +114 -0
- data/spec/type_nested_spec.rb +191 -0
- data/spec/type_spec.rb +317 -0
- data/spec/utilities/ignored_properties_spec.rb +20 -0
- data/spec/utilities/properties_always_exists_in_document_spec.rb +24 -0
- data/spec/views_spec.rb +32 -11
- metadata +192 -29
@@ -0,0 +1,124 @@
|
|
1
|
+
# frozen_string_literal: true, encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
module MTLibcouchbase
|
4
|
+
class QueryN1QL
|
5
|
+
N1P_QUERY_STATEMENT = 1
|
6
|
+
N1P_CONSISTENCY_REQUEST = 2
|
7
|
+
|
8
|
+
def initialize(connection, reactor, n1ql, **_opts)
|
9
|
+
@connection = connection
|
10
|
+
@reactor = reactor
|
11
|
+
|
12
|
+
@n1ql = n1ql
|
13
|
+
@request_handle = FFI::MemoryPointer.new :pointer, 1
|
14
|
+
end
|
15
|
+
|
16
|
+
attr_reader :connection, :n1ql
|
17
|
+
|
18
|
+
def get_count(metadata)
|
19
|
+
metadata[:metrics][:resultCount]
|
20
|
+
end
|
21
|
+
|
22
|
+
def perform(limit: nil, **_options, &blk)
|
23
|
+
raise 'not connected' unless @connection.handle
|
24
|
+
raise 'query already in progress' if @query_text
|
25
|
+
raise 'callback required' unless block_given?
|
26
|
+
|
27
|
+
# customise the size based on the request being made
|
28
|
+
orig_limit = @n1ql.limit
|
29
|
+
begin
|
30
|
+
if orig_limit && limit
|
31
|
+
@n1ql.limit = limit if orig_limit > limit
|
32
|
+
end
|
33
|
+
@query_text = @n1ql.to_s
|
34
|
+
rescue StandardError
|
35
|
+
@query_text = nil
|
36
|
+
raise
|
37
|
+
ensure
|
38
|
+
@n1ql.limit = orig_limit
|
39
|
+
end
|
40
|
+
|
41
|
+
@reactor.schedule do
|
42
|
+
@error = nil
|
43
|
+
@callback = blk
|
44
|
+
|
45
|
+
@cmd = Ext::CMDN1QL.new
|
46
|
+
@params = Ext.n1p_new
|
47
|
+
err = Ext.n1p_setconsistency(@params, N1P_CONSISTENCY_REQUEST)
|
48
|
+
if err == :success
|
49
|
+
err = Ext.n1p_setquery(@params, @query_text, @query_text.bytesize, N1P_QUERY_STATEMENT)
|
50
|
+
if err == :success
|
51
|
+
|
52
|
+
err = Ext.n1p_mkcmd(@params, @cmd)
|
53
|
+
if err == :success
|
54
|
+
pointer = @cmd.to_ptr
|
55
|
+
@connection.requests[pointer.address] = self
|
56
|
+
|
57
|
+
@cmd[:callback] = @connection.get_callback(:n1ql_callback)
|
58
|
+
@cmd[:handle] = @request_handle
|
59
|
+
|
60
|
+
err = Ext.n1ql_query(@connection.handle, pointer, @cmd)
|
61
|
+
if err != :success
|
62
|
+
error(Error.lookup(err).new('full text search not scheduled'))
|
63
|
+
end
|
64
|
+
else
|
65
|
+
error(Error.lookup(err).new('failed to build full text search command'))
|
66
|
+
end
|
67
|
+
else
|
68
|
+
error(Error.lookup(err).new('failed to build full text search query structure'))
|
69
|
+
end
|
70
|
+
else
|
71
|
+
error(Error.lookup(err).new('failed set consistency value'))
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
# Row is JSON value representing the result
|
77
|
+
def received(row)
|
78
|
+
return if @error
|
79
|
+
|
80
|
+
@callback.call(false, row)
|
81
|
+
rescue StandardError => e
|
82
|
+
@error = e
|
83
|
+
cancel
|
84
|
+
end
|
85
|
+
|
86
|
+
# Example metadata
|
87
|
+
# {:requestID=>"36162fce-ef39-4821-bf03-449e4073185d", :signature=>{:*=>"*"}, :results=>[], :status=>"success",
|
88
|
+
# :metrics=>{:elapsedTime=>"15.298243ms", :executionTime=>"15.256975ms", :resultCount=>12, :resultSize=>8964}}
|
89
|
+
def received_final(metadata)
|
90
|
+
@query_text = nil
|
91
|
+
|
92
|
+
@connection.requests.delete(@cmd.to_ptr.address)
|
93
|
+
@cmd = nil
|
94
|
+
|
95
|
+
Ext.n1p_free(@params)
|
96
|
+
@params = nil
|
97
|
+
|
98
|
+
if @error
|
99
|
+
if @error == :cancelled
|
100
|
+
@callback.call(:final, metadata)
|
101
|
+
else
|
102
|
+
@callback.call(:error, @error)
|
103
|
+
end
|
104
|
+
else
|
105
|
+
@callback.call(:final, metadata)
|
106
|
+
end
|
107
|
+
end
|
108
|
+
|
109
|
+
def error(obj)
|
110
|
+
@error = obj
|
111
|
+
received_final(nil)
|
112
|
+
end
|
113
|
+
|
114
|
+
def cancel
|
115
|
+
@error ||= :cancelled
|
116
|
+
@reactor.schedule do
|
117
|
+
if @connection.handle && @cmd
|
118
|
+
Ext.n1ql_cancel(@connection.handle, @handle_ptr.get_pointer(0))
|
119
|
+
received_final(nil)
|
120
|
+
end
|
121
|
+
end
|
122
|
+
end
|
123
|
+
end
|
124
|
+
end
|
@@ -1,5 +1,6 @@
|
|
1
1
|
common: &common
|
2
|
-
|
2
|
+
connection_string: couchbase://localhost
|
3
|
+
bucket: <%= bucket_name || app_name %>
|
3
4
|
username: <%= username || bucket_name || app_name %>
|
4
5
|
password: <%= password %>
|
5
6
|
|
@@ -13,7 +14,7 @@ test:
|
|
13
14
|
|
14
15
|
# set these environment variables on your production server
|
15
16
|
production:
|
16
|
-
|
17
|
+
connection_string: <%%= ENV['COUCHBASE_CONNECTION_STRING'] %>
|
17
18
|
bucket: <%%= ENV['COUCHBASE_BUCKET'] %>
|
18
19
|
username: <%%= ENV['COUCHBASE_USER'] %>
|
19
20
|
password: <%%= ENV['COUCHBASE_PASSWORD'] %>
|
data/spec/associations_spec.rb
CHANGED
@@ -5,6 +5,13 @@ require File.expand_path("../support", __FILE__)
|
|
5
5
|
|
6
6
|
class Parent < CouchbaseOrm::Base
|
7
7
|
attribute :name
|
8
|
+
has_and_belongs_to_many :children
|
9
|
+
end
|
10
|
+
|
11
|
+
class StrictLoadingParent < CouchbaseOrm::Base
|
12
|
+
attribute :name
|
13
|
+
has_and_belongs_to_many :children
|
14
|
+
self.strict_loading_by_default = true
|
8
15
|
end
|
9
16
|
|
10
17
|
class RandomOtherType < CouchbaseOrm::Base
|
@@ -17,77 +24,239 @@ class Child < CouchbaseOrm::Base
|
|
17
24
|
belongs_to :parent, dependent: :destroy
|
18
25
|
end
|
19
26
|
|
27
|
+
class Assembly < CouchbaseOrm::Base
|
28
|
+
attribute :name
|
29
|
+
|
30
|
+
has_and_belongs_to_many :parts, autosave: true
|
31
|
+
end
|
32
|
+
|
33
|
+
class Part < CouchbaseOrm::Base
|
34
|
+
attribute :name
|
35
|
+
|
36
|
+
has_and_belongs_to_many :assemblies, dependent: :destroy, autosave: true
|
37
|
+
end
|
38
|
+
|
20
39
|
|
21
40
|
describe CouchbaseOrm::Associations do
|
22
|
-
|
23
|
-
|
24
|
-
|
41
|
+
describe 'belongs_to' do
|
42
|
+
it "should work with dependent associations" do
|
43
|
+
parent = Parent.create!(name: 'joe')
|
44
|
+
child = Child.create!(name: 'bob', parent_id: parent.id)
|
25
45
|
|
26
|
-
|
27
|
-
|
28
|
-
|
46
|
+
expect(parent.persisted?).to be(true)
|
47
|
+
expect(child.persisted?).to be(true)
|
48
|
+
id = parent.id
|
49
|
+
|
50
|
+
child.destroy
|
51
|
+
expect(child.destroyed?).to be(true)
|
52
|
+
expect(parent.destroyed?).to be(false)
|
29
53
|
|
30
|
-
|
31
|
-
|
32
|
-
|
54
|
+
# Ensure that parent has been destroyed
|
55
|
+
expect { Parent.find(id) }.to raise_error(Couchbase::Error::DocumentNotFound)
|
56
|
+
|
57
|
+
expect(Parent.find_by_id(id)).to be(nil)
|
33
58
|
|
34
|
-
|
35
|
-
expect { Parent.find(id) }.to raise_error(Libcouchbase::Error::KeyNotFound)
|
36
|
-
expect(Parent.find_by_id(id)).to be(nil)
|
59
|
+
expect { parent.reload }.to raise_error(Couchbase::Error::DocumentNotFound)
|
37
60
|
|
38
|
-
|
61
|
+
# Save will always return true unless the model is changed (won't touch the database)
|
62
|
+
parent.name = 'should fail'
|
63
|
+
expect { parent.save }.to raise_error(Couchbase::Error::DocumentNotFound)
|
64
|
+
expect { parent.save! }.to raise_error(Couchbase::Error::DocumentNotFound)
|
65
|
+
end
|
39
66
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
expect { parent.save! }.to raise_error(Libcouchbase::Error::KeyNotFound)
|
44
|
-
end
|
67
|
+
it "should cache associations" do
|
68
|
+
parent = Parent.create!(name: 'joe')
|
69
|
+
child = Child.create!(name: 'bob', parent_id: parent.id)
|
45
70
|
|
46
|
-
|
47
|
-
|
48
|
-
|
71
|
+
id = child.parent.__id__
|
72
|
+
expect(parent.__id__).not_to eq(child.parent.__id__)
|
73
|
+
expect(parent).to eq(child.parent)
|
74
|
+
expect(child.parent.__id__).to eq(id)
|
49
75
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
expect(child.parent.__id__).to eq(id)
|
76
|
+
child.reload
|
77
|
+
expect(parent).to eq(child.parent)
|
78
|
+
expect(child.parent.__id__).not_to eq(id)
|
54
79
|
|
55
|
-
|
56
|
-
|
57
|
-
expect(child.parent.__id__).not_to eq(id)
|
80
|
+
child.destroy
|
81
|
+
end
|
58
82
|
|
59
|
-
|
60
|
-
|
83
|
+
it "should ignore associations when delete is used" do
|
84
|
+
parent = Parent.create!(name: 'joe')
|
85
|
+
child = Child.create!(name: 'bob', parent_id: parent.id)
|
61
86
|
|
62
|
-
|
63
|
-
|
64
|
-
child = Child.create!(name: 'bob', parent_id: parent.id)
|
87
|
+
id = child.id
|
88
|
+
child.delete
|
65
89
|
|
66
|
-
|
67
|
-
|
90
|
+
expect(Child.exists?(id)).to be(false) # this is flaky
|
91
|
+
expect(Parent.exists?(parent.id)).to be(true)
|
68
92
|
|
69
|
-
|
70
|
-
|
93
|
+
id = parent.id
|
94
|
+
parent.delete
|
95
|
+
expect(Parent.exists?(id)).to be(false)
|
96
|
+
end
|
97
|
+
|
98
|
+
it "should raise an error if an invalid type is being assigned" do
|
99
|
+
begin
|
100
|
+
parent = RandomOtherType.create!(name: 'joe')
|
101
|
+
expect { Child.create!(name: 'bob', parent: parent) }.to raise_error(ArgumentError)
|
102
|
+
ensure
|
103
|
+
parent.delete
|
104
|
+
end
|
105
|
+
end
|
71
106
|
|
72
|
-
|
73
|
-
|
74
|
-
|
107
|
+
describe Parent do
|
108
|
+
it_behaves_like "ActiveModel"
|
109
|
+
end
|
110
|
+
|
111
|
+
describe Child do
|
112
|
+
it_behaves_like "ActiveModel"
|
113
|
+
end
|
75
114
|
end
|
76
115
|
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
116
|
+
describe 'has_and_belongs_to_many' do
|
117
|
+
it "should work with dependent associations" do
|
118
|
+
assembly = Assembly.create!(name: 'a1')
|
119
|
+
part = Part.create!(name: 'p1', assemblies: [assembly])
|
120
|
+
assembly.reload
|
121
|
+
|
122
|
+
expect(assembly.persisted?).to be(true)
|
123
|
+
expect(part.persisted?).to be(true)
|
124
|
+
|
125
|
+
part.destroy
|
126
|
+
expect(part.destroyed?).to be(true)
|
127
|
+
expect(assembly.destroyed?).to be(true)
|
128
|
+
end
|
129
|
+
|
130
|
+
it "should cache associations" do
|
131
|
+
assembly = Assembly.create!(name: 'a1')
|
132
|
+
part = Part.create!(name: 'p1', assembly_ids: [assembly.id])
|
133
|
+
assembly.reload
|
134
|
+
|
135
|
+
id = part.assemblies.first.__id__
|
136
|
+
expect(assembly.__id__).not_to eq(part.assemblies.first.__id__)
|
137
|
+
expect(assembly).to eq(part.assemblies.first)
|
138
|
+
expect(part.assemblies.first.__id__).to eq(id)
|
139
|
+
|
140
|
+
part.reload
|
141
|
+
expect(assembly).to eq(part.assemblies.first)
|
142
|
+
expect(part.assemblies.first.__id__).not_to eq(id)
|
143
|
+
|
144
|
+
part.destroy
|
145
|
+
end
|
146
|
+
|
147
|
+
it "should ignore associations when delete is used" do
|
148
|
+
assembly = Assembly.create!(name: 'a1')
|
149
|
+
part = Part.create!(name: 'p1', assembly_ids: [assembly.id])
|
150
|
+
assembly.reload
|
151
|
+
|
152
|
+
id = part.id
|
153
|
+
part.delete
|
154
|
+
|
155
|
+
expect(Part.exists?(id)).to be(false)
|
156
|
+
expect(Assembly.exists?(assembly.id)).to be(true)
|
157
|
+
|
158
|
+
id = assembly.id
|
159
|
+
assembly.delete
|
160
|
+
expect(Assembly.exists?(id)).to be(false)
|
161
|
+
end
|
162
|
+
|
163
|
+
it "should raise an error if an invalid type is being assigned" do
|
164
|
+
begin
|
165
|
+
assembly = RandomOtherType.create!(name: 'a1')
|
166
|
+
expect { Part.create!(name: 'p1', assemblies: [assembly]) }.to raise_error(ArgumentError)
|
167
|
+
ensure
|
168
|
+
assembly.delete
|
169
|
+
end
|
170
|
+
end
|
171
|
+
|
172
|
+
it "should add association with single" do
|
173
|
+
assembly = Assembly.create!(name: 'a1')
|
174
|
+
part = Part.create!(name: 'p1', assemblies: [assembly])
|
175
|
+
|
176
|
+
expect(assembly.reload.parts.map(&:id)).to match_array([part.id])
|
177
|
+
end
|
178
|
+
|
179
|
+
it 'should add association with multiple' do
|
180
|
+
assembly = Assembly.create!(name: 'a1')
|
181
|
+
part1 = Part.create!(name: 'p1', assemblies: [assembly])
|
182
|
+
part2 = Part.create!(name: 'p2', assemblies: [assembly])
|
183
|
+
|
184
|
+
expect(assembly.reload.parts.map(&:id)).to match_array([part1.id, part2.id])
|
185
|
+
end
|
186
|
+
|
187
|
+
it "should remove association with single" do
|
188
|
+
assembly1 = Assembly.create!(name: 'a1')
|
189
|
+
assembly2 = Assembly.create!(name: 'a2')
|
190
|
+
part = Part.create!(name: 'p1', assemblies: [assembly1])
|
191
|
+
part.assemblies = [assembly2]
|
192
|
+
part.save!
|
193
|
+
|
194
|
+
expect(assembly1.reload.parts.map(&:id)).to be_empty
|
195
|
+
expect(assembly2.reload.parts.map(&:id)).to match_array([part.id])
|
196
|
+
end
|
197
|
+
|
198
|
+
it 'should remove association with multiple' do
|
199
|
+
assembly1 = Assembly.create!(name: 'a1')
|
200
|
+
assembly2 = Assembly.create!(name: 'a2')
|
201
|
+
part1 = Part.create!(name: 'p1', assemblies: [assembly1])
|
202
|
+
part2 = Part.create!(name: 'p2', assemblies: [assembly2])
|
203
|
+
|
204
|
+
part1.assemblies = part1.assemblies + [assembly2]
|
205
|
+
part1.save!
|
206
|
+
|
207
|
+
expect(assembly1.reload.parts.map(&:id)).to match_array([part1.id])
|
208
|
+
expect(assembly2.reload.parts.map(&:id)).to match_array([part1.id, part2.id])
|
209
|
+
end
|
210
|
+
|
211
|
+
describe Assembly do
|
212
|
+
it_behaves_like "ActiveModel"
|
213
|
+
end
|
214
|
+
|
215
|
+
describe Part do
|
216
|
+
it_behaves_like "ActiveModel"
|
83
217
|
end
|
84
218
|
end
|
85
219
|
|
86
|
-
describe
|
87
|
-
|
220
|
+
describe 'strict_loading' do
|
221
|
+
let(:parent) {Parent.create!(name: 'joe')}
|
222
|
+
let(:child) {Child.create!(name: 'bob', parent_id: parent.id)}
|
223
|
+
context 'instance strict loading' do
|
224
|
+
it 'raises StrictLoadingViolationError on lazy loading child relation' do
|
225
|
+
expect {child.parent.id}.not_to raise_error
|
226
|
+
expect_strict_loading_error_on_calling_parent(Child.find(child.id).tap{|child| child.strict_loading!})
|
227
|
+
end
|
228
|
+
end
|
229
|
+
context 'scope strict loading' do
|
230
|
+
it 'raises StrictLoadingViolationError on lazy loading child relation' do
|
231
|
+
expect_strict_loading_error_on_calling_parent(Child.where(id: child.id).strict_loading.first)
|
232
|
+
expect_strict_loading_error_on_calling_parent(Child.strict_loading.where(id: child.id).first)
|
233
|
+
expect_strict_loading_error_on_calling_parent(Child.strict_loading.where(id: child.id).last)
|
234
|
+
expect_strict_loading_error_on_calling_parent(Child.strict_loading.where(id: child.id).to_a.first)
|
235
|
+
expect_strict_loading_error_on_calling_parent(Child.strict_loading.all.to_a.first)
|
236
|
+
end
|
237
|
+
|
238
|
+
it 'does not raise StrictLoadingViolationError on lazy loading child relation without declaring it' do
|
239
|
+
expect_strict_loading_error_on_calling_parent(Child.strict_loading.where(id: child.id).first)
|
240
|
+
expect { Child.where(id: child.id).last.parent}.not_to raise_error
|
241
|
+
end
|
242
|
+
|
243
|
+
it 'raises StrictLoadingViolationError on lazy loading habtm relation' do
|
244
|
+
expect {Parent.strict_loading.where(id: parent.id).first.children}.to raise_error(CouchbaseOrm::StrictLoadingViolationError)
|
245
|
+
# NB any action called on model class breaks find return type (find return an enumerator instead of a record)
|
246
|
+
expect {Parent.strict_loading.find(parent.id).first.children}.to raise_error(CouchbaseOrm::StrictLoadingViolationError)
|
247
|
+
end
|
248
|
+
|
249
|
+
it 'raises StrictLoadingViolationError on lazy loading relation when model is by default strict_loading' do
|
250
|
+
strict_loading_parent = StrictLoadingParent.create!(name: 'joe')
|
251
|
+
expect {StrictLoadingParent.where(id: strict_loading_parent.id).first.children}.to raise_error(CouchbaseOrm::StrictLoadingViolationError)
|
252
|
+
expect {Parent.find(parent.id).children}.not_to raise_error
|
253
|
+
# NB any action called on model class breaks find return type (find return an enumerator instead of a record)
|
254
|
+
expect {Parent.strict_loading.find(strict_loading_parent.id).first.children}.to raise_error(CouchbaseOrm::StrictLoadingViolationError)
|
255
|
+
end
|
256
|
+
end
|
88
257
|
end
|
89
258
|
|
90
|
-
|
91
|
-
|
259
|
+
def expect_strict_loading_error_on_calling_parent(child_instance)
|
260
|
+
expect {child_instance.parent}.to raise_error(CouchbaseOrm::StrictLoadingViolationError)
|
92
261
|
end
|
93
262
|
end
|