pg_saurus 2.1.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (47) hide show
  1. checksums.yaml +7 -0
  2. data/README.markdown +341 -0
  3. data/lib/colorized_text.rb +33 -0
  4. data/lib/core_ext/active_record/connection_adapters/abstract/schema_statements.rb +155 -0
  5. data/lib/core_ext/active_record/connection_adapters/postgresql_adapter.rb +191 -0
  6. data/lib/core_ext/active_record/errors.rb +6 -0
  7. data/lib/core_ext/active_record/schema_dumper.rb +42 -0
  8. data/lib/pg_saurus/connection_adapters/abstract_adapter/comment_methods.rb +80 -0
  9. data/lib/pg_saurus/connection_adapters/abstract_adapter/foreigner_methods.rb +67 -0
  10. data/lib/pg_saurus/connection_adapters/abstract_adapter/index_methods.rb +6 -0
  11. data/lib/pg_saurus/connection_adapters/abstract_adapter/schema_methods.rb +20 -0
  12. data/lib/pg_saurus/connection_adapters/abstract_adapter.rb +20 -0
  13. data/lib/pg_saurus/connection_adapters/foreign_key_definition.rb +5 -0
  14. data/lib/pg_saurus/connection_adapters/index_definition.rb +8 -0
  15. data/lib/pg_saurus/connection_adapters/postgresql_adapter/comment_methods.rb +114 -0
  16. data/lib/pg_saurus/connection_adapters/postgresql_adapter/extension_methods.rb +124 -0
  17. data/lib/pg_saurus/connection_adapters/postgresql_adapter/foreigner_methods.rb +221 -0
  18. data/lib/pg_saurus/connection_adapters/postgresql_adapter/index_methods.rb +42 -0
  19. data/lib/pg_saurus/connection_adapters/postgresql_adapter/schema_methods.rb +58 -0
  20. data/lib/pg_saurus/connection_adapters/postgresql_adapter/translate_exception.rb +20 -0
  21. data/lib/pg_saurus/connection_adapters/postgresql_adapter/view_methods.rb +17 -0
  22. data/lib/pg_saurus/connection_adapters/postgresql_adapter.rb +28 -0
  23. data/lib/pg_saurus/connection_adapters/table/comment_methods.rb +58 -0
  24. data/lib/pg_saurus/connection_adapters/table/foreigner_methods.rb +51 -0
  25. data/lib/pg_saurus/connection_adapters/table.rb +17 -0
  26. data/lib/pg_saurus/connection_adapters.rb +9 -0
  27. data/lib/pg_saurus/create_index_concurrently.rb +227 -0
  28. data/lib/pg_saurus/engine.rb +57 -0
  29. data/lib/pg_saurus/errors.rb +6 -0
  30. data/lib/pg_saurus/migration/command_recorder/comment_methods.rb +68 -0
  31. data/lib/pg_saurus/migration/command_recorder/extension_methods.rb +25 -0
  32. data/lib/pg_saurus/migration/command_recorder/foreigner_methods.rb +31 -0
  33. data/lib/pg_saurus/migration/command_recorder/schema_methods.rb +59 -0
  34. data/lib/pg_saurus/migration/command_recorder/view_methods.rb +31 -0
  35. data/lib/pg_saurus/migration/command_recorder.rb +17 -0
  36. data/lib/pg_saurus/migration.rb +4 -0
  37. data/lib/pg_saurus/schema_dumper/comment_methods.rb +51 -0
  38. data/lib/pg_saurus/schema_dumper/extension_methods.rb +29 -0
  39. data/lib/pg_saurus/schema_dumper/foreigner_methods.rb +63 -0
  40. data/lib/pg_saurus/schema_dumper/schema_methods.rb +27 -0
  41. data/lib/pg_saurus/schema_dumper/view_methods.rb +32 -0
  42. data/lib/pg_saurus/schema_dumper.rb +28 -0
  43. data/lib/pg_saurus/tools.rb +104 -0
  44. data/lib/pg_saurus/version.rb +4 -0
  45. data/lib/pg_saurus.rb +18 -0
  46. data/lib/tasks/pg_saurus_tasks.rake +4 -0
  47. metadata +226 -0
@@ -0,0 +1,124 @@
1
+ # Provides methods to extend {ActiveRecord::ConnectionAdapters::PostgreSQLAdapter}
2
+ # to support extensions feature.
3
+ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter::ExtensionMethods
4
+ # Default options for {#create_extension} method.
5
+ CREATE_EXTENSION_DEFAULTS = {
6
+ :if_not_exists => true,
7
+ :schema_name => nil,
8
+ :version => nil,
9
+ :old_version => nil
10
+ }
11
+
12
+ # Default options for {#drop_extension} method.
13
+ DROP_EXTENSION_DEFAULTS = {
14
+ :if_exists => true,
15
+ :mode => :restrict
16
+ }
17
+
18
+ # The modes which determine postgresql behavior on DROP EXTENSION operation.
19
+ #
20
+ # *:restrict* refuse to drop the extension if any objects depend on it
21
+ # *:cascade* automatically drop objects that depend on the extension
22
+ AVAILABLE_DROP_MODES = {
23
+ :restrict => 'RESTRICT',
24
+ :cascade => 'CASCADE'
25
+ }
26
+
27
+ # @return [Boolean] if adapter supports postgresql extension manipulation
28
+ def supports_extensions?
29
+ true
30
+ end
31
+
32
+ # Execute SQL to load a postgresql extension module into the current database.
33
+ #
34
+ # @param [#to_s] extension_name Name of the extension module to load
35
+ # @param [Hash] options
36
+ # @option options [Boolean] :if_not_exists should the 'IF NOT EXISTS' clause be added
37
+ # @option options [#to_s,nil] :schema_name The name of the schema in which to install the extension's objects
38
+ # @option options [#to_s,nil] :version The version of the extension to install
39
+ # @option options [#to_s,nil] :old_version Alternative installation script name
40
+ # that absorbs the existing objects into the extension, instead of creating new objects
41
+ def create_extension(extension_name, options = {})
42
+ options = CREATE_EXTENSION_DEFAULTS.merge(options.symbolize_keys)
43
+
44
+ sql = ['CREATE EXTENSION']
45
+ sql << 'IF NOT EXISTS' if options[:if_not_exists]
46
+ sql << %Q{"#{extension_name.to_s}"}
47
+ sql << "SCHEMA #{options[:schema_name]}" if options[:schema_name].present?
48
+ sql << "VERSION '#{options[:version]}'" if options[:version].present?
49
+ sql << "FROM #{options[:old_version]}" if options[:old_version].present?
50
+
51
+ sql = sql.join(' ')
52
+ execute(sql)
53
+ end
54
+
55
+ # Execute SQL to remove a postgresql extension module from the current database.
56
+ #
57
+ # @param [#to_s] extension_name Name of the extension module to unload
58
+ # @param [Hash] options
59
+ # @option options [Boolean] :if_exists should the 'IF EXISTS' clause be added
60
+ # @option options [Symbol] :mode Operation mode. See {AVAILABLE_DROP_MODES} for details
61
+ def drop_extension(extension_name, options = {})
62
+ options = DROP_EXTENSION_DEFAULTS.merge(options.symbolize_keys)
63
+
64
+ sql = ['DROP EXTENSION']
65
+ sql << 'IF EXISTS' if options[:if_exists]
66
+ sql << %Q{"#{extension_name.to_s}"}
67
+
68
+ mode = options[:mode]
69
+ if mode.present?
70
+ mode = mode.to_sym
71
+
72
+ unless AVAILABLE_DROP_MODES.include?(mode)
73
+ raise ArgumentError,
74
+ "Expected one of #{AVAILABLE_DROP_MODES.keys.inspect} drop modes, " \
75
+ "but #{mode} received"
76
+ end
77
+
78
+ sql << AVAILABLE_DROP_MODES[mode]
79
+ end
80
+
81
+ sql = sql.join(' ')
82
+ execute(sql)
83
+ end
84
+
85
+ # Query the pg_catalog for all extension modules loaded to the current database.
86
+ #
87
+ # @note
88
+ # Since Rails 4 connection has method +extensions+ that returns array of extensions.
89
+ # This method is slightly different, since it returns also additional options.
90
+ #
91
+ # Please note all extensions which belong to pg_catalog schema are omitted
92
+ # ===Example
93
+ #
94
+ # extension # => {
95
+ # "fuzzystrmatch" => {:schema_name => "public", :version => "1.0" }
96
+ # }
97
+ #
98
+ # @return [Hash{String => Hash{Symbol => String}}] A list of loaded extensions with their options
99
+ def pg_extensions
100
+ # Check postgresql version to not break on Postgresql < 9.1 during schema dump
101
+ pg_version_str = select_value('SELECT version()')
102
+ return {} unless pg_version_str =~ /^PostgreSQL (\d+\.\d+.\d+)/ && ($1 >= '9.1')
103
+
104
+ sql = <<-SQL
105
+ SELECT pge.extname AS ext_name, pgn.nspname AS schema_name, pge.extversion AS ext_version
106
+ FROM pg_extension pge
107
+ INNER JOIN pg_namespace pgn on pge.extnamespace = pgn.oid
108
+ WHERE pgn.nspname <> 'pg_catalog'
109
+ SQL
110
+
111
+ result = select_all(sql)
112
+ formatted_result = result.map do |row|
113
+ [
114
+ row['ext_name'],
115
+ {
116
+ :schema_name => row['schema_name'],
117
+ :version => row['ext_version']
118
+ }
119
+ ]
120
+ end
121
+
122
+ Hash[formatted_result]
123
+ end
124
+ end
@@ -0,0 +1,221 @@
1
+ module PgSaurus # :nodoc:
2
+ # Provides methods to extend {ActiveRecord::ConnectionAdapters::PostgreSQLAdapter}
3
+ # to support foreign keys feature.
4
+ module ConnectionAdapters::PostgreSQLAdapter::ForeignerMethods
5
+ def supports_foreign_keys?
6
+ true
7
+ end
8
+
9
+ # Fetch information about foreign keys related to the passed table.
10
+ # @param [String, Symbol] table_name name of table (e.g. "users", "music.bands")
11
+ # @return [Foreigner::ConnectionAdapters::ForeignKeyDefinition]
12
+ def foreign_keys(table_name)
13
+ relation, schema = table_name.to_s.split('.', 2).reverse
14
+ quoted_schema = schema ? "'#{schema}'" : "ANY (current_schemas(false))"
15
+
16
+ fk_info = select_all <<-SQL
17
+ SELECT nsp.nspname || '.' || t2.relname AS to_table,
18
+ a1.attname AS column ,
19
+ a2.attname AS primary_key,
20
+ c.conname AS name ,
21
+ c.confdeltype AS dependency
22
+ FROM pg_constraint c
23
+ JOIN pg_class t1 ON c.conrelid = t1.oid
24
+ JOIN pg_class t2 ON c.confrelid = t2.oid
25
+ JOIN pg_attribute a1 ON a1.attnum = c.conkey[1] AND a1.attrelid = t1.oid
26
+ JOIN pg_attribute a2 ON a2.attnum = c.confkey[1] AND a2.attrelid = t2.oid
27
+ JOIN pg_namespace t3 ON c.connamespace = t3.oid
28
+ JOIN pg_namespace nsp ON nsp.oid = t2.relnamespace
29
+ WHERE c.contype = 'f'
30
+ AND t1.relname = '#{relation}'
31
+ AND t3.nspname = #{quoted_schema}
32
+ ORDER BY c.conname
33
+ SQL
34
+
35
+ fk_info.map do |row|
36
+ options = { :column => row['column'],
37
+ :name => row['name'],
38
+ :primary_key => row['primary_key'] }
39
+
40
+ options[:dependent] =
41
+ case row['dependency']
42
+ when 'c' then :delete
43
+ when 'n' then :nullify
44
+ when 'r' then :restrict
45
+ end
46
+
47
+ PgSaurus::ConnectionAdapters::ForeignKeyDefinition.new(table_name, row['to_table'], options)
48
+ end
49
+ end
50
+
51
+ # Drop table and optionally disable triggers.
52
+ # Changes adapted from https://github.com/matthuhiggins/foreigner/blob/e72ab9c454c156056d3f037d55e3359cd972af32/lib/foreigner/connection_adapters/sql2003.rb
53
+ # NOTE: Disabling referential integrity requires superuser access in postgres.
54
+ # Default AR behavior is just to drop_table.
55
+ #
56
+ # == Options:
57
+ # * :force - force disabling of referential integrity
58
+ #
59
+ # Note: I don't know a good way to test this -mike 20120420
60
+ def drop_table(*args)
61
+ options = args.clone.extract_options!
62
+ if options[:force]
63
+ disable_referential_integrity { super }
64
+ else
65
+ super
66
+ end
67
+ end
68
+
69
+ # Add foreign key.
70
+ #
71
+ # Ensures that an index is created for the foreign key, unless :exclude_index is true.
72
+ #
73
+ # == Options:
74
+ # * :column
75
+ # * :primary_key
76
+ # * :dependent
77
+ # * :exclude_index [Boolean]
78
+ # * :concurrent_index [Boolean]
79
+ #
80
+ # @param [String, Symbol] from_table
81
+ # @param [String, Symbol] to_table
82
+ # @param [Hash] options
83
+ # @option options [String, Symbol] :column
84
+ # @option options [String, Symbol] :primary_key
85
+ # @option options [Hash] :dependent
86
+ # @option options [Boolean] :exclude_index
87
+ # @option options [Boolean] :concurrent_index
88
+ #
89
+ # @raise [PgSaurus::IndexExistsError] when :exclude_index is true, but the index already exists
90
+ def add_foreign_key(from_table, to_table, options = {})
91
+ options[:column] ||= id_column_name_from_table_name(to_table)
92
+ options[:exclude_index] ||= false
93
+
94
+ if index_exists?(from_table, options[:column]) && !options[:exclude_index]
95
+ raise PgSaurus::IndexExistsError,
96
+ "The index, #{index_name(from_table, options[:column])}, already exists." \
97
+ " Use :exclude_index => true when adding the foreign key."
98
+ end
99
+
100
+ sql = "ALTER TABLE #{quote_table_name(from_table)} #{add_foreign_key_sql(from_table, to_table, options)}"
101
+ execute(sql)
102
+
103
+ # GOTCHA:
104
+ # Index can not be created concurrently inside transaction in PostgreSQL.
105
+ # So, in case of concurrently created index with foreign key only
106
+ # foreign key will be created inside migration transaction and after
107
+ # closing transaction queries for index creation will be send to database.
108
+ # That's why I prevent here normal index creation in case of
109
+ # `concurrent_index` option is given.
110
+ # NOTE: Index creation after closing migration transaction could lead
111
+ # to weird effects when transaction moves smoothly, but index
112
+ # creation with error. In that case transaction will not be rolled back.
113
+ # As it was closed before even index was attempted to create.
114
+ # -- zekefast 2012-09-12
115
+ unless options[:exclude_index] || options[:concurrent_index]
116
+ add_index(from_table, options[:column])
117
+ end
118
+ end
119
+
120
+ # Return the SQL code fragment to add the foreign key based on the table names and options.
121
+ def add_foreign_key_sql(from_table, to_table, options = {})
122
+ column = options[:column]
123
+ options_options = options[:options]
124
+ foreign_key_name = foreign_key_name(from_table, column, options)
125
+ primary_key = options[:primary_key] || "id"
126
+ dependency = dependency_sql(options[:dependent])
127
+
128
+ sql =
129
+ "ADD CONSTRAINT #{quote_column_name(foreign_key_name)} " +
130
+ "FOREIGN KEY (#{quote_column_name(column)}) " +
131
+ "REFERENCES #{quote_table_name(ActiveRecord::Migrator.proper_table_name(to_table))}(#{primary_key})"
132
+ sql << " #{dependency}" if dependency.present?
133
+ sql << " #{options_options}" if options_options
134
+
135
+ sql
136
+ end
137
+
138
+ #
139
+ # TODO Determine if we can refactor the method signature
140
+ # remove_foreign_key(from_table, to_table_or_options_hash, options={}) => remove_foreign_key(from_table, to_table, options={})
141
+ #
142
+ # Remove the foreign key.
143
+ # @param [String, Symbol] from_table
144
+ # @param [String, Hash] to_table_or_options_hash
145
+ #
146
+ # The flexible method signature allows calls of two principal forms. Examples:
147
+ #
148
+ # remove_foreign_key(from_table, options_hash)
149
+ #
150
+ # or:
151
+ #
152
+ # remove_foreign_key(from_table, to_table, options_hash)
153
+ #
154
+ def remove_foreign_key(from_table, to_table_or_options_hash, options={})
155
+ if Hash === to_table_or_options_hash
156
+ options = to_table_or_options_hash
157
+ column = options[:column]
158
+ foreign_key_name = foreign_key_name(from_table, column, options)
159
+ column ||= id_column_name_from_foreign_key_metadata(from_table, foreign_key_name)
160
+ else
161
+ column = id_column_name_from_table_name(to_table_or_options_hash)
162
+ foreign_key_name = foreign_key_name(from_table, column)
163
+ end
164
+
165
+ execute "ALTER TABLE #{quote_table_name(from_table)} #{remove_foreign_key_sql(foreign_key_name)}"
166
+
167
+ options[:exclude_index] ||= false
168
+ unless options[:exclude_index] || !index_exists?(from_table, column) then
169
+ remove_index(from_table, column)
170
+ end
171
+ end
172
+
173
+ # Return the SQL code fragment to remove foreign key based on table name and options.
174
+ def remove_foreign_key_sql(foreign_key_name)
175
+ "DROP CONSTRAINT #{quote_column_name(foreign_key_name)}"
176
+ end
177
+
178
+ # Build the foreign key column id from the referenced table.
179
+ def id_column_name_from_table_name(table)
180
+ "#{table.to_s.split('.').last.singularize}_id"
181
+ end
182
+
183
+ # Extract the foreign key column id from the foreign key metadata.
184
+ # @param [String, Symbol] from_table
185
+ # @param [String] foreign_key_name
186
+ def id_column_name_from_foreign_key_metadata(from_table, foreign_key_name)
187
+ keys = foreign_keys(from_table)
188
+ this_key = keys.find {|key| key.options[:name] == foreign_key_name}
189
+ this_key.options[:column]
190
+ end
191
+ private :id_column_name_from_foreign_key_metadata
192
+
193
+ # Build default name for constraint.
194
+ def foreign_key_name(table, column, options = {})
195
+ name = options[:name]
196
+
197
+ if !name.nil? then
198
+ name
199
+ else
200
+ prefix = table.gsub(".", "_")
201
+ "#{prefix}_#{column}_fk"
202
+ end
203
+ end
204
+ private :foreign_key_name
205
+
206
+ # Get the SQL code fragment that represents dependency for a constraint.
207
+ #
208
+ # @param dependency [Symbol] :nullify, :delete or :restrict
209
+ #
210
+ # @return [String]
211
+ def dependency_sql(dependency)
212
+ case dependency
213
+ when :nullify then "ON DELETE SET NULL"
214
+ when :delete then "ON DELETE CASCADE"
215
+ when :restrict then "ON DELETE RESTRICT"
216
+ else ""
217
+ end
218
+ end
219
+ private :dependency_sql
220
+ end
221
+ end
@@ -0,0 +1,42 @@
1
+ # Provides methods to extend {ActiveRecord::ConnectionAdapters::SchemaStatements}
2
+ # to support index features.
3
+ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter::IndexMethods
4
+ def supports_partial_index?
5
+ true
6
+ end
7
+
8
+ # Overrides ActiveRecord::ConnectionAdapters::SchemaStatements.index_name
9
+ # to support schema notation. Converts dots in index name to underscores.
10
+ #
11
+ # === Example
12
+ # add_index 'demography.citizens', :country_id
13
+ # # produces
14
+ # CREATE INDEX "index_demography_citizens_on_country_id" ON "demography"."citizens" ("country_id")
15
+ # # instead of
16
+ # CREATE INDEX "index_demography.citizens_on_country_id" ON "demography"."citizens" ("country_id")
17
+ #
18
+ def index_name(table_name, options) #:nodoc:
19
+ super.gsub('.','_')
20
+ end
21
+
22
+ # Overrides ActiveRecord::ConnectionAdapters::SchemaStatements.index_name_for_remove
23
+ # to support schema notation. Prepends the schema name to the index name.
24
+ #
25
+ # === Example
26
+ # drop_index 'demography.citizens', :country_id
27
+ # # produces
28
+ # DROP INDEX "demography"."index_demography_citizens_on_country_id"
29
+ # # instead of
30
+ # DROP INDEX "index_demography_citizens_on_country_id"
31
+ #
32
+ def index_name_for_remove(table_name, options = {})
33
+ index_name = super
34
+
35
+ if table_name.include?('.') # schema notation
36
+ schema = table_name.split('.').first
37
+ "#{schema}.#{index_name}"
38
+ else
39
+ index_name
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,58 @@
1
+ # Provides methods to extend {ActiveRecord::ConnectionAdapters::PostgreSQLAdapter}
2
+ # to support schemas feature.
3
+ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter::SchemaMethods
4
+ # Creates new schema in DB.
5
+ # @param [String] schema_name
6
+ def create_schema(schema_name)
7
+ ::PgSaurus::Tools.create_schema(schema_name)
8
+ end
9
+
10
+ # Drops schema in DB.
11
+ # @param [String] schema_name
12
+ def drop_schema(schema_name)
13
+ ::PgSaurus::Tools.drop_schema(schema_name)
14
+ end
15
+
16
+ # Move table to another schema
17
+ # @param [String] table table name. Can be with schema prefix e.g. "demography.people"
18
+ # @param [String] schema schema where table should be moved to.
19
+ def move_table_to_schema(table, schema)
20
+ ::PgSaurus::Tools.move_table_to_schema(table, schema)
21
+ end
22
+
23
+ # Create schema if it does not exist yet.
24
+ #
25
+ # @param schema_name [String]
26
+ def create_schema_if_not_exists(schema_name)
27
+ ::PgSaurus::Tools.create_schema_if_not_exists(schema_name)
28
+ end
29
+
30
+ # Drop schema if it exists.
31
+ #
32
+ # @param schema_name [String]
33
+ def drop_schema_if_exists(schema_name)
34
+ ::PgSaurus::Tools.drop_schema_if_exists(schema_name)
35
+ end
36
+
37
+ # Make method +tables+ return tables not only from public schema.
38
+ #
39
+ # @note
40
+ # Tables from public schema have no "public." prefix. It's done for
41
+ # compatibility with other libraries that relies on a table name.
42
+ # Tables from other schemas has appropriate prefix with schema name.
43
+ # See: https://github.com/TMXCredit/pg_power/pull/42
44
+ #
45
+ # @return [Array<String>] table names
46
+ def tables_with_non_public_schema_tables(*args)
47
+ public_tables = tables_without_non_public_schema_tables(*args)
48
+
49
+ non_public_tables =
50
+ query(<<-SQL, 'SCHEMA').map { |row| row[0] }
51
+ SELECT schemaname || '.' || tablename AS table
52
+ FROM pg_tables
53
+ WHERE schemaname NOT IN ('pg_catalog', 'information_schema', 'public')
54
+ SQL
55
+
56
+ public_tables + non_public_tables
57
+ end
58
+ end
@@ -0,0 +1,20 @@
1
+ # Extend ActiveRecord::ConnectionAdapter::PostgreSQLAdapter logic
2
+ # to wrap more pg-specific errors into specific exception classes
3
+ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter::TranslateException
4
+ # # See http://www.postgresql.org/docs/9.1/static/errcodes-appendix.html
5
+ INSUFFICIENT_PRIVILEGE = "42501"
6
+
7
+ # Intercept insufficient privilege PGError and raise active_record wrapped database exception
8
+ def translate_exception(exception, message)
9
+ exception_result = exception.result
10
+
11
+ case exception_result.try(:error_field, PGresult::PG_DIAG_SQLSTATE)
12
+ when INSUFFICIENT_PRIVILEGE
13
+ exc_message = exception_result.try(:error_field, PGresult::PG_DIAG_MESSAGE_PRIMARY)
14
+ exc_message ||= message
15
+ ::ActiveRecord::InsufficientPrivilege.new(exc_message, exception)
16
+ else
17
+ super
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,17 @@
1
+ # Provides methods to extend {ActiveRecord::ConnectionAdapters::PostgreSQLAdapter}
2
+ # to support views feature.
3
+ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter::ViewMethods
4
+ # Creates new view in DB.
5
+ # @param [String, Symbol] view_name
6
+ # @param [String] view_definition
7
+ def create_view(view_name, view_definition)
8
+ ::PgSaurus::Tools.create_view(view_name, view_definition)
9
+ end
10
+
11
+ # Drops view in DB.
12
+ # @param [String, Symbol] view_name
13
+ def drop_view(view_name)
14
+ ::PgSaurus::Tools.drop_view(view_name)
15
+ end
16
+
17
+ end
@@ -0,0 +1,28 @@
1
+ # Provides methods to extend {ActiveRecord::ConnectionAdapters::PostgreSQLAdapter}
2
+ # to support pg_saurus features.
3
+ module PgSaurus::ConnectionAdapters::PostgreSQLAdapter
4
+ extend ActiveSupport::Autoload
5
+ extend ActiveSupport::Concern
6
+
7
+ # TODO: Looks like explicit path specification can be omitted -- aignatyev 20120904
8
+ autoload :ExtensionMethods, 'pg_saurus/connection_adapters/postgresql_adapter/extension_methods'
9
+ autoload :SchemaMethods, 'pg_saurus/connection_adapters/postgresql_adapter/schema_methods'
10
+ autoload :CommentMethods, 'pg_saurus/connection_adapters/postgresql_adapter/comment_methods'
11
+ autoload :ForeignerMethods, 'pg_saurus/connection_adapters/postgresql_adapter/foreigner_methods'
12
+ autoload :IndexMethods, 'pg_saurus/connection_adapters/postgresql_adapter/index_methods'
13
+ autoload :TranslateException, 'pg_saurus/connection_adapters/postgresql_adapter/translate_exception'
14
+ autoload :ViewMethods, 'pg_saurus/connection_adapters/postgresql_adapter/view_methods'
15
+
16
+ include ExtensionMethods
17
+ include SchemaMethods
18
+ include CommentMethods
19
+ include ForeignerMethods
20
+ include IndexMethods
21
+ include TranslateException
22
+ include ViewMethods
23
+
24
+ included do
25
+ alias_method_chain :tables, :non_public_schema_tables
26
+ alias_method_chain :add_index, :concurrently
27
+ end
28
+ end
@@ -0,0 +1,58 @@
1
+ # Provides methods to extend ActiveRecord::ConnectionAdapters::Table
2
+ # to support comments feature.
3
+ module PgSaurus::ConnectionAdapters::Table::CommentMethods
4
+ # Set the comment on the table.
5
+ #
6
+ # ===== Example
7
+ # ====== Set comment on table
8
+ # t.set_table_comment 'This table stores phone numbers that conform to the North American Numbering Plan.'
9
+ def set_table_comment(comment)
10
+ @base.set_table_comment(@table_name, comment)
11
+ end
12
+
13
+ # Remove any comment from the table.
14
+ #
15
+ # ===== Example
16
+ # ====== Remove table comment
17
+ # t.remove_table_comment
18
+ def remove_table_comment
19
+ @base.remove_table_comment(@table_name)
20
+ end
21
+
22
+ # Set the comment for a given column.
23
+ #
24
+ # ===== Example
25
+ # ====== Set comment on the npa column
26
+ # t.set_column_comment :npa, 'Numbering Plan Area Code - Allowed ranges: [2-9] for first digit, [0-9] for second and third digit.'
27
+ def set_column_comment(column_name, comment)
28
+ @base.set_column_comment(@table_name, column_name, comment)
29
+ end
30
+
31
+ # Set comments on multiple columns. 'comments' is a hash of column_name => comment pairs.
32
+ #
33
+ # ===== Example
34
+ # ====== Setting comments on the columns of the phone_numbers table
35
+ # t.set_column_comments :npa => 'Numbering Plan Area Code - Allowed ranges: [2-9] for first digit, [0-9] for second and third digit.',
36
+ # :nxx => 'Central Office Number'
37
+ def set_column_comments(comments)
38
+ @base.set_column_comments(@table_name, comments)
39
+ end
40
+
41
+ # Remove any comment for a given column.
42
+ #
43
+ # ===== Example
44
+ # ====== Remove comment from the npa column
45
+ # t.remove_column_comment :npa
46
+ def remove_column_comment(column_name)
47
+ @base.remove_column_comment(@table_name, column_name)
48
+ end
49
+
50
+ # Remove any comments from the given columns.
51
+ #
52
+ # ===== Example
53
+ # ====== Remove comment from the npa and nxx columns
54
+ # t.remove_column_comment :npa, :nxx
55
+ def remove_column_comments(*column_names)
56
+ @base.remove_column_comments(@table_name, *column_names)
57
+ end
58
+ end
@@ -0,0 +1,51 @@
1
+ # Provides methods to extend ActiveRecord::ConnectionAdapters::Table
2
+ # to support foreign keys feature.
3
+ module PgSaurus::ConnectionAdapters::Table::ForeignerMethods
4
+ # Adds a new foreign key to the table. +to_table+ can be a single Symbol, or
5
+ # an Array of Symbols. See SchemaStatements#add_foreign_key
6
+ #
7
+ # ===== Examples
8
+ # ====== Creating a simple foreign key
9
+ # t.foreign_key(:people)
10
+ # ====== Defining the column
11
+ # t.foreign_key(:people, :column => :sender_id)
12
+ # ====== Creating a named foreign key
13
+ # t.foreign_key(:people, :column => :sender_id, :name => 'sender_foreign_key')
14
+ # ====== Defining the column of the +to_table+.
15
+ # t.foreign_key(:people, :column => :sender_id, :primary_key => :person_id)
16
+ def foreign_key(to_table, options = {})
17
+ @base.add_foreign_key(@table_name, to_table, options)
18
+ end
19
+
20
+ # Remove the given foreign key from the table.
21
+ #
22
+ # ===== Examples
23
+ # ====== Remove the suppliers_company_id_fk in the suppliers table.
24
+ # change_table :suppliers do |t|
25
+ # t.remove_foreign_key :companies
26
+ # end
27
+ # ====== Remove the foreign key named accounts_branch_id_fk in the accounts table.
28
+ # change_table :accounts do |t|
29
+ # t.remove_foreign_key :column => :branch_id
30
+ # end
31
+ # ====== Remove the foreign key named party_foreign_key in the accounts table.
32
+ # change_table :accounts do |t|
33
+ # t.remove_index :name => :party_foreign_key
34
+ # end
35
+ def remove_foreign_key(options)
36
+ @base.remove_foreign_key(@table_name, options)
37
+ end
38
+
39
+ # Deprecated
40
+ def references_with_foreign_keys(*args)
41
+ options = args.extract_options!
42
+
43
+ if options.delete(:foreign_key)
44
+ p ActiveSupport::Deprecation.send(:deprecation_message, caller,
45
+ ":foreign_key in t.references is deprecated. " \
46
+ "Use t.foreign_key instead")
47
+ end
48
+
49
+ references_without_foreign_keys(*(args.dup << options))
50
+ end
51
+ end
@@ -0,0 +1,17 @@
1
+ # Provides methods to extend ActiveRecord::ConnectionAdapters::Table
2
+ # to support pg_saurus features.
3
+ module PgSaurus::ConnectionAdapters::Table
4
+ extend ActiveSupport::Autoload
5
+ extend ActiveSupport::Concern
6
+
7
+ autoload :CommentMethods
8
+ autoload :ForeignerMethods
9
+
10
+ include CommentMethods
11
+ include ForeignerMethods
12
+
13
+
14
+ included do
15
+ alias_method_chain :references, :foreign_keys
16
+ end
17
+ end
@@ -0,0 +1,9 @@
1
+ module PgSaurus::ConnectionAdapters # :nodoc:
2
+ extend ActiveSupport::Autoload
3
+
4
+ autoload :AbstractAdapter
5
+ autoload :PostgreSQLAdapter, 'pg_saurus/connection_adapters/postgresql_adapter'
6
+ autoload :Table
7
+ autoload :ForeignKeyDefinition
8
+ autoload :IndexDefinition, 'pg_saurus/connection_adapters/index_definition'
9
+ end