scenic 1.4.1 → 1.5.0

Sign up to get free protection for your applications and to get access to all the features.
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 => "../"