hoodoo 1.19.0 → 2.0.0

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