hairtrigger 0.2.19 → 0.2.24
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 +29 -6
- data/lib/hair_trigger.rb +38 -31
- data/lib/hair_trigger/builder.rb +16 -11
- data/lib/hair_trigger/migrator.rb +10 -8
- data/lib/hair_trigger/schema_dumper.rb +14 -14
- data/lib/hair_trigger/version.rb +1 -1
- metadata +17 -24
- data/spec/adapter_spec.rb +0 -95
- data/spec/builder_spec.rb +0 -433
- data/spec/migrations-pre-3.1/20110331212003_initial_tables.rb +0 -18
- data/spec/migrations-pre-3.1/20110331212631_user_trigger.rb +0 -18
- data/spec/migrations-pre-3.1/20110417185102_manual_user_trigger.rb +0 -10
- data/spec/migrations/20110331212003_initial_tables.rb +0 -18
- data/spec/migrations/20110331212631_user_trigger.rb +0 -18
- data/spec/migrations/20110417185102_manual_user_trigger.rb +0 -10
- data/spec/migrations_spec.rb +0 -60
- data/spec/models/group.rb +0 -3
- data/spec/models/user.rb +0 -6
- data/spec/schema_dumper_spec.rb +0 -124
- data/spec/spec_helper.rb +0 -93
@@ -1,18 +0,0 @@
|
|
1
|
-
class InitialTables < ActiveRecord::Migration
|
2
|
-
def self.up
|
3
|
-
create_table "users" do |t|
|
4
|
-
t.integer "group_id"
|
5
|
-
t.string "name"
|
6
|
-
end
|
7
|
-
|
8
|
-
create_table "groups" do |t|
|
9
|
-
t.integer "bob_count", :default => 0
|
10
|
-
t.integer "updated_joe_count", :default => 0
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def self.down
|
15
|
-
drop_table "users"
|
16
|
-
drop_table "groups"
|
17
|
-
end
|
18
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# This migration was auto-generated via `rake db:generate_trigger_migration'.
|
2
|
-
# While you can edit this file, any changes you make to the definitions here
|
3
|
-
# will be undone by the next auto-generated trigger migration.
|
4
|
-
|
5
|
-
class UserTrigger < ActiveRecord::Migration
|
6
|
-
def self.up
|
7
|
-
create_trigger("users_after_insert_row_when_new_name_bob__tr", :generated => true, :compatibility => 1).
|
8
|
-
on("users").
|
9
|
-
after(:insert).
|
10
|
-
where("NEW.name = 'bob'") do
|
11
|
-
"UPDATE groups SET bob_count = bob_count + 1"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def self.down
|
16
|
-
drop_trigger("users_after_insert_row_when_new_name_bob__tr", "users")
|
17
|
-
end
|
18
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
class InitialTables < ActiveRecord::Migration
|
2
|
-
def up
|
3
|
-
create_table "users" do |t|
|
4
|
-
t.integer "group_id"
|
5
|
-
t.string "name"
|
6
|
-
end
|
7
|
-
|
8
|
-
create_table "groups" do |t|
|
9
|
-
t.integer "bob_count", :default => 0
|
10
|
-
t.integer "updated_joe_count", :default => 0
|
11
|
-
end
|
12
|
-
end
|
13
|
-
|
14
|
-
def down
|
15
|
-
drop_table "users"
|
16
|
-
drop_table "groups"
|
17
|
-
end
|
18
|
-
end
|
@@ -1,18 +0,0 @@
|
|
1
|
-
# This migration was auto-generated via `rake db:generate_trigger_migration'.
|
2
|
-
# While you can edit this file, any changes you make to the definitions here
|
3
|
-
# will be undone by the next auto-generated trigger migration.
|
4
|
-
|
5
|
-
class UserTrigger < ActiveRecord::Migration
|
6
|
-
def up
|
7
|
-
create_trigger("users_after_insert_row_when_new_name_bob__tr", :generated => true, :compatibility => 1).
|
8
|
-
on("users").
|
9
|
-
after(:insert).
|
10
|
-
where("NEW.name = 'bob'") do
|
11
|
-
"UPDATE groups SET bob_count = bob_count + 1"
|
12
|
-
end
|
13
|
-
end
|
14
|
-
|
15
|
-
def down
|
16
|
-
drop_trigger("users_after_insert_row_when_new_name_bob__tr", "users")
|
17
|
-
end
|
18
|
-
end
|
data/spec/migrations_spec.rb
DELETED
@@ -1,60 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
# for this spec to work, you need to have postgres and mysql installed (in
|
4
|
-
# addition to the gems), and you should make sure that you have set up
|
5
|
-
# appropriate users and permissions. see database.yml for more info
|
6
|
-
|
7
|
-
describe "migrations" do
|
8
|
-
include_context "hairtrigger utils"
|
9
|
-
let(:adapter) { :sqlite3 }
|
10
|
-
|
11
|
-
describe "migrations_current?" do
|
12
|
-
|
13
|
-
it "should return false if there are pending model triggers" do
|
14
|
-
reset_tmp(:migration_glob => "*initial_tables*")
|
15
|
-
initialize_db
|
16
|
-
HairTrigger.should_not be_migrations_current
|
17
|
-
end
|
18
|
-
|
19
|
-
it "should return true if migrations are current" do
|
20
|
-
# just one trigger migration
|
21
|
-
reset_tmp(:migration_glob => "20110331212*")
|
22
|
-
initialize_db
|
23
|
-
migrate_db
|
24
|
-
HairTrigger.should be_migrations_current
|
25
|
-
|
26
|
-
# or multiple
|
27
|
-
reset_tmp
|
28
|
-
initialize_db
|
29
|
-
migrate_db
|
30
|
-
HairTrigger.should be_migrations_current
|
31
|
-
end
|
32
|
-
|
33
|
-
it "should return true even if migrations haven't run" do
|
34
|
-
reset_tmp
|
35
|
-
initialize_db
|
36
|
-
migrate_db
|
37
|
-
HairTrigger.should be_migrations_current
|
38
|
-
end
|
39
|
-
end
|
40
|
-
|
41
|
-
describe "current_triggers" do
|
42
|
-
it "should be inferred from self.up methods" do
|
43
|
-
reset_tmp(:migration_glob => "20110331212*")
|
44
|
-
initialize_db
|
45
|
-
|
46
|
-
migrations = HairTrigger.current_migrations
|
47
|
-
migrations.size.should == 1
|
48
|
-
migrations[0][1].prepared_name.should == "users_after_insert_row_when_new_name_bob__tr"
|
49
|
-
end
|
50
|
-
|
51
|
-
it "should not be inferred from change methods" do
|
52
|
-
reset_tmp(:migration_glob => "*manual*")
|
53
|
-
replace_file_contents("tmp/migrations/20110417185102_manual_user_trigger.rb", "def up", "def change")
|
54
|
-
initialize_db
|
55
|
-
|
56
|
-
migrations = HairTrigger.current_migrations
|
57
|
-
migrations.size.should == 0
|
58
|
-
end
|
59
|
-
end
|
60
|
-
end
|
data/spec/models/group.rb
DELETED
data/spec/models/user.rb
DELETED
data/spec/schema_dumper_spec.rb
DELETED
@@ -1,124 +0,0 @@
|
|
1
|
-
require 'spec_helper'
|
2
|
-
|
3
|
-
# for this spec to work, you need to have postgres and mysql installed (in
|
4
|
-
# addition to the gems), and you should make sure that you have set up
|
5
|
-
# appropriate users and permissions. see database.yml for more info
|
6
|
-
|
7
|
-
describe "schema dumping" do
|
8
|
-
include_context "hairtrigger utils"
|
9
|
-
|
10
|
-
each_adapter do
|
11
|
-
before do
|
12
|
-
reset_tmp
|
13
|
-
initialize_db
|
14
|
-
migrate_db
|
15
|
-
db_triggers.grep(/bob_count \+ 1/).size.should eql(1)
|
16
|
-
end
|
17
|
-
|
18
|
-
context "without schema.rb" do
|
19
|
-
it "should work" do
|
20
|
-
schema_rb = dump_schema
|
21
|
-
schema_rb.should match(/create_trigger\("users_after_insert_row_when_new_name_bob__tr", :generated => true, :compatibility => 1\)/)
|
22
|
-
schema_rb.should match(/create_trigger\("users_after_update_row_when_new_name_joe__tr", :compatibility => 1\)/)
|
23
|
-
end
|
24
|
-
|
25
|
-
it "should create adapter-specific triggers if no migrations exist" do
|
26
|
-
FileUtils.rm_rf(Dir.glob('tmp/migrations/*rb'))
|
27
|
-
schema_rb = dump_schema
|
28
|
-
schema_rb.should_not match(/create_trigger\(/)
|
29
|
-
schema_rb.should match(/no candidate create_trigger statement could be found, creating an adapter-specific one/)
|
30
|
-
end
|
31
|
-
|
32
|
-
it "should not dump triggers in migrations that haven't run" do
|
33
|
-
# edit our model trigger, generate a new migration
|
34
|
-
replace_file_contents HairTrigger.model_path + '/user.rb',
|
35
|
-
'"UPDATE groups SET bob_count = bob_count + 1"',
|
36
|
-
'{:default => "UPDATE groups SET bob_count = bob_count + 2"}'
|
37
|
-
reset_models
|
38
|
-
|
39
|
-
HairTrigger.should_not be_migrations_current
|
40
|
-
migration = HairTrigger.generate_migration
|
41
|
-
HairTrigger.should be_migrations_current
|
42
|
-
|
43
|
-
schema_rb = dump_schema
|
44
|
-
schema_rb.should match(/bob_count \+ 1/)
|
45
|
-
schema_rb.should_not match(/bob_count \+ 2/)
|
46
|
-
end
|
47
|
-
|
48
|
-
it 'should take in consideration active record schema dumper ignore_tables option with regexp' do
|
49
|
-
ActiveRecord::SchemaDumper.ignore_tables = [/users/]
|
50
|
-
|
51
|
-
dump_schema.should_not match(/create_trigger/)
|
52
|
-
end
|
53
|
-
|
54
|
-
it 'should take in consideration active record schema dumper ignore_tables option with string' do
|
55
|
-
ActiveRecord::SchemaDumper.ignore_tables = ['users']
|
56
|
-
|
57
|
-
dump_schema.should_not match(/create_trigger/)
|
58
|
-
end
|
59
|
-
|
60
|
-
it 'should take in consideration active record schema dumper ignore_tables option with partial string' do
|
61
|
-
ActiveRecord::SchemaDumper.ignore_tables = ['user']
|
62
|
-
|
63
|
-
dump_schema.should match(/create_trigger/)
|
64
|
-
end
|
65
|
-
|
66
|
-
|
67
|
-
end
|
68
|
-
|
69
|
-
context "with schema.rb" do
|
70
|
-
before do
|
71
|
-
ActiveRecord::SchemaDumper.previous_schema = dump_schema
|
72
|
-
end
|
73
|
-
|
74
|
-
it "should work" do
|
75
|
-
schema_rb = dump_schema
|
76
|
-
schema_rb.should match(/create_trigger\("users_after_insert_row_when_new_name_bob__tr", :generated => true, :compatibility => 1\)/)
|
77
|
-
schema_rb.should match(/create_trigger\("users_after_update_row_when_new_name_joe__tr", :compatibility => 1\)/)
|
78
|
-
end
|
79
|
-
|
80
|
-
it "should still work even if migrations have been deleted" do
|
81
|
-
FileUtils.rm_rf(Dir.glob('tmp/migrations/*rb'))
|
82
|
-
schema_rb = dump_schema
|
83
|
-
schema_rb.should match(/create_trigger\("users_after_insert_row_when_new_name_bob__tr", :generated => true, :compatibility => 1\)/)
|
84
|
-
schema_rb.should match(/create_trigger\("users_after_update_row_when_new_name_joe__tr", :compatibility => 1\)/)
|
85
|
-
end
|
86
|
-
|
87
|
-
it "should evaluate all migrations even if they haven't run" do
|
88
|
-
# edit our model trigger, generate a new migration
|
89
|
-
replace_file_contents HairTrigger.model_path + '/user.rb',
|
90
|
-
'"UPDATE groups SET bob_count = bob_count + 1"',
|
91
|
-
'{:default => "UPDATE groups SET bob_count = bob_count + 2"}'
|
92
|
-
reset_models
|
93
|
-
|
94
|
-
HairTrigger.should_not be_migrations_current
|
95
|
-
migration = HairTrigger.generate_migration
|
96
|
-
HairTrigger.should be_migrations_current
|
97
|
-
|
98
|
-
schema_rb = dump_schema
|
99
|
-
schema_rb.should match(/bob_count \+ 1/)
|
100
|
-
schema_rb.should_not match(/bob_count \+ 2/)
|
101
|
-
end
|
102
|
-
|
103
|
-
it 'should take in consideration active record schema dumper ignore_tables option with regexp' do
|
104
|
-
ActiveRecord::SchemaDumper.ignore_tables = [/users/]
|
105
|
-
|
106
|
-
dump_schema.should_not match(/create_trigger/)
|
107
|
-
end
|
108
|
-
|
109
|
-
it 'should take in consideration active record schema dumper ignore_tables option with string' do
|
110
|
-
ActiveRecord::SchemaDumper.ignore_tables = ['users']
|
111
|
-
|
112
|
-
dump_schema.should_not match(/create_trigger/)
|
113
|
-
end
|
114
|
-
|
115
|
-
it 'should take in consideration active record schema dumper ignore_tables option with partial string' do
|
116
|
-
ActiveRecord::SchemaDumper.ignore_tables = ['user']
|
117
|
-
|
118
|
-
dump_schema.should match(/create_trigger/)
|
119
|
-
end
|
120
|
-
|
121
|
-
end
|
122
|
-
|
123
|
-
end
|
124
|
-
end
|
data/spec/spec_helper.rb
DELETED
@@ -1,93 +0,0 @@
|
|
1
|
-
require 'rspec'
|
2
|
-
require 'active_record'
|
3
|
-
require 'logger'
|
4
|
-
require 'hair_trigger'
|
5
|
-
require 'yaml'
|
6
|
-
|
7
|
-
CONFIGS = YAML.load_file(File.expand_path(File.dirname(__FILE__) + '/../database.yml'))[ENV["DB_CONFIG"] || "test"]
|
8
|
-
ADAPTERS = [:mysql2, :postgresql, :sqlite3]
|
9
|
-
ADAPTERS.unshift :mysql if ActiveRecord::VERSION::STRING < "5"
|
10
|
-
|
11
|
-
def each_adapter
|
12
|
-
require 'active_record/connection_adapters/postgresql_adapter'
|
13
|
-
require 'active_record/connection_adapters/mysql_adapter' if ADAPTERS.include? :mysql
|
14
|
-
require 'active_record/connection_adapters/mysql2_adapter'
|
15
|
-
require 'active_record/connection_adapters/sqlite3_adapter'
|
16
|
-
require 'mysql2'
|
17
|
-
|
18
|
-
ADAPTERS.each do |adapter_name|
|
19
|
-
context "under #{adapter_name}" do
|
20
|
-
let(:adapter) { adapter_name }
|
21
|
-
instance_eval &Proc.new
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
|
26
|
-
shared_context "hairtrigger utils" do
|
27
|
-
|
28
|
-
def reset_models
|
29
|
-
User.send :remove_instance_variable, :@triggers if Object.const_defined?('User')
|
30
|
-
load './tmp/models/user.rb' # since some tests modify it
|
31
|
-
end
|
32
|
-
|
33
|
-
def reset_tmp(options = {})
|
34
|
-
options[:migration_glob] ||= '*'
|
35
|
-
HairTrigger.model_path = 'tmp/models'
|
36
|
-
HairTrigger.migration_path = 'tmp/migrations'
|
37
|
-
FileUtils.rm_rf('tmp') if File.directory?('tmp')
|
38
|
-
FileUtils.mkdir_p(HairTrigger.model_path)
|
39
|
-
FileUtils.mkdir_p(HairTrigger.migration_path)
|
40
|
-
FileUtils.cp_r('spec/models', 'tmp')
|
41
|
-
reset_models
|
42
|
-
FileUtils.cp_r(Dir.glob("spec/migrations#{ActiveRecord::VERSION::STRING < "3.1." ? "-pre-3.1" : ""}/#{options[:migration_glob]}"), HairTrigger.migration_path)
|
43
|
-
end
|
44
|
-
|
45
|
-
def initialize_db
|
46
|
-
ActiveRecord::Base.clear_all_connections!
|
47
|
-
config = CONFIGS[adapter.to_s].merge({:adapter => adapter.to_s})
|
48
|
-
case adapter
|
49
|
-
when :mysql, :mysql2
|
50
|
-
ret = `echo "drop database if exists #{config['database']}; create database #{config['database']};" | mysql -u #{config['username']}`
|
51
|
-
raise "error creating database: #{ret}" unless $?.exitstatus == 0
|
52
|
-
when :postgresql
|
53
|
-
`dropdb -U #{config['username']} #{config['database']} &>/dev/null`
|
54
|
-
ret = `createdb -U #{config['username']} #{config['database']} 2>&1`
|
55
|
-
raise "error creating database: #{ret}" unless $?.exitstatus == 0
|
56
|
-
end
|
57
|
-
# Arel has an issue in that it keeps using original connection for quoting,
|
58
|
-
# etc. (which breaks stuff) unless you do this:
|
59
|
-
Arel::Visitors::ENGINE_VISITORS.delete(ActiveRecord::Base) if defined?(Arel::Visitors::ENGINE_VISITORS)
|
60
|
-
ActiveRecord::Base.establish_connection(config)
|
61
|
-
ActiveRecord::Base.logger = Logger.new('/dev/null')
|
62
|
-
ActiveRecord::SchemaDumper.previous_schema = nil
|
63
|
-
end
|
64
|
-
|
65
|
-
def migrate_db
|
66
|
-
ActiveRecord::Migration.verbose = false
|
67
|
-
ActiveRecord::Migrator.migrate(HairTrigger.migration_path)
|
68
|
-
end
|
69
|
-
|
70
|
-
def dump_schema
|
71
|
-
io = StringIO.new
|
72
|
-
ActiveRecord::SchemaDumper.dump(ActiveRecord::Base.connection, io)
|
73
|
-
io.rewind
|
74
|
-
io.read
|
75
|
-
end
|
76
|
-
|
77
|
-
def trigger(*args)
|
78
|
-
HairTrigger::Builder.new(*args)
|
79
|
-
end
|
80
|
-
|
81
|
-
def conn
|
82
|
-
ActiveRecord::Base.connection
|
83
|
-
end
|
84
|
-
|
85
|
-
def db_triggers
|
86
|
-
conn.triggers.values
|
87
|
-
end
|
88
|
-
|
89
|
-
def replace_file_contents(path, source, replacement)
|
90
|
-
contents = File.read(path)
|
91
|
-
File.open(path, 'w') { |f| f.write contents.sub(source, replacement) }
|
92
|
-
end
|
93
|
-
end
|