ensured_schema 0.0.1 → 0.1.0
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/.gitignore +2 -0
- data/Gemfile.lock +23 -0
- data/Rakefile +19 -0
- data/ensured_schema.gemspec +4 -0
- data/lib/ensured_schema/column.rb +9 -0
- data/lib/ensured_schema/ensured_table.rb +53 -0
- data/lib/ensured_schema/mysql_column.rb +17 -0
- data/lib/ensured_schema/schema.rb +7 -0
- data/lib/ensured_schema/schema_statements.rb +69 -0
- data/lib/ensured_schema/version.rb +1 -1
- data/lib/ensured_schema.rb +5 -155
- data/test/cases/ensured_schema_test.rb +206 -0
- data/test/cases/helper.rb +70 -0
- data/test/cases/migration_test.rb +1523 -0
- data/test/cases/repair_helper.rb +50 -0
- data/test/config.rb +5 -0
- data/test/connections/native_mysql/connection.rb +25 -0
- data/test/migrations/broken/100_migration_that_raises_exception.rb +10 -0
- data/test/migrations/decimal/1_give_me_big_numbers.rb +15 -0
- data/test/migrations/duplicate/1_people_have_last_names.rb +9 -0
- data/test/migrations/duplicate/2_we_need_reminders.rb +12 -0
- data/test/migrations/duplicate/3_foo.rb +7 -0
- data/test/migrations/duplicate/3_innocent_jointable.rb +12 -0
- data/test/migrations/duplicate_names/20080507052938_chunky.rb +7 -0
- data/test/migrations/duplicate_names/20080507053028_chunky.rb +7 -0
- data/test/migrations/interleaved/pass_1/3_innocent_jointable.rb +12 -0
- data/test/migrations/interleaved/pass_2/1_people_have_last_names.rb +9 -0
- data/test/migrations/interleaved/pass_2/3_innocent_jointable.rb +12 -0
- data/test/migrations/interleaved/pass_3/1_people_have_last_names.rb +9 -0
- data/test/migrations/interleaved/pass_3/2_i_raise_on_down.rb +8 -0
- data/test/migrations/interleaved/pass_3/3_innocent_jointable.rb +12 -0
- data/test/migrations/missing/1000_people_have_middle_names.rb +9 -0
- data/test/migrations/missing/1_people_have_last_names.rb +9 -0
- data/test/migrations/missing/3_we_need_reminders.rb +12 -0
- data/test/migrations/missing/4_innocent_jointable.rb +12 -0
- data/test/migrations/valid/1_people_have_last_names.rb +9 -0
- data/test/migrations/valid/2_we_need_reminders.rb +12 -0
- data/test/migrations/valid/3_innocent_jointable.rb +12 -0
- data/test/models/author.rb +146 -0
- data/test/models/auto_id.rb +4 -0
- data/test/models/binary.rb +2 -0
- data/test/models/bird.rb +3 -0
- data/test/models/book.rb +4 -0
- data/test/models/categorization.rb +5 -0
- data/test/models/category.rb +34 -0
- data/test/models/citation.rb +6 -0
- data/test/models/club.rb +13 -0
- data/test/models/column_name.rb +3 -0
- data/test/models/comment.rb +29 -0
- data/test/models/company.rb +171 -0
- data/test/models/company_in_module.rb +61 -0
- data/test/models/computer.rb +3 -0
- data/test/models/contact.rb +16 -0
- data/test/models/contract.rb +5 -0
- data/test/models/course.rb +3 -0
- data/test/models/customer.rb +73 -0
- data/test/models/default.rb +2 -0
- data/test/models/developer.rb +101 -0
- data/test/models/edge.rb +5 -0
- data/test/models/entrant.rb +3 -0
- data/test/models/essay.rb +3 -0
- data/test/models/event.rb +3 -0
- data/test/models/guid.rb +2 -0
- data/test/models/item.rb +7 -0
- data/test/models/job.rb +5 -0
- data/test/models/joke.rb +3 -0
- data/test/models/keyboard.rb +3 -0
- data/test/models/legacy_thing.rb +3 -0
- data/test/models/matey.rb +4 -0
- data/test/models/member.rb +12 -0
- data/test/models/member_detail.rb +5 -0
- data/test/models/member_type.rb +3 -0
- data/test/models/membership.rb +9 -0
- data/test/models/minimalistic.rb +2 -0
- data/test/models/mixed_case_monkey.rb +3 -0
- data/test/models/movie.rb +5 -0
- data/test/models/order.rb +4 -0
- data/test/models/organization.rb +6 -0
- data/test/models/owner.rb +5 -0
- data/test/models/parrot.rb +16 -0
- data/test/models/person.rb +16 -0
- data/test/models/pet.rb +5 -0
- data/test/models/pirate.rb +70 -0
- data/test/models/post.rb +100 -0
- data/test/models/price_estimate.rb +3 -0
- data/test/models/project.rb +30 -0
- data/test/models/reader.rb +4 -0
- data/test/models/reference.rb +4 -0
- data/test/models/reply.rb +46 -0
- data/test/models/ship.rb +10 -0
- data/test/models/ship_part.rb +5 -0
- data/test/models/sponsor.rb +4 -0
- data/test/models/subject.rb +4 -0
- data/test/models/subscriber.rb +8 -0
- data/test/models/subscription.rb +4 -0
- data/test/models/tag.rb +7 -0
- data/test/models/tagging.rb +10 -0
- data/test/models/task.rb +3 -0
- data/test/models/topic.rb +80 -0
- data/test/models/toy.rb +6 -0
- data/test/models/treasure.rb +8 -0
- data/test/models/vertex.rb +9 -0
- data/test/models/warehouse_thing.rb +5 -0
- data/test/schema/mysql_specific_schema.rb +24 -0
- data/test/schema/postgresql_specific_schema.rb +114 -0
- data/test/schema/schema.rb +493 -0
- data/test/schema/schema2.rb +6 -0
- data/test/schema/sqlite_specific_schema.rb +25 -0
- metadata +237 -7
data/Gemfile.lock
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
PATH
|
|
2
|
+
remote: .
|
|
3
|
+
specs:
|
|
4
|
+
ensured_schema (0.0.1)
|
|
5
|
+
activerecord (~> 2.3.5)
|
|
6
|
+
|
|
7
|
+
GEM
|
|
8
|
+
remote: http://rubygems.org/
|
|
9
|
+
specs:
|
|
10
|
+
activerecord (2.3.10)
|
|
11
|
+
activesupport (= 2.3.10)
|
|
12
|
+
activesupport (2.3.10)
|
|
13
|
+
mocha (0.9.10)
|
|
14
|
+
rake
|
|
15
|
+
rake (0.8.7)
|
|
16
|
+
|
|
17
|
+
PLATFORMS
|
|
18
|
+
ruby
|
|
19
|
+
|
|
20
|
+
DEPENDENCIES
|
|
21
|
+
activerecord (~> 2.3.5)
|
|
22
|
+
ensured_schema!
|
|
23
|
+
mocha (~> 0.9.8)
|
data/Rakefile
CHANGED
|
@@ -1,2 +1,21 @@
|
|
|
1
1
|
require 'bundler'
|
|
2
2
|
Bundler::GemHelper.install_tasks
|
|
3
|
+
|
|
4
|
+
require 'rake/testtask'
|
|
5
|
+
# for adapter in %w( mysql postgresql sqlite sqlite3 firebird db2 oracle sybase openbase frontbase jdbcmysql jdbcpostgresql jdbcsqlite3 jdbcderby jdbch2 jdbchsqldb )
|
|
6
|
+
for adapter in %w( mysql )
|
|
7
|
+
Rake::TestTask.new("test_#{adapter}") { |t|
|
|
8
|
+
if adapter =~ /jdbc/
|
|
9
|
+
t.libs << "test" << "test/connections/jdbc_#{adapter}"
|
|
10
|
+
else
|
|
11
|
+
t.libs << "test" << "test/connections/native_#{adapter}"
|
|
12
|
+
end
|
|
13
|
+
adapter_short = adapter == 'db2' ? adapter : adapter[/^[a-z]+/]
|
|
14
|
+
t.test_files=Dir.glob( "test/cases/**/*_test{,_#{adapter_short}}.rb" ).sort
|
|
15
|
+
t.verbose = true
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
namespace adapter do
|
|
19
|
+
task :test => "test_#{adapter}"
|
|
20
|
+
end
|
|
21
|
+
end
|
data/ensured_schema.gemspec
CHANGED
|
@@ -12,6 +12,10 @@ Gem::Specification.new do |s|
|
|
|
12
12
|
s.summary = %q{Ensures database schema always matches your schema.rb file}
|
|
13
13
|
s.description = %q{Smarter migrations}
|
|
14
14
|
|
|
15
|
+
s.add_dependency('activerecord', '~> 2.3.5')
|
|
16
|
+
|
|
17
|
+
s.add_development_dependency('mocha', '~> 0.9.8')
|
|
18
|
+
|
|
15
19
|
s.rubyforge_project = "ensured_schema"
|
|
16
20
|
|
|
17
21
|
s.files = `git ls-files`.split("\n")
|
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
module ConnectionAdapters
|
|
3
|
+
class EnsuredTable < Table
|
|
4
|
+
|
|
5
|
+
def column_exists?(column_name, type = nil, options = {})
|
|
6
|
+
#debugger
|
|
7
|
+
@base.column_exists?(@table_name, column_name, type, options)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
%w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
|
|
11
|
+
class_eval <<-EOV
|
|
12
|
+
def #{column_type}(*args) # def string(*args)
|
|
13
|
+
define_columns('#{column_type}', *args) # define_column('string', *args)
|
|
14
|
+
end # end
|
|
15
|
+
EOV
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def define_columns(column_type, *args)
|
|
19
|
+
options = args.extract_options!
|
|
20
|
+
column_names = args
|
|
21
|
+
|
|
22
|
+
column_names.each do |name|
|
|
23
|
+
column_def = build_column_definition(name, column_type, options)
|
|
24
|
+
def_options = column_def.members.inject({}){|h, k| h[k.to_sym] = column_def[k]; h;}
|
|
25
|
+
#debugger
|
|
26
|
+
if column_exists?(name)
|
|
27
|
+
unless column_exists?(name, column_type, def_options)
|
|
28
|
+
change(name, column_def.sql_type, options)
|
|
29
|
+
puts "#{name} has been changed!"
|
|
30
|
+
end
|
|
31
|
+
else
|
|
32
|
+
puts "creating column"
|
|
33
|
+
@base.add_column(@table_name, name, column_def.sql_type, options)
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def build_column_definition(column_name, column_type, options = {})
|
|
39
|
+
column = ColumnDefinition.new(@base, column_name, column_type)
|
|
40
|
+
if options[:limit]
|
|
41
|
+
column.limit = options[:limit]
|
|
42
|
+
elsif native[column_type.to_sym].is_a?(Hash)
|
|
43
|
+
column.limit = native[column_type.to_sym][:limit]
|
|
44
|
+
end
|
|
45
|
+
column.precision = options[:precision]
|
|
46
|
+
column.scale = options[:scale]
|
|
47
|
+
column.default = options[:default]
|
|
48
|
+
column.null = options[:null]
|
|
49
|
+
column
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
module ConnectionAdapters
|
|
3
|
+
class MysqlColumn
|
|
4
|
+
def limit_exists?(new_limit)
|
|
5
|
+
return super unless type.to_s == 'integer'
|
|
6
|
+
case new_limit
|
|
7
|
+
when 5..8
|
|
8
|
+
self.limit == 8
|
|
9
|
+
when nil, 4, 11
|
|
10
|
+
self.limit == 4
|
|
11
|
+
else
|
|
12
|
+
self.limit == new_limit
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
module ActiveRecord
|
|
2
|
+
module ConnectionAdapters
|
|
3
|
+
module SchemaStatements
|
|
4
|
+
# Checks to see if an index exists on a table for a given index definition
|
|
5
|
+
#
|
|
6
|
+
# === Examples
|
|
7
|
+
# # Check an index exists
|
|
8
|
+
# index_exists?(:suppliers, :company_id)
|
|
9
|
+
#
|
|
10
|
+
# # Check an index on multiple columns exists
|
|
11
|
+
# index_exists?(:suppliers, [:company_id, :company_type])
|
|
12
|
+
#
|
|
13
|
+
# # Check a unique index exists
|
|
14
|
+
# index_exists?(:suppliers, :company_id, :unique => true)
|
|
15
|
+
#
|
|
16
|
+
# # Check an index with a custom name exists
|
|
17
|
+
# index_exists?(:suppliers, :company_id, :name => "idx_company_id"
|
|
18
|
+
def new_index_exists?(table_name, column_name, options = {}) # Don't overwrite existing index_exists?
|
|
19
|
+
column_names = Array.wrap(column_name)
|
|
20
|
+
index_name = options.key?(:name) ? options[:name].to_s : index_name(table_name, :column => column_names)
|
|
21
|
+
if options[:unique]
|
|
22
|
+
indexes(table_name).any?{ |i| i.unique && i.name == index_name }
|
|
23
|
+
else
|
|
24
|
+
indexes(table_name).any?{ |i| i.name == index_name }
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
# Checks to see if a column exists in a given table.
|
|
29
|
+
#
|
|
30
|
+
# === Examples
|
|
31
|
+
# # Check a column exists
|
|
32
|
+
# column_exists?(:suppliers, :name)
|
|
33
|
+
#
|
|
34
|
+
# # Check a column exists of a particular type
|
|
35
|
+
# column_exists?(:suppliers, :name, :string)
|
|
36
|
+
#
|
|
37
|
+
# # Check a column exists with a specific definition
|
|
38
|
+
# column_exists?(:suppliers, :name, :string, :limit => 100)
|
|
39
|
+
def column_exists?(table_name, column_name, type = nil, options = {})
|
|
40
|
+
#debugger
|
|
41
|
+
columns(table_name).any?{ |c| c.name == column_name.to_s &&
|
|
42
|
+
(!type || c.type.to_s == type.to_s) &&
|
|
43
|
+
(!options[:limit] || c.limit_exists?(options[:limit])) &&
|
|
44
|
+
(!options[:precision] || c.precision == options[:precision]) &&
|
|
45
|
+
(!options[:scale] || c.scale == options[:scale]) }
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def table(table_name, options = {}, &block)
|
|
49
|
+
if table_exists?(table_name)
|
|
50
|
+
puts "table already exists"
|
|
51
|
+
ensure_table(table_name, &block) # what to do about changing table options
|
|
52
|
+
else
|
|
53
|
+
puts "creating table"
|
|
54
|
+
create_table(table_name, options, &block)
|
|
55
|
+
end
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
def ensure_table(table_name)
|
|
59
|
+
yield EnsuredTable.new(table_name, self)
|
|
60
|
+
end
|
|
61
|
+
|
|
62
|
+
def ensure_index(table_name, column_name, options = {})
|
|
63
|
+
unless new_index_exists?(table_name, column_name, options)
|
|
64
|
+
add_index(table_name, column_name, options)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
end
|
|
69
|
+
end
|
data/lib/ensured_schema.rb
CHANGED
|
@@ -1,155 +1,5 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
end
|
|
7
|
-
end
|
|
8
|
-
|
|
9
|
-
module SchemaStatements
|
|
10
|
-
# Checks to see if a column exists in a given table.
|
|
11
|
-
#
|
|
12
|
-
# === Examples
|
|
13
|
-
# # Check a column exists
|
|
14
|
-
# column_exists?(:suppliers, :name)
|
|
15
|
-
#
|
|
16
|
-
# # Check a column exists of a particular type
|
|
17
|
-
# column_exists?(:suppliers, :name, :string)
|
|
18
|
-
#
|
|
19
|
-
# # Check a column exists with a specific definition
|
|
20
|
-
# column_exists?(:suppliers, :name, :string, :limit => 100)
|
|
21
|
-
def column_exists?(table_name, column_name, type = nil, options = {})
|
|
22
|
-
#debugger
|
|
23
|
-
columns(table_name).any?{ |c| c.name == column_name.to_s &&
|
|
24
|
-
(!type || c.type.to_s == type.to_s) &&
|
|
25
|
-
(!options[:limit] || c.limit_exists?(options[:limit])) &&
|
|
26
|
-
(!options[:precision] || c.precision == options[:precision]) &&
|
|
27
|
-
(!options[:scale] || c.scale == options[:scale]) }
|
|
28
|
-
end
|
|
29
|
-
end
|
|
30
|
-
end
|
|
31
|
-
end
|
|
32
|
-
|
|
33
|
-
module ActiveRecord
|
|
34
|
-
module ConnectionAdapters
|
|
35
|
-
class Column
|
|
36
|
-
def limit_exists?(new_limit)
|
|
37
|
-
self.limit == new_limit
|
|
38
|
-
end
|
|
39
|
-
end
|
|
40
|
-
end
|
|
41
|
-
end
|
|
42
|
-
|
|
43
|
-
module ActiveRecord
|
|
44
|
-
module ConnectionAdapters
|
|
45
|
-
class MysqlColumn
|
|
46
|
-
def limit_exists?(new_limit)
|
|
47
|
-
return super unless type.to_s == 'integer'
|
|
48
|
-
case new_limit
|
|
49
|
-
when 5..8
|
|
50
|
-
self.limit == 8
|
|
51
|
-
when nil, 4, 11
|
|
52
|
-
self.limit == 4
|
|
53
|
-
else
|
|
54
|
-
self.limit == new_limit
|
|
55
|
-
end
|
|
56
|
-
end
|
|
57
|
-
end
|
|
58
|
-
end
|
|
59
|
-
end
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
module ActiveRecord
|
|
63
|
-
module ConnectionAdapters
|
|
64
|
-
class EnsuredTable < Table
|
|
65
|
-
|
|
66
|
-
def column_exists?(column_name, type = nil, options = {})
|
|
67
|
-
#debugger
|
|
68
|
-
@base.column_exists?(@table_name, column_name, type, options)
|
|
69
|
-
end
|
|
70
|
-
|
|
71
|
-
%w( string text integer float decimal datetime timestamp time date binary boolean ).each do |column_type|
|
|
72
|
-
class_eval <<-EOV
|
|
73
|
-
def #{column_type}(*args) # def string(*args)
|
|
74
|
-
define_columns('#{column_type}', *args) # define_column('string', *args)
|
|
75
|
-
end # end
|
|
76
|
-
EOV
|
|
77
|
-
end
|
|
78
|
-
|
|
79
|
-
def define_columns(column_type, *args)
|
|
80
|
-
options = args.extract_options!
|
|
81
|
-
column_names = args
|
|
82
|
-
|
|
83
|
-
column_names.each do |name|
|
|
84
|
-
column_def = build_column_definition(name, column_type, options)
|
|
85
|
-
def_options = column_def.members.inject({}){|h, k| h[k.to_sym] = column_def[k]; h;}
|
|
86
|
-
#debugger
|
|
87
|
-
if column_exists?(name)
|
|
88
|
-
unless column_exists?(name, column_type, def_options)
|
|
89
|
-
debugger
|
|
90
|
-
change(name, column_def.sql_type, options)
|
|
91
|
-
puts "#{name} has been changed!"
|
|
92
|
-
end
|
|
93
|
-
else
|
|
94
|
-
puts "creating column"
|
|
95
|
-
@base.add_column(@table_name, name, column_def.sql_type, options)
|
|
96
|
-
end
|
|
97
|
-
end
|
|
98
|
-
end
|
|
99
|
-
|
|
100
|
-
def build_column_definition(column_name, column_type, options = {})
|
|
101
|
-
column = ColumnDefinition.new(@base, column_name, column_type)
|
|
102
|
-
if options[:limit]
|
|
103
|
-
column.limit = options[:limit]
|
|
104
|
-
elsif native[column_type.to_sym].is_a?(Hash)
|
|
105
|
-
column.limit = native[column_type.to_sym][:limit]
|
|
106
|
-
end
|
|
107
|
-
column.precision = options[:precision]
|
|
108
|
-
column.scale = options[:scale]
|
|
109
|
-
column.default = options[:default]
|
|
110
|
-
column.null = options[:null]
|
|
111
|
-
column
|
|
112
|
-
end
|
|
113
|
-
end
|
|
114
|
-
end
|
|
115
|
-
end
|
|
116
|
-
|
|
117
|
-
module ActiveRecord
|
|
118
|
-
class Schema
|
|
119
|
-
def self.ensure(options={}, &block)
|
|
120
|
-
self.define(options, &block)
|
|
121
|
-
end
|
|
122
|
-
end
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
module ActiveRecord
|
|
126
|
-
module ConnectionAdapters # :nodoc:
|
|
127
|
-
module SchemaStatements
|
|
128
|
-
def table(table_name, options = {}, &block)
|
|
129
|
-
if table_exists?(table_name)
|
|
130
|
-
puts "table already exists"
|
|
131
|
-
ensure_table(table_name, &block) # what to do about changing table options
|
|
132
|
-
else
|
|
133
|
-
puts "creating table"
|
|
134
|
-
create_table(table_name, options, &block)
|
|
135
|
-
end
|
|
136
|
-
end
|
|
137
|
-
|
|
138
|
-
def ensure_table(table_name)
|
|
139
|
-
yield EnsuredTable.new(table_name, self)
|
|
140
|
-
end
|
|
141
|
-
|
|
142
|
-
def ensure_index(table_name, column_name, options = {})
|
|
143
|
-
begin
|
|
144
|
-
add_index(table_name, column_name, options)
|
|
145
|
-
rescue => e
|
|
146
|
-
if e.message =~ /Duplicate key/
|
|
147
|
-
puts "index already exists"
|
|
148
|
-
else
|
|
149
|
-
raise e
|
|
150
|
-
end
|
|
151
|
-
end
|
|
152
|
-
end
|
|
153
|
-
end
|
|
154
|
-
end
|
|
155
|
-
end
|
|
1
|
+
require 'ensured_schema/column'
|
|
2
|
+
require 'ensured_schema/mysql_column'
|
|
3
|
+
require 'ensured_schema/schema_statements'
|
|
4
|
+
require 'ensured_schema/ensured_table'
|
|
5
|
+
require 'ensured_schema/schema'
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
require "cases/helper"
|
|
2
|
+
|
|
3
|
+
require 'models/person'
|
|
4
|
+
|
|
5
|
+
if ActiveRecord::Base.connection.supports_migrations?
|
|
6
|
+
class ActiveRecord::Migration
|
|
7
|
+
class <<self
|
|
8
|
+
attr_accessor :message_count
|
|
9
|
+
def puts(text="")
|
|
10
|
+
self.message_count ||= 0
|
|
11
|
+
self.message_count += 1
|
|
12
|
+
end
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
class EnsuredSchemaTest < ActiveRecord::TestCase
|
|
17
|
+
def setup
|
|
18
|
+
@conn = ActiveRecord::Base.connection
|
|
19
|
+
@conn.drop_table("testings") if @conn.table_exists?("testings")
|
|
20
|
+
@conn.drop_table("testings") if @conn.table_exists?("testings")
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
def testings_definition
|
|
24
|
+
assert_nothing_raised do
|
|
25
|
+
ActiveRecord::Schema.ensure(:version => '1') do
|
|
26
|
+
table(:testings, :id => false, :force => true) do |t|
|
|
27
|
+
t.string :test, :limit => 30, :default => "", :null => false
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
ActiveRecord::Schema.ensure(:version => '1') do
|
|
32
|
+
table(:testings, :id => false, :force => true) do |t|
|
|
33
|
+
t.string :test, :limit => 30, :default => "", :null => false
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
assert @conn.table_exists?("testings")
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def test_column_definition_does_not_raise
|
|
41
|
+
assert_nothing_raised do
|
|
42
|
+
ActiveRecord::Schema.ensure(:version => '1') do
|
|
43
|
+
table(:testings, :id => false, :force => true) do |t|
|
|
44
|
+
t.string :test, :limit => 30, :default => "", :null => false
|
|
45
|
+
end
|
|
46
|
+
table(:testings, :id => false, :force => true) do |t|
|
|
47
|
+
t.expects(:change).never
|
|
48
|
+
t.string :test, :limit => 30, :default => "", :null => false
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
# From original column_exists? patch in Rails 3: https://rails.lighthouseapp.com/projects/8994/tickets/4219
|
|
55
|
+
def test_column_exists
|
|
56
|
+
Person.connection.create_table :testings do |t|
|
|
57
|
+
t.column :foo, :string
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
assert Person.connection.column_exists?(:testings, :foo)
|
|
61
|
+
assert !Person.connection.column_exists?(:testings, :bar)
|
|
62
|
+
ensure
|
|
63
|
+
Person.connection.drop_table :testings rescue nil
|
|
64
|
+
end
|
|
65
|
+
|
|
66
|
+
# From original column_exists? patch in Rails 3: https://rails.lighthouseapp.com/projects/8994/tickets/4219
|
|
67
|
+
def test_column_exists_with_type
|
|
68
|
+
Person.connection.create_table :testings do |t|
|
|
69
|
+
t.column :foo, :string
|
|
70
|
+
t.column :bar, :decimal, :precision => 8, :scale => 2
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
assert Person.connection.column_exists?(:testings, :foo, :string)
|
|
74
|
+
assert !Person.connection.column_exists?(:testings, :foo, :integer)
|
|
75
|
+
assert Person.connection.column_exists?(:testings, :bar, :decimal)
|
|
76
|
+
assert !Person.connection.column_exists?(:testings, :bar, :integer)
|
|
77
|
+
ensure
|
|
78
|
+
Person.connection.drop_table :testings rescue nil
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# From original column_exists? patch in Rails 3: https://rails.lighthouseapp.com/projects/8994/tickets/4219
|
|
82
|
+
def test_column_exists_with_definition
|
|
83
|
+
Person.connection.create_table :testings do |t|
|
|
84
|
+
t.column :foo, :string, :limit => 100
|
|
85
|
+
t.column :bar, :decimal, :precision => 8, :scale => 2
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
assert Person.connection.column_exists?(:testings, :foo, :string, :limit => 100)
|
|
89
|
+
assert !Person.connection.column_exists?(:testings, :foo, :string, :limit => 50)
|
|
90
|
+
assert Person.connection.column_exists?(:testings, :bar, :decimal, :precision => 8, :scale => 2)
|
|
91
|
+
assert !Person.connection.column_exists?(:testings, :bar, :decimal, :precision => 10, :scale => 2)
|
|
92
|
+
ensure
|
|
93
|
+
Person.connection.drop_table :testings rescue nil
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# From original column_exists? patch in Rails 3: https://rails.lighthouseapp.com/projects/8994/tickets/4219
|
|
97
|
+
def test_new_index_exists?
|
|
98
|
+
Person.connection.create_table :testings do |t|
|
|
99
|
+
t.column :foo, :string, :limit => 100
|
|
100
|
+
t.column :bar, :string, :limit => 100
|
|
101
|
+
end
|
|
102
|
+
Person.connection.add_index :testings, :foo
|
|
103
|
+
|
|
104
|
+
assert Person.connection.new_index_exists?(:testings, :foo)
|
|
105
|
+
assert !Person.connection.new_index_exists?(:testings, :bar)
|
|
106
|
+
ensure
|
|
107
|
+
Person.connection.drop_table :testings rescue nil
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
# From original column_exists? patch in Rails 3: https://rails.lighthouseapp.com/projects/8994/tickets/4219
|
|
111
|
+
def test_new_index_exists?_on_multiple_columns
|
|
112
|
+
Person.connection.create_table :testings do |t|
|
|
113
|
+
t.column :foo, :string, :limit => 100
|
|
114
|
+
t.column :bar, :string, :limit => 100
|
|
115
|
+
end
|
|
116
|
+
Person.connection.add_index :testings, [:foo, :bar]
|
|
117
|
+
|
|
118
|
+
assert Person.connection.new_index_exists?(:testings, [:foo, :bar])
|
|
119
|
+
ensure
|
|
120
|
+
Person.connection.drop_table :testings rescue nil
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
# From original column_exists? patch in Rails 3: https://rails.lighthouseapp.com/projects/8994/tickets/4219
|
|
124
|
+
def test_unique_new_index_exists?
|
|
125
|
+
Person.connection.create_table :testings do |t|
|
|
126
|
+
t.column :foo, :string, :limit => 100
|
|
127
|
+
end
|
|
128
|
+
Person.connection.add_index :testings, :foo, :unique => true
|
|
129
|
+
|
|
130
|
+
assert Person.connection.new_index_exists?(:testings, :foo, :unique => true)
|
|
131
|
+
ensure
|
|
132
|
+
Person.connection.drop_table :testings rescue nil
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# From original column_exists? patch in Rails 3: https://rails.lighthouseapp.com/projects/8994/tickets/4219
|
|
136
|
+
def test_named_new_index_exists?
|
|
137
|
+
Person.connection.create_table :testings do |t|
|
|
138
|
+
t.column :foo, :string, :limit => 100
|
|
139
|
+
end
|
|
140
|
+
Person.connection.add_index :testings, :foo, :name => "custom_index_name"
|
|
141
|
+
|
|
142
|
+
assert Person.connection.new_index_exists?(:testings, :foo, :name => "custom_index_name")
|
|
143
|
+
ensure
|
|
144
|
+
Person.connection.drop_table :testings rescue nil
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
def test_column_exists_with_integer_limit
|
|
148
|
+
@conn.create_table :testings do |t|
|
|
149
|
+
t.column :one, :integer, :limit => 1
|
|
150
|
+
t.column :two, :integer, :limit => 2
|
|
151
|
+
t.column :three, :integer, :limit => 3
|
|
152
|
+
t.column :four, :integer, :limit => 4
|
|
153
|
+
t.column :five, :integer, :limit => 5
|
|
154
|
+
t.column :six, :integer, :limit => 6
|
|
155
|
+
t.column :seven, :integer, :limit => 7
|
|
156
|
+
t.column :eight, :integer, :limit => 8
|
|
157
|
+
t.column :eleven, :integer, :limit => 11
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
assert @conn.column_exists?(:testings, :one, :integer, :limit => 1)
|
|
161
|
+
assert @conn.column_exists?(:testings, :two, :integer, :limit => 2)
|
|
162
|
+
assert @conn.column_exists?(:testings, :three, :integer, :limit => 3)
|
|
163
|
+
assert @conn.column_exists?(:testings, :four, :integer, :limit => 4)
|
|
164
|
+
assert @conn.column_exists?(:testings, :five, :integer, :limit => 5)
|
|
165
|
+
assert @conn.column_exists?(:testings, :six, :integer, :limit => 6)
|
|
166
|
+
assert @conn.column_exists?(:testings, :seven, :integer, :limit => 7)
|
|
167
|
+
assert @conn.column_exists?(:testings, :eight, :integer, :limit => 8)
|
|
168
|
+
assert @conn.column_exists?(:testings, :eleven, :integer, :limit => 11)
|
|
169
|
+
end
|
|
170
|
+
|
|
171
|
+
def test_column_gets_changed
|
|
172
|
+
ActiveRecord::Schema.ensure(:version => '1') do
|
|
173
|
+
table(:testings, :id => false, :force => true) do |t|
|
|
174
|
+
t.string :test, :limit => 30, :default => "", :null => false
|
|
175
|
+
end
|
|
176
|
+
table(:testings, :id => false, :force => true) do |t|
|
|
177
|
+
t.string :test, :limit => 20, :default => "", :null => false
|
|
178
|
+
end
|
|
179
|
+
end
|
|
180
|
+
|
|
181
|
+
assert !@conn.column_exists?(:testings, :test, :string, :limit => 30)
|
|
182
|
+
assert @conn.column_exists?(:testings, :test, :string, :limit => 20, :default => "", :null => false)
|
|
183
|
+
assert @conn.column_exists?(:testings, :test)
|
|
184
|
+
end
|
|
185
|
+
|
|
186
|
+
def test_ensure_index
|
|
187
|
+
assert_nothing_raised do
|
|
188
|
+
ActiveRecord::Schema.ensure(:version => '1') do
|
|
189
|
+
table(:testings, :id => false, :force => true) do |t|
|
|
190
|
+
t.string :test, :limit => 30, :default => "", :null => false
|
|
191
|
+
end
|
|
192
|
+
ensure_index :testings, [:test], :name => "test_index", :unique => true
|
|
193
|
+
ensure_index :testings, [:test], :name => "test_index", :unique => true
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
assert @conn.new_index_exists?(:testings, :test, :name => "test_index")
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
protected
|
|
200
|
+
def with_change_table
|
|
201
|
+
Person.connection.change_table :delete_me do |t|
|
|
202
|
+
yield t
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
end
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
$:.unshift(File.dirname(__FILE__) + '/../../lib')
|
|
2
|
+
$:.unshift(File.dirname(__FILE__) + '/../../../activesupport/lib')
|
|
3
|
+
|
|
4
|
+
require 'config'
|
|
5
|
+
|
|
6
|
+
require 'rubygems'
|
|
7
|
+
require 'test/unit'
|
|
8
|
+
require 'stringio'
|
|
9
|
+
|
|
10
|
+
require 'active_record'
|
|
11
|
+
require 'active_record/test_case'
|
|
12
|
+
require 'active_record/fixtures'
|
|
13
|
+
require 'connection'
|
|
14
|
+
|
|
15
|
+
require 'cases/repair_helper'
|
|
16
|
+
|
|
17
|
+
require 'ensured_schema'
|
|
18
|
+
|
|
19
|
+
# Show backtraces for deprecated behavior for quicker cleanup.
|
|
20
|
+
ActiveSupport::Deprecation.debug = true
|
|
21
|
+
|
|
22
|
+
# Quote "type" if it's a reserved word for the current connection.
|
|
23
|
+
QUOTED_TYPE = ActiveRecord::Base.connection.quote_column_name('type')
|
|
24
|
+
|
|
25
|
+
def current_adapter?(*types)
|
|
26
|
+
types.any? do |type|
|
|
27
|
+
ActiveRecord::ConnectionAdapters.const_defined?(type) &&
|
|
28
|
+
ActiveRecord::Base.connection.is_a?(ActiveRecord::ConnectionAdapters.const_get(type))
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
ActiveRecord::Base.connection.class.class_eval do
|
|
33
|
+
IGNORED_SQL = [/^PRAGMA/, /^SELECT currval/, /^SELECT CAST/, /^SELECT @@IDENTITY/, /^SELECT @@ROWCOUNT/, /^SAVEPOINT/, /^ROLLBACK TO SAVEPOINT/, /^RELEASE SAVEPOINT/, /SHOW FIELDS/]
|
|
34
|
+
|
|
35
|
+
def execute_with_query_record(sql, name = nil, &block)
|
|
36
|
+
$queries_executed ||= []
|
|
37
|
+
$queries_executed << sql unless IGNORED_SQL.any? { |r| sql =~ r }
|
|
38
|
+
execute_without_query_record(sql, name, &block)
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
alias_method_chain :execute, :query_record
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
# Make with_scope public for tests
|
|
45
|
+
class << ActiveRecord::Base
|
|
46
|
+
public :with_scope, :with_exclusive_scope
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
unless ENV['FIXTURE_DEBUG']
|
|
50
|
+
module ActiveRecord::TestFixtures::ClassMethods
|
|
51
|
+
def try_to_load_dependency_with_silence(*args)
|
|
52
|
+
ActiveRecord::Base.logger.silence { try_to_load_dependency_without_silence(*args)}
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
alias_method_chain :try_to_load_dependency, :silence
|
|
56
|
+
end
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
class ActiveSupport::TestCase
|
|
60
|
+
include ActiveRecord::TestFixtures
|
|
61
|
+
include ActiveRecord::Testing::RepairHelper
|
|
62
|
+
|
|
63
|
+
self.fixture_path = FIXTURES_ROOT
|
|
64
|
+
self.use_instantiated_fixtures = false
|
|
65
|
+
self.use_transactional_fixtures = true
|
|
66
|
+
|
|
67
|
+
def create_fixtures(*table_names, &block)
|
|
68
|
+
Fixtures.create_fixtures(ActiveSupport::TestCase.fixture_path, table_names, {}, &block)
|
|
69
|
+
end
|
|
70
|
+
end
|