hairtrigger 0.2.12 → 0.2.13
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.
- data/LICENSE.txt +1 -1
- data/README.md +1 -1
- data/lib/hair_trigger.rb +22 -8
- data/lib/hair_trigger/adapter.rb +23 -4
- data/lib/hair_trigger/builder.rb +3 -3
- data/lib/hair_trigger/version.rb +1 -1
- data/spec/adapter_spec.rb +48 -0
- metadata +3 -3
data/LICENSE.txt
CHANGED
data/README.md
CHANGED
data/lib/hair_trigger.rb
CHANGED
@@ -157,21 +157,35 @@ end
|
|
157
157
|
end
|
158
158
|
|
159
159
|
def infer_migration_name(migration_names, create_triggers, drop_triggers)
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
160
|
+
if create_triggers.size > 0
|
161
|
+
migration_base_name = "create trigger#{create_triggers.size > 1 ? 's' : ''} "
|
162
|
+
name_parts = create_triggers.map { |t| [t.options[:table], t.options[:events].join(" ")].join(" ") }.uniq
|
163
|
+
part_limit = 4
|
164
164
|
else
|
165
|
-
|
166
|
-
|
167
|
-
|
165
|
+
migration_base_name = "drop trigger#{drop_triggers.size > 1 ? 's' : ''} "
|
166
|
+
name_parts = drop_triggers.map { |t| t.options[:table] }
|
167
|
+
part_limit = 6
|
168
168
|
end
|
169
169
|
|
170
|
+
# don't let migration names get too ridiculous
|
171
|
+
if name_parts.size > part_limit
|
172
|
+
migration_base_name << " multiple tables"
|
173
|
+
else
|
174
|
+
migration_base_name << name_parts.join(" OR ")
|
175
|
+
end
|
176
|
+
|
177
|
+
migration_base_name = migration_base_name.
|
178
|
+
downcase.
|
179
|
+
gsub(/[^a-z0-9_]/, '_').
|
180
|
+
gsub(/_+/, '_').
|
181
|
+
camelize
|
182
|
+
|
170
183
|
name_version = nil
|
171
184
|
while migration_names.include?("#{migration_base_name}#{name_version}")
|
172
185
|
name_version = name_version.to_i + 1
|
173
186
|
end
|
174
|
-
|
187
|
+
|
188
|
+
"#{migration_base_name}#{name_version}"
|
175
189
|
end
|
176
190
|
|
177
191
|
def infer_migration_version(migration_name)
|
data/lib/hair_trigger/adapter.rb
CHANGED
@@ -29,14 +29,14 @@ module HairTrigger
|
|
29
29
|
case adapter_name
|
30
30
|
when :sqlite
|
31
31
|
select_rows("SELECT name, sql FROM sqlite_master WHERE type = 'trigger' #{name_clause ? " AND name " + name_clause : ""}").each do |(name, definition)|
|
32
|
-
triggers[name] = definition + ";\n"
|
32
|
+
triggers[name] = quote_table_name_in_trigger(definition) + ";\n"
|
33
33
|
end
|
34
34
|
when :mysql
|
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)
|
38
38
|
triggers[name.strip] = <<-SQL
|
39
|
-
CREATE #{definer != implicit_mysql_definer ? "DEFINER = #{definer} " : ""}TRIGGER #{name} #{timing} #{event} ON
|
39
|
+
CREATE #{definer != implicit_mysql_definer ? "DEFINER = #{definer} " : ""}TRIGGER #{name} #{timing} #{event} ON `#{table}`
|
40
40
|
FOR EACH ROW
|
41
41
|
#{actions}
|
42
42
|
SQL
|
@@ -52,7 +52,7 @@ FOR EACH ROW
|
|
52
52
|
)
|
53
53
|
)
|
54
54
|
SQL
|
55
|
-
|
55
|
+
|
56
56
|
sql = <<-SQL
|
57
57
|
SELECT tgname::varchar, pg_get_triggerdef(oid, true)
|
58
58
|
FROM pg_trigger
|
@@ -68,12 +68,31 @@ FOR EACH ROW
|
|
68
68
|
#{name_clause ? " AND (proname || '()')::varchar " + name_clause : ""}
|
69
69
|
SQL
|
70
70
|
select_rows(sql).each do |(name, definition)|
|
71
|
-
triggers[name] = definition
|
71
|
+
triggers[name] = quote_table_name_in_trigger(definition)
|
72
72
|
end
|
73
73
|
else
|
74
74
|
raise "don't know how to retrieve #{adapter_name} triggers yet"
|
75
75
|
end
|
76
76
|
triggers
|
77
77
|
end
|
78
|
+
|
79
|
+
# a bit hacky, but we need to ensure the table name is always quoted
|
80
|
+
# on the way out, not just for reserved words. this is because we
|
81
|
+
# always quote on the way in, so we need them to match exactly
|
82
|
+
# when diffing
|
83
|
+
def quote_table_name_in_trigger(definition)
|
84
|
+
pattern = /
|
85
|
+
(
|
86
|
+
CREATE\sTRIGGER\s+
|
87
|
+
\S+\s+
|
88
|
+
(BEFORE|AFTER|INSTEAD\s+OF)\s+
|
89
|
+
(INSERT|UPDATE|DELETE|TRUNCATE)\s+
|
90
|
+
(OR\s+(INSERT|UPDATE|DELETE|TRUNCATE)\s+)*
|
91
|
+
(ON\s+)
|
92
|
+
)
|
93
|
+
(\w+) # quote if not already quoted
|
94
|
+
/ixm
|
95
|
+
definition.sub(pattern, '\\1"\\7"')
|
96
|
+
end
|
78
97
|
end
|
79
98
|
end
|
data/lib/hair_trigger/builder.rb
CHANGED
@@ -411,7 +411,7 @@ module HairTrigger
|
|
411
411
|
|
412
412
|
def generate_trigger_sqlite
|
413
413
|
<<-SQL
|
414
|
-
CREATE TRIGGER #{prepared_name} #{options[:timing]} #{options[:events].first} #{of_clause}ON #{options[:table]}
|
414
|
+
CREATE TRIGGER #{prepared_name} #{options[:timing]} #{options[:events].first} #{of_clause}ON "#{options[:table]}"
|
415
415
|
FOR EACH #{options[:for_each]}#{prepared_where ? " WHEN " + prepared_where : ''}
|
416
416
|
BEGIN
|
417
417
|
#{normalize(raw_actions, 1).rstrip}
|
@@ -464,7 +464,7 @@ $$ LANGUAGE plpgsql#{security ? " SECURITY #{security.to_s.upcase}" : ""};
|
|
464
464
|
end
|
465
465
|
|
466
466
|
[sql, <<-SQL]
|
467
|
-
CREATE TRIGGER #{prepared_name} #{options[:timing]} #{options[:events].join(" OR ")} #{of_clause}ON #{options[:table]}
|
467
|
+
CREATE TRIGGER #{prepared_name} #{options[:timing]} #{options[:events].join(" OR ")} #{of_clause}ON "#{options[:table]}"
|
468
468
|
FOR EACH #{options[:for_each]}#{prepared_where && db_version >= 90000 ? " WHEN (" + prepared_where + ')': ''} EXECUTE PROCEDURE #{trigger_action};
|
469
469
|
SQL
|
470
470
|
end
|
@@ -472,7 +472,7 @@ FOR EACH #{options[:for_each]}#{prepared_where && db_version >= 90000 ? " WHEN (
|
|
472
472
|
def generate_trigger_mysql
|
473
473
|
security = options[:security] if options[:security] && options[:security] != :definer
|
474
474
|
sql = <<-SQL
|
475
|
-
CREATE #{security ? "DEFINER = #{security} " : ""}TRIGGER #{prepared_name} #{options[:timing]} #{options[:events].first} ON
|
475
|
+
CREATE #{security ? "DEFINER = #{security} " : ""}TRIGGER #{prepared_name} #{options[:timing]} #{options[:events].first} ON `#{options[:table]}`
|
476
476
|
FOR EACH #{options[:for_each]}
|
477
477
|
BEGIN
|
478
478
|
SQL
|
data/lib/hair_trigger/version.rb
CHANGED
data/spec/adapter_spec.rb
CHANGED
@@ -31,6 +31,18 @@ describe "adapter" do
|
|
31
31
|
|
32
32
|
expect(db_triggers).to eq(triggers)
|
33
33
|
end
|
34
|
+
|
35
|
+
it "quotes table names" do
|
36
|
+
conn.execute <<-SQL
|
37
|
+
CREATE TRIGGER foos_tr AFTER DELETE ON users
|
38
|
+
FOR EACH ROW
|
39
|
+
BEGIN
|
40
|
+
UPDATE groups SET bob_count = bob_count - 1;
|
41
|
+
END
|
42
|
+
SQL
|
43
|
+
|
44
|
+
expect(conn.triggers["foos_tr"]).to match(/CREATE TRIGGER foos_tr AFTER DELETE ON `users`/)
|
45
|
+
end
|
34
46
|
end
|
35
47
|
|
36
48
|
context "mysql" do
|
@@ -42,6 +54,42 @@ describe "adapter" do
|
|
42
54
|
let(:adapter) { :mysql2 }
|
43
55
|
it_behaves_like "mysql"
|
44
56
|
end
|
57
|
+
|
58
|
+
context "postgresql" do
|
59
|
+
let(:adapter) { :postgresql }
|
60
|
+
|
61
|
+
it "quotes table names" do
|
62
|
+
conn.execute <<-SQL
|
63
|
+
CREATE FUNCTION foos_tr()
|
64
|
+
RETURNS TRIGGER AS $$
|
65
|
+
BEGIN
|
66
|
+
UPDATE groups SET bob_count = bob_count - 1;
|
67
|
+
END;
|
68
|
+
$$ LANGUAGE plpgsql;
|
69
|
+
|
70
|
+
CREATE TRIGGER foos_tr AFTER DELETE ON users
|
71
|
+
FOR EACH ROW EXECUTE PROCEDURE foos_tr();
|
72
|
+
SQL
|
73
|
+
|
74
|
+
expect(conn.triggers["foos_tr"]).to match(/CREATE TRIGGER foos_tr AFTER DELETE ON "users"/)
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
context "sqlite3" do
|
79
|
+
let(:adapter) { :sqlite3 }
|
80
|
+
|
81
|
+
it "quotes table names" do
|
82
|
+
conn.execute <<-SQL
|
83
|
+
CREATE TRIGGER foos_tr AFTER DELETE ON users
|
84
|
+
FOR EACH ROW
|
85
|
+
BEGIN
|
86
|
+
UPDATE groups SET bob_count = bob_count - 1;
|
87
|
+
END;
|
88
|
+
SQL
|
89
|
+
|
90
|
+
expect(conn.triggers["foos_tr"]).to match(/CREATE TRIGGER foos_tr AFTER DELETE ON "users"/)
|
91
|
+
end
|
92
|
+
end
|
45
93
|
end
|
46
94
|
end
|
47
95
|
|
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: hairtrigger
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.2.
|
4
|
+
version: 0.2.13
|
5
5
|
prerelease:
|
6
6
|
platform: ruby
|
7
7
|
authors:
|
@@ -9,7 +9,7 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2015-04-28 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: activerecord
|
@@ -114,7 +114,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
114
114
|
version: 1.3.5
|
115
115
|
requirements: []
|
116
116
|
rubyforge_project:
|
117
|
-
rubygems_version: 1.8.23
|
117
|
+
rubygems_version: 1.8.23.2
|
118
118
|
signing_key:
|
119
119
|
specification_version: 3
|
120
120
|
summary: easy database triggers for active record
|