hoodoo 1.1.2 → 1.1.3
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 +8 -8
- data/lib/hoodoo/active/active_record/finder.rb +26 -42
- data/lib/hoodoo/version.rb +1 -1
- data/spec/active/active_record/finder_spec.rb +50 -30
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,15 +1,15 @@
|
|
1
1
|
---
|
2
2
|
!binary "U0hBMQ==":
|
3
3
|
metadata.gz: !binary |-
|
4
|
-
|
4
|
+
NWM1MTMyZWRmNGNkZDExY2IyYThiYjdhZDA2OGJmNWFiNTY2NDY4ZA==
|
5
5
|
data.tar.gz: !binary |-
|
6
|
-
|
6
|
+
N2YwMGE5ODIxNmFiNzEzMDc4YjE3YTk1ZWZiOTk2ODJhNTJmNjFhOQ==
|
7
7
|
SHA512:
|
8
8
|
metadata.gz: !binary |-
|
9
|
-
|
10
|
-
|
11
|
-
|
9
|
+
MmY2ODExNTRkZmJiYThmN2MyNGFkYTk0MjU4YjBhMzFkMTExZmU2YmNiMDNk
|
10
|
+
MjAwYzQ4NzRiM2FlMTA5NjQxNjdlMzM3OTA3YzQ3NzA2N2FlMTRhYTI4OGY4
|
11
|
+
NWUzNjFlNTE4NjdiNmE4YzMwYmZmMTJkZTg4NTdiZWVlYTVkODg=
|
12
12
|
data.tar.gz: !binary |-
|
13
|
-
|
14
|
-
|
15
|
-
|
13
|
+
ZjViMjVmM2FjMzY5YzBmYTU2NTljM2FiMjAwNWU3OTRiYzZhZjdiMmMzNzgz
|
14
|
+
MmE2ZmNjYWE2NTA4MGU4ODkwNjhlOTI0OGRlNjQ5ZjM1ZjIxYTI0ZjA5YWMz
|
15
|
+
ZGQ1OWIyYzNhMzBmZTU4Njk2Nzc0YmJjNWI4OGNhYmY4NDIwNjY=
|
@@ -152,48 +152,7 @@ module Hoodoo
|
|
152
152
|
# Returns a found model instance or +nil+ for no match.
|
153
153
|
#
|
154
154
|
def acquire( ident )
|
155
|
-
|
156
|
-
|
157
|
-
id_fields = [ :id ] + extra_fields
|
158
|
-
id_fields.each do | field |
|
159
|
-
|
160
|
-
# This is fiddly.
|
161
|
-
#
|
162
|
-
# You must use a string with field substitution approach, rather
|
163
|
-
# than e.g. ".where( :field => :ident )". AREL/ActiveRecord will,
|
164
|
-
# in the latter case, compose rational SQL based on column data
|
165
|
-
# types. If you have an *integer* ID field, then, it'll try to
|
166
|
-
# convert a *string* ident to an integer. This can give Hilarious
|
167
|
-
# Consequences. Consider looking up on (integer) field "id" or
|
168
|
-
# (text) field "uuid", with a string ident of "1f294942..." - the
|
169
|
-
# text UUID would be fine, but the integer ID may end up with the
|
170
|
-
# UUID being "to_i"'d, yielding integer 1. If the ID field is
|
171
|
-
# looked at first, you're highly likely to find the wrong record.
|
172
|
-
#
|
173
|
-
# The solution is, as written, simple; just use the substitution
|
174
|
-
# approach rather than higher level AREL, causing a string-like SQL
|
175
|
-
# query on all adapters which SQL handles just fine for varying
|
176
|
-
# field data types.
|
177
|
-
#
|
178
|
-
# The caveat is that should the database object to mismatched type
|
179
|
-
# comparisons it will actually raise an error - we see this on
|
180
|
-
# for example PostgreSQL where a column is an integer but we try
|
181
|
-
# to match it against a string that cannot be cleanly converted to
|
182
|
-
# one (e.g. trying to find an integer column 'id' based on a text
|
183
|
-
# UUID value containing alphabetic characters). That is still
|
184
|
-
# preferable to looking up the wrong record!
|
185
|
-
|
186
|
-
checker = where( [ "\"#{ self.table_name }\".\"#{ field }\" = ?", ident ] )
|
187
|
-
|
188
|
-
# If we have found a record return it, otherwise continue to loop
|
189
|
-
# through +id_fields+
|
190
|
-
#
|
191
|
-
if checker.first
|
192
|
-
return checker.first
|
193
|
-
end
|
194
|
-
end
|
195
|
-
|
196
|
-
return nil
|
155
|
+
return acquisition_scope( ident ).first
|
197
156
|
end
|
198
157
|
|
199
158
|
# Implicily secure, translated, dated etc. etc. version of #acquire,
|
@@ -294,6 +253,31 @@ module Hoodoo
|
|
294
253
|
self.nz_co_loyalty_hoodoo_show_id_fields || []
|
295
254
|
end
|
296
255
|
|
256
|
+
# Back-end to #acquire and therefore, in turn, #acquire_in. Returns
|
257
|
+
# an ActiveRecord::Relation instance which scopes the search for a
|
258
|
+
# record by +id+ and across any other columns specified by
|
259
|
+
# #acquire_with, via SQL +OR+.
|
260
|
+
#
|
261
|
+
# Normally such a scope could only ever return a single record based
|
262
|
+
# on an assuption of uniqueness constraints around columns which one
|
263
|
+
# might use in an equivalent of a +find+ call. In some instances
|
264
|
+
# however - e.g. a table that contains historic representations of a
|
265
|
+
# model as well as its 'current' representation - there may be more
|
266
|
+
# than one result and the returned value from this method may need to
|
267
|
+
# be chained in with other scopes to form a useful query.
|
268
|
+
#
|
269
|
+
def acquisition_scope( ident )
|
270
|
+
extra_fields = self.acquired_with()
|
271
|
+
arel_table = self.arel_table()
|
272
|
+
arel_query = arel_table[ :id ].eq( ident )
|
273
|
+
|
274
|
+
extra_fields.each do | field |
|
275
|
+
arel_query = arel_query.or( arel_table[ field ].eq( ident ) )
|
276
|
+
end
|
277
|
+
|
278
|
+
return where( arel_query )
|
279
|
+
end
|
280
|
+
|
297
281
|
# Generate an ActiveRecord::Relation instance which can be used to
|
298
282
|
# count, retrieve or further refine a list of model instances from
|
299
283
|
# the database.
|
data/lib/hoodoo/version.rb
CHANGED
@@ -154,47 +154,50 @@ describe Hoodoo::ActiveRecord::Finder do
|
|
154
154
|
expect( found ).to eq(nil) # Not in 'group 1'
|
155
155
|
end
|
156
156
|
|
157
|
-
#
|
158
|
-
#
|
157
|
+
# Early versions of the 'acquire'-backed methods always inadvertently
|
158
|
+
# performed two database calls, via a count then a true find. This was
|
159
|
+
# refactored to only make one call per attribute, but that in turn can
|
160
|
+
# be much improved via the AREL table to compose a single query that
|
161
|
+
# uses "OR" to get the database to check each attribute in order. Thus
|
162
|
+
# every test below expects exactly one database call only.
|
159
163
|
#
|
160
|
-
|
164
|
+
context 'only makes one database call when' do
|
161
165
|
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
# therefore only one call will be made
|
168
|
-
expect( count ).to eq( 1 )
|
166
|
+
it 'finding on the first attribute' do
|
167
|
+
count = count_database_calls_in do
|
168
|
+
found = RSpecModelFinderTest.acquire( @id )
|
169
|
+
expect( found ).to eq(@a)
|
170
|
+
end
|
169
171
|
|
170
|
-
|
171
|
-
found = RSpecModelFinderTest.acquire( @uuid )
|
172
|
-
expect( found ).to eq(@b)
|
172
|
+
expect( count ).to eq( 1 )
|
173
173
|
end
|
174
174
|
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
175
|
+
it 'finding on the second attribute' do
|
176
|
+
count = count_database_calls_in do
|
177
|
+
found = RSpecModelFinderTest.acquire( @uuid )
|
178
|
+
expect( found ).to eq(@b)
|
179
|
+
end
|
179
180
|
|
180
|
-
|
181
|
-
found = RSpecModelFinderTest.acquire( @code )
|
182
|
-
expect( found ).to eq(@c)
|
181
|
+
expect( count ).to eq( 1 )
|
183
182
|
end
|
184
183
|
|
185
|
-
|
186
|
-
|
187
|
-
|
188
|
-
|
189
|
-
|
184
|
+
it 'finding on the third attribute' do
|
185
|
+
count = count_database_calls_in do
|
186
|
+
found = RSpecModelFinderTest.acquire( @code )
|
187
|
+
expect( found ).to eq(@c)
|
188
|
+
end
|
190
189
|
|
191
|
-
|
192
|
-
found = RSpecModelFinderTest.acquire( Hoodoo::UUID.generate )
|
193
|
-
expect( found ).to be_nil
|
190
|
+
expect( count ).to eq( 1 )
|
194
191
|
end
|
195
192
|
|
196
|
-
|
197
|
-
|
193
|
+
it 'checking all three attributes but finding nothing' do
|
194
|
+
count = count_database_calls_in do
|
195
|
+
found = RSpecModelFinderTest.acquire( Hoodoo::UUID.generate )
|
196
|
+
expect( found ).to be_nil
|
197
|
+
end
|
198
|
+
|
199
|
+
expect( count ).to eq( 1 )
|
200
|
+
end
|
198
201
|
end
|
199
202
|
end
|
200
203
|
|
@@ -347,6 +350,23 @@ describe Hoodoo::ActiveRecord::Finder do
|
|
347
350
|
|
348
351
|
# ==========================================================================
|
349
352
|
|
353
|
+
context 'acquisition_scope' do
|
354
|
+
it 'SQL generation is as expected' do
|
355
|
+
sql = RSpecModelFinderTest.acquisition_scope( @id ).to_sql()
|
356
|
+
expect( sql ).to eq( "SELECT \"r_spec_model_finder_tests\".* "<<
|
357
|
+
"FROM \"r_spec_model_finder_tests\" " <<
|
358
|
+
"WHERE (" <<
|
359
|
+
"(" <<
|
360
|
+
"\"r_spec_model_finder_tests\".\"id\" = '#{ @id }' OR " <<
|
361
|
+
"\"r_spec_model_finder_tests\".\"uuid\" = '#{ @id }'" <<
|
362
|
+
") OR " <<
|
363
|
+
"\"r_spec_model_finder_tests\".\"code\" = '#{ @id }'" <<
|
364
|
+
")" )
|
365
|
+
end
|
366
|
+
end
|
367
|
+
|
368
|
+
# ==========================================================================
|
369
|
+
|
350
370
|
context 'lists' do
|
351
371
|
it 'lists with pages, offsets and counts' do
|
352
372
|
@list_params.offset = 1 # 0 is first record
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hoodoo
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.1.
|
4
|
+
version: 1.1.3
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Loyalty New Zealand
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-02-
|
11
|
+
date: 2016-02-04 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: uuidtools
|