samidare 0.0.11 → 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/lib/samidare.rb +14 -45
- data/lib/samidare/bigquery_utility.rb +16 -16
- data/lib/samidare/embulk.rb +57 -0
- data/lib/samidare/embulk_utility.rb +19 -140
- data/lib/samidare/mysql.rb +117 -0
- data/lib/samidare/version.rb +1 -1
- data/spec/samidare/bigquery_utility_spec.rb +12 -12
- data/spec/samidare/embulk_spec.rb +23 -0
- data/spec/samidare/embulk_utility_spec.rb +7 -7
- data/spec/samidare/mysql_spec.rb +135 -0
- data/spec/samidare_spec.rb +7 -30
- data/spec/support/databe.yml +13 -0
- data/spec/support/table.yml +11 -0
- metadata +12 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: e2e4fe3e66626b0fd4eaf311505f35fd0b6c72e5
|
4
|
+
data.tar.gz: bf4ffdd752f991a74f55541a40068c2f560cc774
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: cec779faaaefadbd2731fd3010ea735fadae9823231bf4307d3c7d1ff7d1eb29804563812d15129611937da6eb5adce08af9bcef0eef709d758d2bd5f9fd126e
|
7
|
+
data.tar.gz: 5959e5303709334e485676f55c522f435b0d03ea461f2e4cba7cf085c9b034118ca1ee0522af418290164d94c5f6759a6aa5e5130755d44e6ac7eceacb189263
|
data/lib/samidare.rb
CHANGED
@@ -1,58 +1,27 @@
|
|
1
1
|
require 'samidare/version'
|
2
2
|
require 'samidare/embulk_utility'
|
3
|
+
require 'samidare/embulk'
|
4
|
+
require 'samidare/mysql'
|
3
5
|
|
4
6
|
module Samidare
|
5
7
|
class EmbulkClient
|
6
|
-
def generate_config(
|
7
|
-
Samidare::EmbulkUtility::ConfigGenerator.new(
|
8
|
+
def generate_config(bq_config)
|
9
|
+
Samidare::EmbulkUtility::ConfigGenerator.new.generate_config(database_configs, bq_config)
|
8
10
|
end
|
9
11
|
|
10
|
-
def run(
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
|
15
|
-
|
12
|
+
def run(bq_config, target_table_names = [])
|
13
|
+
error_tables = Samidare::Embulk.new.run(
|
14
|
+
database_configs,
|
15
|
+
Samidare::MySQL::TableConfig.generate_table_configs,
|
16
|
+
bq_config,
|
17
|
+
target_table_names)
|
18
|
+
# return batch status(true: all tables success)
|
19
|
+
error_tables.size == 0
|
16
20
|
end
|
17
21
|
|
18
22
|
private
|
19
|
-
def
|
20
|
-
|
21
|
-
big_query = Samidare::BigQueryUtility.new(config)
|
22
|
-
tables.each do |table|
|
23
|
-
next unless target_table?(table.name, target_tables)
|
24
|
-
|
25
|
-
start_time = Time.now
|
26
|
-
log "table: #{table.name} - start"
|
27
|
-
|
28
|
-
begin
|
29
|
-
big_query.delete_table(bq_dataset, table.name)
|
30
|
-
log "table: #{table.name} - deleted"
|
31
|
-
rescue
|
32
|
-
log "table: #{table.name} - does not exist"
|
33
|
-
end
|
34
|
-
|
35
|
-
cmd = "embulk run #{config['config_dir']}/#{db_name}/#{table.name}.yml"
|
36
|
-
log "cmd: #{cmd}"
|
37
|
-
result = system(cmd) ? 'success' : 'error'
|
38
|
-
|
39
|
-
process_time = Time.now - start_time
|
40
|
-
message = "table: #{table.name} - result: #{result} #{sprintf('%10.1f', process_time)}sec"
|
41
|
-
log message
|
42
|
-
process_times << message
|
43
|
-
end
|
44
|
-
log '------------------------------------'
|
45
|
-
log "db_name: #{db_name}"
|
46
|
-
process_times.each { |process_time| log process_time }
|
47
|
-
end
|
48
|
-
|
49
|
-
def target_table?(table, target_tables)
|
50
|
-
return true if target_tables.empty?
|
51
|
-
target_tables.include?(table)
|
52
|
-
end
|
53
|
-
|
54
|
-
def log(message)
|
55
|
-
puts "[#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}] #{message}"
|
23
|
+
def database_configs
|
24
|
+
YAML.load_file('database.yml')
|
56
25
|
end
|
57
26
|
end
|
58
27
|
end
|
@@ -39,33 +39,33 @@ module Samidare
|
|
39
39
|
@current_date = Date.today
|
40
40
|
end
|
41
41
|
|
42
|
-
def self.generate_schema(
|
43
|
-
json_body =
|
42
|
+
def self.generate_schema(columns)
|
43
|
+
json_body = columns.map { |column| column.to_json }.join(",\n")
|
44
44
|
"[\n" + json_body + "\n]\n"
|
45
45
|
end
|
46
46
|
|
47
|
-
def self.generate_sql(
|
48
|
-
columns =
|
47
|
+
def self.generate_sql(table_config, columns)
|
48
|
+
columns = columns.map { |column| column.converted_value }
|
49
49
|
sql = "SELECT " + columns.join(",")
|
50
|
-
sql << " FROM #{
|
51
|
-
sql << " WHERE #{
|
50
|
+
sql << " FROM #{table_config.name}"
|
51
|
+
sql << " WHERE #{table_config.condition}" if table_config.condition
|
52
52
|
sql << "\n"
|
53
53
|
sql
|
54
54
|
end
|
55
55
|
|
56
|
-
def generate_embulk_config(db_name,
|
57
|
-
host =
|
58
|
-
user =
|
59
|
-
password =
|
60
|
-
database =
|
61
|
-
query = Samidare::BigQueryUtility.generate_sql(
|
56
|
+
def generate_embulk_config(db_name, database_config, table_config, columns)
|
57
|
+
host = database_config['host']
|
58
|
+
user = database_config['username']
|
59
|
+
password = database_config['password']
|
60
|
+
database = database_config['database']
|
61
|
+
query = Samidare::BigQueryUtility.generate_sql(table_config, columns)
|
62
62
|
project = @config['project_id']
|
63
63
|
p12_keyfile_path = @config['key']
|
64
64
|
service_account_email = @config['service_email']
|
65
|
-
dataset =
|
66
|
-
table_name = actual_table_name(
|
67
|
-
schema_path = "#{@config['schema_dir']}/#{db_name}/#{
|
68
|
-
path_prefix = "/var/tmp/embulk_#{db_name}_#{
|
65
|
+
dataset = database_config['bq_dataset']
|
66
|
+
table_name = actual_table_name(table_config.name, database_config['daily_snapshot'] || table_config.daily_snapshot)
|
67
|
+
schema_path = "#{@config['schema_dir']}/#{db_name}/#{table_config.name}.json"
|
68
|
+
path_prefix = "/var/tmp/embulk_#{db_name}_#{table_config.name}"
|
69
69
|
|
70
70
|
ERB.new(CONTENTS).result(binding)
|
71
71
|
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module Samidare
|
2
|
+
class Embulk
|
3
|
+
def run(database_configs, all_table_configs, bq_config, target_table_names = [])
|
4
|
+
error_tables = []
|
5
|
+
database_configs.keys.each do |db_name|
|
6
|
+
table_configs = target_table_configs(all_table_configs[db_name], target_table_names)
|
7
|
+
error_tables << run_by_database(db_name, table_configs, database_configs[db_name]['bq_dataset'], bq_config)
|
8
|
+
end
|
9
|
+
error_tables
|
10
|
+
end
|
11
|
+
|
12
|
+
def target_table_configs(table_configs, target_table_names)
|
13
|
+
return table_configs if target_table_names.empty?
|
14
|
+
table_configs.select { |table_config| target_table_names.include?(table_config.name) }
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
def run_by_database(db_name, table_configs, bq_dataset, bq_config)
|
19
|
+
process_times = []
|
20
|
+
error_tables = []
|
21
|
+
big_query = Samidare::BigQueryUtility.new(bq_config)
|
22
|
+
table_configs.each do |table_config|
|
23
|
+
start_time = Time.now
|
24
|
+
log "table: #{table_config.name} - start"
|
25
|
+
|
26
|
+
begin
|
27
|
+
big_query.delete_table(bq_dataset, table_config.name)
|
28
|
+
log "table: #{table_config.name} - deleted"
|
29
|
+
rescue
|
30
|
+
log "table: #{table_config.name} - does not exist"
|
31
|
+
end
|
32
|
+
|
33
|
+
cmd = "embulk run #{bq_config['config_dir']}/#{db_name}/#{table_config.name}.yml"
|
34
|
+
log "cmd: #{cmd}"
|
35
|
+
if system(cmd)
|
36
|
+
result = 'success'
|
37
|
+
else
|
38
|
+
result = 'error'
|
39
|
+
error_tables << table_config.name
|
40
|
+
end
|
41
|
+
|
42
|
+
process_time = "table: #{table_config.name} - result: #{result} #{sprintf('%10.1f', Time.now - start_time)}sec"
|
43
|
+
log process_time
|
44
|
+
process_times << process_time
|
45
|
+
end
|
46
|
+
log '------------------------------------'
|
47
|
+
log "db_name: #{db_name}"
|
48
|
+
process_times.each { |process_time| log process_time }
|
49
|
+
|
50
|
+
error_tables
|
51
|
+
end
|
52
|
+
|
53
|
+
def log(message)
|
54
|
+
puts "[#{Time.now.strftime("%Y-%m-%d %H:%M:%S")}] #{message}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
@@ -1,36 +1,28 @@
|
|
1
|
-
require 'mysql2-cs-bind'
|
2
|
-
require 'json'
|
3
|
-
require 'yaml'
|
4
|
-
require 'fileutils'
|
5
|
-
require 'samidare/bigquery_utility'
|
6
|
-
|
7
1
|
module Samidare
|
8
2
|
module EmbulkUtility
|
9
3
|
class ConfigGenerator
|
10
|
-
def
|
11
|
-
|
12
|
-
end
|
13
|
-
|
14
|
-
def generate_config
|
15
|
-
db_infos = EmbulkUtility::DBInfo.generate_db_infos
|
16
|
-
table_infos = EmbulkUtility::TableInfo.generate_table_infos
|
17
|
-
bq_utility = BigQueryUtility.new(@bq_config)
|
4
|
+
def generate_config(database_configs, bq_config)
|
5
|
+
bq_utility = BigQueryUtility.new(bq_config)
|
18
6
|
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
mysql_client =
|
7
|
+
database_configs.keys.each do |db_name|
|
8
|
+
database_config = database_configs[db_name]
|
9
|
+
table_configs = all_table_configs[db_name]
|
10
|
+
mysql_client = MySQL::MySQLClient.new(database_config)
|
23
11
|
|
24
|
-
|
12
|
+
table_configs.each do |table_config|
|
25
13
|
write(
|
26
|
-
"#{
|
27
|
-
"#{
|
28
|
-
mysql_client.generate_bq_schema(
|
14
|
+
"#{bq_config['schema_dir']}/#{db_name}",
|
15
|
+
"#{table_config.name}.json",
|
16
|
+
mysql_client.generate_bq_schema(table_config.name)
|
29
17
|
)
|
30
18
|
write(
|
31
|
-
"#{
|
32
|
-
"#{
|
33
|
-
bq_utility.generate_embulk_config(
|
19
|
+
"#{bq_config['config_dir']}/#{db_name}",
|
20
|
+
"#{table_config.name}.yml",
|
21
|
+
bq_utility.generate_embulk_config(
|
22
|
+
db_name,
|
23
|
+
database_config,
|
24
|
+
table_config,
|
25
|
+
mysql_client.columns(table_config.name))
|
34
26
|
)
|
35
27
|
end
|
36
28
|
end
|
@@ -41,122 +33,9 @@ module Samidare
|
|
41
33
|
FileUtils.mkdir_p(directory) unless FileTest.exist?(directory)
|
42
34
|
File.write("#{directory}/#{file_name}", content)
|
43
35
|
end
|
44
|
-
end
|
45
|
-
|
46
|
-
class MySQLClient
|
47
|
-
COLUMN_INFO_SQL = <<-SQL
|
48
|
-
SELECT column_name, data_type
|
49
|
-
FROM INFORMATION_SCHEMA.COLUMNS
|
50
|
-
WHERE table_schema = ?
|
51
|
-
AND table_name = ?
|
52
|
-
ORDER BY ordinal_position
|
53
|
-
SQL
|
54
|
-
|
55
|
-
def initialize(db_info)
|
56
|
-
@db_info = db_info
|
57
|
-
end
|
58
|
-
|
59
|
-
def client
|
60
|
-
@client ||= Mysql2::Client.new(
|
61
|
-
:host => @db_info['host'],
|
62
|
-
:username => @db_info['username'],
|
63
|
-
:password => @db_info['password'],
|
64
|
-
:database => @db_info['database'])
|
65
|
-
end
|
66
|
-
|
67
|
-
def generate_bq_schema(table_name)
|
68
|
-
infos = column_infos(table_name)
|
69
|
-
BigQueryUtility.generate_schema(infos)
|
70
|
-
end
|
71
36
|
|
72
|
-
def
|
73
|
-
|
74
|
-
rows.map { |row| ColumnInfo.new(row['column_name'], row['data_type']) }
|
75
|
-
end
|
76
|
-
end
|
77
|
-
|
78
|
-
class DBInfo
|
79
|
-
def self.generate_db_infos
|
80
|
-
configs = YAML.load_file('database.yml')
|
81
|
-
configs
|
82
|
-
end
|
83
|
-
end
|
84
|
-
|
85
|
-
class TableInfo
|
86
|
-
def initialize(config)
|
87
|
-
@config = config.dup
|
88
|
-
end
|
89
|
-
|
90
|
-
def self.generate_table_infos
|
91
|
-
configs = YAML.load_file('table.yml')
|
92
|
-
configs.each_with_object({}) do |(db, db_info), table_infos|
|
93
|
-
table_infos[db] = db_info['tables'].map { |config| TableInfo.new(config) }
|
94
|
-
table_infos
|
95
|
-
end
|
96
|
-
end
|
97
|
-
|
98
|
-
def name
|
99
|
-
@config['name']
|
100
|
-
end
|
101
|
-
|
102
|
-
def daily_snapshot
|
103
|
-
@config['daily_snapshot'] || false
|
104
|
-
end
|
105
|
-
|
106
|
-
def condition
|
107
|
-
@config['condition']
|
108
|
-
end
|
109
|
-
end
|
110
|
-
|
111
|
-
class ColumnInfo
|
112
|
-
attr_reader :column_name, :data_type
|
113
|
-
|
114
|
-
TYPE_MAPPINGS = {
|
115
|
-
'int' => 'integer',
|
116
|
-
'tinyint' => 'integer',
|
117
|
-
'smallint' => 'integer',
|
118
|
-
'mediumint' => 'integer',
|
119
|
-
'bigint' => 'integer',
|
120
|
-
'float' => 'float',
|
121
|
-
'double' => 'float',
|
122
|
-
'decimal' => 'float',
|
123
|
-
'char' => 'string',
|
124
|
-
'varchar' => 'string',
|
125
|
-
'tinytext' => 'string',
|
126
|
-
'text' => 'string',
|
127
|
-
'date' => 'timestamp',
|
128
|
-
'datetime' => 'timestamp',
|
129
|
-
'timestamp' => 'timestamp'
|
130
|
-
}
|
131
|
-
|
132
|
-
def initialize(column_name, data_type)
|
133
|
-
@column_name = column_name
|
134
|
-
@data_type = data_type
|
135
|
-
end
|
136
|
-
|
137
|
-
def bigquery_data_type
|
138
|
-
TYPE_MAPPINGS[@data_type]
|
139
|
-
end
|
140
|
-
|
141
|
-
def converted_value
|
142
|
-
if bigquery_data_type == 'timestamp'
|
143
|
-
# time zone translate to UTC
|
144
|
-
"UNIX_TIMESTAMP(#{escaped_column_name}) AS #{escaped_column_name}"
|
145
|
-
elsif data_type == 'tinyint'
|
146
|
-
# for MySQL tinyint(1) problem
|
147
|
-
"CAST(#{escaped_column_name} AS signed) AS #{escaped_column_name}"
|
148
|
-
else
|
149
|
-
escaped_column_name
|
150
|
-
end
|
151
|
-
end
|
152
|
-
|
153
|
-
def to_json(*a)
|
154
|
-
{ "name" => @column_name, "type" => bigquery_data_type }.to_json(*a)
|
155
|
-
end
|
156
|
-
|
157
|
-
private
|
158
|
-
def escaped_column_name
|
159
|
-
"`#{@column_name}`"
|
37
|
+
def all_table_configs
|
38
|
+
@all_table_configs ||= MySQL::TableConfig.generate_table_configs
|
160
39
|
end
|
161
40
|
end
|
162
41
|
end
|
@@ -0,0 +1,117 @@
|
|
1
|
+
require 'mysql2-cs-bind'
|
2
|
+
require 'json'
|
3
|
+
require 'yaml'
|
4
|
+
require 'fileutils'
|
5
|
+
require 'samidare/bigquery_utility'
|
6
|
+
|
7
|
+
module Samidare
|
8
|
+
module MySQL
|
9
|
+
class MySQLClient
|
10
|
+
COLUMN_SQL = <<-SQL
|
11
|
+
SELECT column_name, data_type
|
12
|
+
FROM INFORMATION_SCHEMA.COLUMNS
|
13
|
+
WHERE table_schema = ?
|
14
|
+
AND table_name = ?
|
15
|
+
ORDER BY ordinal_position
|
16
|
+
SQL
|
17
|
+
|
18
|
+
def initialize(database_config)
|
19
|
+
@database_config = database_config
|
20
|
+
end
|
21
|
+
|
22
|
+
def client
|
23
|
+
@client ||= Mysql2::Client.new(
|
24
|
+
:host => @database_config['host'],
|
25
|
+
:username => @database_config['username'],
|
26
|
+
:password => @database_config['password'],
|
27
|
+
:database => @database_config['database'])
|
28
|
+
end
|
29
|
+
|
30
|
+
def generate_bq_schema(table_name)
|
31
|
+
infos = columns(table_name)
|
32
|
+
BigQueryUtility.generate_schema(infos)
|
33
|
+
end
|
34
|
+
|
35
|
+
def columns(table_name)
|
36
|
+
rows = client.xquery(COLUMN_SQL, @database_config['database'], table_name)
|
37
|
+
rows.map { |row| Column.new(row['column_name'], row['data_type']) }
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
class TableConfig
|
42
|
+
attr_reader :name, :daily_snapshot, :condition
|
43
|
+
|
44
|
+
def initialize(config)
|
45
|
+
@name = config['name']
|
46
|
+
@daily_snapshot = config['daily_snapshot'] || false
|
47
|
+
@condition = config['condition']
|
48
|
+
end
|
49
|
+
|
50
|
+
def self.generate_table_configs(file_path = 'table.yml')
|
51
|
+
configs = YAML.load_file(file_path)
|
52
|
+
configs.each_with_object({}) do |(db, database_config), table_configs|
|
53
|
+
table_configs[db] = database_config['tables'].map { |config| TableConfig.new(config) }
|
54
|
+
table_configs
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
def ==(another)
|
59
|
+
self.instance_variables.all? do |v|
|
60
|
+
self.instance_variable_get(v) == another.instance_variable_get(v)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
class Column
|
66
|
+
attr_reader :column_name, :data_type
|
67
|
+
|
68
|
+
TYPE_MAPPINGS = {
|
69
|
+
'int' => 'integer',
|
70
|
+
'tinyint' => 'integer',
|
71
|
+
'smallint' => 'integer',
|
72
|
+
'mediumint' => 'integer',
|
73
|
+
'bigint' => 'integer',
|
74
|
+
'float' => 'float',
|
75
|
+
'double' => 'float',
|
76
|
+
'decimal' => 'float',
|
77
|
+
'char' => 'string',
|
78
|
+
'varchar' => 'string',
|
79
|
+
'tinytext' => 'string',
|
80
|
+
'text' => 'string',
|
81
|
+
'date' => 'timestamp',
|
82
|
+
'datetime' => 'timestamp',
|
83
|
+
'timestamp' => 'timestamp'
|
84
|
+
}
|
85
|
+
|
86
|
+
def initialize(column_name, data_type)
|
87
|
+
@column_name = column_name
|
88
|
+
@data_type = data_type
|
89
|
+
end
|
90
|
+
|
91
|
+
def bigquery_data_type
|
92
|
+
TYPE_MAPPINGS[@data_type]
|
93
|
+
end
|
94
|
+
|
95
|
+
def converted_value
|
96
|
+
if bigquery_data_type == 'timestamp'
|
97
|
+
# time zone translate to UTC
|
98
|
+
"UNIX_TIMESTAMP(#{escaped_column_name}) AS #{escaped_column_name}"
|
99
|
+
elsif data_type == 'tinyint'
|
100
|
+
# for MySQL tinyint(1) problem
|
101
|
+
"CAST(#{escaped_column_name} AS signed) AS #{escaped_column_name}"
|
102
|
+
else
|
103
|
+
escaped_column_name
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
def to_json(*a)
|
108
|
+
{ "name" => @column_name, "type" => bigquery_data_type }.to_json(*a)
|
109
|
+
end
|
110
|
+
|
111
|
+
private
|
112
|
+
def escaped_column_name
|
113
|
+
"`#{@column_name}`"
|
114
|
+
end
|
115
|
+
end
|
116
|
+
end
|
117
|
+
end
|
data/lib/samidare/version.rb
CHANGED
@@ -4,12 +4,12 @@ require 'timecop'
|
|
4
4
|
|
5
5
|
describe Samidare::BigQueryUtility do
|
6
6
|
describe '.generate_schema' do
|
7
|
-
subject { Samidare::BigQueryUtility.generate_schema(
|
7
|
+
subject { Samidare::BigQueryUtility.generate_schema(columns) }
|
8
8
|
|
9
|
-
let(:
|
10
|
-
Samidare::
|
11
|
-
Samidare::
|
12
|
-
Samidare::
|
9
|
+
let(:columns) { [
|
10
|
+
Samidare::MySQL::Column.new('id', 'int'),
|
11
|
+
Samidare::MySQL::Column.new('name', 'varchar'),
|
12
|
+
Samidare::MySQL::Column.new('created_at', 'datetime')
|
13
13
|
] }
|
14
14
|
let(:schema_json) {
|
15
15
|
<<-JSON.unindent
|
@@ -24,22 +24,22 @@ describe Samidare::BigQueryUtility do
|
|
24
24
|
end
|
25
25
|
|
26
26
|
describe '.generate_sql' do
|
27
|
-
subject { Samidare::BigQueryUtility.generate_sql(
|
27
|
+
subject { Samidare::BigQueryUtility.generate_sql(table_config, columns) }
|
28
28
|
|
29
|
-
let(:
|
30
|
-
Samidare::
|
31
|
-
Samidare::
|
32
|
-
Samidare::
|
29
|
+
let(:columns) { [
|
30
|
+
Samidare::MySQL::Column.new('id', 'int'),
|
31
|
+
Samidare::MySQL::Column.new('name', 'varchar'),
|
32
|
+
Samidare::MySQL::Column.new('created_at', 'datetime')
|
33
33
|
] }
|
34
34
|
|
35
35
|
context 'no condition' do
|
36
|
-
let(:
|
36
|
+
let(:table_config) { Samidare::MySQL::TableConfig.new({ 'name' => 'simple' }) }
|
37
37
|
let(:sql) { "SELECT `id`,`name`,UNIX_TIMESTAMP(`created_at`) AS `created_at` FROM simple\n" }
|
38
38
|
it { expect(subject).to eq sql }
|
39
39
|
end
|
40
40
|
|
41
41
|
context 'has condition' do
|
42
|
-
let(:
|
42
|
+
let(:table_config) { Samidare::MySQL::TableConfig.new({ 'name' => 'simple', 'condition' => 'created_at >= CURRENT_DATE() - INTERVAL 3 MONTH' }) }
|
43
43
|
let(:sql) { "SELECT `id`,`name`,UNIX_TIMESTAMP(`created_at`) AS `created_at` FROM simple WHERE created_at >= CURRENT_DATE() - INTERVAL 3 MONTH\n" }
|
44
44
|
it { expect(subject).to eq sql }
|
45
45
|
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Samidare::Embulk do
|
4
|
+
describe '#target_table_configs' do
|
5
|
+
subject { Samidare::Embulk.new(nil, nil).target_table_configs(table_configs, target_table_names) }
|
6
|
+
|
7
|
+
context 'all tables' do
|
8
|
+
let(:table_hoge) { Samidare::MySQL::TableConfig.new({ 'name' => 'hoge' }) }
|
9
|
+
let(:table_fuga) { Samidare::MySQL::TableConfig.new({ 'name' => 'fuga' }) }
|
10
|
+
let(:table_configs) { [table_hoge, table_fuga] }
|
11
|
+
let(:target_table_names) { [] }
|
12
|
+
it { expect(subject).to match(table_configs) }
|
13
|
+
end
|
14
|
+
|
15
|
+
context 'target table selected' do
|
16
|
+
let(:table_hoge) { Samidare::MySQL::TableConfig.new({ 'name' => 'hoge' }) }
|
17
|
+
let(:table_fuga) { Samidare::MySQL::TableConfig.new({ 'name' => 'fuga' }) }
|
18
|
+
let(:table_configs) { [table_hoge, table_fuga] }
|
19
|
+
let(:target_table_names) { ['hoge'] }
|
20
|
+
it { expect(subject).to match([table_hoge]) }
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -1,15 +1,15 @@
|
|
1
1
|
require 'spec_helper'
|
2
2
|
|
3
|
-
describe Samidare::
|
4
|
-
let(:
|
3
|
+
describe Samidare::MySQL::Column do
|
4
|
+
let(:column) { Samidare::MySQL::Column.new(column_name, data_type) }
|
5
5
|
let(:column_name) { 'id' }
|
6
6
|
let(:data_type) { 'int' }
|
7
7
|
|
8
|
-
it { expect(
|
9
|
-
it { expect(
|
8
|
+
it { expect(column.column_name).to eq 'id' }
|
9
|
+
it { expect(column.data_type).to eq 'int' }
|
10
10
|
|
11
11
|
describe '#bigquery_data_type' do
|
12
|
-
subject {
|
12
|
+
subject { column.bigquery_data_type }
|
13
13
|
|
14
14
|
context 'int' do
|
15
15
|
let(:data_type) { 'int' }
|
@@ -88,7 +88,7 @@ describe Samidare::EmbulkUtility::ColumnInfo do
|
|
88
88
|
end
|
89
89
|
|
90
90
|
describe '#converted_value' do
|
91
|
-
subject {
|
91
|
+
subject { column.converted_value }
|
92
92
|
|
93
93
|
context 'datetime' do
|
94
94
|
let(:column_name) { 'create_at' }
|
@@ -110,7 +110,7 @@ describe Samidare::EmbulkUtility::ColumnInfo do
|
|
110
110
|
end
|
111
111
|
|
112
112
|
describe '#to_json' do
|
113
|
-
subject {
|
113
|
+
subject { column.to_json }
|
114
114
|
|
115
115
|
let(:column_name) { 'id' }
|
116
116
|
let(:data_type) { 'int' }
|
@@ -0,0 +1,135 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Samidare::MySQL::TableConfig do
|
4
|
+
|
5
|
+
describe '.generate_table_configs' do
|
6
|
+
subject { Samidare::MySQL::TableConfig.generate_table_configs('spec/support/table.yml') }
|
7
|
+
let(:db01_hoge) { Samidare::MySQL::TableConfig.new({ 'name' => 'hoge', 'daily_snapshot' => true }) }
|
8
|
+
let(:db01_simple) { Samidare::MySQL::TableConfig.new({ 'name' => 'simple' }) }
|
9
|
+
let(:db02_fuga) { Samidare::MySQL::TableConfig.new({ 'name' => 'fuga' }) }
|
10
|
+
let(:db02_with_condition) { Samidare::MySQL::TableConfig.new({ 'name' => 'with_condition', 'condition' => 'created_at < CURRENT_DATE()' }) }
|
11
|
+
|
12
|
+
it { expect(subject['db01'][0]).to eq db01_hoge }
|
13
|
+
it { expect(subject['db01'][1]).to eq db01_simple }
|
14
|
+
it { expect(subject['db02'][0]).to eq db02_fuga }
|
15
|
+
it { expect(subject['db02'][1]).to eq db02_with_condition }
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
describe Samidare::MySQL::Column do
|
20
|
+
let(:column) { Samidare::MySQL::Column.new(column_name, data_type) }
|
21
|
+
let(:column_name) { 'id' }
|
22
|
+
let(:data_type) { 'int' }
|
23
|
+
|
24
|
+
it { expect(column.column_name).to eq 'id' }
|
25
|
+
it { expect(column.data_type).to eq 'int' }
|
26
|
+
|
27
|
+
describe '#bigquery_data_type' do
|
28
|
+
subject { column.bigquery_data_type }
|
29
|
+
|
30
|
+
context 'int' do
|
31
|
+
let(:data_type) { 'int' }
|
32
|
+
it { expect(subject).to eq 'integer' }
|
33
|
+
end
|
34
|
+
|
35
|
+
context 'tinyint' do
|
36
|
+
let(:data_type) { 'tinyint' }
|
37
|
+
it { expect(subject).to eq 'integer' }
|
38
|
+
end
|
39
|
+
|
40
|
+
context 'smallint' do
|
41
|
+
let(:data_type) { 'smallint' }
|
42
|
+
it { expect(subject).to eq 'integer' }
|
43
|
+
end
|
44
|
+
|
45
|
+
context 'mediumint' do
|
46
|
+
let(:data_type) { 'mediumint' }
|
47
|
+
it { expect(subject).to eq 'integer' }
|
48
|
+
end
|
49
|
+
|
50
|
+
context 'bigint' do
|
51
|
+
let(:data_type) { 'bigint' }
|
52
|
+
it { expect(subject).to eq 'integer' }
|
53
|
+
end
|
54
|
+
|
55
|
+
context 'float' do
|
56
|
+
let(:data_type) { 'float' }
|
57
|
+
it { expect(subject).to eq 'float' }
|
58
|
+
end
|
59
|
+
|
60
|
+
context 'double' do
|
61
|
+
let(:data_type) { 'double' }
|
62
|
+
it { expect(subject).to eq 'float' }
|
63
|
+
end
|
64
|
+
|
65
|
+
context 'decimal' do
|
66
|
+
let(:data_type) { 'decimal' }
|
67
|
+
it { expect(subject).to eq 'float' }
|
68
|
+
end
|
69
|
+
|
70
|
+
context 'char' do
|
71
|
+
let(:data_type) { 'char' }
|
72
|
+
it { expect(subject).to eq 'string' }
|
73
|
+
end
|
74
|
+
|
75
|
+
context 'varchar' do
|
76
|
+
let(:data_type) { 'varchar' }
|
77
|
+
it { expect(subject).to eq 'string' }
|
78
|
+
end
|
79
|
+
|
80
|
+
context 'tinytext' do
|
81
|
+
let(:data_type) { 'tinytext' }
|
82
|
+
it { expect(subject).to eq 'string' }
|
83
|
+
end
|
84
|
+
|
85
|
+
context 'text' do
|
86
|
+
let(:data_type) { 'text' }
|
87
|
+
it { expect(subject).to eq 'string' }
|
88
|
+
end
|
89
|
+
|
90
|
+
context 'date' do
|
91
|
+
let(:data_type) { 'date' }
|
92
|
+
it { expect(subject).to eq 'timestamp' }
|
93
|
+
end
|
94
|
+
|
95
|
+
context 'datetime' do
|
96
|
+
let(:data_type) { 'datetime' }
|
97
|
+
it { expect(subject).to eq 'timestamp' }
|
98
|
+
end
|
99
|
+
|
100
|
+
context 'timestamp' do
|
101
|
+
let(:data_type) { 'timestamp' }
|
102
|
+
it { expect(subject).to eq 'timestamp' }
|
103
|
+
end
|
104
|
+
end
|
105
|
+
|
106
|
+
describe '#converted_value' do
|
107
|
+
subject { column.converted_value }
|
108
|
+
|
109
|
+
context 'datetime' do
|
110
|
+
let(:column_name) { 'create_at' }
|
111
|
+
let(:data_type) { 'datetime' }
|
112
|
+
it { expect(subject).to eq 'UNIX_TIMESTAMP(`create_at`) AS `create_at`' }
|
113
|
+
end
|
114
|
+
|
115
|
+
context 'int' do
|
116
|
+
let(:column_name) { 'id' }
|
117
|
+
let(:data_type) { 'int' }
|
118
|
+
it { expect(subject).to eq '`id`' }
|
119
|
+
end
|
120
|
+
|
121
|
+
context 'varchar' do
|
122
|
+
let(:column_name) { 'explanation' }
|
123
|
+
let(:data_type) { 'varchar' }
|
124
|
+
it { expect(subject).to eq '`explanation`' }
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
128
|
+
describe '#to_json' do
|
129
|
+
subject { column.to_json }
|
130
|
+
|
131
|
+
let(:column_name) { 'id' }
|
132
|
+
let(:data_type) { 'int' }
|
133
|
+
it { expect(subject).to eq '{"name":"id","type":"integer"}' }
|
134
|
+
end
|
135
|
+
end
|
data/spec/samidare_spec.rb
CHANGED
@@ -1,30 +1,7 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
describe Samidare do
|
4
|
-
it 'has a version number' do
|
5
|
-
expect(Samidare::VERSION).not_to be nil
|
6
|
-
end
|
7
|
-
|
8
|
-
describe Samidare::EmbulkClient do
|
9
|
-
describe '#target_table?' do
|
10
|
-
subject { Samidare::EmbulkClient.new.send(:target_table?, table, target_tables) }
|
11
|
-
context 'target_tables is empty' do
|
12
|
-
let(:table) { 'hoge' }
|
13
|
-
let(:target_tables) { [] }
|
14
|
-
it { expect(subject).to be_truthy }
|
15
|
-
end
|
16
|
-
|
17
|
-
context 'is included' do
|
18
|
-
let(:table) { 'hoge' }
|
19
|
-
let(:target_tables) { ['hoge'] }
|
20
|
-
it { expect(subject).to be_truthy }
|
21
|
-
end
|
22
|
-
|
23
|
-
context 'is not included' do
|
24
|
-
let(:table) { 'hoge' }
|
25
|
-
let(:target_tables) { ['fuga'] }
|
26
|
-
it { expect(subject).to be_falsy }
|
27
|
-
end
|
28
|
-
end
|
29
|
-
end
|
30
|
-
end
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe Samidare do
|
4
|
+
it 'has a version number' do
|
5
|
+
expect(Samidare::VERSION).not_to be nil
|
6
|
+
end
|
7
|
+
end
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: samidare
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.0
|
4
|
+
version: 0.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Ryoji Kobori
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-12-31 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -179,13 +179,19 @@ files:
|
|
179
179
|
- Rakefile
|
180
180
|
- lib/samidare.rb
|
181
181
|
- lib/samidare/bigquery_utility.rb
|
182
|
+
- lib/samidare/embulk.rb
|
182
183
|
- lib/samidare/embulk_utility.rb
|
184
|
+
- lib/samidare/mysql.rb
|
183
185
|
- lib/samidare/version.rb
|
184
186
|
- samidare.gemspec
|
185
187
|
- spec/samidare/bigquery_utility_spec.rb
|
188
|
+
- spec/samidare/embulk_spec.rb
|
186
189
|
- spec/samidare/embulk_utility_spec.rb
|
190
|
+
- spec/samidare/mysql_spec.rb
|
187
191
|
- spec/samidare_spec.rb
|
188
192
|
- spec/spec_helper.rb
|
193
|
+
- spec/support/databe.yml
|
194
|
+
- spec/support/table.yml
|
189
195
|
homepage: https://github.com/cobot00/samidare
|
190
196
|
licenses:
|
191
197
|
- MIT
|
@@ -212,6 +218,10 @@ specification_version: 4
|
|
212
218
|
summary: Embulk utility for MySQL to BigQuery
|
213
219
|
test_files:
|
214
220
|
- spec/samidare/bigquery_utility_spec.rb
|
221
|
+
- spec/samidare/embulk_spec.rb
|
215
222
|
- spec/samidare/embulk_utility_spec.rb
|
223
|
+
- spec/samidare/mysql_spec.rb
|
216
224
|
- spec/samidare_spec.rb
|
217
225
|
- spec/spec_helper.rb
|
226
|
+
- spec/support/databe.yml
|
227
|
+
- spec/support/table.yml
|