mysql2postgres 0.3.3 → 0.4.1

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 44c431dce8b1d09c5ebef95e6f1a56dbc2d7b79e67b594821d9a33c287d5d2b5
4
- data.tar.gz: cf5352e91abcd255f2286a95a5a0c3c1dadae5cd3804f0914ea8dee999e27f4d
3
+ metadata.gz: 1108264fc3155986e78c07a12abd11c6ef39a1fb671a252e6921bf4bbf7f3a4b
4
+ data.tar.gz: 19837bf3a64bf6a204c9325b1271566e982467f7a3e9a53f966681c8a680e1ad
5
5
  SHA512:
6
- metadata.gz: 34cce30cf4cffd22bc21e0be57267da80f5806ebeebfcd2934acb6f306af79ba5da512065a8acd5367964a5af00265cea9b3c5cfbacc1f6e7425412300613420
7
- data.tar.gz: 72c40e74f83546cac80b33e8b22ecb7f8035ec15ace7a572d95373c83ce4055fde7809f52f7a0608fb7a426197d4c6a71cb39f815f3719f1a52adaf1ade266a2
6
+ metadata.gz: e5c54b071adaa63e1bfa5819fcadc7520f1063a4a0d2218adb5337361df259ddf574ab37bec2bc7f7683a0c4024679fd87c6d6715fe692a56768365cb5021a71
7
+ data.tar.gz: 992c22cdfa9e8ebea90fdecb10f95a00367b3ba9cd744c6cb0d954a0a2be81138376319a7f657337e8a50b83cd4969e577e7b6de480369e34edd1b9dcc8697e6
data/.gitignore CHANGED
@@ -7,3 +7,5 @@ config/database.yml
7
7
  Gemfile.lock
8
8
  pkg
9
9
  test/fixtures/test*.sql
10
+ .enable_dev
11
+ .enable_test
data/README.md CHANGED
@@ -2,8 +2,7 @@
2
2
 
3
3
  [![Run Linters](https://github.com/AlphaNodes/mysql2postgres/workflows/Run%20Rubocop/badge.svg)](https://github.com/AlphaNodes/mysql2postgres/actions/workflows/rubocop.yml) [![Run Tests](https://github.com/AlphaNodes/mysql2postgres/workflows/Tests/badge.svg)](https://github.com/AlphaNodes/mysql2postgres/actions/workflows/tests.yml)
4
4
 
5
- The minimum Ruby version supported in `main` branch is `2.7`,
6
- and the next release will have the same requirement.
5
+ Convert MySQL database to PostgreSQL database.
7
6
 
8
7
  ## Requirements
9
8
 
@@ -22,16 +21,22 @@ gem 'mysql2postgres'
22
21
  Configuration is written in [YAML format](http://www.yaml.org/ "YAML Ain't Markup Language")
23
22
  and passed as the first argument on the command line.
24
23
 
25
- Configuration file has be provided with config/database.yml, see config/default.database.yml for
26
- an example.
24
+ Configuration file has be provided with config/database.yml, see [config/default.database.yml](config/default.database.yml) for an example and for configuration information.
27
25
 
28
26
  ## Usage
29
27
 
30
28
  After providing settings, start migration with
31
29
 
32
30
  ```sh
31
+ # set destination to use
32
+ MYSQL2POSTGRES_ENV=test
33
+ # use can also use (MYSQL2POSTGRES_ENV is used, if both are defined)
34
+ RAILS_ENV=test
33
35
 
36
+ # with default configuration, which use config/database.yml
34
37
  bundle exec mysql2postgres
38
+ # OR with specified configuration file
39
+ bundle exec mysql2postgres /home/you/mysql2postgres.yml
35
40
  ```
36
41
 
37
42
  ## Tests
data/Rakefile CHANGED
@@ -22,7 +22,7 @@ end
22
22
 
23
23
  desc 'Run all tests'
24
24
  task :test do
25
- # Rake::Task['test:units'].invoke
25
+ Rake::Task['test:units'].invoke
26
26
  Rake::Task['test:integration'].invoke
27
27
  end
28
28
 
data/bin/mysql2postgres CHANGED
@@ -7,21 +7,13 @@ require 'rubygems'
7
7
  require 'bundler/setup'
8
8
  require 'mysql2postgres'
9
9
 
10
- CONFIG_FILE = File.join File.dirname(__dir__), 'config', 'database.yml'
10
+ config_file = ARGV.empty? ? File.join(File.dirname(__dir__), 'config', 'database.yml') : File.expand_path(ARGV[0])
11
11
 
12
- file = if ARGV.length.positive?
13
- ARGV[0]
14
- else
15
- CONFIG_FILE
16
- end
12
+ raise "'#{config_file}' does not exist" unless FileTest.exist? config_file
17
13
 
18
- unless FileTest.exist?(CONFIG_FILE) || (ARGV.length.positive? && FileTest.exist?(File.expand_path(ARGV[0])))
19
- raise "'#{file}' does not exist"
20
- end
14
+ db_yaml = YAML.safe_load File.read(config_file)
21
15
 
22
- db_yaml = YAML.safe_load File.read(file)
16
+ raise "'#{config_file}' does not contain a mysql configuration directive for conversion" unless db_yaml.key? 'mysql'
17
+ raise "'#{config_file}' does not contain destinations configuration directive for conversion" unless db_yaml.key? 'destinations'
23
18
 
24
- raise "'#{file}' does not contain a mysql configuration directive for conversion" unless db_yaml.key? 'mysql'
25
- raise "'#{file}' does not contain a destination configuration directive for conversion" unless db_yaml.key? 'destination'
26
-
27
- Mysql2postgres.new(db_yaml).convert
19
+ Mysql2postgres.new(db_yaml, config_file).convert
@@ -3,29 +3,17 @@
3
3
  class Mysql2postgres
4
4
  class Connection
5
5
  attr_reader :conn,
6
- :adapter,
7
6
  :hostname,
8
7
  :login,
9
8
  :password,
10
9
  :database,
11
10
  :schema,
12
11
  :port,
13
- :environment,
14
12
  :copy_manager,
15
13
  :stream,
16
14
  :is_copying
17
15
 
18
- def initialize(options)
19
- @environment = (ENV['RAILS_ENV'] || 'development').to_sym
20
-
21
- if options[:destination].nil? ||
22
- options[:destination].empty? ||
23
- options[:destination][environment].nil? ||
24
- options[:destination][environment].empty?
25
- raise 'Unable to locate PostgreSQL destination environment in the configuration file'
26
- end
27
-
28
- pg_options = options[:destination][environment]
16
+ def initialize(pg_options)
29
17
  @hostname = pg_options[:hostname] || 'localhost'
30
18
  @login = pg_options[:username]
31
19
  @password = pg_options[:password]
@@ -33,18 +21,20 @@ class Mysql2postgres
33
21
  @port = (pg_options[:port] || 5432).to_s
34
22
 
35
23
  @database, @schema = database.split ':'
36
- @adapter = pg_options[:adapter] || 'jdbcpostgresql'
37
24
 
25
+ @conn = open
26
+ raise_nil_connection if conn.nil?
27
+
28
+ @is_copying = false
29
+ @current_statement = ''
30
+ end
31
+
32
+ def open
38
33
  @conn = PG::Connection.open dbname: database,
39
34
  user: login,
40
35
  password: password,
41
36
  host: hostname,
42
37
  port: port
43
-
44
- raise_nil_connection if conn.nil?
45
-
46
- @is_copying = false
47
- @current_statement = ''
48
38
  end
49
39
 
50
40
  # ensure that the copy is completed, in case we hadn't seen a '\.' in the data stream.
@@ -120,6 +110,16 @@ class Mysql2postgres
120
110
  raise 'No Connection'
121
111
  end
122
112
 
113
+ def tables
114
+ result = run_statement <<~SQL_TABLES
115
+ SELECT table_name
116
+ FROM information_schema.tables
117
+ WHERE table_schema = 'public' AND table_type = 'BASE TABLE'
118
+ SQL_TABLES
119
+
120
+ result.map { |t| t['table_name'] }
121
+ end
122
+
123
123
  private
124
124
 
125
125
  def run_statement(statement)
@@ -16,7 +16,6 @@ class Mysql2postgres
16
16
  def initialize(reader, writer, options)
17
17
  @reader = reader
18
18
  @writer = writer
19
- @options = options
20
19
  @exclude_tables = options[:exclude_tables] || []
21
20
  @only_tables = options[:tables]
22
21
  @suppress_data = options[:suppress_data] || false
@@ -28,7 +27,7 @@ class Mysql2postgres
28
27
 
29
28
  def convert
30
29
  tables = reader.tables
31
- tables.reject! { |table| exclude_tables.include?(table.name) }
30
+ tables.reject! { |table| exclude_tables.include? table.name }
32
31
  tables.select! { |table| only_tables ? only_tables.include?(table.name) : true }
33
32
 
34
33
  # preserve order only works, if only_tables are specified
@@ -125,7 +125,7 @@ class Mysql2postgres
125
125
  @indexes << index
126
126
  elsif (match_data = /PRIMARY KEY .*\((.*)\)/.match(line))
127
127
  index[:primary] = true
128
- index[:columns] = match_data[1].split(',').map { |col| col.strip.delete('`') }
128
+ index[:columns] = match_data[1].split(',').map { |col| col.strip.delete '`' }
129
129
  @indexes << index
130
130
  end
131
131
  end
@@ -164,6 +164,24 @@ class Mysql2postgres
164
164
  end
165
165
  end
166
166
 
167
+ attr_reader :mysql
168
+
169
+ def initialize(options)
170
+ @host = options[:mysql][:hostname]
171
+ @user = options[:mysql][:username]
172
+ @passwd = options[:mysql][:password]
173
+ @db = options[:mysql][:database]
174
+ @port = if options[:mysql][:port]
175
+ options[:mysql][:port] unless options[:mysql][:port].to_s.empty?
176
+ else
177
+ 3306
178
+ end
179
+ @sock = options[:mysql][:socket] && !options[:mysql][:socket].empty? ? options[:mysql][:socket] : nil
180
+ @flag = options[:mysql][:flag] && !options[:mysql][:flag].empty? ? options[:mysql][:flag] : nil
181
+
182
+ connect
183
+ end
184
+
167
185
  def connect
168
186
  @mysql = ::Mysql.connect @host, @user, @passwd, @db, @port, @sock
169
187
  # utf8_unicode_ci :: https://rubydoc.info/gems/ruby-mysql/Mysql/Charset
@@ -197,22 +215,8 @@ class Mysql2postgres
197
215
  end
198
216
  end
199
217
 
200
- def initialize(options)
201
- @host = options[:mysql][:hostname]
202
- @user = options[:mysql][:username]
203
- @passwd = options[:mysql][:password]
204
- @db = options[:mysql][:database]
205
- @port = options[:mysql][:port] || 3306
206
- @sock = options[:mysql][:socket] && !options[:mysql][:socket].empty? ? options[:mysql][:socket] : nil
207
- @sock = options[:mysql][:flag] && !options[:mysql][:flag].empty? ? options[:mysql][:flag] : nil
208
-
209
- connect
210
- end
211
-
212
- attr_reader :mysql
213
-
214
218
  def tables
215
- @tables ||= @mysql.query('SHOW TABLES').map { |row| Table.new(self, row.first) }
219
+ @tables ||= @mysql.query('SHOW TABLES').map { |row| Table.new self, row.first }
216
220
  end
217
221
 
218
222
  def paginated_read(table, page_size)
@@ -5,14 +5,13 @@ require 'mysql2postgres/connection'
5
5
 
6
6
  class Mysql2postgres
7
7
  class PostgresDbWriter < PostgresFileWriter
8
- attr_reader :connection, :filename
8
+ attr_reader :connection
9
9
 
10
- def initialize(filename, options)
10
+ def initialize(file, destination)
11
11
  # NOTE: the superclass opens and truncates filename for writing
12
- super filename
12
+ super
13
13
 
14
- @filename = filename
15
- @connection = Connection.new options
14
+ @connection = Connection.new destination
16
15
  end
17
16
 
18
17
  def inload(path = filename)
@@ -1,12 +1,16 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'mysql2postgres/postgres_writer'
4
+ require 'fileutils'
4
5
 
5
6
  class Mysql2postgres
6
7
  class PostgresFileWriter < PostgresWriter
7
- def initialize(file)
8
+ def initialize(file, destination)
8
9
  super()
9
10
 
11
+ @filename = file
12
+ @destination = destination
13
+
10
14
  @f = File.open file, 'w+:UTF-8'
11
15
  @f << <<~SQL_HEADER
12
16
  -- MySQL 2 PostgreSQL dump\n
@@ -88,7 +92,7 @@ class Mysql2postgres
88
92
  @f << columns
89
93
 
90
94
  if (primary_index = table.indexes.find { |index| index[:primary] })
91
- @f << ",\n CONSTRAINT #{table.name}_pkey PRIMARY KEY(#{primary_index[:columns].map { |col| PG::Connection.quote_ident(col) }.join(', ')})"
95
+ @f << ",\n CONSTRAINT #{table.name}_pkey PRIMARY KEY(#{quoted_list primary_index[:columns]})"
92
96
  end
93
97
 
94
98
  @f << <<~SQL_OIDS
@@ -103,7 +107,7 @@ class Mysql2postgres
103
107
  @f << <<~SQL_INDEX
104
108
  DROP INDEX IF EXISTS #{PG::Connection.quote_ident index[:name]} CASCADE;
105
109
  CREATE #{unique}INDEX #{PG::Connection.quote_ident index[:name]}
106
- ON #{PG::Connection.quote_ident table.name} (#{index[:columns].map { |col| PG::Connection.quote_ident(col) }.join(', ')});
110
+ ON #{PG::Connection.quote_ident table.name} (#{quoted_list index[:columns]});
107
111
  SQL_INDEX
108
112
  end
109
113
  end
@@ -113,8 +117,8 @@ class Mysql2postgres
113
117
  def write_constraints(table)
114
118
  table.foreign_keys.each do |key|
115
119
  @f << "ALTER TABLE #{PG::Connection.quote_ident table.name} " \
116
- "ADD FOREIGN KEY (#{key[:column].map { |c| PG::Connection.quote_ident(c) }.join(', ')}) " \
117
- "REFERENCES #{PG::Connection.quote_ident key[:ref_table]}(#{key[:ref_column].map { |c| PG::Connection.quote_ident(c) }.join(', ')}) " \
120
+ "ADD FOREIGN KEY (#{quoted_list key[:column]}) " \
121
+ "REFERENCES #{PG::Connection.quote_ident key[:ref_table]}(#{quoted_list key[:ref_column]}) " \
118
122
  "ON UPDATE #{key[:on_update]} ON DELETE #{key[:on_delete]};\n"
119
123
  end
120
124
  end
@@ -125,7 +129,7 @@ class Mysql2postgres
125
129
  -- Data for Name: #{table.name}; Type: TABLE DATA; Schema: public
126
130
  --
127
131
 
128
- COPY "#{table.name}" (#{table.columns.map { |column| PG::Connection.quote_ident(column[:name]) }.join(', ')}) FROM stdin;
132
+ COPY "#{table.name}" (#{quoted_list(table.columns.map { |m| m[:name] })}) FROM stdin;
129
133
  SQL_COPY
130
134
 
131
135
  reader.paginated_read table, 1000 do |row, _counter|
@@ -139,5 +143,15 @@ class Mysql2postgres
139
143
  def close
140
144
  @f.close
141
145
  end
146
+
147
+ def inload
148
+ puts "\nSkip import to PostgreSQL DB. SQL file created successfully."
149
+ end
150
+
151
+ private
152
+
153
+ def quoted_list(list)
154
+ list.map { |c| PG::Connection.quote_ident c }.join(', ')
155
+ end
142
156
  end
143
157
  end
@@ -1,10 +1,11 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  require 'zlib'
4
- require 'mysql2postgres/writer'
5
4
 
6
5
  class Mysql2postgres
7
- class PostgresWriter < Writer
6
+ class PostgresWriter
7
+ attr_reader :filename, :destination
8
+
8
9
  def column_description(column)
9
10
  "#{PG::Connection.quote_ident column[:name]} #{column_type_info column}"
10
11
  end
@@ -50,16 +51,21 @@ class Mysql2postgres
50
51
  when 'double precision'
51
52
  default = " DEFAULT #{column[:default].nil? ? 'NULL' : column[:default]}" if default
52
53
  'double precision'
53
- when 'datetime'
54
+ when 'datetime', 'datetime(6)'
54
55
  default = nil
55
56
  'timestamp without time zone'
56
57
  when 'date'
57
58
  default = nil
58
59
  'date'
59
60
  when 'timestamp'
60
- default = ' DEFAULT CURRENT_TIMESTAMP' if column[:default] == 'CURRENT_TIMESTAMP'
61
- default = " DEFAULT '1970-01-01 00:00'" if column[:default] == '0000-00-00 00:00'
62
- default = " DEFAULT '1970-01-01 00:00:00'" if column[:default] == '0000-00-00 00:00:00'
61
+ case column[:default]
62
+ when 'CURRENT_TIMESTAMP'
63
+ default = ' DEFAULT CURRENT_TIMESTAMP'
64
+ when datetime_zero
65
+ default = " DEFAULT '#{datetime_zero_fix}'"
66
+ when datetime_zero(with_seconds: true) # rubocop: disable Style/MethodCallWithArgsParentheses
67
+ default = " DEFAULT '#{datetime_zero_fix with_seconds: true}'"
68
+ end
63
69
  'timestamp without time zone'
64
70
  when 'time'
65
71
  default = ' DEFAULT NOW()' if default
@@ -89,45 +95,74 @@ class Mysql2postgres
89
95
  row[index] = Time.at(row[index]).utc.strftime('%H:%M:%S') if column[:type] == 'time' && row[index]
90
96
 
91
97
  if row[index].is_a? Time
92
- row[index] = row[index].to_s.gsub '0000-00-00 00:00', '1970-01-01 00:00'
93
- row[index] = row[index].to_s.gsub '0000-00-00 00:00:00', '1970-01-01 00:00:00'
98
+ row[index] = row[index].to_s.gsub datetime_zero, datetime_zero_fix
99
+ row[index] = row[index].to_s.gsub datetime_zero(with_seconds: true), datetime_zero_fix(with_seconds: true)
94
100
  end
95
101
 
96
102
  if column_type(column) == 'boolean'
97
103
  row[index] = if row[index] == 1
98
104
  't'
105
+ elsif row[index]&.zero?
106
+ 'f'
99
107
  else
100
- row[index].zero? ? 'f' : row[index]
108
+ row[index]
101
109
  end
102
110
  end
103
111
 
104
- if row[index].is_a? String
105
- row[index] = if column_type(column) == 'bytea'
106
- if column[:name] == 'data'
107
- with_gzip = false
108
- table.columns.each_with_index do |column_data, index_data|
109
- if column_data[:name] == 'compression' && row[index_data] == 'gzip'
110
- with_gzip = true
111
- break
112
- end
113
- end
114
- if with_gzip
115
- PG::Connection.escape_bytea(Zlib::Inflate.inflate(row[index])).gsub(/\\/, '\\\\\\').gsub(/''/, "'")
116
- else
117
- PG::Connection.escape_bytea(row[index]).gsub(/\\/, '\\\\\\').gsub(/''/, "'")
118
- end
119
- else
120
- PG::Connection.escape_bytea(row[index]).gsub(/\\/, '\\\\\\').gsub(/''/, "'")
121
- end
122
- else
123
- row[index].gsub(/\\/, '\\\\\\').gsub(/\n/, '\n').gsub(/\t/, '\t').gsub(/\r/, '\r').gsub(/\0/, '')
124
- end
125
- end
112
+ row[index] = string_data table, row, index, column if row[index].is_a? String
126
113
 
127
114
  row[index] = '\N' unless row[index]
128
115
  end
129
116
  end
130
117
 
131
118
  def truncate(_table) end
119
+
120
+ def inload
121
+ raise "Method 'inload' needs to be overridden..."
122
+ end
123
+
124
+ private
125
+
126
+ def datetime_zero(with_seconds: false)
127
+ datetime_value date: '0000-00-00', with_seconds: with_seconds
128
+ end
129
+
130
+ def datetime_zero_fix(with_seconds: false)
131
+ datetime_value date: '1970-01-01', with_seconds: with_seconds
132
+ end
133
+
134
+ def datetime_value(date:, with_seconds: false)
135
+ value = ["#{date} 00:00"]
136
+ value << '00' if with_seconds
137
+ value.join ':'
138
+ end
139
+
140
+ def string_data(table, row, index, column)
141
+ if column_type(column) == 'bytea'
142
+ if column[:name] == 'data'
143
+ with_gzip = false
144
+ table.columns.each_with_index do |column_data, index_data|
145
+ if column_data[:name] == 'compression' && row[index_data] == 'gzip'
146
+ with_gzip = true
147
+ break
148
+ end
149
+ end
150
+
151
+ escape_bytea(with_gzip ? Zlib::Inflate.inflate(row[index]) : row[index])
152
+ else
153
+ escape_bytea row[index]
154
+ end
155
+ else
156
+ escape_data(row[index]).gsub("\n", '\n').gsub("\t", '\t').gsub("\r", '\r').gsub(/\0/, '')
157
+ end
158
+ end
159
+
160
+ def escape_bytea(data)
161
+ escape_data(PG::Connection.escape_bytea(data)).gsub("''", "'")
162
+ end
163
+
164
+ def escape_data(value)
165
+ value.gsub '\\', '\\\\\\'
166
+ end
132
167
  end
133
168
  end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  class Mysql2postgres
4
- VERSION = '0.3.3'
4
+ VERSION = '0.4.1'
5
5
  end
@@ -12,7 +12,6 @@ require 'pg/result'
12
12
  require 'mysql2postgres/version'
13
13
  require 'mysql2postgres/converter'
14
14
  require 'mysql2postgres/mysql_reader'
15
- require 'mysql2postgres/writer'
16
15
  require 'mysql2postgres/postgres_writer'
17
16
  require 'mysql2postgres/postgres_file_writer'
18
17
  require 'mysql2postgres/postgres_db_writer'
@@ -20,42 +19,76 @@ require 'mysql2postgres/postgres_db_writer'
20
19
  require 'debug' if ENV.fetch('ENABLE_DEBUG', nil) == '1'
21
20
 
22
21
  class Mysql2postgres
23
- attr_reader :options, :reader, :writer
22
+ attr_reader :options, :config_file, :reader, :writer
24
23
 
25
- def initialize(yaml)
24
+ def initialize(yaml, config_file = nil)
25
+ @config_file = config_file
26
26
  @options = build_options yaml
27
27
  end
28
28
 
29
- def build_options(yaml)
30
- yaml.transform_keys(&:to_sym).tap do |opts|
31
- opts[:mysql].transform_keys!(&:to_sym)
32
- opts[:destination].transform_keys!(&:to_sym)
33
- opts[:destination].each do |env, settings|
34
- opts[:destination][env] = settings.transform_keys(&:to_sym)
35
- end
36
- end
37
- end
29
+ def convert
30
+ @reader = MysqlReader.new options
31
+
32
+ puts "mysql2postgres #{Mysql2postgres::VERSION}"
33
+ puts "Config file: #{config_file}"
34
+ puts "Dumpfile: #{dump_file}"
35
+
36
+ @writer = if to_file?
37
+ puts 'Target: File'
38
+ PostgresFileWriter.new dump_file, options[:destination]
39
+ else
40
+ puts "Target: PostgreSQL DB (#{adapter})"
41
+ PostgresDbWriter.new dump_file, options[:destination]
42
+ end
38
43
 
39
- def send_file_to_postgres(path)
40
- connection = Connection.new options
41
- connection.load_file path
44
+ Converter.new(reader, writer, options).convert
45
+ File.delete dump_file if options[:remove_dump_file] && File.exist?(dump_file)
42
46
  end
43
47
 
44
- def convert
45
- @reader = MysqlReader.new options
48
+ private
46
49
 
47
- tag = Time.new.strftime '%Y%m%d-%H%M%S'
50
+ def adapter
51
+ if options[:destination][:adapter].nil? || options[:destination][:adapter].empty?
52
+ 'postgresql'
53
+ else
54
+ options[:destination][:adapter]
55
+ end
56
+ end
48
57
 
49
- path = './'
50
- path = options[:dump_file_directory] if options[:dump_file_directory]
58
+ def environment
59
+ if ENV['MYSQL2POSTGRES_ENV']
60
+ ENV['MYSQL2POSTGRES_ENV']
61
+ elsif ENV['RAILS_ENV']
62
+ ENV['RAILS_ENV']
63
+ else
64
+ 'development'
65
+ end
66
+ end
51
67
 
52
- filename = File.expand_path File.join(path, "output_#{tag}.sql")
53
- puts "Dumpfile: #{filename}"
68
+ def to_file?
69
+ adapter == 'file'
70
+ end
54
71
 
55
- @writer = PostgresDbWriter.new filename, options
72
+ def build_options(yaml)
73
+ yaml.transform_keys(&:to_sym).tap do |opts|
74
+ opts[:mysql].transform_keys!(&:to_sym)
56
75
 
57
- Converter.new(reader, writer, options).convert
76
+ destinations = opts.delete :destinations
77
+ opts[:destination] = destinations[environment]&.transform_keys(&:to_sym)
78
+
79
+ if opts[:destination].nil? || opts[:destination].empty?
80
+ raise "no configuration for environment '#{environment}' in destinations available. Use MYSQL2POSTGRES_ENV or RAILS_ENV."
81
+ end
82
+ end
83
+ end
58
84
 
59
- File.delete filename if options[:remove_dump_file] && File.exist?(filename)
85
+ def dump_file
86
+ @dump_file ||= if to_file? && options[:destination][:filename] && options[:destination][:filename] != ''
87
+ options[:destination][:filename]
88
+ else
89
+ tag = Time.new.strftime '%Y%m%d-%H%M%S'
90
+ path = options[:dump_file_directory] || './'
91
+ File.expand_path File.join(path, "output_#{tag}.sql")
92
+ end
60
93
  end
61
94
  end
@@ -1,7 +1,6 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  lib = File.expand_path '../lib', __FILE__
4
- puts lib
5
4
  $LOAD_PATH.unshift lib unless $LOAD_PATH.include? lib
6
5
  require 'mysql2postgres/version'
7
6
 
@@ -50,31 +49,28 @@ Gem::Specification.new do |s|
50
49
  'lib/mysql2postgres/postgres_db_writer.rb',
51
50
  'lib/mysql2postgres/postgres_writer.rb',
52
51
  'lib/mysql2postgres/version.rb',
53
- 'lib/mysql2postgres/writer.rb',
54
52
  'mysql2postgres.gemspec',
55
53
  'test/fixtures/config_all_options.yml',
54
+ 'test/fixtures/config_min_options.yml',
55
+ 'test/fixtures/config_to_file.yml',
56
56
  'test/fixtures/seed_integration_tests.sql',
57
57
  'test/integration/convert_to_db_test.rb',
58
58
  'test/integration/convert_to_file_test.rb',
59
59
  'test/integration/converter_test.rb',
60
- 'test/integration/mysql_reader_base_test.rb',
60
+ 'test/integration/mysql_reader_connection_test.rb',
61
61
  'test/integration/mysql_reader_test.rb',
62
- 'test/integration/postgres_db_writer_base_test.rb',
62
+ 'test/integration/postgres_db_writer_test.rb',
63
+ 'test/units/mysql_test.rb',
63
64
  'test/units/option_test.rb',
64
65
  'test/units/postgres_file_writer_test.rb',
65
66
  'test/test_helper.rb'
66
67
  ]
67
- s.homepage = 'https://code.alphanodes.com/alphanodes/mysql2postgres'
68
+ s.homepage = 'https://github.com/AlphaNodes/mysql2postgres'
68
69
  s.rdoc_options = ['--charset=UTF-8']
69
70
  s.require_paths = ['lib']
70
71
  s.summary = 'MySQL to PostgreSQL Data Translation'
71
72
 
72
- s.add_dependency 'rake'
73
73
  s.add_runtime_dependency 'pg', '~> 1.2.2'
74
- s.add_runtime_dependency 'postgres-pr', '~> 0.7'
74
+ s.add_runtime_dependency 'rake'
75
75
  s.add_runtime_dependency 'ruby-mysql', '~> 3.0'
76
- s.add_development_dependency 'debug'
77
- s.add_development_dependency 'rubocop-minitest'
78
- s.add_development_dependency 'rubocop-performance'
79
- s.add_development_dependency 'test-unit', '~> 3.5.3'
80
76
  end