bricolage 5.8.7

Sign up to get free protection for your applications and to get access to all the features.
Files changed (65) hide show
  1. checksums.yaml +7 -0
  2. data/README.md +4 -0
  3. data/bin/bricolage +6 -0
  4. data/bin/bricolage-jobnet +6 -0
  5. data/jobclass/create.rb +21 -0
  6. data/jobclass/exec.rb +17 -0
  7. data/jobclass/insert-delta.rb +31 -0
  8. data/jobclass/insert.rb +33 -0
  9. data/jobclass/load.rb +39 -0
  10. data/jobclass/my-export.rb +40 -0
  11. data/jobclass/my-migrate.rb +103 -0
  12. data/jobclass/noop.rb +13 -0
  13. data/jobclass/rebuild-drop.rb +37 -0
  14. data/jobclass/rebuild-rename.rb +49 -0
  15. data/jobclass/s3-put.rb +19 -0
  16. data/jobclass/sql.rb +29 -0
  17. data/jobclass/td-delete.rb +20 -0
  18. data/jobclass/td-export.rb +30 -0
  19. data/jobclass/unload.rb +30 -0
  20. data/jobclass/wait-file.rb +48 -0
  21. data/lib/bricolage/application.rb +260 -0
  22. data/lib/bricolage/commandutils.rb +52 -0
  23. data/lib/bricolage/configloader.rb +126 -0
  24. data/lib/bricolage/context.rb +108 -0
  25. data/lib/bricolage/datasource.rb +144 -0
  26. data/lib/bricolage/eventhandlers.rb +47 -0
  27. data/lib/bricolage/exception.rb +47 -0
  28. data/lib/bricolage/filedatasource.rb +42 -0
  29. data/lib/bricolage/filesystem.rb +165 -0
  30. data/lib/bricolage/genericdatasource.rb +37 -0
  31. data/lib/bricolage/job.rb +212 -0
  32. data/lib/bricolage/jobclass.rb +98 -0
  33. data/lib/bricolage/jobfile.rb +100 -0
  34. data/lib/bricolage/jobflow.rb +389 -0
  35. data/lib/bricolage/jobnetrunner.rb +264 -0
  36. data/lib/bricolage/jobresult.rb +74 -0
  37. data/lib/bricolage/logger.rb +52 -0
  38. data/lib/bricolage/mysqldatasource.rb +223 -0
  39. data/lib/bricolage/parameters.rb +653 -0
  40. data/lib/bricolage/postgresconnection.rb +78 -0
  41. data/lib/bricolage/psqldatasource.rb +449 -0
  42. data/lib/bricolage/resource.rb +68 -0
  43. data/lib/bricolage/rubyjobclass.rb +42 -0
  44. data/lib/bricolage/s3datasource.rb +144 -0
  45. data/lib/bricolage/script.rb +120 -0
  46. data/lib/bricolage/sqlstatement.rb +351 -0
  47. data/lib/bricolage/taskqueue.rb +156 -0
  48. data/lib/bricolage/tddatasource.rb +116 -0
  49. data/lib/bricolage/variables.rb +208 -0
  50. data/lib/bricolage/version.rb +4 -0
  51. data/lib/bricolage.rb +8 -0
  52. data/libexec/sqldump +9 -0
  53. data/libexec/sqldump.Darwin +0 -0
  54. data/libexec/sqldump.Linux +0 -0
  55. data/test/all.rb +3 -0
  56. data/test/home/config/development/database.yml +57 -0
  57. data/test/home/config/development/password.yml +2 -0
  58. data/test/home/subsys/separated.job +1 -0
  59. data/test/home/subsys/separated.sql +1 -0
  60. data/test/home/subsys/unified.jobnet +1 -0
  61. data/test/home/subsys/unified.sql.job +5 -0
  62. data/test/test_filesystem.rb +19 -0
  63. data/test/test_parameters.rb +401 -0
  64. data/test/test_variables.rb +114 -0
  65. metadata +192 -0
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: afb5228b706d506b2b2f7b468f216f76cdd82dc9
4
+ data.tar.gz: 9c947de18235c29e7db2b3a7b54fa095f8bf2335
5
+ SHA512:
6
+ metadata.gz: 3759c24eda01c02d78d0f3724c14254dc8dd8b687fc0bdd82869ec3db4ef9120b6cff2a5312533a04ef79d912fc9be96191edde3a81e0f79477783fc563245e9
7
+ data.tar.gz: 3873fafbb3f9dbbec2b2a38afbcbe4f2230ecd1f4467c421ceb37717a6be6723fa111a456c568adf03353471e9c3f5a89ecee9d1d649b02248b95d24858b36d0
data/README.md ADDED
@@ -0,0 +1,4 @@
1
+ bricolage
2
+ =========
3
+
4
+ SQL batch framework
data/bin/bricolage ADDED
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ Bundler.require(:default) if defined?(Bundler)
4
+ require 'bricolage/application'
5
+
6
+ Bricolage::Application.main
@@ -0,0 +1,6 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ Bundler.require(:default) if defined?(Bundler)
4
+ require 'bricolage/jobnetrunner'
5
+
6
+ Bricolage::JobNetRunner.main
@@ -0,0 +1,21 @@
1
+ JobClass.define('create') {
2
+ parameters {|params|
3
+ params.add SQLFileParam.new('table-def', 'PATH', 'CREATE TABLE file.')
4
+ params.add DestTableParam.new
5
+ params.add OptionalBoolParam.new('drop', 'DROP table before CREATE.')
6
+ params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.')
7
+ params.add DataSourceParam.new('sql')
8
+ }
9
+
10
+ declarations {|params|
11
+ params['table-def'].declarations
12
+ }
13
+
14
+ script {|params, script|
15
+ script.task(params['data-source']) {|task|
16
+ task.drop_force_if params['drop']
17
+ task.exec params['table-def']
18
+ task.analyze_if params['analyze']
19
+ }
20
+ }
21
+ }
data/jobclass/exec.rb ADDED
@@ -0,0 +1,17 @@
1
+ JobClass.define('exec') {
2
+ parameters {|params|
3
+ params.add StringListParam.new('args', 'ARG', 'Command line arguments.')
4
+ }
5
+
6
+ script {|params, script|
7
+ script.task(params.generic_ds) {|task|
8
+ task.action(params['args'].join(' ')) {|ds|
9
+ ds.logger.info '[CMD] ' + params['args'].join(' ')
10
+ system(*params['args'])
11
+ st = $?
12
+ ds.logger.info "status=#{st.exitstatus}"
13
+ JobResult.for_bool(st.exitstatus == 0)
14
+ }
15
+ }
16
+ }
17
+ }
@@ -0,0 +1,31 @@
1
+ JobClass.define('insert-delta') {
2
+ parameters {|params|
3
+ params.add SQLFileParam.new
4
+ params.add DestTableParam.new
5
+ params.add SrcTableParam.new
6
+ params.add StringParam.new('delete-cond', 'SQL_EXPR', 'DELETE condition.')
7
+ params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.')
8
+ params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
9
+ params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
10
+ params.add DataSourceParam.new('sql')
11
+ }
12
+
13
+ parameters_filter {|job|
14
+ job.provide_sql_file_by_job_id
15
+ }
16
+
17
+ declarations {|params|
18
+ params['sql-file'].declarations
19
+ }
20
+
21
+ script {|params, script|
22
+ script.task(params['data-source']) {|task|
23
+ task.transaction {
24
+ task.exec SQLStatement.delete_where(params['delete-cond'])
25
+ task.exec params['sql-file']
26
+ }
27
+ task.vacuum_if params['vacuum'], params['vacuum-sort']
28
+ task.analyze_if params['analyze']
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,33 @@
1
+ JobClass.define('insert') {
2
+ parameters {|params|
3
+ params.add SQLFileParam.new
4
+ params.add DestTableParam.new
5
+ params.add SrcTableParam.new
6
+ params.add SQLFileParam.new('table-def', 'PATH', 'Create table file.', optional: true)
7
+ params.add OptionalBoolParam.new('drop', 'DROP table before CREATE.')
8
+ params.add OptionalBoolParam.new('truncate', 'TRUNCATE table before SQL is executed.')
9
+ params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.')
10
+ params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
11
+ params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
12
+ params.add DataSourceParam.new('sql')
13
+ }
14
+
15
+ parameters_filter {|job|
16
+ job.provide_sql_file_by_job_id
17
+ }
18
+
19
+ declarations {|params|
20
+ params['sql-file'].declarations
21
+ }
22
+
23
+ script {|params, script|
24
+ script.task(params['data-source']) {|task|
25
+ task.truncate_if params['truncate']
26
+ task.drop_force_if params['drop']
27
+ task.exec params['table-def'] if params['table-def']
28
+ task.exec params['sql-file']
29
+ task.vacuum_if params['vacuum'], params['vacuum-sort']
30
+ task.analyze_if params['analyze']
31
+ }
32
+ }
33
+ }
data/jobclass/load.rb ADDED
@@ -0,0 +1,39 @@
1
+ require 'bricolage/psqldatasource'
2
+
3
+ JobClass.define('load') {
4
+ parameters {|params|
5
+ params.add DataSourceParam.new('s3', 'src-ds', 'Input data source.')
6
+ params.add SrcFileParam.new
7
+ params.add DataSourceParam.new('sql', 'dest-ds', 'Target data source.')
8
+ params.add DestTableParam.new(optional: false)
9
+ params.add EnumParam.new('format', %w(tsv json), 'Data file format.', default: 'tsv')
10
+ params.add StringParam.new('jsonpath', 'PATH', 'jsonpath to specify columns of json format records', optional: true)
11
+ params.add KeyValuePairsParam.new('options', 'OPTIONS', 'Loader options.',
12
+ optional: true, default: PSQLLoadOptions.new,
13
+ value_handler: lambda {|value, ctx, vars| PSQLLoadOptions.parse(value) })
14
+ params.add SQLFileParam.new('table-def', 'PATH', 'Create table file.', optional: true)
15
+ params.add OptionalBoolParam.new('drop', 'DROP table before CREATE.')
16
+ params.add OptionalBoolParam.new('truncate', 'TRUNCATE table before SQL is executed.')
17
+ params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.')
18
+ params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
19
+ params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
20
+ params.add KeyValuePairsParam.new('grant', 'KEY:VALUE', 'GRANT table after SQL is executed. (required keys: privilege, to)')
21
+ }
22
+
23
+ declarations {|params|
24
+ Declarations.new("dest_table" => nil)
25
+ }
26
+
27
+ script {|params, script|
28
+ script.task(params['dest-ds']) {|task|
29
+ task.drop_force_if params['drop']
30
+ task.exec params['table-def'] if params['table-def']
31
+ task.truncate_if params['truncate']
32
+ task.load params['src-ds'], params['src-file'], params['dest-table'],
33
+ params['format'], params['jsonpath'], params['options']
34
+ task.vacuum_if params['vacuum'], params['vacuum-sort']
35
+ task.analyze_if params['analyze']
36
+ task.grant_if params['grant'], params['dest-table']
37
+ }
38
+ }
39
+ }
@@ -0,0 +1,40 @@
1
+ JobClass.define('my-export') {
2
+ parameters {|params|
3
+ params.add SQLFileParam.new(optional: true)
4
+ params.add DestFileParam.new
5
+ params.add SrcTableParam.new
6
+ params.add EnumParam.new('format', %w(json tsv csv), 'Target file format.', default: 'json')
7
+ params.add OptionalBoolParam.new('gzip', 'If true, compresses target file by gzip.')
8
+ params.add OptionalBoolParam.new('override', 'If true, clears target file. Otherwise causes error.')
9
+ params.add OptionalBoolParam.new('sqldump', 'If true, clears use sqldump command to dump, only wheen usable.')
10
+ params.add DataSourceParam.new('mysql')
11
+ }
12
+
13
+ declarations {|params|
14
+ sql_statement(params).declarations
15
+ }
16
+
17
+ script {|params, script|
18
+ script.task(params['data-source']) {|task|
19
+ task.export sql_statement(params),
20
+ path: params['dest-file'],
21
+ format: params['format'],
22
+ override: params['override'],
23
+ gzip: params['gzip'],
24
+ sqldump: params['sqldump']
25
+ }
26
+ }
27
+
28
+ def sql_statement(params)
29
+ if sql = params['sql-file']
30
+ sql
31
+ else
32
+ srcs = params['src-tables']
33
+ raise ParameterError, "src-tables must be singleton when no sql-file is given" unless srcs.size == 1
34
+ src_table_var = srcs.keys.first
35
+ stmt = SQLStatement.for_string("select * from $#{src_table_var};")
36
+ stmt.declarations = Declarations.new({src_table_var => src_table_var})
37
+ stmt
38
+ end
39
+ end
40
+ }
@@ -0,0 +1,103 @@
1
+ require 'bricolage/psqldatasource'
2
+
3
+ JobClass.define('my-migrate') {
4
+ parameters {|params|
5
+ # Export
6
+ params.add SrcTableParam.new(optional: false)
7
+ params.add DataSourceParam.new('mysql', 'src-ds', 'Source data source.')
8
+ params.add DestFileParam.new('tmp-file', 'PATH', 'Temporary local file path.')
9
+ params.add OptionalBoolParam.new('sqldump', 'If true, use sqldump command to dump, only on available.', default: true)
10
+
11
+ # Put
12
+ params.add DestFileParam.new('s3-file', 'PATH', 'Temporary S3 file path.')
13
+ params.add DataSourceParam.new('s3', 's3-ds', 'Temporary file storage.')
14
+ params.add OptionalBoolParam.new('override', 'If true, overwrite s3 target file. Otherwise causes error.')
15
+
16
+ # Load
17
+ params.add DestTableParam.new(optional: false)
18
+ params.add DataSourceParam.new('sql', 'dest-ds', 'Destination data source.')
19
+ params.add KeyValuePairsParam.new('options', 'OPTIONS', 'Loader options.',
20
+ optional: true, default: PSQLLoadOptions.new,
21
+ value_handler: lambda {|value, ctx, vars| PSQLLoadOptions.parse(value) })
22
+ params.add SQLFileParam.new('table-def', 'PATH', 'Create table file.')
23
+
24
+ # Misc
25
+ params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.', default: true)
26
+ params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
27
+ params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
28
+ params.add KeyValuePairsParam.new('grant', 'KEY:VALUE', 'GRANT table after SQL is executed.')
29
+
30
+ # All
31
+ params.add OptionalBoolParam.new('export', 'Runs EXPORT task.')
32
+ params.add OptionalBoolParam.new('put', 'Runs PUT task.')
33
+ params.add OptionalBoolParam.new('load', 'Runs LOAD task.')
34
+ params.add OptionalBoolParam.new('gzip', 'If true, compresses target file by gzip.', default: true)
35
+ }
36
+
37
+ declarations {|params|
38
+ decls = sql_statement(params).declarations
39
+ decls.declare 'dest-table', nil
40
+ decls
41
+ }
42
+
43
+ script {|params, script|
44
+ run_all = !params['export'] && !params['put'] && !params['load']
45
+
46
+ # Export
47
+ if params['export'] || run_all
48
+ script.task(params['src-ds']) {|task|
49
+ task.export sql_statement(params),
50
+ path: params['tmp-file'],
51
+ format: 'json',
52
+ override: true,
53
+ gzip: params['gzip'],
54
+ sqldump: params['sqldump']
55
+ }
56
+ end
57
+
58
+ # Put
59
+ if params['put'] || run_all
60
+ script.task(params['s3-ds']) {|task|
61
+ task.put params['tmp-file'], params['s3-file'], check_args: false
62
+ }
63
+ end
64
+
65
+ # Load
66
+ if params['load'] || run_all
67
+ script.task(params['dest-ds']) {|task|
68
+ prev_table = '${dest_table}_old'
69
+ work_table = '${dest_table}_wk'
70
+
71
+ # CREATE
72
+ task.drop_force prev_table
73
+ task.drop_force work_table
74
+ task.exec params['table-def'].replace(/\$\{?dest_table\}?\b/, work_table)
75
+
76
+ # COPY
77
+ task.load params['s3-ds'], params['s3-file'], work_table,
78
+ 'json', nil, params['options'].merge('gzip' => params['gzip'])
79
+
80
+ # VACUUM, ANALYZE, GRANT
81
+ task.vacuum_if params['vacuum'], params['vacuum-sort'], work_table
82
+ task.analyze_if params['analyze'], work_table
83
+ task.grant_if params['grant'], work_table
84
+
85
+ # RENAME
86
+ task.create_dummy_table '${dest_table}'
87
+ task.transaction {
88
+ task.rename_table params['dest-table'].to_s, "#{params['dest-table'].name}_old"
89
+ task.rename_table work_table, params['dest-table'].name
90
+ }
91
+ }
92
+ end
93
+ }
94
+
95
+ def sql_statement(params)
96
+ srcs = params['src-tables']
97
+ raise ParameterError, "src-tables must be singleton when no sql-file is given" unless srcs.size == 1
98
+ src_table_var = srcs.keys.first
99
+ stmt = SQLStatement.for_string("select * from $#{src_table_var};")
100
+ stmt.declarations = Declarations.new({src_table_var => src_table_var})
101
+ stmt
102
+ end
103
+ }
data/jobclass/noop.rb ADDED
@@ -0,0 +1,13 @@
1
+ JobClass.define('noop') {
2
+ parameters {|params|
3
+ params.add OptionalBoolParam.new('failure', 'Finish with failure or not.')
4
+ }
5
+
6
+ script {|params, script|
7
+ script.task(params.generic_ds) {|task|
8
+ task.action('return !$failure') {
9
+ JobResult.for_bool(!params['failure'])
10
+ }
11
+ }
12
+ }
13
+ }
@@ -0,0 +1,37 @@
1
+ JobClass.define('rebuild-drop') {
2
+ parameters {|params|
3
+ params.add SQLFileParam.new
4
+ params.add DestTableParam.new
5
+ params.add SrcTableParam.new
6
+ params.add SQLFileParam.new('table-def', 'PATH', 'Create table file.')
7
+ params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.', default: true)
8
+ params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
9
+ params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
10
+ params.add KeyValuePairsParam.new('grant', 'KEY:VALUE', 'GRANT table after SQL is executed. (required keys: on, to)')
11
+ params.add DataSourceParam.new('sql')
12
+ }
13
+
14
+ parameters_filter {|job|
15
+ job.provide_sql_file_by_job_id
16
+ }
17
+
18
+ declarations {|params|
19
+ params['sql-file'].declarations
20
+ }
21
+
22
+ script {|params, script|
23
+ script.task(params['data-source']) {|task|
24
+ # CREATE
25
+ task.drop_force params['dest-table']
26
+ task.exec params['table-def']
27
+
28
+ # INSERT
29
+ task.exec params['sql-file']
30
+
31
+ # VACUUM, ANALYZE, GRANT
32
+ task.vacuum_if params['vacuum'], params['vacuum-sort'], params['dest-table']
33
+ task.analyze_if params['analyze'], params['dest-table']
34
+ task.grant_if params['grant'], params['dest-table']
35
+ }
36
+ }
37
+ }
@@ -0,0 +1,49 @@
1
+ JobClass.define('rebuild-rename') {
2
+ parameters {|params|
3
+ params.add SQLFileParam.new
4
+ params.add DestTableParam.new
5
+ params.add SrcTableParam.new
6
+ params.add SQLFileParam.new('table-def', 'PATH', 'Create table file.')
7
+ params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.', default: true)
8
+ params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
9
+ params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
10
+ params.add KeyValuePairsParam.new('grant', 'KEY:VALUE', 'GRANT table after SQL is executed.')
11
+ params.add DataSourceParam.new('sql')
12
+ }
13
+
14
+ parameters_filter {|job|
15
+ job.provide_sql_file_by_job_id
16
+ }
17
+
18
+ declarations {|params|
19
+ params['sql-file'].declarations
20
+ }
21
+
22
+ script {|params, script|
23
+ script.task(params['data-source']) {|task|
24
+ prev_table = '${dest_table}_old'
25
+ work_table = '${dest_table}_wk'
26
+
27
+ # CREATE
28
+ task.drop_force prev_table
29
+ task.drop_force work_table
30
+ task.exec params['table-def'].replace(/\$\{?dest_table\}?\b/, work_table)
31
+
32
+ # INSERT
33
+ task.exec params['sql-file'].replace(/\$\{?dest_table\}?\b/, work_table)
34
+
35
+ # VACUUM, ANALYZE, GRANT
36
+ task.vacuum_if params['vacuum'], params['vacuum-sort'], work_table
37
+ task.analyze_if params['analyze'], work_table
38
+ task.grant_if params['grant'], work_table
39
+
40
+ # RENAME
41
+ task.create_dummy_table '$dest_table'
42
+ task.transaction {
43
+ dest_table = params['dest-table']
44
+ task.rename_table dest_table.to_s, "#{dest_table.name}_old"
45
+ task.rename_table "#{dest_table}_wk", dest_table.name
46
+ }
47
+ }
48
+ }
49
+ }
@@ -0,0 +1,19 @@
1
+ JobClass.define('s3-put') {
2
+ parameters {|params|
3
+ params.add DestFileParam.new
4
+ params.add SrcFileParam.new
5
+ params.add OptionalBoolParam.new('remove', 'Removes source files after PUT is succeeded.')
6
+ params.add DataSourceParam.new('s3')
7
+ }
8
+
9
+ script {|params, script|
10
+ script.task(params['data-source']) {|task|
11
+ task.put params['src-file'], params['dest-file']
12
+ }
13
+ if params['remove']
14
+ script.task(params.file_ds) {|task|
15
+ task.remove params['src-file']
16
+ }
17
+ end
18
+ }
19
+ }
data/jobclass/sql.rb ADDED
@@ -0,0 +1,29 @@
1
+ JobClass.define('sql') {
2
+ parameters {|params|
3
+ params.add SQLFileParam.new
4
+ params.add DestTableParam.new
5
+ params.add SrcTableParam.new
6
+ params.add OptionalBoolParam.new('truncate', 'TRUNCATE table before SQL is executed.')
7
+ params.add OptionalBoolParam.new('analyze', 'ANALYZE table after SQL is executed.')
8
+ params.add OptionalBoolParam.new('vacuum', 'VACUUM table after SQL is executed.')
9
+ params.add OptionalBoolParam.new('vacuum-sort', 'VACUUM SORT table after SQL is executed.')
10
+ params.add DataSourceParam.new('sql')
11
+ }
12
+
13
+ parameters_filter {|job|
14
+ job.provide_sql_file_by_job_id
15
+ }
16
+
17
+ declarations {|params|
18
+ params['sql-file'].declarations
19
+ }
20
+
21
+ script {|params, script|
22
+ script.task(params['data-source']) {|task|
23
+ task.truncate_if params['truncate']
24
+ task.exec params['sql-file']
25
+ task.vacuum_if params['vacuum'], params['vacuum-sort']
26
+ task.analyze_if params['analyze']
27
+ }
28
+ }
29
+ }
@@ -0,0 +1,20 @@
1
+ JobClass.define('td-delete') {
2
+ parameters {|params|
3
+ params.add DestTableParam.new(optional: false)
4
+ params.add DataSourceParam.new('td')
5
+ params.add DateParam.new('from', 'DATE', 'Start date of logs to delete (%Y-%m-%d).')
6
+ params.add DateParam.new('to', 'DATE', 'End date of logs to delete (%Y-%m-%d).')
7
+ }
8
+
9
+ declarations {|params|
10
+ Declarations.new("dest_table" => nil)
11
+ }
12
+
13
+ script {|params, script|
14
+ script.task(params['data-source']) {|task|
15
+ task.delete params['dest-table'],
16
+ from: params['from'],
17
+ to: params['to']
18
+ }
19
+ }
20
+ }
@@ -0,0 +1,30 @@
1
+ JobClass.define('td-export') {
2
+ parameters {|params|
3
+ params.add SQLFileParam.new
4
+ params.add DestFileParam.new
5
+ params.add SrcTableParam.new
6
+ params.add StringParam.new('src-database', 'NAME', 'Source TD database name.', optional: true)
7
+ params.add EnumParam.new('format', %w(msgpack tsv csv json), 'Target file format.', default: 'msgpack')
8
+ params.add OptionalBoolParam.new('gzip', 'If true, compresses target file by gzip.')
9
+ params.add OptionalBoolParam.new('override', 'If true, clears target file. Otherwise causes error.')
10
+ params.add DataSourceParam.new('td')
11
+ }
12
+
13
+ parameters_filter {|job|
14
+ job.provide_sql_file_by_job_id
15
+ }
16
+
17
+ declarations {|params|
18
+ params['sql-file'].declarations
19
+ }
20
+
21
+ script {|params, script|
22
+ script.task(params['data-source']) {|task|
23
+ task.export params['sql-file'],
24
+ path: params['dest-file'],
25
+ format: params['format'],
26
+ gzip: params['gzip'],
27
+ override: params['override']
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,30 @@
1
+ require 'bricolage/psqldatasource'
2
+
3
+ JobClass.define('unload') {
4
+ parameters {|params|
5
+ params.add SQLFileParam.new
6
+ params.add DataSourceParam.new('sql', 'src-ds', 'Input data source (sql).')
7
+ params.add SrcTableParam.new(optional: false)
8
+ params.add DataSourceParam.new('s3', 'dest-ds', 'Target data source (s3).')
9
+ params.add DestFileParam.new
10
+ params.add EnumParam.new('format', %w(tsv), 'Data file format.', default: 'tsv')
11
+ params.add KeyValuePairsParam.new('options', 'OPTIONS', 'Loader options.',
12
+ optional: true, default: PSQLLoadOptions.new,
13
+ value_handler: lambda {|value, ctx, vars| PSQLLoadOptions.parse(value) })
14
+ }
15
+
16
+ parameters_filter {|job|
17
+ job.provide_sql_file_by_job_id
18
+ }
19
+
20
+ declarations {|params|
21
+ params['sql-file'].declarations
22
+ }
23
+
24
+ script {|params, script|
25
+ script.task(params['src-ds']) {|task|
26
+ task.unload params['sql-file'], params['dest-ds'], params['dest-file'],
27
+ params['format'], params['options']
28
+ }
29
+ }
30
+ }
@@ -0,0 +1,48 @@
1
+ JobClass.define('wait-file') {
2
+ parameters {|params|
3
+ params.add DestFileParam.new
4
+ params.add StringParam.new('condition-expr', 'RUBY_EXPR', 'Wait condition expression (in Ruby). (default: check file existance)', optional: true)
5
+ params.add StringParam.new('max-wait-minutes', 'NUM', 'Max waiting minutes.')
6
+ }
7
+
8
+ script {|params, script|
9
+ script.task(params.generic_ds) {|task|
10
+ dest_file = params['dest-file']
11
+ max_wait_minutes = params['max-wait-minutes'].to_i
12
+
13
+ default_expr = "File.exist?('#{dest_file}')"
14
+ condition_expr = params['condition-expr'] || default_expr
15
+
16
+ task.action("wait #{dest_file} (condition: #{condition_expr})") {|ds|
17
+ wait_file_condition(dest_file, condition_expr, max_wait_minutes, ds.logger)
18
+ }
19
+ }
20
+ }
21
+
22
+ REPORT_INTERVAL = 90 # 15 min
23
+ WAIT_INTERVAL = 5
24
+
25
+ def wait_file_condition(dest_file, condition_expr, max_wait_minutes, logger)
26
+ logger.info "waiting file by { #{condition_expr} }"
27
+
28
+ # DO NOT CHANGE these variables name; they are condition expression interface.
29
+ start_time = Time.now
30
+ wait_limit = start_time + max_wait_minutes * 60
31
+ last_log_time = start_time
32
+
33
+ until eval(condition_expr)
34
+ now = Time.now
35
+ if now > wait_limit
36
+ logger.error "exceeded wait limit (#{max_wait_minutes} minutes); abort"
37
+ return JobResult.for_bool(false)
38
+ end
39
+ if now - last_log_time > REPORT_INTERVAL
40
+ logger.info "waiting..."
41
+ last_log_time = Time.now
42
+ end
43
+ sleep WAIT_INTERVAL
44
+ end
45
+ logger.info "condition fullfilled"
46
+ JobResult.for_bool(true)
47
+ end
48
+ }