schema_plus 1.5.3 → 1.6.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.travis.yml +8 -8
- data/CHANGELOG.md +10 -4
- data/README.md +24 -4
- data/Rakefile +1 -1
- data/gemfiles/rails-4.1/Gemfile.base +1 -1
- data/lib/schema_plus/active_record/connection_adapters/abstract_adapter.rb +11 -5
- data/lib/schema_plus/active_record/connection_adapters/postgresql_adapter.rb +58 -2
- data/lib/schema_plus/active_record/schema_dumper.rb +10 -0
- data/lib/schema_plus/version.rb +1 -1
- data/runspecs +1 -1
- data/spec/column_default_spec.rb +20 -26
- data/spec/column_spec.rb +22 -24
- data/spec/connections/postgresql/connection.rb +1 -1
- data/spec/enum_spec.rb +132 -0
- data/spec/foreign_key_spec.rb +18 -15
- data/spec/index_definition_spec.rb +97 -102
- data/spec/index_spec.rb +5 -8
- data/spec/migration_spec.rb +288 -303
- data/spec/named_schemas_spec.rb +24 -26
- data/spec/schema_dumper_spec.rb +66 -53
- data/spec/spec_helper.rb +6 -0
- data/spec/views_spec.rb +41 -24
- metadata +24 -22
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 620224f986e74b013fddffb7147eecfabe3f27bd
|
4
|
+
data.tar.gz: 323fdba9ed583753abfbdaee67353391356213f0
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 8510bd7c390e12f5e4f2c113395dcde1831e46c9b525a90bb9a5cb2a4e48095840467e03dcac5229fdcab72abc11089d3d14c72ef535c6751fed159578f41bd6
|
7
|
+
data.tar.gz: 47df08a80fb0257e6cc1fa632005517685424af5f717ad847ef817b579288803c36e14f1cf2a96c7bb9442e288aaae08cd328e16ca0bfadda8a47f0910d8aa13
|
data/.travis.yml
CHANGED
@@ -18,7 +18,7 @@ before_script:
|
|
18
18
|
- rake create_databases
|
19
19
|
after_script:
|
20
20
|
- rake drop_databases
|
21
|
-
env: '
|
21
|
+
env: 'POSTGRESQL_DB_USER=postgres MYSQL_DB_USER="travis"'
|
22
22
|
notifications:
|
23
23
|
recipients:
|
24
24
|
- michal.lomnicki@gmail.com
|
@@ -27,22 +27,22 @@ matrix:
|
|
27
27
|
exclude:
|
28
28
|
- rvm: jruby
|
29
29
|
gemfile: gemfiles/rails-3.2/Gemfile.sqlite3
|
30
|
-
env: '
|
30
|
+
env: 'POSTGRESQL_DB_USER=postgres MYSQL_DB_USER="travis"'
|
31
31
|
- rvm: jruby
|
32
32
|
gemfile: gemfiles/rails-4.0/Gemfile.postgresql
|
33
|
-
env: '
|
33
|
+
env: 'POSTGRESQL_DB_USER=postgres MYSQL_DB_USER="travis"'
|
34
34
|
- rvm: jruby
|
35
35
|
gemfile: gemfiles/rails-4.0/Gemfile.sqlite3
|
36
|
-
env: '
|
36
|
+
env: 'POSTGRESQL_DB_USER=postgres MYSQL_DB_USER="travis"'
|
37
37
|
- rvm: jruby
|
38
38
|
gemfile: gemfiles/rails-4.0/Gemfile.mysql2
|
39
|
-
env: '
|
39
|
+
env: 'POSTGRESQL_DB_USER=postgres MYSQL_DB_USER="travis"'
|
40
40
|
- rvm: jruby
|
41
41
|
gemfile: gemfiles/rails-4.1/Gemfile.postgresql
|
42
|
-
env: '
|
42
|
+
env: 'POSTGRESQL_DB_USER=postgres MYSQL_DB_USER="travis"'
|
43
43
|
- rvm: jruby
|
44
44
|
gemfile: gemfiles/rails-4.1/Gemfile.sqlite3
|
45
|
-
env: '
|
45
|
+
env: 'POSTGRESQL_DB_USER=postgres MYSQL_DB_USER="travis"'
|
46
46
|
- rvm: jruby
|
47
47
|
gemfile: gemfiles/rails-4.1/Gemfile.mysql2
|
48
|
-
env: '
|
48
|
+
env: 'POSTGRESQL_DB_USER=postgres MYSQL_DB_USER="travis"'
|
data/CHANGELOG.md
CHANGED
@@ -2,12 +2,18 @@
|
|
2
2
|
|
3
3
|
## Change Log
|
4
4
|
|
5
|
+
### 1.6.0
|
6
|
+
|
7
|
+
* Added PostgreSQL enum support (thanks to [@juike](https://github.com/juike)) (issue #167)
|
8
|
+
* Added if_exists to drop_view (thanks to [@abrom](https://github.com/abrom)) (issue #171)
|
9
|
+
* Partial support for AR 4.* with jRuby (thanks to [@bacrossland])) (issue #172)
|
10
|
+
|
5
11
|
### 1.5.3
|
6
12
|
|
7
13
|
* No longer limited to rails 4.1.1 (issue #159)
|
8
14
|
* Bug fix: multiple competing indexes created for `t.references... index: :unique` (issue #157)
|
9
|
-
* Now works with rspec 3 (thanks to [@robababa](https://github.com/robababa) (issue #160)
|
10
|
-
* Improvements to ./runspecs (thanks to [@robababa](https://github.com/robababa) (issue #162)
|
15
|
+
* Now works with rspec 3 (thanks to [@robababa](https://github.com/robababa)) (issue #160)
|
16
|
+
* Improvements to ./runspecs (thanks to [@robababa](https://github.com/robababa)) (issue #162)
|
11
17
|
|
12
18
|
### 1.5.2
|
13
19
|
|
@@ -19,7 +25,7 @@
|
|
19
25
|
|
20
26
|
### 1.5.0
|
21
27
|
* Can now be used with activerecord standalone, doesn't need all of rails.
|
22
|
-
* `views` ignores
|
28
|
+
* `views` ignores PostgreSQL internal views, thanks to [@everplays](https://github.com/everplays) (issue #147)
|
23
29
|
|
24
30
|
### 1.4.1
|
25
31
|
|
@@ -103,7 +109,7 @@
|
|
103
109
|
[@zaadjis](https://github.com/zaadjis))
|
104
110
|
* New feature: renaming a table renames its indexes and constraints
|
105
111
|
correspondingly.
|
106
|
-
* Bug fix for
|
112
|
+
* Bug fix for PostgreSQL :kind index attribute (thanks to [@eugenebolshakov](https://github.com/eugenebolshakov))
|
107
113
|
* Sort fks in dump for stability (thanks to [@zephyr-dev](https://github.com/zephyr-dev))
|
108
114
|
* Bug fix: change_column should maintain foreign key constraints even when
|
109
115
|
config.foreign_keys.auto_create is false
|
data/README.md
CHANGED
@@ -211,7 +211,7 @@ a view can be created using a rails relation or literal sql:
|
|
211
211
|
And can be dropped:
|
212
212
|
|
213
213
|
drop_view :posts_commented_by_staff
|
214
|
-
drop_view :uncommented_posts
|
214
|
+
drop_view :uncommented_posts, :if_exists => true
|
215
215
|
|
216
216
|
ActiveRecord works with views the same as with ordinary tables. That is, for
|
217
217
|
the above views you can define
|
@@ -223,7 +223,7 @@ the above views you can define
|
|
223
223
|
class UncommentedPost < ActiveRecord::Base
|
224
224
|
end
|
225
225
|
|
226
|
-
Note: In
|
226
|
+
Note: In PostgreSQL, all internal views (the ones with `pg_` prefix) will be skipped.
|
227
227
|
|
228
228
|
### Column Defaults: Expressions
|
229
229
|
|
@@ -267,6 +267,26 @@ Note that after updating, you would need to reload a record to replace
|
|
267
267
|
Note also that Sqlite3 does not support `ActiveRecord::DB_DEFAULT`; attempting
|
268
268
|
to use it will raise `ActiveRecord::StatementInvalid`
|
269
269
|
|
270
|
+
### Enums (PostgreSQL only)
|
271
|
+
|
272
|
+
SchemaPlus provides support for creating, altering and dropping enums. In a migration,
|
273
|
+
a enum can be created:
|
274
|
+
|
275
|
+
create_enum :color, :red, :green, :blue # default schema is 'public'
|
276
|
+
create_enum :cmyk, :cyan, :magenta, :yellow, :black, :schema => 'color'
|
277
|
+
|
278
|
+
And can be altered: (added a new value)
|
279
|
+
|
280
|
+
alter_enum :color, :black
|
281
|
+
alter_enum :color, :purple, :after => 'red'
|
282
|
+
alter_enum :color, :pink, :before => 'purple'
|
283
|
+
alter_enum :color, :white, :schema => 'public'
|
284
|
+
|
285
|
+
Finally, a enum can be dropped:
|
286
|
+
|
287
|
+
drop_enum :color
|
288
|
+
drop_enum :cmyk, :schema => 'color'
|
289
|
+
|
270
290
|
### Schema Dump and Load (schema.rb)
|
271
291
|
|
272
292
|
When dumping `schema.rb`, SchemaPlus orders the views and tables in the schema
|
@@ -316,9 +336,9 @@ Schema_plus has a full set of rspec tests. [travis-ci](http://travis-ci.org/lom
|
|
316
336
|
|
317
337
|
* Of course you must have installed whichever databases you want to test. The default set is: PostgreSQL, MySQL, and SQLite3.
|
318
338
|
|
319
|
-
* For PostgreSQL and MySQL the tests need a db user with permissions to create and access databases: The default username used by the specs is 'postgres' for
|
339
|
+
* For PostgreSQL and MySQL the tests need a db user with permissions to create and access databases: The default username used by the specs is 'postgres' for PostgreSQL and 'schema_plus' for MySQL; you can change them via:
|
320
340
|
|
321
|
-
$ export
|
341
|
+
$ export POSTGRESQL_DB_USER = pgusername
|
322
342
|
$ export MYSQL_DB_USER = mysqlusername
|
323
343
|
|
324
344
|
* For PostgreSQL and MySQL you must explicitly create the databases used by the tests:
|
data/Rakefile
CHANGED
@@ -37,7 +37,7 @@ end
|
|
37
37
|
|
38
38
|
DATABASES = %w[schema_plus_test]
|
39
39
|
[
|
40
|
-
{ namespace: :postgresql, uservar: '
|
40
|
+
{ namespace: :postgresql, uservar: 'POSTGRESQL_DB_USER', defaultuser: 'postgres', create: "createdb -U '%{user}' %{dbname}", drop: "dropdb -U '%{user}' %{dbname}" },
|
41
41
|
{ namespace: :mysql, uservar: 'MYSQL_DB_USER', defaultuser: 'schema_plus', create: "mysqladmin -u '%{user}' create %{dbname}", drop: "mysqladmin -u '%{user}' -f drop %{dbname}" }
|
42
42
|
].each do |db|
|
43
43
|
namespace db[:namespace] do
|
@@ -27,8 +27,10 @@ module SchemaPlus
|
|
27
27
|
when 'PostgreSQL', 'PostGIS' then 'PostgresqlAdapter'
|
28
28
|
when 'SQLite' then 'Sqlite3Adapter'
|
29
29
|
end
|
30
|
-
|
31
|
-
|
30
|
+
if adapter.nil?
|
31
|
+
unless adapter_name == 'JDBC' # ARJDBC
|
32
|
+
::ActiveRecord::Base.logger.warn "SchemaPlus: Unsupported adapter name #{adapter_name.inspect}. Leaving it alone."
|
33
|
+
end
|
32
34
|
return
|
33
35
|
end
|
34
36
|
adapter_module = SchemaPlus::ActiveRecord::ConnectionAdapters.const_get(adapter)
|
@@ -51,9 +53,13 @@ module SchemaPlus
|
|
51
53
|
execute "CREATE VIEW #{quote_table_name(view_name)} AS #{definition}"
|
52
54
|
end
|
53
55
|
|
54
|
-
# Drop the named view
|
55
|
-
|
56
|
-
|
56
|
+
# Drop the named view. Specify :if_exists => true
|
57
|
+
# to fail silently if the view doesn't exist.
|
58
|
+
def drop_view(view_name, options = {})
|
59
|
+
sql = "DROP VIEW"
|
60
|
+
sql += " IF EXISTS" if options[:if_exists]
|
61
|
+
sql += " #{quote_table_name(view_name)}"
|
62
|
+
execute sql
|
57
63
|
end
|
58
64
|
|
59
65
|
|
@@ -68,7 +68,7 @@ module SchemaPlus
|
|
68
68
|
::ActiveRecord::ConnectionAdapters::PostgreSQLColumn.send(:include, PostgreSQLColumn) unless ::ActiveRecord::ConnectionAdapters::PostgreSQLColumn.include?(PostgreSQLColumn)
|
69
69
|
end
|
70
70
|
|
71
|
-
# SchemaPlus provides the following extra options for
|
71
|
+
# SchemaPlus provides the following extra options for PostgreSQL
|
72
72
|
# indexes:
|
73
73
|
# * +:conditions+ - SQL conditions for the WHERE clause of the index
|
74
74
|
# * +:expression+ - SQL expression to index. column_name can be nil or ommitted, in which case :name must be provided
|
@@ -154,7 +154,7 @@ module SchemaPlus
|
|
154
154
|
SQL
|
155
155
|
|
156
156
|
result.map do |(index_name, is_unique, indkey, inddef, oid, kind, conditions, expression)|
|
157
|
-
unique = (is_unique == 't')
|
157
|
+
unique = (is_unique == 't' || is_unique == true) # The test against true is for JDBC which is returning a boolean and not a String.
|
158
158
|
index_keys = indkey.split(" ")
|
159
159
|
|
160
160
|
rows = query(<<-SQL, "Columns for index #{index_name} on #{table_name}")
|
@@ -282,8 +282,64 @@ module SchemaPlus
|
|
282
282
|
row.first.chomp(';') unless row.nil?
|
283
283
|
end
|
284
284
|
|
285
|
+
def enums #:nodoc:
|
286
|
+
result = query(<<-SQL)
|
287
|
+
SELECT
|
288
|
+
N.nspname AS schema_name,
|
289
|
+
T.typname AS enum_name,
|
290
|
+
E.enumlabel AS enum_label,
|
291
|
+
E.enumsortorder AS enum_sort_order
|
292
|
+
--array_agg(E.enumlabel ORDER BY enumsortorder) AS labels
|
293
|
+
FROM pg_type T
|
294
|
+
JOIN pg_enum E ON E.enumtypid = T.oid
|
295
|
+
JOIN pg_namespace N ON N.oid = T.typnamespace
|
296
|
+
ORDER BY 1, 2, 4
|
297
|
+
SQL
|
298
|
+
|
299
|
+
result.reduce([]) do |res, row|
|
300
|
+
last = res.last
|
301
|
+
if last && last[0] == row[0] && last[1] == row[1]
|
302
|
+
last[2] << row[2]
|
303
|
+
else
|
304
|
+
res << (row[0..1] << [row[2]])
|
305
|
+
end
|
306
|
+
res
|
307
|
+
end
|
308
|
+
end
|
309
|
+
|
310
|
+
def create_enum(name, *values)
|
311
|
+
options = values.extract_options!
|
312
|
+
list = values.map { |value| escape_enum_value(value) }
|
313
|
+
execute "CREATE TYPE #{enum_name(name, options[:schema])} AS ENUM (#{list.join(',')})"
|
314
|
+
end
|
315
|
+
|
316
|
+
def alter_enum(name, value, options = {})
|
317
|
+
opts = case
|
318
|
+
when options[:before] then "BEFORE #{escape_enum_value(options[:before])}"
|
319
|
+
when options[:after] then "AFTER #{escape_enum_value(options[:after])}"
|
320
|
+
else
|
321
|
+
''
|
322
|
+
end
|
323
|
+
execute "ALTER TYPE #{enum_name(name, options[:schema])} ADD VALUE #{escape_enum_value(value)} #{opts}"
|
324
|
+
end
|
325
|
+
|
326
|
+
def drop_enum(name, options = {})
|
327
|
+
execute "DROP TYPE #{enum_name(name, options[:schema])}"
|
328
|
+
end
|
329
|
+
|
285
330
|
private
|
286
331
|
|
332
|
+
def enum_name(name, schema)
|
333
|
+
[schema || 'public', name].map { |s|
|
334
|
+
%Q{"#{s}"}
|
335
|
+
}.join('.')
|
336
|
+
end
|
337
|
+
|
338
|
+
def escape_enum_value(value)
|
339
|
+
escaped_value = value.sub("'", "''")
|
340
|
+
"'#{escaped_value}'"
|
341
|
+
end
|
342
|
+
|
287
343
|
def namespace_sql(table_name)
|
288
344
|
(table_name.to_s =~ /(.*)[.]/) ? "'#{$1}'" : "ANY (current_schemas(false))"
|
289
345
|
end
|
@@ -49,6 +49,16 @@ module SchemaPlus
|
|
49
49
|
@backref_fks = Hash.new{ |h, k| h[k] = [] }
|
50
50
|
@dump_dependencies = {}
|
51
51
|
|
52
|
+
if @connection.respond_to?(:enums)
|
53
|
+
@connection.enums.each do |schema, name, values|
|
54
|
+
params = [name.inspect]
|
55
|
+
params << values.map(&:inspect).join(', ')
|
56
|
+
params << ":schema => #{schema.inspect}" if schema != 'public'
|
57
|
+
|
58
|
+
stream.puts " create_enum #{params.join(', ')}"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
52
62
|
tables_without_schema_plus(nil)
|
53
63
|
|
54
64
|
@connection.views.each do |view_name|
|
data/lib/schema_plus/version.rb
CHANGED
data/runspecs
CHANGED
@@ -47,7 +47,7 @@ OptionParser.new do |opts|
|
|
47
47
|
o.db_adapters = DB_ADAPTERS
|
48
48
|
end
|
49
49
|
|
50
|
-
opts.on("--quick", "quick run on
|
50
|
+
opts.on("--quick", "quick run on PostgreSQL, ruby #{RUBY_VERSIONS.last} and rails #{RAILS_VERSIONS.last}") do
|
51
51
|
o.ruby_versions = [RUBY_VERSIONS.last]
|
52
52
|
o.rails_versions = [RAILS_VERSIONS.last]
|
53
53
|
o.db_adapters = ["postgresql"]
|
data/spec/column_default_spec.rb
CHANGED
@@ -70,14 +70,12 @@ describe "Column definition" do
|
|
70
70
|
end
|
71
71
|
end
|
72
72
|
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
is_expected.to match @nowish
|
80
|
-
end
|
73
|
+
it "should use NOW() as the default", :mysql => :skip do
|
74
|
+
is_expected.to match @nowish
|
75
|
+
end
|
76
|
+
|
77
|
+
it "should raise an error", :mysql => :only do
|
78
|
+
expect(@raised_argument_error).to be_a ArgumentError
|
81
79
|
end
|
82
80
|
end
|
83
81
|
|
@@ -90,29 +88,25 @@ describe "Column definition" do
|
|
90
88
|
end
|
91
89
|
end
|
92
90
|
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
is_expected.to match @nowish
|
100
|
-
end
|
91
|
+
it "should use NOW() as the default", :mysql => :skip do
|
92
|
+
is_expected.to match @nowish
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should raise an error", :mysql => :only do
|
96
|
+
expect(@raised_argument_error).to be_a ArgumentError
|
101
97
|
end
|
102
98
|
end
|
103
99
|
|
104
100
|
context "valid expr passed as default" do
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
it "uses the expression" do
|
101
|
+
it "uses the expression", :mysql => :skip do
|
102
|
+
define_test_column(:string, :default => { :expr => "(replace('THIS IS A TEST', 'TEST', 'DOG'))" })
|
103
|
+
is_expected.to eq "THIS IS A DOG"
|
104
|
+
end
|
105
|
+
|
106
|
+
it "raises an error", :mysql => :only do
|
107
|
+
expect {
|
113
108
|
define_test_column(:string, :default => { :expr => "(replace('THIS IS A TEST', 'TEST', 'DOG'))" })
|
114
|
-
|
115
|
-
end
|
109
|
+
}.to raise_error ArgumentError
|
116
110
|
end
|
117
111
|
end
|
118
112
|
|
data/spec/column_spec.rb
CHANGED
@@ -101,32 +101,30 @@ describe "Column" do
|
|
101
101
|
create_table(User, :alpha => { :default => "gabba" }, :beta => {})
|
102
102
|
end
|
103
103
|
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
u = User.create!(:alpha => "hey", :beta => "hello")
|
110
|
-
expect { u.update_attributes(:alpha => ActiveRecord::DB_DEFAULT, :beta => "goodbye") }.to raise_error ActiveRecord::StatementInvalid
|
111
|
-
end
|
112
|
-
else
|
104
|
+
it "creating a record should respect default expression", :sqlite3 => :skip do
|
105
|
+
User.create!(:alpha => ActiveRecord::DB_DEFAULT, :beta => "hello")
|
106
|
+
expect(User.last.alpha).to eq("gabba")
|
107
|
+
expect(User.last.beta).to eq("hello")
|
108
|
+
end
|
113
109
|
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
expect(User.last.beta).to eq("hello")
|
118
|
-
end
|
110
|
+
it "creating a record should raise an error", :sqlite3 => :only do
|
111
|
+
expect { User.create!(:alpha => ActiveRecord::DB_DEFAULT, :beta => "hello") }.to raise_error ActiveRecord::StatementInvalid
|
112
|
+
end
|
119
113
|
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
114
|
+
it "updating a record should respect default expression", :sqlite3 => :skip do
|
115
|
+
u = User.create!(:alpha => "hey", :beta => "hello")
|
116
|
+
u.reload
|
117
|
+
expect(u.alpha).to eq("hey")
|
118
|
+
expect(u.beta).to eq("hello")
|
119
|
+
u.update_attributes(:alpha => ActiveRecord::DB_DEFAULT, :beta => "goodbye")
|
120
|
+
u.reload
|
121
|
+
expect(u.alpha).to eq("gabba")
|
122
|
+
expect(u.beta).to eq("goodbye")
|
123
|
+
end
|
124
|
+
|
125
|
+
it "updating a record should raise an error", :sqlite3 => :only do
|
126
|
+
u = User.create!(:alpha => "hey", :beta => "hello")
|
127
|
+
expect { u.update_attributes(:alpha => ActiveRecord::DB_DEFAULT, :beta => "goodbye") }.to raise_error ActiveRecord::StatementInvalid
|
130
128
|
end
|
131
129
|
end
|
132
130
|
|
@@ -6,7 +6,7 @@ ActiveRecord::Base.logger = Logger.new(File.open("postgresql.log", "w"))
|
|
6
6
|
ActiveRecord::Base.configurations = {
|
7
7
|
'schema_plus' => {
|
8
8
|
:adapter => 'postgresql',
|
9
|
-
:username => ENV['
|
9
|
+
:username => ENV['POSTGRESQL_DB_USER'],
|
10
10
|
:database => 'schema_plus_test',
|
11
11
|
:min_messages => 'warning'
|
12
12
|
}
|
data/spec/enum_spec.rb
ADDED
@@ -0,0 +1,132 @@
|
|
1
|
+
require File.expand_path(File.dirname(__FILE__) + '/spec_helper')
|
2
|
+
|
3
|
+
def enum_fields(name, schema = 'public')
|
4
|
+
sql = <<-SQL
|
5
|
+
SELECT array_to_string(array_agg(E.enumlabel ORDER BY enumsortorder), ' ') AS "values"
|
6
|
+
FROM pg_enum E
|
7
|
+
JOIN pg_type T ON E.enumtypid = T.oid
|
8
|
+
JOIN pg_namespace N ON N.oid = T.typnamespace
|
9
|
+
WHERE N.nspname = '#{schema}' AND T.typname = '#{name}'
|
10
|
+
GROUP BY T.oid;
|
11
|
+
SQL
|
12
|
+
|
13
|
+
data = ActiveRecord::Base.connection.select_all(sql)
|
14
|
+
return nil if data.empty?
|
15
|
+
data[0]['values'].split(' ')
|
16
|
+
end
|
17
|
+
|
18
|
+
describe 'enum', :postgresql => :only do
|
19
|
+
before(:all) do ActiveRecord::Migration.verbose = false end
|
20
|
+
|
21
|
+
let(:migration) { ActiveRecord::Migration }
|
22
|
+
|
23
|
+
describe 'enums' do
|
24
|
+
it 'should return all enums' do
|
25
|
+
begin
|
26
|
+
migration.execute 'create schema cmyk'
|
27
|
+
migration.create_enum 'color', 'red', 'green', 'blue'
|
28
|
+
migration.create_enum 'color', 'cyan', 'magenta', 'yellow', 'black', schema: 'cmyk'
|
29
|
+
|
30
|
+
expect(migration.enums).to match_array [['cmyk', 'color', %w|cyan magenta yellow black|], ['public', 'color', %w|red green blue|]]
|
31
|
+
ensure
|
32
|
+
migration.drop_enum 'color'
|
33
|
+
migration.execute 'drop schema cmyk cascade'
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
describe 'create_enum' do
|
39
|
+
it 'should create enum with given values' do
|
40
|
+
begin
|
41
|
+
migration.create_enum 'color', *%w|red green blue|
|
42
|
+
expect(enum_fields('color')).to eq(%w|red green blue|)
|
43
|
+
ensure
|
44
|
+
migration.execute 'DROP TYPE IF EXISTS color'
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
it 'should create enum with schema' do
|
49
|
+
begin
|
50
|
+
migration.execute 'CREATE SCHEMA colors'
|
51
|
+
migration.create_enum 'color', *%|red green blue|, schema: 'colors'
|
52
|
+
expect(enum_fields('color', 'colors')).to eq(%w|red green blue|)
|
53
|
+
ensure
|
54
|
+
migration.execute 'DROP SCHEMA IF EXISTS colors CASCADE'
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
it 'should escape enum value' do
|
59
|
+
begin
|
60
|
+
migration.create_enum('names', "O'Neal")
|
61
|
+
expect(enum_fields('names')).to eq(["O'Neal"])
|
62
|
+
ensure
|
63
|
+
migration.execute "DROP TYPE IF EXISTS names"
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
it 'should escape schame name and enum name' do
|
68
|
+
begin
|
69
|
+
migration.execute 'CREATE SCHEMA "select"'
|
70
|
+
migration.create_enum 'where', *%|red green blue|, schema: 'select'
|
71
|
+
expect(enum_fields('where', 'select')).to eq(%w|red green blue|)
|
72
|
+
ensure
|
73
|
+
migration.execute 'DROP SCHEMA IF EXISTS "select" CASCADE'
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
|
79
|
+
describe 'alter_enum' do
|
80
|
+
before(:each) do migration.create_enum('color', 'red', 'green', 'blue') end
|
81
|
+
after(:each) do migration.execute 'DROP TYPE IF EXISTS color' end
|
82
|
+
|
83
|
+
it 'should add new value after all values' do
|
84
|
+
migration.alter_enum('color', 'magenta')
|
85
|
+
expect(enum_fields('color')).to eq(%w|red green blue magenta|)
|
86
|
+
end
|
87
|
+
|
88
|
+
it 'should add new value after existed' do
|
89
|
+
migration.alter_enum('color', 'magenta', after: 'red')
|
90
|
+
expect(enum_fields('color')).to eq(%w|red magenta green blue|)
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'should add new value before existed' do
|
94
|
+
migration.alter_enum('color', 'magenta', before: 'green')
|
95
|
+
expect(enum_fields('color')).to eq(%w|red magenta green blue|)
|
96
|
+
end
|
97
|
+
|
98
|
+
it 'should add new value within given schema' do
|
99
|
+
begin
|
100
|
+
migration.execute 'CREATE SCHEMA colors'
|
101
|
+
migration.create_enum('color', 'red', schema: 'colors')
|
102
|
+
migration.alter_enum('color', 'green', schema: 'colors')
|
103
|
+
|
104
|
+
expect(enum_fields('color', 'colors')).to eq(%w|red green|)
|
105
|
+
ensure
|
106
|
+
migration.execute 'DROP SCHEMA colors CASCADE'
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
describe 'drop_enum' do
|
112
|
+
it 'should drop enum with given name' do
|
113
|
+
migration.execute "CREATE TYPE color AS ENUM ('red', 'blue')"
|
114
|
+
expect(enum_fields('color')).to eq(%w|red blue|)
|
115
|
+
migration.drop_enum('color')
|
116
|
+
|
117
|
+
expect(enum_fields('color')).to be_nil
|
118
|
+
end
|
119
|
+
|
120
|
+
it 'should drop enum within given name and schema' do
|
121
|
+
begin
|
122
|
+
migration.execute "CREATE SCHEMA colors; CREATE TYPE colors.color AS ENUM ('red', 'blue')"
|
123
|
+
expect(enum_fields('color', 'colors')).to eq(%w|red blue|)
|
124
|
+
migration.drop_enum('color', schema: 'colors')
|
125
|
+
|
126
|
+
expect(enum_fields('color', 'colors')).to be_nil
|
127
|
+
ensure
|
128
|
+
migration.execute "DROP SCHEMA colors CASCADE"
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/spec/foreign_key_spec.rb
CHANGED
@@ -79,25 +79,12 @@ describe "Foreign Key" do
|
|
79
79
|
class Comment < ::ActiveRecord::Base ; end
|
80
80
|
end
|
81
81
|
|
82
|
-
if SchemaPlusHelpers.sqlite3?
|
83
82
|
|
84
|
-
|
85
|
-
expect {
|
86
|
-
add_foreign_key(:posts, :author_id, :users, :id, :on_update => :cascade, :on_delete => :restrict)
|
87
|
-
}.to raise_error(NotImplementedError)
|
88
|
-
end
|
89
|
-
|
90
|
-
it "raises an exception when attempting to remove" do
|
91
|
-
expect {
|
92
|
-
remove_foreign_key(:posts, "dummy")
|
93
|
-
}.to raise_error(NotImplementedError)
|
94
|
-
end
|
95
|
-
|
96
|
-
else
|
83
|
+
context "works", :sqlite3 => :skip do
|
97
84
|
|
98
85
|
context "when is added", "posts(author_id)" do
|
99
86
|
|
100
|
-
before(:each) do
|
87
|
+
before(:each) do
|
101
88
|
add_foreign_key(:posts, :author_id, :users, :id, :on_update => :cascade, :on_delete => :restrict)
|
102
89
|
end
|
103
90
|
|
@@ -186,6 +173,22 @@ describe "Foreign Key" do
|
|
186
173
|
end
|
187
174
|
|
188
175
|
end
|
176
|
+
|
177
|
+
context "raises an exception", :sqlite3 => :only do
|
178
|
+
|
179
|
+
it "when attempting to add" do
|
180
|
+
expect {
|
181
|
+
add_foreign_key(:posts, :author_id, :users, :id, :on_update => :cascade, :on_delete => :restrict)
|
182
|
+
}.to raise_error(NotImplementedError)
|
183
|
+
end
|
184
|
+
|
185
|
+
it "when attempting to remove" do
|
186
|
+
expect {
|
187
|
+
remove_foreign_key(:posts, "dummy")
|
188
|
+
}.to raise_error(NotImplementedError)
|
189
|
+
end
|
190
|
+
|
191
|
+
end
|
189
192
|
end
|
190
193
|
|
191
194
|
protected
|