scenic 1.4.1 → 1.5.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 (44) hide show
  1. checksums.yaml +5 -5
  2. data/.hound.yml +2 -4
  3. data/.rubocop.yml +129 -0
  4. data/.travis.yml +11 -17
  5. data/Appraisals +14 -21
  6. data/CODE_OF_CONDUCT.md +76 -0
  7. data/CONTRIBUTING.md +3 -7
  8. data/Gemfile +1 -1
  9. data/NEWS.md +32 -13
  10. data/README.md +15 -16
  11. data/Rakefile +2 -2
  12. data/gemfiles/rails42.gemfile +1 -1
  13. data/gemfiles/rails50.gemfile +1 -1
  14. data/gemfiles/rails51.gemfile +1 -1
  15. data/gemfiles/rails52.gemfile +8 -0
  16. data/gemfiles/rails_edge.gemfile +3 -3
  17. data/lib/generators/scenic/materializable.rb +9 -0
  18. data/lib/generators/scenic/model/model_generator.rb +2 -2
  19. data/lib/generators/scenic/view/USAGE +1 -0
  20. data/lib/generators/scenic/view/templates/db/migrate/create_view.erb +1 -1
  21. data/lib/generators/scenic/view/templates/db/migrate/update_view.erb +1 -1
  22. data/lib/generators/scenic/view/view_generator.rb +13 -5
  23. data/lib/scenic/adapters/postgres.rb +14 -4
  24. data/lib/scenic/adapters/postgres/refresh_dependencies.rb +12 -2
  25. data/lib/scenic/adapters/postgres/views.rb +10 -1
  26. data/lib/scenic/schema_dumper.rb +2 -2
  27. data/lib/scenic/statements.rb +24 -6
  28. data/lib/scenic/version.rb +1 -1
  29. data/lib/scenic/view.rb +1 -2
  30. data/scenic.gemspec +22 -23
  31. data/spec/acceptance/user_manages_views_spec.rb +2 -1
  32. data/spec/dummy/app/models/application_record.rb +5 -0
  33. data/spec/generators/scenic/model/model_generator_spec.rb +1 -1
  34. data/spec/generators/scenic/view/view_generator_spec.rb +1 -1
  35. data/spec/scenic/adapters/postgres/refresh_dependencies_spec.rb +60 -26
  36. data/spec/scenic/adapters/postgres_spec.rb +2 -2
  37. data/spec/scenic/definition_spec.rb +1 -1
  38. data/spec/scenic/schema_dumper_spec.rb +17 -2
  39. data/spec/scenic/statements_spec.rb +48 -13
  40. data/spec/spec_helper.rb +1 -1
  41. data/spec/support/generator_spec_setup.rb +1 -1
  42. metadata +15 -13
  43. data/gemfiles/rails40.gemfile +0 -8
  44. data/gemfiles/rails41.gemfile +0 -8
@@ -1,4 +1,5 @@
1
1
  require "acceptance_helper"
2
+ require "English"
2
3
 
3
4
  describe "User manages views" do
4
5
  it "handles simple views" do
@@ -56,7 +57,7 @@ describe "User manages views" do
56
57
 
57
58
  def successfully(command)
58
59
  `RAILS_ENV=test #{command}`
59
- expect($?.exitstatus).to eq(0), "'#{command}' was unsuccessful"
60
+ expect($CHILD_STATUS.exitstatus).to eq(0), "'#{command}' was unsuccessful"
60
61
  end
61
62
 
62
63
  def write_definition(file, contents)
@@ -0,0 +1,5 @@
1
+ if Rails::VERSION::STRING >= "5.0.0"
2
+ class ApplicationRecord < ActiveRecord::Base
3
+ self.abstract_class = true
4
+ end
5
+ end
@@ -6,7 +6,7 @@ module Scenic::Generators
6
6
  before do
7
7
  allow(ViewGenerator).to receive(:new)
8
8
  .and_return(
9
- instance_double("Scenic::Generators::ViewGenerator").as_null_object
9
+ instance_double("Scenic::Generators::ViewGenerator").as_null_object,
10
10
  )
11
11
  end
12
12
 
@@ -31,7 +31,7 @@ describe Scenic::Generators::ViewGenerator, :generator do
31
31
 
32
32
  run_generator ["aired_episode", "--materialized"]
33
33
  migration = migration_file(
34
- "db/migrate/update_aired_episodes_to_version_2.rb"
34
+ "db/migrate/update_aired_episodes_to_version_2.rb",
35
35
  )
36
36
  expect(migration).to contain "materialized: true"
37
37
  end
@@ -3,39 +3,73 @@ require "spec_helper"
3
3
  module Scenic
4
4
  module Adapters
5
5
  describe Postgres::RefreshDependencies, :db do
6
- it "refreshes dependecies in the correct order" do
7
- adapter = Postgres.new
6
+ context "view has dependencies" do
7
+ let(:adapter) { Postgres.new }
8
8
 
9
- adapter.create_materialized_view(
10
- "first",
11
- "SELECT text 'hi' AS greeting",
12
- )
9
+ before do
10
+ adapter.create_materialized_view(
11
+ "first",
12
+ "SELECT text 'hi' AS greeting",
13
+ )
14
+ adapter.create_materialized_view(
15
+ "second",
16
+ "SELECT * FROM first",
17
+ )
18
+ adapter.create_materialized_view(
19
+ "third",
20
+ "SELECT * FROM first UNION SELECT * FROM second",
21
+ )
22
+ adapter.create_materialized_view(
23
+ "fourth_1",
24
+ "SELECT * FROM third",
25
+ )
26
+ adapter.create_materialized_view(
27
+ "x_fourth",
28
+ "SELECT * FROM fourth_1",
29
+ )
30
+ adapter.create_materialized_view(
31
+ "fourth",
32
+ "SELECT * FROM fourth_1 UNION SELECT * FROM x_fourth",
33
+ )
13
34
 
14
- adapter.create_materialized_view(
15
- "second",
16
- "SELECT * from first",
17
- )
35
+ expect(adapter).to receive(:refresh_materialized_view)
36
+ .with("public.first").ordered
37
+ expect(adapter).to receive(:refresh_materialized_view)
38
+ .with("public.second").ordered
39
+ expect(adapter).to receive(:refresh_materialized_view)
40
+ .with("public.third").ordered
41
+ expect(adapter).to receive(:refresh_materialized_view)
42
+ .with("public.fourth_1").ordered
43
+ expect(adapter).to receive(:refresh_materialized_view)
44
+ .with("public.x_fourth").ordered
45
+ end
18
46
 
19
- adapter.create_materialized_view(
20
- "third",
21
- "SELECT * from first UNION SELECT * from second",
22
- )
47
+ it "refreshes in the right order when called without namespace" do
48
+ described_class.call(:fourth, adapter, ActiveRecord::Base.connection)
49
+ end
23
50
 
24
- adapter.create_materialized_view(
25
- "fourth",
26
- "SELECT * from third",
27
- )
28
-
29
- expect(adapter).to receive(:refresh_materialized_view).
30
- with("public.first").ordered
51
+ it "refreshes in the right order when called with namespace" do
52
+ described_class.call(
53
+ "public.fourth",
54
+ adapter,
55
+ ActiveRecord::Base.connection,
56
+ )
57
+ end
58
+ end
31
59
 
32
- expect(adapter).to receive(:refresh_materialized_view).
33
- with("public.second").ordered
60
+ context "view has no dependencies" do
61
+ it "does not raise an error" do
62
+ adapter = Postgres.new
34
63
 
35
- expect(adapter).to receive(:refresh_materialized_view).
36
- with("public.third").ordered
64
+ adapter.create_materialized_view(
65
+ "first",
66
+ "SELECT text 'hi' AS greeting",
67
+ )
37
68
 
38
- described_class.call(:fourth, adapter, ActiveRecord::Base.connection)
69
+ expect {
70
+ described_class.call(:first, adapter, ActiveRecord::Base.connection)
71
+ }.not_to raise_error
72
+ end
39
73
  end
40
74
  end
41
75
  end
@@ -104,8 +104,8 @@ module Scenic
104
104
  connection = double("Connection").as_null_object
105
105
  connectable = double("Connectable", connection: connection)
106
106
  adapter = Postgres.new(connectable)
107
- expect(Scenic::Adapters::Postgres::RefreshDependencies).
108
- to receive(:call).with(:tests, adapter, connection)
107
+ expect(Scenic::Adapters::Postgres::RefreshDependencies)
108
+ .to receive(:call).with(:tests, adapter, connection)
109
109
  adapter.refresh_materialized_view(:tests, cascade: true)
110
110
  end
111
111
 
@@ -22,7 +22,7 @@ module Scenic
22
22
  end
23
23
 
24
24
  describe "path" do
25
- it "returns a sql file in db/views with padded version and view name" do
25
+ it "returns a sql file in db/views with padded version and view name" do
26
26
  expected = "db/views/searches_v01.sql"
27
27
 
28
28
  definition = Definition.new("searches", 1)
@@ -15,7 +15,8 @@ describe Scenic::SchemaDumper, :db do
15
15
  ActiveRecord::SchemaDumper.dump(Search.connection, stream)
16
16
 
17
17
  output = stream.string
18
- expect(output).to include 'create_view "searches"'
18
+
19
+ expect(output).to include 'create_view "searches", sql_definition: <<-SQL'
19
20
  expect(output).to include view_definition
20
21
 
21
22
  Search.connection.drop_view :searches
@@ -25,6 +26,19 @@ describe Scenic::SchemaDumper, :db do
25
26
  expect(Search.first.haystack).to eq "needle"
26
27
  end
27
28
 
29
+ it "dumps a create_view for a materialized view in the database" do
30
+ view_definition = "SELECT 'needle'::text AS haystack"
31
+ Search.connection.create_view :searches, materialized: true, sql_definition: view_definition
32
+ stream = StringIO.new
33
+
34
+ ActiveRecord::SchemaDumper.dump(Search.connection, stream)
35
+
36
+ output = stream.string
37
+
38
+ expect(output).to include 'create_view "searches", materialized: true, sql_definition: <<-SQL'
39
+ expect(output).to include view_definition
40
+ end
41
+
28
42
  context "with views in non public schemas" do
29
43
  it "dumps a create_view including namespace for a view in the database" do
30
44
  view_definition = "SELECT 'needle'::text AS haystack"
@@ -79,7 +93,8 @@ describe Scenic::SchemaDumper, :db do
79
93
  it "dumps a create_view for a view in the database" do
80
94
  view_definition = "SELECT 'needle'::text AS haystack"
81
95
  Search.connection.execute(
82
- "CREATE SCHEMA scenic; SET search_path TO scenic, public")
96
+ "CREATE SCHEMA scenic; SET search_path TO scenic, public",
97
+ )
83
98
  Search.connection.create_view 'scenic."search in a haystack"',
84
99
  sql_definition: view_definition
85
100
  stream = StringIO.new
@@ -33,14 +33,14 @@ module Scenic
33
33
  it "creates version 1 of the view if neither version nor sql_defintion are provided" do
34
34
  version = 1
35
35
  definition_stub = instance_double("Definition", to_sql: "foo")
36
- allow(Definition).to receive(:new).
37
- with(:views, version).
38
- and_return(definition_stub)
36
+ allow(Definition).to receive(:new)
37
+ .with(:views, version)
38
+ .and_return(definition_stub)
39
39
 
40
40
  connection.create_view :views
41
41
 
42
- expect(Scenic.database).to have_received(:create_view).
43
- with(:views, definition_stub.to_sql)
42
+ expect(Scenic.database).to have_received(:create_view)
43
+ .with(:views, definition_stub.to_sql)
44
44
  end
45
45
 
46
46
  it "raises an error if both version and sql_defintion are provided" do
@@ -52,12 +52,29 @@ module Scenic
52
52
 
53
53
  describe "create_view :materialized" do
54
54
  it "sends the create_materialized_view message" do
55
- allow(Definition).to receive(:new)
56
- .and_return(instance_double("Scenic::Definition").as_null_object)
55
+ definition = instance_double("Scenic::Definition", to_sql: "definition")
56
+ allow(Definition).to receive(:new).and_return(definition)
57
57
 
58
58
  connection.create_view(:views, version: 1, materialized: true)
59
59
 
60
60
  expect(Scenic.database).to have_received(:create_materialized_view)
61
+ .with(:views, definition.to_sql, no_data: false)
62
+ end
63
+ end
64
+
65
+ describe "create_view :materialized with :no_data" do
66
+ it "sends the create_materialized_view message" do
67
+ definition = instance_double("Scenic::Definition", to_sql: "definition")
68
+ allow(Definition).to receive(:new).and_return(definition)
69
+
70
+ connection.create_view(
71
+ :views,
72
+ version: 1,
73
+ materialized: { no_data: true },
74
+ )
75
+
76
+ expect(Scenic.database).to have_received(:create_materialized_view)
77
+ .with(:views, definition.to_sql, no_data: true)
61
78
  end
62
79
  end
63
80
 
@@ -95,8 +112,8 @@ module Scenic
95
112
 
96
113
  connection.update_view(:name, sql_definition: sql_definition)
97
114
 
98
- expect(Scenic.database).to have_received(:update_view).
99
- with(:name, sql_definition)
115
+ expect(Scenic.database).to have_received(:update_view)
116
+ .with(:name, sql_definition)
100
117
  end
101
118
 
102
119
  it "updates the materialized view in the database" do
@@ -107,14 +124,31 @@ module Scenic
107
124
 
108
125
  connection.update_view(:name, version: 3, materialized: true)
109
126
 
110
- expect(Scenic.database).to have_received(:update_materialized_view).
111
- with(:name, definition.to_sql)
127
+ expect(Scenic.database).to have_received(:update_materialized_view)
128
+ .with(:name, definition.to_sql, no_data: false)
129
+ end
130
+
131
+ it "updates the materialized view in the database with NO DATA" do
132
+ definition = instance_double("Definition", to_sql: "definition")
133
+ allow(Definition).to receive(:new)
134
+ .with(:name, 3)
135
+ .and_return(definition)
136
+
137
+ connection.update_view(
138
+ :name,
139
+ version: 3,
140
+ materialized: { no_data: true },
141
+ )
142
+
143
+ expect(Scenic.database).to have_received(:update_materialized_view)
144
+ .with(:name, definition.to_sql, no_data: true)
112
145
  end
113
146
 
114
147
  it "raises an error if not supplied a version or sql_defintion" do
115
148
  expect { connection.update_view :views }.to raise_error(
116
149
  ArgumentError,
117
- /sql_definition or version must be specified/)
150
+ /sql_definition or version must be specified/,
151
+ )
118
152
  end
119
153
 
120
154
  it "raises an error if both version and sql_defintion are provided" do
@@ -122,7 +156,8 @@ module Scenic
122
156
  connection.update_view(
123
157
  :views,
124
158
  version: 1,
125
- sql_definition: "a defintion")
159
+ sql_definition: "a defintion",
160
+ )
126
161
  end.to raise_error ArgumentError, /cannot both be set/
127
162
  end
128
163
  end
@@ -1,7 +1,7 @@
1
1
  ENV["RAILS_ENV"] = "test"
2
2
  require "database_cleaner"
3
3
 
4
- require File.expand_path("../dummy/config/environment", __FILE__)
4
+ require File.expand_path("dummy/config/environment", __dir__)
5
5
  require "support/generator_spec_setup"
6
6
  require "support/view_definition_helpers"
7
7
 
@@ -5,7 +5,7 @@ require "ammeter/init"
5
5
 
6
6
  RSpec.configure do |config|
7
7
  config.before(:example, :generator) do
8
- fake_rails_root = File.expand_path("../../../tmp", __FILE__)
8
+ fake_rails_root = File.expand_path("../../tmp", __dir__)
9
9
  allow(Rails).to receive(:root).and_return(Pathname.new(fake_rails_root))
10
10
 
11
11
  destination fake_rails_root
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.1
4
+ version: 1.5.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Derek Prior
@@ -9,7 +9,7 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2017-12-16 00:00:00.000000000 Z
12
+ date: 2019-02-09 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: appraisal
@@ -85,16 +85,16 @@ dependencies:
85
85
  name: pg
86
86
  requirement: !ruby/object:Gem::Requirement
87
87
  requirements:
88
- - - ">="
88
+ - - "~>"
89
89
  - !ruby/object:Gem::Version
90
- version: '0'
90
+ version: '0.19'
91
91
  type: :development
92
92
  prerelease: false
93
93
  version_requirements: !ruby/object:Gem::Requirement
94
94
  requirements:
95
- - - ">="
95
+ - - "~>"
96
96
  - !ruby/object:Gem::Version
97
- version: '0'
97
+ version: '0.19'
98
98
  - !ruby/object:Gem::Dependency
99
99
  name: pry
100
100
  requirement: !ruby/object:Gem::Requirement
@@ -191,9 +191,11 @@ extra_rdoc_files: []
191
191
  files:
192
192
  - ".gitignore"
193
193
  - ".hound.yml"
194
+ - ".rubocop.yml"
194
195
  - ".travis.yml"
195
196
  - ".yardopts"
196
197
  - Appraisals
198
+ - CODE_OF_CONDUCT.md
197
199
  - CONTRIBUTING.md
198
200
  - Gemfile
199
201
  - LICENSE.txt
@@ -205,11 +207,10 @@ files:
205
207
  - bin/rspec
206
208
  - bin/setup
207
209
  - bin/yard
208
- - gemfiles/rails40.gemfile
209
- - gemfiles/rails41.gemfile
210
210
  - gemfiles/rails42.gemfile
211
211
  - gemfiles/rails50.gemfile
212
212
  - gemfiles/rails51.gemfile
213
+ - gemfiles/rails52.gemfile
213
214
  - gemfiles/rails_edge.gemfile
214
215
  - lib/generators/scenic/generators.rb
215
216
  - lib/generators/scenic/materializable.rb
@@ -243,6 +244,7 @@ files:
243
244
  - spec/acceptance_helper.rb
244
245
  - spec/dummy/.gitignore
245
246
  - spec/dummy/Rakefile
247
+ - spec/dummy/app/models/application_record.rb
246
248
  - spec/dummy/bin/bundle
247
249
  - spec/dummy/bin/rails
248
250
  - spec/dummy/bin/rake
@@ -269,7 +271,7 @@ files:
269
271
  - spec/spec_helper.rb
270
272
  - spec/support/generator_spec_setup.rb
271
273
  - spec/support/view_definition_helpers.rb
272
- homepage: https://github.com/thoughtbot/scenic
274
+ homepage: https://github.com/scenic-views/scenic
273
275
  licenses:
274
276
  - MIT
275
277
  metadata: {}
@@ -279,17 +281,16 @@ require_paths:
279
281
  - lib
280
282
  required_ruby_version: !ruby/object:Gem::Requirement
281
283
  requirements:
282
- - - "~>"
284
+ - - ">="
283
285
  - !ruby/object:Gem::Version
284
- version: '2.1'
286
+ version: 2.3.0
285
287
  required_rubygems_version: !ruby/object:Gem::Requirement
286
288
  requirements:
287
289
  - - ">="
288
290
  - !ruby/object:Gem::Version
289
291
  version: '0'
290
292
  requirements: []
291
- rubyforge_project:
292
- rubygems_version: 2.6.14
293
+ rubygems_version: 3.0.1
293
294
  signing_key:
294
295
  specification_version: 4
295
296
  summary: Support for database views in Rails migrations
@@ -298,6 +299,7 @@ test_files:
298
299
  - spec/acceptance_helper.rb
299
300
  - spec/dummy/.gitignore
300
301
  - spec/dummy/Rakefile
302
+ - spec/dummy/app/models/application_record.rb
301
303
  - spec/dummy/bin/bundle
302
304
  - spec/dummy/bin/rails
303
305
  - spec/dummy/bin/rake
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "~> 4.0.0"
6
- gem "railties", "~> 4.0.0"
7
-
8
- gemspec :path => "../"
@@ -1,8 +0,0 @@
1
- # This file was generated by Appraisal
2
-
3
- source "https://rubygems.org"
4
-
5
- gem "activerecord", "~> 4.1.0"
6
- gem "railties", "~> 4.1.0"
7
-
8
- gemspec :path => "../"