hoodoo 1.3.1 → 1.4.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 CHANGED
@@ -1,15 +1,15 @@
1
1
  ---
2
2
  !binary "U0hBMQ==":
3
3
  metadata.gz: !binary |-
4
- MmVkNzQ3ZmU3YWQ3ZjY5YzFhOTQzOWQ3ODgwYWYwNGI5NDRhOGM2YQ==
4
+ OGQ2ZGRmYWM3NTIwOWEwOGIyNjFiOTkyN2I4ZDdhNzY1YWUzZWIyNw==
5
5
  data.tar.gz: !binary |-
6
- ZTM4ZDc5NWM5OTVjZjI4ZWQ3M2E5M2Y5YzVmNGYyMzcwYmVhMjczNg==
6
+ OWUxNzBkMjc2NzM5N2ViZDM5ZWY2ZjNjMDFhZjJiNDVmNzA5NDYxMA==
7
7
  SHA512:
8
8
  metadata.gz: !binary |-
9
- ODEwNjVhMDM1ODM0ZGUyMWVmMjUxMDQzZWU2NDY1YTFlNzg4YjI2MDYxNWFk
10
- NmI1YzU4ZmVjYzFkODNmMjhjNjYxNTRhNzc4ZDAwZDNhMmUzYzAyOTE4Yjlm
11
- MDNkYjI3MzJjMWUzYzU5MDQ5NzhiYWVkZDJkN2I2YTExOWVmNDA=
9
+ MjE2MTQ5YTU0OWFkZWEyN2Y0YTU5ZDJhOWU5MjkwODI3MmViYWFmODg4ZDll
10
+ MWI5MjUyNjIzNGFjMWZiYmViYzhhYTcyZGQyZmRhMjk5M2ZjMjQzOWJiNWFl
11
+ Mzg4NWZlMDFhZjQ3MjA4ZmQxZWM1YzM5YTY4YTJiNTE4MjFjOGQ=
12
12
  data.tar.gz: !binary |-
13
- NjNhNmY1YTk4MjYxNTk2MTUxNDFiMjIyMTEyODM0MzEzMDU4ZDBkMGU3ODFj
14
- ZWU0NzYwOTUyNDVmNDZlNjAyZjc4N2IwMDk4ZmE5ZWU2NjBmY2RhNWY4YjI2
15
- MGQ1OWExN2Q1OWRkYTY5ZDQxYzY4ODIxNjJkMzM2ZDQzNjA1NzQ=
13
+ NWFlNzg2Y2E4ODg4ODY3MjYwMTRmMzQzZmYzMWQ0OGJkYzljZDdhZjY0ZmYw
14
+ YjUwNjljZjkwMWM5Y2ZjOTgwNmJiNTZkNzg4MGE3OTk4M2ZlOWQxZDEzMWQy
15
+ ZDJiYzBjNTAzMDkwOGIzYzI3MjU1OGQxMjk0MDg2OTcwMTdjMWY=
@@ -88,6 +88,27 @@ module Hoodoo
88
88
  #
89
89
  module ClassMethods
90
90
 
91
+ # Returns an ActiveRecord::Relation instance representing a primitive
92
+ # base scope that includes various context-related aspects according
93
+ # to the prevailing mixins included by "this" class, if any - e.g.
94
+ # security, dating and/or translation.
95
+ #
96
+ # See Hoodoo::ActiveRecord::Support#full_scope_for to see the list
97
+ # of things that get included. If there are no "interesting" mixins,
98
+ # the returned scope will just return the same thing that the +all+
99
+ # method in ActiveRecord would have returned. Consequently, a default
100
+ # scope _will_ be honoured if one has been declared, though default
101
+ # scopes are generally considered an anti-pattern to be avoided.
102
+ #
103
+ # +context+:: Hoodoo::Services::Context instance describing a call
104
+ # context. This is typically a value passed to one of
105
+ # the Hoodoo::Services::Implementation instance methods
106
+ # that a resource subclass implements.
107
+ #
108
+ def scoped_in( context )
109
+ Hoodoo::ActiveRecord::Support.full_scope_for( self, context )
110
+ end
111
+
91
112
  # "Polymorphic" find - support for finding a model by fields other
92
113
  # than just +:id+, based on a single unique identifier. Use #acquire
93
114
  # just like you'd use +find_by_id+ and only bother with it if you
@@ -159,10 +180,11 @@ module Hoodoo
159
180
  end
160
181
 
161
182
  # Implicily secure, translated, dated etc. etc. version of #acquire,
162
- # according to which modules are mixed into your model class. See
163
- # Hoodoo::ActiveRecord::Support#full_scope_for to see the list of
164
- # things that get included in the scope according to the mixins
165
- # that are in use.
183
+ # according to which modules are mixed into your model class. Uses
184
+ # #scoped_in to obtain a base scope in which to operate, so it is
185
+ # "mixin aware" and incorporates other Hoodoo extensions within the
186
+ # wider scope chain. See that method's documentation for more
187
+ # information.
166
188
  #
167
189
  # For example, if you are using or at some point intend to mix in and
168
190
  # use the mechanism described by the likes of
@@ -213,8 +235,7 @@ module Hoodoo
213
235
  # SomeModel.acquire_in( context )
214
236
  #
215
237
  # The same applies to forgetting dated scopes, translated scopes, or
216
- # anything else that Hoodoo::ActiveRecord::Support#full_scope_for
217
- # might include for you.
238
+ # anything else that #scoped_in might include for you.
218
239
  #
219
240
  # Parameters:
220
241
  #
@@ -226,8 +247,7 @@ module Hoodoo
226
247
  # Returns a found model instance or +nil+ for no match.
227
248
  #
228
249
  def acquire_in( context )
229
- scope = Hoodoo::ActiveRecord::Support.full_scope_for( self, context )
230
- return scope.acquire( context.request.ident )
250
+ return scoped_in( context ).acquire( context.request.ident )
231
251
  end
232
252
 
233
253
  # Describe the list of model fields _in_ _addition_ _to_ +id+ which
@@ -294,11 +314,13 @@ module Hoodoo
294
314
  #
295
315
  # Normally such a scope could only ever return a single record based
296
316
  # on an assuption of uniqueness constraints around columns which one
297
- # might use in an equivalent of a +find+ call. In some instances
298
- # however - e.g. a table that contains historic representations of a
299
- # model as well as its 'current' representation - there may be more
300
- # than one result and the returned value from this method may need to
301
- # be chained in with other scopes to form a useful query.
317
+ # might use in an equivalent of a +find+ call. This scope is often
318
+ # chained on top of a wider listing scope provided by #scoped_in to
319
+ # create a fully context-aware, secure, dated, translated etc. query.
320
+ # It is possible however that the chosen +ident+ value might not
321
+ # resolve to a single unique record depending on how your data works
322
+ # and you may need to manually apply additional constraints to the
323
+ # returned ActiveRecord::Relation instance.
302
324
  #
303
325
  def acquisition_scope( ident )
304
326
  extra_fields = self.acquired_with()
@@ -432,9 +454,8 @@ module Hoodoo
432
454
 
433
455
  # Implicily secure, translated, dated etc. etc. version of #list,
434
456
  # according to which modules are mixed into your model class. See
435
- # Hoodoo::ActiveRecord::Support#full_scope_for to see the list of
436
- # things that get included in the scope according to the mixins
437
- # that are in use.
457
+ # #scoped_in to see the list of things that get included in the
458
+ # scope according to the mixins that are in use.
438
459
  #
439
460
  # For example, if you have included Hoodoo::ActiveRecord::Secure,
440
461
  # this method provides you with an implicitly secure query. Read the
@@ -450,8 +471,7 @@ module Hoodoo
450
471
  # SomeModel.list_in( context )
451
472
  #
452
473
  # The same applies to forgetting dated scopes, translated scopes, or
453
- # anything else that Hoodoo::ActiveRecord::Support#full_scope_for
454
- # might include for you.
474
+ # anything else that #scoped_in might include for you.
455
475
  #
456
476
  # +context+:: Hoodoo::Services::Context instance describing a call
457
477
  # context. This is typically a value passed to one of
@@ -462,8 +482,7 @@ module Hoodoo
462
482
  # query methods like +where+ or fetching from the database with +all+.
463
483
  #
464
484
  def list_in( context )
465
- scope = Hoodoo::ActiveRecord::Support.full_scope_for( self, context )
466
- return scope.list( context.request.list )
485
+ return scoped_in( context ).list( context.request.list )
467
486
  end
468
487
 
469
488
  # Given some scope - typically that obtained from a prior call to
@@ -12,6 +12,6 @@ module Hoodoo
12
12
  # The Hoodoo gem version. If this changes, ensure that the date in
13
13
  # "hoodoo.gemspec" is correct and run "bundle install" (or "update").
14
14
  #
15
- VERSION = '1.3.1'
15
+ VERSION = '1.4.0'
16
16
 
17
17
  end
@@ -129,7 +129,90 @@ describe Hoodoo::ActiveRecord::Finder do
129
129
 
130
130
  # ==========================================================================
131
131
 
132
- context 'acquire' do
132
+ context '#scoped_in' do
133
+ before :each do
134
+
135
+ # Get a good-enough-for-test interaction which has a context
136
+ # that contains a Session we can modify.
137
+
138
+ @interaction = Hoodoo::Services::Middleware::Interaction.new( {}, nil )
139
+ @interaction.context = Hoodoo::Services::Context.new(
140
+ Hoodoo::Services::Session.new,
141
+ @interaction.context.request,
142
+ @interaction.context.response,
143
+ @interaction
144
+ )
145
+
146
+ @context = @interaction.context
147
+ @session = @interaction.context.session
148
+ end
149
+
150
+ # If security scoping works _and_ we know that it called #full_scope_for
151
+ # in the "internal"-ish support API, then we consider that good enough
152
+ # to prove that it's calling the scope engine and that engine has its
153
+ # own comprehensive test coverage in suport_spec.rb.
154
+ #
155
+ it 'generates appropriate scope' do
156
+ @session.scoping = { :authorised_uuids => [ 'uuid 1', 'uuid 2' ], :authorised_code => 'code 1' }
157
+
158
+ expect( Hoodoo::ActiveRecord::Support ).to(
159
+ receive( :full_scope_for ).once().with(
160
+ RSpecModelFinderTest, @context
161
+ ).and_call_original()
162
+ )
163
+
164
+ sql = RSpecModelFinderTest.scoped_in( @context ).to_sql
165
+
166
+ expect( sql ).to eq( "SELECT \"r_spec_model_finder_tests\".* "<<
167
+ "FROM \"r_spec_model_finder_tests\" " <<
168
+ "WHERE " <<
169
+ "\"r_spec_model_finder_tests\".\"uuid\" IN ('uuid 1', 'uuid 2') AND " <<
170
+ "\"r_spec_model_finder_tests\".\"code\" = 'code 1'" )
171
+ end
172
+ end
173
+
174
+ # ==========================================================================
175
+
176
+ context 'acquisition scope and overrides' do
177
+ def expect_sql( sql, id_attr_name )
178
+ expect( sql ).to eq( "SELECT \"r_spec_model_finder_tests\".* "<<
179
+ "FROM \"r_spec_model_finder_tests\" " <<
180
+ "WHERE (" <<
181
+ "(" <<
182
+ "\"r_spec_model_finder_tests\".\"#{ id_attr_name }\" = '#{ @id }' OR " <<
183
+ "\"r_spec_model_finder_tests\".\"uuid\" = '#{ @id }'" <<
184
+ ") OR " <<
185
+ "\"r_spec_model_finder_tests\".\"code\" = '#{ @id }'" <<
186
+ ")" )
187
+ end
188
+
189
+ context '#acquisition_scope' do
190
+ it 'SQL generation is as expected' do
191
+ sql = RSpecModelFinderTest.acquisition_scope( @id ).to_sql()
192
+ expect_sql( sql, 'id' )
193
+ end
194
+ end
195
+
196
+ context '#acquire_with_id_substitute' do
197
+ before :each do
198
+ @alt_attr_name = 'foo'
199
+ RSpecModelFinderTest.acquire_with_id_substitute( @alt_attr_name )
200
+ end
201
+
202
+ after :each do
203
+ RSpecModelFinderTest.acquire_with_id_substitute( 'id' )
204
+ end
205
+
206
+ it 'SQL generation is as expected' do
207
+ sql = RSpecModelFinderTest.acquisition_scope( @id ).to_sql()
208
+ expect_sql( sql, @alt_attr_name )
209
+ end
210
+ end
211
+ end
212
+
213
+ # ==========================================================================
214
+
215
+ context '#acquire' do
133
216
  it 'finds from the class' do
134
217
  found = RSpecModelFinderTest.acquire( @id )
135
218
  expect( found ).to eq(@a)
@@ -203,7 +286,7 @@ describe Hoodoo::ActiveRecord::Finder do
203
286
 
204
287
  # ==========================================================================
205
288
 
206
- context 'acquire_in' do
289
+ context '#acquire_in' do
207
290
  before :each do
208
291
  @scoped_1 = RSpecModelFinderTest.new
209
292
  @scoped_1.id = 'id 1'
@@ -350,46 +433,7 @@ describe Hoodoo::ActiveRecord::Finder do
350
433
 
351
434
  # ==========================================================================
352
435
 
353
- context 'acquisition scope and overrides' do
354
- def expect_sql( sql, id_attr_name )
355
- expect( sql ).to eq( "SELECT \"r_spec_model_finder_tests\".* "<<
356
- "FROM \"r_spec_model_finder_tests\" " <<
357
- "WHERE (" <<
358
- "(" <<
359
- "\"r_spec_model_finder_tests\".\"#{ id_attr_name }\" = '#{ @id }' OR " <<
360
- "\"r_spec_model_finder_tests\".\"uuid\" = '#{ @id }'" <<
361
- ") OR " <<
362
- "\"r_spec_model_finder_tests\".\"code\" = '#{ @id }'" <<
363
- ")" )
364
- end
365
-
366
- context 'acquisition_scope' do
367
- it 'SQL generation is as expected' do
368
- sql = RSpecModelFinderTest.acquisition_scope( @id ).to_sql()
369
- expect_sql( sql, 'id' )
370
- end
371
- end
372
-
373
- context 'acquire_with_id_substitute' do
374
- before :each do
375
- @alt_attr_name = 'foo'
376
- RSpecModelFinderTest.acquire_with_id_substitute( @alt_attr_name )
377
- end
378
-
379
- after :each do
380
- RSpecModelFinderTest.acquire_with_id_substitute( 'id' )
381
- end
382
-
383
- it 'SQL generation is as expected' do
384
- sql = RSpecModelFinderTest.acquisition_scope( @id ).to_sql()
385
- expect_sql( sql, @alt_attr_name )
386
- end
387
- end
388
- end
389
-
390
- # ==========================================================================
391
-
392
- context 'lists' do
436
+ context '#list' do
393
437
  it 'lists with pages, offsets and counts' do
394
438
  @list_params.offset = 1 # 0 is first record
395
439
  @list_params.limit = 1
@@ -695,7 +739,7 @@ describe Hoodoo::ActiveRecord::Finder do
695
739
 
696
740
  # ==========================================================================
697
741
 
698
- context 'list_in' do
742
+ context '#list_in' do
699
743
  before :each do
700
744
  @scoped_1 = RSpecModelFinderTest.new
701
745
  @scoped_1.id = 'id 1'
@@ -74,6 +74,14 @@ describe Hoodoo::ActiveRecord::Support do
74
74
  t.string :bar
75
75
  t.timestamps :null => true
76
76
  end
77
+
78
+ ActiveRecord::Migration.create_table( :r_spec_full_scope_for_manually_dateds ) do | t |
79
+ t.string :baz
80
+ t.string :uuid, :length => 32
81
+ t.datetime :effective_start
82
+ t.datetime :effective_end
83
+ t.timestamps :null => true
84
+ end
77
85
  end
78
86
 
79
87
  # Note inheritance from plain ActiveRecord::Base, important for
@@ -107,6 +115,16 @@ describe Hoodoo::ActiveRecord::Support do
107
115
  class RSpecFullScopeForTestBaseSubclassWithoutOverrides < RSpecFullScopeForTestBaseWithDirectives
108
116
  # No overrides at all
109
117
  end
118
+
119
+ # Manual and automatic effective dating can live in the same mixin
120
+ # collection but can't both be enabled at the same time, so do this
121
+ # in a special test class with a database table that meets the
122
+ # related requirements.
123
+ #
124
+ class RSpecFullScopeForManuallyDated < Hoodoo::ActiveRecord::Base
125
+ secure_with( :baz => :baz )
126
+ manual_dating_enabled()
127
+ end
110
128
  end
111
129
 
112
130
  before :each do
@@ -221,5 +239,37 @@ describe Hoodoo::ActiveRecord::Support do
221
239
  expect( auto_scope ).to eq( manual_scope )
222
240
  end
223
241
  end
242
+
243
+ context '(with manual dating enabled)' do
244
+ before :each do
245
+ @session.scoping.baz = [ @test_scoping_value ]
246
+ end
247
+
248
+ context 'gets customised scope:' do
249
+ it 'manually dated' do
250
+ manual_scope = RSpecFullScopeForManuallyDated.manually_dated( @context ).to_sql()
251
+
252
+ expect( manual_scope ).to include( 'FROM "r_spec_full_scope_for_manually_dateds"' )
253
+ expect( manual_scope ).to include( "\"effective_end\" > #{ RSpecFullScopeForTestSubclass.sanitize( @test_time_value.to_time.round( Hoodoo::ActiveRecord::ManuallyDated::SECONDS_DECIMAL_PLACES ) ) }" )
254
+ end
255
+
256
+ it 'secure' do
257
+ manual_scope = RSpecFullScopeForManuallyDated.secure( @context ).to_sql()
258
+
259
+ expect( manual_scope ).to include( "\"r_spec_full_scope_for_manually_dateds\".\"baz\" = '#{ @test_scoping_value }'" )
260
+ end
261
+
262
+ pending 'translated' do
263
+ raise "Scope verification for '\#translated'"
264
+ end
265
+
266
+ it 'everything' do
267
+ auto_scope = described_class.full_scope_for( RSpecFullScopeForManuallyDated, @context ).to_sql()
268
+ manual_scope = RSpecFullScopeForManuallyDated.manually_dated( @context ).secure( @context ).translated( @context ).to_sql()
269
+
270
+ expect( auto_scope ).to eq( manual_scope )
271
+ end
272
+ end
273
+ end
224
274
  end
225
275
  end
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.3.1
4
+ version: 1.4.0
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-18 00:00:00.000000000 Z
11
+ date: 2016-02-23 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: kgio