redhillonrails_core 1.0.9.1 → 1.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/CHANGELOG +7 -0
- data/README.rdoc +31 -47
- data/lib/redhillonrails_core/active_record/base.rb +63 -0
- data/lib/redhillonrails_core/active_record/connection_adapters/abstract_adapter.rb +75 -0
- data/lib/redhillonrails_core/active_record/connection_adapters/column.rb +25 -0
- data/lib/redhillonrails_core/active_record/connection_adapters/foreign_key_definition.rb +30 -0
- data/lib/redhillonrails_core/active_record/connection_adapters/index_definition.rb +17 -0
- data/lib/redhillonrails_core/active_record/connection_adapters/mysql_adapter.rb +78 -0
- data/lib/redhillonrails_core/active_record/connection_adapters/mysql_column.rb +12 -0
- data/lib/redhillonrails_core/active_record/connection_adapters/postgresql_adapter.rb +160 -0
- data/lib/redhillonrails_core/active_record/connection_adapters/sqlite3_adapter.rb +111 -0
- data/lib/redhillonrails_core/active_record/connection_adapters/table_definition.rb +31 -0
- data/lib/redhillonrails_core/active_record/schema.rb +27 -0
- data/lib/redhillonrails_core/active_record/schema_dumper.rb +70 -0
- data/lib/redhillonrails_core.rb +20 -26
- data/redhillonrails_core.gemspec +34 -40
- data/spec/connections/mysql/connection.rb +18 -0
- data/spec/connections/mysql2/connection.rb +18 -0
- data/spec/connections/postgresql/connection.rb +15 -0
- data/spec/connections/sqlite3/connection.rb +14 -0
- data/spec/foreign_key_spec.rb +100 -0
- data/spec/index_definition_spec.rb +145 -0
- data/spec/index_spec.rb +67 -0
- data/spec/models/comment.rb +5 -0
- data/spec/models/post.rb +6 -0
- data/spec/models/user.rb +5 -0
- data/spec/schema/schema.rb +21 -0
- data/spec/schema_dumper_spec.rb +117 -0
- data/spec/spec_helper.rb +16 -0
- data/spec/support/reference.rb +66 -0
- metadata +32 -57
- data/.document +0 -5
- data/.gitignore +0 -23
- data/.rvmrc +0 -1
- data/Gemfile +0 -20
- data/Gemfile.lock +0 -50
- data/Rakefile +0 -76
- data/VERSION +0 -1
- data/examples/example_helper.rb +0 -44
- data/examples/postgresql_index_parser_example.rb +0 -198
- data/lib/red_hill_consulting/core/active_record/base.rb +0 -61
- data/lib/red_hill_consulting/core/active_record/connection_adapters/abstract_adapter.rb +0 -71
- data/lib/red_hill_consulting/core/active_record/connection_adapters/column.rb +0 -21
- data/lib/red_hill_consulting/core/active_record/connection_adapters/foreign_key_definition.rb +0 -26
- data/lib/red_hill_consulting/core/active_record/connection_adapters/index_definition.rb +0 -13
- data/lib/red_hill_consulting/core/active_record/connection_adapters/mysql4_adapter.rb +0 -37
- data/lib/red_hill_consulting/core/active_record/connection_adapters/mysql5_adapter.rb +0 -40
- data/lib/red_hill_consulting/core/active_record/connection_adapters/mysql_adapter.rb +0 -103
- data/lib/red_hill_consulting/core/active_record/connection_adapters/mysql_column.rb +0 -8
- data/lib/red_hill_consulting/core/active_record/connection_adapters/postgresql_adapter.rb +0 -178
- data/lib/red_hill_consulting/core/active_record/connection_adapters/schema_statements.rb +0 -23
- data/lib/red_hill_consulting/core/active_record/connection_adapters/sqlite3_adapter.rb +0 -109
- data/lib/red_hill_consulting/core/active_record/connection_adapters/table_definition.rb +0 -27
- data/lib/red_hill_consulting/core/active_record/schema.rb +0 -25
- data/lib/red_hill_consulting/core/active_record/schema_dumper.rb +0 -66
- data/lib/red_hill_consulting/core/active_record.rb +0 -4
- data/lib/red_hill_consulting/core.rb +0 -4
- data/tasks/db/comments.rake +0 -9
@@ -1,103 +0,0 @@
|
|
1
|
-
module RedHillConsulting::Core::ActiveRecord::ConnectionAdapters
|
2
|
-
module MysqlAdapter
|
3
|
-
def self.included(base)
|
4
|
-
base.class_eval do
|
5
|
-
alias_method_chain :remove_column, :redhillonrails_core
|
6
|
-
alias_method_chain :connect, :redhillonrails_core
|
7
|
-
end
|
8
|
-
end
|
9
|
-
|
10
|
-
def connect_with_redhillonrails_core(*args)
|
11
|
-
result = connect_without_redhillonrails_core(*args)
|
12
|
-
if version[0] < 5
|
13
|
-
self.class.send(:include, Mysql4Adapter) unless self.class.include?(Mysql4Adapter)
|
14
|
-
else
|
15
|
-
self.class.send(:include, Mysql5Adapter) unless self.class.include?(Mysql5Adapter)
|
16
|
-
end
|
17
|
-
result
|
18
|
-
end
|
19
|
-
|
20
|
-
def set_table_comment(table_name, comment)
|
21
|
-
execute "ALTER TABLE #{quote_table_name(table_name)} COMMENT='#{quote_string(comment)}'"
|
22
|
-
end
|
23
|
-
|
24
|
-
def clear_table_comment(table_name)
|
25
|
-
execute "ALTER TABLE #{quote_table_name(table_name)} COMMENT=''"
|
26
|
-
end
|
27
|
-
|
28
|
-
def remove_foreign_key(table_name, foreign_key_name, options = {})
|
29
|
-
execute "ALTER TABLE #{quote_table_name(table_name)} DROP FOREIGN KEY #{foreign_key_name}"
|
30
|
-
end
|
31
|
-
|
32
|
-
def remove_column_with_redhillonrails_core(table_name, column_name)
|
33
|
-
foreign_keys(table_name).select { |foreign_key| foreign_key.column_names.include?(column_name.to_s) }.each do |foreign_key|
|
34
|
-
remove_foreign_key(table_name, foreign_key.name)
|
35
|
-
end
|
36
|
-
remove_column_without_redhillonrails_core(table_name, column_name)
|
37
|
-
end
|
38
|
-
|
39
|
-
def foreign_keys(table_name, name = nil)
|
40
|
-
results = execute("SHOW CREATE TABLE #{quote_table_name(table_name)}", name)
|
41
|
-
|
42
|
-
foreign_keys = []
|
43
|
-
|
44
|
-
results.each do |row|
|
45
|
-
row[1].lines.each do |line|
|
46
|
-
if line =~ /^ CONSTRAINT [`"](.+?)[`"] FOREIGN KEY \([`"](.+?)[`"]\) REFERENCES [`"](.+?)[`"] \((.+?)\)( ON DELETE (.+?))?( ON UPDATE (.+?))?,?$/
|
47
|
-
name = $1
|
48
|
-
column_names = $2
|
49
|
-
references_table_name = $3
|
50
|
-
references_column_names = $4
|
51
|
-
on_update = $8
|
52
|
-
on_delete = $6
|
53
|
-
on_update = on_update.downcase.gsub(' ', '_').to_sym if on_update
|
54
|
-
on_delete = on_delete.downcase.gsub(' ', '_').to_sym if on_delete
|
55
|
-
|
56
|
-
foreign_keys << ForeignKeyDefinition.new(name,
|
57
|
-
table_name, column_names.gsub('`', '').split(', '),
|
58
|
-
references_table_name, references_column_names.gsub('`', '').split(', '),
|
59
|
-
on_update, on_delete)
|
60
|
-
end
|
61
|
-
end
|
62
|
-
end
|
63
|
-
|
64
|
-
foreign_keys
|
65
|
-
end
|
66
|
-
|
67
|
-
def reverse_foreign_keys(table_name, name = nil)
|
68
|
-
@@schema ||= nil
|
69
|
-
@@schema_version ||= 0
|
70
|
-
current_version = ActiveRecord::Migrator.current_version
|
71
|
-
if @@schema.nil? || @@schema_version != current_version
|
72
|
-
@@schema_version = current_version
|
73
|
-
ans = execute(<<-SQL, name)
|
74
|
-
SELECT constraint_name, table_name, column_name, referenced_table_name, referenced_column_name
|
75
|
-
FROM information_schema.key_column_usage
|
76
|
-
WHERE table_schema = SCHEMA()
|
77
|
-
AND referenced_table_schema = table_schema
|
78
|
-
ORDER BY constraint_name, ordinal_position;
|
79
|
-
SQL
|
80
|
-
@@schema = []
|
81
|
-
ans.each do | row |
|
82
|
-
@@schema << [row[0], row[1], row[2], row[3], row[4]]
|
83
|
-
end
|
84
|
-
end
|
85
|
-
results = @@schema
|
86
|
-
current_foreign_key = nil
|
87
|
-
foreign_keys = []
|
88
|
-
|
89
|
-
results.each do |row|
|
90
|
-
next if row[3] != table_name
|
91
|
-
if current_foreign_key != row[0]
|
92
|
-
foreign_keys << ForeignKeyDefinition.new(row[0], row[1], [], row[3], [])
|
93
|
-
current_foreign_key = row[0]
|
94
|
-
end
|
95
|
-
|
96
|
-
foreign_keys.last.column_names << row[2]
|
97
|
-
foreign_keys.last.references_column_names << row[4]
|
98
|
-
end
|
99
|
-
|
100
|
-
foreign_keys
|
101
|
-
end
|
102
|
-
end
|
103
|
-
end
|
@@ -1,178 +0,0 @@
|
|
1
|
-
module RedHillConsulting::Core::ActiveRecord::ConnectionAdapters
|
2
|
-
module PostgresqlAdapter
|
3
|
-
def self.included(base)
|
4
|
-
base.class_eval do
|
5
|
-
alias_method_chain :indexes, :redhillonrails_core
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
def set_table_comment(table_name, comment)
|
10
|
-
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS '#{quote_string(comment)}'"
|
11
|
-
end
|
12
|
-
|
13
|
-
def clear_table_comment(table_name)
|
14
|
-
execute "COMMENT ON TABLE #{quote_table_name(table_name)} IS NULL"
|
15
|
-
end
|
16
|
-
|
17
|
-
def add_index(table_name, column_name, options = {})
|
18
|
-
column_name, options = [], column_name if column_name.is_a?(Hash)
|
19
|
-
column_names = Array(column_name)
|
20
|
-
if column_names.empty?
|
21
|
-
raise ArgumentError, "No columns and :expression missing from options - cannot create index" if options[:expression].blank?
|
22
|
-
raise ArgumentError, "Index name not given. Pass :name option" if options[:name].blank?
|
23
|
-
end
|
24
|
-
|
25
|
-
index_type = options[:unique] ? "UNIQUE" : ""
|
26
|
-
index_name = options[:name] || index_name(table_name, column_names)
|
27
|
-
conditions = options[:conditions]
|
28
|
-
|
29
|
-
if column_names.empty? then
|
30
|
-
sql = "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} #{options[:expression]}"
|
31
|
-
else
|
32
|
-
quoted_column_names = column_names.map { |e| options[:case_sensitive] == false && e.to_s !~ /_id$/ ? "LOWER(#{quote_column_name(e)})" : quote_column_name(e) }
|
33
|
-
|
34
|
-
sql = "CREATE #{index_type} INDEX #{quote_column_name(index_name)} ON #{quote_table_name(table_name)} (#{quoted_column_names.join(", ")})"
|
35
|
-
sql += " WHERE (#{ ActiveRecord::Base.send(:sanitize_sql, conditions, quote_table_name(table_name)) })" if conditions
|
36
|
-
end
|
37
|
-
execute sql
|
38
|
-
end
|
39
|
-
|
40
|
-
def supports_partial_indexes?
|
41
|
-
true
|
42
|
-
end
|
43
|
-
|
44
|
-
INDEX_CASE_INSENSITIVE_REGEX = /\((.*LOWER\([^:]+(::text)?\).*)\)/i
|
45
|
-
INDEX_PARTIAL_REGEX = /\((.*)\)\s+WHERE (.*)$/i
|
46
|
-
INDEX_NON_BTREE_REGEX = /((?:gin|gist|hash).*)$/i
|
47
|
-
|
48
|
-
def indexes_with_redhillonrails_core(table_name, name = nil)
|
49
|
-
indexes = indexes_without_redhillonrails_core(table_name, name)
|
50
|
-
# Process indexes containg expressions and partial indexes
|
51
|
-
# Ie. consider
|
52
|
-
result = query(<<-SQL, name)
|
53
|
-
SELECT c2.relname, i.indisunique, pg_catalog.pg_get_indexdef(i.indexrelid, 0, true)
|
54
|
-
FROM pg_catalog.pg_class c, pg_catalog.pg_class c2, pg_catalog.pg_index i
|
55
|
-
WHERE c.relname = '#{table_name}'
|
56
|
-
AND c.oid = i.indrelid AND i.indexrelid = c2.oid
|
57
|
-
AND i.indisprimary = 'f'
|
58
|
-
AND (i.indexprs IS NOT NULL OR i.indpred IS NOT NULL)
|
59
|
-
ORDER BY 1
|
60
|
-
SQL
|
61
|
-
|
62
|
-
|
63
|
-
# Correctly process complex indexes, ie:
|
64
|
-
# CREATE INDEX test_index ON custom_pages USING btree (lower(title::text), created_at) WHERE kind = 1 AND author_id = 3
|
65
|
-
result.each do |(index_name, unique, index_def)|
|
66
|
-
case_sensitive_match = INDEX_CASE_INSENSITIVE_REGEX.match(index_def)
|
67
|
-
partial_index_match = INDEX_PARTIAL_REGEX.match(index_def)
|
68
|
-
if non_btree_match = INDEX_NON_BTREE_REGEX.match(index_def) || (case_sensitive_match && partial_index_match) then
|
69
|
-
# If we have both types of indexes simultaneously, we don't try to parse it all: simply assume it's an expression index
|
70
|
-
indexes.delete_if { |index| index.name == index_name } # prevent duplicated indexes
|
71
|
-
|
72
|
-
index = ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, index_name, false, nil)
|
73
|
-
index.expression = if case_sensitive_match then
|
74
|
-
index_def.split(/using/i, 2).last.strip
|
75
|
-
else
|
76
|
-
non_btree_match[1]
|
77
|
-
end
|
78
|
-
indexes << index
|
79
|
-
elsif case_sensitive_match || partial_index_match then
|
80
|
-
# column_definitions may be ie. 'LOWER(lower)' or 'login, deleted_at' or LOWER(login), deleted_at
|
81
|
-
column_definitions = case_sensitive_match ? case_sensitive_match[1] : partial_index_match[1]
|
82
|
-
|
83
|
-
indexes.delete_if { |index| index.name == index_name } # prevent duplicated indexes
|
84
|
-
column_names = determine_index_column_names(column_definitions)
|
85
|
-
|
86
|
-
index = ActiveRecord::ConnectionAdapters::IndexDefinition.new(table_name, index_name, unique == "t", column_names)
|
87
|
-
index.case_sensitive = !case_sensitive_match
|
88
|
-
# conditions may be ie. active = true AND deleted_at IS NULL.
|
89
|
-
index.conditions = partial_index_match[2] if partial_index_match
|
90
|
-
indexes << index
|
91
|
-
|
92
|
-
end
|
93
|
-
end
|
94
|
-
|
95
|
-
indexes
|
96
|
-
end
|
97
|
-
|
98
|
-
def foreign_keys(table_name, name = nil)
|
99
|
-
load_foreign_keys(<<-SQL, name)
|
100
|
-
SELECT f.conname, pg_get_constraintdef(f.oid), t.relname
|
101
|
-
FROM pg_class t, pg_constraint f
|
102
|
-
WHERE f.conrelid = t.oid
|
103
|
-
AND f.contype = 'f'
|
104
|
-
AND t.relname = '#{table_name}'
|
105
|
-
SQL
|
106
|
-
end
|
107
|
-
|
108
|
-
def reverse_foreign_keys(table_name, name = nil)
|
109
|
-
load_foreign_keys(<<-SQL, name)
|
110
|
-
SELECT f.conname, pg_get_constraintdef(f.oid), t2.relname
|
111
|
-
FROM pg_class t, pg_class t2, pg_constraint f
|
112
|
-
WHERE f.confrelid = t.oid
|
113
|
-
AND f.conrelid = t2.oid
|
114
|
-
AND f.contype = 'f'
|
115
|
-
AND t.relname = '#{table_name}'
|
116
|
-
SQL
|
117
|
-
end
|
118
|
-
|
119
|
-
def views(name = nil)
|
120
|
-
schemas = schema_search_path.split(/,/).map { |p| quote(p) }.join(',')
|
121
|
-
query(<<-SQL, name).map { |row| row[0] }
|
122
|
-
SELECT viewname
|
123
|
-
FROM pg_views
|
124
|
-
WHERE schemaname IN (#{schemas})
|
125
|
-
SQL
|
126
|
-
end
|
127
|
-
|
128
|
-
def view_definition(view_name, name = nil)
|
129
|
-
result = query(<<-SQL, name)
|
130
|
-
SELECT pg_get_viewdef(oid)
|
131
|
-
FROM pg_class
|
132
|
-
WHERE relkind = 'v'
|
133
|
-
AND relname = '#{view_name}'
|
134
|
-
SQL
|
135
|
-
row = result.first
|
136
|
-
row.first unless row.nil?
|
137
|
-
end
|
138
|
-
|
139
|
-
private
|
140
|
-
|
141
|
-
def load_foreign_keys(sql, name = nil)
|
142
|
-
foreign_keys = []
|
143
|
-
|
144
|
-
query(sql, name).each do |row|
|
145
|
-
if row[1] =~ /^FOREIGN KEY \((.+?)\) REFERENCES (.+?)\((.+?)\)( ON UPDATE (.+?))?( ON DELETE (.+?))?( (DEFERRABLE|NOT DEFERRABLE))?$/
|
146
|
-
name = row[0]
|
147
|
-
from_table_name = row[2]
|
148
|
-
column_names = $1
|
149
|
-
references_table_name = $2
|
150
|
-
references_column_names = $3
|
151
|
-
on_update = $5
|
152
|
-
on_delete = $7
|
153
|
-
deferrable = $9 == "DEFERRABLE"
|
154
|
-
on_update = on_update.downcase.gsub(' ', '_').to_sym if on_update
|
155
|
-
on_delete = on_delete.downcase.gsub(' ', '_').to_sym if on_delete
|
156
|
-
|
157
|
-
foreign_keys << ForeignKeyDefinition.new(name,
|
158
|
-
from_table_name, column_names.split(', '),
|
159
|
-
references_table_name.sub(/^"(.*)"$/, '\1'), references_column_names.split(', '),
|
160
|
-
on_update, on_delete, deferrable)
|
161
|
-
end
|
162
|
-
end
|
163
|
-
|
164
|
-
foreign_keys
|
165
|
-
end
|
166
|
-
|
167
|
-
# Converts form like: column1, LOWER(column2)
|
168
|
-
# to: column1, column2
|
169
|
-
def determine_index_column_names(column_definitions)
|
170
|
-
column_definitions.split(", ").map do |name|
|
171
|
-
name = $1 if name =~ /^LOWER\(([^:]+)(::text)?\)$/i
|
172
|
-
name = $1 if name =~ /^"(.*)"$/
|
173
|
-
name
|
174
|
-
end
|
175
|
-
end
|
176
|
-
|
177
|
-
end
|
178
|
-
end
|
@@ -1,23 +0,0 @@
|
|
1
|
-
module RedHillConsulting::Core::ActiveRecord::ConnectionAdapters
|
2
|
-
module SchemaStatements
|
3
|
-
def self.included(base)
|
4
|
-
base.module_eval do
|
5
|
-
alias_method_chain :create_table, :redhillonrails_core
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
def create_table_with_redhillonrails_core(name, options = {})
|
10
|
-
if options.include?(:comment)
|
11
|
-
options = options.dup
|
12
|
-
comment = options.delete(:comment)
|
13
|
-
end
|
14
|
-
|
15
|
-
create_table_without_redhillonrails_core(name, options) do |table_defintion|
|
16
|
-
table_defintion.name = name
|
17
|
-
yield table_defintion if block_given?
|
18
|
-
end
|
19
|
-
|
20
|
-
set_table_comment(name, comment) if comment
|
21
|
-
end
|
22
|
-
end
|
23
|
-
end
|
@@ -1,109 +0,0 @@
|
|
1
|
-
module RedHillConsulting::Core::ActiveRecord::ConnectionAdapters
|
2
|
-
module Sqlite3Adapter
|
3
|
-
def self.included(base)
|
4
|
-
base.class_eval do
|
5
|
-
alias_method_chain :tables, :redhillonrails_core
|
6
|
-
end
|
7
|
-
end
|
8
|
-
|
9
|
-
def move_table(from, to, options = {}, &block) #:nodoc:
|
10
|
-
copy_table(from, to, options, &block)
|
11
|
-
drop_table(from, options)
|
12
|
-
end
|
13
|
-
|
14
|
-
def add_foreign_key(from_table_name, from_column_names, to_table_name, to_column_names, options = {})
|
15
|
-
initialize_sqlite3_foreign_key_table
|
16
|
-
from_column_names = Array(from_column_names)
|
17
|
-
to_column_names = Array(to_column_names)
|
18
|
-
fk_name = options[:name] || ["fk", from_table_name, *to_column_names].join("_")
|
19
|
-
|
20
|
-
columns = %w(name from_table_name from_column_names to_table_name to_column_names)
|
21
|
-
values = [fk_name, from_table_name, from_column_names.join(","), to_table_name, to_column_names.join(",")]
|
22
|
-
|
23
|
-
quoted_values = values.map { |x| quote(x.to_s) }.join(",")
|
24
|
-
|
25
|
-
# TODO: support options
|
26
|
-
|
27
|
-
insert <<-SQL
|
28
|
-
INSERT INTO #{sqlite3_foreign_key_table}(#{quoted_columns(columns)})
|
29
|
-
VALUES (#{quoted_values})
|
30
|
-
SQL
|
31
|
-
end
|
32
|
-
|
33
|
-
def remove_foreign_key(table_name, foreign_key_name, options = {})
|
34
|
-
return if options[:temporary] == true
|
35
|
-
initialize_sqlite3_foreign_key_table
|
36
|
-
|
37
|
-
rows_deleted = delete <<-SQL
|
38
|
-
DELETE FROM #{sqlite3_foreign_key_table}
|
39
|
-
WHERE #{quote_column_name("name")} = #{quote(foreign_key_name.to_s)}
|
40
|
-
AND #{quote_column_name("from_table_name")} = #{quote(table_name.to_s)}
|
41
|
-
SQL
|
42
|
-
|
43
|
-
if rows_deleted != 1
|
44
|
-
raise ActiveRecord::ActiveRecordError, "Foreign-key '#{foreign_key_name}' on table '#{table_name}' not found"
|
45
|
-
end
|
46
|
-
end
|
47
|
-
|
48
|
-
def tables_with_redhillonrails_core(name=nil)
|
49
|
-
tables_without_redhillonrails_core.reject{ |name| name == sqlite3_foreign_key_table }
|
50
|
-
end
|
51
|
-
|
52
|
-
def foreign_keys(table_name, name = nil)
|
53
|
-
load_foreign_keys("from_table_name", table_name, name)
|
54
|
-
end
|
55
|
-
|
56
|
-
def reverse_foreign_keys(table_name, name = nil)
|
57
|
-
load_foreign_keys("to_table_name", table_name, name)
|
58
|
-
end
|
59
|
-
|
60
|
-
# TODO: tests!
|
61
|
-
|
62
|
-
private
|
63
|
-
|
64
|
-
def quoted_columns(columns)
|
65
|
-
columns.map { |x| quote_column_name(x) }.join(",")
|
66
|
-
end
|
67
|
-
|
68
|
-
def sqlite3_foreign_key_table
|
69
|
-
"sqlite3_foreign_keys"
|
70
|
-
end
|
71
|
-
|
72
|
-
def initialize_sqlite3_foreign_key_table
|
73
|
-
unless sqlite3_foreign_key_table_exists?
|
74
|
-
create_table(sqlite3_foreign_key_table, :id => false) do |t|
|
75
|
-
t.string "name", :null => false
|
76
|
-
t.string "from_table_name", :null => false
|
77
|
-
t.string "from_column_names", :null => false
|
78
|
-
t.string "to_table_name", :null => false
|
79
|
-
t.string "to_column_names", :null => false
|
80
|
-
end
|
81
|
-
add_index(sqlite3_foreign_key_table, "name", :unique => true)
|
82
|
-
add_index(sqlite3_foreign_key_table, "from_table_name", :unique => false)
|
83
|
-
add_index(sqlite3_foreign_key_table, "to_table_name", :unique => false)
|
84
|
-
end
|
85
|
-
end
|
86
|
-
|
87
|
-
def sqlite3_foreign_key_table_exists?
|
88
|
-
tables_without_redhillonrails_core.detect { |name| name == sqlite3_foreign_key_table }
|
89
|
-
end
|
90
|
-
|
91
|
-
def load_foreign_keys(discriminating_column, table_name, name = nil)
|
92
|
-
rows = select_all(<<-SQL, name)
|
93
|
-
SELECT *
|
94
|
-
FROM #{sqlite3_foreign_key_table}
|
95
|
-
WHERE #{quote_column_name(discriminating_column)} = #{quote(table_name.to_s)}
|
96
|
-
SQL
|
97
|
-
|
98
|
-
rows.map do |row|
|
99
|
-
ForeignKeyDefinition.new(
|
100
|
-
row["name"],
|
101
|
-
row["from_table_name"], row["from_column_names"].split(","),
|
102
|
-
row["to_table_name"], row["to_column_names"].split(",")
|
103
|
-
)
|
104
|
-
end
|
105
|
-
end
|
106
|
-
|
107
|
-
end
|
108
|
-
|
109
|
-
end
|
@@ -1,27 +0,0 @@
|
|
1
|
-
module RedHillConsulting::Core::ActiveRecord::ConnectionAdapters
|
2
|
-
module TableDefinition
|
3
|
-
def self.included(base)
|
4
|
-
base.class_eval do
|
5
|
-
attr_accessor :name
|
6
|
-
alias_method_chain :initialize, :redhillonrails_core
|
7
|
-
alias_method_chain :to_sql, :redhillonrails_core
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
def initialize_with_redhillonrails_core(*args)
|
12
|
-
initialize_without_redhillonrails_core(*args)
|
13
|
-
@foreign_keys = []
|
14
|
-
end
|
15
|
-
|
16
|
-
def foreign_key(column_names, references_table_name, references_column_names, options = {})
|
17
|
-
@foreign_keys << ForeignKeyDefinition.new(options[:name], nil, column_names, ActiveRecord::Migrator.proper_table_name(references_table_name), references_column_names, options[:on_update], options[:on_delete], options[:deferrable])
|
18
|
-
self
|
19
|
-
end
|
20
|
-
|
21
|
-
def to_sql_with_redhillonrails_core
|
22
|
-
sql = to_sql_without_redhillonrails_core
|
23
|
-
sql << ', ' << @foreign_keys * ', ' unless @foreign_keys.empty? || ActiveRecord::Schema.defining?
|
24
|
-
sql
|
25
|
-
end
|
26
|
-
end
|
27
|
-
end
|
@@ -1,25 +0,0 @@
|
|
1
|
-
module RedHillConsulting::Core::ActiveRecord
|
2
|
-
module Schema
|
3
|
-
def self.included(base)
|
4
|
-
base.extend(ClassMethods)
|
5
|
-
end
|
6
|
-
|
7
|
-
module ClassMethods
|
8
|
-
def self.extended(base)
|
9
|
-
class << base
|
10
|
-
attr_accessor :defining
|
11
|
-
alias :defining? :defining
|
12
|
-
|
13
|
-
alias_method_chain :define, :redhillonrails_core
|
14
|
-
end
|
15
|
-
end
|
16
|
-
|
17
|
-
def define_with_redhillonrails_core(info={}, &block)
|
18
|
-
self.defining = true
|
19
|
-
define_without_redhillonrails_core(info, &block)
|
20
|
-
ensure
|
21
|
-
self.defining = false
|
22
|
-
end
|
23
|
-
end
|
24
|
-
end
|
25
|
-
end
|
@@ -1,66 +0,0 @@
|
|
1
|
-
module RedHillConsulting::Core::ActiveRecord
|
2
|
-
module SchemaDumper
|
3
|
-
def self.included(base)
|
4
|
-
base.class_eval do
|
5
|
-
private
|
6
|
-
alias_method_chain :tables, :redhillonrails_core
|
7
|
-
alias_method_chain :indexes, :redhillonrails_core
|
8
|
-
end
|
9
|
-
end
|
10
|
-
|
11
|
-
private
|
12
|
-
|
13
|
-
def tables_with_redhillonrails_core(stream)
|
14
|
-
@foreign_keys = StringIO.new
|
15
|
-
begin
|
16
|
-
tables_without_redhillonrails_core(stream)
|
17
|
-
@foreign_keys.rewind
|
18
|
-
stream.print @foreign_keys.read
|
19
|
-
views(stream)
|
20
|
-
ensure
|
21
|
-
@foreign_keys = nil
|
22
|
-
end
|
23
|
-
end
|
24
|
-
|
25
|
-
def indexes_with_redhillonrails_core(table, stream)
|
26
|
-
indexes = @connection.indexes(table)
|
27
|
-
indexes.each do |index|
|
28
|
-
if index.expression.blank? then
|
29
|
-
stream.print " add_index #{index.table.inspect}, #{index.columns.inspect}, :name => #{index.name.inspect}"
|
30
|
-
stream.print ", :unique => true" if index.unique
|
31
|
-
stream.print ", :case_sensitive => false" unless index.case_sensitive?
|
32
|
-
stream.print ", :conditions => #{index.conditions.inspect}" unless index.conditions.blank?
|
33
|
-
else
|
34
|
-
stream.print " add_index #{index.table.inspect}"
|
35
|
-
stream.print ", :expression => #{index.expression.inspect}"
|
36
|
-
stream.print ", :name => #{index.name.inspect}"
|
37
|
-
end
|
38
|
-
|
39
|
-
stream.puts
|
40
|
-
end
|
41
|
-
stream.puts unless indexes.empty?
|
42
|
-
|
43
|
-
foreign_keys(table, @foreign_keys)
|
44
|
-
end
|
45
|
-
|
46
|
-
def foreign_keys(table, stream)
|
47
|
-
foreign_keys = @connection.foreign_keys(table)
|
48
|
-
foreign_keys.each do |foreign_key|
|
49
|
-
stream.print " "
|
50
|
-
stream.print foreign_key.to_dump
|
51
|
-
stream.puts
|
52
|
-
end
|
53
|
-
stream.puts unless foreign_keys.empty?
|
54
|
-
end
|
55
|
-
|
56
|
-
def views(stream)
|
57
|
-
views = @connection.views
|
58
|
-
views.each do |view_name|
|
59
|
-
definition = @connection.view_definition(view_name)
|
60
|
-
stream.print " create_view #{view_name.inspect}, #{definition.inspect}"
|
61
|
-
stream.puts
|
62
|
-
end
|
63
|
-
stream.puts unless views.empty?
|
64
|
-
end
|
65
|
-
end
|
66
|
-
end
|
data/tasks/db/comments.rake
DELETED
@@ -1,9 +0,0 @@
|
|
1
|
-
namespace :db do
|
2
|
-
desc "Describe all the tables in the database by reading the table comments"
|
3
|
-
task :comments => :environment do
|
4
|
-
ActiveRecord::Base.connection.tables.sort.each do |table_name|
|
5
|
-
comment = ActiveRecord::Base.connection.table_comment(table_name)
|
6
|
-
puts "#{table_name} - #{comment}"
|
7
|
-
end
|
8
|
-
end
|
9
|
-
end
|