marty 4.0.0.rc2 → 5.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +5 -5
- data/.gitignore +7 -0
- data/.rubocop.yml +1 -0
- data/.rubocop_todo.yml +3 -16
- data/.ssh-docker/.keep +0 -0
- data/Dockerfile.dummy +3 -0
- data/Gemfile +19 -15
- data/app/components/marty/base_rule_view.rb +104 -10
- data/app/components/marty/base_rule_view/client/base_rule_view.js +24 -0
- data/app/components/marty/data_grid_user_view.rb +39 -0
- data/app/components/marty/data_grid_view.rb +68 -18
- data/app/components/marty/extras/layout.rb +1 -1
- data/app/components/marty/grid.rb +1 -1
- data/app/components/marty/grid/client/grid.js +29 -13
- data/app/components/marty/import_view.rb +3 -3
- data/app/components/marty/main_auth_app.rb +11 -1
- data/app/components/marty/report_form.rb +6 -6
- data/app/components/marty/script_form.rb +5 -5
- data/app/components/marty/script_tester.rb +2 -2
- data/app/components/marty/user_view.rb +3 -9
- data/app/models/marty/base_rule.rb +92 -32
- data/app/models/marty/data_grid.rb +92 -22
- data/app/models/marty/event.rb +2 -2
- data/app/models/marty/promise.rb +4 -4
- data/app/models/marty/role_type.rb +14 -1
- data/app/services/marty/data_grid_view/save_grid.rb +2 -2
- data/app/services/marty/promises/delorean/create.rb +2 -2
- data/app/services/marty/promises/ruby/create.rb +2 -2
- data/config/locales/en.yml +11 -2
- data/db/migrate/108_add_data_grid_perms.rb +16 -0
- data/db/migrate/508_add_not_to_data_grids_tables.rb +18 -0
- data/db/migrate/509_update_dg_plpgsql_v1_fns.rb +13 -0
- data/db/sql/query_grid_dir_v1.sql +16 -2
- data/docker-compose.dummy.yml +1 -0
- data/lib/marty/content_handler.rb +2 -2
- data/lib/marty/data_change.rb +1 -1
- data/lib/marty/data_conversion.rb +3 -4
- data/lib/marty/data_importer.rb +4 -4
- data/lib/marty/mcfly_model.rb +7 -10
- data/lib/marty/migrations.rb +1 -1
- data/lib/marty/monkey.rb +2 -2
- data/lib/marty/promise_job.rb +5 -5
- data/lib/marty/promise_proxy.rb +2 -2
- data/lib/marty/promise_ruby_job.rb +4 -4
- data/lib/marty/version.rb +1 -1
- data/make-app.mk +1 -1
- data/marty.gemspec +13 -18
- data/other/marty/diagnostic/aws/ec2_instance.rb +17 -2
- data/other/marty/diagnostic/aws/error.rb +8 -0
- data/other/marty/diagnostic/database.rb +2 -2
- data/other/marty/diagnostic/delayed_job_version.rb +0 -1
- data/spec/dummy/app/components/gemini/my_rule_view.rb +32 -6
- data/spec/dummy/app/models/gemini/fannie_bup.rb +13 -20
- data/spec/dummy/app/models/gemini/my_rule.rb +4 -0
- data/spec/dummy/app/models/gemini/xyz_rule.rb +3 -1
- data/spec/dummy/config/application.rb +1 -0
- data/spec/dummy/config/initializers/secret_token.rb +1 -1
- data/spec/dummy/db/migrate/20190702115241_add_simple_guards_options_to_rules.rb +37 -0
- data/spec/features/data_grid_spec.rb +109 -47
- data/spec/features/reporting_spec.rb +4 -4
- data/spec/features/rule_spec.rb +62 -31
- data/spec/features/scripting_spec.rb +3 -3
- data/spec/features/user_view_spec.rb +17 -8
- data/spec/fixtures/csv/rule/MyRule.csv +4 -1
- data/spec/lib/data_importer_spec.rb +8 -8
- data/spec/lib/mcfly_model_spec.rb +6 -6
- data/spec/models/data_grid_spec.rb +139 -7
- data/spec/models/rule_spec.rb +116 -9
- data/spec/spec_helper.rb +2 -2
- data/spec/support/netzke.rb +4 -3
- metadata +55 -54
- data/Gemfile.lock +0 -289
@@ -206,8 +206,8 @@ DELOREAN
|
|
206
206
|
end
|
207
207
|
|
208
208
|
wait_for_element do
|
209
|
-
expect(page).to have_content(
|
210
|
-
|
209
|
+
expect(page).to have_content("XYZ1,XYZ2,XYZ3,XYZ4\n1,2,3,4\n2,4,6,8\n" +
|
210
|
+
"3,6,9,12\n4,8,12,16")
|
211
211
|
end
|
212
212
|
end
|
213
213
|
|
@@ -263,8 +263,8 @@ DELOREAN
|
|
263
263
|
url = generate_rep_url(format: 'txt') + URI.encode('&disposition=inline')
|
264
264
|
visit url
|
265
265
|
wait_for_element do
|
266
|
-
expect(page).to have_content(
|
267
|
-
|
266
|
+
expect(page).to have_content("XYZ1,XYZ2,XYZ3,XYZ4\n1,2,3,4\n2,4,6,8\n" +
|
267
|
+
"3,6,9,12\n4,8,12,16")
|
268
268
|
end
|
269
269
|
end
|
270
270
|
|
data/spec/features/rule_spec.rb
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
require 'spec_helper'
|
2
|
-
require 'marty_rspec'
|
3
2
|
|
4
3
|
feature 'rule view', js: true do
|
5
4
|
before(:all) do
|
@@ -39,7 +38,6 @@ feature 'rule view', js: true do
|
|
39
38
|
JS
|
40
39
|
end
|
41
40
|
|
42
|
-
# click_checkbox in marty_rspec not working here for some reason
|
43
41
|
def click_checkbox(name)
|
44
42
|
q = %Q(checkbox[fieldLabel="#{name}"])
|
45
43
|
page.execute_script <<-JS
|
@@ -48,7 +46,6 @@ feature 'rule view', js: true do
|
|
48
46
|
JS
|
49
47
|
end
|
50
48
|
|
51
|
-
# click_col in marty_rspec is not reliable
|
52
49
|
def click_column(rv, name)
|
53
50
|
cid = col_id(rv, name)
|
54
51
|
c = find('#' + cid)
|
@@ -115,7 +112,7 @@ feature 'rule view', js: true do
|
|
115
112
|
time_fill_in(1, '08:03:01')
|
116
113
|
press('OK')
|
117
114
|
wait_for_ajax
|
118
|
-
expect(mrv.row_count()).to eq(
|
115
|
+
expect(mrv.row_count()).to eq(12)
|
119
116
|
expect(mrv.get_row_vals(1)).to include('name' => 'abc',
|
120
117
|
'rule_type' => 'SimpleRule',
|
121
118
|
'start_dt' => '2013-01-01T11:03:01',
|
@@ -339,7 +336,7 @@ computed_value = if paramb
|
|
339
336
|
else (grid2_grid_result||1) / param1
|
340
337
|
EOL
|
341
338
|
|
342
|
-
names = mrv.get_col_vals(:name,
|
339
|
+
names = mrv.get_col_vals(:name, 12, 0)
|
343
340
|
idx = names.index { |n| n == 'Rule3' } + 1
|
344
341
|
mrv.select_row(idx)
|
345
342
|
press('Edit')
|
@@ -362,35 +359,68 @@ EOL
|
|
362
359
|
'ZRule3', 'ZRule4',
|
363
360
|
'ZRule5'])
|
364
361
|
xrv.select_row(1)
|
362
|
+
|
363
|
+
expect(page).to_not have_content('NOT (G2V1)')
|
364
|
+
|
365
365
|
press('Edit')
|
366
|
-
|
367
|
-
fill_in('
|
366
|
+
|
367
|
+
fill_in('Guard two', with: 'G2V1')
|
368
|
+
click_checkbox('Not')
|
369
|
+
|
370
|
+
fill_in('Range Guard 1', with: '[100,200)', fill_options: { clear: :backspace })
|
371
|
+
fill_in('Range Guard 2', with: '[30,40)', fill_options: { clear: :backspace })
|
368
372
|
press('OK')
|
373
|
+
|
369
374
|
wait_for_ajax
|
370
|
-
|
371
|
-
|
375
|
+
|
376
|
+
r = Gemini::XyzRule.get_matches(
|
377
|
+
'infinity',
|
378
|
+
{},
|
379
|
+
'g_range1' => 150,
|
380
|
+
'g_range2' => 35,
|
381
|
+
'guard_two' => 'G2V2'
|
382
|
+
)
|
372
383
|
|
373
384
|
expect(r.to_a.count).to eq(1)
|
374
|
-
exp = {
|
375
|
-
|
376
|
-
|
377
|
-
|
378
|
-
|
379
|
-
|
380
|
-
|
381
|
-
|
382
|
-
|
383
|
-
|
384
|
-
|
385
|
-
|
386
|
-
|
387
|
-
|
388
|
-
|
389
|
-
|
390
|
-
|
391
|
-
|
385
|
+
exp = {
|
386
|
+
'user_id' => 1,
|
387
|
+
'o_user_id' => nil,
|
388
|
+
'name' => 'ZRule1',
|
389
|
+
'engine' => 'Gemini::XyzRuleScriptSet',
|
390
|
+
'rule_type' => 'ZRule',
|
391
|
+
'start_dt' => DateTime.parse('2017-1-1 08:01:00'),
|
392
|
+
'simple_guards' => {
|
393
|
+
'g_bool' => false,
|
394
|
+
'g_date' => '2017-1-1',
|
395
|
+
'guard_two' => 'G2V1',
|
396
|
+
'g_range1' => '[100,200)',
|
397
|
+
'g_range2' => '[30,40)',
|
398
|
+
'g_string' => 'aaa',
|
399
|
+
'g_integer' => '5',
|
400
|
+
'g_datetime' => '2017-1-1 12:00:01'
|
401
|
+
},
|
402
|
+
'simple_guards_options' => {
|
403
|
+
'g_bool' => { 'not' => false },
|
404
|
+
'g_date' => { 'not' => false },
|
405
|
+
'g_datetime' => { 'not' => false },
|
406
|
+
'g_integer' => { 'not' => false },
|
407
|
+
'g_range1' => { 'not' => false },
|
408
|
+
'g_range2' => { 'not' => false },
|
409
|
+
'g_string' => { 'not' => false },
|
410
|
+
'guard_two' => { 'not' => true }
|
411
|
+
},
|
412
|
+
'computed_guards' => {},
|
413
|
+
'grids' => { 'grid1' => 'DataGrid1' },
|
414
|
+
'results' => {
|
415
|
+
'bvlen' => 'base_value.length',
|
416
|
+
'bv' => 'base_value'
|
417
|
+
}
|
418
|
+
}
|
392
419
|
|
393
420
|
expect(r.first.as_json).to include(exp)
|
421
|
+
|
422
|
+
expect(page).to have_content('NOT (G2V1)')
|
423
|
+
|
394
424
|
expect(xrv.get_col_vals(:g_string, 8, 0)).to eq(['aaa', 'bbb', 'ccc', 'ddd',
|
395
425
|
'eee', 'eee', 'eee', 'eee'])
|
396
426
|
click_column(xrv, 'String list Guard')
|
@@ -418,8 +448,9 @@ EOL
|
|
418
448
|
%Q({"grid1":"DataGrid2"}),
|
419
449
|
%Q({"grid1":"DataGrid1"}),
|
420
450
|
%Q({"grid1":"DataGrid1"})])
|
451
|
+
|
421
452
|
press('Applications')
|
422
|
-
press('Data Grids')
|
453
|
+
press('Data Grids Admin')
|
423
454
|
dgv = netzke_find('data_grid_view')
|
424
455
|
cvs = dgv.get_col_vals(:name, 4, 0)
|
425
456
|
ind1 = cvs.index('DataGrid1') + 1
|
@@ -447,9 +478,9 @@ EOL
|
|
447
478
|
go_to_my_rules
|
448
479
|
wait_for_ajax
|
449
480
|
|
450
|
-
names = mrv.get_col_vals(:name,
|
451
|
-
gvs = mrv.get_col_vals(:grids,
|
452
|
-
rvs = mrv.get_col_vals(:results,
|
481
|
+
names = mrv.get_col_vals(:name, 12, 0)
|
482
|
+
gvs = mrv.get_col_vals(:grids, 12, 0)
|
483
|
+
rvs = mrv.get_col_vals(:results, 12, 0)
|
453
484
|
expect(JSON.parse(gvs[names.index('abc')])).to eq(g1h)
|
454
485
|
expect(JSON.parse(gvs[names.index('Rule2b')])).to eq(g1h +
|
455
486
|
{ 'grid2' => 'DataGrid2' })
|
@@ -221,7 +221,7 @@ feature 'under Applications menu, Scripting workflows', js: true do
|
|
221
221
|
|
222
222
|
and_by 'form displays correct body' do
|
223
223
|
wait_for_ajax
|
224
|
-
expect(page).to have_content
|
224
|
+
expect(page).to have_content "1\n#5\n2\n#1\n3\n#2\n4\n#3"
|
225
225
|
end
|
226
226
|
|
227
227
|
and_by 'select different tag' do
|
@@ -235,7 +235,7 @@ feature 'under Applications menu, Scripting workflows', js: true do
|
|
235
235
|
|
236
236
|
and_by 'form displays updated body' do
|
237
237
|
wait_for_ajax
|
238
|
-
expect(page).to have_content
|
238
|
+
expect(page).to have_content "1\n#5\n2\n#1"
|
239
239
|
end
|
240
240
|
end
|
241
241
|
|
@@ -288,7 +288,7 @@ feature 'under Applications menu, Scripting workflows', js: true do
|
|
288
288
|
tag_grid.select_row(2)
|
289
289
|
wait_for_ajax
|
290
290
|
script_grid.select_row(5)
|
291
|
-
expect(page).to have_content
|
291
|
+
expect(page).to have_content "1\n#123\n2\n#456"
|
292
292
|
expect(tag_grid.get_row_vals(2)).to netzke_include(comment: 'ABCD')
|
293
293
|
end
|
294
294
|
end
|
@@ -1,6 +1,6 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
feature 'under
|
3
|
+
feature 'under System menu, User Management worflows', js: true do
|
4
4
|
def go_to_user_view
|
5
5
|
press('System')
|
6
6
|
press('User Management')
|
@@ -8,7 +8,7 @@ feature 'under Sytem menu, User Management worflows', js: true do
|
|
8
8
|
end
|
9
9
|
|
10
10
|
def go_to_user_view_backdoor
|
11
|
-
sys_btn = first(:btn, 'System')
|
11
|
+
sys_btn = first(:btn, 'System') rescue nil
|
12
12
|
if sys_btn
|
13
13
|
sys_btn.click
|
14
14
|
expect(page).not_to have_content 'User Management'
|
@@ -77,6 +77,7 @@ feature 'under Sytem menu, User Management worflows', js: true do
|
|
77
77
|
|
78
78
|
and_by 'check row got edited' do
|
79
79
|
wait_for_ajax
|
80
|
+
r2 = user_view.get_row_vals(2)
|
80
81
|
expect(user_view.get_row_vals(2)).to netzke_include(
|
81
82
|
login: 'new_login',
|
82
83
|
firstname: 'new_fname',
|
@@ -114,6 +115,9 @@ feature 'under Sytem menu, User Management worflows', js: true do
|
|
114
115
|
by 'check buttons' do
|
115
116
|
find(:btn, 'New User', match: :first)
|
116
117
|
user_view.select_row(1)
|
118
|
+
expect { find(:btn, 'New User') }.not_to raise_error
|
119
|
+
expect { find(:btn, 'Edit') }.not_to raise_error
|
120
|
+
expect { find(:btn, 'Delete') }.not_to raise_error
|
117
121
|
expect(btn_disabled?('New User')).to be_falsy
|
118
122
|
expect(btn_disabled?('Edit')).to be_falsy
|
119
123
|
expect(btn_disabled?('Delete')).to be_falsy
|
@@ -127,6 +131,9 @@ feature 'under Sytem menu, User Management worflows', js: true do
|
|
127
131
|
by 'check buttons' do
|
128
132
|
find(:btn, 'New User', match: :first)
|
129
133
|
user_view.select_row(1)
|
134
|
+
expect { find(:btn, 'New User') }.not_to raise_error
|
135
|
+
expect { find(:btn, 'Edit') }.not_to raise_error
|
136
|
+
expect { find(:btn, 'Delete') }.not_to raise_error
|
130
137
|
expect(btn_disabled?('New User')).to be_falsy
|
131
138
|
expect(btn_disabled?('Edit')).to be_falsy
|
132
139
|
expect(btn_disabled?('Delete')).to be_falsy
|
@@ -140,9 +147,10 @@ feature 'under Sytem menu, User Management worflows', js: true do
|
|
140
147
|
user_view = netzke_find('user_view')
|
141
148
|
by 'check buttons' do
|
142
149
|
user_view.select_row(1)
|
143
|
-
|
144
|
-
|
145
|
-
|
150
|
+
err = /Unable to find btn/
|
151
|
+
['New User', 'Edit', 'Delete'].each do |btn_name|
|
152
|
+
expect { find(:btn, btn_name) }.to raise_error(err)
|
153
|
+
end
|
146
154
|
end
|
147
155
|
end
|
148
156
|
|
@@ -153,9 +161,10 @@ feature 'under Sytem menu, User Management worflows', js: true do
|
|
153
161
|
user_view = netzke_find('user_view')
|
154
162
|
by 'check buttons' do
|
155
163
|
user_view.select_row(1)
|
156
|
-
|
157
|
-
|
158
|
-
|
164
|
+
err = /Unable to find btn/
|
165
|
+
['New User', 'Edit', 'Delete'].each do |btn_name|
|
166
|
+
expect { find(:btn, btn_name) }.to raise_error(err)
|
167
|
+
end
|
159
168
|
end
|
160
169
|
end
|
161
170
|
end
|
@@ -1,4 +1,4 @@
|
|
1
|
-
name,rule_type,start_dt,end_dt,other_flag,simple_guards,computed_guards,grids,results
|
1
|
+
name,rule_type,start_dt,end_dt,other_flag,simple_guards,computed_guards,grids,results,simple_guards_options
|
2
2
|
Rule1,SimpleRule,2017-1-1 12:00:00,2017-4-1,,"{""g_has_default"":""different"",""g_array"":[""G1V1"",""G1V3""],""g_single"":""G2V2"",""g_string"":""Hi Mom"",""g_bool"":true,""g_bool_def"":false,""g_nbool_def"":true,""g_range"":""[50,)"",""g_integer"":10}",,,"{""simple_result"":""\""a value\""""}"
|
3
3
|
Rule2,SimpleRule,2017-2-1 14:00:00,2017-4-1,true,"{""g_array"":[""G1V2""],""g_single"":""G2V3"",""g_string"":""abc"",""g_bool"":true,""g_range"":""(,50]"",""g_integer"":11}",,,"{
|
4
4
|
""simple_result"":""\""b value\"" # with comment "",
|
@@ -13,3 +13,6 @@ Rule2c,SimpleRule,2017-2-1 14:00:00,2017-4-1,true,"{""g_array"":[""G1V2""],""g_s
|
|
13
13
|
Rule3,ComplexRule,2017-3-1 00:00:00,2017-4-1,false,"{""g_array"":[""G1V2"",""G1V3""],""g_string"":""def"",""g_integer"":11}","{""cguard1"":""1==1"",""cguard2"":""[param2 == 'abc', \""a string\""]""}","{""grid1"":""DataGrid1"",""grid2"":""DataGrid2""}","{""simple_result"":""\""c value\"""",""computed_value"":""if paramb\n then param1 / (grid1_grid_result||1)\n else (grid2_grid_result||1) / param1""}"
|
14
14
|
Rule4,ComplexRule,2017-4-1 15:00:01,2017-5-1,,"{""g_array"":[""G1V2"",""G1V3""],""g_string"":""Hi Mom"",""g_integer"":11}","{""cguard1"":""1==1"",""cguard2"":""param2 == \""abc\""""}","{""grid1"":""DataGrid1"",""grid2"":""DataGrid2""}","{""computed_name_grid"":""\""DataGrid\""+\""X\"""", ""simple_result"":""computed_name_grid"",""grid_sum"":""computed_name_grid_result + (grid1_grid_result||0)+(grid2_grid_result||0)""}"
|
15
15
|
Rule5,ComplexRule,2017-4-2 15:00:01,2017-5-1,,"{""g_string"":""zzz"",""g_integer"":3757,""g_has_default"":""foo""}","{""cguard1"":""[1==1, \""a string\""]""}",,"{""flavor"": ""[\""cherry\"",\""lemon\""][param2]"",""other_grid"": ""\""DataGrid4\"""",""final_value"": ""other_grid_result * 3""}"
|
16
|
+
NotRule1,SimpleRule,2017-4-2 15:00:01,2017-5-1,,"{""g_string"":""zzz"",""g_range"":""(,20]"",""g_integer"":3757,""g_has_default"":""foo"",""g_bool"":false,""g_array"":[""G1V1""]}","{""cguard1"":""[1==1, \""a string\""]""}",,"{""flavor"": ""[\""cherry\"",\""lemon\""][param2]"",""other_grid"": ""\""DataGrid4\"""",""final_value"": ""other_grid_result * 3""}","{""g_string"":{""not"":true},""g_integer"":{""not"":false}}"
|
17
|
+
NotRule2,SimpleRule,2017-4-2 15:00:01,2017-5-1,,"{""g_string"":""zzz"",""g_range"":""(,20]"",""g_integer"":3757,""g_has_default"":""foo"",""g_bool"":false,""g_array"":[""G1V1""]}","{""cguard1"":""[1==1, \""a string\""]""}",,"{""flavor"": ""[\""cherry\"",\""lemon\""][param2]"",""other_grid"": ""\""DataGrid4\"""",""final_value"": ""other_grid_result * 3""}","{""g_string"":{""not"":true},""g_integer"":{""not"":true}}"
|
18
|
+
NotRule3,SimpleRule,2017-4-2 15:00:01,2017-5-1,,"{""g_string"":""zzz"",""g_range"":""(,200]"",""g_integer"":3757,""g_has_default"":""foo"",""g_bool"":false,""g_array"":[""G1V1""]}","{""cguard1"":""[1==1, \""a string\""]""}",,"{""flavor"": ""[\""cherry\"",\""lemon\""][param2]"",""other_grid"": ""\""DataGrid4\"""",""final_value"": ""other_grid_result * 3""}","{""g_string"":{""not"":true},""g_integer"":{""not"":true}, ""g_range"":{""not"":true}}"
|
@@ -349,8 +349,8 @@ describe DataImporter do
|
|
349
349
|
|
350
350
|
begin
|
351
351
|
Marty::DataImporter.do_import_summary(Gemini::FannieBup, fannie_bup4)
|
352
|
-
rescue Marty::DataImporter::Error =>
|
353
|
-
|
352
|
+
rescue Marty::DataImporter::Error => e
|
353
|
+
e.lines.should == [0]
|
354
354
|
else
|
355
355
|
raise 'should have had an exception'
|
356
356
|
end
|
@@ -390,9 +390,9 @@ describe DataImporter do
|
|
390
390
|
|
391
391
|
begin
|
392
392
|
Marty::DataImporter.do_import_summary(Gemini::FannieBup, fannie_bup5)
|
393
|
-
rescue Marty::DataImporter::Error =>
|
394
|
-
|
395
|
-
|
393
|
+
rescue Marty::DataImporter::Error => e
|
394
|
+
e.lines.should == [1]
|
395
|
+
e.message.should =~ /Conv Fixed XX/
|
396
396
|
else
|
397
397
|
raise 'should have had an exception'
|
398
398
|
end
|
@@ -409,9 +409,9 @@ describe DataImporter do
|
|
409
409
|
begin
|
410
410
|
res = Marty::DataImporter.
|
411
411
|
do_import_summary(Gemini::FannieBup, fannie_bup6)
|
412
|
-
rescue Marty::DataImporter::Error =>
|
413
|
-
|
414
|
-
|
412
|
+
rescue Marty::DataImporter::Error => e
|
413
|
+
e.lines.should == [1]
|
414
|
+
e.message.should =~ /bad float/
|
415
415
|
else
|
416
416
|
raise 'should have had an exception'
|
417
417
|
end
|
@@ -113,16 +113,16 @@ describe 'McflyModel' do
|
|
113
113
|
a1 = @engine.evaluate('A', 'lookup', params)
|
114
114
|
a2 = @engine.evaluate('A', 'clookup', params)
|
115
115
|
expect(a1).to eq(a2) # cache/non return same
|
116
|
-
expect(a1.class).to eq(
|
117
|
-
expect(a2.class).to eq(
|
116
|
+
expect(a1.class).to eq(OpenStruct) # mode default so return OS
|
117
|
+
expect(a2.class).to eq(OpenStruct)
|
118
118
|
|
119
119
|
# check that keys are non mcfly non uniqueness
|
120
|
-
expect(a1.to_h.keys.to_set).to eq(Set[
|
120
|
+
expect(a1.to_h.keys.to_set).to eq(Set[:buy_up, :buy_down])
|
121
121
|
end
|
122
122
|
|
123
123
|
it 'lookup non generated' do
|
124
124
|
# a1 will be AR Relations
|
125
|
-
# b1 will be
|
125
|
+
# b1 will be OpenStructs because the b fns return #first
|
126
126
|
e_id = Gemini::Entity.where(name: 'PLS').first.id
|
127
127
|
bc_id = Gemini::BudCategory.where(name: 'Conv Fixed 20').first.id
|
128
128
|
p = { 'e_id' => e_id, 'bc_id' => bc_id }
|
@@ -141,10 +141,10 @@ describe 'McflyModel' do
|
|
141
141
|
# a1 is AR but still missing the FK entity_id so will raise
|
142
142
|
expect { a1.first.entity }.to raise_error(/missing attribute: entity_id/)
|
143
143
|
|
144
|
-
expect(b1.class).to eq(
|
144
|
+
expect(b1.class).to eq(OpenStruct)
|
145
145
|
|
146
146
|
# make sure b1 has correct keys
|
147
|
-
expect(b1.to_h.keys.to_set).to eq(Set[
|
147
|
+
expect(b1.to_h.keys.to_set).to eq(Set[:buy_up, :buy_down])
|
148
148
|
end
|
149
149
|
|
150
150
|
it 'lookup mode nil' do
|
@@ -177,6 +177,16 @@ Investor Services\t-0.625
|
|
177
177
|
Admin Services\t-1.0
|
178
178
|
Admin Services Plus\t-1.625
|
179
179
|
Investor Services Acadamy\t-0.5
|
180
|
+
EOS
|
181
|
+
|
182
|
+
Gl = <<EOS
|
183
|
+
lenient
|
184
|
+
fha_203k_option2\tstring\tv\tfha_203k_option2
|
185
|
+
|
186
|
+
Investor Services\t-0.625
|
187
|
+
NOT (Admin Premium Services|Admin Services|Admin Services Plus)\t-1.0
|
188
|
+
Admin Services Plus\t-1.625
|
189
|
+
Investor Services Acadamy\t-0.5
|
180
190
|
EOS
|
181
191
|
|
182
192
|
before(:each) do
|
@@ -295,8 +305,8 @@ EOS
|
|
295
305
|
let(:pt) { 'infinity' }
|
296
306
|
|
297
307
|
before(:each) do
|
298
|
-
[
|
299
|
-
|
308
|
+
%w[G1 G2 G3 G4 G5 G6 G7 G8 Ga Gb
|
309
|
+
Gc Gd Ge Gf Gg Gh Gj Gl].each do |g|
|
300
310
|
dg_from_import(g, "Marty::DataGridSpec::#{g}".constantize)
|
301
311
|
end
|
302
312
|
end
|
@@ -624,18 +634,22 @@ EOS
|
|
624
634
|
expected_metadata = [{ 'dir' => 'v',
|
625
635
|
'attr' => 'units',
|
626
636
|
'keys' => [[1, 2], [1, 2], [3, 4], [3, 4]],
|
637
|
+
'nots' => [false, false, false, false],
|
627
638
|
'type' => 'integer' },
|
628
639
|
{ 'dir' => 'v',
|
629
640
|
'attr' => 'ltv',
|
630
641
|
'keys' => ['[,80]', '(80,105]', '[,80]', '(80,105]'],
|
642
|
+
'nots' => [false, false, false, false],
|
631
643
|
'type' => 'numrange' },
|
632
644
|
{ 'dir' => 'h',
|
633
645
|
'attr' => 'cltv',
|
634
646
|
'keys' => ['[100,110)', '[110,120)', '[120,]'],
|
647
|
+
'nots' => [false, false, false],
|
635
648
|
'type' => 'numrange' },
|
636
649
|
{ 'dir' => 'h',
|
637
650
|
'attr' => 'fico',
|
638
651
|
'keys' => ['[600,700)', '[700,750)', '[750,]'],
|
652
|
+
'nots' => [false, false, false],
|
639
653
|
'type' => 'numrange' }]
|
640
654
|
|
641
655
|
dgh = Marty::DataGrid.lookup_h(pt, 'G2')
|
@@ -651,15 +665,18 @@ EOS
|
|
651
665
|
expected_metadata = [{ 'dir' => 'v',
|
652
666
|
'attr' => 'state',
|
653
667
|
'keys' => [['CA'], ['HI', 'TX'], ['NM'], ['MA'], nil],
|
668
|
+
'nots' => [false, false, false, false, false],
|
654
669
|
'type' => 'string' },
|
655
670
|
{ 'dir' => 'v',
|
656
671
|
'attr' => 'ltv',
|
657
672
|
'keys' => ['[,80]', '(80,105]', '[,80]', '(80,105]',
|
658
673
|
'[,80]'],
|
674
|
+
'nots' => [false, false, false, false, false],
|
659
675
|
'type' => 'numrange' },
|
660
676
|
{ 'dir' => 'h',
|
661
677
|
'attr' => 'fico',
|
662
678
|
'keys' => ['[600,700)', '[700,750)', '[750,]'],
|
679
|
+
'nots' => [false, false, false],
|
663
680
|
'type' => 'numrange' }]
|
664
681
|
dgh = Marty::DataGrid.lookup_h(pt, 'G8')
|
665
682
|
res = Marty::DataGrid.lookup_grid_distinct_entry_h(pt,
|
@@ -676,6 +693,7 @@ EOS
|
|
676
693
|
expected_metadata = [{ 'dir' => 'v',
|
677
694
|
'attr' => 'ltv',
|
678
695
|
'keys' => ['[,115]', '(115,135]', '(135,140]'],
|
696
|
+
'nots' => [false, false, false],
|
679
697
|
'type' => 'numrange' }]
|
680
698
|
dgh = Marty::DataGrid.lookup_h(pt, 'G8')
|
681
699
|
res = Marty::DataGrid.lookup_grid_distinct_entry_h(pt,
|
@@ -698,6 +716,7 @@ EOS
|
|
698
716
|
dgh, nil, false, true)
|
699
717
|
end
|
700
718
|
end
|
719
|
+
|
701
720
|
it 'should handle all quote chars in grid inputs' do
|
702
721
|
dgh = Marty::DataGrid.lookup_h(pt, 'G1')
|
703
722
|
# single, double, backslash, grave, acute, unicode quotes: left single,
|
@@ -710,12 +729,70 @@ EOS
|
|
710
729
|
pt, { 'ltv' => 10, 'fico' => 690, 'state' => st }, dgh, nil, false, true)
|
711
730
|
end
|
712
731
|
end
|
732
|
+
|
713
733
|
it 'should handle quote chars in object name' do
|
714
734
|
dgh = Marty::DataGrid.lookup_h(pt, 'G1')
|
715
735
|
st = Gemini::State.new(name: "'\\")
|
716
736
|
res = Marty::DataGrid.lookup_grid_distinct_entry_h(
|
717
737
|
pt, { 'ltv' => 10, 'fico' => 690, 'state' => st }, dgh, nil, false, true)
|
718
738
|
end
|
739
|
+
|
740
|
+
it 'Should handle NOT condition in lookups' do
|
741
|
+
dgh = Marty::DataGrid.lookup_h(pt, 'Gl')
|
742
|
+
|
743
|
+
g1_res = lookup_grid_helper(
|
744
|
+
'infinity',
|
745
|
+
'Gl',
|
746
|
+
{ 'fha_203k_option2' => 'Admin Services Plus' },
|
747
|
+
false,
|
748
|
+
true
|
749
|
+
)
|
750
|
+
expect(g1_res).to eq([-1.625, 'Gl'])
|
751
|
+
|
752
|
+
g1_res = lookup_grid_helper(
|
753
|
+
'infinity',
|
754
|
+
'Gl',
|
755
|
+
{ 'fha_203k_option2' => 'Not Existing Services' },
|
756
|
+
false,
|
757
|
+
true
|
758
|
+
)
|
759
|
+
expect(g1_res).to eq([-1.0, 'Gl'])
|
760
|
+
|
761
|
+
g1_res = lookup_grid_helper(
|
762
|
+
'infinity',
|
763
|
+
'Gl',
|
764
|
+
{ 'fha_203k_option2' => 'Admin Services' },
|
765
|
+
false,
|
766
|
+
true
|
767
|
+
)
|
768
|
+
expect(g1_res).to eq([nil, 'Gl'])
|
769
|
+
end
|
770
|
+
|
771
|
+
it 'Should handle NOT condition in import' do
|
772
|
+
dg = dg_from_import('Gl0', Gl)
|
773
|
+
expect(dg.id).to be_present
|
774
|
+
|
775
|
+
expect(dg.metadata.first['nots']).to eq([false, true, false, false])
|
776
|
+
expect(dg.metadata.first['keys']).to eq(
|
777
|
+
[
|
778
|
+
['Investor Services'],
|
779
|
+
['Admin Premium Services', 'Admin Services', 'Admin Services Plus'],
|
780
|
+
['Admin Services Plus'],
|
781
|
+
['Investor Services Acadamy']
|
782
|
+
]
|
783
|
+
)
|
784
|
+
|
785
|
+
indexes = Marty::GridIndexString.where(data_grid_id: dg.id)
|
786
|
+
|
787
|
+
expect(indexes.size).to eq 4
|
788
|
+
expect(indexes.where(not: true).size).to eq 1
|
789
|
+
|
790
|
+
not_index = indexes.find_by(not: true)
|
791
|
+
expect(not_index.key).to eq(
|
792
|
+
['Admin Premium Services', 'Admin Services', 'Admin Services Plus']
|
793
|
+
)
|
794
|
+
expect(not_index.index).to eq(1)
|
795
|
+
end
|
719
796
|
end
|
720
797
|
|
721
798
|
describe 'exports' do
|
@@ -725,6 +802,11 @@ EOS
|
|
725
802
|
|
726
803
|
expect(dg.export).to eq(dg2.export)
|
727
804
|
end
|
805
|
+
|
806
|
+
it 'Should handle NOT condition in export' do
|
807
|
+
dg = dg_from_import('Gl0', Gl)
|
808
|
+
expect(dg.export.delete("\r")).to eq(Gl)
|
809
|
+
end
|
728
810
|
end
|
729
811
|
|
730
812
|
describe 'updates' do
|
@@ -757,15 +839,50 @@ EOS
|
|
757
839
|
end
|
758
840
|
|
759
841
|
it 'should be able to export and import back grids' do
|
760
|
-
[G1, G2, G3, G4, G5, G6, G7, G8, G9, Ga, Gb].each_with_index do |grid, i|
|
842
|
+
[G1, G2, G3, G4, G5, G6, G7, G8, G9, Ga, Gb, Gl].each_with_index do |grid, i|
|
761
843
|
dg = dg_from_import("G#{i}", grid)
|
762
844
|
g1 = dg.export
|
845
|
+
|
763
846
|
dg = dg_from_import("Gx#{i}", g1)
|
764
847
|
g2 = dg.export
|
848
|
+
|
849
|
+
dg1 = Marty::DataGrid.lookup_h('infinity', "G#{i}").except(
|
850
|
+
'id',
|
851
|
+
'group_id',
|
852
|
+
'created_dt',
|
853
|
+
'name',
|
854
|
+
)
|
855
|
+
|
856
|
+
dg2 = Marty::DataGrid.lookup_h('infinity', "Gx#{i}").except(
|
857
|
+
'id',
|
858
|
+
'group_id',
|
859
|
+
'created_dt',
|
860
|
+
'name',
|
861
|
+
)
|
862
|
+
|
765
863
|
expect(g1).to eq g2
|
864
|
+
expect(dg1).to eq dg2
|
766
865
|
end
|
767
866
|
end
|
768
867
|
|
868
|
+
it 'Should handle NOT condition in update' do
|
869
|
+
dgb = dg_from_import('Gl', Gl, '1/1/2014')
|
870
|
+
new_gl = Gl.sub(/-1.0/, '-3.45').sub('Investor Services', 'NOT (Investor Services)')
|
871
|
+
dgb.update_from_import('Gl', new_gl, '1/1/2015')
|
872
|
+
|
873
|
+
grids = Marty::DataGrid.where(name: 'Gl')
|
874
|
+
expect(grids.size).to eq 2
|
875
|
+
|
876
|
+
old_dg = grids.where.not(obsoleted_dt: 'infinity').first
|
877
|
+
new_dg = grids.where(obsoleted_dt: 'infinity').first
|
878
|
+
|
879
|
+
expect(old_dg.metadata.first['nots']).to eq [false, true, false, false]
|
880
|
+
expect(old_dg.data).to eq [[-0.625], [-1.0], [-1.625], [-0.5]]
|
881
|
+
|
882
|
+
expect(new_dg.metadata.first['nots']).to eq [true, true, false, false]
|
883
|
+
expect(new_dg.data).to eq [[-0.625], [-3.45], [-1.625], [-0.5]]
|
884
|
+
end
|
885
|
+
|
769
886
|
it 'should be able to externally export/import grids' do
|
770
887
|
load_scripts(nil, Date.today)
|
771
888
|
|
@@ -814,7 +931,8 @@ EOS
|
|
814
931
|
# rubocop:disable Style/NestedTernaryOperator
|
815
932
|
type_str = type == 'float' ? (explicit_float ? 'float' : nil) : type
|
816
933
|
# rubocop:enable Style/NestedTernaryOperator
|
817
|
-
|
934
|
+
con_part = constraint.present? ? "\t" + constraint : ''
|
935
|
+
top = [lenient_str, type_str].compact.join(' ') + con_part + "\n"
|
818
936
|
(top =~ /\A\s*\z/ ? '' : top) +
|
819
937
|
<<~EOS
|
820
938
|
b\tboolean\tv
|
@@ -836,8 +954,8 @@ EOS
|
|
836
954
|
tests = JSON.parse(File.read('spec/fixtures/json/data_grid.json'))
|
837
955
|
aggregate_failures do
|
838
956
|
tests.each do |test|
|
839
|
-
keys = %w[id type constraint values error]
|
840
|
-
id, type, constraint, values, error = test.values_at(*keys)
|
957
|
+
keys = %w[id type constraint values error line1]
|
958
|
+
id, type, constraint, values, error, line1 = test.values_at(*keys)
|
841
959
|
err_re = Regexp.new(error) if error
|
842
960
|
# for float, do both ex- and implicit declaration
|
843
961
|
exfls = type == 'float' ? [true, false] : [true]
|
@@ -848,7 +966,21 @@ EOS
|
|
848
966
|
got = nil
|
849
967
|
tnam = "Test #{id} lenient=#{lenient} exfl=#{exfl}"
|
850
968
|
begin
|
851
|
-
dg_from_import(tnam, grid)
|
969
|
+
dg = dg_from_import(tnam, grid)
|
970
|
+
|
971
|
+
# make sure export of line1 works correctly
|
972
|
+
# when dg is lenient and/or has constraint and/or
|
973
|
+
# not float
|
974
|
+
next unless lenient || constraint.present? ||
|
975
|
+
type != 'float'
|
976
|
+
|
977
|
+
# also skip grids where we included float explicitly
|
978
|
+
# because export will convert back to implicit
|
979
|
+
next if type == 'float' && exfl
|
980
|
+
|
981
|
+
dga = dg.export_array
|
982
|
+
line1 = dga.first.first.join("\t") + "\n"
|
983
|
+
expect(line1).to eq(grid.lines.first)
|
852
984
|
rescue StandardError => e
|
853
985
|
got = e.message
|
854
986
|
end
|