activerecord-postgresql-extensions 0.0.12 → 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 +18 -0
- data/Gemfile +3 -0
- data/MIT-LICENSE +1 -1
- data/README.rdoc +7 -2
- data/Rakefile +4 -17
- data/activerecord-postgresql-extensions.gemspec +13 -57
- data/lib/{postgresql_extensions/postgresql_adapter_extensions.rb → active_record/postgresql_extensions/adapter_extensions.rb} +44 -46
- data/lib/{postgresql_extensions/postgresql_constraints.rb → active_record/postgresql_extensions/constraints.rb} +121 -10
- data/lib/{postgresql_extensions/postgresql_extensions.rb → active_record/postgresql_extensions/extensions.rb} +1 -1
- data/lib/{postgresql_extensions → active_record/postgresql_extensions}/foreign_key_associations.rb +9 -1
- data/lib/{postgresql_extensions/postgresql_functions.rb → active_record/postgresql_extensions/functions.rb} +9 -3
- data/lib/{postgresql_extensions/postgresql_geometry.rb → active_record/postgresql_extensions/geometry.rb} +111 -35
- data/lib/{postgresql_extensions/postgresql_indexes.rb → active_record/postgresql_extensions/indexes.rb} +4 -2
- data/lib/{postgresql_extensions/postgresql_languages.rb → active_record/postgresql_extensions/languages.rb} +1 -1
- data/lib/{postgresql_extensions/postgresql_permissions.rb → active_record/postgresql_extensions/permissions.rb} +3 -3
- data/lib/active_record/postgresql_extensions/postgis.rb +53 -0
- data/lib/{postgresql_extensions/postgresql_roles.rb → active_record/postgresql_extensions/roles.rb} +1 -1
- data/lib/{postgresql_extensions/postgresql_rules.rb → active_record/postgresql_extensions/rules.rb} +3 -3
- data/lib/{postgresql_extensions/postgresql_schemas.rb → active_record/postgresql_extensions/schemas.rb} +1 -1
- data/lib/{postgresql_extensions/postgresql_sequences.rb → active_record/postgresql_extensions/sequences.rb} +2 -2
- data/lib/{postgresql_extensions/postgresql_tables.rb → active_record/postgresql_extensions/tables.rb} +18 -4
- data/lib/{postgresql_extensions/postgresql_tablespaces.rb → active_record/postgresql_extensions/tablespaces.rb} +1 -1
- data/lib/{postgresql_extensions/postgresql_text_search.rb → active_record/postgresql_extensions/text_search.rb} +3 -3
- data/lib/{postgresql_extensions/postgresql_triggers.rb → active_record/postgresql_extensions/triggers.rb} +1 -1
- data/lib/{postgresql_extensions/postgresql_types.rb → active_record/postgresql_extensions/types.rb} +1 -1
- data/lib/active_record/postgresql_extensions/utils.rb +23 -0
- data/lib/active_record/postgresql_extensions/version.rb +7 -0
- data/lib/{postgresql_extensions/postgresql_views.rb → active_record/postgresql_extensions/views.rb} +2 -2
- data/lib/activerecord-postgresql-extensions.rb +23 -22
- data/test/adapter_tests.rb +9 -9
- data/test/constraints_tests.rb +155 -0
- data/test/database.yml +17 -0
- data/test/geometry_tests.rb +224 -52
- data/test/index_tests.rb +16 -1
- data/test/rules_tests.rb +4 -4
- data/test/sequences_tests.rb +0 -22
- data/test/tables_tests.rb +28 -31
- data/test/test_helper.rb +70 -23
- data/test/trigger_tests.rb +5 -5
- metadata +112 -25
- data/VERSION +0 -1
data/.gitignore
ADDED
data/Gemfile
ADDED
data/MIT-LICENSE
CHANGED
data/README.rdoc
CHANGED
@@ -12,7 +12,7 @@ PostgreSQL adapter including:
|
|
12
12
|
functions, sequences, views, schemas and triggers.
|
13
13
|
|
14
14
|
* better support for creating indexes with expressions so you can use functions
|
15
|
-
and
|
15
|
+
and GiST and GIN indexes.
|
16
16
|
|
17
17
|
* support for manipulating role privileges.
|
18
18
|
|
@@ -20,10 +20,15 @@ PostgreSQL adapter including:
|
|
20
20
|
creating tables.
|
21
21
|
|
22
22
|
* support for automatically detecting foreign key relationships and building
|
23
|
-
ActiveRecord associations accordingly. This associations can be
|
23
|
+
ActiveRecord associations accordingly. This associations can be overridden
|
24
24
|
as necessary and are sane enough that they won't try to overwrite existing
|
25
25
|
associations.
|
26
26
|
|
27
|
+
* support for some PostGIS functionality including some support for using
|
28
|
+
PostGIS columns in migrations. For manipulating PostGIS data, see our
|
29
|
+
geos-extensions gem at https://github.com/zoocasa/geos-extensions or
|
30
|
+
the RGeo project at https://github.com/dazuma/rgeo .
|
31
|
+
|
27
32
|
== First Public Release Notice!
|
28
33
|
|
29
34
|
This is the first public release of this gem, so while it has been kind to us
|
data/Rakefile
CHANGED
@@ -8,6 +8,7 @@ gem 'rdoc', '~> 3.12'
|
|
8
8
|
require 'rubygems/package_task'
|
9
9
|
require 'rake/testtask'
|
10
10
|
require 'rdoc/task'
|
11
|
+
require 'bundler/gem_tasks'
|
11
12
|
|
12
13
|
if RUBY_VERSION >= '1.9'
|
13
14
|
begin
|
@@ -19,27 +20,13 @@ end
|
|
19
20
|
|
20
21
|
$:.push 'lib'
|
21
22
|
|
22
|
-
version =
|
23
|
-
|
24
|
-
begin
|
25
|
-
require 'jeweler'
|
26
|
-
Jeweler::Tasks.new do |gem|
|
27
|
-
gem.name = "activerecord-postgresql-extensions"
|
28
|
-
gem.summary = "A whole bunch of extensions the ActiveRecord PostgreSQL adapter."
|
29
|
-
gem.description = gem.summary
|
30
|
-
gem.email = "code@zoocasa.com"
|
31
|
-
gem.homepage = "http://github.com/zoocasa/activerecord-postgresql-extensions"
|
32
|
-
gem.authors = [ "J Smith" ]
|
33
|
-
end
|
34
|
-
Jeweler::GemcutterTasks.new
|
35
|
-
rescue LoadError
|
36
|
-
puts "Jeweler (or a dependency) not available. Install it with: sudo gem install jeweler"
|
37
|
-
end
|
23
|
+
version = ActiveRecord::PostgreSQLExtensions::VERSION
|
38
24
|
|
39
25
|
desc 'Test PostgreSQL extensions'
|
40
26
|
Rake::TestTask.new(:test) do |t|
|
41
27
|
t.test_files = FileList['test/**/*_tests.rb']
|
42
|
-
t.verbose =
|
28
|
+
t.verbose = !!ENV['VERBOSE_TESTS']
|
29
|
+
t.warning = !!ENV['WARNINGS']
|
43
30
|
end
|
44
31
|
|
45
32
|
desc 'Build docs'
|
@@ -1,76 +1,32 @@
|
|
1
|
-
# Generated by jeweler
|
2
|
-
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
-
# Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
|
4
1
|
# -*- encoding: utf-8 -*-
|
5
2
|
|
3
|
+
require File.expand_path('../lib/active_record/postgresql_extensions/version', __FILE__)
|
4
|
+
|
6
5
|
Gem::Specification.new do |s|
|
7
6
|
s.name = "activerecord-postgresql-extensions"
|
8
|
-
s.version =
|
7
|
+
s.version = ActiveRecord::PostgreSQLExtensions::VERSION
|
9
8
|
|
10
9
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
10
|
s.authors = ["J Smith"]
|
12
|
-
s.date = "2012-03-22"
|
13
11
|
s.description = "A whole bunch of extensions the ActiveRecord PostgreSQL adapter."
|
12
|
+
s.summary = s.description
|
14
13
|
s.email = "code@zoocasa.com"
|
15
14
|
s.extra_rdoc_files = [
|
16
15
|
"README.rdoc"
|
17
16
|
]
|
18
|
-
s.files =
|
19
|
-
|
20
|
-
|
21
|
-
"Rakefile",
|
22
|
-
"VERSION",
|
23
|
-
"activerecord-postgresql-extensions.gemspec",
|
24
|
-
"lib/activerecord-postgresql-extensions.rb",
|
25
|
-
"lib/postgresql_extensions/foreign_key_associations.rb",
|
26
|
-
"lib/postgresql_extensions/postgresql_adapter_extensions.rb",
|
27
|
-
"lib/postgresql_extensions/postgresql_constraints.rb",
|
28
|
-
"lib/postgresql_extensions/postgresql_extensions.rb",
|
29
|
-
"lib/postgresql_extensions/postgresql_functions.rb",
|
30
|
-
"lib/postgresql_extensions/postgresql_geometry.rb",
|
31
|
-
"lib/postgresql_extensions/postgresql_indexes.rb",
|
32
|
-
"lib/postgresql_extensions/postgresql_languages.rb",
|
33
|
-
"lib/postgresql_extensions/postgresql_permissions.rb",
|
34
|
-
"lib/postgresql_extensions/postgresql_roles.rb",
|
35
|
-
"lib/postgresql_extensions/postgresql_rules.rb",
|
36
|
-
"lib/postgresql_extensions/postgresql_schemas.rb",
|
37
|
-
"lib/postgresql_extensions/postgresql_sequences.rb",
|
38
|
-
"lib/postgresql_extensions/postgresql_tables.rb",
|
39
|
-
"lib/postgresql_extensions/postgresql_tablespaces.rb",
|
40
|
-
"lib/postgresql_extensions/postgresql_text_search.rb",
|
41
|
-
"lib/postgresql_extensions/postgresql_triggers.rb",
|
42
|
-
"lib/postgresql_extensions/postgresql_types.rb",
|
43
|
-
"lib/postgresql_extensions/postgresql_views.rb",
|
44
|
-
"test/adapter_tests.rb",
|
45
|
-
"test/constraints_tests.rb",
|
46
|
-
"test/extensions_tests.rb",
|
47
|
-
"test/functions_tests.rb",
|
48
|
-
"test/geometry_tests.rb",
|
49
|
-
"test/index_tests.rb",
|
50
|
-
"test/languages_tests.rb",
|
51
|
-
"test/permissions_tests.rb",
|
52
|
-
"test/roles_tests.rb",
|
53
|
-
"test/rules_tests.rb",
|
54
|
-
"test/schemas_tests.rb",
|
55
|
-
"test/sequences_tests.rb",
|
56
|
-
"test/tables_tests.rb",
|
57
|
-
"test/tablespace_tests.rb",
|
58
|
-
"test/test_helper.rb",
|
59
|
-
"test/text_search_tests.rb",
|
60
|
-
"test/trigger_tests.rb"
|
61
|
-
]
|
17
|
+
s.files = `git ls-files`.split($\)
|
18
|
+
s.executables = s.files.grep(%r{^bin/}).map { |f| File.basename(f) }
|
19
|
+
s.test_files = s.files.grep(%r{^(test|spec|features)/})
|
62
20
|
s.homepage = "http://github.com/zoocasa/activerecord-postgresql-extensions"
|
63
21
|
s.require_paths = ["lib"]
|
64
|
-
s.rubygems_version = "1.8.15"
|
65
|
-
s.summary = "A whole bunch of extensions the ActiveRecord PostgreSQL adapter."
|
66
|
-
|
67
|
-
if s.respond_to? :specification_version then
|
68
|
-
s.specification_version = 3
|
69
22
|
|
70
|
-
|
71
|
-
|
72
|
-
|
23
|
+
s.add_dependency("activerecord", [">= 2.3"])
|
24
|
+
if RUBY_PLATFORM == "java"
|
25
|
+
s.add_dependency("activerecord-jdbcpostgresql-adapter")
|
73
26
|
else
|
27
|
+
s.add_dependency("pg")
|
74
28
|
end
|
29
|
+
s.add_dependency("rdoc")
|
30
|
+
s.add_dependency("rake", ["~> 0.9"])
|
75
31
|
end
|
76
32
|
|
@@ -1,12 +1,13 @@
|
|
1
1
|
|
2
2
|
module ActiveRecord
|
3
3
|
module ConnectionAdapters
|
4
|
-
class PostgreSQLAdapter
|
4
|
+
class PostgreSQLAdapter
|
5
5
|
if defined?(Rails)
|
6
6
|
LOGGER_REGEXP = /^#{Rails.root}(?!\/vendor\/rails)/
|
7
7
|
|
8
|
-
def query_with_extra_logging(
|
8
|
+
def query_with_extra_logging(*args) #:nodoc:
|
9
9
|
if ActiveRecord::Base.enable_extended_logging && Rails.logger && Rails.logger.level == Logger::DEBUG
|
10
|
+
sql = args.first
|
10
11
|
unless (sql =~ /(pg_get_constraintdef|pg_attribute|pg_class)/)
|
11
12
|
Rails.logger.debug
|
12
13
|
Rails.logger.debug(caller.select { |x|
|
@@ -14,12 +15,13 @@ module ActiveRecord
|
|
14
15
|
}.join("\n"))
|
15
16
|
end
|
16
17
|
end
|
17
|
-
query_without_extra_logging(
|
18
|
+
query_without_extra_logging(*args)
|
18
19
|
end
|
19
20
|
alias_method_chain :query, :extra_logging
|
20
21
|
|
21
|
-
def execute_with_extra_logging(
|
22
|
+
def execute_with_extra_logging(*args) #:nodoc:
|
22
23
|
if ActiveRecord::Base.enable_extended_logging && Rails.logger && Rails.logger.level == Logger::DEBUG
|
24
|
+
sql = args.first
|
23
25
|
unless (sql =~ /(pg_get_constraintdef|pg_attribute|pg_class)/)
|
24
26
|
Rails.logger.debug
|
25
27
|
Rails.logger.debug(caller.select { |x|
|
@@ -27,29 +29,11 @@ module ActiveRecord
|
|
27
29
|
}.join("\n"))
|
28
30
|
end
|
29
31
|
end
|
30
|
-
execute_without_extra_logging(
|
32
|
+
execute_without_extra_logging(*args)
|
31
33
|
end
|
32
34
|
alias_method_chain :execute, :extra_logging
|
33
35
|
end
|
34
36
|
|
35
|
-
# There seems to be a bug in ActiveRecord where it isn't setting
|
36
|
-
# the schema search path properly because it's using ',' as a
|
37
|
-
# separator rather than /,\s+/.
|
38
|
-
def schema_search_path_with_fix_csv=(schema_csv)
|
39
|
-
if schema_csv
|
40
|
-
csv = schema_csv.gsub(/,\s+/, ',')
|
41
|
-
execute "SET search_path TO #{csv}"
|
42
|
-
@schema_search_path = csv
|
43
|
-
end
|
44
|
-
end
|
45
|
-
alias_method_chain :schema_search_path=, :fix_csv
|
46
|
-
|
47
|
-
# Fix ActiveRecord bug when grabbing the current search_path.
|
48
|
-
def schema_search_path_with_fix_csv
|
49
|
-
@schema_search_path ||= query('SHOW search_path')[0][0].gsub(/,\s+/, ',')
|
50
|
-
end
|
51
|
-
alias_method_chain :schema_search_path, :fix_csv
|
52
|
-
|
53
37
|
# with_schema is kind of like with_scope. It wraps various
|
54
38
|
# object names in SQL statements into a PostgreSQL schema. You
|
55
39
|
# can have multiple with_schemas wrapped around each other, and
|
@@ -82,7 +66,7 @@ module ActiveRecord
|
|
82
66
|
#
|
83
67
|
# with_schema :geospatial do
|
84
68
|
# create_table(:test) do |t|
|
85
|
-
#
|
69
|
+
# ignore_scoped_schema do
|
86
70
|
# t.integer(
|
87
71
|
# :ref_id,
|
88
72
|
# :references => {
|
@@ -106,11 +90,11 @@ module ActiveRecord
|
|
106
90
|
# Here we see that we used the geospatial schema when naming the
|
107
91
|
# test table and dropped back to not specifying a schema when
|
108
92
|
# setting up the foreign key to the refs table. If we had not
|
109
|
-
# used
|
93
|
+
# used ignore_scoped_schema, the foreign key would have been defined
|
110
94
|
# thusly:
|
111
95
|
#
|
112
96
|
# FOREIGN KEY ("ref_id") REFERENCES "geospatial"."refs" ("id")
|
113
|
-
def
|
97
|
+
def ignore_scoped_schema
|
114
98
|
with_schema nil do
|
115
99
|
yield
|
116
100
|
end
|
@@ -124,18 +108,24 @@ module ActiveRecord
|
|
124
108
|
end
|
125
109
|
|
126
110
|
# Get the current scoped schema.
|
127
|
-
def
|
111
|
+
def current_scoped_schema
|
128
112
|
scoped_schemas.last
|
129
113
|
end
|
130
114
|
|
131
115
|
# A generic quoting method for PostgreSQL.
|
132
|
-
|
133
|
-
|
116
|
+
if RUBY_PLATFORM == 'java'
|
117
|
+
def quote_generic(g)
|
118
|
+
quote_column_name(g)
|
119
|
+
end
|
120
|
+
else
|
121
|
+
def quote_generic(g)
|
122
|
+
PGconn.quote_ident(g.to_s)
|
123
|
+
end
|
134
124
|
end
|
135
125
|
|
136
126
|
# A generic quoting method for PostgreSQL that specifically ignores
|
137
127
|
# any and all schemas.
|
138
|
-
def
|
128
|
+
def quote_generic_ignore_scoped_schema(g)
|
139
129
|
if g.is_a?(Hash)
|
140
130
|
quote_generic g.values.first
|
141
131
|
else
|
@@ -149,8 +139,8 @@ module ActiveRecord
|
|
149
139
|
if g.is_a?(Hash)
|
150
140
|
"#{quote_schema(g.keys.first)}.#{quote_generic(g.values.first)}"
|
151
141
|
else
|
152
|
-
if
|
153
|
-
quote_schema(
|
142
|
+
if current_scoped_schema
|
143
|
+
quote_schema(current_scoped_schema) << '.'
|
154
144
|
end.to_s << quote_generic(g)
|
155
145
|
end
|
156
146
|
end
|
@@ -215,13 +205,13 @@ module ActiveRecord
|
|
215
205
|
# # => "geospatial"."epois"
|
216
206
|
#
|
217
207
|
# with_schema(:geospatial) do
|
218
|
-
#
|
208
|
+
# ignore_scoped_schema do
|
219
209
|
# quote_table_name(:epois)
|
220
210
|
# end
|
221
211
|
# end
|
222
212
|
# # => "epois"
|
223
213
|
def quote_table_name_with_schemas(name)
|
224
|
-
if
|
214
|
+
if current_scoped_schema || name.is_a?(Hash)
|
225
215
|
quote_generic_with_schema(name)
|
226
216
|
else
|
227
217
|
quote_table_name_without_schemas(name)
|
@@ -472,15 +462,21 @@ module ActiveRecord
|
|
472
462
|
end
|
473
463
|
alias_method_chain :tables, :views
|
474
464
|
|
475
|
-
|
476
|
-
|
477
|
-
|
478
|
-
|
465
|
+
unless RUBY_PLATFORM == "java"
|
466
|
+
# There seems to be a bug in ActiveRecord where it isn't setting
|
467
|
+
# the schema search path properly because it's using ',' as a
|
468
|
+
# separator rather than /,\s+/.
|
469
|
+
def schema_search_path_with_csv_fix=(schema_csv) #:nodoc:
|
470
|
+
self.schema_search_path_without_csv_fix = schema_csv.gsub(/,\s+/, ',') if schema_csv
|
471
|
+
end
|
472
|
+
alias_method_chain :schema_search_path=, :csv_fix
|
479
473
|
|
480
|
-
|
481
|
-
|
474
|
+
# Fix ActiveRecord bug when grabbing the current search_path.
|
475
|
+
def schema_search_path_with_csv_fix
|
476
|
+
@schema_search_path ||= query('SHOW search_path;')[0][0].gsub(/,\s+/, ',')
|
477
|
+
end
|
478
|
+
alias_method_chain :schema_search_path, :csv_fix
|
482
479
|
end
|
483
|
-
alias_method_chain :schema_search_path, :csv_fix
|
484
480
|
|
485
481
|
def disable_referential_integrity_with_views #:nodoc:
|
486
482
|
if supports_disable_referential_integrity? then
|
@@ -682,11 +678,13 @@ module ActiveRecord
|
|
682
678
|
alias_method_chain :change_column_default, :expression
|
683
679
|
end
|
684
680
|
|
685
|
-
class PostgreSQLColumn
|
681
|
+
class PostgreSQLColumn
|
686
682
|
def simplified_type_with_additional_types(field_type)
|
687
683
|
case field_type
|
688
684
|
when 'geometry'
|
689
685
|
:geometry
|
686
|
+
when 'geography'
|
687
|
+
:geography
|
690
688
|
when 'tsvector'
|
691
689
|
:tsvector
|
692
690
|
else
|
@@ -707,8 +705,8 @@ module ActiveRecord
|
|
707
705
|
}
|
708
706
|
end
|
709
707
|
|
710
|
-
def
|
711
|
-
self.connection.
|
708
|
+
def ignore_scoped_schema
|
709
|
+
self.connection.ignore_scoped_schema { |*block_args|
|
712
710
|
yield(*block_args)
|
713
711
|
}
|
714
712
|
end
|
@@ -717,8 +715,8 @@ module ActiveRecord
|
|
717
715
|
self.connection.scope_schemas
|
718
716
|
end
|
719
717
|
|
720
|
-
def
|
721
|
-
self.connection.
|
718
|
+
def current_scoped_schema
|
719
|
+
self.connection.current_scoped_schema
|
722
720
|
end
|
723
721
|
|
724
722
|
def sequence_exists?
|
@@ -1,4 +1,7 @@
|
|
1
1
|
|
2
|
+
require 'active_record/connection_adapters/postgresql_adapter'
|
3
|
+
require 'active_record/postgresql_extensions/utils'
|
4
|
+
|
2
5
|
module ActiveRecord
|
3
6
|
class InvalidForeignKeyAction < ActiveRecordError #:nodoc:
|
4
7
|
def initialize(action)
|
@@ -25,7 +28,7 @@ module ActiveRecord
|
|
25
28
|
end
|
26
29
|
|
27
30
|
module ConnectionAdapters
|
28
|
-
class PostgreSQLAdapter
|
31
|
+
class PostgreSQLAdapter
|
29
32
|
# Adds a CHECK constraint to the table. See
|
30
33
|
# PostgreSQLCheckConstraint for usage.
|
31
34
|
def add_check_constraint(table, expression, options = {})
|
@@ -50,8 +53,16 @@ module ActiveRecord
|
|
50
53
|
execute("#{sql};")
|
51
54
|
end
|
52
55
|
|
56
|
+
# Adds an EXCLUDE constraint to the table. See
|
57
|
+
# PostgreSQLExcludeConstraint for details.
|
58
|
+
def add_exclude_constraint(table, excludes, options = {})
|
59
|
+
sql = "ALTER TABLE #{quote_table_name(table)} ADD "
|
60
|
+
sql << PostgreSQLExcludeConstraint.new(self, table, excludes, options).to_s
|
61
|
+
execute("#{sql};")
|
62
|
+
end
|
63
|
+
|
53
64
|
# Drops a constraint from the table. Use this to drop CHECK,
|
54
|
-
# UNIQUE and FOREIGN KEY constraints from a table.
|
65
|
+
# UNIQUE, EXCLUDE and FOREIGN KEY constraints from a table.
|
55
66
|
#
|
56
67
|
# Options:
|
57
68
|
#
|
@@ -304,7 +315,7 @@ module ActiveRecord
|
|
304
315
|
# PostgreSQLAdapter#create_index method similarly. The create_index
|
305
316
|
# method adds a couple of PostgreSQL-specific options if you need them.
|
306
317
|
#
|
307
|
-
# ==== Examples
|
318
|
+
# ==== Examples
|
308
319
|
#
|
309
320
|
# # using the constraint method:
|
310
321
|
# add_unique_constraint(:foo, [ :fancy_id, :another_fancy_id ])
|
@@ -335,7 +346,8 @@ module ActiveRecord
|
|
335
346
|
# couple of additional parameters to indexes to govern disk usage and
|
336
347
|
# such. This option is a simple String that lets you insert these
|
337
348
|
# options as necessary. See the PostgreSQL documentation on index
|
338
|
-
# storage parameters for details.
|
349
|
+
# storage parameters for details. <tt>:index_parameters</tt> can also
|
350
|
+
# be used.
|
339
351
|
# * <tt>:tablespace</tt> - allows you to specify a tablespace for the
|
340
352
|
# unique index being created. See the PostgreSQL documentation on
|
341
353
|
# tablespaces for details.
|
@@ -363,7 +375,7 @@ module ActiveRecord
|
|
363
375
|
sql = "#{constraint_name}UNIQUE ("
|
364
376
|
sql << Array(columns).collect { |c| base.quote_column_name(c) }.join(', ')
|
365
377
|
sql << ")"
|
366
|
-
sql << " WITH (#{options[:storage_parameters]})" if options[:storage_parameters]
|
378
|
+
sql << " WITH (#{options[:storage_parameters] || options[:index_parameters]})" if options[:storage_parameters] || options[:index_parameters]
|
367
379
|
sql << " USING INDEX TABLESPACE #{base.quote_tablespace(options[:tablespace])}" if options[:tablespace]
|
368
380
|
sql
|
369
381
|
end
|
@@ -470,13 +482,13 @@ module ActiveRecord
|
|
470
482
|
# You can also create new FOREIGN KEY constraints outside of a table
|
471
483
|
# definition using PostgreSQLAdapter#add_foreign_key.
|
472
484
|
#
|
473
|
-
# ==== Examples
|
485
|
+
# ==== Examples
|
474
486
|
#
|
475
487
|
# add_foreign_key(:foo, :bar_id, :bar)
|
476
|
-
# # => ALTER TABLE "
|
488
|
+
# # => ALTER TABLE "foo" ADD FOREIGN KEY ("bar_id") REFERENCES "bar";
|
477
489
|
#
|
478
490
|
# add_foreign_key(:foo, :bar_id, :bar, :id)
|
479
|
-
# # => ALTER TABLE "
|
491
|
+
# # => ALTER TABLE "foo" ADD FOREIGN KEY ("bar_id") REFERENCES "bar"("id");
|
480
492
|
#
|
481
493
|
# add_foreign_key(:foo, [ :bar_id, :blort_id ], :bar, [ :id, :blort_id ],
|
482
494
|
# :name => 'my_fk', :match => :simple
|
@@ -505,7 +517,7 @@ module ActiveRecord
|
|
505
517
|
# the <tt>:deferrable</tt>, <tt>:match</tt>, <tt>:on_delete</tt>
|
506
518
|
# and <tt>:on_update</tt> options.
|
507
519
|
#
|
508
|
-
# === Dropping
|
520
|
+
# === Dropping FOREIGN KEY Constraints
|
509
521
|
#
|
510
522
|
# Like all PostgreSQL constraints, you can use
|
511
523
|
# PostgreSQLAdapter#drop_constraint to remove a constraint from a
|
@@ -522,7 +534,7 @@ module ActiveRecord
|
|
522
534
|
assert_valid_action(options[:on_update]) if options[:on_update]
|
523
535
|
assert_valid_deferrable_option(options[:deferrable])
|
524
536
|
@columns, @ref_table, @ref_columns = columns, ref_table, ref_columns
|
525
|
-
@schema = base.
|
537
|
+
@schema = base.current_scoped_schema
|
526
538
|
super(base, options)
|
527
539
|
end
|
528
540
|
|
@@ -564,5 +576,104 @@ module ActiveRecord
|
|
564
576
|
end
|
565
577
|
end
|
566
578
|
end
|
579
|
+
|
580
|
+
# Creates EXCLUDE constraints for PostgreSQL tables and columns.
|
581
|
+
#
|
582
|
+
# This class is meant to be used by PostgreSQL column and table
|
583
|
+
# definition and manipulation methods. There are two ways to create
|
584
|
+
# a EXCLUDE constraint:
|
585
|
+
#
|
586
|
+
# * on a table definition
|
587
|
+
# * when altering a table
|
588
|
+
#
|
589
|
+
# In both cases, a Hash or an Array of Hashes should be used to set the
|
590
|
+
# EXCLUDE constraint checks. The Hash(es) should be in the format
|
591
|
+
# <tt>{ :element => ..., :with => ... }</tt>, where <tt>:element</tt> is
|
592
|
+
# a column name or expression and <tt>:with</tt> is the operator to
|
593
|
+
# compare against. The key <tt>:operator</tt> is an alias for <tt>:where</tt>.
|
594
|
+
#
|
595
|
+
# === Table Definition
|
596
|
+
#
|
597
|
+
# EXCLUDE constraints can also be applied to the table directly
|
598
|
+
# rather than on a column definition.
|
599
|
+
#
|
600
|
+
# ==== Example:
|
601
|
+
#
|
602
|
+
# The following example produces the same result as above:
|
603
|
+
#
|
604
|
+
# create_table('foo') do |t|
|
605
|
+
# t.integer :blort
|
606
|
+
# t.exclude({
|
607
|
+
# :element => 'length(blort)',
|
608
|
+
# :with => '='
|
609
|
+
# }, {
|
610
|
+
# :name => 'exclude_blort_length'
|
611
|
+
# })
|
612
|
+
# end
|
613
|
+
#
|
614
|
+
# # Produces:
|
615
|
+
# #
|
616
|
+
# # CREATE TABLE "foo" (
|
617
|
+
# # "id" serial primary key,
|
618
|
+
# # "blort" text,
|
619
|
+
# # CONSTRAINT "exclude_blort_length" EXCLUDE (length(blort) WITH =)
|
620
|
+
# # );
|
621
|
+
#
|
622
|
+
# === Table Manipulation
|
623
|
+
#
|
624
|
+
# You can also create new EXCLUDE constraints outside of a table
|
625
|
+
# definition using PostgreSQLAdapter#add_exclude_constraint.
|
626
|
+
#
|
627
|
+
# ==== Examples
|
628
|
+
#
|
629
|
+
# add_exclude_constraint(:foo, { :element => :bar_id, :with => '=' })
|
630
|
+
# # => ALTER TABLE "foo" ADD EXCLUDE ("bar_id" WITH =);
|
631
|
+
#
|
632
|
+
# === Options for EXCLUDE Constraints
|
633
|
+
#
|
634
|
+
# * <tt>:using</tt> - sets the index type to be used. Usually this will
|
635
|
+
# <tt>:gist</tt>, but the default is left blank to allow for the PostgreSQL
|
636
|
+
# default which is <tt>:btree</tt>. See the PostgreSQL docs for details.
|
637
|
+
# * <tt>:storage_parameters</tt> - PostgreSQL allows you to add a
|
638
|
+
# couple of additional parameters to indexes to govern disk usage and
|
639
|
+
# such. This option is a simple String that lets you insert these
|
640
|
+
# options as necessary. See the PostgreSQL documentation on index
|
641
|
+
# storage parameters for details. <tt>:index_parameters</tt> can also
|
642
|
+
# be used.
|
643
|
+
# * <tt>:tablespace</tt> - allows you to specify a tablespace for the
|
644
|
+
# index being created. See the PostgreSQL documentation on
|
645
|
+
# tablespaces for details.
|
646
|
+
# * <tt>:conditions</tt> - sets the WHERE conditions for the EXCLUDE
|
647
|
+
# constraint. You can also use the <tt>:where</tt> option.
|
648
|
+
#
|
649
|
+
# === Dropping EXCLUDE Constraints
|
650
|
+
#
|
651
|
+
# Like all PostgreSQL constraints, you can use
|
652
|
+
# PostgreSQLAdapter#drop_constraint to remove a constraint from a
|
653
|
+
# table.
|
654
|
+
class PostgreSQLExcludeConstraint < PostgreSQLConstraint
|
655
|
+
attr_accessor :excludes
|
656
|
+
|
657
|
+
def initialize(base, table, excludes, options = {}) #:nodoc:
|
658
|
+
@excludes = ActiveRecord::PostgreSQLExtensions::Utils.hash_or_array_of_hashes(excludes)
|
659
|
+
|
660
|
+
super(base, options)
|
661
|
+
end
|
662
|
+
|
663
|
+
def to_sql #:nodoc:
|
664
|
+
sql = String.new
|
665
|
+
sql << "#{constraint_name}EXCLUDE "
|
666
|
+
sql << "USING #{base.quote_column_name(options[:using])} " if options[:using]
|
667
|
+
sql << "(" << excludes.collect { |e|
|
668
|
+
"#{e[:element]} WITH #{e[:with] || e[:operator]}"
|
669
|
+
}.join(', ')
|
670
|
+
sql << ")"
|
671
|
+
sql << " WITH (#{options[:index_parameters] || options[:storage_parameters]})" if options[:index_parameters] || options[:storage_parameters]
|
672
|
+
sql << " USING INDEX TABLESPACE #{base.quote_tablespace(options[:tablespace])}" if options[:tablespace]
|
673
|
+
sql << " WHERE (#{options[:conditions] || options[:where]})" if options[:conditions] || options[:where]
|
674
|
+
sql
|
675
|
+
end
|
676
|
+
alias :to_s :to_sql
|
677
|
+
end
|
567
678
|
end
|
568
679
|
end
|