hoodoo 1.3.1 → 1.4.0

Sign up to get free protection for your applications and to get access to all the features.
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