hoodoo 1.19.0 → 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.
Files changed (34) hide show
  1. checksums.yaml +4 -4
  2. data/lib/hoodoo/active/active_model/uuid_validator.rb +0 -1
  3. data/lib/hoodoo/active/active_record/dated.rb +2 -2
  4. data/lib/hoodoo/active/active_record/support.rb +2 -1
  5. data/lib/hoodoo/active/active_record/uuid.rb +2 -2
  6. data/lib/hoodoo/active/active_record/writer.rb +1 -1
  7. data/lib/hoodoo/generator.rb +52 -12
  8. data/lib/hoodoo/monkey/patch/datadog_traced_amqp.rb +11 -6
  9. data/lib/hoodoo/monkey/patch/newrelic_middleware_analytics.rb +17 -10
  10. data/lib/hoodoo/monkey/patch/newrelic_traced_amqp.rb +71 -33
  11. data/lib/hoodoo/services/discovery/discoverers/by_drb/by_drb.rb +13 -8
  12. data/lib/hoodoo/services/middleware/exception_reporting/reporters/airbrake_reporter.rb +8 -3
  13. data/lib/hoodoo/services/middleware/interaction.rb +1 -1
  14. data/lib/hoodoo/services/middleware/middleware.rb +52 -41
  15. data/lib/hoodoo/version.rb +2 -2
  16. data/spec/active/active_record/creator_spec.rb +1 -1
  17. data/spec/active/active_record/dated_spec.rb +7 -7
  18. data/spec/active/active_record/finder_spec.rb +953 -839
  19. data/spec/active/active_record/manually_dated_spec.rb +1 -1
  20. data/spec/active/active_record/search_helper_spec.rb +1 -1
  21. data/spec/active/active_record/secure_spec.rb +2 -2
  22. data/spec/active/active_record/support_spec.rb +3 -3
  23. data/spec/monkey/patch/datadog_traced_amqp_spec.rb +10 -2
  24. data/spec/monkey/patch/newrelic_traced_amqp_spec.rb +54 -21
  25. data/spec/new_relic/agent/logger.rb +24 -0
  26. data/spec/new_relic/agent/transaction.rb +32 -0
  27. data/spec/services/discovery/discoverers/by_drb/by_drb_spec.rb +48 -2
  28. data/spec/services/middleware/exception_reporting/reporters/airbrake_reporter_spec.rb +4 -4
  29. data/spec/services/middleware/middleware_multi_local_spec.rb +41 -13
  30. data/spec/services/middleware/middleware_multi_remote_spec.rb +93 -67
  31. data/spec/services/middleware/middleware_spec.rb +80 -7
  32. data/spec/services/services/interface_spec.rb +2 -2
  33. data/spec/transient_store/transient_store/mocks/redis_spec.rb +8 -6
  34. metadata +30 -26
@@ -63,7 +63,7 @@ module Hoodoo
63
63
  # +version+:: Passed to #discover_remote.
64
64
  # +options+:: Options hash as described below.
65
65
  #
66
- # Options keys are currently all required:
66
+ # Options keys are:
67
67
  #
68
68
  # +host+:: Host name as a string for location of service endpoint,
69
69
  # over HTTP (usually, local development is assumed).
@@ -72,20 +72,25 @@ module Hoodoo
72
72
  #
73
73
  # +path+:: Path on the above host and port of service endpoint.
74
74
  #
75
+ # If any are missing or +nil+, remote announcement is aborted and
76
+ # the return value is correspondingly +nil+.
77
+ #
75
78
  def announce_remote( resource, version, options = {} )
76
79
 
77
80
  host = options[ :host ]
78
81
  port = options[ :port ]
79
82
  path = options[ :path ]
80
83
 
81
- endpoint_uri_string = "http://#{ host }:#{ port }#{ path }"
84
+ endpoint_uri_string = unless host.nil? || port.nil? || path.nil?
85
+ "http://#{ host }:#{ port }#{ path }"
86
+ end
82
87
 
83
- # Announce our local services if we managed to find the host and port,
84
- # but no point otherwise; the values could be anything. In a 'guard'
85
- # based environment, first-run determines host and port but subsequent
86
- # runs do not - yet it stays the same, so it works out OK there.
88
+ # Announce our local services only if we have an endpoint URI. In a
89
+ # 'guard' based environment, first-run determines host and port but
90
+ # subsequent runs do not - yet it stays the same, so it works out
91
+ # OK there.
87
92
  #
88
- unless host.nil? || port.nil? || discover_remote( resource, version )
93
+ unless endpoint_uri_string.nil? || discover_remote( resource, version )
89
94
  drb_service().add( resource, version, endpoint_uri_string )
90
95
  end
91
96
 
@@ -157,7 +162,7 @@ module Hoodoo
157
162
  rescue DRb::DRbConnError
158
163
  if start_on_localhost_if_not_already_running
159
164
  script_path = File.join( File.dirname( __FILE__ ), 'drb_server_start.rb' )
160
- command = "bundle exec ruby '#{ script_path }'"
165
+ command = "#{ defined?( Bundler ) ? 'bundle exec ' : '' }ruby '#{ script_path }'"
161
166
  command << " --port #{ @drb_port }" unless @drb_port.nil? || @drb_port.empty?
162
167
 
163
168
  Process.detach( spawn( command ) )
@@ -27,7 +27,8 @@ module Hoodoo; module Services
27
27
  # require 'airbrake'
28
28
  #
29
29
  # Airbrake.configure do | config |
30
- # config.api_key = 'YOUR_AIRBRAKE_API_KEY'
30
+ # config.project_key = 'YOUR_AIRBRAKE_PROJECT_KEY'
31
+ # config.project_id = 'YOUR_AIRBRAKE_PROJECT_ID'
31
32
  # end
32
33
  #
33
34
  # Hoodoo::Services::Middleware::ExceptionReporting.add(
@@ -57,7 +58,11 @@ module Hoodoo; module Services
57
58
  opts = { :backtrace => Kernel.caller() }
58
59
  opts[ :rack_env ] = env unless env.nil?
59
60
 
60
- Airbrake.notify_or_ignore( e, opts )
61
+ # Since an ExceptionReporter is already a "slow communicatory",
62
+ # Hoodoo is using threads for behaviour; we don't need the async
63
+ # Airbrake mechanism to waste resources doing the same.
64
+ #
65
+ Airbrake.notify_sync( e, opts )
61
66
  end
62
67
 
63
68
  # Report an exception for errors that occur within a fully handled Rack
@@ -77,7 +82,7 @@ module Hoodoo; module Services
77
82
  :session => user_data_for( context ) || 'unknown'
78
83
  }
79
84
 
80
- Airbrake.notify_or_ignore( e, opts )
85
+ Airbrake.notify_sync( e, opts )
81
86
  end
82
87
  end
83
88
 
@@ -24,7 +24,7 @@ module Hoodoo; module Services; class Middleware
24
24
  #
25
25
  attr_reader :owning_middleware_instance
26
26
 
27
- # The inbound Rack request a Rack::Request instance.
27
+ # The inbound Rack request; a <tt>Rack::Request</tt> instance.
28
28
  #
29
29
  attr_reader :rack_request
30
30
 
@@ -12,6 +12,7 @@
12
12
  ########################################################################
13
13
 
14
14
  require 'set'
15
+ require 'cgi'
15
16
  require 'uri'
16
17
  require 'json'
17
18
  require 'benchmark'
@@ -186,6 +187,15 @@ module Hoodoo; module Services
186
187
  nil
187
188
  }
188
189
 
190
+ # A validation Proc for FRAMEWORK_QUERY_DATA - see that for details. This
191
+ # one ensures that the value is a valid UUID and evaluates to that UUID
192
+ # string if so.
193
+ #
194
+ FRAMEWORK_QUERY_VALUE_UUID_PROC = -> ( value ) {
195
+ value = Hoodoo::UUID.valid?( value ) && value
196
+ value || nil # => 'value' if 'value' is truthy, 'nil' if 'value' falsy
197
+ }
198
+
189
199
  # Out-of-box search and filter query keys. Interfaces can override the
190
200
  # support for these inside the Hoodoo::Services::Interface.to_list block
191
201
  # using Hoodoo::Services::Interface::ToListDSL.do_not_search and
@@ -216,6 +226,7 @@ module Hoodoo; module Services
216
226
  FRAMEWORK_QUERY_DATA = {
217
227
  'created_after' => FRAMEWORK_QUERY_VALUE_DATE_PROC,
218
228
  'created_before' => FRAMEWORK_QUERY_VALUE_DATE_PROC,
229
+ 'created_by' => FRAMEWORK_QUERY_VALUE_UUID_PROC
219
230
  }
220
231
 
221
232
  # Utility - returns the execution environment as a Rails-like environment
@@ -478,7 +489,6 @@ module Hoodoo; module Services
478
489
  # implementation Hoodoo::Services::Implementation subclass *instance* to
479
490
  # use on match
480
491
  #
481
- #
482
492
  @@services = service_container.component_interfaces.map do | interface |
483
493
 
484
494
  if interface.nil? || interface.endpoint.nil? || interface.implementation.nil?
@@ -620,10 +630,10 @@ module Hoodoo; module Services
620
630
  #
621
631
  # +version+:: Required implemented version for the endpoint. Integer.
622
632
  #
623
- # +interaction+:: The Hoodoo::Services::Interaction instance describing
624
- # the inbound call, the processing of which is leading to
625
- # a request for an inter-resource call by an endpoint
626
- # implementation.
633
+ # +interaction+:: The Hoodoo::Services::Middleware::Interaction instance
634
+ # describing the inbound call, the processing of which is
635
+ # leading to a request for an inter-resource call by an
636
+ # endpoint implementation.
627
637
  #
628
638
  def inter_resource_endpoint_for( resource, version, interaction )
629
639
  resource = resource.to_sym
@@ -720,11 +730,12 @@ module Hoodoo; module Services
720
730
  #
721
731
  # Named parameters are as follows:
722
732
  #
723
- # +source_interaction+:: A Hoodoo::Services::Interaction instance for the
724
- # inbound call which is being processed right now
725
- # by some resource endpoint implementation and this
726
- # implementation is now making an inter-resource
727
- # call as part of its processing;
733
+ # +source_interaction+:: A Hoodoo::Services::Middleware::Interaction
734
+ # instance for the inbound call which is being
735
+ # processed right now by some resource endpoint
736
+ # implementation and this implementation is now
737
+ # making an inter-resource call as part of its
738
+ # processing;
728
739
  #
729
740
  # +discovery_result+:: A Hoodoo::Services::Discovery::ForLocal instance
730
741
  # describing the target of the inter-resource call;
@@ -991,13 +1002,13 @@ module Hoodoo; module Services
991
1002
 
992
1003
  # Make an "inbound" call log based on the given interaction.
993
1004
  #
994
- # +interaction+:: Hoodoo::Services::Interaction describing the inbound
995
- # request. The +interaction_id+, +rack_request+ and
996
- # +session+ data is used (the latter being optional).
997
- # If +target_interface+ and +requested_action+ are
998
- # available, body data _might_ be logged according to
999
- # secure log settings in the interface; if these
1000
- # values are unset, body data is _not_ logged.
1005
+ # +interaction+:: Hoodoo::Services::Middleware::Interaction describing the
1006
+ # inbound request. The +interaction_id+, +rack_request+ and
1007
+ # +session+ data is used (the latter being optional). If
1008
+ # +target_interface+ and +requested_action+ are available,
1009
+ # body data _might_ be logged according to secure log
1010
+ # settings in the interface; if these values are unset,
1011
+ # body data is _not_ logged.
1001
1012
  #
1002
1013
  def monkey_log_inbound_request( interaction )
1003
1014
 
@@ -1181,12 +1192,12 @@ module Hoodoo; module Services
1181
1192
  # Build common log information for the 'data' part of a payload based
1182
1193
  # on the given interaction. Returned as a Hash with Symbol keys.
1183
1194
  #
1184
- # +interaction+:: Hoodoo::Services::Interaction describing a request.
1185
- # A +context+ and +interaction_id+ are expected. The
1186
- # +target_interface+ and +requested_action+ are optional
1187
- # and if present result in a <tt>:target</tt> entry in
1188
- # the returned Hash. The +context.session+ value if
1189
- # present will be included in a <tt>:session</tt> entry;
1195
+ # +interaction+:: Hoodoo::Services::Middleware::Interaction describing a
1196
+ # request. A +context+ and +interaction_id+ are expected.
1197
+ # The +target_interface+ and +requested_action+ are
1198
+ # optional and if present result in a <tt>:target</tt>
1199
+ # entry in the returned Hash. The +context.session+ value
1200
+ # if present will be included in a <tt>:session</tt> entry;
1190
1201
  # if verbose logging is enabled this will be quoted in
1191
1202
  # full, else only identity-related parts are recorded.
1192
1203
  #
@@ -1577,8 +1588,8 @@ module Hoodoo; module Services
1577
1588
  end
1578
1589
  end
1579
1590
 
1580
- host = @@recorded_host if host.nil? && defined?( @@recorded_host )
1581
- port = @@recorded_port if port.nil? && defined?( @@recorded_port )
1591
+ host ||= @@recorded_host if defined?( @@recorded_host )
1592
+ port ||= @@recorded_port if defined?( @@recorded_port )
1582
1593
 
1583
1594
  # Under test, ensure a simulation of an available host and port is
1584
1595
  # always available for discovery-related tests.
@@ -1588,23 +1599,23 @@ module Hoodoo; module Services
1588
1599
  port ||= '9292'
1589
1600
  end
1590
1601
 
1591
- # Announce the resource endpoints unless we are still missing a host
1592
- # or port. Implication is 'racksh'.
1602
+ # Announce the resource endpoints. We might not be able to annouce
1603
+ # the remote availability of this endpoint if the host/port are not
1604
+ # determined; but that might just be because we are running under
1605
+ # "racksh" and we wouldn't want to announce remotely anyway.
1593
1606
 
1594
- unless host.nil? || port.nil?
1595
- services.each do | service |
1596
- interface = service.interface_class
1607
+ services.each do | service |
1608
+ interface = service.interface_class
1597
1609
 
1598
- @discoverer.announce(
1599
- interface.resource,
1600
- interface.version,
1601
- {
1602
- :host => host,
1603
- :port => port,
1604
- :path => service.base_path
1605
- }
1606
- )
1607
- end
1610
+ @discoverer.announce(
1611
+ interface.resource,
1612
+ interface.version,
1613
+ {
1614
+ :host => host,
1615
+ :port => port,
1616
+ :path => service.base_path
1617
+ }
1618
+ )
1608
1619
  end
1609
1620
  end
1610
1621
  end
@@ -1752,7 +1763,7 @@ module Hoodoo; module Services
1752
1763
  # We try the custom routing path first, then the de facto path, then
1753
1764
  # give up if neither match.
1754
1765
 
1755
- uri_path = CGI.unescape( interaction.rack_request.path() )
1766
+ uri_path = ::CGI.unescape( interaction.rack_request.path() )
1756
1767
 
1757
1768
  selected_path_data = nil
1758
1769
  selected_services = @@services.select do | service_data |
@@ -12,11 +12,11 @@ module Hoodoo
12
12
  # The Hoodoo gem version. If this changes, be sure to re-run
13
13
  # <tt>bundle install</tt> or <tt>bundle update</tt>.
14
14
  #
15
- VERSION = '1.19.0'
15
+ VERSION = '2.0.0'
16
16
 
17
17
  # The Hoodoo gem date. If this changes, be sure to re-run
18
18
  # <tt>bundle install</tt> or <tt>bundle update</tt>.
19
19
  #
20
- DATE = '2017-08-17'
20
+ DATE = '2017-10-13'
21
21
 
22
22
  end
@@ -8,7 +8,7 @@ describe Hoodoo::ActiveRecord::Creator do
8
8
  t.text :code
9
9
  t.text :field_one
10
10
 
11
- t.timestamps
11
+ t.timestamps :null => true
12
12
  end
13
13
  end
14
14
 
@@ -9,7 +9,7 @@ describe Hoodoo::ActiveRecord::Dated do
9
9
  ActiveRecord::Migration.create_table( :r_spec_model_effective_date_tests, :id => false ) do | t |
10
10
  t.text :id, :null => false
11
11
  t.text :data
12
- t.timestamps
12
+ t.timestamps :null => true
13
13
  end
14
14
 
15
15
  ActiveRecord::Migration.create_table( :r_spec_model_effective_date_tests_history_entries, :id => false ) do | t |
@@ -18,7 +18,7 @@ describe Hoodoo::ActiveRecord::Dated do
18
18
  t.text :data
19
19
  t.datetime :effective_start, :null => false
20
20
  t.datetime :effective_end, :null => false
21
- t.timestamps
21
+ t.timestamps :null => true
22
22
  end
23
23
 
24
24
  class RSpecModelEffectiveDateTest < ActiveRecord::Base
@@ -29,7 +29,7 @@ describe Hoodoo::ActiveRecord::Dated do
29
29
  ActiveRecord::Migration.create_table( :r_spec_model_effective_date_test_overrides, :id => false ) do | t |
30
30
  t.text :id, :null => false
31
31
  t.text :data
32
- t.timestamps
32
+ t.timestamps :null => true
33
33
  end
34
34
 
35
35
  ActiveRecord::Migration.create_table( :r_spec_model_effective_date_history_entries, :id => false ) do | t |
@@ -38,7 +38,7 @@ describe Hoodoo::ActiveRecord::Dated do
38
38
  t.text :data
39
39
  t.datetime :effective_start, :null => false
40
40
  t.datetime :effective_end, :null => false
41
- t.timestamps
41
+ t.timestamps :null => true
42
42
  end
43
43
 
44
44
  class RSpecModelEffectiveDateTestOverride < ActiveRecord::Base
@@ -299,7 +299,7 @@ describe Hoodoo::ActiveRecord::Dated do
299
299
  context "SQL and column selections" do
300
300
  before :each do
301
301
  @now = Time.now.utc
302
- @safe_now = RSpecModelEffectiveDateTestOverride.sanitize( @now )
302
+ @safe_now = RSpecModelEffectiveDateTestOverride.connection.quoted_date( @now )
303
303
 
304
304
  request = Hoodoo::Services::Request.new
305
305
  @context = Hoodoo::Services::Context.new( nil, request, nil, nil )
@@ -309,8 +309,8 @@ describe Hoodoo::ActiveRecord::Dated do
309
309
 
310
310
  def run_other_expectations( sql )
311
311
  expect( sql ).to include( "from r_spec_model_effective_date_history_entries" )
312
- expect( sql ).to include( "\"effective_start\" <= #{ @safe_now }" )
313
- expect( sql ).to include( "\"effective_end\" > #{ @safe_now }" )
312
+ expect( sql ).to include( "\"effective_start\" <= '#{ @safe_now }'" )
313
+ expect( sql ).to include( "\"effective_end\" > '#{ @safe_now }'" )
314
314
  expect( sql ).to include( "\"effective_end\" is null" )
315
315
  end
316
316
 
@@ -1,7 +1,14 @@
1
1
  require 'spec_helper'
2
2
  require 'active_record'
3
3
 
4
- describe Hoodoo::ActiveRecord::Finder do
4
+ # The "counting" tests must run first and in-order internally, else e.g. an
5
+ # ANALYZE might happen before the pre-ANALYZE test, breaking the results.
6
+ # Other tests that create objects in the table can cause the estimated count
7
+ # to shift away from initial expectations too, so this test is run early.
8
+ # All other tests are wrapped in a giant context that allows for random
9
+ # ordering to be preserved there.
10
+ #
11
+ describe Hoodoo::ActiveRecord::Finder, :order => :defined do
5
12
  before :all do
6
13
  spec_helper_silence_stdout() do
7
14
  ActiveRecord::Migration.create_table( :r_spec_model_finder_tests, :id => false ) do | t |
@@ -12,7 +19,8 @@ describe Hoodoo::ActiveRecord::Finder do
12
19
  t.text :field_two
13
20
  t.text :field_three
14
21
 
15
- t.timestamps
22
+ t.timestamps :null => true
23
+ t.text :created_by
16
24
  end
17
25
  end
18
26
 
@@ -79,7 +87,8 @@ describe Hoodoo::ActiveRecord::Finder do
79
87
  :wild_field_one => sh.ciaw_match_generic( 'field_one '),
80
88
  :field_two => sh.cs_match_csv(),
81
89
  'field_three' => sh.cs_match_array(),
82
- 'created_after' => sh.cs_gte( 'updated_at' )
90
+ 'created_after' => sh.cs_gte( 'updated_at' ), # Deliberate framework override
91
+ 'created_by' => sh.ci_match_generic( 'code' ) # Deliberate framework override
83
92
  }
84
93
 
85
94
  search_with( search_and_filter_map )
@@ -118,7 +127,9 @@ describe Hoodoo::ActiveRecord::Finder do
118
127
  end
119
128
 
120
129
  before :each do
121
- @tn = Time.now.round()
130
+ @tn = Time.now.round()
131
+ @cb1 = Hoodoo::UUID.generate()
132
+ @cb2 = Hoodoo::UUID.generate()
122
133
 
123
134
  @a = RSpecModelFinderTest.new
124
135
  @a.id = "one"
@@ -128,6 +139,7 @@ describe Hoodoo::ActiveRecord::Finder do
128
139
  @a.field_three = 'three a'
129
140
  @a.created_at = @tn - 1.year
130
141
  @a.updated_at = @tn - 1.month
142
+ @a.created_by = @cb1
131
143
  @a.save!
132
144
  @id = @a.id
133
145
 
@@ -140,6 +152,7 @@ describe Hoodoo::ActiveRecord::Finder do
140
152
  @b.field_three = 'three b'
141
153
  @b.created_at = @tn - 1.month
142
154
  @b.updated_at = @tn - 1.week
155
+ @b.created_by = @cb1
143
156
  @b.save!
144
157
  @uuid = @b.uuid
145
158
 
@@ -151,6 +164,7 @@ describe Hoodoo::ActiveRecord::Finder do
151
164
  @c.field_three = 'three c'
152
165
  @c.created_at = @tn
153
166
  @c.updated_at = @tn + 1.day
167
+ @c.created_by = @cb2
154
168
  @c.save!
155
169
  @code = @c.code
156
170
 
@@ -191,700 +205,692 @@ describe Hoodoo::ActiveRecord::Finder do
191
205
 
192
206
  # ==========================================================================
193
207
 
194
- context '#scoped_in' do
195
- before :each do
208
+ context "(ordered)" do
209
+ context 'counting' do
210
+ it 'lists with a normal count' do
211
+ finder = RSpecModelFinderTest.list( @list_params )
196
212
 
197
- # Get a good-enough-for-test interaction which has a context
198
- # that contains a Session we can modify.
213
+ expect( finder ).to receive( :dataset_size ).at_least( :once ).and_call_original
214
+ expect( finder ).to receive( :count ).at_least( :once ).and_call_original
199
215
 
200
- @interaction = Hoodoo::Services::Middleware::Interaction.new( {}, nil )
201
- @interaction.context = Hoodoo::Services::Context.new(
202
- Hoodoo::Services::Session.new,
203
- @interaction.context.request,
204
- @interaction.context.response,
205
- @interaction
206
- )
216
+ expect( finder ).to_not receive( :estimated_dataset_size )
217
+ expect( finder ).to_not receive( :estimated_count )
207
218
 
208
- @context = @interaction.context
209
- @session = @interaction.context.session
210
- end
219
+ result = finder.dataset_size()
211
220
 
212
- # If security scoping works _and_ we know that it called #full_scope_for
213
- # in the "internal"-ish support API, then we consider that good enough
214
- # to prove that it's calling the scope engine and that engine has its
215
- # own comprehensive test coverage in suport_spec.rb.
216
- #
217
- it 'generates appropriate scope' do
218
- @session.scoping = { :authorised_uuids => [ 'uuid 1', 'uuid 2' ], :authorised_code => 'code 1' }
221
+ expect( result ).to_not be_nil
222
+ end
219
223
 
220
- expect( Hoodoo::ActiveRecord::Support ).to(
221
- receive( :full_scope_for ).once().with(
222
- RSpecModelFinderTest, @context
223
- ).and_call_original()
224
- )
224
+ it 'lists with an estimated count' do
225
+ finder = RSpecModelFinderTest.list( @list_params )
225
226
 
226
- sql = RSpecModelFinderTest.scoped_in( @context ).to_sql
227
+ expect( finder ).to_not receive( :dataset_size )
227
228
 
228
- expect( sql ).to eq( "SELECT \"r_spec_model_finder_tests\".* " \
229
- "FROM \"r_spec_model_finder_tests\" " \
230
- "WHERE " \
231
- "\"r_spec_model_finder_tests\".\"uuid\" IN ('uuid 1', 'uuid 2') AND " \
232
- "\"r_spec_model_finder_tests\".\"code\" = 'code 1'" )
233
- end
234
- end
229
+ expect( finder ).to receive( :estimated_dataset_size ).at_least( :once ).and_call_original
230
+ expect( finder ).to receive( :estimated_count ).at_least( :once ).and_call_original
231
+ expect( finder ).to receive( :count ).at_least( :once ).and_call_original
235
232
 
236
- # ==========================================================================
237
-
238
- context 'acquisition scope and overrides' do
239
- def expect_sql( sql, id_attr_name )
240
- expect( sql ).to eq( "SELECT \"r_spec_model_finder_tests\".* " \
241
- "FROM \"r_spec_model_finder_tests\" " \
242
- "WHERE (" \
243
- "(" \
244
- "\"r_spec_model_finder_tests\".\"#{ id_attr_name }\" = '#{ @id }' OR " \
245
- "\"r_spec_model_finder_tests\".\"uuid\" = '#{ @id }'" \
246
- ") OR " \
247
- "\"r_spec_model_finder_tests\".\"code\" = '#{ @id }'" \
248
- ")" )
249
- end
233
+ result = finder.estimated_dataset_size
250
234
 
251
- context '#acquisition_scope' do
252
- it 'SQL generation is as expected' do
253
- sql = RSpecModelFinderTest.acquisition_scope( @id ).to_sql()
254
- expect_sql( sql, 'id' )
235
+ expect( result ).to_not be_nil
255
236
  end
256
- end
257
237
 
258
- context '#acquire_with_id_substitute' do
259
- before :each do
260
- @alt_attr_name = 'foo'
261
- RSpecModelFinderTest.acquire_with_id_substitute( @alt_attr_name )
262
- end
238
+ context 'RDoc-recommended PostgreSQL migration example' do
239
+ before :each do
240
+ ActiveRecord::Base.connection.execute <<-SQL
241
+ CREATE FUNCTION estimated_count(query text) RETURNS integer AS
242
+ $func$
243
+ DECLARE
244
+ rec record;
245
+ rows integer;
246
+ BEGIN
247
+ FOR rec IN EXECUTE 'EXPLAIN ' || query LOOP
248
+ rows := substring(rec."QUERY PLAN" FROM ' rows=([[:digit:]]+)');
249
+ EXIT WHEN rows IS NOT NULL;
250
+ END LOOP;
251
+
252
+ RETURN rows;
253
+ END
254
+ $func$ LANGUAGE plpgsql;
255
+ SQL
256
+
257
+ counter = Proc.new do | sql |
258
+ begin
259
+ ActiveRecord::Base.connection.execute(
260
+ "SELECT estimated_count('#{ sql}')"
261
+ ).first[ 'estimated_count' ].to_i
262
+ rescue
263
+ nil
264
+ end
265
+ end
263
266
 
264
- after :each do
265
- RSpecModelFinderTest.acquire_with_id_substitute( 'id' )
266
- end
267
+ RSpecModelFinderTest.estimate_counts_with( counter )
267
268
 
268
- it 'SQL generation is as expected' do
269
- sql = RSpecModelFinderTest.acquisition_scope( @id ).to_sql()
270
- expect_sql( sql, @alt_attr_name )
271
- end
272
- end
273
- end
269
+ # Tests start by ensuring the database knows about the current
270
+ # object count.
271
+ #
272
+ ActiveRecord::Base.connection.execute( 'ANALYZE' )
273
+ end
274
274
 
275
- # ==========================================================================
275
+ after :each do
276
+ ActiveRecord::Base.connection.execute "DROP FUNCTION estimated_count(query text);"
277
+ RSpecModelFinderTest.estimate_counts_with( nil )
278
+ end
276
279
 
277
- context '#acquire' do
278
- it 'finds from the class' do
279
- found = RSpecModelFinderTest.acquire( @id )
280
- expect( found ).to eq(@a)
280
+ context 'estimate' do
281
+ before :each do
282
+ @initial_count = RSpecModelFinderTest.count
281
283
 
282
- found = RSpecModelFinderTest.acquire( @uuid )
283
- expect( found ).to eq(@b)
284
+ # The outer 'before' code ensures an accurate initial count of 3,
285
+ # but we're going add in a few more unestimated items.
286
+ #
287
+ @uncounted1 = RSpecModelFinderTest.new.save!
288
+ @uncounted2 = RSpecModelFinderTest.new.save!
289
+ @uncounted3 = RSpecModelFinderTest.new.save!
284
290
 
285
- found = RSpecModelFinderTest.acquire( @code )
286
- expect( found ).to eq(@c)
287
- end
291
+ @subsequent_accurate_count = RSpecModelFinderTest.count
292
+ end
288
293
 
289
- it 'finds with a chain' do
290
- finder = RSpecModelFinderTest.where( :field_one => 'group 1' )
294
+ it 'may be initially inaccurate' do
295
+ finder = RSpecModelFinderTest.list( @list_params )
296
+ result = finder.estimated_dataset_size
297
+ expect( result ).to eq( @initial_count ).or( eq( @subsequent_accurate_count ) )
298
+ end
291
299
 
292
- found = finder.acquire( @id )
293
- expect( found ).to eq(@a)
300
+ # The outer 'before' code kind of already tests this anyway since if
301
+ # the analyze call therein didn't work, prerequisites in the tests
302
+ # would be wrong and other tests would fail. It's useful to
303
+ # double-check something this important though.
304
+ #
305
+ it 'is accurate after ANALYZE' do
306
+ ActiveRecord::Base.connection.execute( 'ANALYZE' )
294
307
 
295
- found = finder.acquire( @uuid )
296
- expect( found ).to eq(@b)
308
+ finder = RSpecModelFinderTest.list( @list_params )
309
+ result = finder.estimated_dataset_size
310
+ expect( result ).to eq( @subsequent_accurate_count )
311
+ end
297
312
 
298
- found = finder.acquire( @code )
299
- expect( found ).to eq(nil) # Not in 'group 1'
313
+ it 'is "nil" if the Proc evaluates thus' do
314
+ RSpecModelFinderTest.estimate_counts_with( Proc.new() { | sql | nil } )
315
+ finder = RSpecModelFinderTest.list( @list_params )
316
+ result = finder.estimated_dataset_size
317
+ expect( result ).to be_nil
318
+ end
319
+ end
320
+ end
300
321
  end
322
+ end
301
323
 
302
- # Early versions of the 'acquire'-backed methods always inadvertently
303
- # performed two database calls, via a count then a true find. This was
304
- # refactored to only make one call per attribute, but that in turn can
305
- # be much improved via the AREL table to compose a single query that
306
- # uses "OR" to get the database to check each attribute in order. Thus
307
- # every test below expects exactly one database call only.
308
- #
309
- context 'only makes one database call when' do
324
+ # ==========================================================================
310
325
 
311
- it 'finding on the first attribute' do
312
- count = spec_helper_count_database_calls_in do
313
- found = RSpecModelFinderTest.acquire( @id )
314
- expect( found ).to eq(@a)
315
- end
326
+ context "(randomised)", :order => :random do
327
+ context '#scoped_in' do
328
+ before :each do
316
329
 
317
- expect( count ).to eq( 1 )
318
- end
330
+ # Get a good-enough-for-test interaction which has a context
331
+ # that contains a Session we can modify.
319
332
 
320
- it 'finding on the second attribute' do
321
- count = spec_helper_count_database_calls_in do
322
- found = RSpecModelFinderTest.acquire( @uuid )
323
- expect( found ).to eq(@b)
324
- end
333
+ @interaction = Hoodoo::Services::Middleware::Interaction.new( {}, nil )
334
+ @interaction.context = Hoodoo::Services::Context.new(
335
+ Hoodoo::Services::Session.new,
336
+ @interaction.context.request,
337
+ @interaction.context.response,
338
+ @interaction
339
+ )
325
340
 
326
- expect( count ).to eq( 1 )
341
+ @context = @interaction.context
342
+ @session = @interaction.context.session
327
343
  end
328
344
 
329
- it 'finding on the third attribute' do
330
- count = spec_helper_count_database_calls_in do
331
- found = RSpecModelFinderTest.acquire( @code )
332
- expect( found ).to eq(@c)
333
- end
345
+ # If security scoping works _and_ we know that it called #full_scope_for
346
+ # in the "internal"-ish support API, then we consider that good enough
347
+ # to prove that it's calling the scope engine and that engine has its
348
+ # own comprehensive test coverage in suport_spec.rb.
349
+ #
350
+ it 'generates appropriate scope' do
351
+ @session.scoping = { :authorised_uuids => [ 'uuid 1', 'uuid 2' ], :authorised_code => 'code 1' }
352
+
353
+ expect( Hoodoo::ActiveRecord::Support ).to(
354
+ receive( :full_scope_for ).once().with(
355
+ RSpecModelFinderTest, @context
356
+ ).and_call_original()
357
+ )
358
+
359
+ sql = RSpecModelFinderTest.scoped_in( @context ).to_sql
360
+
361
+ expect( sql ).to eq( "SELECT \"r_spec_model_finder_tests\".* " \
362
+ "FROM \"r_spec_model_finder_tests\" " \
363
+ "WHERE " \
364
+ "\"r_spec_model_finder_tests\".\"uuid\" IN ('uuid 1', 'uuid 2') AND " \
365
+ "\"r_spec_model_finder_tests\".\"code\" = 'code 1'" )
366
+ end
367
+ end
334
368
 
335
- expect( count ).to eq( 1 )
369
+ # ========================================================================
370
+
371
+ context 'acquisition scope and overrides' do
372
+ def expect_sql( sql, id_attr_name )
373
+ expect( sql ).to eq( "SELECT \"r_spec_model_finder_tests\".* " \
374
+ "FROM \"r_spec_model_finder_tests\" " \
375
+ "WHERE (" \
376
+ "(" \
377
+ "\"r_spec_model_finder_tests\".\"#{ id_attr_name }\" = '#{ @id }' OR " \
378
+ "\"r_spec_model_finder_tests\".\"uuid\" = '#{ @id }'" \
379
+ ") OR " \
380
+ "\"r_spec_model_finder_tests\".\"code\" = '#{ @id }'" \
381
+ ")" )
336
382
  end
337
383
 
338
- it 'checking all three attributes but finding nothing' do
339
- count = spec_helper_count_database_calls_in do
340
- found = RSpecModelFinderTest.acquire( Hoodoo::UUID.generate )
341
- expect( found ).to be_nil
384
+ context '#acquisition_scope' do
385
+ it 'SQL generation is as expected' do
386
+ sql = RSpecModelFinderTest.acquisition_scope( @id ).to_sql()
387
+ expect_sql( sql, 'id' )
342
388
  end
343
-
344
- expect( count ).to eq( 1 )
345
389
  end
346
- end
347
- end
348
390
 
349
- # ==========================================================================
391
+ context '#acquire_with_id_substitute' do
392
+ before :each do
393
+ @alt_attr_name = 'foo'
394
+ RSpecModelFinderTest.acquire_with_id_substitute( @alt_attr_name )
395
+ end
350
396
 
351
- context '#acquire_in' do
352
- before :each do
353
- @scoped_1 = RSpecModelFinderTest.new
354
- @scoped_1.id = 'id 1'
355
- @scoped_1.uuid = 'uuid 1'
356
- @scoped_1.code = 'code 1'
357
- @scoped_1.field_one = 'scoped 1'
358
- @scoped_1.save!
359
-
360
- @scoped_2 = RSpecModelFinderTest.new
361
- @scoped_2.id = 'id 2'
362
- @scoped_2.uuid = 'uuid 1'
363
- @scoped_2.code = 'code 2'
364
- @scoped_2.field_one = 'scoped 2'
365
- @scoped_2.save!
366
-
367
- @scoped_3 = RSpecModelFinderTest.new
368
- @scoped_3.id = 'id 3'
369
- @scoped_3.uuid = 'uuid 2'
370
- @scoped_3.code = 'code 2'
371
- @scoped_3.field_one = 'scoped 3'
372
- @scoped_3.save!
373
-
374
- # Get a good-enough-for-test interaction which has a context
375
- # that contains a Session we can modify.
376
-
377
- @interaction = Hoodoo::Services::Middleware::Interaction.new( {}, nil )
378
- @interaction.context = Hoodoo::Services::Context.new(
379
- Hoodoo::Services::Session.new,
380
- @interaction.context.request,
381
- @interaction.context.response,
382
- @interaction
383
- )
397
+ after :each do
398
+ RSpecModelFinderTest.acquire_with_id_substitute( 'id' )
399
+ end
384
400
 
385
- @context = @interaction.context
386
- @session = @interaction.context.session
401
+ it 'SQL generation is as expected' do
402
+ sql = RSpecModelFinderTest.acquisition_scope( @id ).to_sql()
403
+ expect_sql( sql, @alt_attr_name )
404
+ end
405
+ end
387
406
  end
388
407
 
389
- it 'knowns how to acquire' do
390
-
391
- # Note the corresponding 'acquire_with' used Symbols and had a
392
- # duplicated entry - we expect Strings and no duplicates here.
393
- #
394
- expect( RSpecModelFinderTest.acquired_with() ).to eq( [ 'uuid', 'code' ] )
395
-
396
- end
408
+ # ========================================================================
397
409
 
398
- it 'finds with secure scopes from the class' do
399
- @session.scoping = { :authorised_uuids => [ 'uuid 1' ], :authorised_code => 'code 1' }
410
+ context '#acquire' do
411
+ it 'finds from the class' do
412
+ found = RSpecModelFinderTest.acquire( @id )
413
+ expect( found ).to eq(@a)
400
414
 
401
- @context.request.uri_path_components = [ @scoped_1.id ]
402
- found = RSpecModelFinderTest.acquire_in( @context )
403
- expect( found ).to eq( @scoped_1 )
415
+ found = RSpecModelFinderTest.acquire( @uuid )
416
+ expect( found ).to eq(@b)
404
417
 
405
- @context.request.uri_path_components = [ @scoped_2.id ]
406
- found = RSpecModelFinderTest.acquire_in( @context )
407
- expect( found ).to be_nil
418
+ found = RSpecModelFinderTest.acquire( @code )
419
+ expect( found ).to eq(@c)
420
+ end
408
421
 
409
- @context.request.uri_path_components = [ @scoped_3.id ]
410
- found = RSpecModelFinderTest.acquire_in( @context )
411
- expect( found ).to be_nil
422
+ it 'finds with a chain' do
423
+ finder = RSpecModelFinderTest.where( :field_one => 'group 1' )
412
424
 
413
- @session.scoping.authorised_code = 'code 2'
425
+ found = finder.acquire( @id )
426
+ expect( found ).to eq(@a)
414
427
 
415
- @context.request.uri_path_components = [ @scoped_1.id ]
416
- found = RSpecModelFinderTest.acquire_in( @context )
417
- expect( found ).to be_nil
428
+ found = finder.acquire( @uuid )
429
+ expect( found ).to eq(@b)
418
430
 
419
- @context.request.uri_path_components = [ @scoped_2.id ]
420
- found = RSpecModelFinderTest.acquire_in( @context )
421
- expect( found ).to eq( @scoped_2 )
431
+ found = finder.acquire( @code )
432
+ expect( found ).to eq(nil) # Not in 'group 1'
433
+ end
422
434
 
423
- @context.request.uri_path_components = [ @scoped_3.id ]
424
- found = RSpecModelFinderTest.acquire_in( @context )
425
- expect( found ).to be_nil
435
+ # Early versions of the 'acquire'-backed methods always inadvertently
436
+ # performed two database calls, via a count then a true find. This was
437
+ # refactored to only make one call per attribute, but that in turn can
438
+ # be much improved via the AREL table to compose a single query that
439
+ # uses "OR" to get the database to check each attribute in order. Thus
440
+ # every test below expects exactly one database call only.
441
+ #
442
+ context 'only makes one database call when' do
426
443
 
427
- @session.scoping.authorised_uuids = [ 'uuid 2' ]
444
+ it 'finding on the first attribute' do
445
+ count = spec_helper_count_database_calls_in do
446
+ found = RSpecModelFinderTest.acquire( @id )
447
+ expect( found ).to eq(@a)
448
+ end
428
449
 
429
- @context.request.uri_path_components = [ @scoped_1.id ]
430
- found = RSpecModelFinderTest.acquire_in( @context )
431
- expect( found ).to be_nil
450
+ expect( count ).to eq( 1 )
451
+ end
432
452
 
433
- @context.request.uri_path_components = [ @scoped_2.id ]
434
- found = RSpecModelFinderTest.acquire_in( @context )
435
- expect( found ).to be_nil
453
+ it 'finding on the second attribute' do
454
+ count = spec_helper_count_database_calls_in do
455
+ found = RSpecModelFinderTest.acquire( @uuid )
456
+ expect( found ).to eq(@b)
457
+ end
436
458
 
437
- @context.request.uri_path_components = [ @scoped_3.id ]
438
- found = RSpecModelFinderTest.acquire_in( @context )
439
- expect( found ).to eq( @scoped_3 )
459
+ expect( count ).to eq( 1 )
460
+ end
440
461
 
441
- @session.scoping.authorised_uuids = [ 'uuid 1', 'uuid 2' ]
462
+ it 'finding on the third attribute' do
463
+ count = spec_helper_count_database_calls_in do
464
+ found = RSpecModelFinderTest.acquire( @code )
465
+ expect( found ).to eq(@c)
466
+ end
442
467
 
443
- @context.request.uri_path_components = [ @scoped_1.id ]
444
- found = RSpecModelFinderTest.acquire_in( @context )
445
- expect( found ).to be_nil
468
+ expect( count ).to eq( 1 )
469
+ end
446
470
 
447
- @context.request.uri_path_components = [ @scoped_2.id ]
448
- found = RSpecModelFinderTest.acquire_in( @context )
449
- expect( found ).to eq( @scoped_2 )
471
+ it 'checking all three attributes but finding nothing' do
472
+ count = spec_helper_count_database_calls_in do
473
+ found = RSpecModelFinderTest.acquire( Hoodoo::UUID.generate )
474
+ expect( found ).to be_nil
475
+ end
450
476
 
451
- @context.request.uri_path_components = [ @scoped_3.id ]
452
- found = RSpecModelFinderTest.acquire_in( @context )
453
- expect( found ).to eq( @scoped_3 )
477
+ expect( count ).to eq( 1 )
478
+ end
479
+ end
454
480
  end
455
481
 
456
- it 'finds with secure scopes with a chain' do
457
- @session.scoping = { :authorised_uuids => [ 'uuid 1' ], :authorised_code => 'code 1' }
482
+ # ========================================================================
458
483
 
459
- @context.request.uri_path_components = [ @scoped_1.id ]
460
- found = RSpecModelFinderTest.where( :field_one => @scoped_1.field_one ).acquire_in( @context )
461
- expect( found ).to eq( @scoped_1 )
484
+ context '#acquire_in' do
485
+ before :each do
486
+ @scoped_1 = RSpecModelFinderTest.new
487
+ @scoped_1.id = 'id 1'
488
+ @scoped_1.uuid = 'uuid 1'
489
+ @scoped_1.code = 'code 1'
490
+ @scoped_1.field_one = 'scoped 1'
491
+ @scoped_1.save!
492
+
493
+ @scoped_2 = RSpecModelFinderTest.new
494
+ @scoped_2.id = 'id 2'
495
+ @scoped_2.uuid = 'uuid 1'
496
+ @scoped_2.code = 'code 2'
497
+ @scoped_2.field_one = 'scoped 2'
498
+ @scoped_2.save!
499
+
500
+ @scoped_3 = RSpecModelFinderTest.new
501
+ @scoped_3.id = 'id 3'
502
+ @scoped_3.uuid = 'uuid 2'
503
+ @scoped_3.code = 'code 2'
504
+ @scoped_3.field_one = 'scoped 3'
505
+ @scoped_3.save!
506
+
507
+ # Get a good-enough-for-test interaction which has a context
508
+ # that contains a Session we can modify.
509
+
510
+ @interaction = Hoodoo::Services::Middleware::Interaction.new( {}, nil )
511
+ @interaction.context = Hoodoo::Services::Context.new(
512
+ Hoodoo::Services::Session.new,
513
+ @interaction.context.request,
514
+ @interaction.context.response,
515
+ @interaction
516
+ )
517
+
518
+ @context = @interaction.context
519
+ @session = @interaction.context.session
520
+ end
462
521
 
463
- @context.request.uri_path_components = [ @scoped_1.id ]
464
- found = RSpecModelFinderTest.where( :field_one => @scoped_1.field_one + '!' ).acquire_in( @context )
465
- expect( found ).to be_nil
522
+ it 'knowns how to acquire' do
466
523
 
467
- @context.request.uri_path_components = [ @scoped_2.id ]
468
- found = RSpecModelFinderTest.where( :field_one => @scoped_2.field_one ).acquire_in( @context )
469
- expect( found ).to be_nil
524
+ # Note the corresponding 'acquire_with' used Symbols and had a
525
+ # duplicated entry - we expect Strings and no duplicates here.
526
+ #
527
+ expect( RSpecModelFinderTest.acquired_with() ).to eq( [ 'uuid', 'code' ] )
470
528
 
471
- @context.request.uri_path_components = [ @scoped_3.id ]
472
- found = RSpecModelFinderTest.where( :field_one => @scoped_3.field_one ).acquire_in( @context )
473
- expect( found ).to be_nil
529
+ end
474
530
 
475
- @session.scoping.authorised_uuids = [ 'uuid 1', 'uuid 2' ]
476
- @session.scoping.authorised_code = 'code 2'
531
+ it 'finds with secure scopes from the class' do
532
+ @session.scoping = { :authorised_uuids => [ 'uuid 1' ], :authorised_code => 'code 1' }
477
533
 
478
- @context.request.uri_path_components = [ @scoped_1.id ]
479
- found = RSpecModelFinderTest.where( :field_one => @scoped_1.field_one ).acquire_in( @context )
480
- expect( found ).to be_nil
534
+ @context.request.uri_path_components = [ @scoped_1.id ]
535
+ found = RSpecModelFinderTest.acquire_in( @context )
536
+ expect( found ).to eq( @scoped_1 )
481
537
 
482
- @context.request.uri_path_components = [ @scoped_2.id ]
483
- found = RSpecModelFinderTest.where( :field_one => @scoped_2.field_one ).acquire_in( @context )
484
- expect( found ).to eq( @scoped_2 )
538
+ @context.request.uri_path_components = [ @scoped_2.id ]
539
+ found = RSpecModelFinderTest.acquire_in( @context )
540
+ expect( found ).to be_nil
485
541
 
486
- @context.request.uri_path_components = [ @scoped_3.id ]
487
- found = RSpecModelFinderTest.where( :field_one => @scoped_3.field_one ).acquire_in( @context )
488
- expect( found ).to eq( @scoped_3 )
542
+ @context.request.uri_path_components = [ @scoped_3.id ]
543
+ found = RSpecModelFinderTest.acquire_in( @context )
544
+ expect( found ).to be_nil
489
545
 
490
- @context.request.uri_path_components = [ @scoped_3.id ]
491
- found = RSpecModelFinderTest.where( :field_one => @scoped_3.field_one + '!' ).acquire_in( @context )
492
- expect( found ).to be_nil
493
- end
494
- end
546
+ @session.scoping.authorised_code = 'code 2'
495
547
 
496
- # ==========================================================================
548
+ @context.request.uri_path_components = [ @scoped_1.id ]
549
+ found = RSpecModelFinderTest.acquire_in( @context )
550
+ expect( found ).to be_nil
497
551
 
498
- context '#list' do
499
- it 'lists with pages, offsets and counts' do
500
- expect_any_instance_of( RSpecModelFinderTest ).to_not receive( :estimated_dataset_size )
552
+ @context.request.uri_path_components = [ @scoped_2.id ]
553
+ found = RSpecModelFinderTest.acquire_in( @context )
554
+ expect( found ).to eq( @scoped_2 )
501
555
 
502
- @list_params.offset = 1 # 0 is first record
503
- @list_params.limit = 1
556
+ @context.request.uri_path_components = [ @scoped_3.id ]
557
+ found = RSpecModelFinderTest.acquire_in( @context )
558
+ expect( found ).to be_nil
504
559
 
505
- finder = RSpecModelFinderTest.order( :field_three => :asc ).list( @list_params )
506
- expect( finder ).to eq([@b])
507
- expect( finder.dataset_size).to eq(3)
560
+ @session.scoping.authorised_uuids = [ 'uuid 2' ]
508
561
 
509
- @list_params.offset = 1
510
- @list_params.limit = 2
562
+ @context.request.uri_path_components = [ @scoped_1.id ]
563
+ found = RSpecModelFinderTest.acquire_in( @context )
564
+ expect( found ).to be_nil
511
565
 
512
- finder = RSpecModelFinderTest.order( :field_three => :asc ).list( @list_params )
513
- expect( finder ).to eq([@b, @c])
514
- expect( finder.dataset_size).to eq(3)
515
- end
516
- end
566
+ @context.request.uri_path_components = [ @scoped_2.id ]
567
+ found = RSpecModelFinderTest.acquire_in( @context )
568
+ expect( found ).to be_nil
517
569
 
518
- # ==========================================================================
570
+ @context.request.uri_path_components = [ @scoped_3.id ]
571
+ found = RSpecModelFinderTest.acquire_in( @context )
572
+ expect( found ).to eq( @scoped_3 )
519
573
 
520
- context 'counting' do
521
- it 'lists with a normal count' do
522
- finder = RSpecModelFinderTest.list( @list_params )
574
+ @session.scoping.authorised_uuids = [ 'uuid 1', 'uuid 2' ]
523
575
 
524
- expect( finder ).to receive( :dataset_size ).at_least( :once ).and_call_original
525
- expect( finder ).to receive( :count ).at_least( :once ).and_call_original
576
+ @context.request.uri_path_components = [ @scoped_1.id ]
577
+ found = RSpecModelFinderTest.acquire_in( @context )
578
+ expect( found ).to be_nil
526
579
 
527
- expect( finder ).to_not receive( :estimated_dataset_size )
528
- expect( finder ).to_not receive( :estimated_count )
580
+ @context.request.uri_path_components = [ @scoped_2.id ]
581
+ found = RSpecModelFinderTest.acquire_in( @context )
582
+ expect( found ).to eq( @scoped_2 )
529
583
 
530
- result = finder.dataset_size()
584
+ @context.request.uri_path_components = [ @scoped_3.id ]
585
+ found = RSpecModelFinderTest.acquire_in( @context )
586
+ expect( found ).to eq( @scoped_3 )
587
+ end
531
588
 
532
- expect( result ).to_not be_nil
533
- end
589
+ it 'finds with secure scopes with a chain' do
590
+ @session.scoping = { :authorised_uuids => [ 'uuid 1' ], :authorised_code => 'code 1' }
534
591
 
535
- it 'lists with an estimated count' do
536
- finder = RSpecModelFinderTest.list( @list_params )
592
+ @context.request.uri_path_components = [ @scoped_1.id ]
593
+ found = RSpecModelFinderTest.where( :field_one => @scoped_1.field_one ).acquire_in( @context )
594
+ expect( found ).to eq( @scoped_1 )
537
595
 
538
- expect( finder ).to_not receive( :dataset_size )
596
+ @context.request.uri_path_components = [ @scoped_1.id ]
597
+ found = RSpecModelFinderTest.where( :field_one => @scoped_1.field_one + '!' ).acquire_in( @context )
598
+ expect( found ).to be_nil
539
599
 
540
- expect( finder ).to receive( :estimated_dataset_size ).at_least( :once ).and_call_original
541
- expect( finder ).to receive( :estimated_count ).at_least( :once ).and_call_original
542
- expect( finder ).to receive( :count ).at_least( :once ).and_call_original
600
+ @context.request.uri_path_components = [ @scoped_2.id ]
601
+ found = RSpecModelFinderTest.where( :field_one => @scoped_2.field_one ).acquire_in( @context )
602
+ expect( found ).to be_nil
543
603
 
544
- result = finder.estimated_dataset_size
604
+ @context.request.uri_path_components = [ @scoped_3.id ]
605
+ found = RSpecModelFinderTest.where( :field_one => @scoped_3.field_one ).acquire_in( @context )
606
+ expect( found ).to be_nil
545
607
 
546
- expect( result ).to_not be_nil
547
- end
608
+ @session.scoping.authorised_uuids = [ 'uuid 1', 'uuid 2' ]
609
+ @session.scoping.authorised_code = 'code 2'
548
610
 
549
- context 'RDoc-recommended PostgreSQL migration example' do
550
- before :each do
551
- ActiveRecord::Base.connection.execute <<-SQL
552
- CREATE FUNCTION estimated_count(query text) RETURNS integer AS
553
- $func$
554
- DECLARE
555
- rec record;
556
- rows integer;
557
- BEGIN
558
- FOR rec IN EXECUTE 'EXPLAIN ' || query LOOP
559
- rows := substring(rec."QUERY PLAN" FROM ' rows=([[:digit:]]+)');
560
- EXIT WHEN rows IS NOT NULL;
561
- END LOOP;
562
-
563
- RETURN rows;
564
- END
565
- $func$ LANGUAGE plpgsql;
566
- SQL
567
-
568
- counter = Proc.new do | sql |
569
- begin
570
- ActiveRecord::Base.connection.execute(
571
- "SELECT estimated_count('#{ sql}')"
572
- ).first[ 'estimated_count' ].to_i
573
- rescue
574
- nil
575
- end
576
- end
611
+ @context.request.uri_path_components = [ @scoped_1.id ]
612
+ found = RSpecModelFinderTest.where( :field_one => @scoped_1.field_one ).acquire_in( @context )
613
+ expect( found ).to be_nil
577
614
 
578
- RSpecModelFinderTest.estimate_counts_with( counter )
615
+ @context.request.uri_path_components = [ @scoped_2.id ]
616
+ found = RSpecModelFinderTest.where( :field_one => @scoped_2.field_one ).acquire_in( @context )
617
+ expect( found ).to eq( @scoped_2 )
579
618
 
580
- # Tests start by ensuring the database knows about the current object count.
581
- #
582
- ActiveRecord::Base.connection.execute( 'ANALYZE' )
583
- end
619
+ @context.request.uri_path_components = [ @scoped_3.id ]
620
+ found = RSpecModelFinderTest.where( :field_one => @scoped_3.field_one ).acquire_in( @context )
621
+ expect( found ).to eq( @scoped_3 )
584
622
 
585
- after :each do
586
- ActiveRecord::Base.connection.execute "DROP FUNCTION estimated_count(query text);"
587
- RSpecModelFinderTest.estimate_counts_with( nil )
623
+ @context.request.uri_path_components = [ @scoped_3.id ]
624
+ found = RSpecModelFinderTest.where( :field_one => @scoped_3.field_one + '!' ).acquire_in( @context )
625
+ expect( found ).to be_nil
588
626
  end
627
+ end
589
628
 
590
- # These must run in order else e.g. the ANALYZE might happen before the
591
- # pre-ANALYZE test, breaking the results.
592
- #
593
- context 'estimate', :order => :defined do
594
- before :each do
595
- @initial_count = RSpecModelFinderTest.count
596
-
597
- # The outer 'before' code ensures an accurate initial count of 3,
598
- # but we're going add in a few more unestimated items.
599
- #
600
- @uncounted1 = RSpecModelFinderTest.new.save!
601
- @uncounted2 = RSpecModelFinderTest.new.save!
602
- @uncounted3 = RSpecModelFinderTest.new.save!
629
+ # ========================================================================
603
630
 
604
- @subsequent_accurate_count = RSpecModelFinderTest.count
605
- end
631
+ context '#list' do
632
+ it 'lists with pages, offsets and counts' do
633
+ expect_any_instance_of( RSpecModelFinderTest ).to_not receive( :estimated_dataset_size )
606
634
 
607
- it 'may be initially inaccurate' do
608
- finder = RSpecModelFinderTest.list( @list_params )
609
- result = finder.estimated_dataset_size
610
- expect( result ).to eq( @initial_count ).or( eq( @subsequent_accurate_count ) )
611
- end
635
+ @list_params.offset = 1 # 0 is first record
636
+ @list_params.limit = 1
612
637
 
613
- # The outer 'before' code kind of already tests this anyway since if
614
- # the analyze call therein didn't work, prerequisites in the tests
615
- # would be wrong and other tests would fail. It's useful to
616
- # double-check something this important though.
617
- #
618
- it 'is accurate after ANALYZE' do
619
- ActiveRecord::Base.connection.execute( 'ANALYZE' )
638
+ finder = RSpecModelFinderTest.order( :field_three => :asc ).list( @list_params )
639
+ expect( finder ).to eq([@b])
640
+ expect( finder.dataset_size).to eq(3)
620
641
 
621
- finder = RSpecModelFinderTest.list( @list_params )
622
- result = finder.estimated_dataset_size
623
- expect( result ).to eq( @subsequent_accurate_count )
624
- end
642
+ @list_params.offset = 1
643
+ @list_params.limit = 2
625
644
 
626
- it 'is "nil" if the Proc evaluates thus' do
627
- RSpecModelFinderTest.estimate_counts_with( Proc.new() { | sql | nil } )
628
- finder = RSpecModelFinderTest.list( @list_params )
629
- result = finder.estimated_dataset_size
630
- expect( result ).to be_nil
631
- end
645
+ finder = RSpecModelFinderTest.order( :field_three => :asc ).list( @list_params )
646
+ expect( finder ).to eq([@b, @c])
647
+ expect( finder.dataset_size).to eq(3)
632
648
  end
633
649
  end
634
- end
635
650
 
636
- # ==========================================================================
651
+ # ========================================================================
637
652
 
638
- context 'search' do
639
- it 'searches without chain' do
640
- @list_params.search_data = {
641
- 'field_one' => 'group 1'
642
- }
653
+ context 'search' do
654
+ it 'searches without chain' do
655
+ @list_params.search_data = {
656
+ 'field_one' => 'group 1'
657
+ }
643
658
 
644
- finder = RSpecModelFinderTest.list( @list_params )
645
- expect( finder ).to eq([@b, @a])
659
+ finder = RSpecModelFinderTest.list( @list_params )
660
+ expect( finder ).to eq([@b, @a])
646
661
 
647
- @list_params.search_data = {
648
- 'field_one' => 'group 2'
649
- }
662
+ @list_params.search_data = {
663
+ 'field_one' => 'group 2'
664
+ }
650
665
 
651
- finder = RSpecModelFinderTest.list( @list_params )
652
- expect( finder ).to eq([@c])
666
+ finder = RSpecModelFinderTest.list( @list_params )
667
+ expect( finder ).to eq([@c])
653
668
 
654
- @list_params.search_data = {
655
- 'field_two' => 'TWO_A'
656
- }
669
+ @list_params.search_data = {
670
+ 'field_two' => 'TWO_A'
671
+ }
657
672
 
658
- finder = RSpecModelFinderTest.list( @list_params )
659
- expect( finder ).to eq([@a])
673
+ finder = RSpecModelFinderTest.list( @list_params )
674
+ expect( finder ).to eq([@a])
660
675
 
661
- @list_params.search_data = {
662
- 'field_three' => [ 'three a', 'three c' ]
663
- }
676
+ @list_params.search_data = {
677
+ 'field_three' => [ 'three a', 'three c' ]
678
+ }
664
679
 
665
- finder = RSpecModelFinderTest.list( @list_params )
666
- expect( finder ).to eq([@c, @a])
680
+ finder = RSpecModelFinderTest.list( @list_params )
681
+ expect( finder ).to eq([@c, @a])
667
682
 
668
- @list_params.search_data = {
669
- 'field_two' => 'two c',
670
- 'field_three' => [ 'three a', 'three c' ]
671
- }
683
+ @list_params.search_data = {
684
+ 'field_two' => 'two c',
685
+ 'field_three' => [ 'three a', 'three c' ]
686
+ }
672
687
 
673
- finder = RSpecModelFinderTest.list( @list_params )
674
- expect( finder ).to eq([@c])
688
+ finder = RSpecModelFinderTest.list( @list_params )
689
+ expect( finder ).to eq([@c])
675
690
 
676
- @list_params.search_data = {
677
- 'created_after' => @tn - 1.month
678
- }
691
+ @list_params.search_data = {
692
+ 'created_after' => @tn - 1.month
693
+ }
679
694
 
680
- finder = RSpecModelFinderTest.list( @list_params )
681
- expect( finder ).to eq([@c])
695
+ finder = RSpecModelFinderTest.list( @list_params )
696
+ expect( finder ).to eq([@c])
682
697
 
683
- @list_params.search_data = {
684
- 'created_before' => @tn - 1.month
685
- }
698
+ @list_params.search_data = {
699
+ 'created_before' => @tn - 1.month
700
+ }
686
701
 
687
- finder = RSpecModelFinderTest.list( @list_params )
688
- expect( finder ).to eq([@a])
702
+ finder = RSpecModelFinderTest.list( @list_params )
703
+ expect( finder ).to eq([@a])
689
704
 
690
- @list_params.search_data = {
691
- 'created_before' => @tn - 1.month + 1.day
692
- }
693
-
694
- finder = RSpecModelFinderTest.list( @list_params )
695
- expect( finder ).to eq([@b, @a])
696
- end
705
+ @list_params.search_data = {
706
+ 'created_before' => @tn - 1.month + 1.day
707
+ }
697
708
 
698
- it 'searches with chain' do
699
- constraint = RSpecModelFinderTest.where( :field_one => 'group 1' )
709
+ finder = RSpecModelFinderTest.list( @list_params )
710
+ expect( finder ).to eq([@b, @a])
700
711
 
701
- @list_params.search_data = {
702
- 'field_one' => 'group 1'
703
- }
712
+ @list_params.search_data = {
713
+ 'created_by' => @cb1
714
+ }
704
715
 
705
- finder = constraint.list( @list_params )
706
- expect( finder ).to eq([@b, @a])
716
+ finder = RSpecModelFinderTest.list( @list_params )
717
+ expect( finder ).to eq([@b, @a])
707
718
 
708
- @list_params.search_data = {
709
- 'field_one' => 'group 2'
710
- }
719
+ @list_params.search_data = {
720
+ 'created_by' => @cb2
721
+ }
711
722
 
712
- finder = constraint.list( @list_params )
713
- expect( finder ).to eq([])
723
+ finder = RSpecModelFinderTest.list( @list_params )
724
+ expect( finder ).to eq([@c])
725
+ end
714
726
 
715
- @list_params.search_data = {
716
- 'field_two' => 'TWO_A'
717
- }
727
+ it 'searches with chain' do
728
+ constraint = RSpecModelFinderTest.where( :field_one => 'group 1' )
718
729
 
719
- finder = constraint.list( @list_params )
720
- expect( finder ).to eq([@a])
730
+ @list_params.search_data = {
731
+ 'field_one' => 'group 1'
732
+ }
721
733
 
722
- @list_params.search_data = {
723
- 'field_three' => [ 'three a', 'three c' ]
724
- }
734
+ finder = constraint.list( @list_params )
735
+ expect( finder ).to eq([@b, @a])
725
736
 
726
- finder = constraint.list( @list_params )
727
- expect( finder ).to eq([@a])
737
+ @list_params.search_data = {
738
+ 'field_one' => 'group 2'
739
+ }
728
740
 
729
- @list_params.search_data = {
730
- 'field_two' => 'two c',
731
- 'field_three' => [ 'three a', 'three c' ]
732
- }
741
+ finder = constraint.list( @list_params )
742
+ expect( finder ).to eq([])
733
743
 
734
- finder = constraint.list( @list_params )
735
- expect( finder ).to eq([])
744
+ @list_params.search_data = {
745
+ 'field_two' => 'TWO_A'
746
+ }
736
747
 
737
- @list_params.search_data = {
738
- 'created_after' => @tn - 1.month
739
- }
748
+ finder = constraint.list( @list_params )
749
+ expect( finder ).to eq([@a])
740
750
 
741
- finder = constraint.list( @list_params )
742
- expect( finder ).to eq([])
751
+ @list_params.search_data = {
752
+ 'field_three' => [ 'three a', 'three c' ]
753
+ }
743
754
 
744
- @list_params.search_data = {
745
- 'created_before' => @tn - 1.month
746
- }
755
+ finder = constraint.list( @list_params )
756
+ expect( finder ).to eq([@a])
747
757
 
748
- finder = constraint.list( @list_params )
749
- expect( finder ).to eq([@a])
758
+ @list_params.search_data = {
759
+ 'field_two' => 'two c',
760
+ 'field_three' => [ 'three a', 'three c' ]
761
+ }
750
762
 
751
- @list_params.search_data = {
752
- 'created_before' => @tn - 1.month + 1.day
753
- }
763
+ finder = constraint.list( @list_params )
764
+ expect( finder ).to eq([])
754
765
 
755
- finder = constraint.list( @list_params )
756
- expect( finder ).to eq([@b, @a])
757
- end
758
- end
766
+ @list_params.search_data = {
767
+ 'created_after' => @tn - 1.month
768
+ }
759
769
 
760
- # ==========================================================================
770
+ finder = constraint.list( @list_params )
771
+ expect( finder ).to eq([])
761
772
 
762
- context 'helper-based search' do
763
- it 'finds by mapped code' do
764
- @list_params.search_data = {
765
- 'mapped_code' => @code
766
- }
773
+ @list_params.search_data = {
774
+ 'created_before' => @tn - 1.month
775
+ }
767
776
 
768
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
769
- expect( finder ).to eq( [ @c_wh ] )
770
- end
777
+ finder = constraint.list( @list_params )
778
+ expect( finder ).to eq([@a])
771
779
 
772
- it 'finds by mapped field-one' do
773
- @list_params.search_data = {
774
- 'mapped_field_one' => :'grOUp 1'
775
- }
780
+ @list_params.search_data = {
781
+ 'created_before' => @tn - 1.month + 1.day
782
+ }
776
783
 
777
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
778
- expect( finder ).to eq( [ @b_wh, @a_wh ] )
779
- end
784
+ finder = constraint.list( @list_params )
785
+ expect( finder ).to eq([@b, @a])
780
786
 
781
- it 'finds by mapped, wildcard field-one' do
782
- @list_params.search_data = {
783
- 'wild_field_one' => :'oUP '
784
- }
787
+ @list_params.search_data = {
788
+ 'created_by' => @cb1
789
+ }
785
790
 
786
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
787
- expect( finder ).to eq( [ @c_wh, @b_wh, @a_wh ] )
791
+ finder = constraint.list( @list_params )
792
+ expect( finder ).to eq([@b, @a])
788
793
 
789
- @list_params.search_data = {
790
- 'wild_field_one' => :'o!p '
791
- }
794
+ @list_params.search_data = {
795
+ 'created_by' => @cb2
796
+ }
792
797
 
793
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
794
- expect( finder ).to eq( [] )
798
+ finder = constraint.list( @list_params )
799
+ expect( finder ).to eq([])
800
+ end
795
801
  end
796
802
 
797
- it 'finds by comma-separated list' do
798
- @list_params.search_data = {
799
- 'field_two' => 'two a,something else,two c,more'
800
- }
803
+ # ========================================================================
801
804
 
802
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
803
- expect( finder ).to eq( [ @c_wh, @a_wh ] )
804
- end
805
+ context 'helper-based search' do
806
+ it 'finds by mapped code' do
807
+ @list_params.search_data = {
808
+ 'mapped_code' => @code
809
+ }
805
810
 
806
- it 'finds by Array' do
807
- @list_params.search_data = {
808
- 'field_three' => [ 'hello', :'three b', 'three c', :there ]
809
- }
811
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
812
+ expect( finder ).to eq( [ @c_wh ] )
813
+ end
810
814
 
811
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
812
- expect( finder ).to eq( [ @c_wh, @b_wh ] )
813
- end
815
+ it 'finds by mapped field-one' do
816
+ @list_params.search_data = {
817
+ 'mapped_field_one' => :'grOUp 1'
818
+ }
814
819
 
815
- it 'finds with framework override' do
816
- @list_params.search_data = {
817
- 'created_after' => @tn - 1.week
818
- }
820
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
821
+ expect( finder ).to eq( [ @b_wh, @a_wh ] )
822
+ end
819
823
 
820
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
821
- expect( finder ).to eq( [ @c_wh, @b_wh ] )
824
+ it 'finds by mapped, wildcard field-one' do
825
+ @list_params.search_data = {
826
+ 'wild_field_one' => :'oUP '
827
+ }
822
828
 
823
- @list_params.search_data = {
824
- 'created_after' => @tn + 1.day
825
- }
829
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
830
+ expect( finder ).to eq( [ @c_wh, @b_wh, @a_wh ] )
826
831
 
827
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
828
- expect( finder ).to eq( [ @c_wh ] )
829
- end
830
- end
832
+ @list_params.search_data = {
833
+ 'wild_field_one' => :'o!p '
834
+ }
831
835
 
832
- # ==========================================================================
836
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
837
+ expect( finder ).to eq( [] )
838
+ end
833
839
 
834
- context 'pure framework search' do
835
- it 'on created_after' do
836
- @list_params.search_data = {
837
- 'created_after' => @tn - 1.month
838
- }
840
+ it 'finds by comma-separated list' do
841
+ @list_params.search_data = {
842
+ 'field_two' => 'two a,something else,two c,more'
843
+ }
839
844
 
840
- finder = RSpecModelFinderWithoutSearchOrFilterTest.list( @list_params )
841
- expect( finder ).to eq( [ @c_wosf ] )
842
- end
845
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
846
+ expect( finder ).to eq( [ @c_wh, @a_wh ] )
847
+ end
843
848
 
844
- it 'on created_before' do
845
- @list_params.search_data = {
846
- 'created_before' => @tn - 1.month
847
- }
849
+ it 'finds by Array' do
850
+ @list_params.search_data = {
851
+ 'field_three' => [ 'hello', :'three b', 'three c', :there ]
852
+ }
848
853
 
849
- finder = RSpecModelFinderWithoutSearchOrFilterTest.list( @list_params )
850
- expect( finder ).to eq( [ @a_wosf ] )
851
- end
852
- end
854
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
855
+ expect( finder ).to eq( [ @c_wh, @b_wh ] )
856
+ end
853
857
 
854
- # ==========================================================================
858
+ it 'finds with framework override (to same column)' do
859
+ @list_params.search_data = {
860
+ 'created_after' => @tn - 1.week
861
+ }
862
+
863
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
864
+ expect( finder ).to eq( [ @c_wh, @b_wh ] )
855
865
 
856
- context 'as a Hoodoo::ActiveRecord::Base subclass and sub-subclass' do # (instead of explicitly including the Finder module)
857
- context 'custom search' do
858
- it 'on mapped_code' do
859
866
  @list_params.search_data = {
860
- 'mapped_code' => @code
867
+ 'created_after' => @tn + 1.day
861
868
  }
862
869
 
863
- finder = RSpecModelFinderSubclassTest.list( @list_params )
864
- expect( finder ).to eq( [ @c_sc ] )
870
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
871
+ expect( finder ).to eq( [ @c_wh ] )
872
+ end
865
873
 
866
- finder = RSpecModelFinderSubclassATest.list( @list_params )
867
- expect( finder ).to eq( [ @c_sc_a ] )
874
+ it 'finds by framework override (to different column)' do
875
+ @list_params.search_data = {
876
+ 'created_by' => 'b' # Maps to 'code' field, case insensitive
877
+ }
868
878
 
869
- finder = RSpecModelFinderSubclassBTest.list( @list_params )
870
- expect( finder ).to eq( [ @c_sc_b ] )
879
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
880
+ expect( finder ).to eq( [ @b_wh ] )
871
881
  end
872
882
  end
873
883
 
884
+ # ========================================================================
885
+
874
886
  context 'pure framework search' do
875
887
  it 'on created_after' do
876
888
  @list_params.search_data = {
877
889
  'created_after' => @tn - 1.month
878
890
  }
879
891
 
880
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterTest.list( @list_params )
881
- expect( finder ).to eq( [ @c_sc_wosf ] )
882
-
883
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterATest.list( @list_params )
884
- expect( finder ).to eq( [ @c_sc_wosf_a ] )
885
-
886
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterBTest.list( @list_params )
887
- expect( finder ).to eq( [ @c_sc_wosf_b ] )
892
+ finder = RSpecModelFinderWithoutSearchOrFilterTest.list( @list_params )
893
+ expect( finder ).to eq( [ @c_wosf ] )
888
894
  end
889
895
 
890
896
  it 'on created_before' do
@@ -892,279 +898,316 @@ describe Hoodoo::ActiveRecord::Finder do
892
898
  'created_before' => @tn - 1.month
893
899
  }
894
900
 
895
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterTest.list( @list_params )
896
- expect( finder ).to eq( [ @a_sc_wosf ] )
901
+ finder = RSpecModelFinderWithoutSearchOrFilterTest.list( @list_params )
902
+ expect( finder ).to eq( [ @a_wosf ] )
903
+ end
897
904
 
898
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterATest.list( @list_params )
899
- expect( finder ).to eq( [ @a_sc_wosf_a ] )
905
+ it 'on created_by' do
906
+ @list_params.search_data = {
907
+ 'created_by' => @cb1
908
+ }
900
909
 
901
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterBTest.list( @list_params )
902
- expect( finder ).to eq( [ @a_sc_wosf_b ] )
910
+ finder = RSpecModelFinderWithoutSearchOrFilterTest.list( @list_params )
911
+ expect( finder ).to eq( [ @b_wosf, @a_wosf ] )
903
912
  end
904
913
  end
905
- end
906
914
 
907
- # ==========================================================================
915
+ # ========================================================================
908
916
 
909
- context 'filter' do
910
- it 'filters without chain' do
911
- @list_params.filter_data = {
912
- 'field_two' => 'two a'
913
- }
917
+ context 'as a Hoodoo::ActiveRecord::Base subclass and sub-subclass' do # (instead of explicitly including the Finder module)
918
+ context 'custom search' do
919
+ it 'on mapped_code' do
920
+ @list_params.search_data = {
921
+ 'mapped_code' => @code
922
+ }
914
923
 
915
- finder = RSpecModelFinderTest.list( @list_params )
916
- expect( finder ).to eq([@c, @b])
924
+ finder = RSpecModelFinderSubclassTest.list( @list_params )
925
+ expect( finder ).to eq( [ @c_sc ] )
917
926
 
918
- @list_params.filter_data = {
919
- 'field_three' => 'three c'
920
- }
927
+ finder = RSpecModelFinderSubclassATest.list( @list_params )
928
+ expect( finder ).to eq( [ @c_sc_a ] )
921
929
 
922
- finder = RSpecModelFinderTest.list( @list_params )
923
- expect( finder ).to eq([@b, @a])
930
+ finder = RSpecModelFinderSubclassBTest.list( @list_params )
931
+ expect( finder ).to eq( [ @c_sc_b ] )
932
+ end
933
+ end
924
934
 
925
- @list_params.filter_data = {
926
- 'field_one' => [ 'group 1', 'group 2' ]
927
- }
935
+ context 'pure framework search' do
936
+ it 'on created_after' do
937
+ @list_params.search_data = {
938
+ 'created_after' => @tn - 1.month
939
+ }
928
940
 
929
- finder = RSpecModelFinderTest.list( @list_params )
930
- expect( finder ).to eq([])
941
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterTest.list( @list_params )
942
+ expect( finder ).to eq( [ @c_sc_wosf ] )
931
943
 
932
- @list_params.filter_data = {
933
- 'field_one' => [ 'group 2' ]
934
- }
944
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterATest.list( @list_params )
945
+ expect( finder ).to eq( [ @c_sc_wosf_a ] )
935
946
 
936
- finder = RSpecModelFinderTest.list( @list_params )
937
- expect( finder ).to eq([@b, @a])
947
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterBTest.list( @list_params )
948
+ expect( finder ).to eq( [ @c_sc_wosf_b ] )
949
+ end
938
950
 
939
- @list_params.filter_data = {
940
- 'field_one' => [ 'group 2' ],
941
- 'field_three' => 'three a'
942
- }
951
+ it 'on created_before' do
952
+ @list_params.search_data = {
953
+ 'created_before' => @tn - 1.month
954
+ }
943
955
 
944
- finder = RSpecModelFinderTest.list( @list_params )
945
- expect( finder ).to eq([@b])
956
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterTest.list( @list_params )
957
+ expect( finder ).to eq( [ @a_sc_wosf ] )
946
958
 
947
- @list_params.filter_data = {
948
- 'created_after' => @tn - 1.month
949
- }
959
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterATest.list( @list_params )
960
+ expect( finder ).to eq( [ @a_sc_wosf_a ] )
950
961
 
951
- finder = RSpecModelFinderTest.list( @list_params )
952
- expect( finder ).to eq([@b, @a])
962
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterBTest.list( @list_params )
963
+ expect( finder ).to eq( [ @a_sc_wosf_b ] )
964
+ end
965
+ end
966
+ end
953
967
 
954
- @list_params.filter_data = {
955
- 'created_before' => @tn - 1.month
956
- }
968
+ # ========================================================================
957
969
 
958
- finder = RSpecModelFinderTest.list( @list_params )
959
- expect( finder ).to eq([@c, @b])
970
+ context 'filter' do
971
+ it 'filters without chain' do
972
+ @list_params.filter_data = {
973
+ 'field_two' => 'two a'
974
+ }
960
975
 
961
- @list_params.filter_data = {
962
- 'created_before' => @tn - 1.month + 1.day
963
- }
976
+ finder = RSpecModelFinderTest.list( @list_params )
977
+ expect( finder ).to eq([@c, @b])
964
978
 
965
- finder = RSpecModelFinderTest.list( @list_params )
966
- expect( finder ).to eq([@c])
967
- end
979
+ @list_params.filter_data = {
980
+ 'field_three' => 'three c'
981
+ }
968
982
 
969
- it 'filters with chain' do
983
+ finder = RSpecModelFinderTest.list( @list_params )
984
+ expect( finder ).to eq([@b, @a])
970
985
 
971
- # Remember, the constraint is *inclusive* unlike all the
972
- # subsequent filters which *exclude*.
986
+ @list_params.filter_data = {
987
+ 'field_one' => [ 'group 1', 'group 2' ]
988
+ }
973
989
 
974
- constraint = RSpecModelFinderTest.where( :field_one => 'group 2' )
990
+ finder = RSpecModelFinderTest.list( @list_params )
991
+ expect( finder ).to eq([])
975
992
 
976
- @list_params.filter_data = {
977
- 'field_two' => 'two a'
978
- }
993
+ @list_params.filter_data = {
994
+ 'field_one' => [ 'group 2' ]
995
+ }
979
996
 
980
- finder = constraint.list( @list_params )
981
- expect( finder ).to eq([@c])
997
+ finder = RSpecModelFinderTest.list( @list_params )
998
+ expect( finder ).to eq([@b, @a])
982
999
 
983
- @list_params.filter_data = {
984
- 'field_three' => 'three c'
985
- }
1000
+ @list_params.filter_data = {
1001
+ 'field_one' => [ 'group 2' ],
1002
+ 'field_three' => 'three a'
1003
+ }
986
1004
 
987
- finder = constraint.list( @list_params )
988
- expect( finder ).to eq([])
1005
+ finder = RSpecModelFinderTest.list( @list_params )
1006
+ expect( finder ).to eq([@b])
989
1007
 
990
- @list_params.filter_data = {
991
- 'field_one' => [ 'group 1', 'group 2' ]
992
- }
1008
+ @list_params.filter_data = {
1009
+ 'created_after' => @tn - 1.month
1010
+ }
993
1011
 
994
- finder = constraint.list( @list_params )
995
- expect( finder ).to eq([])
1012
+ finder = RSpecModelFinderTest.list( @list_params )
1013
+ expect( finder ).to eq([@b, @a])
996
1014
 
997
- @list_params.filter_data = {
998
- 'field_one' => [ 'group 2' ]
999
- }
1015
+ @list_params.filter_data = {
1016
+ 'created_before' => @tn - 1.month
1017
+ }
1000
1018
 
1001
- finder = constraint.list( @list_params )
1002
- expect( finder ).to eq([])
1019
+ finder = RSpecModelFinderTest.list( @list_params )
1020
+ expect( finder ).to eq([@c, @b])
1003
1021
 
1004
- @list_params.filter_data = {
1005
- 'field_one' => [ 'group 2' ],
1006
- 'field_three' => 'three a'
1007
- }
1022
+ @list_params.filter_data = {
1023
+ 'created_before' => @tn - 1.month + 1.day
1024
+ }
1008
1025
 
1009
- finder = constraint.list( @list_params )
1010
- expect( finder ).to eq([])
1026
+ finder = RSpecModelFinderTest.list( @list_params )
1027
+ expect( finder ).to eq([@c])
1011
1028
 
1012
- @list_params.filter_data = {
1013
- 'created_after' => @tn - 1.month
1014
- }
1029
+ @list_params.filter_data = {
1030
+ 'created_by' => @cb1
1031
+ }
1015
1032
 
1016
- finder = constraint.list( @list_params )
1017
- expect( finder ).to eq([])
1033
+ finder = RSpecModelFinderTest.list( @list_params )
1034
+ expect( finder ).to eq([@c])
1018
1035
 
1019
- @list_params.filter_data = {
1020
- 'created_before' => @tn - 1.month
1021
- }
1036
+ @list_params.filter_data = {
1037
+ 'created_by' => @cb2
1038
+ }
1022
1039
 
1023
- finder = constraint.list( @list_params )
1024
- expect( finder ).to eq([@c])
1040
+ finder = RSpecModelFinderTest.list( @list_params )
1041
+ expect( finder ).to eq([@b, @a])
1042
+ end
1025
1043
 
1026
- @list_params.filter_data = {
1027
- 'created_before' => @tn - 1.month + 1.day
1028
- }
1044
+ it 'filters with chain' do
1029
1045
 
1030
- finder = constraint.list( @list_params )
1031
- expect( finder ).to eq([@c])
1032
- end
1033
- end
1046
+ # Remember, the constraint is *inclusive* unlike all the
1047
+ # subsequent filters which *exclude*.
1034
1048
 
1035
- # ==========================================================================
1049
+ constraint = RSpecModelFinderTest.where( :field_one => 'group 2' )
1036
1050
 
1037
- # This set of copy-and-modify tests based on the helper-based search tests
1038
- # earlier seems somewhat redundant, but should anyone accidentally decouple
1039
- # the search/filter back-end processing and introduce some sort of error at
1040
- # a finder-level, the tests here have a chance of catching that.
1051
+ @list_params.filter_data = {
1052
+ 'field_two' => 'two a'
1053
+ }
1041
1054
 
1042
- context 'helper-based filtering' do
1043
- it 'filters by mapped code' do
1044
- @list_params.filter_data = {
1045
- 'mapped_code' => @code
1046
- }
1055
+ finder = constraint.list( @list_params )
1056
+ expect( finder ).to eq([@c])
1047
1057
 
1048
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1049
- expect( finder ).to eq( [ @b_wh, @a_wh ] )
1050
- end
1058
+ @list_params.filter_data = {
1059
+ 'field_three' => 'three c'
1060
+ }
1051
1061
 
1052
- it 'filters by mapped field-one' do
1053
- @list_params.filter_data = {
1054
- 'mapped_field_one' => :'grOUp 1'
1055
- }
1062
+ finder = constraint.list( @list_params )
1063
+ expect( finder ).to eq([])
1056
1064
 
1057
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1058
- expect( finder ).to eq( [ @c_wh ] )
1059
- end
1065
+ @list_params.filter_data = {
1066
+ 'field_one' => [ 'group 1', 'group 2' ]
1067
+ }
1060
1068
 
1061
- it 'filters by mapped, wildcard field-one' do
1062
- @list_params.filter_data = {
1063
- 'wild_field_one' => :'oUP '
1064
- }
1069
+ finder = constraint.list( @list_params )
1070
+ expect( finder ).to eq([])
1065
1071
 
1066
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1067
- expect( finder ).to eq( [] )
1072
+ @list_params.filter_data = {
1073
+ 'field_one' => [ 'group 2' ]
1074
+ }
1068
1075
 
1069
- @list_params.filter_data = {
1070
- 'wild_field_one' => :'o!p '
1071
- }
1076
+ finder = constraint.list( @list_params )
1077
+ expect( finder ).to eq([])
1072
1078
 
1073
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1074
- expect( finder ).to eq( [ @c_wh, @b_wh, @a_wh ] )
1075
- end
1079
+ @list_params.filter_data = {
1080
+ 'field_one' => [ 'group 2' ],
1081
+ 'field_three' => 'three a'
1082
+ }
1076
1083
 
1077
- it 'filters by comma-separated list' do
1078
- @list_params.filter_data = {
1079
- 'field_two' => 'two a,something else,two c,more'
1080
- }
1084
+ finder = constraint.list( @list_params )
1085
+ expect( finder ).to eq([])
1081
1086
 
1082
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1083
- expect( finder ).to eq( [ @b_wh ] )
1084
- end
1087
+ @list_params.filter_data = {
1088
+ 'created_after' => @tn - 1.month
1089
+ }
1085
1090
 
1086
- it 'filters by Array' do
1087
- @list_params.filter_data = {
1088
- 'field_three' => [ 'hello', :'three b', 'three c', :there ]
1089
- }
1091
+ finder = constraint.list( @list_params )
1092
+ expect( finder ).to eq([])
1090
1093
 
1091
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1092
- expect( finder ).to eq( [ @a_wh ] )
1093
- end
1094
+ @list_params.filter_data = {
1095
+ 'created_before' => @tn - 1.month
1096
+ }
1094
1097
 
1095
- it 'filters with framework override' do
1096
- @list_params.filter_data = {
1097
- 'created_after' => @tn - 1.week
1098
- }
1098
+ finder = constraint.list( @list_params )
1099
+ expect( finder ).to eq([@c])
1099
1100
 
1100
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1101
- expect( finder ).to eq( [ @a_wh ] )
1101
+ @list_params.filter_data = {
1102
+ 'created_before' => @tn - 1.month + 1.day
1103
+ }
1102
1104
 
1103
- @list_params.filter_data = {
1104
- 'created_after' => @tn + 1.day
1105
- }
1105
+ finder = constraint.list( @list_params )
1106
+ expect( finder ).to eq([@c])
1106
1107
 
1107
- finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1108
- expect( finder ).to eq( [ @b_wh, @a_wh ] )
1109
- end
1110
- end
1108
+ @list_params.filter_data = {
1109
+ 'created_by' => @cb1
1110
+ }
1111
1111
 
1112
- # ==========================================================================
1112
+ finder = constraint.list( @list_params )
1113
+ expect( finder ).to eq([@c])
1113
1114
 
1114
- context 'pure framework filter' do
1115
- it 'on created_after' do
1116
- @list_params.filter_data = {
1117
- 'created_after' => @tn - 1.month
1118
- }
1115
+ @list_params.filter_data = {
1116
+ 'created_by' => @cb2
1117
+ }
1119
1118
 
1120
- finder = RSpecModelFinderWithoutSearchOrFilterTest.list( @list_params )
1121
- expect( finder ).to eq( [ @b_wosf, @a_wosf ] )
1119
+ finder = constraint.list( @list_params )
1120
+ expect( finder ).to eq([])
1121
+ end
1122
1122
  end
1123
1123
 
1124
- it 'on created_before' do
1125
- @list_params.filter_data = {
1126
- 'created_before' => @tn - 1.month
1127
- }
1124
+ # ========================================================================
1128
1125
 
1129
- finder = RSpecModelFinderWithoutSearchOrFilterTest.list( @list_params )
1130
- expect( finder ).to eq( [ @c_wosf, @b_wosf ] )
1131
- end
1132
- end
1126
+ # This set of copy-and-modify tests based on the helper-based search tests
1127
+ # earlier seems somewhat redundant but should anyone accidentally decouple
1128
+ # the search/filter back-end processing and introduce some sort of error
1129
+ # at a finder-level, the tests here have a chance of catching that.
1130
+ #
1131
+ context 'helper-based filtering' do
1132
+ it 'filters by mapped code' do
1133
+ @list_params.filter_data = {
1134
+ 'mapped_code' => @code
1135
+ }
1133
1136
 
1134
- # ==========================================================================
1137
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1138
+ expect( finder ).to eq( [ @b_wh, @a_wh ] )
1139
+ end
1135
1140
 
1136
- context 'as a Hoodoo::ActiveRecord::Base subclass and sub-subclass' do # (instead of explicitly including the Finder module)
1137
- context 'custom filter' do
1138
- it 'on mapped_code' do
1141
+ it 'filters by mapped field-one' do
1139
1142
  @list_params.filter_data = {
1140
- 'mapped_code' => @code
1143
+ 'mapped_field_one' => :'grOUp 1'
1144
+ }
1145
+
1146
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1147
+ expect( finder ).to eq( [ @c_wh ] )
1148
+ end
1149
+
1150
+ it 'filters by mapped, wildcard field-one' do
1151
+ @list_params.filter_data = {
1152
+ 'wild_field_one' => :'oUP '
1153
+ }
1154
+
1155
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1156
+ expect( finder ).to eq( [] )
1157
+
1158
+ @list_params.filter_data = {
1159
+ 'wild_field_one' => :'o!p '
1160
+ }
1161
+
1162
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1163
+ expect( finder ).to eq( [ @c_wh, @b_wh, @a_wh ] )
1164
+ end
1165
+
1166
+ it 'filters by comma-separated list' do
1167
+ @list_params.filter_data = {
1168
+ 'field_two' => 'two a,something else,two c,more'
1169
+ }
1170
+
1171
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1172
+ expect( finder ).to eq( [ @b_wh ] )
1173
+ end
1174
+
1175
+ it 'filters by Array' do
1176
+ @list_params.filter_data = {
1177
+ 'field_three' => [ 'hello', :'three b', 'three c', :there ]
1178
+ }
1179
+
1180
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1181
+ expect( finder ).to eq( [ @a_wh ] )
1182
+ end
1183
+
1184
+ it 'filters with framework override' do
1185
+ @list_params.filter_data = {
1186
+ 'created_after' => @tn - 1.week
1141
1187
  }
1142
1188
 
1143
- finder = RSpecModelFinderSubclassTest.list( @list_params )
1144
- expect( finder ).to eq( [ @b_sc, @a_sc ] )
1189
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1190
+ expect( finder ).to eq( [ @a_wh ] )
1145
1191
 
1146
- finder = RSpecModelFinderSubclassATest.list( @list_params )
1147
- expect( finder ).to eq( [ @b_sc_a, @a_sc_a ] )
1192
+ @list_params.filter_data = {
1193
+ 'created_after' => @tn + 1.day
1194
+ }
1148
1195
 
1149
- finder = RSpecModelFinderSubclassBTest.list( @list_params )
1150
- expect( finder ).to eq( [ @b_sc_b, @a_sc_b ] )
1196
+ finder = RSpecModelFinderTestWithHelpers.list( @list_params )
1197
+ expect( finder ).to eq( [ @b_wh, @a_wh ] )
1151
1198
  end
1152
1199
  end
1153
1200
 
1201
+ # ========================================================================
1202
+
1154
1203
  context 'pure framework filter' do
1155
1204
  it 'on created_after' do
1156
1205
  @list_params.filter_data = {
1157
1206
  'created_after' => @tn - 1.month
1158
1207
  }
1159
1208
 
1160
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterTest.list( @list_params )
1161
- expect( finder ).to eq( [ @b_sc_wosf, @a_sc_wosf ] )
1162
-
1163
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterATest.list( @list_params )
1164
- expect( finder ).to eq( [ @b_sc_wosf_a, @a_sc_wosf_a ] )
1165
-
1166
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterBTest.list( @list_params )
1167
- expect( finder ).to eq( [ @b_sc_wosf_b, @a_sc_wosf_b ] )
1209
+ finder = RSpecModelFinderWithoutSearchOrFilterTest.list( @list_params )
1210
+ expect( finder ).to eq( [ @b_wosf, @a_wosf ] )
1168
1211
  end
1169
1212
 
1170
1213
  it 'on created_before' do
@@ -1172,159 +1215,230 @@ describe Hoodoo::ActiveRecord::Finder do
1172
1215
  'created_before' => @tn - 1.month
1173
1216
  }
1174
1217
 
1175
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterTest.list( @list_params )
1176
- expect( finder ).to eq( [ @c_sc_wosf, @b_sc_wosf ] )
1218
+ finder = RSpecModelFinderWithoutSearchOrFilterTest.list( @list_params )
1219
+ expect( finder ).to eq( [ @c_wosf, @b_wosf ] )
1220
+ end
1177
1221
 
1178
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterATest.list( @list_params )
1179
- expect( finder ).to eq( [ @c_sc_wosf_a, @b_sc_wosf_a ] )
1222
+ it 'on created_by' do
1223
+ @list_params.filter_data = {
1224
+ 'created_by' => @cb1
1225
+ }
1180
1226
 
1181
- finder = RSpecModelFinderSubclassWithoutSearchOrFilterBTest.list( @list_params )
1182
- expect( finder ).to eq( [ @c_sc_wosf_b, @b_sc_wosf_b ] )
1227
+ finder = RSpecModelFinderWithoutSearchOrFilterTest.list( @list_params )
1228
+ expect( finder ).to eq( [ @c_wosf ] )
1183
1229
  end
1184
1230
  end
1185
- end
1186
1231
 
1187
- # ==========================================================================
1232
+ # ========================================================================
1188
1233
 
1189
- context '#list_in' do
1190
- before :each do
1191
- @scoped_1 = RSpecModelFinderTest.new
1192
- @scoped_1.id = 'id 1'
1193
- @scoped_1.uuid = 'uuid 1'
1194
- @scoped_1.code = 'code 1'
1195
- @scoped_1.field_one = 'scoped 1'
1196
- @scoped_1.created_at = @tn - 1.year
1197
- @scoped_1.save!
1198
-
1199
- @scoped_2 = RSpecModelFinderTest.new
1200
- @scoped_2.id = 'id 2'
1201
- @scoped_2.uuid = 'uuid 1'
1202
- @scoped_2.code = 'code 2'
1203
- @scoped_2.field_one = 'scoped 2'
1204
- @scoped_2.save!
1205
-
1206
- @scoped_3 = RSpecModelFinderTest.new
1207
- @scoped_3.id = 'id 3'
1208
- @scoped_3.uuid = 'uuid 2'
1209
- @scoped_3.code = 'code 2'
1210
- @scoped_3.field_one = 'scoped 3'
1211
- @scoped_3.save!
1212
-
1213
- # Get a good-enough-for-test interaction which has a context
1214
- # that contains a Session we can modify.
1215
-
1216
- @interaction = Hoodoo::Services::Middleware::Interaction.new( {}, nil )
1217
- @interaction.context = Hoodoo::Services::Context.new(
1218
- Hoodoo::Services::Session.new,
1219
- @interaction.context.request,
1220
- @interaction.context.response,
1221
- @interaction
1222
- )
1234
+ context 'as a Hoodoo::ActiveRecord::Base subclass and sub-subclass' do # (instead of explicitly including the Finder module)
1235
+ context 'custom filter' do
1236
+ it 'on mapped_code' do
1237
+ @list_params.filter_data = {
1238
+ 'mapped_code' => @code
1239
+ }
1223
1240
 
1224
- @context = @interaction.context
1225
- @session = @interaction.context.session
1226
- end
1241
+ finder = RSpecModelFinderSubclassTest.list( @list_params )
1242
+ expect( finder ).to eq( [ @b_sc, @a_sc ] )
1227
1243
 
1228
- it 'lists with secure scopes from the class' do
1229
- @session.scoping = { :authorised_uuids => [ 'uuid 1' ], :authorised_code => 'code 1' }
1244
+ finder = RSpecModelFinderSubclassATest.list( @list_params )
1245
+ expect( finder ).to eq( [ @b_sc_a, @a_sc_a ] )
1230
1246
 
1231
- list = RSpecModelFinderTest.list_in( @context )
1232
- expect( list ).to eq( [ @scoped_1 ] )
1247
+ finder = RSpecModelFinderSubclassBTest.list( @list_params )
1248
+ expect( finder ).to eq( [ @b_sc_b, @a_sc_b ] )
1249
+ end
1250
+ end
1251
+
1252
+ context 'pure framework filter' do
1253
+ it 'on created_after' do
1254
+ @list_params.filter_data = {
1255
+ 'created_after' => @tn - 1.month
1256
+ }
1257
+
1258
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterTest.list( @list_params )
1259
+ expect( finder ).to eq( [ @b_sc_wosf, @a_sc_wosf ] )
1233
1260
 
1234
- @session.scoping.authorised_code = 'code 2'
1261
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterATest.list( @list_params )
1262
+ expect( finder ).to eq( [ @b_sc_wosf_a, @a_sc_wosf_a ] )
1235
1263
 
1236
- list = RSpecModelFinderTest.list_in( @context )
1237
- expect( list ).to eq( [ @scoped_2 ] )
1264
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterBTest.list( @list_params )
1265
+ expect( finder ).to eq( [ @b_sc_wosf_b, @a_sc_wosf_b ] )
1266
+ end
1238
1267
 
1239
- @session.scoping.authorised_uuids = [ 'uuid 2' ]
1268
+ it 'on created_before' do
1269
+ @list_params.filter_data = {
1270
+ 'created_before' => @tn - 1.month
1271
+ }
1240
1272
 
1241
- list = RSpecModelFinderTest.list_in( @context )
1242
- expect( list ).to eq( [ @scoped_3 ] )
1273
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterTest.list( @list_params )
1274
+ expect( finder ).to eq( [ @c_sc_wosf, @b_sc_wosf ] )
1243
1275
 
1244
- @session.scoping.authorised_uuids = [ 'uuid 1', 'uuid 2' ]
1276
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterATest.list( @list_params )
1277
+ expect( finder ).to eq( [ @c_sc_wosf_a, @b_sc_wosf_a ] )
1245
1278
 
1246
- # OK, so these test 'with a chain' too... It's just convenient to (re-)cover
1247
- # that aspect here.
1279
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterBTest.list( @list_params )
1280
+ expect( finder ).to eq( [ @c_sc_wosf_b, @b_sc_wosf_b ] )
1281
+ end
1248
1282
 
1249
- list = RSpecModelFinderTest.list_in( @context ).reorder( 'field_one' => 'asc' )
1250
- expect( list ).to eq( [ @scoped_2, @scoped_3 ] )
1283
+ it 'on created_by' do
1284
+ @list_params.filter_data = {
1285
+ 'created_by' => @cb2
1286
+ }
1251
1287
 
1252
- list = RSpecModelFinderTest.list_in( @context ).reorder( 'field_one' => 'desc' )
1253
- expect( list ).to eq( [ @scoped_3, @scoped_2 ] )
1288
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterTest.list( @list_params )
1289
+ expect( finder ).to eq( [ @b_sc_wosf, @a_sc_wosf ] )
1254
1290
 
1255
- list = RSpecModelFinderTest.reorder( 'field_one' => 'asc' ).list_in( @context )
1256
- expect( list ).to eq( [ @scoped_2, @scoped_3 ] )
1291
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterATest.list( @list_params )
1292
+ expect( finder ).to eq( [ @b_sc_wosf_a, @a_sc_wosf_a ] )
1257
1293
 
1258
- list = RSpecModelFinderTest.reorder( 'field_one' => 'desc' ).list_in( @context )
1259
- expect( list ).to eq( [ @scoped_3, @scoped_2 ] )
1294
+ finder = RSpecModelFinderSubclassWithoutSearchOrFilterBTest.list( @list_params )
1295
+ expect( finder ).to eq( [ @b_sc_wosf_b, @a_sc_wosf_b ] )
1296
+ end
1297
+ end
1260
1298
  end
1261
1299
 
1262
- it 'finds with secure scopes with a chain' do
1263
- @session.scoping = { :authorised_uuids => [ 'uuid 1' ], :authorised_code => 'code 1' }
1300
+ # ========================================================================
1264
1301
 
1265
- list = RSpecModelFinderTest.where( :field_one => @scoped_1.field_one ).list_in( @context )
1266
- expect( list ).to eq( [ @scoped_1 ] )
1302
+ context '#list_in' do
1303
+ before :each do
1304
+ @scoped_1 = RSpecModelFinderTest.new
1305
+ @scoped_1.id = 'id 1'
1306
+ @scoped_1.uuid = 'uuid 1'
1307
+ @scoped_1.code = 'code 1'
1308
+ @scoped_1.field_one = 'scoped 1'
1309
+ @scoped_1.created_at = @tn - 1.year
1310
+ @scoped_1.save!
1311
+
1312
+ @scoped_2 = RSpecModelFinderTest.new
1313
+ @scoped_2.id = 'id 2'
1314
+ @scoped_2.uuid = 'uuid 1'
1315
+ @scoped_2.code = 'code 2'
1316
+ @scoped_2.field_one = 'scoped 2'
1317
+ @scoped_2.save!
1318
+
1319
+ @scoped_3 = RSpecModelFinderTest.new
1320
+ @scoped_3.id = 'id 3'
1321
+ @scoped_3.uuid = 'uuid 2'
1322
+ @scoped_3.code = 'code 2'
1323
+ @scoped_3.field_one = 'scoped 3'
1324
+ @scoped_3.save!
1325
+
1326
+ # Get a good-enough-for-test interaction which has a context
1327
+ # that contains a Session we can modify.
1328
+
1329
+ @interaction = Hoodoo::Services::Middleware::Interaction.new( {}, nil )
1330
+ @interaction.context = Hoodoo::Services::Context.new(
1331
+ Hoodoo::Services::Session.new,
1332
+ @interaction.context.request,
1333
+ @interaction.context.response,
1334
+ @interaction
1335
+ )
1336
+
1337
+ @context = @interaction.context
1338
+ @session = @interaction.context.session
1339
+ end
1267
1340
 
1268
- list = RSpecModelFinderTest.where( :field_one => @scoped_1.field_one + '!' ).list_in( @context )
1269
- expect( list ).to eq( [] )
1341
+ it 'lists with secure scopes from the class' do
1342
+ @session.scoping = { :authorised_uuids => [ 'uuid 1' ], :authorised_code => 'code 1' }
1270
1343
 
1271
- list = RSpecModelFinderTest.list_in( @context ).where( :field_one => @scoped_1.field_one )
1272
- expect( list ).to eq( [ @scoped_1 ] )
1344
+ list = RSpecModelFinderTest.list_in( @context )
1345
+ expect( list ).to eq( [ @scoped_1 ] )
1273
1346
 
1274
- list = RSpecModelFinderTest.list_in( @context ).where( :field_one => @scoped_1.field_one + '!' )
1275
- expect( list ).to eq( [] )
1347
+ @session.scoping.authorised_code = 'code 2'
1276
1348
 
1277
- @session.scoping.authorised_uuids = [ 'uuid 1', 'uuid 2' ]
1278
- @session.scoping.authorised_code = 'code 2'
1349
+ list = RSpecModelFinderTest.list_in( @context )
1350
+ expect( list ).to eq( [ @scoped_2 ] )
1279
1351
 
1280
- list = RSpecModelFinderTest.where( :field_one => [ @scoped_1.field_one, @scoped_2.field_one ] ).list_in( @context )
1281
- expect( list ).to eq( [ @scoped_2 ] )
1352
+ @session.scoping.authorised_uuids = [ 'uuid 2' ]
1282
1353
 
1283
- list = RSpecModelFinderTest.list_in( @context ).where( :field_one => [ @scoped_1.field_one, @scoped_2.field_one ] )
1284
- expect( list ).to eq( [ @scoped_2 ] )
1354
+ list = RSpecModelFinderTest.list_in( @context )
1355
+ expect( list ).to eq( [ @scoped_3 ] )
1285
1356
 
1286
- list = RSpecModelFinderTest.where( :field_one => [ @scoped_2.field_one, @scoped_3.field_one ] ).list_in( @context ).reorder( 'field_one' => 'asc' )
1287
- expect( list ).to eq( [ @scoped_2, @scoped_3 ] )
1357
+ @session.scoping.authorised_uuids = [ 'uuid 1', 'uuid 2' ]
1288
1358
 
1289
- list = RSpecModelFinderTest.list_in( @context ).reorder( 'field_one' => 'asc' ).where( :field_one => [ @scoped_2.field_one, @scoped_3.field_one ] )
1290
- expect( list ).to eq( [ @scoped_2, @scoped_3 ] )
1291
- end
1292
- end
1359
+ # OK, so these test 'with a chain' too... It's just convenient to (re-)cover
1360
+ # that aspect here.
1293
1361
 
1294
- # ==========================================================================
1362
+ list = RSpecModelFinderTest.list_in( @context ).reorder( 'field_one' => 'asc' )
1363
+ expect( list ).to eq( [ @scoped_2, @scoped_3 ] )
1295
1364
 
1296
- context 'deprecated' do
1297
- it '#polymorphic_find calls #acquire' do
1298
- expect( $stderr ).to receive( :puts ).once
1299
- expect( RSpecModelFinderTest ).to receive( :acquire ).once.with( 21 )
1300
- RSpecModelFinderTest.polymorphic_find( RSpecModelFinderTest, 21 )
1301
- end
1365
+ list = RSpecModelFinderTest.list_in( @context ).reorder( 'field_one' => 'desc' )
1366
+ expect( list ).to eq( [ @scoped_3, @scoped_2 ] )
1302
1367
 
1303
- it '#polymorphic_id_fields calls #acquire_with' do
1304
- expect( $stderr ).to receive( :puts ).once
1305
- expect( RSpecModelFinderTest ).to receive( :acquire_with ).once.with( :uuid, :code )
1306
- RSpecModelFinderTest.polymorphic_id_fields( :uuid, :code )
1307
- end
1368
+ list = RSpecModelFinderTest.reorder( 'field_one' => 'asc' ).list_in( @context )
1369
+ expect( list ).to eq( [ @scoped_2, @scoped_3 ] )
1308
1370
 
1309
- it '#list_finder calls #list' do
1310
- params = { :search => { :field_one => 'one' } }
1311
- expect( $stderr ).to receive( :puts ).once
1312
- expect( RSpecModelFinderTest ).to receive( :list ).once.with( params )
1313
- RSpecModelFinderTest.list_finder( params )
1314
- end
1371
+ list = RSpecModelFinderTest.reorder( 'field_one' => 'desc' ).list_in( @context )
1372
+ expect( list ).to eq( [ @scoped_3, @scoped_2 ] )
1373
+ end
1374
+
1375
+ it 'finds with secure scopes with a chain' do
1376
+ @session.scoping = { :authorised_uuids => [ 'uuid 1' ], :authorised_code => 'code 1' }
1377
+
1378
+ list = RSpecModelFinderTest.where( :field_one => @scoped_1.field_one ).list_in( @context )
1379
+ expect( list ).to eq( [ @scoped_1 ] )
1380
+
1381
+ list = RSpecModelFinderTest.where( :field_one => @scoped_1.field_one + '!' ).list_in( @context )
1382
+ expect( list ).to eq( [] )
1383
+
1384
+ list = RSpecModelFinderTest.list_in( @context ).where( :field_one => @scoped_1.field_one )
1385
+ expect( list ).to eq( [ @scoped_1 ] )
1386
+
1387
+ list = RSpecModelFinderTest.list_in( @context ).where( :field_one => @scoped_1.field_one + '!' )
1388
+ expect( list ).to eq( [] )
1389
+
1390
+ @session.scoping.authorised_uuids = [ 'uuid 1', 'uuid 2' ]
1391
+ @session.scoping.authorised_code = 'code 2'
1392
+
1393
+ list = RSpecModelFinderTest.where( :field_one => [ @scoped_1.field_one, @scoped_2.field_one ] ).list_in( @context )
1394
+ expect( list ).to eq( [ @scoped_2 ] )
1395
+
1396
+ list = RSpecModelFinderTest.list_in( @context ).where( :field_one => [ @scoped_1.field_one, @scoped_2.field_one ] )
1397
+ expect( list ).to eq( [ @scoped_2 ] )
1315
1398
 
1316
- it '#list_search_map calls #search_with' do
1317
- params = { :foo => nil, :bar => nil }
1318
- expect( $stderr ).to receive( :puts ).once
1319
- expect( RSpecModelFinderTest ).to receive( :search_with ).once.with( params )
1320
- RSpecModelFinderTest.list_search_map( params )
1399
+ list = RSpecModelFinderTest.where( :field_one => [ @scoped_2.field_one, @scoped_3.field_one ] ).list_in( @context ).reorder( 'field_one' => 'asc' )
1400
+ expect( list ).to eq( [ @scoped_2, @scoped_3 ] )
1401
+
1402
+ list = RSpecModelFinderTest.list_in( @context ).reorder( 'field_one' => 'asc' ).where( :field_one => [ @scoped_2.field_one, @scoped_3.field_one ] )
1403
+ expect( list ).to eq( [ @scoped_2, @scoped_3 ] )
1404
+ end
1321
1405
  end
1322
1406
 
1323
- it '#list_filter_map calls #filter_with' do
1324
- params = { :foo => nil, :bar => nil }
1325
- expect( $stderr ).to receive( :puts ).once
1326
- expect( RSpecModelFinderTest ).to receive( :filter_with ).once.with( params )
1327
- RSpecModelFinderTest.list_filter_map( params )
1407
+ # ========================================================================
1408
+
1409
+ context 'deprecated' do
1410
+ it '#polymorphic_find calls #acquire' do
1411
+ expect( $stderr ).to receive( :puts ).once
1412
+ expect( RSpecModelFinderTest ).to receive( :acquire ).once.with( 21 )
1413
+ RSpecModelFinderTest.polymorphic_find( RSpecModelFinderTest, 21 )
1414
+ end
1415
+
1416
+ it '#polymorphic_id_fields calls #acquire_with' do
1417
+ expect( $stderr ).to receive( :puts ).once
1418
+ expect( RSpecModelFinderTest ).to receive( :acquire_with ).once.with( :uuid, :code )
1419
+ RSpecModelFinderTest.polymorphic_id_fields( :uuid, :code )
1420
+ end
1421
+
1422
+ it '#list_finder calls #list' do
1423
+ params = { :search => { :field_one => 'one' } }
1424
+ expect( $stderr ).to receive( :puts ).once
1425
+ expect( RSpecModelFinderTest ).to receive( :list ).once.with( params )
1426
+ RSpecModelFinderTest.list_finder( params )
1427
+ end
1428
+
1429
+ it '#list_search_map calls #search_with' do
1430
+ params = { :foo => nil, :bar => nil }
1431
+ expect( $stderr ).to receive( :puts ).once
1432
+ expect( RSpecModelFinderTest ).to receive( :search_with ).once.with( params )
1433
+ RSpecModelFinderTest.list_search_map( params )
1434
+ end
1435
+
1436
+ it '#list_filter_map calls #filter_with' do
1437
+ params = { :foo => nil, :bar => nil }
1438
+ expect( $stderr ).to receive( :puts ).once
1439
+ expect( RSpecModelFinderTest ).to receive( :filter_with ).once.with( params )
1440
+ RSpecModelFinderTest.list_filter_map( params )
1441
+ end
1328
1442
  end
1329
1443
  end
1330
1444
  end