pg_saurus 2.1.1

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.
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