marty 4.0.0.rc2 → 5.1.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- 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
|