require 'flydata-core/compatibility_check/base' module FlydataCore module CompatibilityCheck class DbCompatibilityChecker < Base def do_check(option = @option, &block) query = create_query(option) result = if block block.call query else exec_query(query) end check_result(result, option) end def exec_query(query) begin client = build_db_client(@option) client.query(query) ensure client.close rescue nil if client end end # Override #def build_db_client(option) #end # Utility for building query # input: Array ['table_1', 'table_2', 'table_3', ...] # output: String "'table_1','table_2'" def table_names_in_query(tables) tables.collect{|tn| "'#{tn}'"}.join(',') end def database_in_query(database) "'#{database}'" end def word_for_table_schema "schema" end def get_schema_and_tables(result) table_schema = nil tables = [] result.each do |r| tbl = r['table_name'] tables << tbl unless tbl.to_s.empty? table_schema = r['table_schema'] if table_schema.nil? end [table_schema, tables] end end module TableExistenceCheck # Override # TABLE_EXISTENCE_CHECK_QUERY_TMPLT = SELECT... # COMPATIBILITY_ERROR_CLASS = MysqlCompatibilityError def create_query(option = @option) return nil if option[:tables].empty? self.class::TABLE_EXISTENCE_CHECK_QUERY_TMPLT % schema_and_table_in_query(option) end def check_result(result, option = @option) table_schema, existing_tables = get_schema_and_tables(result) missing_tables = option[:tables] - existing_tables unless missing_tables.empty? raise self.class::COMPATIBILITY_ERROR_CLASS, "These tables are missing in \"#{table_schema}\" #{word_for_table_schema}. Create these tables on your database or remove them from the data entry: #{missing_tables.join(", ")}" end end end module PrimaryKeyCheck # Override # PK_CHECK_QUERY_TMPLT = SELECT... # COMPATIBILITY_ERROR_CLASS = MysqlCompatibilityError def create_query(option = @option) pk_override = option[:pk_override] || {} tables = option[:tables].select{|tbl| pk_override[tbl.to_s].nil? } # exclude tables having pk_override return nil if tables.empty? (self.class::PK_CHECK_QUERY_TMPLT) % schema_and_table_in_query(option.merge(tables: tables)) end def check_result(result, option = @option) table_schema, missing_pk_tables = get_schema_and_tables(result) unless missing_pk_tables.empty? raise self.class::COMPATIBILITY_ERROR_CLASS, "Primary key is required for tables to sync. " + "Add primary key or remove following tables in \"#{table_schema}\" #{word_for_table_schema} from data entry: #{missing_pk_tables.join(", ")}" end end end module PkOverrideCheck # Override # PK_OVERRIDE_QUERY_TMPLT = SELECT... # COMPATIBILITY_ERROR_CLASS = MysqlCompatibilityError def create_query(option = @option) pk_override = option[:pk_override] || {} return nil if pk_override.empty? self.class::PK_OVERRIDE_QUERY_TMPLT % schema_and_table_in_query(option.merge(tables: pk_override.keys)) end def check_result(result, option = @option) tbl_cols = Hash.new{|h, k| h[k] = []} # key: table-name, value: array of column-name table_schema = nil result.each do |r| tbl_cols[r['table_name']] << r['column_name'] table_schema = r['table_schema'] if table_schema.nil? end pk_override = option[:pk_override] || {} missing_pk_override = {} pk_override.each do |tbl, pk_cols| missing_cols = pk_cols - tbl_cols[tbl] missing_pk_override[tbl] = missing_cols unless missing_cols.empty? end unless missing_pk_override.empty? msg = missing_pk_override.collect {|tbl, cols| "#{tbl} (#{cols.join(',')})" }.join(', ') raise self.class::COMPATIBILITY_ERROR_CLASS, "Columns set as primary key don't exist. " + "Set correct column names to these tables in \"#{table_schema}\" #{word_for_table_schema}: #{msg}" end end end end end