scenic 1.0.0 → 1.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.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/.travis.yml +14 -4
- data/.yardopts +0 -1
- data/Appraisals +25 -0
- data/CONTRIBUTING.md +5 -4
- data/LICENSE.txt +1 -1
- data/NEWS.md +20 -0
- data/README.md +68 -28
- data/bin/appraisal +16 -0
- data/bin/setup +5 -0
- data/bin/yard +16 -0
- data/gemfiles/rails40.gemfile +8 -0
- data/gemfiles/rails41.gemfile +8 -0
- data/gemfiles/rails42.gemfile +8 -0
- data/gemfiles/rails50.gemfile +14 -0
- data/lib/generators/scenic/generators.rb +1 -0
- data/lib/generators/scenic/model/templates/model.erb +1 -1
- data/lib/scenic.rb +1 -0
- data/lib/scenic/adapters/postgres.rb +140 -33
- data/lib/scenic/adapters/postgres/connection.rb +57 -0
- data/lib/scenic/adapters/postgres/errors.rb +26 -0
- data/lib/scenic/adapters/postgres/index_reapplication.rb +71 -0
- data/lib/scenic/adapters/postgres/indexes.rb +53 -0
- data/lib/scenic/adapters/postgres/views.rb +51 -0
- data/lib/scenic/configuration.rb +2 -2
- data/lib/scenic/index.rb +36 -0
- data/lib/scenic/schema_dumper.rb +1 -1
- data/lib/scenic/statements.rb +7 -13
- data/lib/scenic/version.rb +1 -1
- data/lib/scenic/view.rb +0 -3
- data/scenic.gemspec +4 -1
- data/spec/dummy/config/application.rb +3 -0
- data/spec/scenic/adapters/postgres/connection_spec.rb +79 -0
- data/spec/scenic/adapters/postgres/views_spec.rb +37 -0
- data/spec/scenic/adapters/postgres_spec.rb +84 -26
- data/spec/scenic/statements_spec.rb +14 -15
- data/spec/smoke +16 -3
- data/spec/spec_helper.rb +4 -0
- metadata +64 -8
- data/spec/dummy/config/environments/development.rb +0 -6
- data/spec/dummy/config/environments/test.rb +0 -5
@@ -0,0 +1,37 @@
|
|
1
|
+
require "spec_helper"
|
2
|
+
|
3
|
+
module Scenic
|
4
|
+
module Adapters
|
5
|
+
describe Postgres::Views, :db do
|
6
|
+
it "returns scenic view objects for plain old views" do
|
7
|
+
connection = ActiveRecord::Base.connection
|
8
|
+
connection.execute <<-SQL
|
9
|
+
CREATE VIEW children AS SELECT text 'Elliot' AS name
|
10
|
+
SQL
|
11
|
+
|
12
|
+
views = Postgres::Views.new(connection).all
|
13
|
+
first = views.first
|
14
|
+
|
15
|
+
expect(views.size).to eq 1
|
16
|
+
expect(first.name).to eq "children"
|
17
|
+
expect(first.materialized).to be false
|
18
|
+
expect(first.definition).to eq "SELECT 'Elliot'::text AS name;"
|
19
|
+
end
|
20
|
+
|
21
|
+
it "returns scenic view objects for materialized views" do
|
22
|
+
connection = ActiveRecord::Base.connection
|
23
|
+
connection.execute <<-SQL
|
24
|
+
CREATE MATERIALIZED VIEW children AS SELECT text 'Owen' AS name
|
25
|
+
SQL
|
26
|
+
|
27
|
+
views = Postgres::Views.new(connection).all
|
28
|
+
first = views.first
|
29
|
+
|
30
|
+
expect(views.size).to eq 1
|
31
|
+
expect(first.name).to eq "children"
|
32
|
+
expect(first.materialized).to be true
|
33
|
+
expect(first.definition).to eq "SELECT 'Owen'::text AS name;"
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -3,7 +3,7 @@ require "spec_helper"
|
|
3
3
|
module Scenic
|
4
4
|
module Adapters
|
5
5
|
describe Postgres, :db do
|
6
|
-
describe "create_view" do
|
6
|
+
describe "#create_view" do
|
7
7
|
it "successfully creates a view" do
|
8
8
|
adapter = Postgres.new
|
9
9
|
|
@@ -13,7 +13,7 @@ module Scenic
|
|
13
13
|
end
|
14
14
|
end
|
15
15
|
|
16
|
-
describe "create_materialized_view" do
|
16
|
+
describe "#create_materialized_view" do
|
17
17
|
it "successfully creates a materialized view" do
|
18
18
|
adapter = Postgres.new
|
19
19
|
|
@@ -26,9 +26,18 @@ module Scenic
|
|
26
26
|
expect(view.name).to eq("greetings")
|
27
27
|
expect(view.materialized).to eq true
|
28
28
|
end
|
29
|
+
|
30
|
+
it "raises an exception if the version of PostgreSQL is too old" do
|
31
|
+
connection = double("Connection", supports_materialized_views?: false)
|
32
|
+
adapter = Postgres.new(connection)
|
33
|
+
err = Scenic::Adapters::Postgres::MaterializedViewsNotSupportedError
|
34
|
+
|
35
|
+
expect { adapter.create_materialized_view("greetings", "select 1") }
|
36
|
+
.to raise_error err
|
37
|
+
end
|
29
38
|
end
|
30
39
|
|
31
|
-
describe "drop_view" do
|
40
|
+
describe "#drop_view" do
|
32
41
|
it "successfully drops a view" do
|
33
42
|
adapter = Postgres.new
|
34
43
|
|
@@ -39,7 +48,7 @@ module Scenic
|
|
39
48
|
end
|
40
49
|
end
|
41
50
|
|
42
|
-
describe "drop_materialized_view" do
|
51
|
+
describe "#drop_materialized_view" do
|
43
52
|
it "successfully drops a materialized view" do
|
44
53
|
adapter = Postgres.new
|
45
54
|
|
@@ -51,30 +60,79 @@ module Scenic
|
|
51
60
|
|
52
61
|
expect(adapter.views.map(&:name)).not_to include("greetings")
|
53
62
|
end
|
63
|
+
|
64
|
+
it "raises an exception if the version of PostgreSQL is too old" do
|
65
|
+
connection = double("Connection", supports_materialized_views?: false)
|
66
|
+
adapter = Postgres.new(connection)
|
67
|
+
err = Scenic::Adapters::Postgres::MaterializedViewsNotSupportedError
|
68
|
+
|
69
|
+
expect { adapter.drop_materialized_view("greetings") }
|
70
|
+
.to raise_error err
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
74
|
+
describe "#refresh_materialized_view" do
|
75
|
+
it "raises an exception if the version of PostgreSQL is too old" do
|
76
|
+
connection = double("Connection", supports_materialized_views?: false)
|
77
|
+
adapter = Postgres.new(connection)
|
78
|
+
err = Scenic::Adapters::Postgres::MaterializedViewsNotSupportedError
|
79
|
+
|
80
|
+
expect { adapter.refresh_materialized_view(:tests) }
|
81
|
+
.to raise_error err
|
82
|
+
end
|
83
|
+
|
84
|
+
context "refreshing concurrently" do
|
85
|
+
it "raises descriptive error if concurrent refresh is not possible" do
|
86
|
+
adapter = Postgres.new
|
87
|
+
adapter.create_materialized_view(:tests, "SELECT text 'hi' as text")
|
88
|
+
|
89
|
+
expect {
|
90
|
+
adapter.refresh_materialized_view(:tests, concurrently: true)
|
91
|
+
}.to raise_error(/Create a unique index with no WHERE clause/)
|
92
|
+
end
|
93
|
+
|
94
|
+
it "raises an exception if the version of PostgreSQL is too old" do
|
95
|
+
connection = double("Connection", postgresql_version: 90300)
|
96
|
+
adapter = Postgres.new(connection)
|
97
|
+
e = Scenic::Adapters::Postgres::ConcurrentRefreshesNotSupportedError
|
98
|
+
|
99
|
+
expect {
|
100
|
+
adapter.refresh_materialized_view(:tests, concurrently: true)
|
101
|
+
}.to raise_error e
|
102
|
+
end
|
103
|
+
end
|
54
104
|
end
|
55
105
|
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
106
|
+
describe "#views" do
|
107
|
+
it "returns the views defined on this connection" do
|
108
|
+
adapter = Postgres.new
|
109
|
+
|
110
|
+
ActiveRecord::Base.connection.execute <<-SQL
|
111
|
+
CREATE VIEW parents AS SELECT text 'Joe' AS name
|
112
|
+
SQL
|
113
|
+
|
114
|
+
ActiveRecord::Base.connection.execute <<-SQL
|
115
|
+
CREATE VIEW children AS SELECT text 'Owen' AS name
|
116
|
+
SQL
|
117
|
+
|
118
|
+
ActiveRecord::Base.connection.execute <<-SQL
|
119
|
+
CREATE MATERIALIZED VIEW people AS
|
120
|
+
SELECT name FROM parents UNION SELECT name FROM children
|
121
|
+
SQL
|
122
|
+
|
123
|
+
ActiveRecord::Base.connection.execute <<-SQL
|
124
|
+
CREATE VIEW people_with_names AS
|
125
|
+
SELECT name FROM people
|
126
|
+
WHERE name IS NOT NULL
|
127
|
+
SQL
|
128
|
+
|
129
|
+
expect(adapter.views.map(&:name)).to eq [
|
130
|
+
"parents",
|
131
|
+
"children",
|
132
|
+
"people",
|
133
|
+
"people_with_names",
|
134
|
+
]
|
135
|
+
end
|
78
136
|
end
|
79
137
|
end
|
80
138
|
end
|
@@ -65,7 +65,7 @@ module Scenic
|
|
65
65
|
end
|
66
66
|
|
67
67
|
describe "update_view" do
|
68
|
-
it "
|
68
|
+
it "updates the view in the database" do
|
69
69
|
definition = instance_double("Definition", to_sql: "definition")
|
70
70
|
allow(Definition).to receive(:new)
|
71
71
|
.with(:name, 3)
|
@@ -73,8 +73,19 @@ module Scenic
|
|
73
73
|
|
74
74
|
connection.update_view(:name, version: 3)
|
75
75
|
|
76
|
-
expect(Scenic.database).to have_received(:
|
77
|
-
|
76
|
+
expect(Scenic.database).to have_received(:update_view)
|
77
|
+
.with(:name, definition.to_sql)
|
78
|
+
end
|
79
|
+
|
80
|
+
it "updates the materialized view in the database" do
|
81
|
+
definition = instance_double("Definition", to_sql: "definition")
|
82
|
+
allow(Definition).to receive(:new)
|
83
|
+
.with(:name, 3)
|
84
|
+
.and_return(definition)
|
85
|
+
|
86
|
+
connection.update_view(:name, version: 3, materialized: true)
|
87
|
+
|
88
|
+
expect(Scenic.database).to have_received(:update_materialized_view)
|
78
89
|
.with(:name, definition.to_sql)
|
79
90
|
end
|
80
91
|
|
@@ -84,18 +95,6 @@ module Scenic
|
|
84
95
|
end
|
85
96
|
end
|
86
97
|
|
87
|
-
describe "update_view :materialized" do
|
88
|
-
it "raises an error because this is not supported" do
|
89
|
-
definition = instance_double("Definition").as_null_object
|
90
|
-
allow(Definition).to receive(:new).and_return(definition)
|
91
|
-
|
92
|
-
expect { connection.update_view(:name, version: 3, materialized: true) }.
|
93
|
-
to raise_error(/not supported/)
|
94
|
-
expect(Scenic.database).not_to have_received(:drop_materialized_view)
|
95
|
-
expect(Scenic.database).not_to have_received(:create_materialized_view)
|
96
|
-
end
|
97
|
-
end
|
98
|
-
|
99
98
|
def connection
|
100
99
|
Class.new { extend Statements }
|
101
100
|
end
|
data/spec/smoke
CHANGED
@@ -21,7 +21,7 @@ trap teardown EXIT
|
|
21
21
|
verifySearchResults() {
|
22
22
|
echo "verify search results"
|
23
23
|
local expectedResult=$1
|
24
|
-
local actualResult=$(rails runner "puts Search.
|
24
|
+
local actualResult=$(rails runner "puts Search.take.results")
|
25
25
|
[[ "$actualResult" == "$expectedResult" ]] || exit 1
|
26
26
|
echo "[success]"
|
27
27
|
}
|
@@ -32,7 +32,7 @@ writeToFileAndMigrateAndVerifySearchResults() {
|
|
32
32
|
local expectedResult=$2
|
33
33
|
local filePath=db/views/searches_v$version\.sql
|
34
34
|
cp /dev/null $filePath
|
35
|
-
echo "SELECT '$expectedResult'::text AS results" >> $filePath
|
35
|
+
echo "SELECT '$expectedResult'::text AS results, 1 AS user_id" >> $filePath
|
36
36
|
rake db:migrate
|
37
37
|
echo "[success]"
|
38
38
|
verifySearchResults $expectedResult
|
@@ -97,11 +97,24 @@ main() {
|
|
97
97
|
rails runner "Search.refresh" || exit 1
|
98
98
|
echo "[success]"
|
99
99
|
|
100
|
+
echo "add indexes to materialized view"
|
101
|
+
rails runner "ActiveRecord::Base.connection.execute 'CREATE INDEX searches_test_1 ON searches USING btree (results);'" || exit 1
|
102
|
+
rails runner "ActiveRecord::Base.connection.execute 'CREATE INDEX searches_test_2 ON searches USING btree (user_id);'" || exit 1
|
103
|
+
echo "[success]"
|
104
|
+
|
105
|
+
echo "update materialized view"
|
106
|
+
rails generate scenic:view search --materialized
|
107
|
+
echo "SELECT 'test'::text AS results" > db/views/searches_v02.sql
|
108
|
+
rake db:migrate
|
109
|
+
verifySearchResults 'test'
|
110
|
+
|
100
111
|
echo "rake db:rollback"
|
101
112
|
rake db:rollback
|
113
|
+
rake db:rollback
|
102
114
|
echo "[success]"
|
103
115
|
|
104
|
-
echo "rails destroy scenic:
|
116
|
+
echo "rails destroy scenic:model search --materialized"
|
117
|
+
rails destroy scenic:view search --materialized
|
105
118
|
rails destroy scenic:model search --materialized
|
106
119
|
[[ ! -f app/models/search.rb ]] || exit 1
|
107
120
|
[[ ! -f db/views/searches_v01.sql ]] || exit 1
|
data/spec/spec_helper.rb
CHANGED
metadata
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: scenic
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.
|
4
|
+
version: 1.1.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Derek Prior
|
@@ -9,8 +9,22 @@ authors:
|
|
9
9
|
autorequire:
|
10
10
|
bindir: bin
|
11
11
|
cert_chain: []
|
12
|
-
date:
|
12
|
+
date: 2016-01-20 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
|
+
- !ruby/object:Gem::Dependency
|
15
|
+
name: appraisal
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
17
|
+
requirements:
|
18
|
+
- - ">="
|
19
|
+
- !ruby/object:Gem::Version
|
20
|
+
version: '0'
|
21
|
+
type: :development
|
22
|
+
prerelease: false
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
24
|
+
requirements:
|
25
|
+
- - ">="
|
26
|
+
- !ruby/object:Gem::Version
|
27
|
+
version: '0'
|
14
28
|
- !ruby/object:Gem::Dependency
|
15
29
|
name: bundler
|
16
30
|
requirement: !ruby/object:Gem::Requirement
|
@@ -109,6 +123,34 @@ dependencies:
|
|
109
123
|
- - ">="
|
110
124
|
- !ruby/object:Gem::Version
|
111
125
|
version: 1.1.3
|
126
|
+
- !ruby/object:Gem::Dependency
|
127
|
+
name: yard
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
129
|
+
requirements:
|
130
|
+
- - ">="
|
131
|
+
- !ruby/object:Gem::Version
|
132
|
+
version: '0'
|
133
|
+
type: :development
|
134
|
+
prerelease: false
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
136
|
+
requirements:
|
137
|
+
- - ">="
|
138
|
+
- !ruby/object:Gem::Version
|
139
|
+
version: '0'
|
140
|
+
- !ruby/object:Gem::Dependency
|
141
|
+
name: redcarpet
|
142
|
+
requirement: !ruby/object:Gem::Requirement
|
143
|
+
requirements:
|
144
|
+
- - ">="
|
145
|
+
- !ruby/object:Gem::Version
|
146
|
+
version: '0'
|
147
|
+
type: :development
|
148
|
+
prerelease: false
|
149
|
+
version_requirements: !ruby/object:Gem::Requirement
|
150
|
+
requirements:
|
151
|
+
- - ">="
|
152
|
+
- !ruby/object:Gem::Version
|
153
|
+
version: '0'
|
112
154
|
- !ruby/object:Gem::Dependency
|
113
155
|
name: activerecord
|
114
156
|
requirement: !ruby/object:Gem::Requirement
|
@@ -151,13 +193,20 @@ files:
|
|
151
193
|
- ".hound.yml"
|
152
194
|
- ".travis.yml"
|
153
195
|
- ".yardopts"
|
196
|
+
- Appraisals
|
154
197
|
- CONTRIBUTING.md
|
155
198
|
- Gemfile
|
156
199
|
- LICENSE.txt
|
157
200
|
- NEWS.md
|
158
201
|
- README.md
|
159
202
|
- Rakefile
|
203
|
+
- bin/appraisal
|
160
204
|
- bin/setup
|
205
|
+
- bin/yard
|
206
|
+
- gemfiles/rails40.gemfile
|
207
|
+
- gemfiles/rails41.gemfile
|
208
|
+
- gemfiles/rails42.gemfile
|
209
|
+
- gemfiles/rails50.gemfile
|
161
210
|
- lib/generators/scenic/generators.rb
|
162
211
|
- lib/generators/scenic/materializable.rb
|
163
212
|
- lib/generators/scenic/model/USAGE
|
@@ -169,10 +218,16 @@ files:
|
|
169
218
|
- lib/generators/scenic/view/view_generator.rb
|
170
219
|
- lib/scenic.rb
|
171
220
|
- lib/scenic/adapters/postgres.rb
|
221
|
+
- lib/scenic/adapters/postgres/connection.rb
|
222
|
+
- lib/scenic/adapters/postgres/errors.rb
|
223
|
+
- lib/scenic/adapters/postgres/index_reapplication.rb
|
224
|
+
- lib/scenic/adapters/postgres/indexes.rb
|
225
|
+
- lib/scenic/adapters/postgres/views.rb
|
172
226
|
- lib/scenic/command_recorder.rb
|
173
227
|
- lib/scenic/command_recorder/statement_arguments.rb
|
174
228
|
- lib/scenic/configuration.rb
|
175
229
|
- lib/scenic/definition.rb
|
230
|
+
- lib/scenic/index.rb
|
176
231
|
- lib/scenic/railtie.rb
|
177
232
|
- lib/scenic/schema_dumper.rb
|
178
233
|
- lib/scenic/statements.rb
|
@@ -189,13 +244,13 @@ files:
|
|
189
244
|
- spec/dummy/config/boot.rb
|
190
245
|
- spec/dummy/config/database.yml
|
191
246
|
- spec/dummy/config/environment.rb
|
192
|
-
- spec/dummy/config/environments/development.rb
|
193
|
-
- spec/dummy/config/environments/test.rb
|
194
247
|
- spec/dummy/db/migrate/.keep
|
195
248
|
- spec/dummy/db/views/.keep
|
196
249
|
- spec/generators/scenic/model/model_generator_spec.rb
|
197
250
|
- spec/generators/scenic/view/view_generator_spec.rb
|
198
251
|
- spec/integration/revert_spec.rb
|
252
|
+
- spec/scenic/adapters/postgres/connection_spec.rb
|
253
|
+
- spec/scenic/adapters/postgres/views_spec.rb
|
199
254
|
- spec/scenic/adapters/postgres_spec.rb
|
200
255
|
- spec/scenic/command_recorder/statement_arguments_spec.rb
|
201
256
|
- spec/scenic/command_recorder_spec.rb
|
@@ -219,7 +274,7 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
219
274
|
requirements:
|
220
275
|
- - "~>"
|
221
276
|
- !ruby/object:Gem::Version
|
222
|
-
version: '2.
|
277
|
+
version: '2.1'
|
223
278
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
224
279
|
requirements:
|
225
280
|
- - ">="
|
@@ -227,7 +282,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
227
282
|
version: '0'
|
228
283
|
requirements: []
|
229
284
|
rubyforge_project:
|
230
|
-
rubygems_version: 2.
|
285
|
+
rubygems_version: 2.5.1
|
231
286
|
signing_key:
|
232
287
|
specification_version: 4
|
233
288
|
summary: Support for database views in Rails migrations
|
@@ -242,13 +297,13 @@ test_files:
|
|
242
297
|
- spec/dummy/config/boot.rb
|
243
298
|
- spec/dummy/config/database.yml
|
244
299
|
- spec/dummy/config/environment.rb
|
245
|
-
- spec/dummy/config/environments/development.rb
|
246
|
-
- spec/dummy/config/environments/test.rb
|
247
300
|
- spec/dummy/db/migrate/.keep
|
248
301
|
- spec/dummy/db/views/.keep
|
249
302
|
- spec/generators/scenic/model/model_generator_spec.rb
|
250
303
|
- spec/generators/scenic/view/view_generator_spec.rb
|
251
304
|
- spec/integration/revert_spec.rb
|
305
|
+
- spec/scenic/adapters/postgres/connection_spec.rb
|
306
|
+
- spec/scenic/adapters/postgres/views_spec.rb
|
252
307
|
- spec/scenic/adapters/postgres_spec.rb
|
253
308
|
- spec/scenic/command_recorder/statement_arguments_spec.rb
|
254
309
|
- spec/scenic/command_recorder_spec.rb
|
@@ -260,3 +315,4 @@ test_files:
|
|
260
315
|
- spec/spec_helper.rb
|
261
316
|
- spec/support/generator_spec_setup.rb
|
262
317
|
- spec/support/view_definition_helpers.rb
|
318
|
+
has_rdoc:
|