scenic 1.0.0 → 1.2.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.
Files changed (46) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +1 -0
  3. data/.travis.yml +14 -4
  4. data/.yardopts +0 -1
  5. data/Appraisals +26 -0
  6. data/CONTRIBUTING.md +5 -4
  7. data/LICENSE.txt +1 -1
  8. data/NEWS.md +49 -0
  9. data/README.md +71 -28
  10. data/bin/appraisal +16 -0
  11. data/bin/setup +5 -0
  12. data/bin/yard +16 -0
  13. data/gemfiles/rails40.gemfile +8 -0
  14. data/gemfiles/rails41.gemfile +8 -0
  15. data/gemfiles/rails42.gemfile +8 -0
  16. data/gemfiles/rails50.gemfile +13 -0
  17. data/lib/generators/scenic/generators.rb +1 -0
  18. data/lib/generators/scenic/model/templates/model.erb +1 -1
  19. data/lib/generators/scenic/view/templates/db/migrate/create_view.erb +1 -1
  20. data/lib/generators/scenic/view/templates/db/migrate/update_view.erb +2 -2
  21. data/lib/generators/scenic/view/view_generator.rb +13 -1
  22. data/lib/scenic/adapters/postgres/connection.rb +57 -0
  23. data/lib/scenic/adapters/postgres/errors.rb +26 -0
  24. data/lib/scenic/adapters/postgres/index_reapplication.rb +71 -0
  25. data/lib/scenic/adapters/postgres/indexes.rb +53 -0
  26. data/lib/scenic/adapters/postgres/views.rb +51 -0
  27. data/lib/scenic/adapters/postgres.rb +144 -33
  28. data/lib/scenic/configuration.rb +2 -2
  29. data/lib/scenic/index.rb +36 -0
  30. data/lib/scenic/schema_dumper.rb +12 -5
  31. data/lib/scenic/statements.rb +7 -13
  32. data/lib/scenic/version.rb +1 -1
  33. data/lib/scenic/view.rb +1 -4
  34. data/lib/scenic.rb +1 -0
  35. data/scenic.gemspec +4 -1
  36. data/spec/dummy/config/application.rb +3 -0
  37. data/spec/generators/scenic/view/view_generator_spec.rb +12 -0
  38. data/spec/scenic/adapters/postgres/connection_spec.rb +79 -0
  39. data/spec/scenic/adapters/postgres/views_spec.rb +37 -0
  40. data/spec/scenic/adapters/postgres_spec.rb +88 -26
  41. data/spec/scenic/statements_spec.rb +14 -15
  42. data/spec/smoke +24 -3
  43. data/spec/spec_helper.rb +4 -0
  44. metadata +64 -8
  45. data/spec/dummy/config/environments/development.rb +0 -6
  46. data/spec/dummy/config/environments/test.rb +0 -5
@@ -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,19 @@ 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
+ connectable = double("Connectable", connection: connection)
33
+ adapter = Postgres.new(connectable)
34
+ err = Scenic::Adapters::Postgres::MaterializedViewsNotSupportedError
35
+
36
+ expect { adapter.create_materialized_view("greetings", "select 1") }
37
+ .to raise_error err
38
+ end
29
39
  end
30
40
 
31
- describe "drop_view" do
41
+ describe "#drop_view" do
32
42
  it "successfully drops a view" do
33
43
  adapter = Postgres.new
34
44
 
@@ -39,7 +49,7 @@ module Scenic
39
49
  end
40
50
  end
41
51
 
42
- describe "drop_materialized_view" do
52
+ describe "#drop_materialized_view" do
43
53
  it "successfully drops a materialized view" do
44
54
  adapter = Postgres.new
45
55
 
@@ -51,30 +61,82 @@ module Scenic
51
61
 
52
62
  expect(adapter.views.map(&:name)).not_to include("greetings")
53
63
  end
64
+
65
+ it "raises an exception if the version of PostgreSQL is too old" do
66
+ connection = double("Connection", supports_materialized_views?: false)
67
+ connectable = double("Connectable", connection: connection)
68
+ adapter = Postgres.new(connectable)
69
+ err = Scenic::Adapters::Postgres::MaterializedViewsNotSupportedError
70
+
71
+ expect { adapter.drop_materialized_view("greetings") }
72
+ .to raise_error err
73
+ end
74
+ end
75
+
76
+ describe "#refresh_materialized_view" do
77
+ it "raises an exception if the version of PostgreSQL is too old" do
78
+ connection = double("Connection", supports_materialized_views?: false)
79
+ connectable = double("Connectable", connection: connection)
80
+ adapter = Postgres.new(connectable)
81
+ err = Scenic::Adapters::Postgres::MaterializedViewsNotSupportedError
82
+
83
+ expect { adapter.refresh_materialized_view(:tests) }
84
+ .to raise_error err
85
+ end
86
+
87
+ context "refreshing concurrently" do
88
+ it "raises descriptive error if concurrent refresh is not possible" do
89
+ adapter = Postgres.new
90
+ adapter.create_materialized_view(:tests, "SELECT text 'hi' as text")
91
+
92
+ expect {
93
+ adapter.refresh_materialized_view(:tests, concurrently: true)
94
+ }.to raise_error(/Create a unique index with no WHERE clause/)
95
+ end
96
+
97
+ it "raises an exception if the version of PostgreSQL is too old" do
98
+ connection = double("Connection", postgresql_version: 90300)
99
+ connectable = double("Connectable", connection: connection)
100
+ adapter = Postgres.new(connectable)
101
+ e = Scenic::Adapters::Postgres::ConcurrentRefreshesNotSupportedError
102
+
103
+ expect {
104
+ adapter.refresh_materialized_view(:tests, concurrently: true)
105
+ }.to raise_error e
106
+ end
107
+ end
54
108
  end
55
109
 
56
- it "finds views and builds Scenic::View objects" do
57
- adapter = Postgres.new
58
-
59
- ActiveRecord::Base.connection.execute(
60
- "CREATE VIEW greetings AS SELECT text 'hi' AS greeting"
61
- )
62
- ActiveRecord::Base.connection.execute(
63
- "CREATE MATERIALIZED VIEW farewells AS SELECT text 'bye' AS farewell"
64
- )
65
-
66
- expect(adapter.views).to eq([
67
- Scenic::View.new(
68
- name: "farewells",
69
- definition: "SELECT 'bye'::text AS farewell;",
70
- materialized: true,
71
- ),
72
- Scenic::View.new(
73
- name: "greetings",
74
- definition: "SELECT 'hi'::text AS greeting;",
75
- materialized: false,
76
- ),
77
- ])
110
+ describe "#views" do
111
+ it "returns the views defined on this connection" do
112
+ adapter = Postgres.new
113
+
114
+ ActiveRecord::Base.connection.execute <<-SQL
115
+ CREATE VIEW parents AS SELECT text 'Joe' AS name
116
+ SQL
117
+
118
+ ActiveRecord::Base.connection.execute <<-SQL
119
+ CREATE VIEW children AS SELECT text 'Owen' AS name
120
+ SQL
121
+
122
+ ActiveRecord::Base.connection.execute <<-SQL
123
+ CREATE MATERIALIZED VIEW people AS
124
+ SELECT name FROM parents UNION SELECT name FROM children
125
+ SQL
126
+
127
+ ActiveRecord::Base.connection.execute <<-SQL
128
+ CREATE VIEW people_with_names AS
129
+ SELECT name FROM people
130
+ WHERE name IS NOT NULL
131
+ SQL
132
+
133
+ expect(adapter.views.map(&:name)).to eq [
134
+ "parents",
135
+ "children",
136
+ "people",
137
+ "people_with_names",
138
+ ]
139
+ end
78
140
  end
79
141
  end
80
142
  end
@@ -65,7 +65,7 @@ module Scenic
65
65
  end
66
66
 
67
67
  describe "update_view" do
68
- it "drops the existing version and creates the new" do
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(:drop_view).with(:name)
77
- expect(Scenic.database).to have_received(:create_view)
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,18 +21,25 @@ trap teardown EXIT
21
21
  verifySearchResults() {
22
22
  echo "verify search results"
23
23
  local expectedResult=$1
24
- local actualResult=$(rails runner "puts Search.first.results")
24
+ local actualResult=$(rails runner "puts Search.take.results")
25
25
  [[ "$actualResult" == "$expectedResult" ]] || exit 1
26
26
  echo "[success]"
27
27
  }
28
28
 
29
+ verifySchemaContains() {
30
+ local expectedString=$1
31
+ echo "verify schema contains '$expectedString'"
32
+ grep -q "$expectedString" db/schema.rb || exit 1
33
+ echo "[success]"
34
+ }
35
+
29
36
  writeToFileAndMigrateAndVerifySearchResults() {
30
37
  echo "write search definition and migrate"
31
38
  local version=$1
32
39
  local expectedResult=$2
33
40
  local filePath=db/views/searches_v$version\.sql
34
41
  cp /dev/null $filePath
35
- echo "SELECT '$expectedResult'::text AS results" >> $filePath
42
+ echo "SELECT '$expectedResult'::text AS results, 1 AS user_id" >> $filePath
36
43
  rake db:migrate
37
44
  echo "[success]"
38
45
  verifySearchResults $expectedResult
@@ -97,11 +104,25 @@ main() {
97
104
  rails runner "Search.refresh" || exit 1
98
105
  echo "[success]"
99
106
 
107
+ echo "add indexes to materialized view"
108
+ rails runner 'ActiveRecord::Migration.add_index :searches, :results' || exit 1
109
+ rails runner 'ActiveRecord::Migration.add_index :searches, :user_id' || exit 1
110
+ echo "[success]"
111
+
112
+ echo "update materialized view"
113
+ rails generate scenic:view search --materialized
114
+ echo "SELECT 'test'::text AS results" > db/views/searches_v02.sql
115
+ rake db:migrate
116
+ verifySearchResults 'test'
117
+ verifySchemaContains 'add_index "searches"'
118
+
100
119
  echo "rake db:rollback"
101
120
  rake db:rollback
121
+ rake db:rollback
102
122
  echo "[success]"
103
123
 
104
- echo "rails destroy scenic:view search --materialized"
124
+ echo "rails destroy scenic:model search --materialized"
125
+ rails destroy scenic:view search --materialized
105
126
  rails destroy scenic:model search --materialized
106
127
  [[ ! -f app/models/search.rb ]] || exit 1
107
128
  [[ ! -f db/views/searches_v01.sql ]] || exit 1
data/spec/spec_helper.rb CHANGED
@@ -15,4 +15,8 @@ RSpec.configure do |config|
15
15
  example.run
16
16
  DatabaseCleaner.clean
17
17
  end
18
+
19
+ if defined? ActiveSupport::Testing::Stream
20
+ config.include ActiveSupport::Testing::Stream
21
+ end
18
22
  end
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.0.0
4
+ version: 1.2.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: 2015-12-03 00:00:00.000000000 Z
12
+ date: 2016-02-06 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.0'
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.4.8
285
+ rubygems_version: 2.2.5
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:
@@ -1,6 +0,0 @@
1
- Rails.application.configure do
2
- config.cache_classes = false
3
-
4
- # Do not eager load code on boot.
5
- config.eager_load = false
6
- end
@@ -1,5 +0,0 @@
1
- Rails.application.configure do
2
- config.cache_classes = true
3
- config.eager_load = false
4
- config.active_support.deprecation = :stderr
5
- end