marty 2.5.2 → 2.5.4
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 +4 -0
- data/.rubocop.yml +7 -0
- data/.rubocop_todo.yml +11 -589
- data/Gemfile +9 -9
- data/Gemfile.lock +1 -1
- data/Rakefile +1 -3
- data/app/components/marty/api_auth_view.rb +3 -3
- data/app/components/marty/api_config_view.rb +8 -8
- data/app/components/marty/api_log_view.rb +16 -20
- data/app/components/marty/auth_app.rb +6 -6
- data/app/components/marty/base_rule_view.rb +27 -19
- data/app/components/marty/config_view.rb +12 -9
- data/app/components/marty/data_grid_view.rb +26 -26
- data/app/components/marty/delorean_rule_view.rb +0 -1
- data/app/components/marty/event_view.rb +27 -27
- data/app/components/marty/extras/layout.rb +26 -26
- data/app/components/marty/extras/misc.rb +2 -2
- data/app/components/marty/grid.rb +13 -13
- data/app/components/marty/grid_append_only.rb +0 -1
- data/app/components/marty/import_type_view.rb +13 -13
- data/app/components/marty/import_view.rb +17 -16
- data/app/components/marty/log_view.rb +16 -14
- data/app/components/marty/main_auth_app.rb +59 -59
- data/app/components/marty/main_auth_app/client/main_auth_app.js +3 -3
- data/app/components/marty/mcfly_grid_panel.rb +10 -10
- data/app/components/marty/new_posting_form.rb +11 -11
- data/app/components/marty/new_posting_window.rb +0 -1
- data/app/components/marty/posting_grid.rb +12 -13
- data/app/components/marty/promise_view.rb +6 -6
- data/app/components/marty/report_form.rb +50 -53
- data/app/components/marty/report_select.rb +27 -27
- data/app/components/marty/reporting.rb +4 -4
- data/app/components/marty/script_form.rb +40 -42
- data/app/components/marty/script_grid.rb +24 -24
- data/app/components/marty/script_tester.rb +40 -42
- data/app/components/marty/scripting.rb +25 -27
- data/app/components/marty/simple_app.rb +24 -9
- data/app/components/marty/tag_grid.rb +12 -13
- data/app/components/marty/user_view.rb +35 -35
- data/app/controllers/marty/application_controller.rb +3 -4
- data/app/controllers/marty/components_controller.rb +1 -1
- data/app/controllers/marty/delayed_job_controller.rb +1 -0
- data/app/controllers/marty/diagnostic/controller.rb +4 -6
- data/app/controllers/marty/job_controller.rb +6 -6
- data/app/controllers/marty/report_controller.rb +11 -11
- data/app/controllers/marty/rpc_controller.rb +15 -16
- data/app/helpers/marty/script_set.rb +4 -4
- data/app/models/marty/api_auth.rb +4 -5
- data/app/models/marty/api_config.rb +1 -1
- data/app/models/marty/base.rb +9 -8
- data/app/models/marty/base_rule.rb +18 -13
- data/app/models/marty/config.rb +4 -5
- data/app/models/marty/data_grid.rb +157 -181
- data/app/models/marty/delorean_rule.rb +63 -62
- data/app/models/marty/enum.rb +1 -1
- data/app/models/marty/event.rb +56 -59
- data/app/models/marty/helper.rb +38 -6
- data/app/models/marty/import_type.rb +6 -6
- data/app/models/marty/log.rb +3 -2
- data/app/models/marty/name_validator.rb +3 -2
- data/app/models/marty/pg_enum.rb +3 -4
- data/app/models/marty/posting.rb +20 -24
- data/app/models/marty/promise.rb +28 -30
- data/app/models/marty/script.rb +30 -28
- data/app/models/marty/tag.rb +8 -8
- data/app/models/marty/token.rb +2 -2
- data/app/models/marty/user.rb +24 -23
- data/app/models/marty/vw_promise.rb +10 -11
- data/config/routes.rb +2 -2
- data/delorean/blame_report.dl +268 -0
- data/{spec/dummy/delorean/fields.dl → delorean/marty_fields.dl} +8 -0
- data/delorean/table_report.dl +34 -0
- data/docker-compose.dummy.yml +2 -3
- data/lib/marty/aws/base.rb +8 -8
- data/lib/marty/aws/request.rb +4 -4
- data/lib/marty/cache_adapters/mcfly_ruby_cache.rb +1 -0
- data/lib/marty/content_handler.rb +25 -25
- data/lib/marty/data_change.rb +49 -71
- data/lib/marty/data_conversion.rb +20 -28
- data/lib/marty/data_exporter.rb +25 -28
- data/lib/marty/data_importer.rb +25 -27
- data/lib/marty/engine.rb +1 -2
- data/lib/marty/json_schema.rb +22 -24
- data/lib/marty/logger.rb +6 -9
- data/lib/marty/mcfly_model.rb +20 -24
- data/lib/marty/migrations.rb +37 -35
- data/lib/marty/monkey.rb +33 -33
- data/lib/marty/permissions.rb +18 -18
- data/lib/marty/promise_job.rb +17 -17
- data/lib/marty/promise_proxy.rb +6 -6
- data/lib/marty/relation.rb +6 -7
- data/lib/marty/rpc_call.rb +13 -12
- data/lib/marty/rule_script_set.rb +32 -28
- data/lib/marty/schema_helper.rb +37 -51
- data/lib/marty/util.rb +25 -24
- data/lib/marty/version.rb +1 -1
- data/lib/marty/xl.rb +121 -115
- data/make-dummy.mk +3 -0
- data/marty.gemspec +21 -21
- data/other/marty/api/base.rb +34 -35
- data/other/marty/diagnostic/aws/ec2_instance.rb +8 -8
- data/other/marty/diagnostic/base.rb +13 -14
- data/other/marty/diagnostic/collection.rb +2 -1
- data/other/marty/diagnostic/connections.rb +8 -6
- data/other/marty/diagnostic/database.rb +1 -0
- data/other/marty/diagnostic/delayed_job_version.rb +7 -9
- data/other/marty/diagnostic/delayed_job_worker_total_count.rb +1 -1
- data/other/marty/diagnostic/delayed_job_workers.rb +1 -1
- data/other/marty/diagnostic/environment_variables.rb +17 -15
- data/other/marty/diagnostic/fatal.rb +1 -1
- data/other/marty/diagnostic/node.rb +5 -9
- data/other/marty/diagnostic/nodes.rb +7 -5
- data/other/marty/diagnostic/packer.rb +7 -7
- data/other/marty/diagnostic/reporter.rb +24 -27
- data/other/marty/diagnostic/version.rb +3 -5
- data/script/rails +2 -1
- data/spec/controllers/application_controller_spec.rb +6 -6
- data/spec/controllers/delayed_job_controller_spec.rb +4 -4
- data/spec/controllers/diagnostic/controller_spec.rb +59 -60
- data/spec/controllers/job_controller_spec.rb +68 -69
- data/spec/controllers/rpc_controller_spec.rb +353 -359
- data/spec/controllers/rpc_import_spec.rb +15 -16
- data/spec/dummy/delorean/blame_report.dl +110 -15
- data/spec/dummy/delorean/data_report.dl +4 -4
- data/spec/dummy/delorean/marty_fields.dl +63 -0
- data/spec/dummy/delorean/table_report.dl +34 -0
- data/spec/features/auth_app_spec.rb +1 -2
- data/spec/features/data_import_spec.rb +2 -3
- data/spec/features/enum_spec.rb +42 -46
- data/spec/features/jobs_dashboard_spec.rb +14 -8
- data/spec/features/log_view_spec.rb +40 -43
- data/spec/features/reporting_spec.rb +15 -15
- data/spec/features/rule_spec.rb +195 -190
- data/spec/features/scripting_spec.rb +17 -20
- data/spec/features/scripting_test_spec.rb +32 -33
- data/spec/features/user_view_spec.rb +15 -17
- data/spec/job_helper.rb +11 -11
- data/spec/lib/data_blame_spec.rb +82 -0
- data/spec/lib/data_exporter_spec.rb +31 -32
- data/spec/lib/data_importer_spec.rb +382 -395
- data/spec/lib/delorean_query_spec.rb +117 -119
- data/spec/lib/json_schema_spec.rb +382 -392
- data/spec/lib/logger_spec.rb +23 -24
- data/spec/lib/mcfly_model_spec.rb +112 -109
- data/spec/lib/migrations_spec.rb +10 -10
- data/spec/lib/struct_compare_spec.rb +6 -6
- data/spec/lib/table_report_spec.rb +90 -0
- data/spec/lib/xl_spec.rb +63 -65
- data/spec/lib/xl_styles_spec.rb +16 -19
- data/spec/models/api_auth_spec.rb +30 -30
- data/spec/models/config_spec.rb +32 -32
- data/spec/models/data_grid_spec.rb +642 -655
- data/spec/models/event_spec.rb +96 -88
- data/spec/models/import_type_spec.rb +20 -20
- data/spec/models/posting_spec.rb +35 -35
- data/spec/models/promise_spec.rb +5 -5
- data/spec/models/rule_spec.rb +280 -269
- data/spec/models/script_spec.rb +27 -18
- data/spec/models/user_spec.rb +9 -9
- data/spec/other/diagnostic/base_spec.rb +20 -19
- data/spec/other/diagnostic/collection_spec.rb +6 -5
- data/spec/other/diagnostic/delayed_job_version_spec.rb +1 -1
- data/spec/other/diagnostic/delayed_job_workers_spec.rb +8 -8
- data/spec/other/diagnostic/reporter_spec.rb +31 -33
- data/spec/spec_helper.rb +5 -5
- data/spec/support/chromedriver.rb +3 -5
- data/spec/support/components/netzke_combobox.rb +1 -1
- data/spec/support/components/netzke_grid.rb +17 -17
- data/spec/support/custom_matchers.rb +2 -2
- data/spec/support/download_helper.rb +1 -1
- data/spec/support/helper.rb +1 -2
- data/spec/support/netzke.rb +31 -31
- data/spec/support/performance_helper.rb +8 -8
- data/spec/support/post_run_logger.rb +1 -2
- data/spec/support/setup.rb +1 -4
- data/spec/support/shared_connection.rb +2 -2
- data/spec/support/structure_compare.rb +21 -22
- data/spec/support/suite.rb +1 -2
- data/spec/support/users.rb +5 -6
- metadata +32 -26
|
@@ -32,6 +32,14 @@ ClassField: ClassListField
|
|
|
32
32
|
|
|
33
33
|
######################################################################
|
|
34
34
|
|
|
35
|
+
CheckboxField:
|
|
36
|
+
xtype = ":checkboxfield"
|
|
37
|
+
checked = false
|
|
38
|
+
input_value = true
|
|
39
|
+
unchecked_value = false
|
|
40
|
+
|
|
41
|
+
######################################################################
|
|
42
|
+
|
|
35
43
|
JsonField:
|
|
36
44
|
xtype = ":textareafield"
|
|
37
45
|
name = "json_field"
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import MartyFields
|
|
2
|
+
import Styles
|
|
3
|
+
|
|
4
|
+
ReadableField: MartyFields::CheckboxField
|
|
5
|
+
name = "readable"
|
|
6
|
+
field_label = "Disable Encoding"
|
|
7
|
+
|
|
8
|
+
TableReport:
|
|
9
|
+
readable =? nil
|
|
10
|
+
pt_name =? nil
|
|
11
|
+
posting = Marty::Posting.lookup(pt_name)
|
|
12
|
+
pt = posting.created_dt
|
|
13
|
+
module_name =? nil
|
|
14
|
+
class_name =? nil
|
|
15
|
+
title =? (class_name || "Table Report") + (
|
|
16
|
+
if pt_name then "_" + pt_name else "")
|
|
17
|
+
sort_field =? nil
|
|
18
|
+
exclude_attrs =? nil
|
|
19
|
+
|
|
20
|
+
result_raw = Marty::DataChange.do_export(
|
|
21
|
+
pt,
|
|
22
|
+
if module_name then module_name + '::' + class_name else class_name,
|
|
23
|
+
sort_field,
|
|
24
|
+
exclude_attrs || [],
|
|
25
|
+
)
|
|
26
|
+
row_count = result_raw.length
|
|
27
|
+
result = Marty::Helper.to_csv(result_raw, {'readable' : readable})
|
|
28
|
+
form = [
|
|
29
|
+
MartyFields::PostingField,
|
|
30
|
+
MartyFields::ClassField,
|
|
31
|
+
ReadableField,
|
|
32
|
+
]
|
|
33
|
+
format = "csv"
|
|
34
|
+
|
data/docker-compose.dummy.yml
CHANGED
|
@@ -22,9 +22,8 @@ services:
|
|
|
22
22
|
- "postgres"
|
|
23
23
|
volumes:
|
|
24
24
|
- .:/opt/app:delegated
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
# - '~/.pry_history:/root/.pry_history'
|
|
25
|
+
- '.bash_history.docker:/root/.bash_history'
|
|
26
|
+
- '.pry_history.docker:/root/.pry_history'
|
|
28
27
|
volumes_from:
|
|
29
28
|
- bundle_box
|
|
30
29
|
tty: true
|
data/lib/marty/aws/base.rb
CHANGED
|
@@ -11,13 +11,12 @@ class Marty::Aws::Base
|
|
|
11
11
|
:creds,
|
|
12
12
|
:version,
|
|
13
13
|
:host,
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
end
|
|
14
|
+
def self.get url
|
|
15
|
+
uri = URI.parse(url)
|
|
16
|
+
req = Net::HTTP.new(uri.host, uri.port)
|
|
17
|
+
req.read_timeout = req.open_timeout = ENV['AWS_REQUEST_TIMEOUT'] || 0.25
|
|
18
|
+
req.start { |http| http.get(uri.to_s) }.body
|
|
19
|
+
end
|
|
21
20
|
|
|
22
21
|
def self.is_aws?
|
|
23
22
|
# FIXME: hack to pass tests on CI
|
|
@@ -44,6 +43,7 @@ class Marty::Aws::Base
|
|
|
44
43
|
end
|
|
45
44
|
|
|
46
45
|
private
|
|
46
|
+
|
|
47
47
|
def get_instance_id
|
|
48
48
|
query_meta_data('instance-id').to_s
|
|
49
49
|
end
|
|
@@ -53,7 +53,7 @@ class Marty::Aws::Base
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def sym obj
|
|
56
|
-
obj.each_with_object({}){|(k,v),h| h[k.underscore.to_sym] = v}
|
|
56
|
+
obj.each_with_object({}) { |(k, v), h| h[k.underscore.to_sym] = v }
|
|
57
57
|
end
|
|
58
58
|
|
|
59
59
|
def get_credentials
|
data/lib/marty/aws/request.rb
CHANGED
|
@@ -7,13 +7,13 @@ class Marty::Aws::Request < Marty::Aws::Base
|
|
|
7
7
|
endpoint = info[:endpoint]
|
|
8
8
|
method = info[:method] || :get
|
|
9
9
|
|
|
10
|
-
default = action ? {'Action' => action, 'Version' => @version} : {}
|
|
10
|
+
default = action ? { 'Action' => action, 'Version' => @version } : {}
|
|
11
11
|
|
|
12
12
|
host = "#{@service}.#{@doc[:region]}.amazonaws.com"
|
|
13
13
|
|
|
14
14
|
url = "https://#{host}/"
|
|
15
15
|
url += endpoint if endpoint
|
|
16
|
-
url += '?' + (default + params).map{|a, v| "#{a}=#{v}"}.join('&') unless
|
|
16
|
+
url += '?' + (default + params).map { |a, v| "#{a}=#{v}" }.join('&') unless
|
|
17
17
|
params.empty?
|
|
18
18
|
|
|
19
19
|
sig = Aws::Sigv4::Signer.new(service: @service,
|
|
@@ -21,7 +21,7 @@ class Marty::Aws::Request < Marty::Aws::Base
|
|
|
21
21
|
access_key_id: @creds[:access_key_id],
|
|
22
22
|
secret_access_key: @creds[:secret_access_key],
|
|
23
23
|
session_token: @creds[:token])
|
|
24
|
-
signed_url = sig.presign_url(http_method:'GET', url: url)
|
|
24
|
+
signed_url = sig.presign_url(http_method: 'GET', url: url)
|
|
25
25
|
|
|
26
26
|
http = Net::HTTP.new(host, 443)
|
|
27
27
|
http.use_ssl = true
|
|
@@ -38,7 +38,7 @@ class Marty::Aws::Request < Marty::Aws::Base
|
|
|
38
38
|
|
|
39
39
|
ensure_resp(path, obj[key])
|
|
40
40
|
else
|
|
41
|
-
obj.map{|s| ensure_resp(path.clone, s)}.flatten(1)
|
|
41
|
+
obj.map { |s| ensure_resp(path.clone, s) }.flatten(1)
|
|
42
42
|
end
|
|
43
43
|
end
|
|
44
44
|
end
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
module Marty::ContentHandler
|
|
2
2
|
GEN_FORMATS = {
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
3
|
+
'csv' => ['text/csv', 'download'],
|
|
4
|
+
'zip' => ['application/zip', 'download'],
|
|
5
|
+
'xlsx' => ['application/vnd.ms-excel', 'download'],
|
|
6
|
+
'html' => ['text/html', 'download'],
|
|
7
|
+
'txt' => ['text/plain', 'inline'],
|
|
8
|
+
'json' => ['application/json', 'download'],
|
|
9
9
|
|
|
10
10
|
# hacky: default format is JSON
|
|
11
11
|
nil => ['application/json', 'download'],
|
|
@@ -19,29 +19,29 @@ module Marty::ContentHandler
|
|
|
19
19
|
def self.export(data, format, name)
|
|
20
20
|
begin
|
|
21
21
|
case format
|
|
22
|
-
when
|
|
22
|
+
when 'csv'
|
|
23
23
|
# Somewhat hacky, if data is string => pass through as CSV.
|
|
24
24
|
# Should generalize to other data types, not just CSV.
|
|
25
25
|
res = data.is_a?(String) ? data : Marty::DataExporter.to_csv(data)
|
|
26
|
-
when
|
|
26
|
+
when 'xlsx'
|
|
27
27
|
res = Marty::Xl.spreadsheet(data).to_stream.read
|
|
28
|
-
when
|
|
28
|
+
when 'zip'
|
|
29
29
|
res = to_zip(data)
|
|
30
|
-
when nil,
|
|
31
|
-
res, format = data.to_json,
|
|
32
|
-
when
|
|
30
|
+
when nil, 'json'
|
|
31
|
+
res, format = data.to_json, 'json'
|
|
32
|
+
when 'html'
|
|
33
33
|
res = data.to_s
|
|
34
34
|
else
|
|
35
|
-
res, format = {error: "Unknown format: #{format}"}.to_json,
|
|
35
|
+
res, format = { error: "Unknown format: #{format}" }.to_json, 'json'
|
|
36
36
|
end
|
|
37
|
-
rescue => exc
|
|
37
|
+
rescue StandardError => exc
|
|
38
38
|
res, format =
|
|
39
|
-
{error: "Failed conversion #{format}: #{exc}"}.to_json,
|
|
39
|
+
{ error: "Failed conversion #{format}: #{exc}" }.to_json, 'json'
|
|
40
40
|
end
|
|
41
41
|
|
|
42
42
|
type, disposition = GEN_FORMATS[format]
|
|
43
43
|
|
|
44
|
-
|
|
44
|
+
[res, type, disposition, "#{name}.#{format}"]
|
|
45
45
|
end
|
|
46
46
|
|
|
47
47
|
private
|
|
@@ -53,24 +53,24 @@ module Marty::ContentHandler
|
|
|
53
53
|
end
|
|
54
54
|
|
|
55
55
|
def self.uniq_filename(filename, fset)
|
|
56
|
-
(0..1000).each
|
|
57
|
-
post = i==0 ?
|
|
56
|
+
(0..1000).each do |i|
|
|
57
|
+
post = i == 0 ? '' : " (#{i})"
|
|
58
58
|
fn = filename + post
|
|
59
59
|
return fn unless fset.member? fn
|
|
60
|
-
|
|
60
|
+
end
|
|
61
61
|
filename
|
|
62
62
|
end
|
|
63
63
|
|
|
64
64
|
def self.to_zip_stream(stream, path, data)
|
|
65
65
|
fset = Set.new
|
|
66
66
|
|
|
67
|
-
data.each
|
|
68
|
-
title, format, result = r[
|
|
67
|
+
data.each do |r|
|
|
68
|
+
title, format, result = r['title'], r['format'], r['result']
|
|
69
69
|
|
|
70
|
-
log_and_raise
|
|
71
|
-
log_and_raise
|
|
70
|
+
log_and_raise 'Result has no title' unless title
|
|
71
|
+
log_and_raise 'Result has no result' unless result
|
|
72
72
|
|
|
73
|
-
if format ==
|
|
73
|
+
if format == 'zip'
|
|
74
74
|
to_zip_stream(stream, path + [title], result)
|
|
75
75
|
next
|
|
76
76
|
end
|
|
@@ -82,7 +82,7 @@ module Marty::ContentHandler
|
|
|
82
82
|
|
|
83
83
|
stream.put_next_entry((path + [filename]).join('/'))
|
|
84
84
|
stream.write res_data
|
|
85
|
-
|
|
85
|
+
end
|
|
86
86
|
end
|
|
87
87
|
|
|
88
88
|
def self.to_zip(data)
|
data/lib/marty/data_change.rb
CHANGED
|
@@ -6,9 +6,7 @@ class Marty::DataChange
|
|
|
6
6
|
|
|
7
7
|
# will break if DataExporter::export_attrs recurses more than 1 level
|
|
8
8
|
# and a level 2+ child table has a compound mcfly_uniqueness key
|
|
9
|
-
delorean_fn :changes, sig: [3, 4] do
|
|
10
|
-
|t0, t1, class_name, ids = nil|
|
|
11
|
-
|
|
9
|
+
delorean_fn :changes, sig: [3, 4] do |t0, t1, class_name, ids = nil|
|
|
12
10
|
klass = class_name.constantize
|
|
13
11
|
|
|
14
12
|
t0 = Mcfly.normalize_infinity t0
|
|
@@ -21,38 +19,37 @@ class Marty::DataChange
|
|
|
21
19
|
|
|
22
20
|
changes.each_with_object({}) do |(group_id, ol), h|
|
|
23
21
|
h[group_id] = ol.each_with_index.map do |o, i|
|
|
24
|
-
profile = {
|
|
22
|
+
profile = { 'obj' => o.attributes }
|
|
25
23
|
|
|
26
24
|
# Create a profile hash for each object in the group.
|
|
27
25
|
# "status" tells us if the object is old/new/mod. If
|
|
28
26
|
# status=="mod" then "changes" will provide the list of
|
|
29
27
|
# columns which changed. If the object was deleted during
|
|
30
28
|
# t0-t1 then we set the deleted flag in the profile.
|
|
31
|
-
profile[
|
|
29
|
+
profile['deleted'] = (group_id == o.id &&
|
|
32
30
|
o.obsoleted_dt != Float::INFINITY &&
|
|
33
31
|
(t1 == 'infinity' || o.obsoleted_dt < t1)
|
|
34
|
-
|
|
32
|
+
)
|
|
35
33
|
if i == 0
|
|
36
|
-
profile[
|
|
34
|
+
profile['status'] = o.created_dt < t0 ? 'old' : 'new'
|
|
37
35
|
prev = nil
|
|
38
36
|
else
|
|
39
|
-
profile[
|
|
37
|
+
profile['status'], prev = 'mod', prev = ol[i - 1]
|
|
40
38
|
end
|
|
41
39
|
|
|
42
40
|
exp_attrs = Marty::DataExporter.export_attrs(klass, o).flatten(1)
|
|
43
41
|
|
|
44
42
|
# assumes cols order is same as that returned by export_attrs
|
|
45
43
|
|
|
46
|
-
profile[
|
|
47
|
-
|(col, i), a|
|
|
44
|
+
profile['attrs'] = cols_model.each_with_index.with_object([]) do |(col, i), a|
|
|
48
45
|
header_current = cols_header[i]
|
|
49
46
|
valcount = Array === header_current ? header_current.count : 1
|
|
50
47
|
changed = o.send(col.to_sym) != prev.send(col.to_sym) if prev
|
|
51
48
|
valcount.times do
|
|
52
|
-
a.push(
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
49
|
+
a.push(
|
|
50
|
+
'value' => exp_attrs.shift,
|
|
51
|
+
'changed' => changed
|
|
52
|
+
)
|
|
56
53
|
end
|
|
57
54
|
end
|
|
58
55
|
profile
|
|
@@ -60,9 +57,7 @@ class Marty::DataChange
|
|
|
60
57
|
end
|
|
61
58
|
end
|
|
62
59
|
|
|
63
|
-
delorean_fn :change_summary, sig: 3 do
|
|
64
|
-
|t0, t1, class_name|
|
|
65
|
-
|
|
60
|
+
delorean_fn :change_summary, sig: 3 do |t0, t1, class_name|
|
|
66
61
|
klass = class_name.constantize
|
|
67
62
|
|
|
68
63
|
t0 = Mcfly.normalize_infinity t0
|
|
@@ -72,49 +67,43 @@ class Marty::DataChange
|
|
|
72
67
|
|
|
73
68
|
created = updated = deleted = 0
|
|
74
69
|
|
|
75
|
-
changes.each
|
|
76
|
-
ol.each_with_index.map
|
|
77
|
-
deleted +=1 if (group_id == o.id &&
|
|
70
|
+
changes.each do |group_id, ol|
|
|
71
|
+
ol.each_with_index.map do |o, i|
|
|
72
|
+
deleted += 1 if (group_id == o.id &&
|
|
78
73
|
o.obsoleted_dt != Float::INFINITY &&
|
|
79
74
|
(t1 == 'infinity' || o.obsoleted_dt < t1)
|
|
80
75
|
)
|
|
81
76
|
if i == 0
|
|
82
|
-
created +=1 unless o.created_dt < t0
|
|
77
|
+
created += 1 unless o.created_dt < t0
|
|
83
78
|
else
|
|
84
79
|
updated += 1
|
|
85
80
|
end
|
|
86
|
-
|
|
87
|
-
|
|
81
|
+
end
|
|
82
|
+
end
|
|
88
83
|
|
|
89
|
-
{'created' => created, 'updated' => updated, 'deleted' => deleted}
|
|
84
|
+
{ 'created' => created, 'updated' => updated, 'deleted' => deleted }
|
|
90
85
|
end
|
|
91
86
|
|
|
92
87
|
delorean_fn :class_list, sig: 0 do
|
|
93
88
|
Rails.configuration.marty.class_list.sort.uniq || []
|
|
94
89
|
end
|
|
95
90
|
|
|
96
|
-
delorean_fn :class_headers, sig: 1 do
|
|
97
|
-
|class_name|
|
|
91
|
+
delorean_fn :class_headers, sig: 1 do |class_name|
|
|
98
92
|
Marty::DataExporter.export_headers(class_name.constantize, nil, []).flatten.
|
|
99
93
|
map { |f| I18n.t(f, scope: 'attributes', default: f) }
|
|
100
94
|
end
|
|
101
95
|
|
|
102
|
-
delorean_fn :user_name, sig: 1 do
|
|
103
|
-
|user_id|
|
|
104
|
-
|
|
96
|
+
delorean_fn :user_name, sig: 1 do |user_id|
|
|
105
97
|
Marty::User.find_by_id(user_id).try(:name)
|
|
106
98
|
end
|
|
107
99
|
|
|
108
|
-
delorean_fn :sanitize_classes, sig: 1 do
|
|
109
|
-
|classes|
|
|
100
|
+
delorean_fn :sanitize_classes, sig: 1 do |classes|
|
|
110
101
|
classes = classes.split(/,\s*/) if classes.is_a? String
|
|
111
102
|
|
|
112
103
|
classes.to_set & class_list.to_set
|
|
113
104
|
end
|
|
114
105
|
|
|
115
|
-
delorean_fn :do_export, sig: [2, 4] do
|
|
116
|
-
|pt, klass, sort_field=nil, exclude_attrs=[]|
|
|
117
|
-
|
|
106
|
+
delorean_fn :do_export, sig: [2, 4] do |pt, klass, sort_field = nil, exclude_attrs = []|
|
|
118
107
|
# allow classes on class_list or any Enum to be exported
|
|
119
108
|
raise "'#{klass}' not on class_list" unless
|
|
120
109
|
class_list.member?(klass) || klass.constantize.is_a?(Marty::Enum)
|
|
@@ -123,15 +112,12 @@ class Marty::DataChange
|
|
|
123
112
|
do_export(pt, klass.constantize, sort_field, exclude_attrs)
|
|
124
113
|
end
|
|
125
114
|
|
|
126
|
-
delorean_fn :do_pg_enum_export, sig: 1 do
|
|
127
|
-
|k|
|
|
115
|
+
delorean_fn :do_pg_enum_export, sig: 1 do |k|
|
|
128
116
|
klass = k.constantize
|
|
129
117
|
next (klass.is_a? Marty::PgEnum) ? klass.get_all : []
|
|
130
118
|
end
|
|
131
119
|
|
|
132
|
-
delorean_fn :export_changes, sig: 3 do
|
|
133
|
-
|t0, t1, class_name|
|
|
134
|
-
|
|
120
|
+
delorean_fn :export_changes, sig: 3 do |t0, t1, class_name|
|
|
135
121
|
klass = class_name.constantize
|
|
136
122
|
|
|
137
123
|
t0 = Mcfly.normalize_infinity t0
|
|
@@ -142,9 +128,9 @@ class Marty::DataChange
|
|
|
142
128
|
|
|
143
129
|
# find all changes from t0 to t1 -- orders by id to get the lower
|
|
144
130
|
# ones since those are the original version in Mcfly.
|
|
145
|
-
changes = klass.select(
|
|
131
|
+
changes = klass.select('DISTINCT ON (group_id) *').
|
|
146
132
|
where(change_q, t0, t1, t0, t1).
|
|
147
|
-
order(
|
|
133
|
+
order('group_id, id').
|
|
148
134
|
to_a
|
|
149
135
|
|
|
150
136
|
# update/adds, deletes
|
|
@@ -156,16 +142,16 @@ class Marty::DataChange
|
|
|
156
142
|
else
|
|
157
143
|
# if a version of row existed before t0 => add it to del list
|
|
158
144
|
del << o if klass.
|
|
159
|
-
where(
|
|
145
|
+
where('group_id = ? AND created_dt < ?', o.group_id, t0).exists?
|
|
160
146
|
end
|
|
161
147
|
end
|
|
162
148
|
|
|
163
|
-
[chg, del].map
|
|
149
|
+
[chg, del].map do |l|
|
|
164
150
|
l.empty? ? nil : Marty::DataExporter.do_export_query_result(klass, l)
|
|
165
|
-
|
|
151
|
+
end
|
|
166
152
|
end
|
|
167
153
|
|
|
168
|
-
def self.get_changed_data(t0, t1, klass, ids=nil)
|
|
154
|
+
def self.get_changed_data(t0, t1, klass, ids = nil)
|
|
169
155
|
# The following test fails when t0/t1 are infinity. ActiveSupport
|
|
170
156
|
# doesn't know about infinity.
|
|
171
157
|
# return unless t0 < t1
|
|
@@ -183,7 +169,7 @@ class Marty::DataChange
|
|
|
183
169
|
|
|
184
170
|
raise "Change count exceeds limit #{MAX_COUNT}" if countq.count > MAX_COUNT
|
|
185
171
|
|
|
186
|
-
dataq.order(
|
|
172
|
+
dataq.order('group_id, created_dt').group_by(&:group_id)
|
|
187
173
|
end
|
|
188
174
|
|
|
189
175
|
######################################################################
|
|
@@ -209,21 +195,17 @@ class Marty::DataChange
|
|
|
209
195
|
# {"source" => {k1=>v1, k2=>v2, ...},
|
|
210
196
|
# "input" => {k1=>v1, k2=>v2, ...}}
|
|
211
197
|
|
|
212
|
-
delorean_fn :diff, sig: [2, 3] do
|
|
213
|
-
|klass, input_data, ts='infinity'|
|
|
214
|
-
|
|
198
|
+
delorean_fn :diff, sig: [2, 3] do |klass, input_data, ts = 'infinity'|
|
|
215
199
|
ts = Mcfly.normalize_infinity(ts)
|
|
216
200
|
keys = Marty::DataConversion.assoc_keys(klass).map(&:to_s).to_set
|
|
217
201
|
|
|
218
202
|
only_source, only_input, different, same = [], [], [], []
|
|
219
203
|
found_sources = Set[]
|
|
220
204
|
|
|
221
|
-
input_data.each do
|
|
222
|
-
|input|
|
|
223
|
-
|
|
205
|
+
input_data.each do |input|
|
|
224
206
|
input_keys = input.keys
|
|
225
207
|
|
|
226
|
-
raise
|
|
208
|
+
raise 'non-String keys in input data' unless
|
|
227
209
|
input_keys.all? { |x| String === x }
|
|
228
210
|
|
|
229
211
|
begin
|
|
@@ -235,7 +217,7 @@ class Marty::DataChange
|
|
|
235
217
|
# "different".
|
|
236
218
|
conv =
|
|
237
219
|
Marty::DataConversion.convert_row(klass, input, ts)
|
|
238
|
-
rescue => exc
|
|
220
|
+
rescue StandardError => exc
|
|
239
221
|
only_input << input
|
|
240
222
|
next
|
|
241
223
|
end
|
|
@@ -263,24 +245,24 @@ class Marty::DataChange
|
|
|
263
245
|
source_export = Marty::DataExporter.export_obj(source) % input_keys
|
|
264
246
|
|
|
265
247
|
different << [
|
|
266
|
-
{
|
|
267
|
-
{
|
|
248
|
+
{ '_origin_' => 'source' } + source_export,
|
|
249
|
+
{ '_origin_' => 'input' } + input,
|
|
268
250
|
]
|
|
269
251
|
end
|
|
270
252
|
|
|
271
253
|
# now find any live source object which have not been visited
|
|
272
254
|
query = klass
|
|
273
255
|
|
|
274
|
-
query = query.where(
|
|
256
|
+
query = query.where('obsoleted_dt >= ? AND created_dt < ?', ts, ts) if
|
|
275
257
|
Mcfly.has_mcfly?(klass)
|
|
276
258
|
|
|
277
259
|
query = query.where.not(id: found_sources.map(&:id))
|
|
278
260
|
|
|
279
261
|
{
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
262
|
+
'different' => different,
|
|
263
|
+
'same' => same,
|
|
264
|
+
'only_input' => only_input,
|
|
265
|
+
'only_source' => Marty::DataExporter.
|
|
284
266
|
do_export_query_result(klass, query),
|
|
285
267
|
}
|
|
286
268
|
end
|
|
@@ -289,9 +271,7 @@ class Marty::DataChange
|
|
|
289
271
|
|
|
290
272
|
# Given a Mcfly class_name, find all of the obsoleted Mcfly objects
|
|
291
273
|
# which are referenced by live (non-obsoleted) class instances.
|
|
292
|
-
delorean_fn :dead_refs, sig: 2 do
|
|
293
|
-
|ts, class_name|
|
|
294
|
-
|
|
274
|
+
delorean_fn :dead_refs, sig: 2 do |ts, class_name|
|
|
295
275
|
klass = class_name.constantize
|
|
296
276
|
|
|
297
277
|
return unless Mcfly.has_mcfly?(klass)
|
|
@@ -299,13 +279,11 @@ class Marty::DataChange
|
|
|
299
279
|
ts = Mcfly.normalize_infinity(ts)
|
|
300
280
|
col_types = Marty::DataConversion.col_types(klass)
|
|
301
281
|
|
|
302
|
-
mcfly_cols = col_types.map
|
|
282
|
+
mcfly_cols = col_types.map do |attr, h|
|
|
303
283
|
Hash === h && Mcfly.has_mcfly?(h[:assoc_class]) && h || nil
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
mcfly_cols.each_with_object({}) {
|
|
307
|
-
|h, res|
|
|
284
|
+
end.compact
|
|
308
285
|
|
|
286
|
+
mcfly_cols.each_with_object({}) do |h, res|
|
|
309
287
|
fk = h[:foreign_key]
|
|
310
288
|
rtable = h[:assoc_class].table_name
|
|
311
289
|
ktable = klass.table_name
|
|
@@ -324,9 +302,9 @@ class Marty::DataChange
|
|
|
324
302
|
where("#{rtable}.group_id = #{rtable}.id").
|
|
325
303
|
all
|
|
326
304
|
|
|
327
|
-
arr = arr.map {|obj| Marty::DataExporter.export_attrs(klass, obj, [fk])}
|
|
305
|
+
arr = arr.map { |obj| Marty::DataExporter.export_attrs(klass, obj, [fk]) }
|
|
328
306
|
|
|
329
307
|
res[fk] = arr unless arr.empty?
|
|
330
|
-
|
|
308
|
+
end
|
|
331
309
|
end
|
|
332
310
|
end
|