scenic 1.2.0 → 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/README.md +43 -0
- data/Rakefile +15 -1
- data/lib/generators/scenic/model/model_generator.rb +2 -2
- data/lib/scenic/adapters/postgres.rb +25 -0
- data/lib/scenic/adapters/postgres/views.rb +11 -2
- data/lib/scenic/command_recorder.rb +8 -0
- data/lib/scenic/statements.rb +30 -0
- data/lib/scenic/version.rb +1 -1
- data/lib/scenic/view.rb +3 -1
- data/spec/acceptance/user_manages_views_spec.rb +86 -0
- data/spec/acceptance_helper.rb +32 -0
- data/spec/scenic/adapters/postgres_spec.rb +37 -0
- data/spec/scenic/command_recorder_spec.rb +26 -0
- data/spec/scenic/schema_dumper_spec.rb +16 -0
- data/spec/scenic/statements_spec.rb +30 -0
- metadata +7 -5
- data/spec/smoke +0 -135
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d319d2791defb8c1025c78605b3003c0275664ba
|
4
|
+
data.tar.gz: 0c79eb3cb32bf171ec085987b83ac89df8bd4ffe
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f858662b6d60d851a0aa402401c750da7a9c482d018e49e6fcdde39cd5672bd4d8cbd5593f422afa7541c0867805f28e0a73cb1add550c0742552851f67359a3
|
7
|
+
data.tar.gz: 81c7ec7accf60272ff77476c73b31ed7b332334874d150b655b5933a4546be4a009a75c9dcd4a2d93a623de702c34c6e6f80bb76d5f3f8665ff65a56dc2ca896
|
data/README.md
CHANGED
@@ -78,6 +78,49 @@ Scenic detected that we already had an existing `search_results` view at version
|
|
78
78
|
update to the version 2 schema. All that's left for you to do is tweak the
|
79
79
|
schema in the new definition and run the `update_view` migration.
|
80
80
|
|
81
|
+
## What if I want to change a view without dropping it?
|
82
|
+
|
83
|
+
The `update_view` statement used by default will drop your view then create
|
84
|
+
a new version of it.
|
85
|
+
|
86
|
+
This is not desirable when you have complicated hierarchies of views, especially
|
87
|
+
when some of those views may be materialized and take a long time to recreate.
|
88
|
+
|
89
|
+
You can use `replace_view` to generate a CREATE OR REPLACE VIEW SQL statement.
|
90
|
+
|
91
|
+
See postgresql documentation on how this works:
|
92
|
+
http://www.postgresql.org/docs/current/static/sql-createview.html
|
93
|
+
|
94
|
+
To start replacing a view run the generator like for a regular change:
|
95
|
+
|
96
|
+
```sh
|
97
|
+
$ rails generate scenic:view search_results
|
98
|
+
create db/views/search_results_v02.sql
|
99
|
+
create db/migrate/[TIMESTAMP]_update_search_results_to_version_2.rb
|
100
|
+
```
|
101
|
+
|
102
|
+
Now, edit the migration. It should look something like:
|
103
|
+
|
104
|
+
```ruby
|
105
|
+
class UpdateSearchResultsToVersion2 < ActiveRecord::Migration
|
106
|
+
def change
|
107
|
+
update_view :search_results, version: 2, revert_to_version: 1
|
108
|
+
end
|
109
|
+
end
|
110
|
+
```
|
111
|
+
|
112
|
+
Update it to use replace view:
|
113
|
+
|
114
|
+
```ruby
|
115
|
+
class UpdateSearchResultsToVersion2 < ActiveRecord::Migration
|
116
|
+
def change
|
117
|
+
replace_view :search_results, version: 2, revert_to_version: 1
|
118
|
+
end
|
119
|
+
end
|
120
|
+
```
|
121
|
+
|
122
|
+
Now you can run the migration like normal.
|
123
|
+
|
81
124
|
## Can I use this view to back a model?
|
82
125
|
|
83
126
|
You bet! Using view-backed models can help promote concepts hidden in your
|
data/Rakefile
CHANGED
@@ -12,4 +12,18 @@ namespace :dummy do
|
|
12
12
|
Dummy::Application.load_tasks
|
13
13
|
end
|
14
14
|
|
15
|
-
task
|
15
|
+
task(:spec).clear
|
16
|
+
desc "Run specs other than spec/acceptance"
|
17
|
+
RSpec::Core::RakeTask.new("spec") do |task|
|
18
|
+
task.exclude_pattern = "spec/acceptance/**/*_spec.rb"
|
19
|
+
task.verbose = false
|
20
|
+
end
|
21
|
+
|
22
|
+
desc "Run acceptance specs in spec/acceptance"
|
23
|
+
RSpec::Core::RakeTask.new("spec:acceptance") do |task|
|
24
|
+
task.pattern = "spec/acceptance/**/*_spec.rb"
|
25
|
+
task.verbose = false
|
26
|
+
end
|
27
|
+
|
28
|
+
desc "Run the specs and acceptance tests"
|
29
|
+
task default: %w(spec spec:acceptance)
|
@@ -11,12 +11,12 @@ module Scenic
|
|
11
11
|
source_root File.expand_path("../templates", __FILE__)
|
12
12
|
|
13
13
|
def invoke_rails_model_generator
|
14
|
-
invoke "model", [
|
14
|
+
invoke "model", [file_path.singularize], options.merge(migration: false)
|
15
15
|
end
|
16
16
|
|
17
17
|
def inject_model_methods
|
18
18
|
if materialized? && generating?
|
19
|
-
inject_into_class "app/models/#{file_path}.rb", class_name do
|
19
|
+
inject_into_class "app/models/#{file_path.singularize}.rb", class_name do
|
20
20
|
evaluate_template("model.erb")
|
21
21
|
end
|
22
22
|
end
|
@@ -81,6 +81,31 @@ module Scenic
|
|
81
81
|
create_view(name, sql_definition)
|
82
82
|
end
|
83
83
|
|
84
|
+
# Replaces a view in the database using `CREATE OR REPLACE VIEW`.
|
85
|
+
#
|
86
|
+
# This results in a `CREATE OR REPLACE VIEW`. Most of the time the
|
87
|
+
# explicitness of the two step process used in {#update_view} is preferred
|
88
|
+
# to `CREATE OR REPLACE VIEW` because the former ensures that the view you
|
89
|
+
# are trying to update did, in fact, already exist. Additionally,
|
90
|
+
# `CREATE OR REPLACE VIEW` is allowed only to add new columns to the end
|
91
|
+
# of an existing view schema. Existing columns cannot be re-ordered,
|
92
|
+
# removed, or have their types changed. Drop and create overcomes this
|
93
|
+
# limitation as well.
|
94
|
+
#
|
95
|
+
# However, when there is a tangled dependency tree
|
96
|
+
# `CREATE OR REPLACE VIEW` can be preferable.
|
97
|
+
#
|
98
|
+
# This is typically called in a migration via
|
99
|
+
# {Statements#replace_view}.
|
100
|
+
#
|
101
|
+
# @param name The name of the view to update
|
102
|
+
# @param sql_definition The SQL schema for the updated view.
|
103
|
+
#
|
104
|
+
# @return [void]
|
105
|
+
def replace_view(name, sql_definition)
|
106
|
+
execute "CREATE OR REPLACE VIEW #{quote_table_name(name)} AS #{sql_definition};"
|
107
|
+
end
|
108
|
+
|
84
109
|
# Drops the named view from the database
|
85
110
|
#
|
86
111
|
# This is typically called in a migration via {Statements#drop_view}.
|
@@ -27,7 +27,8 @@ module Scenic
|
|
27
27
|
SELECT
|
28
28
|
c.relname as viewname,
|
29
29
|
pg_get_viewdef(c.oid) AS definition,
|
30
|
-
c.relkind AS kind
|
30
|
+
c.relkind AS kind,
|
31
|
+
n.nspname AS namespace
|
31
32
|
FROM pg_class c
|
32
33
|
LEFT JOIN pg_namespace n ON n.oid = c.relnamespace
|
33
34
|
WHERE
|
@@ -39,8 +40,16 @@ module Scenic
|
|
39
40
|
end
|
40
41
|
|
41
42
|
def to_scenic_view(result)
|
43
|
+
namespace, viewname = result.values_at "namespace", "viewname"
|
44
|
+
|
45
|
+
if namespace != "public"
|
46
|
+
namespaced_viewname = "#{namespace}.#{viewname}"
|
47
|
+
else
|
48
|
+
namespaced_viewname = viewname
|
49
|
+
end
|
50
|
+
|
42
51
|
Scenic::View.new(
|
43
|
-
name:
|
52
|
+
name: namespaced_viewname,
|
44
53
|
definition: result["definition"].strip,
|
45
54
|
materialized: result["kind"] == "m",
|
46
55
|
)
|
@@ -15,6 +15,10 @@ module Scenic
|
|
15
15
|
record(:update_view, args)
|
16
16
|
end
|
17
17
|
|
18
|
+
def replace_view(*args)
|
19
|
+
record(:replace_view, args)
|
20
|
+
end
|
21
|
+
|
18
22
|
def invert_create_view(args)
|
19
23
|
[:drop_view, args]
|
20
24
|
end
|
@@ -27,6 +31,10 @@ module Scenic
|
|
27
31
|
perform_scenic_inversion(:update_view, args)
|
28
32
|
end
|
29
33
|
|
34
|
+
def invert_replace_view(args)
|
35
|
+
perform_scenic_inversion(:replace_view, args)
|
36
|
+
end
|
37
|
+
|
30
38
|
private
|
31
39
|
|
32
40
|
def perform_scenic_inversion(method, args)
|
data/lib/scenic/statements.rb
CHANGED
@@ -89,6 +89,36 @@ module Scenic
|
|
89
89
|
end
|
90
90
|
end
|
91
91
|
|
92
|
+
# Update a database view to a new version using `CREATE OR REPLACE VIEW`.
|
93
|
+
#
|
94
|
+
# The existing view is replaced using the supplied `version`
|
95
|
+
# parameter.
|
96
|
+
#
|
97
|
+
# Does not work with materialized views due to lack of database support.
|
98
|
+
#
|
99
|
+
# @param name [String, Symbol] The name of the database view.
|
100
|
+
# @param version [Fixnum] The version number of the view.
|
101
|
+
# @param revert_to_version [Fixnum] The version number to rollback to on
|
102
|
+
# `rake db rollback`
|
103
|
+
# @return The database response from executing the create statement.
|
104
|
+
#
|
105
|
+
# @example
|
106
|
+
# replace_view :engagement_reports, version: 3, revert_to_version: 2
|
107
|
+
#
|
108
|
+
def replace_view(name, version: nil, revert_to_version: nil, materialized: false)
|
109
|
+
if version.blank?
|
110
|
+
raise ArgumentError, "version is required"
|
111
|
+
end
|
112
|
+
|
113
|
+
if materialized
|
114
|
+
raise ArgumentError, "Cannot replace materialized views"
|
115
|
+
end
|
116
|
+
|
117
|
+
sql_definition = definition(name, version)
|
118
|
+
|
119
|
+
Scenic.database.replace_view(name, sql_definition)
|
120
|
+
end
|
121
|
+
|
92
122
|
private
|
93
123
|
|
94
124
|
def definition(name, version)
|
data/lib/scenic/version.rb
CHANGED
data/lib/scenic/view.rb
CHANGED
@@ -43,8 +43,10 @@ module Scenic
|
|
43
43
|
# @api private
|
44
44
|
def to_schema
|
45
45
|
materialized_option = materialized ? "materialized: true, " : ""
|
46
|
+
safe_to_symbolize_name = name.include?(".") ? "'#{name}'" : name
|
47
|
+
|
46
48
|
<<-DEFINITION
|
47
|
-
create_view :#{
|
49
|
+
create_view :#{safe_to_symbolize_name}, #{materialized_option} sql_definition: <<-\SQL
|
48
50
|
#{definition.indent(2)}
|
49
51
|
SQL
|
50
52
|
|
@@ -0,0 +1,86 @@
|
|
1
|
+
require "acceptance_helper"
|
2
|
+
|
3
|
+
describe "User manages views" do
|
4
|
+
it "handles simple views" do
|
5
|
+
successfully "rails generate scenic:model search_result"
|
6
|
+
write_definition "search_results_v01", "SELECT 'needle'::text AS term"
|
7
|
+
|
8
|
+
successfully "rake db:migrate"
|
9
|
+
verify_result "SearchResult.take.term", "needle"
|
10
|
+
|
11
|
+
successfully "rails generate scenic:view search_results"
|
12
|
+
verify_identical_view_definitions "search_results_v01", "search_results_v02"
|
13
|
+
|
14
|
+
write_definition "search_results_v02", "SELECT 'haystack'::text AS term"
|
15
|
+
successfully "rake db:migrate"
|
16
|
+
|
17
|
+
successfully "rake db:reset"
|
18
|
+
verify_result "SearchResult.take.term", "haystack"
|
19
|
+
|
20
|
+
successfully "rake db:rollback"
|
21
|
+
successfully "rake db:rollback"
|
22
|
+
successfully "rails destroy scenic:model search_result"
|
23
|
+
end
|
24
|
+
|
25
|
+
it "handles materialized views" do
|
26
|
+
successfully "rails generate scenic:model child --materialized"
|
27
|
+
write_definition "children_v01", "SELECT 'Owen'::text AS name, 5 AS age"
|
28
|
+
|
29
|
+
successfully "rake db:migrate"
|
30
|
+
verify_result "Child.take.name", "Owen"
|
31
|
+
|
32
|
+
add_index "children", "name"
|
33
|
+
add_index "children", "age"
|
34
|
+
|
35
|
+
successfully "rails runner 'Child.refresh'"
|
36
|
+
|
37
|
+
successfully "rails generate scenic:view child --materialized"
|
38
|
+
verify_identical_view_definitions "children_v01", "children_v02"
|
39
|
+
|
40
|
+
write_definition "children_v02", "SELECT 'Elliot'::text AS name"
|
41
|
+
successfully "rake db:migrate"
|
42
|
+
|
43
|
+
successfully "rake db:reset"
|
44
|
+
verify_result "Child.take.name", "Elliot"
|
45
|
+
verify_schema_contains 'add_index "children"'
|
46
|
+
|
47
|
+
successfully "rake db:rollback"
|
48
|
+
successfully "rake db:rollback"
|
49
|
+
successfully "rails destroy scenic:model child"
|
50
|
+
end
|
51
|
+
|
52
|
+
it "handles plural view names gracefully during generation" do
|
53
|
+
successfully "rails generate scenic:model search_results --materialized"
|
54
|
+
end
|
55
|
+
|
56
|
+
def successfully(command)
|
57
|
+
`RAILS_ENV=test #{command}`
|
58
|
+
expect($?.exitstatus).to eq(0), "'#{command}' was unsuccessful"
|
59
|
+
end
|
60
|
+
|
61
|
+
def write_definition(file, contents)
|
62
|
+
File.open("db/views/#{file}.sql", File::WRONLY) do |definition|
|
63
|
+
definition.truncate(0)
|
64
|
+
definition.write(contents)
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
def verify_result(command, expected_output)
|
69
|
+
successfully %{rails runner "#{command} == '#{expected_output}' || exit(1)"}
|
70
|
+
end
|
71
|
+
|
72
|
+
def verify_identical_view_definitions(def_a, def_b)
|
73
|
+
successfully "cmp db/views/#{def_a}.sql db/views/#{def_b}.sql"
|
74
|
+
end
|
75
|
+
|
76
|
+
def add_index(table, column)
|
77
|
+
successfully(<<-CMD.strip)
|
78
|
+
rails runner 'ActiveRecord::Migration.add_index "#{table}", "#{column}"'
|
79
|
+
CMD
|
80
|
+
end
|
81
|
+
|
82
|
+
def verify_schema_contains(statement)
|
83
|
+
expect(File.readlines("db/schema.rb").grep(/#{statement}/))
|
84
|
+
.not_to be_empty, "Schema does not contain '#{statement}'"
|
85
|
+
end
|
86
|
+
end
|
@@ -0,0 +1,32 @@
|
|
1
|
+
require "bundler"
|
2
|
+
|
3
|
+
ENV["RAILS_ENV"] = "test"
|
4
|
+
|
5
|
+
RSpec.configure do |config|
|
6
|
+
config.around(:each) do |example|
|
7
|
+
Dir.chdir("spec/dummy") do
|
8
|
+
example.run
|
9
|
+
end
|
10
|
+
end
|
11
|
+
|
12
|
+
config.before(:suite) do
|
13
|
+
Dir.chdir("spec/dummy") do
|
14
|
+
system <<-CMD
|
15
|
+
git init 1>/dev/null &&
|
16
|
+
git add -A &&
|
17
|
+
git commit --no-gpg-sign --message 'initial' 1>/dev/null
|
18
|
+
CMD
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
config.after(:suite) do
|
23
|
+
Dir.chdir("spec/dummy") do
|
24
|
+
system <<-CMD
|
25
|
+
rake db:drop db:create &&
|
26
|
+
git add -A &&
|
27
|
+
git reset --hard HEAD 1>/dev/null &&
|
28
|
+
rm -rf .git/ 1>/dev/null
|
29
|
+
CMD
|
30
|
+
end
|
31
|
+
end
|
32
|
+
end
|
@@ -38,6 +38,22 @@ module Scenic
|
|
38
38
|
end
|
39
39
|
end
|
40
40
|
|
41
|
+
describe "#replace_view" do
|
42
|
+
it "successfully replaces a view" do
|
43
|
+
adapter = Postgres.new
|
44
|
+
|
45
|
+
adapter.create_view("greetings", "SELECT text 'hi' AS greeting")
|
46
|
+
|
47
|
+
view = adapter.views.first.definition
|
48
|
+
expect(view).to eql "SELECT 'hi'::text AS greeting;"
|
49
|
+
|
50
|
+
adapter.replace_view("greetings", "SELECT text 'hello' AS greeting")
|
51
|
+
|
52
|
+
view = adapter.views.first.definition
|
53
|
+
expect(view).to eql "SELECT 'hello'::text AS greeting;"
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
41
57
|
describe "#drop_view" do
|
42
58
|
it "successfully drops a view" do
|
43
59
|
adapter = Postgres.new
|
@@ -137,6 +153,27 @@ module Scenic
|
|
137
153
|
"people_with_names",
|
138
154
|
]
|
139
155
|
end
|
156
|
+
|
157
|
+
context "with views in non public schemas" do
|
158
|
+
it "returns also the non public views" do
|
159
|
+
adapter = Postgres.new
|
160
|
+
|
161
|
+
ActiveRecord::Base.connection.execute <<-SQL
|
162
|
+
CREATE VIEW parents AS SELECT text 'Joe' AS name
|
163
|
+
SQL
|
164
|
+
|
165
|
+
ActiveRecord::Base.connection.execute <<-SQL
|
166
|
+
CREATE SCHEMA scenic;
|
167
|
+
CREATE VIEW scenic.parents AS SELECT text 'Maarten' AS name;
|
168
|
+
SET search_path TO scenic, public;
|
169
|
+
SQL
|
170
|
+
|
171
|
+
expect(adapter.views.map(&:name)).to eq [
|
172
|
+
"parents",
|
173
|
+
"scenic.parents",
|
174
|
+
]
|
175
|
+
end
|
176
|
+
end
|
140
177
|
end
|
141
178
|
end
|
142
179
|
end
|
@@ -65,6 +65,32 @@ describe Scenic::CommandRecorder do
|
|
65
65
|
end
|
66
66
|
end
|
67
67
|
|
68
|
+
describe "#replace_view" do
|
69
|
+
it "records the replaced view" do
|
70
|
+
args = [:users, { version: 2 }]
|
71
|
+
|
72
|
+
recorder.replace_view(*args)
|
73
|
+
|
74
|
+
expect(recorder.commands).to eq [[:replace_view, args, nil]]
|
75
|
+
end
|
76
|
+
|
77
|
+
it "reverts to replace_view with the specified revert_to_version" do
|
78
|
+
args = [:users, { version: 2, revert_to_version: 1 }]
|
79
|
+
revert_args = [:users, { version: 1 }]
|
80
|
+
|
81
|
+
recorder.revert { recorder.replace_view(*args) }
|
82
|
+
|
83
|
+
expect(recorder.commands).to eq [[:replace_view, revert_args]]
|
84
|
+
end
|
85
|
+
|
86
|
+
it "raises when reverting without revert_to_version set" do
|
87
|
+
args = [:users, { version: 42, another_argument: 1 }]
|
88
|
+
|
89
|
+
expect { recorder.revert { recorder.replace_view(*args) } }
|
90
|
+
.to raise_error(ActiveRecord::IrreversibleMigration)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
68
94
|
def recorder
|
69
95
|
@recorder ||= ActiveRecord::Migration::CommandRecorder.new
|
70
96
|
end
|
@@ -20,4 +20,20 @@ describe Scenic::SchemaDumper, :db do
|
|
20
20
|
|
21
21
|
expect(Search.first.haystack).to eq "needle"
|
22
22
|
end
|
23
|
+
|
24
|
+
context "with views in non public schemas" do
|
25
|
+
it "dumps a create_view including namespace for a view in the database" do
|
26
|
+
view_definition = "SELECT 'needle'::text AS haystack"
|
27
|
+
Search.connection.execute "CREATE SCHEMA scenic; SET search_path TO scenic, public"
|
28
|
+
Search.connection.create_view :"scenic.searches", sql_definition: view_definition
|
29
|
+
stream = StringIO.new
|
30
|
+
|
31
|
+
ActiveRecord::SchemaDumper.dump(Search.connection, stream)
|
32
|
+
|
33
|
+
output = stream.string
|
34
|
+
expect(output).to include "create_view :'scenic.searches',"
|
35
|
+
|
36
|
+
Search.connection.drop_view :'scenic.searches'
|
37
|
+
end
|
38
|
+
end
|
23
39
|
end
|
@@ -95,6 +95,36 @@ module Scenic
|
|
95
95
|
end
|
96
96
|
end
|
97
97
|
|
98
|
+
describe "replace_view" do
|
99
|
+
it "replaces the view in the database" do
|
100
|
+
definition = instance_double("Definition", to_sql: "definition")
|
101
|
+
allow(Definition).to receive(:new)
|
102
|
+
.with(:name, 3)
|
103
|
+
.and_return(definition)
|
104
|
+
|
105
|
+
connection.replace_view(:name, version: 3)
|
106
|
+
|
107
|
+
expect(Scenic.database).to have_received(:replace_view)
|
108
|
+
.with(:name, definition.to_sql)
|
109
|
+
end
|
110
|
+
|
111
|
+
it "fails to replace the materialized view in the database" do
|
112
|
+
definition = instance_double("Definition", to_sql: "definition")
|
113
|
+
allow(Definition).to receive(:new)
|
114
|
+
.with(:name, 3)
|
115
|
+
.and_return(definition)
|
116
|
+
|
117
|
+
expect do
|
118
|
+
connection.replace_view(:name, version: 3, materialized: true)
|
119
|
+
end.to raise_error(ArgumentError, /Cannot replace materialized views/)
|
120
|
+
end
|
121
|
+
|
122
|
+
it "raises an error if not supplied a version" do
|
123
|
+
expect { connection.replace_view :views }
|
124
|
+
.to raise_error(ArgumentError, /version is required/)
|
125
|
+
end
|
126
|
+
end
|
127
|
+
|
98
128
|
def connection
|
99
129
|
Class.new { extend Statements }
|
100
130
|
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.
|
4
|
+
version: 1.3.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: 2016-
|
12
|
+
date: 2016-05-27 00:00:00.000000000 Z
|
13
13
|
dependencies:
|
14
14
|
- !ruby/object:Gem::Dependency
|
15
15
|
name: appraisal
|
@@ -234,6 +234,8 @@ files:
|
|
234
234
|
- lib/scenic/version.rb
|
235
235
|
- lib/scenic/view.rb
|
236
236
|
- scenic.gemspec
|
237
|
+
- spec/acceptance/user_manages_views_spec.rb
|
238
|
+
- spec/acceptance_helper.rb
|
237
239
|
- spec/dummy/.gitignore
|
238
240
|
- spec/dummy/Rakefile
|
239
241
|
- spec/dummy/bin/bundle
|
@@ -258,7 +260,6 @@ files:
|
|
258
260
|
- spec/scenic/definition_spec.rb
|
259
261
|
- spec/scenic/schema_dumper_spec.rb
|
260
262
|
- spec/scenic/statements_spec.rb
|
261
|
-
- spec/smoke
|
262
263
|
- spec/spec_helper.rb
|
263
264
|
- spec/support/generator_spec_setup.rb
|
264
265
|
- spec/support/view_definition_helpers.rb
|
@@ -282,11 +283,13 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
282
283
|
version: '0'
|
283
284
|
requirements: []
|
284
285
|
rubyforge_project:
|
285
|
-
rubygems_version: 2.
|
286
|
+
rubygems_version: 2.5.1
|
286
287
|
signing_key:
|
287
288
|
specification_version: 4
|
288
289
|
summary: Support for database views in Rails migrations
|
289
290
|
test_files:
|
291
|
+
- spec/acceptance/user_manages_views_spec.rb
|
292
|
+
- spec/acceptance_helper.rb
|
290
293
|
- spec/dummy/.gitignore
|
291
294
|
- spec/dummy/Rakefile
|
292
295
|
- spec/dummy/bin/bundle
|
@@ -311,7 +314,6 @@ test_files:
|
|
311
314
|
- spec/scenic/definition_spec.rb
|
312
315
|
- spec/scenic/schema_dumper_spec.rb
|
313
316
|
- spec/scenic/statements_spec.rb
|
314
|
-
- spec/smoke
|
315
317
|
- spec/spec_helper.rb
|
316
318
|
- spec/support/generator_spec_setup.rb
|
317
319
|
- spec/support/view_definition_helpers.rb
|
data/spec/smoke
DELETED
@@ -1,135 +0,0 @@
|
|
1
|
-
#!/bin/bash
|
2
|
-
|
3
|
-
set -euo pipefail
|
4
|
-
|
5
|
-
setup() {
|
6
|
-
cd spec/dummy
|
7
|
-
git init
|
8
|
-
git add -A
|
9
|
-
git commit --no-gpg-sign --message "initial"
|
10
|
-
}
|
11
|
-
|
12
|
-
teardown() {
|
13
|
-
git add -A
|
14
|
-
git reset --hard HEAD
|
15
|
-
rm -rf .git/
|
16
|
-
rake db:drop db:create
|
17
|
-
}
|
18
|
-
|
19
|
-
trap teardown EXIT
|
20
|
-
|
21
|
-
verifySearchResults() {
|
22
|
-
echo "verify search results"
|
23
|
-
local expectedResult=$1
|
24
|
-
local actualResult=$(rails runner "puts Search.take.results")
|
25
|
-
[[ "$actualResult" == "$expectedResult" ]] || exit 1
|
26
|
-
echo "[success]"
|
27
|
-
}
|
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
|
-
|
36
|
-
writeToFileAndMigrateAndVerifySearchResults() {
|
37
|
-
echo "write search definition and migrate"
|
38
|
-
local version=$1
|
39
|
-
local expectedResult=$2
|
40
|
-
local filePath=db/views/searches_v$version\.sql
|
41
|
-
cp /dev/null $filePath
|
42
|
-
echo "SELECT '$expectedResult'::text AS results, 1 AS user_id" >> $filePath
|
43
|
-
rake db:migrate
|
44
|
-
echo "[success]"
|
45
|
-
verifySearchResults $expectedResult
|
46
|
-
}
|
47
|
-
|
48
|
-
main() {
|
49
|
-
setup
|
50
|
-
echo "rails generate scenic:model search"
|
51
|
-
rails generate scenic:model search
|
52
|
-
[[ -f db/views/searches_v01.sql ]] || exit 1
|
53
|
-
[[ -f app/models/search.rb ]] || exit 1
|
54
|
-
[[ -n "$(find db/migrate -maxdepth 1 -name "*create_searches.rb" -print -quit)" ]] || exit 1
|
55
|
-
echo "[success]"
|
56
|
-
|
57
|
-
writeToFileAndMigrateAndVerifySearchResults "01" "search-results"
|
58
|
-
|
59
|
-
echo "rails generate scenic:view search (to get updates search view)"
|
60
|
-
rails generate scenic:view search
|
61
|
-
[[ -f db/views/searches_v02.sql ]] || exit 1
|
62
|
-
cmp db/views/searches_v01.sql db/views/searches_v02.sql || exit 1
|
63
|
-
[[ -n "$(find db/migrate -maxdepth 1 -name "*update_searches_to_version_2.rb" -print -quit)" ]] || exit 1
|
64
|
-
echo "[success]"
|
65
|
-
|
66
|
-
writeToFileAndMigrateAndVerifySearchResults "02" "different-results"
|
67
|
-
|
68
|
-
echo "rake db:rollback"
|
69
|
-
rake db:rollback
|
70
|
-
echo "[success]"
|
71
|
-
|
72
|
-
verifySearchResults "search-results"
|
73
|
-
|
74
|
-
echo "rails destroy scenic:view search"
|
75
|
-
rails destroy scenic:view search
|
76
|
-
[[ ! -f db/views/searches_v02.sql ]] || exit 1
|
77
|
-
[[ -z "$(find db/migrate -maxdepth 1 -name "*update_searches_to_version_2.rb" -print -quit)" ]] || exit 1
|
78
|
-
[[ -f db/views/searches_v01.sql ]] || exit 1
|
79
|
-
[[ -f app/models/search.rb ]] || exit 1
|
80
|
-
[[ -n "$(find db/migrate -maxdepth 1 -name "*create_searches.rb" -print -quit)" ]] || exit 1
|
81
|
-
echo "[success]"
|
82
|
-
|
83
|
-
echo "rake db:rollback"
|
84
|
-
rake db:rollback
|
85
|
-
echo "[success]"
|
86
|
-
|
87
|
-
echo "rails destroy scenic:view search"
|
88
|
-
rails destroy scenic:model search
|
89
|
-
[[ ! -f db/views/searches_v01.sql ]] || exit 1
|
90
|
-
[[ ! -f app/models/search.rb ]] || exit 1
|
91
|
-
[[ -z "$(find db/migrate -maxdepth 1 -name "*create_searches.rb" -print -quit)" ]] || exit 1
|
92
|
-
echo "[success]"
|
93
|
-
|
94
|
-
echo "rails generate scenic:model search (materialized)"
|
95
|
-
rails generate scenic:model search --materialized
|
96
|
-
[[ -f db/views/searches_v01.sql ]] || exit 1
|
97
|
-
[[ -f app/models/search.rb ]] || exit 1
|
98
|
-
[[ -n "$(find db/migrate -maxdepth 1 -name "*create_searches.rb" -print -quit)" ]] || exit 1
|
99
|
-
echo "[success]"
|
100
|
-
|
101
|
-
writeToFileAndMigrateAndVerifySearchResults "01" "search-results"
|
102
|
-
|
103
|
-
echo "refresh materialized view"
|
104
|
-
rails runner "Search.refresh" || exit 1
|
105
|
-
echo "[success]"
|
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
|
-
|
119
|
-
echo "rake db:rollback"
|
120
|
-
rake db:rollback
|
121
|
-
rake db:rollback
|
122
|
-
echo "[success]"
|
123
|
-
|
124
|
-
echo "rails destroy scenic:model search --materialized"
|
125
|
-
rails destroy scenic:view search --materialized
|
126
|
-
rails destroy scenic:model search --materialized
|
127
|
-
[[ ! -f app/models/search.rb ]] || exit 1
|
128
|
-
[[ ! -f db/views/searches_v01.sql ]] || exit 1
|
129
|
-
[[ -z "$(find db/migrate -maxdepth 1 -name "*create_searches.rb" -print -quit)" ]] || exit 1
|
130
|
-
echo "[success]"
|
131
|
-
|
132
|
-
echo "[done]"
|
133
|
-
}
|
134
|
-
|
135
|
-
main $*
|