marty 13.0.2 → 14.0.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.rubocop_todo.yml +48 -70
- data/CHANGELOG.md +26 -0
- data/Gemfile +2 -1
- data/app/components/marty/data_grid_view.rb +5 -0
- data/app/helpers/marty/application_helper.rb +1 -1
- data/app/models/marty/data_grid.rb +256 -49
- data/app/services/marty/data_grid/constraint.rb +2 -2
- data/db/migrate/603_add_strict_null_mode_to_data_grids.rb +5 -0
- data/lib/marty/content_handler.rb +3 -1
- data/lib/marty/railtie.rb +1 -0
- data/lib/marty/util.rb +27 -0
- data/lib/marty/version.rb +1 -1
- data/spec/models/data_grid_spec.rb +335 -21
- metadata +3 -2
@@ -19,7 +19,7 @@ module Marty
|
|
19
19
|
|
20
20
|
pt = 'infinity'
|
21
21
|
vals = raw_vals.map do |v|
|
22
|
-
DataGrid.parse_fvalue(pt, v, data_type, dt)
|
22
|
+
DataGrid.parse_fvalue(pt, v, data_type, dt, false)
|
23
23
|
end
|
24
24
|
[[:in?, vals.flatten]]
|
25
25
|
end
|
@@ -56,7 +56,7 @@ module Marty
|
|
56
56
|
err = nil
|
57
57
|
begin
|
58
58
|
cvt_val = cvt && !data_v.class.in?(rt) ?
|
59
|
-
[DataGrid.parse_fvalue(pt, data_v, dt, klass)].
|
59
|
+
[DataGrid.parse_fvalue(pt, data_v, dt, klass, false)].
|
60
60
|
flatten.first : data_v
|
61
61
|
rescue StandardError => e
|
62
62
|
err = e.message
|
@@ -6,6 +6,7 @@ module Marty::ContentHandler
|
|
6
6
|
'html' => ['text/html', 'download'],
|
7
7
|
'txt' => ['text/plain', 'inline'],
|
8
8
|
'json' => ['application/json', 'download'],
|
9
|
+
'pdf' => ['application/pdf', 'download'],
|
9
10
|
|
10
11
|
# hacky: default format is JSON
|
11
12
|
nil => ['application/json', 'download'],
|
@@ -29,7 +30,7 @@ module Marty::ContentHandler
|
|
29
30
|
res = to_zip(data)
|
30
31
|
when nil, 'json'
|
31
32
|
res, format = data.to_json, 'json'
|
32
|
-
when 'html'
|
33
|
+
when 'html', 'pdf'
|
33
34
|
res = data.to_s
|
34
35
|
else
|
35
36
|
res, format = { error: "Unknown format: #{format}" }.to_json, 'json'
|
@@ -92,6 +93,7 @@ module Marty::ContentHandler
|
|
92
93
|
res = Zip::OutputStream.write_buffer do |stream|
|
93
94
|
to_zip_stream(stream, [], data)
|
94
95
|
end
|
96
|
+
|
95
97
|
res.string
|
96
98
|
end
|
97
99
|
end
|
data/lib/marty/railtie.rb
CHANGED
data/lib/marty/util.rb
CHANGED
@@ -1,4 +1,6 @@
|
|
1
1
|
module Marty::Util
|
2
|
+
extend Delorean::Functions
|
3
|
+
|
2
4
|
def self.set_posting_id(sid)
|
3
5
|
snap = Marty::Posting.find_by(id: sid)
|
4
6
|
sid = nil if snap && (snap.created_dt == Float::INFINITY)
|
@@ -56,6 +58,31 @@ module Marty::Util
|
|
56
58
|
res
|
57
59
|
end
|
58
60
|
|
61
|
+
# Returns an array of methods and values that can be applied to a number
|
62
|
+
# in order to check if it's in the given range.
|
63
|
+
# Example: '(1,14]') => [[">", 1.0], ["<=", 14.0]]
|
64
|
+
delorean_fn :pg_range_to_ruby, cache: true do |r|
|
65
|
+
next r if r == 'empty' || r.nil?
|
66
|
+
|
67
|
+
m = pg_range_match(r)
|
68
|
+
|
69
|
+
raise "bad PG range #{r}" unless m
|
70
|
+
|
71
|
+
res = []
|
72
|
+
|
73
|
+
if m[:start] != ''
|
74
|
+
op = m[:open] == '(' ? '>' : '>='
|
75
|
+
res += [[op, m[:start].to_f]]
|
76
|
+
end
|
77
|
+
|
78
|
+
if m[:end] != ''
|
79
|
+
op = m[:close] == ')' ? '<' : '<='
|
80
|
+
res += [[op, m[:end].to_f]]
|
81
|
+
end
|
82
|
+
|
83
|
+
res
|
84
|
+
end
|
85
|
+
|
59
86
|
def self.human_to_pg_range(r)
|
60
87
|
return r if r == 'empty'
|
61
88
|
|
data/lib/marty/version.rb
CHANGED
@@ -1,4 +1,5 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
+
require 'benchmark/ips'
|
2
3
|
|
3
4
|
module Marty::DataGridSpec # rubocop:disable Metrics/ModuleLength
|
4
5
|
describe DataGrid do
|
@@ -187,11 +188,51 @@ Investor Services\t-0.625
|
|
187
188
|
NOT (Admin Premium Services|Admin Services|Admin Services Plus)\t-1.0
|
188
189
|
Admin Services Plus\t-1.625
|
189
190
|
Investor Services Acadamy\t-0.5
|
191
|
+
EOS
|
192
|
+
|
193
|
+
G1_with_nulls = <<EOS
|
194
|
+
strict_null_mode
|
195
|
+
state\tstring\tv\t\t
|
196
|
+
ltv\tnumrange\tv\t\t
|
197
|
+
fico\tnumrange\th\t\t
|
198
|
+
|
199
|
+
\t\t>=600<700\t>=700<750\t>=750
|
200
|
+
CA\t<=80\t1.1\t2.2\t3.3
|
201
|
+
TX|HI\t>80<=105\t4.4\t5.5\t6.6
|
202
|
+
NM\t<=80\t1.2\t2.3\t3.4
|
203
|
+
MA\t>80<=105\t4.5\t5.6\t
|
204
|
+
NULL\t<=80\t11\t22\t33
|
205
|
+
EOS
|
206
|
+
|
207
|
+
G1_with_bool_nulls = <<EOS
|
208
|
+
strict_null_mode
|
209
|
+
bool_state\tboolean\tv\t\t
|
210
|
+
ltv\tnumrange\tv\t\t
|
211
|
+
fico\tnumrange\th\t\t
|
212
|
+
|
213
|
+
\t\t>=600<700\t>=700<750\t>=750
|
214
|
+
f\t>80<=105\t4.5\t5.6\t
|
215
|
+
NULL\t<=80\t11\t22\t33
|
216
|
+
EOS
|
217
|
+
|
218
|
+
G1_with_integer_nulls = <<EOS
|
219
|
+
strict_null_mode
|
220
|
+
int_state\tinteger\tv\t\t
|
221
|
+
ltv\tnumrange\tv\t\t
|
222
|
+
fico\tnumrange\th\t\t
|
223
|
+
|
224
|
+
\t\t>=600<700\t>=700<750\t>=750
|
225
|
+
1\t<=80\t1.1\t2.2\t3.3
|
226
|
+
2\t>80<=105\t4.4\t5.5\t6.6
|
227
|
+
3\t<=80\t1.2\t2.3\t3.4
|
228
|
+
4|5\t>80<=105\t4.5\t5.6\t
|
229
|
+
NULL\t<=80\t11\t22\t33
|
190
230
|
EOS
|
191
231
|
|
192
232
|
before(:each) do
|
193
233
|
# Mcfly.whodunnit = Marty::User.find_by_login('marty')
|
194
234
|
marty_whodunnit
|
235
|
+
Rails.application.config.marty.data_grid_plpg_lookups = false
|
195
236
|
end
|
196
237
|
|
197
238
|
def lookup_grid_helper(pt, gridname, params, follow = false, distinct = true)
|
@@ -213,6 +254,110 @@ EOS
|
|
213
254
|
dg_from_import('Gh', Gh + "\t\t\n")
|
214
255
|
end.to raise_error(RuntimeError)
|
215
256
|
end
|
257
|
+
|
258
|
+
it 'show not allow import NULL fields unless strict_null_mode is on' do
|
259
|
+
expect do
|
260
|
+
dg_from_import(
|
261
|
+
'G1_with_nulls',
|
262
|
+
G1_with_nulls.gsub("strict_null_mode\n", '')
|
263
|
+
)
|
264
|
+
end.to raise_error(
|
265
|
+
/NULL is not supported in grids without strict_null_mode/
|
266
|
+
)
|
267
|
+
end
|
268
|
+
|
269
|
+
it 'should import wildcards' do
|
270
|
+
dg = dg_from_import('G1', G1)
|
271
|
+
state_attr = dg.metadata.find { |key| key['attr'] == 'state' }
|
272
|
+
expect(state_attr['keys'].last).to be nil
|
273
|
+
expect(state_attr['wildcards'].last).to be true
|
274
|
+
expect(state_attr['wildcards']).to eq [false, false, false, false, true]
|
275
|
+
end
|
276
|
+
|
277
|
+
it 'allows to import NULL values in string fields' do
|
278
|
+
dg = dg_from_import('G1_with_nulls', G1_with_nulls)
|
279
|
+
state_attr = dg.metadata.find { |key| key['attr'] == 'state' }
|
280
|
+
expect(state_attr['keys'].last).to be nil
|
281
|
+
expect(state_attr['wildcards'].last).to be false
|
282
|
+
|
283
|
+
# FIXME: do we actually need mixing nulls with values?
|
284
|
+
dg = dg_from_import(
|
285
|
+
'G1_with_nulls2',
|
286
|
+
G1_with_nulls.sub('NULL', 'NY|NULL')
|
287
|
+
)
|
288
|
+
state_attr = dg.metadata.find { |key| key['attr'] == 'state' }
|
289
|
+
expect(state_attr['keys'].last).to eq [nil, 'NY']
|
290
|
+
expect(state_attr['wildcards'].last).to be false
|
291
|
+
|
292
|
+
dg = dg_from_import(
|
293
|
+
'G1_with_nulls3',
|
294
|
+
G1_with_nulls.sub('NULL', 'NOT (NULL)')
|
295
|
+
)
|
296
|
+
|
297
|
+
state_attr = dg.metadata.find { |key| key['attr'] == 'state' }
|
298
|
+
expect(state_attr['keys'].last).to be nil
|
299
|
+
expect(state_attr['wildcards'].last).to be false
|
300
|
+
expect(state_attr['nots'].last).to be true
|
301
|
+
|
302
|
+
dg = dg_from_import(
|
303
|
+
'G1_with_nulls4',
|
304
|
+
G1_with_nulls.sub('NULL', 'NOT (NY|NULL)')
|
305
|
+
)
|
306
|
+
|
307
|
+
state_attr = dg.metadata.find { |key| key['attr'] == 'state' }
|
308
|
+
expect(state_attr['keys'].last).to eq [nil, 'NY']
|
309
|
+
expect(state_attr['wildcards'].last).to be false
|
310
|
+
expect(state_attr['nots'].last).to be true
|
311
|
+
end
|
312
|
+
|
313
|
+
it 'allows to import NULL values in integer field' do
|
314
|
+
dg = dg_from_import('G1_with_integer_nulls', G1_with_integer_nulls)
|
315
|
+
state_attr = dg.metadata.find { |key| key['attr'] == 'int_state' }
|
316
|
+
expect(state_attr['keys'].last).to be nil
|
317
|
+
expect(state_attr['wildcards'].last).to be false
|
318
|
+
|
319
|
+
dg = dg_from_import(
|
320
|
+
'G1_with_integer_nulls2',
|
321
|
+
G1_with_integer_nulls.sub('NULL', '6|NULL')
|
322
|
+
)
|
323
|
+
|
324
|
+
state_attr = dg.metadata.find { |key| key['attr'] == 'int_state' }
|
325
|
+
expect(state_attr['keys'].last).to eq [nil, 6]
|
326
|
+
expect(state_attr['nots'].last).to be false
|
327
|
+
expect(state_attr['wildcards'].last).to be false
|
328
|
+
|
329
|
+
dg = dg_from_import(
|
330
|
+
'G1_with_integer_nulls3',
|
331
|
+
G1_with_integer_nulls.sub('NULL', 'NOT (NULL)')
|
332
|
+
)
|
333
|
+
|
334
|
+
state_attr = dg.metadata.find { |key| key['attr'] == 'int_state' }
|
335
|
+
expect(state_attr['keys'].last).to be nil
|
336
|
+
expect(state_attr['nots'].last).to be true
|
337
|
+
expect(state_attr['wildcards'].last).to be false
|
338
|
+
|
339
|
+
dg = dg_from_import(
|
340
|
+
'G1_with_integer_nulls4',
|
341
|
+
G1_with_integer_nulls.sub('NULL', 'NOT (6|NULL)')
|
342
|
+
)
|
343
|
+
|
344
|
+
state_attr = dg.metadata.find { |key| key['attr'] == 'int_state' }
|
345
|
+
expect(state_attr['keys'].last).to eq [nil, 6]
|
346
|
+
expect(state_attr['nots'].last).to be true
|
347
|
+
expect(state_attr['wildcards'].last).to be false
|
348
|
+
end
|
349
|
+
|
350
|
+
it 'allows to import NULL values in boolean field' do
|
351
|
+
dg = dg_from_import('G1_with_bool_nulls', G1_with_bool_nulls)
|
352
|
+
state_attr = dg.metadata.find { |key| key['attr'] == 'bool_state' }
|
353
|
+
expect(state_attr['keys'].last).to be nil
|
354
|
+
expect(state_attr['wildcards'].last).to be false
|
355
|
+
|
356
|
+
dg = dg_from_import('G1_with_bool_nulls2', G1_with_bool_nulls.sub('NULL', 'NOT (NULL)'))
|
357
|
+
state_attr = dg.metadata.find { |key| key['attr'] == 'bool_state' }
|
358
|
+
expect(state_attr['keys'].last).to be nil
|
359
|
+
expect(state_attr['nots'].last).to be true
|
360
|
+
end
|
216
361
|
end
|
217
362
|
|
218
363
|
describe 'validations' do
|
@@ -306,7 +451,7 @@ EOS
|
|
306
451
|
|
307
452
|
before(:each) do
|
308
453
|
%w[G1 G2 G3 G4 G5 G6 G7 G8 Ga Gb
|
309
|
-
Gc Gd Ge Gf Gg Gh Gj Gl].each do |g|
|
454
|
+
Gc Gd Ge Gf Gg Gh Gj Gl G1_with_nulls].each do |g|
|
310
455
|
dg_from_import(g, "Marty::DataGridSpec::#{g}".constantize)
|
311
456
|
end
|
312
457
|
end
|
@@ -351,6 +496,24 @@ EOS
|
|
351
496
|
end
|
352
497
|
end
|
353
498
|
|
499
|
+
it 'should cast types' do
|
500
|
+
res = Marty::DataGrid.lookup_grid_h(pt, 'Gf', { 'i' => 13, 'n' => 15 }, true)
|
501
|
+
expect(res).to eq('N')
|
502
|
+
|
503
|
+
res = Marty::DataGrid.lookup_grid_h(pt, 'Gf', { 'i' => '13', 'n' => '15' }, true)
|
504
|
+
expect(res).to eq('N')
|
505
|
+
|
506
|
+
res = Marty::DataGrid.lookup_grid_h(pt, 'Gf', { 'b' => 'true', 'i4' => '6' }, false)
|
507
|
+
expect(res).to eq('Y')
|
508
|
+
|
509
|
+
res = Marty::DataGrid.lookup_grid_h(pt, 'Gg', { 'i1' => 2, 'i2' => 1 }, false)
|
510
|
+
expect(res).to eq(1)
|
511
|
+
|
512
|
+
dg_from_import('G9', G9)
|
513
|
+
res = Marty::DataGrid.lookup_grid_h(pt, 'G9', { 'state' => 4, 'ltv' => 81 }, false)
|
514
|
+
expect(res).to eq(456)
|
515
|
+
end
|
516
|
+
|
354
517
|
it 'should handle ambiguous lookups' do
|
355
518
|
h1 = {
|
356
519
|
'property_state' => 'NY',
|
@@ -454,7 +617,7 @@ EOS
|
|
454
617
|
'ltv' => 100,
|
455
618
|
'cltv' => 110.1,
|
456
619
|
)
|
457
|
-
end.to raise_error(RuntimeError)
|
620
|
+
end.to raise_error(RuntimeError, /matches > 1/)
|
458
621
|
end
|
459
622
|
|
460
623
|
it 'should return nil when matching data grid cell is nil' do
|
@@ -474,9 +637,81 @@ EOS
|
|
474
637
|
'state' => 'GU',
|
475
638
|
'ltv' => 80,
|
476
639
|
)
|
640
|
+
|
477
641
|
expect(res).to eq [22, 'G1']
|
478
642
|
end
|
479
643
|
|
644
|
+
it 'should treat nil as missing attr' do
|
645
|
+
expect do
|
646
|
+
res = lookup_grid_helper('infinity',
|
647
|
+
'G1',
|
648
|
+
'fico' => 720,
|
649
|
+
'state' => 'NM',
|
650
|
+
'ltv' => 80,
|
651
|
+
)
|
652
|
+
end.to raise_error(RuntimeError, /matches > 1/)
|
653
|
+
|
654
|
+
expect do
|
655
|
+
res = lookup_grid_helper('infinity',
|
656
|
+
'G1',
|
657
|
+
'fico' => 720,
|
658
|
+
'ltv' => 80,
|
659
|
+
)
|
660
|
+
end.to raise_error(RuntimeError, /matches > 1/)
|
661
|
+
|
662
|
+
expect do
|
663
|
+
res = lookup_grid_helper('infinity',
|
664
|
+
'G1',
|
665
|
+
'fico' => 720,
|
666
|
+
'state' => nil,
|
667
|
+
'ltv' => 80,
|
668
|
+
)
|
669
|
+
end.to raise_error(RuntimeError, /matches > 1/)
|
670
|
+
end
|
671
|
+
|
672
|
+
it 'should handle string NULLS' do
|
673
|
+
res = lookup_grid_helper('infinity',
|
674
|
+
'G1_with_nulls',
|
675
|
+
'fico' => 720,
|
676
|
+
'state' => nil,
|
677
|
+
'ltv' => 80,
|
678
|
+
)
|
679
|
+
|
680
|
+
expect(res).to eq [22, 'G1_with_nulls']
|
681
|
+
|
682
|
+
expect do
|
683
|
+
lookup_grid_helper('infinity',
|
684
|
+
'G1_with_nulls',
|
685
|
+
'fico' => 720,
|
686
|
+
'state' => 'BLABLA',
|
687
|
+
'ltv' => 80,
|
688
|
+
)
|
689
|
+
end.to raise_error(/Data Grid lookup failed/)
|
690
|
+
|
691
|
+
dg = dg_from_import(
|
692
|
+
'G1_with_nulls2',
|
693
|
+
G1_with_nulls.sub('NULL', 'NY|NULL')
|
694
|
+
)
|
695
|
+
|
696
|
+
res = lookup_grid_helper('infinity',
|
697
|
+
dg.name,
|
698
|
+
'fico' => 720,
|
699
|
+
'state' => nil,
|
700
|
+
'ltv' => 80,
|
701
|
+
)
|
702
|
+
|
703
|
+
expect(res).to eq [22, dg.name]
|
704
|
+
|
705
|
+
res = lookup_grid_helper('infinity',
|
706
|
+
dg.name,
|
707
|
+
'fico' => 720,
|
708
|
+
'state' => 'NY',
|
709
|
+
'ltv' => 80,
|
710
|
+
)
|
711
|
+
|
712
|
+
expect(res).to eq [22, dg.name]
|
713
|
+
end
|
714
|
+
|
480
715
|
it 'should handle matches which also have a wildcard match' do
|
481
716
|
dg_from_import('G9', G9)
|
482
717
|
|
@@ -485,7 +720,7 @@ EOS
|
|
485
720
|
'G9',
|
486
721
|
'state' => 'CA', 'ltv' => 81,
|
487
722
|
)
|
488
|
-
end.to raise_error(RuntimeError)
|
723
|
+
end.to raise_error(RuntimeError, /matches > 1/)
|
489
724
|
|
490
725
|
res = lookup_grid_helper('infinity',
|
491
726
|
'G9',
|
@@ -494,30 +729,42 @@ EOS
|
|
494
729
|
expect(res).to eq [456, 'G9']
|
495
730
|
end
|
496
731
|
|
497
|
-
it 'should raise on nil attr values' do
|
732
|
+
# it 'should raise on nil attr values' do
|
733
|
+
# next
|
734
|
+
# dg_from_import('G9', G9)
|
735
|
+
#
|
736
|
+
# expect do
|
737
|
+
# lookup_grid_helper('infinity',
|
738
|
+
# 'G9',
|
739
|
+
# 'ltv' => 81,
|
740
|
+
# )
|
741
|
+
# end.to raise_error(/matches > 1/)
|
742
|
+
#
|
743
|
+
# err = /Data Grid lookup failed/
|
744
|
+
# expect do
|
745
|
+
# lookup_grid_helper('infinity',
|
746
|
+
# 'G9',
|
747
|
+
# { 'state' => 'CA', 'ltv' => nil },
|
748
|
+
# false, false)
|
749
|
+
# end.to raise_error(err)
|
750
|
+
#
|
751
|
+
# res = lookup_grid_helper('infinity',
|
752
|
+
# 'G9',
|
753
|
+
# { 'state' => nil, 'ltv' => 81 },
|
754
|
+
# false, false)
|
755
|
+
#
|
756
|
+
# expect(res).to eq [456, 'G9']
|
757
|
+
# end
|
758
|
+
|
759
|
+
it 'should raise if nothing was found' do
|
498
760
|
dg_from_import('G9', G9)
|
499
761
|
|
500
762
|
expect do
|
501
763
|
lookup_grid_helper('infinity',
|
502
764
|
'G9',
|
503
|
-
'ltv' =>
|
765
|
+
'ltv' => 80,
|
504
766
|
)
|
505
|
-
end.to raise_error(/
|
506
|
-
|
507
|
-
err = /Data Grid lookup failed/
|
508
|
-
expect do
|
509
|
-
lookup_grid_helper('infinity',
|
510
|
-
'G9',
|
511
|
-
{ 'state' => 'CA', 'ltv' => nil },
|
512
|
-
false, false)
|
513
|
-
end.to raise_error(err)
|
514
|
-
|
515
|
-
res = lookup_grid_helper('infinity',
|
516
|
-
'G9',
|
517
|
-
{ 'state' => nil, 'ltv' => 81 },
|
518
|
-
false, false)
|
519
|
-
|
520
|
-
expect(res).to eq [456, 'G9']
|
767
|
+
end.to raise_error(/Data Grid lookup failed/)
|
521
768
|
end
|
522
769
|
|
523
770
|
it 'should handle boolean keys' do
|
@@ -635,21 +882,25 @@ EOS
|
|
635
882
|
'attr' => 'units',
|
636
883
|
'keys' => [[1, 2], [1, 2], [3, 4], [3, 4]],
|
637
884
|
'nots' => [false, false, false, false],
|
885
|
+
'wildcards' => [false, false, false, false],
|
638
886
|
'type' => 'integer' },
|
639
887
|
{ 'dir' => 'v',
|
640
888
|
'attr' => 'ltv',
|
641
889
|
'keys' => ['[,80]', '(80,105]', '[,80]', '(80,105]'],
|
642
890
|
'nots' => [false, false, false, false],
|
891
|
+
'wildcards' => [false, false, false, false],
|
643
892
|
'type' => 'numrange' },
|
644
893
|
{ 'dir' => 'h',
|
645
894
|
'attr' => 'cltv',
|
646
895
|
'keys' => ['[100,110)', '[110,120)', '[120,]'],
|
647
896
|
'nots' => [false, false, false],
|
897
|
+
'wildcards' => [false, false, false],
|
648
898
|
'type' => 'numrange' },
|
649
899
|
{ 'dir' => 'h',
|
650
900
|
'attr' => 'fico',
|
651
901
|
'keys' => ['[600,700)', '[700,750)', '[750,]'],
|
652
902
|
'nots' => [false, false, false],
|
903
|
+
'wildcards' => [false, false, false],
|
653
904
|
'type' => 'numrange' }]
|
654
905
|
|
655
906
|
dgh = Marty::DataGrid.lookup_h(pt, 'G2')
|
@@ -666,17 +917,20 @@ EOS
|
|
666
917
|
'attr' => 'state',
|
667
918
|
'keys' => [['CA'], ['HI', 'TX'], ['NM'], ['MA'], nil],
|
668
919
|
'nots' => [false, false, false, false, false],
|
920
|
+
'wildcards' => [false, false, false, false, true],
|
669
921
|
'type' => 'string' },
|
670
922
|
{ 'dir' => 'v',
|
671
923
|
'attr' => 'ltv',
|
672
924
|
'keys' => ['[,80]', '(80,105]', '[,80]', '(80,105]',
|
673
925
|
'[,80]'],
|
674
926
|
'nots' => [false, false, false, false, false],
|
927
|
+
'wildcards' => [false, false, false, false, false],
|
675
928
|
'type' => 'numrange' },
|
676
929
|
{ 'dir' => 'h',
|
677
930
|
'attr' => 'fico',
|
678
931
|
'keys' => ['[600,700)', '[700,750)', '[750,]'],
|
679
932
|
'nots' => [false, false, false],
|
933
|
+
'wildcards' => [false, false, false],
|
680
934
|
'type' => 'numrange' }]
|
681
935
|
dgh = Marty::DataGrid.lookup_h(pt, 'G8')
|
682
936
|
res = Marty::DataGrid.lookup_grid_distinct_entry_h(pt,
|
@@ -694,6 +948,7 @@ EOS
|
|
694
948
|
'attr' => 'ltv',
|
695
949
|
'keys' => ['[,115]', '(115,135]', '(135,140]'],
|
696
950
|
'nots' => [false, false, false],
|
951
|
+
'wildcards' => [false, false, false],
|
697
952
|
'type' => 'numrange' }]
|
698
953
|
dgh = Marty::DataGrid.lookup_h(pt, 'G8')
|
699
954
|
res = Marty::DataGrid.lookup_grid_distinct_entry_h(pt,
|
@@ -945,6 +1200,65 @@ EOS
|
|
945
1200
|
false\t\t>10\t\t#{values3[2]}
|
946
1201
|
EOS
|
947
1202
|
end
|
1203
|
+
|
1204
|
+
describe 'performance' do
|
1205
|
+
before(:each) do
|
1206
|
+
%w[G1 Gf Gl].each do |g|
|
1207
|
+
dg_from_import(g, "Marty::DataGridSpec::#{g}".constantize)
|
1208
|
+
end
|
1209
|
+
end
|
1210
|
+
|
1211
|
+
after do
|
1212
|
+
Rails.application.config.marty.data_grid_plpg_lookups = false
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
let(:pt) { 'infinity' }
|
1216
|
+
|
1217
|
+
grid_data = {
|
1218
|
+
'Gf' => { 'b' => true },
|
1219
|
+
'G1' => {
|
1220
|
+
'fico' => 600,
|
1221
|
+
'state' => 'RI',
|
1222
|
+
'ltv' => 10,
|
1223
|
+
},
|
1224
|
+
'Gl' => {
|
1225
|
+
'fha_203k_option2' => 'Not Existing Services'
|
1226
|
+
}
|
1227
|
+
}
|
1228
|
+
|
1229
|
+
grid_data.each_with_index do |(grid, params), index|
|
1230
|
+
it "ruby lookup is faster than plpgsql #{index}" do
|
1231
|
+
bm = Benchmark.ips do |x|
|
1232
|
+
x.report('postgres') do
|
1233
|
+
Rails.application.config.marty.data_grid_plpg_lookups = true
|
1234
|
+
res = Marty::DataGrid.lookup_grid_h(pt, grid, params, false)
|
1235
|
+
end
|
1236
|
+
|
1237
|
+
x.report('ruby') do
|
1238
|
+
Rails.application.config.marty.data_grid_plpg_lookups = false
|
1239
|
+
res = Marty::DataGrid.lookup_grid_h(pt, grid, params, false)
|
1240
|
+
end
|
1241
|
+
|
1242
|
+
x.compare!
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
h = bm.entries.each_with_object({}) do |e, hh|
|
1246
|
+
hh[e.label] = e.stats.central_tendency
|
1247
|
+
end
|
1248
|
+
|
1249
|
+
factor = h['ruby'] / h['postgres']
|
1250
|
+
|
1251
|
+
if ENV['CI'] == 'true'
|
1252
|
+
# Performance drops down in CI, probably due to running postgres
|
1253
|
+
# in a separate container utilizing it's own CPU core.
|
1254
|
+
expect(factor).to be > 0.8
|
1255
|
+
else
|
1256
|
+
expect(factor).to be > 1.02
|
1257
|
+
end
|
1258
|
+
end
|
1259
|
+
end
|
1260
|
+
end
|
1261
|
+
|
948
1262
|
describe 'constraint' do
|
949
1263
|
it 'constraint' do
|
950
1264
|
Mcfly.whodunnit = system_user
|