Class: Exwiw::Adapter::Mysql2Adapter
- Defined in:
- lib/exwiw/adapter/mysql2_adapter.rb
Instance Attribute Summary
Attributes inherited from Base
Instance Method Summary collapse
- #build_query(table, dump_target, table_by_name) ⇒ Object
- #compile_ast(query_ast) ⇒ Object
- #dump_schema(ordered_tables, output_path) ⇒ Object
- #execute(query_ast) ⇒ Object
- #to_bulk_delete(select_query_ast, table) ⇒ Object
- #to_bulk_insert(results, table) ⇒ Object
Methods inherited from Base
#dumpable?, #initialize, #output_extension, #post_insert_sql, #schema_output_extension, #supports_bulk_delete?, table_config_class, #validate_as_dump_target!
Constructor Details
This class inherits a constructor from Exwiw::Adapter::Base
Instance Method Details
#build_query(table, dump_target, table_by_name) ⇒ Object
6 7 8 |
# File 'lib/exwiw/adapter/mysql2_adapter.rb', line 6 def build_query(table, dump_target, table_by_name) Exwiw::QueryAstBuilder.run(table.name, table_by_name, dump_target, @logger) end |
#compile_ast(query_ast) ⇒ Object
129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 |
# File 'lib/exwiw/adapter/mysql2_adapter.rb', line 129 def compile_ast(query_ast) raise NotImplementedError unless query_ast.is_a?(Exwiw::QueryAst::Select) sql = "SELECT " sql += query_ast.columns.map { |col| compile_column_name(query_ast, col) }.join(', ') sql += " FROM #{query_ast.from_table_name}" query_ast.join_clauses.each do |join| sql += " JOIN #{join.join_table_name} ON #{join.base_table_name}.#{join.foreign_key} = #{join.join_table_name}.#{join.primary_key}" join.where_clauses.each do |where| compiled_where_condition = compile_where_condition(where, join.join_table_name) sql += " AND #{compiled_where_condition}" end end if query_ast.where_clauses.any? sql += " WHERE " sql += query_ast.where_clauses.map { |where| compile_where_condition(where, query_ast.from_table_name) }.join(' AND ') end sql end |
#dump_schema(ordered_tables, output_path) ⇒ Object
17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
# File 'lib/exwiw/adapter/mysql2_adapter.rb', line 17 def dump_schema(ordered_tables, output_path) require 'open3' table_names = ordered_tables.map(&:name) if table_names.empty? File.write(output_path, "-- Auto-generated by exwiw. No tables in scope.\n") return end cmd = [ 'mysqldump', "--host=#{@connection_config.host}", "--port=#{@connection_config.port}", "--user=#{@connection_config.user}", '--no-data', '--skip-add-drop-table', # `--skip-comments` only suppresses the dump's header lines # (e.g. `-- MySQL dump ...`, server version banner). Column and # table `COMMENT '...'` clauses are emitted inline inside # CREATE TABLE statements and are NOT affected, so this flag is # purely about reducing noise in the generated file. '--skip-comments', '--skip-set-charset', # Suppress `SET @@GLOBAL.GTID_PURGED=...` from the dump. It is intended # for replication setup and breaks when the target already has GTIDs # (ERROR 3546: added gtid set must not overlap with @@GLOBAL.GTID_EXECUTED). '--set-gtid-purged=OFF', '--compact', @connection_config.database_name, *table_names, ] env = { 'MYSQL_PWD' => @connection_config.password.to_s } @logger.debug(" Running mysqldump for #{table_names.size} table(s)...") stdout, stderr, status = Open3.capture3(env, *cmd) unless status.success? if stderr.include?('command not found') || stderr.empty? raise "Failed to run `mysqldump`. Ensure the mysql client is installed and on PATH. stderr: #{stderr}" end raise "mysqldump failed (exit #{status.exitstatus}): #{stderr}" end idempotent = DdlPostprocessor.add_if_not_exists_to_create_table(stdout) File.open(output_path, 'w') do |file| file.puts("-- Auto-generated by exwiw via mysqldump. Idempotent CREATE TABLE statements for mysql.") file.write(idempotent) end @logger.info(" Wrote schema for #{table_names.size} table(s) to #{output_path}.") end |
#execute(query_ast) ⇒ Object
10 11 12 13 14 15 |
# File 'lib/exwiw/adapter/mysql2_adapter.rb', line 10 def execute(query_ast) sql = compile_ast(query_ast) @logger.debug(" Executing SQL: \n#{sql}") connection.query(sql, cast: false, as: :array).to_a end |
#to_bulk_delete(select_query_ast, table) ⇒ Object
83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 |
# File 'lib/exwiw/adapter/mysql2_adapter.rb', line 83 def to_bulk_delete(select_query_ast, table) raise NotImplementedError unless select_query_ast.is_a?(Exwiw::QueryAst::Select) sql = "DELETE FROM #{select_query_ast.from_table_name}" if select_query_ast.join_clauses.empty? # Ignore filter option, because bulk delete is for cleaning before import, # so it should delete all records to avoid foreign key violation & data consistancy. compiled_where_conditions = select_query_ast. where_clauses. select { |where| where.is_a?(Exwiw::QueryAst::WhereClause) }. map do |where| compile_where_condition(where, select_query_ast.from_table_name) end if compiled_where_conditions.size > 0 sql += "\nWHERE " sql += compiled_where_conditions.join(' AND ') end sql += ";" return sql end subquery_ast = Exwiw::QueryAst::Select.new first_join = select_query_ast.join_clauses.first.clone subquery_ast.from(first_join.join_table_name) primay_key_col = table.columns.find { |col| col.name == table.primary_key } subquery_ast.select([primay_key_col]) select_query_ast.join_clauses[1..].each do |join| subquery_ast.join(join) end first_join.where_clauses.each do |where| # Ignore filter option, because bulk delete is for cleaning before import, # so it should delete all records to avoid foreign key violation & data consistancy. subquery_ast.where(where) if where.is_a?(Exwiw::QueryAst::WhereClause) end foreign_key = first_join.foreign_key subquery_sql = compile_ast(subquery_ast) sql += "\nWHERE #{select_query_ast.from_table_name}.#{foreign_key} IN (#{subquery_sql});" sql end |
#to_bulk_insert(results, table) ⇒ Object
68 69 70 71 72 73 74 75 76 77 78 79 80 81 |
# File 'lib/exwiw/adapter/mysql2_adapter.rb', line 68 def to_bulk_insert(results, table) table_name = table.name value_list = results.map do |row| quoted_values = row.map do |value| escape_value(value) end "(" + quoted_values.join(', ') + ")" end values = value_list.join(",\n") column_names = table.columns.map(&:name).join(', ') "INSERT INTO #{table_name} (#{column_names}) VALUES\n#{values};" end |