schema_plus_views 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 94cd524efd83a80577764570786aa30b828218b4
4
- data.tar.gz: e86c50e980bd4e483caea91b6ab00f787a0f7425
3
+ metadata.gz: f120d0fd9e453a3e35a2ba8b71630edb81a93d96
4
+ data.tar.gz: 5b84b184193e12d27e883953d787d8f4b45f4743
5
5
  SHA512:
6
- metadata.gz: 56febaf08947bed4af3cb7efd7c45a5ccd465f2c8204d71facd52ccea83147342a3ef62cd5cb7a491d9e33a8a7e6c363d6abd418c5513bb7e42f76289dc460ad
7
- data.tar.gz: 562f3fbf5c349ee0373948e8e1186d713ef91c90754847ba162ed44d78d3bb0c753d47d747ca63851d51ce3582420c44e567d97da73a91e8fc39c8010a36927c
6
+ metadata.gz: db00fa4def6a06f90503c86bbbca407e9e61f911c9f7e3f2d99b6ab17d0ae57759f75aa880ce8f032093adf1ff569c2207600e8ff513bc255d5adb7890121b82
7
+ data.tar.gz: 5a993567b4ba203f891b8dd205640f41bc37aea6f74f90d27bca7caab7b8fa54f2051ce055b253e2f06b84559898ec6f8fedf8154d832fcd23e981ec111a8d8c
data/.travis.yml CHANGED
@@ -12,7 +12,7 @@ gemfile:
12
12
  - gemfiles/activerecord-4.2/Gemfile.sqlite3
13
13
  env: POSTGRESQL_DB_USER=postgres MYSQL_DB_USER=travis
14
14
  addons:
15
- postgresql: '9.3'
15
+ postgresql: '9.4'
16
16
  before_script: bundle exec rake create_databases
17
17
  after_script: bundle exec rake drop_databases
18
18
  script: bundle exec rake travis
data/README.md CHANGED
@@ -20,14 +20,6 @@ gem "schema_plus_views" # in a Gemfile
20
20
  gem.add_dependency "schema_plus_views" # in a .gemspec
21
21
  ```
22
22
 
23
- To use with a rails app, also include
24
-
25
- ```ruby
26
- gem "schema_monkey_rails"
27
- ```
28
-
29
- which creates a Railtie to that will insert SchemaPlus::Views appropriately into the rails stack. To use with Padrino, see [schema_monkey_padrino](https://github.com/SchemaPlus/schema_monkey_padrino).
30
-
31
23
  <!-- SCHEMA_DEV: TEMPLATE INSTALLATION - end -->
32
24
 
33
25
  ## Compatibility
@@ -44,10 +36,10 @@ SchemaPlus::Views is tested on:
44
36
 
45
37
  ### Creating views
46
38
 
47
- In a migration, a view can be created using literal SQL:
39
+ In a migration, a view can be created using literal SQL:
48
40
 
49
41
  ```ruby
50
- create_view :uncommented_posts, "SELECT * FROM posts LEFT OUTER JOIN comments ON comments.post_id = posts.id WHERE comments.id IS NULL"
42
+ create_view :uncommented_posts, "SELECT * FROM posts LEFT OUTER JOIN comments ON comments.post_id = posts.id WHERE comments.id IS NULL"
51
43
  ```
52
44
 
53
45
  or using an object that responds to `:to_sql`, such as a relation:
@@ -56,7 +48,16 @@ or using an object that responds to `:to_sql`, such as a relation:
56
48
  create_view :posts_commented_by_staff, Post.joins(comment: user).where(users: {role: 'staff'}).uniq
57
49
  ```
58
50
 
59
- (It's of course a questionable idea for your migrations to depend on your model definitions. But you *can* if you want.)
51
+ (It's of course a questionable idea for your migration files to depend on your model definitions. But you *can* if you want.)
52
+
53
+ Additional options can be provided:
54
+
55
+ * `:force => true` if there's an existing view with the given name, deletes it first. Note that this could fail if another view depends on it.
56
+
57
+ * `:allow_replace => true` will use the command "CREATE OR REPLACE" when creating the view, for seamlessly redefining the view even if other views depend on it. It's only supported by MySQL and PostgreSQL, and each has some limitations on when a view can be replaced; see their docs for details.
58
+
59
+
60
+ SchemaPlus::Views also arranges to include the `create_view` statements (with literal SQL) in the schema dump.
60
61
 
61
62
  ### Dropping views
62
63
 
@@ -69,12 +70,12 @@ drop_view :uncommented_posts, :if_exists => true
69
70
 
70
71
  ### Using views
71
72
 
72
- ActiveRecord models can be use views the same as ordinary tables. That is, for the above views you can define
73
+ ActiveRecord models can be based on views the same as ordinary tables. That is, for the above views you can define
73
74
 
74
75
  ```ruby
75
76
  class UncommentedPost < ActiveRecord::Base
76
77
  end
77
-
78
+
78
79
  class PostCommentedByStaff < ActiveRecord::Base
79
80
  table_name = "posts_commented_by_staff"
80
81
  end
@@ -85,15 +86,15 @@ end
85
86
  You can look up the defined views analogously to looking up tables:
86
87
 
87
88
  ```ruby
88
- connection.tables # => array of table names (defined by ActiveRecord)
89
- connection.views # => array of names of views (defined by SchemaPlus::Views)
89
+ connection.tables # => array of table names [method provided by ActiveRecord]
90
+ connection.views # => array of view names [method provided by SchemaPlus::Views]
90
91
  ```
91
92
 
92
93
  Notes:
93
94
 
94
95
  1. For Mysql and SQLite3, ActiveRecord's `connection.tables` method would return views as well as tables; SchemaPlus::Views normalizes them to return only tables.
95
96
 
96
- 2. For PostgreSQL, `connection.views` does *not* return views prefixed with `pg_` as those are presumed to be internal.
97
+ 2. For PostgreSQL, `connection.views` suppresses views prefixed with `pg_` as those are presumed to be internal.
97
98
 
98
99
  ### Querying view definitions
99
100
 
@@ -108,13 +109,12 @@ This returns just the body of the definition, i.e. the part after the `CREATE VI
108
109
 
109
110
  ## History
110
111
 
112
+ * 0.2.0 - Added :allow_replace option (thanks to [@hcarver](https://github.com/hcarver))
111
113
  * 0.1.0 - Initial release, extracted from schema_plus 1.x
112
114
 
113
115
  ## Development & Testing
114
116
 
115
- Are you interested in contributing to SchemaPlus::Views? Thanks! Please follow
116
- the standard protocol: fork, feature branch, develop, push, and issue pull
117
- request.
117
+ Are you interested in contributing to SchemaPlus::Views? Thanks! Please follow the standard protocol: fork, feature branch, develop, push, and issue pull request.
118
118
 
119
119
  Some things to know about to help you develop and test:
120
120
 
@@ -144,8 +144,8 @@ Some things to know about to help you develop and test:
144
144
  provides middleware callback stacks to make it easy to extend
145
145
  ActiveRecord's behavior. If that API is missing something you need for
146
146
  your contribution, please head over to
147
- [schema_plus_core](https://github/SchemaPlus/schema_plus_core) and open
148
- an issue or pull request.
147
+ [schema_plus_core](https://github.com/SchemaPlus/schema_plus_core) and open
148
+ an issue or pull request.
149
149
 
150
150
  <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_PLUS_CORE - end -->
151
151
 
@@ -155,6 +155,5 @@ Some things to know about to help you develop and test:
155
155
  [schema_monkey](https://github.com/SchemaPlus/schema_monkey) client,
156
156
  using [schema_monkey](https://github.com/SchemaPlus/schema_monkey)'s
157
157
  convention-based protocols for extending ActiveRecord and using middleware stacks.
158
- For more information see [schema_monkey](https://github.com/SchemaPlus/schema_monkey)'s README.
159
158
 
160
159
  <!-- SCHEMA_DEV: TEMPLATE USES SCHEMA_MONKEY - end -->
@@ -9,7 +9,14 @@ module SchemaPlus::Views
9
9
  if options[:force]
10
10
  drop_view(view_name, if_exists: true)
11
11
  end
12
- execute "CREATE VIEW #{quote_table_name(view_name)} AS #{definition}"
12
+
13
+ command = if options[:allow_replace]
14
+ "CREATE OR REPLACE"
15
+ else
16
+ "CREATE"
17
+ end
18
+
19
+ execute "#{command} VIEW #{quote_table_name(view_name)} AS #{definition}"
13
20
  end
14
21
 
15
22
  # Drop the named view. Specify :if_exists => true
@@ -1,5 +1,5 @@
1
1
  module SchemaPlus
2
2
  module Views
3
- VERSION = "0.1.0"
3
+ VERSION = "0.2.0"
4
4
  end
5
5
  end
@@ -1 +1 @@
1
- require_relative 'schema_plus/views.rb'
1
+ require_relative 'schema_plus/views'
@@ -23,7 +23,7 @@ Gem::Specification.new do |gem|
23
23
  gem.add_development_dependency "bundler", "~> 1.7"
24
24
  gem.add_development_dependency "rake", "~> 10.0"
25
25
  gem.add_development_dependency "rspec", "~> 3.0"
26
- gem.add_development_dependency "schema_dev", "~> 3.2"
26
+ gem.add_development_dependency "schema_dev", "~> 3.3"
27
27
  gem.add_development_dependency "simplecov"
28
28
  gem.add_development_dependency "simplecov-gem-profile"
29
29
  end
data/spec/views_spec.rb CHANGED
@@ -9,7 +9,7 @@ end
9
9
  class ABOnes < ActiveRecord::Base
10
10
  end
11
11
 
12
- describe ActiveRecord do
12
+ describe "Views" do
13
13
 
14
14
  let(:schema) { ActiveRecord::Schema }
15
15
 
@@ -17,50 +17,67 @@ describe ActiveRecord do
17
17
 
18
18
  let(:connection) { ActiveRecord::Base.connection }
19
19
 
20
- context "views" do
20
+ before(:each) do
21
+ define_schema_and_data
22
+ end
21
23
 
22
- around(:each) do |example|
23
- define_schema_and_data
24
- example.run
25
- drop_definitions
26
- end
24
+ context "querys" do
27
25
 
28
26
  it "should query correctly" do
29
27
  expect(AOnes.all.collect(&:s)).to eq(%W[one_one one_two])
30
28
  expect(ABOnes.all.collect(&:s)).to eq(%W[one_one])
31
29
  end
32
30
 
33
- it "should instrospect" do
34
- # for postgresql, ignore views named pg_*
31
+ end
32
+
33
+ context "introspection" do
34
+
35
+ it "should list all views" do
35
36
  expect(connection.views.sort).to eq(%W[a_ones ab_ones])
36
37
  expect(connection.view_definition('a_ones')).to match(%r{^ ?SELECT .*b.*,.*s.* FROM .*items.* WHERE .*a.* = 1}mi)
37
38
  expect(connection.view_definition('ab_ones')).to match(%r{^ ?SELECT .*s.* FROM .*a_ones.* WHERE .*b.* = 1}mi)
38
39
  end
39
40
 
41
+ it "should ignore views named pg_*", postgresql: :only do
42
+ begin
43
+ migration.create_view :pg_dummy_internal, "select 1"
44
+ expect(connection.views.sort).to eq(%W[a_ones ab_ones])
45
+ ensure
46
+ migration.drop_view :pg_dummy_internal
47
+ end
48
+ end
49
+
40
50
  it "should not be listed as a table" do
41
51
  expect(connection.tables).not_to include('a_ones')
42
52
  expect(connection.tables).not_to include('ab_ones')
43
53
  end
44
54
 
55
+ it "should introspect definition" do
56
+ expect(connection.view_definition('a_ones')).to match(%r{^ ?SELECT .*b.*,.*s.* FROM .*items.* WHERE .*a.* = 1}mi)
57
+ expect(connection.view_definition('ab_ones')).to match(%r{^ ?SELECT .*s.* FROM .*a_ones.* WHERE .*b.* = 1}mi)
58
+ end
59
+ end
60
+
45
61
 
46
- it "should be included in schema dump" do
62
+ context "dumper" do
63
+
64
+ it "should include view definitions" do
47
65
  expect(dump).to match(%r{create_view "a_ones", " ?SELECT .*b.*,.*s.* FROM .*items.* WHERE .*a.* = 1.*, :force => true}mi)
48
66
  expect(dump).to match(%r{create_view "ab_ones", " ?SELECT .*s.* FROM .*a_ones.* WHERE .*b.* = 1.*, :force => true}mi)
49
67
  end
50
68
 
51
- it "should be included in schema dump in dependency order" do
69
+ it "should include views in dependency order" do
52
70
  expect(dump).to match(%r{create_table "items".*create_view "a_ones".*create_view "ab_ones"}m)
53
71
  end
54
72
 
55
- it "should not be included in schema if listed in ignore_tables" do
73
+ it "should not include views listed in ignore_tables" do
56
74
  dump(ignore_tables: /b_/) do |dump|
57
75
  expect(dump).to match(%r{create_view "a_ones", " ?SELECT .*b.*,.*s.* FROM .*items.* WHERE .*a.* = 1.*, :force => true}mi)
58
76
  expect(dump).not_to match(%r{"ab_ones"})
59
77
  end
60
78
  end
61
79
 
62
-
63
- it "dump should not reference current database" do
80
+ it "should not reference current database" do
64
81
  # why check this? mysql default to providing the view definition
65
82
  # with tables explicitly scoped to the current database, which
66
83
  # resulted in the dump being bound to the current database. this
@@ -71,115 +88,97 @@ describe ActiveRecord do
71
88
  db = connection.respond_to?(:current_database)? connection.current_database : SchemaDev::Rspec.db_configuration[:database]
72
89
  expect(dump).not_to match(%r{#{connection.quote_table_name(db)}[.]})
73
90
  end
91
+ end
74
92
 
75
- context "duplicate view creation" do
76
- around(:each) do |example|
77
- migration.suppress_messages do
78
- begin
79
- migration.create_view('dupe_me', 'SELECT * FROM items WHERE (a=1)')
80
- example.run
81
- ensure
82
- migration.drop_view('dupe_me')
83
- end
84
- end
85
- end
86
-
93
+ context "duplicate creation" do
94
+ before(:each) do
95
+ migration.create_view('dupe_me', 'SELECT * FROM items WHERE (a=1)')
96
+ end
87
97
 
88
- it "should raise an error by default" do
89
- expect {migration.create_view('dupe_me', 'SELECT * FROM items WHERE (a=2)')}.to raise_error ActiveRecord::StatementInvalid
90
- end
98
+ it "should raise an error by default" do
99
+ expect {migration.create_view('dupe_me', 'SELECT * FROM items WHERE (a=2)')}.to raise_error ActiveRecord::StatementInvalid
100
+ end
91
101
 
92
- it "should override existing definition if :force true" do
93
- migration.create_view('dupe_me', 'SELECT * FROM items WHERE (a=2)', :force => true)
102
+ it "should override existing definition if :force true" do
103
+ migration.create_view('dupe_me', 'SELECT * FROM items WHERE (a=2)', :force => true)
104
+ expect(connection.view_definition('dupe_me')).to match(%r{WHERE .*a.*=.*2}i)
105
+ end
106
+
107
+ context "Postgres and MySQL only", :sqlite3 => :skip do
108
+ it "should override existing definition if :allow_replace is true" do
109
+ migration.create_view('dupe_me', 'SELECT * FROM items WHERE (a=2)', :allow_replace => true)
94
110
  expect(connection.view_definition('dupe_me')).to match(%r{WHERE .*a.*=.*2}i)
95
111
  end
96
112
  end
113
+ end
97
114
 
98
- context "dropping views" do
99
- it "should raise an error if the view doesn't exist" do
100
- expect { migration.drop_view('doesnt_exist') }.to raise_error ActiveRecord::StatementInvalid
101
- end
115
+ context "dropping" do
116
+ it "should raise an error if the view doesn't exist" do
117
+ expect { migration.drop_view('doesnt_exist') }.to raise_error ActiveRecord::StatementInvalid
118
+ end
102
119
 
103
- it "should fail silently when using if_exists option" do
104
- expect { migration.drop_view('doesnt_exist', :if_exists => true) }.not_to raise_error
105
- end
120
+ it "should fail silently when using if_exists option" do
121
+ expect { migration.drop_view('doesnt_exist', :if_exists => true) }.not_to raise_error
122
+ end
106
123
 
107
- context "with a view that exists" do
108
- before { migration.create_view('view_that_exists', 'SELECT * FROM items WHERE (a=1)') }
124
+ context "with a view that exists" do
125
+ before { migration.create_view('view_that_exists', 'SELECT * FROM items WHERE (a=1)') }
109
126
 
110
- it "should succeed" do
111
- migration.drop_view('view_that_exists')
112
- expect(connection.views).not_to include('view_that_exists')
113
- end
127
+ it "should succeed" do
128
+ migration.drop_view('view_that_exists')
129
+ expect(connection.views).not_to include('view_that_exists')
114
130
  end
115
131
  end
132
+ end
116
133
 
117
- context "in mysql", :mysql => :only do
134
+ context "in mysql", :mysql => :only do
118
135
 
119
- around(:each) do |example|
120
- migration.suppress_messages do
121
- begin
122
- migration.drop_view :check if connection.views.include? 'check'
123
- example.run
124
- ensure
125
- migration.drop_view :check if connection.views.include? 'check'
126
- end
127
- end
136
+ around(:each) do |example|
137
+ begin
138
+ migration.drop_view :check if connection.views.include? 'check'
139
+ example.run
140
+ ensure
141
+ migration.drop_view :check if connection.views.include? 'check'
128
142
  end
143
+ end
129
144
 
130
- it "should introspect WITH CHECK OPTION" do
131
- migration.create_view :check, 'SELECT * FROM items WHERE (a=2) WITH CHECK OPTION'
132
- expect(connection.view_definition('check')).to match(%r{WITH CASCADED CHECK OPTION$})
133
- end
145
+ it "should introspect WITH CHECK OPTION" do
146
+ migration.create_view :check, 'SELECT * FROM items WHERE (a=2) WITH CHECK OPTION'
147
+ expect(connection.view_definition('check')).to match(%r{WITH CASCADED CHECK OPTION$})
148
+ end
134
149
 
135
- it "should introspect WITH CASCADED CHECK OPTION" do
136
- migration.create_view :check, 'SELECT * FROM items WHERE (a=2) WITH CASCADED CHECK OPTION'
137
- expect(connection.view_definition('check')).to match(%r{WITH CASCADED CHECK OPTION$})
138
- end
150
+ it "should introspect WITH CASCADED CHECK OPTION" do
151
+ migration.create_view :check, 'SELECT * FROM items WHERE (a=2) WITH CASCADED CHECK OPTION'
152
+ expect(connection.view_definition('check')).to match(%r{WITH CASCADED CHECK OPTION$})
153
+ end
139
154
 
140
- it "should introspect WITH LOCAL CHECK OPTION" do
141
- migration.create_view :check, 'SELECT * FROM items WHERE (a=2) WITH LOCAL CHECK OPTION'
142
- expect(connection.view_definition('check')).to match(%r{WITH LOCAL CHECK OPTION$})
143
- end
155
+ it "should introspect WITH LOCAL CHECK OPTION" do
156
+ migration.create_view :check, 'SELECT * FROM items WHERE (a=2) WITH LOCAL CHECK OPTION'
157
+ expect(connection.view_definition('check')).to match(%r{WITH LOCAL CHECK OPTION$})
144
158
  end
145
159
  end
146
160
 
147
161
  protected
148
162
 
149
163
  def define_schema_and_data
150
- migration.suppress_messages do
151
- connection.views.each do |view| connection.drop_view view end
152
- connection.tables.each do |table| connection.drop_table table, cascade: true end
164
+ connection.views.each do |view| connection.drop_view view end
165
+ connection.tables.each do |table| connection.drop_table table, cascade: true end
153
166
 
154
- schema.define do
167
+ schema.define do
155
168
 
156
- create_table :items, :force => true do |t|
157
- t.integer :a
158
- t.integer :b
159
- t.string :s
160
- end
161
-
162
- create_view :a_ones, Item.select('b, s').where(:a => 1)
163
- create_view :ab_ones, "select s from a_ones where b = 1"
164
- create_view :pg_dummy_internal, "select 1" if SchemaDev::Rspec::Helpers.postgresql?
169
+ create_table :items, :force => true do |t|
170
+ t.integer :a
171
+ t.integer :b
172
+ t.string :s
165
173
  end
174
+
175
+ create_view :a_ones, Item.select('b, s').where(:a => 1)
176
+ create_view :ab_ones, "select s from a_ones where b = 1"
166
177
  end
167
178
  connection.execute "insert into items (a, b, s) values (1, 1, 'one_one')"
168
179
  connection.execute "insert into items (a, b, s) values (1, 2, 'one_two')"
169
180
  connection.execute "insert into items (a, b, s) values (2, 1, 'two_one')"
170
181
  connection.execute "insert into items (a, b, s) values (2, 2, 'two_two')"
171
-
172
- end
173
-
174
- def drop_definitions
175
- migration.suppress_messages do
176
- schema.define do
177
- drop_view "ab_ones"
178
- drop_view "a_ones"
179
- drop_table "items"
180
- drop_view :pg_dummy_internal if SchemaDev::Rspec::Helpers.postgresql?
181
- end
182
- end
183
182
  end
184
183
 
185
184
  def dump(opts={})
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: schema_plus_views
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - ronen barzel
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-02-11 00:00:00.000000000 Z
11
+ date: 2015-06-02 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -86,14 +86,14 @@ dependencies:
86
86
  requirements:
87
87
  - - "~>"
88
88
  - !ruby/object:Gem::Version
89
- version: '3.2'
89
+ version: '3.3'
90
90
  type: :development
91
91
  prerelease: false
92
92
  version_requirements: !ruby/object:Gem::Requirement
93
93
  requirements:
94
94
  - - "~>"
95
95
  - !ruby/object:Gem::Version
96
- version: '3.2'
96
+ version: '3.3'
97
97
  - !ruby/object:Gem::Dependency
98
98
  name: simplecov
99
99
  requirement: !ruby/object:Gem::Requirement