hairtrigger 0.2.4 → 0.2.5

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,290 @@
1
+ # HairTrigger
2
+ [<img src="https://secure.travis-ci.org/jenseng/hair_trigger.png?branch=master" />](http://travis-ci.org/jenseng/hair_trigger)
3
+
4
+ HairTrigger lets you create and manage database triggers in a concise,
5
+ db-agnostic, Rails-y way. You declare triggers right in your models in Ruby,
6
+ and a simple rake task does all the dirty work for you.
7
+
8
+ ## Installation
9
+
10
+ ### Rails 3 or 4
11
+
12
+ If you are using Rails 3 or 4, just `gem 'hairtrigger'`
13
+
14
+ ### Rails 2
15
+
16
+ #### Step 1.
17
+
18
+ Put hairtrigger in your Gemfile, or if you're not using bundler, you can
19
+ `gem install hairtrigger` and then put hairtrigger in environment.rb
20
+
21
+ #### Step 2.
22
+
23
+ Create lib/tasks/hair_trigger.rake with the following:
24
+
25
+ ```ruby
26
+ $VERBOSE = nil
27
+ Dir["#{Gem::Specification.find_by_name('hairtrigger').full_gem_path}/lib/tasks/*.rake"].each { |ext| load ext }
28
+ ```
29
+
30
+ This will give you the `db:generate_trigger_migration` task, and will ensure
31
+ that hairtrigger hooks into `db:schema:dump`.
32
+
33
+ If you are unpacking the gem in vendor/plugins, this step is not needed
34
+ (though you'll then want to delete its Gemfile to avoid possible conflicts).
35
+
36
+ ## Usage
37
+
38
+ ### Models
39
+
40
+ Declare triggers in your models and use a rake task to auto-generate the
41
+ appropriate migration. For example:
42
+
43
+ ```ruby
44
+ class AccountUser < ActiveRecord::Base
45
+ trigger.after(:insert) do
46
+ "UPDATE accounts SET user_count = user_count + 1 WHERE id = NEW.account_id;"
47
+ end
48
+ end
49
+ ```
50
+
51
+ and then:
52
+
53
+ ```bash
54
+ rake db:generate_trigger_migration
55
+ ```
56
+
57
+ This will create a db-agnostic migration for the trigger that mirrors the
58
+ model declaration. The end result in MySQL will be something like this:
59
+
60
+ ```sql
61
+ CREATE TRIGGER account_users_after_insert_row_tr AFTER INSERT ON account_users
62
+ FOR EACH ROW
63
+ BEGIN
64
+ UPDATE accounts SET user_count = user_count + 1 WHERE id = NEW.account_id;
65
+ END
66
+ ```
67
+
68
+ Note that these auto-generated `create_trigger` statements in the migration
69
+ contain the `:generated => true` option, indicating that they were created
70
+ from the model definition. This is important, as the rake task will also
71
+ generate appropriate drop/create statements for any model triggers that get
72
+ removed or updated. It does this by diffing the current model trigger
73
+ declarations and any auto-generated triggers in schema.rb (and subsequent
74
+ migrations).
75
+
76
+ ### Chainable Methods
77
+
78
+ Triggers are built by chaining several methods together, ending in a block
79
+ that specifies the SQL to be run when the trigger fires. Supported methods
80
+ include:
81
+
82
+ #### name(trigger_name)
83
+ Optional, inferred from other calls.
84
+
85
+ #### on(table_name)
86
+ Ignored in models, required in migrations.
87
+
88
+ #### for_each(item)
89
+ Defaults to `:row`, PostgreSQL allows `:statement`.
90
+
91
+ #### before(*events)
92
+ Shorthand for `timing(:before).events(*events)`.
93
+
94
+ #### after(*events)
95
+ Shorthand for `timing(:after).events(*events)`.
96
+
97
+ #### where(conditions)
98
+ Optional, SQL snippet limiting when the trigger will fire. Supports delayed interpolation of variables.
99
+
100
+ #### security(user)
101
+ Permissions/role to check when calling trigger. PostgreSQL supports `:invoker` (default) and `:definer`, MySQL supports `:definer` (default) and arbitrary users (syntax: `'user'@'host'`).
102
+
103
+ #### timing(timing)
104
+ Required (but may be satisified by `before`/`after`). Possible values are `:before`/`:after`.
105
+
106
+ #### events(*events)
107
+ Required (but may be satisified by `before`/`after`). Possible values are `:insert`/`:update`/`:delete`/`:truncate`. MySQL/SQLite only support one action per trigger, and don't support `:truncate`.
108
+
109
+ #### all
110
+ Noop, useful for trigger groups (see below).
111
+
112
+ ### Trigger Groups
113
+
114
+ Trigger groups allow you to use a slightly more concise notation if you have
115
+ several triggers that fire on a given model. This is also important for MySQL,
116
+ since it does not support multiple triggers on a table for the same action
117
+ and timing. For example:
118
+
119
+ ```ruby
120
+ trigger.after(:update) do |t|
121
+ t.all do # every row
122
+ # some sql
123
+ end
124
+ t.where("OLD.foo != NEW.foo") do
125
+ # some more sql
126
+ end
127
+ t.where("OLD.bar != NEW.bar") do
128
+ # some other sql
129
+ end
130
+ end
131
+ ```
132
+
133
+ For MySQL, this will just create a single trigger with conditional logic
134
+ (since it doesn't support multiple triggers). PostgreSQL and SQLite will have
135
+ distinct triggers. This same notation is also used within trigger migrations.
136
+ MySQL does not currently support nested trigger groups.
137
+
138
+ ### Database-specific trigger bodies
139
+
140
+ Although HairTrigger aims to be totally db-agnostic, at times you do need a
141
+ little more control over the body of the trigger. You can tailor it for
142
+ specific databases by returning a hash rather than a string. Make sure to set
143
+ a `:default` value if you aren't explicitly specifying all of them.
144
+
145
+ For example, MySQL generally performs poorly with subselects in `UPDATE`
146
+ statements, and it has its own proprietary syntax for multi-table `UPDATE`s. So
147
+ you might do something like the following:
148
+
149
+ ```ruby
150
+ trigger.after(:insert) do
151
+ {:default => <<-DEFAULT_SQL, :mysql => <<-MYSQL}
152
+
153
+ UPDATE users SET item_count = item_count + 1
154
+ WHERE id IN (SELECT user_id FROM buckets WHERE id = NEW.bucket_id)
155
+ DEFAULT_SQL
156
+
157
+ UPDATE users, buckets SET item_count = item_count + 1
158
+ WHERE users.id = user_id AND buckets.id = NEW.bucket_id
159
+ MYSQL
160
+ end
161
+ ```
162
+
163
+ ### Manual Migrations
164
+
165
+ You can also manage triggers manually in your migrations via `create_trigger` and
166
+ `drop_trigger`. They are a little more verbose than model triggers, and they can
167
+ be more work since you need to figure out the up/down create/drop logic when
168
+ you change things. A sample trigger:
169
+
170
+ ```ruby
171
+ create_trigger(:compatibility => 1).on(:users).after(:insert) do
172
+ "UPDATE accounts SET user_count = user_count + 1 WHERE id = NEW.account_id;"
173
+ end
174
+ ```
175
+
176
+ #### Manual triggers and :compatibility
177
+
178
+ As bugs are fixed and features are implemented in hairtrigger, it's possible
179
+ that the generated trigger SQL will change (this has only happened once so
180
+ far). If you upgrade to a newer version of hairtrigger, it needs a way of
181
+ knowing which previous version generated the original trigger. You only need
182
+ to worry about this for manual trigger migrations, as the model ones
183
+ automatically take care of this. For your manual triggers you can either:
184
+
185
+ * pass `:compatibility => x` to your `create_trigger` statement, where x is
186
+ whatever HairTrigger::Builder.compatiblity is (1 for this version).
187
+ * set `HairTrigger::Builder.base_compatibility = x` in an initializer, where
188
+ x is whatever HairTrigger::Builder.compatiblity is. This is like doing the
189
+ first option on every `create_trigger`. Note that once the compatibility
190
+ changes, you'll need to set `:compatibility` on new triggers (unless you
191
+ just redo all your triggers and bump the `base_compatibility`).
192
+
193
+ If you upgrade to a newer version of hairtrigger and see that the SQL
194
+ compatibility has changed, you'll need to set the appropriate compatibility
195
+ on any new triggers that you create.
196
+
197
+ ## rake db:schema:dump
198
+
199
+ HairTrigger hooks into `rake db:schema:dump` (and rake tasks that call it) to
200
+ make it trigger-aware. A newly generated schema.rb will contain:
201
+
202
+ * `create_trigger` statements for any database triggers that exactly match a
203
+ `create_trigger` statement in an applied migration or in the previous
204
+ schema.rb file. this includes both generated and manual `create_trigger`
205
+ calls.
206
+ * adapter-specific `execute('CREATE TRIGGER..')` statements for any unmatched
207
+ database triggers.
208
+
209
+ As long as you don't delete old migrations and schema.rb prior to running
210
+ `rake db:schema:dump`, the result should be what you expect (and portable).
211
+ If you have deleted all trigger migrations, you can regenerate a new
212
+ baseline for model triggers via rake db:generate_trigger_migration.
213
+
214
+ ## Testing
215
+
216
+ To stay on top of things, it's strongly recommended that you add a test or
217
+ spec to ensure your migrations/schema.rb match your models. This is as simple
218
+ as:
219
+
220
+ ```ruby
221
+ assert HairTrigger::migrations_current?
222
+ ```
223
+
224
+ This way you'll know if there are any outstanding migrations you need to
225
+ create.
226
+
227
+ ## Warnings and Errors
228
+
229
+ There are a couple classes of errors: declaration errors and generation
230
+ errors/warnings.
231
+
232
+ Declaration errors happen if your trigger declaration is obviously wrong, and
233
+ will cause a runtime error in your model or migration class. An example would
234
+ be `trigger.after(:never)`, since `:never` is not a valid event.
235
+
236
+ Generation errors happen if you try something that your adapter doesn't
237
+ support. An example would be something like `trigger.security(:invoker)` for
238
+ MySQL. These errors only happen when the trigger is actually generated, e.g.
239
+ when you attempt to run the migration.
240
+
241
+ Generation warnings are similar but they don't stop the trigger from being
242
+ generated. If you do something adapter-specific supported by your database,
243
+ you will still get a warning ($stderr) that your trigger is not portable. You
244
+ can silence warnings via `HairTrigger::Builder.show_warnings = false`
245
+
246
+ You can validate your triggers beforehand using the `Builder#validate!` method.
247
+ It will throw the appropriate errors/warnings so that you know what to fix,
248
+ e.g.
249
+
250
+ ```ruby
251
+ User.triggers.each(&:validate!)
252
+ ```
253
+
254
+ HairTrigger does not validate your SQL, so be sure to test it in all databases
255
+ you want to support.
256
+
257
+ ## Gotchas
258
+
259
+ * As is the case with ActiveRecord::Base.update_all or any direct SQL you do,
260
+ be careful to reload updated objects from the database. For example, the
261
+ following code will display the wrong count since we aren't reloading the
262
+ account:
263
+
264
+ ```ruby
265
+ a = Account.find(123)
266
+ a.account_users.create(:name => 'bob')
267
+ puts "count is now #{a.user_count}"
268
+ ```
269
+ * For repeated chained calls, the last one wins, there is currently no
270
+ merging.
271
+ * If you want your code to be portable, the trigger actions should be
272
+ limited to `INSERT`/`UPDATE`/`DELETE`/`SELECT`, and conditional logic should be
273
+ handled through the `:where` option/method. Otherwise you'll likely run into
274
+ trouble due to differences in syntax and supported features.
275
+ * Manual `create_trigger` statements have some gotchas. See the section
276
+ "Manual triggers and :compatibility"
277
+
278
+ ## Compatibility
279
+
280
+ * Ruby 1.8.7+
281
+ * Rails 2.3+
282
+ * Postgres 8.0+
283
+ * MySQL 5.0.10+
284
+ * SQLite 3.3.8+
285
+
286
+ ## [Changelog](blob/master/CHANGELOG.md)
287
+
288
+ ## Copyright
289
+
290
+ Copyright (c) 2011-2014 Jon Jensen. See LICENSE.txt for further details.
@@ -1,5 +1,5 @@
1
1
  module HairTrigger
2
- VERSION = "0.2.4"
2
+ VERSION = "0.2.5"
3
3
 
4
4
  def VERSION.<=>(other)
5
5
  split(/\./).map(&:to_i) <=> other.split(/\./).map(&:to_i)
data/spec/builder_spec.rb CHANGED
@@ -14,8 +14,8 @@ class MockAdapter
14
14
  end
15
15
  end
16
16
 
17
- def builder
18
- HairTrigger::Builder.new(nil, :adapter => @adapter)
17
+ def builder(name = nil)
18
+ HairTrigger::Builder.new(name, :adapter => @adapter)
19
19
  end
20
20
 
21
21
  describe "builder" do
@@ -48,6 +48,20 @@ describe "builder" do
48
48
  end
49
49
  end
50
50
 
51
+ describe "name" do
52
+ it "should be inferred if none is provided" do
53
+ builder.on(:foos).after(:update){ "foo" }.prepared_name.
54
+ should == "foos_after_update_row_tr"
55
+ end
56
+
57
+ it "should respect the last chained name" do
58
+ builder("lolwut").on(:foos).after(:update){ "foo" }.prepared_name.
59
+ should == "lolwut"
60
+ builder("lolwut").on(:foos).name("zomg").after(:update).name("yolo"){ "foo" }.prepared_name.
61
+ should == "yolo"
62
+ end
63
+ end
64
+
51
65
  context "adapter-specific actions" do
52
66
  before(:each) do
53
67
  @adapter = MockAdapter.new("mysql")
@@ -263,4 +277,4 @@ describe "builder" do
263
277
  }.should raise_error
264
278
  end
265
279
  end
266
- end
280
+ end
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
4
+ version: 0.2.5
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: 2013-07-12 00:00:00.000000000 Z
12
+ date: 2014-03-13 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: activerecord
@@ -34,7 +34,7 @@ dependencies:
34
34
  requirements:
35
35
  - - ~>
36
36
  - !ruby/object:Gem::Version
37
- version: 3.2.2
37
+ version: '3.4'
38
38
  type: :runtime
39
39
  prerelease: false
40
40
  version_requirements: !ruby/object:Gem::Requirement
@@ -42,7 +42,7 @@ dependencies:
42
42
  requirements:
43
43
  - - ~>
44
44
  - !ruby/object:Gem::Version
45
- version: 3.2.2
45
+ version: '3.4'
46
46
  - !ruby/object:Gem::Dependency
47
47
  name: ruby2ruby
48
48
  requirement: !ruby/object:Gem::Requirement
@@ -160,12 +160,11 @@ description: allows you to declare database triggers in ruby in your models, and
160
160
  email: jenseng@gmail.com
161
161
  executables: []
162
162
  extensions: []
163
- extra_rdoc_files:
164
- - README.rdoc
163
+ extra_rdoc_files: []
165
164
  files:
166
165
  - LICENSE.txt
167
166
  - Rakefile
168
- - README.rdoc
167
+ - README.md
169
168
  - lib/hair_trigger/adapter.rb
170
169
  - lib/hair_trigger/base.rb
171
170
  - lib/hair_trigger/builder.rb
@@ -208,7 +207,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
208
207
  version: 1.3.5
209
208
  requirements: []
210
209
  rubyforge_project:
211
- rubygems_version: 1.8.25
210
+ rubygems_version: 1.8.23
212
211
  signing_key:
213
212
  specification_version: 3
214
213
  summary: easy database triggers for active record
data/README.rdoc DELETED
@@ -1,289 +0,0 @@
1
- = HairTrigger
2
- {<img src="https://secure.travis-ci.org/jenseng/hair_trigger.png?branch=master" />}[http://travis-ci.org/jenseng/hair_trigger]
3
-
4
- HairTrigger lets you create and manage database triggers in a concise,
5
- db-agnostic, Rails-y way. You declare triggers right in your models in Ruby,
6
- and a simple rake task does all the dirty work for you.
7
-
8
- == Installation
9
-
10
- === Rails 3 or 4
11
-
12
- If you are using Rails 3 or 4, just put hairtrigger in your Gemfile.
13
-
14
- === Rails 2
15
-
16
- ==== Step 1.
17
-
18
- Put hairtrigger in your Gemfile, or if you're not using bundler, you can
19
- "gem install hairtrigger" and then put hairtrigger in environment.rb
20
-
21
- ==== Step 2.
22
-
23
- Create lib/tasks/hair_trigger.rake with the following:
24
-
25
- $VERBOSE = nil
26
- Dir["#{Gem::Specification.find_by_name('hairtrigger').full_gem_path}/lib/tasks/*.rake"].each { |ext| load ext }
27
-
28
- This will give you the db:generate_trigger_migration task, and will ensure
29
- that hairtrigger hooks into db:schema:dump.
30
-
31
- If you are unpacking the gem in vendor/plugins, this step is not needed
32
- (though you'll then want to delete its Gemfile to avoid possible conflicts).
33
-
34
- == Usage
35
-
36
- === Models
37
-
38
- Declare triggers in your models and use a rake task to auto-generate the
39
- appropriate migration. For example:
40
-
41
- class AccountUser < ActiveRecord::Base
42
- trigger.after(:insert) do
43
- "UPDATE accounts SET user_count = user_count + 1 WHERE id = NEW.account_id;"
44
- end
45
- end
46
-
47
- and then:
48
-
49
- rake db:generate_trigger_migration
50
-
51
- This will create a db-agnostic migration for the trigger that mirrors the
52
- model declaration. The end result in MySQL will be something like this:
53
-
54
- CREATE TRIGGER account_users_after_insert_row_tr AFTER INSERT ON account_users
55
- FOR EACH ROW
56
- BEGIN
57
- UPDATE accounts SET user_count = user_count + 1 WHERE id = NEW.account_id;
58
- END
59
-
60
- Note that these auto-generated create_trigger statements in the migration
61
- contain the ":generated => true" option, indicating that they were created
62
- from the model definition. This is important, as the rake task will also
63
- generate appropriate drop/create statements for any model triggers that get
64
- removed or updated. It does this by diffing the current model trigger
65
- declarations and any auto-generated triggers in schema.rb (and subsequent
66
- migrations).
67
-
68
- === Chainable Methods
69
-
70
- Triggers are built by chaining several methods together, ending in a block
71
- that specifies the SQL to be run when the trigger fires. Supported methods
72
- include:
73
-
74
- ==== name(trigger_name)
75
- Optional, inferred from other calls.
76
-
77
- ==== on(table_name)
78
- Ignored in models, required in migrations.
79
-
80
- ==== for_each(item)
81
- Defaults to :row, PostgreSQL allows :statement.
82
-
83
- ==== before(*events)
84
- Shorthand for timing(:before).events(*events).
85
-
86
- ==== after(*events)
87
- Shorthand for timing(:after).events(*events).
88
-
89
- ==== where(conditions)
90
- Optional, SQL snippet limiting when the trigger will fire. Supports delayed interpolation of variables.
91
-
92
- ==== security(user)
93
- Permissions/role to check when calling trigger. PostgreSQL supports :invoker (default) and :definer, MySQL supports :definer (default) and arbitrary users (syntax: 'user'@'host').
94
-
95
- ==== timing(timing)
96
- Required (but may be satisified by before/after). Possible values are :before/:after.
97
-
98
- ==== events(*events)
99
- Required (but may be satisified by before/after). Possible values are :insert/:update/:delete/:truncate. MySQL/SQLite only support one action per trigger, and don't support :truncate.
100
-
101
- ==== all
102
- Noop, useful for trigger groups (see below).
103
-
104
- === Trigger Groups
105
-
106
- Trigger groups allow you to use a slightly more concise notation if you have
107
- several triggers that fire on a given model. This is also important for MySQL,
108
- since it does not support multiple triggers on a table for the same action
109
- and timing. For example:
110
-
111
- trigger.after(:update) do |t|
112
- t.all do # every row
113
- # some sql
114
- end
115
- t.where("OLD.foo != NEW.foo") do
116
- # some more sql
117
- end
118
- t.where("OLD.bar != NEW.bar") do
119
- # some other sql
120
- end
121
- end
122
-
123
- For MySQL, this will just create a single trigger with conditional logic
124
- (since it doesn't support multiple triggers). PostgreSQL and SQLite will have
125
- distinct triggers. This same notation is also used within trigger migrations.
126
- MySQL does not currently support nested trigger groups.
127
-
128
- === Database-specific trigger bodies
129
-
130
- Although HairTrigger aims to be totally db-agnostic, at times you do need a
131
- little more control over the body of the trigger. You can tailor it for
132
- specific databases by returning a hash rather than a string. Make sure to set
133
- a :default value if you aren't explicitly specifying all of them.
134
-
135
- For example, MySQL generally performs poorly with subselects in UPDATE
136
- statements, and it has its own proprietary syntax for multi-table UPDATEs. So
137
- you might do something like the following:
138
-
139
- trigger.after(:insert) do
140
- {:default => <<-DEFAULT_SQL, :mysql => <<-MYSQL}
141
-
142
- UPDATE users SET item_count = item_count + 1
143
- WHERE id IN (SELECT user_id FROM buckets WHERE id = NEW.bucket_id)
144
- DEFAULT_SQL
145
-
146
- UPDATE users, buckets SET item_count = item_count + 1
147
- WHERE users.id = user_id AND buckets.id = NEW.bucket_id
148
- MYSQL
149
- end
150
-
151
- === Manual Migrations
152
-
153
- You can also manage triggers manually in your migrations via create_trigger and
154
- drop_trigger. They are a little more verbose than model triggers, and they can
155
- be more work since you need to figure out the up/down create/drop logic when
156
- you change things. A sample trigger:
157
-
158
- create_trigger(:compatibility => 1).on(:users).after(:insert) do
159
- "UPDATE accounts SET user_count = user_count + 1 WHERE id = NEW.account_id;"
160
- end
161
-
162
- ==== Manual triggers and :compatibility
163
-
164
- As bugs are fixed and features are implemented in hairtrigger, it's possible
165
- that the generated trigger SQL will change (this has only happened once so
166
- far). If you upgrade to a newer version of hairtrigger, it needs a way of
167
- knowing which previous version generated the original trigger. You only need
168
- to worry about this for manual trigger migrations, as the model ones
169
- automatically take care of this. For your manual triggers you can either:
170
-
171
- * pass ":compatibility => x" to your create_trigger statement, where x is
172
- whatever HairTrigger::Builder.compatiblity is (1 for this version).
173
- * set "HairTrigger::Builder.base_compatibility = x" in an initializer, where
174
- x is whatever HairTrigger::Builder.compatiblity is. This is like doing the
175
- first option on every create_trigger. Note that once the compatibility
176
- changes, you'll need to set :compatibility on new triggers (unless you
177
- just redo all your triggers and bump the base_compatibility).
178
-
179
- If you upgrade to a newer version of hairtrigger and see that the SQL
180
- compatibility has changed, you'll need to set the appropriate compatibility
181
- on any new triggers that you create.
182
-
183
- == rake db:schema:dump
184
-
185
- HairTrigger hooks into rake db:schema:dump (and rake tasks that call it) to
186
- make it trigger-aware. A newly generated schema.rb will contain:
187
-
188
- * create_trigger statements for any database triggers that exactly match a
189
- create_trigger statement in an applied migration or in the previous
190
- schema.rb file. this includes both generated and manual create_trigger
191
- calls.
192
- * adapter-specific execute('CREATE TRIGGER..') statements for any unmatched
193
- database triggers.
194
-
195
- As long as you don't delete old migrations and schema.rb prior to running
196
- rake db:schema:dump, the result should be what you expect (and portable).
197
- If you have deleted all trigger migrations, you can regenerate a new
198
- baseline for model triggers via rake db:generate_trigger_migration.
199
-
200
- == Testing
201
-
202
- To stay on top of things, it's strongly recommended that you add a test or
203
- spec to ensure your migrations/schema.rb match your models. This is as simple
204
- as:
205
-
206
- assert HairTrigger::migrations_current?
207
-
208
- This way you'll know if there are any outstanding migrations you need to
209
- create.
210
-
211
- == Warnings and Errors
212
-
213
- There are a couple classes of errors: declaration errors and generation
214
- errors/warnings.
215
-
216
- Declaration errors happen if your trigger declaration is obviously wrong, and
217
- will cause a runtime error in your model or migration class. An example would
218
- be "trigger.after(:never)", since :never is not a valid event.
219
-
220
- Generation errors happen if you try something that your adapter doesn't
221
- support. An example would be something like "trigger.security(:invoker)" for
222
- MySQL. These errors only happen when the trigger is actually generated, e.g.
223
- when you attempt to run the migration.
224
-
225
- Generation warnings are similar but they don't stop the trigger from being
226
- generated. If you do something adapter-specific supported by your database,
227
- you will still get a warning ($stderr) that your trigger is not portable. You
228
- can silence warnings via "HairTrigger::Builder.show_warnings = false"
229
-
230
- You can validate your triggers beforehand using the Builder#validate! method.
231
- It will throw the appropriate errors/warnings so that you know what to fix,
232
- e.g.
233
-
234
- > User.triggers.each(&:validate!)
235
-
236
- HairTrigger does not validate your SQL, so be sure to test it in all databases
237
- you want to support.
238
-
239
- == Gotchas
240
-
241
- * As is the case with ActiveRecord::Base.update_all or any direct SQL you do,
242
- be careful to reload updated objects from the database. For example, the
243
- following code will display the wrong count since we aren't reloading the
244
- account:
245
- a = Account.find(123)
246
- a.account_users.create(:name => 'bob')
247
- puts "count is now #{a.user_count}"
248
- * For repeated chained calls, the last one wins, there is currently no
249
- merging.
250
- * If you want your code to be portable, the trigger actions should be
251
- limited to INSERT/UPDATE/DELETE/SELECT, and conditional logic should be
252
- handled through the :where option/method. Otherwise you'll likely run into
253
- trouble due to differences in syntax and supported features.
254
- * Manual create_trigger statements have some gotchas. See the section
255
- "Manual triggers and :compatibility"
256
-
257
- == Compatibility
258
-
259
- * Ruby 1.8.7+
260
- * Rails 2.3+
261
- * Postgres 8.0+
262
- * MySQL 5.0.10+
263
- * SQLite 3.3.8+
264
-
265
- == Version History
266
-
267
- * 0.2.4 Rails 4 and Ruby 2 support
268
- * 0.2.3 Better 1.9 support, update parsing gems
269
- * 0.2.2 PostGIS support
270
- * 0.2.1 Bugfix for adapter-specific warnings, loosen parser dependencies
271
- * 0.2.0 Rails 3.1+ support, easier installation, ruby 1.9 fix, travis-ci
272
- * 0.1.14 sqlite + ruby1.9 bugfix
273
- * 0.1.13 drop_trigger fix
274
- * 0.1.12 DB-specific trigger body support, bugfixes
275
- * 0.1.11 Safer migration loading, some speedups
276
- * 0.1.10 Sped up migration evaluation
277
- * 0.1.9 MySQL fixes for inferred root@localhost
278
- * 0.1.7 Rails 3 support, fixed a couple manual create_trigger bugs
279
- * 0.1.6 rake db:schema:dump support, respect non-timestamped migrations
280
- * 0.1.4 Compatibility tracking, fixed Postgres return bug, ensure last action
281
- has a semicolon
282
- * 0.1.3 Better error handling, Postgres 8.x support, updated docs
283
- * 0.1.2 Fixed Builder#security, updated docs
284
- * 0.1.1 Fixed bug in HairTrigger.migrations_current?, fixed up Gemfile
285
- * 0.1.0 Initial release
286
-
287
- == Copyright
288
-
289
- Copyright (c) 2011-2013 Jon Jensen. See LICENSE.txt for further details.