mysql2postgres 0.3.3 → 0.4.1

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 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