hairtrigger 1.3.0 → 1.3.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: 1798fb4e1b61d82806b26b2dcf147e220b9ff5c4044a60ccb589407390695f4d
4
- data.tar.gz: 2ccbd8b57c5c8c7edd82c512c3526d4be004363cecdf0cd710e5315db64fb39b
3
+ metadata.gz: 00e0ef28f55f9f28dddc16dadc2acfadbefa3007eacc294591fc8a2047f547ed
4
+ data.tar.gz: 7c1aef527b1343d68651bddc00a4cd1b9012b78a4c9a81c0fd333be8f2adb72d
5
5
  SHA512:
6
- metadata.gz: 14903c29e02310555603f4298a3e930e16467bbc5495db09089eeef0d5291e998978078fc1dbd79f390bef21bea31f4e76dae7438069362aebcdaf047b22ed43
7
- data.tar.gz: 2b96e24dbad2c2d9b71534229a267bca2c5de95d9954b43e69fdbcb9f4a22ec064d52e7ca9ce3dc941d2376f26877e086631a3aa895f5fdd7b94fac31e33e64e
6
+ metadata.gz: e81ed119bd7f7a3c20fc5f9a7ed365ed5a67551b11063efbd3aeecf9f4116b88b662d6ecf309e7e8fa1b7efedd76519c2f5770851797639750078e034793e152
7
+ data.tar.gz: e1416ac1fca775b6a600c2a658a1aa51088893293a818d56d8bd0df13821ff4bf54d104177db54bf532a85c054cbbde55a1afe2575b1ab48ef66139b06981afa
data/README.md CHANGED
@@ -338,6 +338,13 @@ ignore. Note that this behavior [may change](https://github.com/jenseng/hair_tri
338
338
  in a future release, meaning you'll first need to explicitly drop the
339
339
  existing trigger if you wish to redefine it.
340
340
 
341
+ ## Custom adapters
342
+
343
+ Out of the box, HairTrigger supports the standard adapters for PostgreSQL, MySQL, and SQLite, plus several common variations (`postgis`, `mysql2rgeo`, `trilogy`, and `litedb`). If you would like to use HairTrigger with another compatible variation, you can dynamically add it to `HairTrigger.hair_trigger_configuration`, for example:
344
+ ```ruby
345
+ HairTrigger.hair_trigger_configuration.postgresql_adapters << :postgresql_proxy
346
+ ```
347
+
341
348
  ## Gotchas
342
349
 
343
350
  * As is the case with `ActiveRecord::Base.update_all` or any direct SQL you do,
@@ -27,11 +27,11 @@ module HairTrigger
27
27
  name_clause = options[:only] ? "IN ('" + options[:only].join("', '") + "')" : nil
28
28
  adapter_name = HairTrigger.adapter_name_for(self)
29
29
  case adapter_name
30
- when *HairTrigger::SQLITE_ADAPTERS
30
+ when *HairTrigger.hair_trigger_config.sqlite_adapters
31
31
  select_rows("SELECT name, sql FROM sqlite_master WHERE type = 'trigger' #{name_clause ? " AND name " + name_clause : ""}").each do |(name, definition)|
32
32
  triggers[name] = quote_table_name_in_trigger(definition) + ";\n"
33
33
  end
34
- when *HairTrigger::MYSQL_ADAPTERS
34
+ when *HairTrigger.hair_trigger_config.mysql_adapters
35
35
  select_rows("SHOW TRIGGERS").each do |(name, event, table, actions, timing, created, sql_mode, definer)|
36
36
  definer = normalize_mysql_definer(definer)
37
37
  next if options[:only] && !options[:only].include?(name)
@@ -41,7 +41,7 @@ FOR EACH ROW
41
41
  #{actions}
42
42
  SQL
43
43
  end
44
- when *POSTGRESQL_ADAPTERS
44
+ when *HairTrigger.hair_trigger_config.postgresql_adapters
45
45
  function_conditions = "(SELECT typname FROM pg_type WHERE oid = prorettype) = 'trigger'"
46
46
  function_conditions << <<-SQL unless options[:simple_check]
47
47
  AND oid IN (
@@ -44,7 +44,7 @@ module HairTrigger
44
44
  end
45
45
 
46
46
  def name(name)
47
- @errors << ["trigger name cannot exceed 63 for postgres", *HairTrigger::POSTGRESQL_ADAPTERS] if name.to_s.size > 63
47
+ @errors << ["trigger name cannot exceed 63 for postgres", *HairTrigger.hair_trigger_config.postgresql_adapters] if name.to_s.size > 63
48
48
  options[:name] = name.to_s
49
49
  end
50
50
 
@@ -54,7 +54,7 @@ module HairTrigger
54
54
  end
55
55
 
56
56
  def for_each(for_each)
57
- @errors << ["sqlite and mysql don't support FOR EACH STATEMENT triggers", *HairTrigger::SQLITE_ADAPTERS, *HairTrigger::MYSQL_ADAPTERS] if for_each == :statement
57
+ @errors << ["sqlite and mysql don't support FOR EACH STATEMENT triggers", *HairTrigger.hair_trigger_config.sqlite_adapters, *HairTrigger.hair_trigger_config.mysql_adapters] if for_each == :statement
58
58
  raise DeclarationError, "invalid for_each" unless [:row, :statement].include?(for_each)
59
59
  options[:for_each] = for_each.to_s.upcase
60
60
  end
@@ -107,9 +107,9 @@ module HairTrigger
107
107
  raise DeclarationError, "trigger security should be :invoker, :definer, CURRENT_USER, or a valid user (e.g. 'user'@'host')"
108
108
  end
109
109
  # sqlite default is n/a, mysql default is :definer, postgres default is :invoker
110
- @errors << ["sqlite doesn't support trigger security", *HairTrigger::SQLITE_ADAPTERS]
111
- @errors << ["postgresql doesn't support arbitrary users for trigger security", *HairTrigger::POSTGRESQL_ADAPTERS] unless [:definer, :invoker].include?(user)
112
- @errors << ["mysql doesn't support invoker trigger security", *HairTrigger::MYSQL_ADAPTERS] if user == :invoker
110
+ @errors << ["sqlite doesn't support trigger security", *HairTrigger.hair_trigger_config.sqlite_adapters]
111
+ @errors << ["postgresql doesn't support arbitrary users for trigger security", *HairTrigger.hair_trigger_config.postgresql_adapters] unless [:definer, :invoker].include?(user)
112
+ @errors << ["mysql doesn't support invoker trigger security", *HairTrigger.hair_trigger_config.mysql_adapters] if user == :invoker
113
113
  options[:security] = user
114
114
  end
115
115
 
@@ -122,8 +122,8 @@ module HairTrigger
122
122
  events << :insert if events.delete(:create)
123
123
  events << :delete if events.delete(:destroy)
124
124
  raise DeclarationError, "invalid events" unless events & [:insert, :update, :delete, :truncate] == events
125
- @errors << ["sqlite and mysql triggers may not be shared by multiple actions", *HairTrigger::MYSQL_ADAPTERS, *HairTrigger::SQLITE_ADAPTERS] if events.size > 1
126
- @errors << ["sqlite and mysql do not support truncate triggers", *HairTrigger::MYSQL_ADAPTERS, *HairTrigger::SQLITE_ADAPTERS] if events.include?(:truncate)
125
+ @errors << ["sqlite and mysql triggers may not be shared by multiple actions", *HairTrigger.hair_trigger_config.mysql_adapters, *HairTrigger.hair_trigger_config.sqlite_adapters] if events.size > 1
126
+ @errors << ["sqlite and mysql do not support truncate triggers", *HairTrigger.hair_trigger_config.mysql_adapters, *HairTrigger.hair_trigger_config.sqlite_adapters] if events.include?(:truncate)
127
127
  options[:events] = events.map{ |e| e.to_s.upcase }
128
128
  end
129
129
 
@@ -152,7 +152,7 @@ module HairTrigger
152
152
  def #{method}(*args, &block)
153
153
  @chained_calls << :#{method}
154
154
  if @triggers || @trigger_group
155
- @errors << ["mysql doesn't support #{method} within a trigger group", *HairTrigger::MYSQL_ADAPTERS] unless [:name, :where, :all, :of].include?(:#{method})
155
+ @errors << ["mysql doesn't support #{method} within a trigger group", *HairTrigger.hair_trigger_config.mysql_adapters] unless [:name, :where, :all, :of].include?(:#{method})
156
156
  end
157
157
  set_#{method}(*args, &(block_given? ? block : nil))
158
158
  end
@@ -174,7 +174,7 @@ module HairTrigger
174
174
  chainable_methods :name, :on, :for_each, :before, :after, :where, :security, :timing, :events, :all, :nowrap, :of, :declare, :old_as, :new_as
175
175
 
176
176
  def create_grouped_trigger?
177
- HairTrigger::MYSQL_ADAPTERS.include?(adapter_name)
177
+ HairTrigger.hair_trigger_config.mysql_adapters.include?(adapter_name)
178
178
  end
179
179
 
180
180
  def prepare!
@@ -234,11 +234,11 @@ module HairTrigger
234
234
 
235
235
  [generate_drop_trigger] +
236
236
  [case adapter_name
237
- when *HairTrigger::SQLITE_ADAPTERS
237
+ when *HairTrigger.hair_trigger_config.sqlite_adapters
238
238
  generate_trigger_sqlite
239
- when *HairTrigger::MYSQL_ADAPTERS
239
+ when *HairTrigger.hair_trigger_config.mysql_adapters
240
240
  generate_trigger_mysql
241
- when *HairTrigger::POSTGRESQL_ADAPTERS
241
+ when *HairTrigger.hair_trigger_config.postgresql_adapters
242
242
  generate_trigger_postgresql
243
243
  else
244
244
  raise GenerationError, "don't know how to build #{adapter_name} triggers yet"
@@ -345,8 +345,8 @@ module HairTrigger
345
345
  def maybe_execute(&block)
346
346
  raise DeclarationError, "of may only be specified on update triggers" if options[:of] && options[:events] != ["UPDATE"]
347
347
  if block.arity > 0 # we're creating a trigger group, so set up some stuff and pass the buck
348
- @errors << ["trigger group must specify timing and event(s) for mysql", *HairTrigger::MYSQL_ADAPTERS] unless options[:timing] && options[:events]
349
- @errors << ["nested trigger groups are not supported for mysql", *HairTrigger::MYSQL_ADAPTERS] if @trigger_group
348
+ @errors << ["trigger group must specify timing and event(s) for mysql", *HairTrigger.hair_trigger_config.mysql_adapters] unless options[:timing] && options[:events]
349
+ @errors << ["nested trigger groups are not supported for mysql", *HairTrigger.hair_trigger_config.mysql_adapters] if @trigger_group
350
350
  @triggers = []
351
351
  block.call(self)
352
352
  raise DeclarationError, "trigger group did not define any triggers" if @triggers.empty?
@@ -375,9 +375,9 @@ module HairTrigger
375
375
  subtriggers = all_triggers(false)
376
376
  named_subtriggers = subtriggers.select{ |t| t.options[:name] }
377
377
  if named_subtriggers.present? && !options[:name]
378
- @warnings << ["nested triggers have explicit names, but trigger group does not. trigger name will be inferred", *HairTrigger::MYSQL_ADAPTERS]
378
+ @warnings << ["nested triggers have explicit names, but trigger group does not. trigger name will be inferred", *HairTrigger.hair_trigger_config.mysql_adapters]
379
379
  elsif subtriggers.present? && !named_subtriggers.present? && options[:name]
380
- @warnings << ["trigger group has an explicit name, but nested triggers do not. trigger names will be inferred", *HairTrigger::POSTGRESQL_ADAPTERS, *HairTrigger::SQLITE_ADAPTERS]
380
+ @warnings << ["trigger group has an explicit name, but nested triggers do not. trigger names will be inferred", *HairTrigger.hair_trigger_config.postgresql_adapters, *HairTrigger.hair_trigger_config.sqlite_adapters]
381
381
  end
382
382
  end
383
383
 
@@ -412,9 +412,9 @@ module HairTrigger
412
412
 
413
413
  def supports_of?
414
414
  case adapter_name
415
- when *HairTrigger::SQLITE_ADAPTERS
415
+ when *HairTrigger.hair_trigger_config.sqlite_adapters
416
416
  true
417
- when *HairTrigger::POSTGRESQL_ADAPTERS
417
+ when *HairTrigger.hair_trigger_config.postgresql_adapters
418
418
  db_version >= 90000
419
419
  else
420
420
  false
@@ -429,9 +429,9 @@ module HairTrigger
429
429
 
430
430
  def supports_referencing?
431
431
  case adapter_name
432
- when *HairTrigger::SQLITE_ADAPTERS, *HairTrigger::MYSQL_ADAPTERS
432
+ when *HairTrigger.hair_trigger_config.sqlite_adapters, *HairTrigger.hair_trigger_config.mysql_adapters
433
433
  false
434
- when *HairTrigger::POSTGRESQL_ADAPTERS
434
+ when *HairTrigger.hair_trigger_config.postgresql_adapters
435
435
  db_version >= 100000
436
436
  else
437
437
  false
@@ -440,9 +440,9 @@ module HairTrigger
440
440
 
441
441
  def generate_drop_trigger
442
442
  case adapter_name
443
- when *HairTrigger::SQLITE_ADAPTERS, *HairTrigger::MYSQL_ADAPTERS
443
+ when *HairTrigger.hair_trigger_config.sqlite_adapters, *HairTrigger.hair_trigger_config.mysql_adapters
444
444
  "DROP TRIGGER IF EXISTS #{prepared_name};\n"
445
- when *HairTrigger::POSTGRESQL_ADAPTERS
445
+ when *HairTrigger.hair_trigger_config.postgresql_adapters
446
446
  "DROP TRIGGER IF EXISTS #{prepared_name} ON #{adapter.quote_table_name(options[:table])};\nDROP FUNCTION IF EXISTS #{adapter.quote_table_name(prepared_name)}();\n"
447
447
  else
448
448
  raise GenerationError, "don't know how to drop #{adapter_name} triggers yet"
@@ -532,7 +532,7 @@ BEGIN
532
532
 
533
533
  def db_version
534
534
  @db_version ||= case adapter_name
535
- when *HairTrigger::POSTGRESQL_ADAPTERS
535
+ when *HairTrigger.hair_trigger_config.postgresql_adapters
536
536
  adapter.send(:postgresql_version)
537
537
  end
538
538
  end
@@ -0,0 +1,11 @@
1
+ module HairTrigger
2
+ class Configuration
3
+ attr_accessor :postgresql_adapters, :mysql_adapters, :sqlite_adapters
4
+
5
+ def initialize(postgresql_adapters: [], mysql_adapters: [], sqlite_adapters: [])
6
+ @postgresql_adapters = postgresql_adapters
7
+ @mysql_adapters = mysql_adapters
8
+ @sqlite_adapters = sqlite_adapters
9
+ end
10
+ end
11
+ end
@@ -74,7 +74,7 @@ module HairTrigger
74
74
  def normalize_trigger(name, definition, type)
75
75
  @adapter_name = @connection.adapter_name.downcase.to_sym
76
76
 
77
- return definition unless HairTrigger::POSTGRESQL_ADAPTERS.include?(@adapter_name)
77
+ return definition unless HairTrigger.hair_trigger_config.postgresql_adapters.include?(@adapter_name)
78
78
  # because postgres does not preserve the original CREATE TRIGGER/
79
79
  # FUNCTION statements, its decompiled reconstruction will not match
80
80
  # ours. we work around it by creating our generated trigger/function,
@@ -1,5 +1,5 @@
1
1
  module HairTrigger
2
- VERSION = "1.3.0"
2
+ VERSION = "1.3.1"
3
3
 
4
4
  def VERSION.<=>(other)
5
5
  split(/\./).map(&:to_i) <=> other.split(/\./).map(&:to_i)
data/lib/hair_trigger.rb CHANGED
@@ -12,12 +12,25 @@ module HairTrigger
12
12
  MYSQL_ADAPTERS = %i[mysql mysql2rgeo trilogy]
13
13
  SQLITE_ADAPTERS = %i[sqlite litedb]
14
14
 
15
+ autoload :Configuration, 'hair_trigger/configuration'
15
16
  autoload :Builder, 'hair_trigger/builder'
16
17
  autoload :MigrationReader, 'hair_trigger/migration_reader'
17
18
 
18
19
  class << self
19
20
  attr_writer :model_path, :schema_rb_path, :migration_path, :pg_schema
20
21
 
22
+ def configure
23
+ yield hair_trigger_config
24
+ end
25
+
26
+ def hair_trigger_config
27
+ @hair_trigger_config ||= Configuration.new(
28
+ postgresql_adapters: POSTGRESQL_ADAPTERS,
29
+ mysql_adapters: MYSQL_ADAPTERS,
30
+ sqlite_adapters: SQLITE_ADAPTERS
31
+ )
32
+ end
33
+
21
34
  def current_triggers
22
35
  # see what the models say there should be
23
36
  canonical_triggers = models.map(&:triggers).flatten.compact
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: hairtrigger
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.0
4
+ version: 1.3.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Jon Jensen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2024-11-25 00:00:00.000000000 Z
11
+ date: 2025-03-31 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -72,6 +72,7 @@ files:
72
72
  - lib/hair_trigger/adapter.rb
73
73
  - lib/hair_trigger/base.rb
74
74
  - lib/hair_trigger/builder.rb
75
+ - lib/hair_trigger/configuration.rb
75
76
  - lib/hair_trigger/migration_reader.rb
76
77
  - lib/hair_trigger/migrator.rb
77
78
  - lib/hair_trigger/railtie.rb