diff --git a/lib/hair_trigger.rb b/lib/hair_trigger.rb index 2400c8c..16867b9 100644 --- a/lib/hair_trigger.rb +++ b/lib/hair_trigger.rb @@ -8,6 +8,9 @@ require 'hair_trigger/railtie' if defined?(Rails::Railtie) module HairTrigger + POSTGRESQL_ADAPTERS = %i[postgresql postgis] + MYSQL_ADAPTERS = %i[mysql mysql2rgeo trilogy] + SQLITE_ADAPTERS = %i[sqlite litedb] autoload :Builder, 'hair_trigger/builder' autoload :MigrationReader, 'hair_trigger/migration_reader' @@ -233,14 +236,7 @@ def pg_schema end def adapter_name_for(adapter) - adapter_name = adapter.adapter_name.downcase - adapter_name.sub!(/\d$/, '') - case adapter_name - when "litedb" - :sqlite - else - adapter_name.to_sym - end + adapter.adapter_name.downcase.sub(/\d$/, '').to_sym end end end diff --git a/lib/hair_trigger/adapter.rb b/lib/hair_trigger/adapter.rb index 60cbd73..ec7cea8 100644 --- a/lib/hair_trigger/adapter.rb +++ b/lib/hair_trigger/adapter.rb @@ -27,11 +27,11 @@ def triggers(options = {}) name_clause = options[:only] ? "IN ('" + options[:only].join("', '") + "')" : nil adapter_name = HairTrigger.adapter_name_for(self) case adapter_name - when :sqlite + when *HairTrigger::SQLITE_ADAPTERS select_rows("SELECT name, sql FROM sqlite_master WHERE type = 'trigger' #{name_clause ? " AND name " + name_clause : ""}").each do |(name, definition)| triggers[name] = quote_table_name_in_trigger(definition) + ";\n" end - when :mysql, :trilogy, :mysql2rgeo + when *HairTrigger::MYSQL_ADAPTERS select_rows("SHOW TRIGGERS").each do |(name, event, table, actions, timing, created, sql_mode, definer)| definer = normalize_mysql_definer(definer) next if options[:only] && !options[:only].include?(name) @@ -41,7 +41,7 @@ def triggers(options = {}) #{actions} SQL end - when :postgresql, :postgis + when *POSTGRESQL_ADAPTERS function_conditions = "(SELECT typname FROM pg_type WHERE oid = prorettype) = 'trigger'" function_conditions << <<-SQL unless options[:simple_check] AND oid IN ( diff --git a/lib/hair_trigger/builder.rb b/lib/hair_trigger/builder.rb index 1880413..4325d99 100644 --- a/lib/hair_trigger/builder.rb +++ b/lib/hair_trigger/builder.rb @@ -44,7 +44,7 @@ def drop_triggers end def name(name) - @errors << ["trigger name cannot exceed 63 for postgres", :postgresql] if name.to_s.size > 63 + @errors << ["trigger name cannot exceed 63 for postgres", *HairTrigger::POSTGRESQL_ADAPTERS] if name.to_s.size > 63 options[:name] = name.to_s end @@ -54,7 +54,7 @@ def on(table) end def for_each(for_each) - @errors << ["sqlite and mysql don't support FOR EACH STATEMENT triggers", :sqlite, :mysql] if for_each == :statement + @errors << ["sqlite and mysql don't support FOR EACH STATEMENT triggers", *HairTrigger::SQLITE_ADAPTERS, *HairTrigger::MYSQL_ADAPTERS] if for_each == :statement raise DeclarationError, "invalid for_each" unless [:row, :statement].include?(for_each) options[:for_each] = for_each.to_s.upcase end @@ -107,9 +107,9 @@ def security(user) raise DeclarationError, "trigger security should be :invoker, :definer, CURRENT_USER, or a valid user (e.g. 'user'@'host')" end # sqlite default is n/a, mysql default is :definer, postgres default is :invoker - @errors << ["sqlite doesn't support trigger security", :sqlite] - @errors << ["postgresql doesn't support arbitrary users for trigger security", :postgresql] unless [:definer, :invoker].include?(user) - @errors << ["mysql doesn't support invoker trigger security", :mysql] if user == :invoker + @errors << ["sqlite doesn't support trigger security", *HairTrigger::SQLITE_ADAPTERS] + @errors << ["postgresql doesn't support arbitrary users for trigger security", *HairTrigger::POSTGRESQL_ADAPTERS] unless [:definer, :invoker].include?(user) + @errors << ["mysql doesn't support invoker trigger security", *HairTrigger::MYSQL_ADAPTERS] if user == :invoker options[:security] = user end @@ -122,8 +122,8 @@ def events(*events) events << :insert if events.delete(:create) events << :delete if events.delete(:destroy) raise DeclarationError, "invalid events" unless events & [:insert, :update, :delete, :truncate] == events - @errors << ["sqlite and mysql triggers may not be shared by multiple actions", :mysql, :sqlite] if events.size > 1 - @errors << ["sqlite and mysql do not support truncate triggers", :mysql, :sqlite] if events.include?(:truncate) + @errors << ["sqlite and mysql triggers may not be shared by multiple actions", *HairTrigger::MYSQL_ADAPTERS, *HairTrigger::SQLITE_ADAPTERS] if events.size > 1 + @errors << ["sqlite and mysql do not support truncate triggers", *HairTrigger::MYSQL_ADAPTERS, *HairTrigger::SQLITE_ADAPTERS] if events.include?(:truncate) options[:events] = events.map{ |e| e.to_s.upcase } end @@ -152,7 +152,7 @@ def self.chainable_methods(*methods) def #{method}(*args, &block) @chained_calls << :#{method} if @triggers || @trigger_group - @errors << ["mysql doesn't support #{method} within a trigger group", :mysql] unless [:name, :where, :all, :of].include?(:#{method}) + @errors << ["mysql doesn't support #{method} within a trigger group", *HairTrigger::MYSQL_ADAPTERS] unless [:name, :where, :all, :of].include?(:#{method}) end set_#{method}(*args, &(block_given? ? block : nil)) end @@ -174,7 +174,7 @@ def set_#{method}(*args, &block) chainable_methods :name, :on, :for_each, :before, :after, :where, :security, :timing, :events, :all, :nowrap, :of, :declare, :old_as, :new_as def create_grouped_trigger? - adapter_name == :mysql || adapter_name == :trilogy || adapter_name == :mysql2rgeo + HairTrigger::MYSQL_ADAPTERS.include?(adapter_name) end def prepare! @@ -234,11 +234,11 @@ def generate(validate = true) [generate_drop_trigger] + [case adapter_name - when :sqlite + when *HairTrigger::SQLITE_ADAPTERS generate_trigger_sqlite - when :mysql, :trilogy, :mysql2rgeo + when *HairTrigger::MYSQL_ADAPTERS generate_trigger_mysql - when :postgresql, :postgis + when *HairTrigger::POSTGRESQL_ADAPTERS generate_trigger_postgresql else raise GenerationError, "don't know how to build #{adapter_name} triggers yet" @@ -345,8 +345,8 @@ def actions_to_ruby(indent = '') def maybe_execute(&block) raise DeclarationError, "of may only be specified on update triggers" if options[:of] && options[:events] != ["UPDATE"] if block.arity > 0 # we're creating a trigger group, so set up some stuff and pass the buck - @errors << ["trigger group must specify timing and event(s) for mysql", :mysql] unless options[:timing] && options[:events] - @errors << ["nested trigger groups are not supported for mysql", :mysql] if @trigger_group + @errors << ["trigger group must specify timing and event(s) for mysql", *HairTrigger::MYSQL_ADAPTERS] unless options[:timing] && options[:events] + @errors << ["nested trigger groups are not supported for mysql", *HairTrigger::MYSQL_ADAPTERS] if @trigger_group @triggers = [] block.call(self) raise DeclarationError, "trigger group did not define any triggers" if @triggers.empty? @@ -375,9 +375,9 @@ def validate_names! subtriggers = all_triggers(false) named_subtriggers = subtriggers.select{ |t| t.options[:name] } if named_subtriggers.present? && !options[:name] - @warnings << ["nested triggers have explicit names, but trigger group does not. trigger name will be inferred", :mysql] + @warnings << ["nested triggers have explicit names, but trigger group does not. trigger name will be inferred", *HairTrigger::MYSQL_ADAPTERS] elsif subtriggers.present? && !named_subtriggers.present? && options[:name] - @warnings << ["trigger group has an explicit name, but nested triggers do not. trigger names will be inferred", :postgresql, :sqlite] + @warnings << ["trigger group has an explicit name, but nested triggers do not. trigger names will be inferred", *HairTrigger::POSTGRESQL_ADAPTERS, *HairTrigger::SQLITE_ADAPTERS] end end @@ -412,9 +412,9 @@ def declarations def supports_of? case adapter_name - when :sqlite + when *HairTrigger::SQLITE_ADAPTERS true - when :postgresql, :postgis + when *HairTrigger::POSTGRESQL_ADAPTERS db_version >= 90000 else false @@ -429,9 +429,9 @@ def referencing_clause(check_support = true) def supports_referencing? case adapter_name - when :sqlite, :mysql + when *HairTrigger::SQLITE_ADAPTERS, *HairTrigger::MYSQL_ADAPTERS false - when :postgresql, :postgis + when *HairTrigger::POSTGRESQL_ADAPTERS db_version >= 100000 else false @@ -440,9 +440,9 @@ def supports_referencing? def generate_drop_trigger case adapter_name - when :sqlite, :mysql, :trilogy, :mysql2rgeo + when *HairTrigger::SQLITE_ADAPTERS, *HairTrigger::MYSQL_ADAPTERS "DROP TRIGGER IF EXISTS #{prepared_name};\n" - when :postgresql, :postgis + when *HairTrigger::POSTGRESQL_ADAPTERS "DROP TRIGGER IF EXISTS #{prepared_name} ON #{adapter.quote_table_name(options[:table])};\nDROP FUNCTION IF EXISTS #{adapter.quote_table_name(prepared_name)}();\n" else raise GenerationError, "don't know how to drop #{adapter_name} triggers yet" @@ -532,7 +532,7 @@ def generate_trigger_mysql def db_version @db_version ||= case adapter_name - when :postgresql, :postgis + when *HairTrigger::POSTGRESQL_ADAPTERS adapter.send(:postgresql_version) end end diff --git a/lib/hair_trigger/schema_dumper.rb b/lib/hair_trigger/schema_dumper.rb index c36b9a4..0e54543 100644 --- a/lib/hair_trigger/schema_dumper.rb +++ b/lib/hair_trigger/schema_dumper.rb @@ -74,7 +74,7 @@ def triggers(stream) def normalize_trigger(name, definition, type) @adapter_name = @connection.adapter_name.downcase.to_sym - return definition unless @adapter_name == :postgresql || @adapter_name == :postgis + return definition unless HairTrigger::POSTGRESQL_ADAPTERS.include?(@adapter_name) # because postgres does not preserve the original CREATE TRIGGER/ # FUNCTION statements, its decompiled reconstruction will not match # ours. we work around it by creating our generated trigger/function, diff --git a/spec/adapter_spec.rb b/spec/adapter_spec.rb index a97d9f4..9663975 100644 --- a/spec/adapter_spec.rb +++ b/spec/adapter_spec.rb @@ -45,11 +45,6 @@ end end - context "mysql" do - let(:adapter) { :mysql } - it_behaves_like "mysql" - end if ADAPTERS.include? :mysql - context "mysql2" do let(:adapter) { :mysql2 } it_behaves_like "mysql"