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 +4 -4
- data/README.md +7 -0
- data/lib/hair_trigger/adapter.rb +3 -3
- data/lib/hair_trigger/builder.rb +23 -23
- data/lib/hair_trigger/configuration.rb +11 -0
- data/lib/hair_trigger/schema_dumper.rb +1 -1
- data/lib/hair_trigger/version.rb +1 -1
- data/lib/hair_trigger.rb +13 -0
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 00e0ef28f55f9f28dddc16dadc2acfadbefa3007eacc294591fc8a2047f547ed
|
4
|
+
data.tar.gz: 7c1aef527b1343d68651bddc00a4cd1b9012b78a4c9a81c0fd333be8f2adb72d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
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,
|
data/lib/hair_trigger/adapter.rb
CHANGED
@@ -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
|
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
|
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 *
|
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 (
|
data/lib/hair_trigger/builder.rb
CHANGED
@@ -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
|
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
|
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
|
111
|
-
@errors << ["postgresql doesn't support arbitrary users for trigger security", *HairTrigger
|
112
|
-
@errors << ["mysql doesn't support invoker trigger security", *HairTrigger
|
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
|
126
|
-
@errors << ["sqlite and mysql do not support truncate triggers", *HairTrigger
|
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
|
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
|
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
|
237
|
+
when *HairTrigger.hair_trigger_config.sqlite_adapters
|
238
238
|
generate_trigger_sqlite
|
239
|
-
when *HairTrigger
|
239
|
+
when *HairTrigger.hair_trigger_config.mysql_adapters
|
240
240
|
generate_trigger_mysql
|
241
|
-
when *HairTrigger
|
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
|
349
|
-
@errors << ["nested trigger groups are not supported for mysql", *HairTrigger
|
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
|
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
|
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
|
415
|
+
when *HairTrigger.hair_trigger_config.sqlite_adapters
|
416
416
|
true
|
417
|
-
when *HairTrigger
|
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
|
432
|
+
when *HairTrigger.hair_trigger_config.sqlite_adapters, *HairTrigger.hair_trigger_config.mysql_adapters
|
433
433
|
false
|
434
|
-
when *HairTrigger
|
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
|
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
|
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
|
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
|
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,
|
data/lib/hair_trigger/version.rb
CHANGED
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.
|
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:
|
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
|