scenic 0.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 +7 -0
- data/.gitignore +17 -0
- data/.hound.yml +2 -0
- data/.travis.yml +17 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +22 -0
- data/README.md +96 -0
- data/Rakefile +6 -0
- data/lib/generators/scenic/model/USAGE +10 -0
- data/lib/generators/scenic/model/model_generator.rb +20 -0
- data/lib/generators/scenic/model/templates/model.erb +2 -0
- data/lib/generators/scenic/view/USAGE +9 -0
- data/lib/generators/scenic/view/templates/db/migrate/create_view.erb +5 -0
- data/lib/generators/scenic/view/view_generator.rb +26 -0
- data/lib/scenic/active_record/command_recorder/statement_arguments.rb +44 -0
- data/lib/scenic/active_record/command_recorder.rb +44 -0
- data/lib/scenic/active_record/schema_dumper.rb +52 -0
- data/lib/scenic/active_record/statements.rb +37 -0
- data/lib/scenic/railtie.rb +11 -0
- data/lib/scenic/version.rb +3 -0
- data/lib/scenic.rb +21 -0
- data/scenic.gemspec +35 -0
- data/spec/dummy/.gitignore +16 -0
- data/spec/dummy/Rakefile +6 -0
- data/spec/dummy/bin/bundle +3 -0
- data/spec/dummy/bin/rails +4 -0
- data/spec/dummy/bin/rake +4 -0
- data/spec/dummy/config/application.rb +12 -0
- data/spec/dummy/config/boot.rb +5 -0
- data/spec/dummy/config/database.yml +9 -0
- data/spec/dummy/config/environment.rb +5 -0
- data/spec/dummy/config/environments/development.rb +6 -0
- data/spec/dummy/config/environments/test.rb +5 -0
- data/spec/dummy/config.ru +4 -0
- data/spec/dummy/db/views/.keep +0 -0
- data/spec/generators/scenic/model/model_generator_spec.rb +23 -0
- data/spec/generators/scenic/view/view_generator_spec.rb +16 -0
- data/spec/integration/revert_spec.rb +66 -0
- data/spec/scenic/active_record/command_recorder/statement_arguments_spec.rb +41 -0
- data/spec/scenic/active_record/command_recorder_spec.rb +78 -0
- data/spec/scenic/active_record/schema_dumper_spec.rb +23 -0
- data/spec/scenic/active_record/statements_spec.rb +82 -0
- data/spec/spec_helper.rb +18 -0
- data/spec/support/generator_spec_setup.rb +9 -0
- data/spec/support/view_definition_helpers.rb +9 -0
- metadata +241 -0
checksums.yaml
ADDED
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
---
|
|
2
|
+
SHA1:
|
|
3
|
+
metadata.gz: 7f9265748cd49c4ab094b3cb7110b61e0bef6b35
|
|
4
|
+
data.tar.gz: c3bd33b0d1ee11d1d807b1a12046839bb8fce53c
|
|
5
|
+
SHA512:
|
|
6
|
+
metadata.gz: 6dd62a29b6991a7c21283764d64c38851ca550a1fa690d8496ee56a6fd0448c81f66c9aaa78e2c9ebabcc430ea1be2b0213f5b7315e05e2c55d4911f5cfb9115
|
|
7
|
+
data.tar.gz: 8248642a38d1c583b6883af55a186bea5d2926faa8dcf790996c082ad8d110da74f785db50b4a33bd948fbe6f4b4ea99e7214fdd1afc4641f17d6d2f600b06ec
|
data/.gitignore
ADDED
data/.hound.yml
ADDED
data/.travis.yml
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
before_install:
|
|
2
|
+
- "echo '--colour' > ~/.rspec"
|
|
3
|
+
- "echo 'gem: --no-document' > ~/.gemrc"
|
|
4
|
+
before_script:
|
|
5
|
+
- pushd spec/dummy && bundle exec rake db:create && popd
|
|
6
|
+
branches:
|
|
7
|
+
only:
|
|
8
|
+
- master
|
|
9
|
+
cache:
|
|
10
|
+
- bundler
|
|
11
|
+
language:
|
|
12
|
+
- ruby
|
|
13
|
+
notifications:
|
|
14
|
+
email:
|
|
15
|
+
- false
|
|
16
|
+
rvm:
|
|
17
|
+
- 2.1.1
|
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2014 Derek Prior
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
# Scenic
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
## Description
|
|
6
|
+
|
|
7
|
+
Scenic adds methods to ActiveRecord::Migration to create and manage database
|
|
8
|
+
views in Rails.
|
|
9
|
+
|
|
10
|
+
Using Scenic, you can use the power of SQL views in your Rails application
|
|
11
|
+
without having to switch your schema format to SQL. Scenic also handles
|
|
12
|
+
versioning your views in a way that eliminates duplication across migrations. As
|
|
13
|
+
an added bonus, you define the structure of your view in a SQL file, meaning you
|
|
14
|
+
get full SQL syntax highlighting support in the editor of your choice.
|
|
15
|
+
|
|
16
|
+
## Great, how do I create a view?
|
|
17
|
+
|
|
18
|
+
You've got this great idea for a view you'd like to call `searches`. Create a
|
|
19
|
+
definition file at `db/views/searches_v1.sql` which contains the query you'd
|
|
20
|
+
like to build your view with. Perhaps that looks something like this:
|
|
21
|
+
|
|
22
|
+
```sql
|
|
23
|
+
SELECT
|
|
24
|
+
statuses.id AS searchable_id,
|
|
25
|
+
'Status' AS searchable_type,
|
|
26
|
+
comments.body AS term
|
|
27
|
+
FROM statuses
|
|
28
|
+
JOIN comments ON statuses.id = comments.status_id
|
|
29
|
+
|
|
30
|
+
UNION
|
|
31
|
+
|
|
32
|
+
SELECT
|
|
33
|
+
statuses.id AS searchable_id,
|
|
34
|
+
'Status' AS searchable_type,
|
|
35
|
+
statuses.body AS term
|
|
36
|
+
FROM statuses
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
Generate a new migration with the following `change` method:
|
|
40
|
+
|
|
41
|
+
```ruby
|
|
42
|
+
def change
|
|
43
|
+
create_view :searches
|
|
44
|
+
end
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
Run that migration and congrats, you've got yourself a view. The migration is
|
|
48
|
+
reversible and it will be dumped into your `schema.rb` file.
|
|
49
|
+
|
|
50
|
+
## Cool, but what if I need to change that view?
|
|
51
|
+
|
|
52
|
+
Add the new query to `db/views/searches_v2.sql` and generate a new migration with
|
|
53
|
+
the following `change` method:
|
|
54
|
+
|
|
55
|
+
```ruby
|
|
56
|
+
def change
|
|
57
|
+
update_view :searches, version: 2, revert_to_version: 1
|
|
58
|
+
end
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
When you run that migration, your view will be updated. The `revert_to_version`
|
|
62
|
+
option makes that migration reversible.
|
|
63
|
+
|
|
64
|
+
## Can I use this view to back a model?
|
|
65
|
+
|
|
66
|
+
You bet!
|
|
67
|
+
|
|
68
|
+
```ruby
|
|
69
|
+
class Search < ActiveRecord::Base
|
|
70
|
+
private
|
|
71
|
+
|
|
72
|
+
# this isn't strictly necessary, but it will prevent
|
|
73
|
+
# rails from calling save, which would fail anyway.
|
|
74
|
+
def readonly?
|
|
75
|
+
true
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
## I don't need this view anymore. Make it go away.
|
|
81
|
+
|
|
82
|
+
We give you `drop_view` too:
|
|
83
|
+
|
|
84
|
+
```ruby
|
|
85
|
+
def change
|
|
86
|
+
drop_view :searches, revert_to_version: 2
|
|
87
|
+
end
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
## Can you make this easier?
|
|
91
|
+
|
|
92
|
+
Yeah, we're working on it. We're going to provide some generators that will take
|
|
93
|
+
some of the busy work of file creation away. We'll create the SQL file, the
|
|
94
|
+
migration, and optionally the model for you.
|
|
95
|
+
|
|
96
|
+
Check out the issue tracker for our other plans.
|
data/Rakefile
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Create a new database view and ActiveRecord::Base subclass for your
|
|
3
|
+
application.
|
|
4
|
+
|
|
5
|
+
Examples:
|
|
6
|
+
rails generate scenic:model search
|
|
7
|
+
|
|
8
|
+
create: app/models/search.rb
|
|
9
|
+
create: db/views/searches_v1.sql
|
|
10
|
+
create: db/migrate/20140803191158_create_searches.rb
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require "generators/scenic/view/view_generator"
|
|
3
|
+
|
|
4
|
+
module Scenic
|
|
5
|
+
module Generators
|
|
6
|
+
class ModelGenerator < Rails::Generators::NamedBase
|
|
7
|
+
source_root File.expand_path("../templates", __FILE__)
|
|
8
|
+
|
|
9
|
+
check_class_collision
|
|
10
|
+
|
|
11
|
+
def create_model_file
|
|
12
|
+
template("model.erb", "app/models/#{file_name}.rb")
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def invoke_view_generator
|
|
16
|
+
invoke "scenic:view", [singular_name]
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
end
|
|
20
|
+
end
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
Description:
|
|
2
|
+
Create a new database view for your application. This will create a new
|
|
3
|
+
view definition file and the accompanying migration.
|
|
4
|
+
|
|
5
|
+
Examples:
|
|
6
|
+
rails generate scenic:view searches
|
|
7
|
+
|
|
8
|
+
create: db/views/searches_v1.sql
|
|
9
|
+
create: db/migrate/20140803191158_create_searches.rb
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
require "rails/generators"
|
|
2
|
+
require "rails/generators/active_record"
|
|
3
|
+
|
|
4
|
+
module Scenic
|
|
5
|
+
module Generators
|
|
6
|
+
class ViewGenerator < Rails::Generators::NamedBase
|
|
7
|
+
include Rails::Generators::Migration
|
|
8
|
+
source_root File.expand_path("../templates", __FILE__)
|
|
9
|
+
|
|
10
|
+
def create_view_definition
|
|
11
|
+
create_file "db/views/#{plural_name}_v1.sql"
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def create_migration_file
|
|
15
|
+
migration_template(
|
|
16
|
+
"db/migrate/create_view.erb",
|
|
17
|
+
"db/migrate/create_#{plural_name}.rb"
|
|
18
|
+
)
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def self.next_migration_number(dir)
|
|
22
|
+
::ActiveRecord::Generators::Base.next_migration_number(dir)
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
end
|
|
26
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
module Scenic
|
|
2
|
+
module ActiveRecord
|
|
3
|
+
module CommandRecorder
|
|
4
|
+
class StatementArguments
|
|
5
|
+
def initialize(args)
|
|
6
|
+
@args = args.freeze
|
|
7
|
+
end
|
|
8
|
+
|
|
9
|
+
def view
|
|
10
|
+
@args[0]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
def version
|
|
14
|
+
options[:version]
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def revert_to_version
|
|
18
|
+
options[:revert_to_version]
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def invert_version
|
|
22
|
+
StatementArguments.new([view, options_for_revert])
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def to_a
|
|
26
|
+
@args.to_a
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
private
|
|
30
|
+
|
|
31
|
+
def options
|
|
32
|
+
@options ||= @args[1] || {}
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
def options_for_revert
|
|
36
|
+
options.clone.tap do |revert_options|
|
|
37
|
+
revert_options[:version] = revert_to_version
|
|
38
|
+
revert_options.delete(:revert_to_version)
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
require "scenic/active_record/command_recorder/statement_arguments"
|
|
2
|
+
|
|
3
|
+
module Scenic
|
|
4
|
+
module ActiveRecord
|
|
5
|
+
module CommandRecorder
|
|
6
|
+
def create_view(*args)
|
|
7
|
+
record(:create_view, args)
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
def drop_view(*args)
|
|
11
|
+
record(:drop_view, args)
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
def update_view(*args)
|
|
15
|
+
record(:update_view, args)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
def invert_create_view(args)
|
|
19
|
+
[:drop_view, args]
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
def invert_drop_view(args)
|
|
23
|
+
perform_scenic_inversion(:create_view, args)
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
def invert_update_view(args)
|
|
27
|
+
perform_scenic_inversion(:update_view, args)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def perform_scenic_inversion(method, args)
|
|
33
|
+
scenic_args = StatementArguments.new(args)
|
|
34
|
+
|
|
35
|
+
if scenic_args.revert_to_version.nil?
|
|
36
|
+
message = "#{method} is reversible only if given a revert_to_version"
|
|
37
|
+
raise ::ActiveRecord::IrreversibleMigration, message
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
[method, scenic_args.invert_version.to_a]
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
require "rails"
|
|
2
|
+
|
|
3
|
+
module Scenic
|
|
4
|
+
module ActiveRecord
|
|
5
|
+
module SchemaDumper
|
|
6
|
+
extend ActiveSupport::Concern
|
|
7
|
+
|
|
8
|
+
included { alias_method_chain :tables, :views }
|
|
9
|
+
|
|
10
|
+
def tables_with_views(stream)
|
|
11
|
+
tables_without_views(stream)
|
|
12
|
+
views(stream)
|
|
13
|
+
end
|
|
14
|
+
|
|
15
|
+
def views(stream)
|
|
16
|
+
defined_views.sort.each do |view_name|
|
|
17
|
+
next if ["schema_migrations", ignore_tables].flatten.any? do |ignored|
|
|
18
|
+
case ignored
|
|
19
|
+
when String; remove_prefix_and_suffix(view_name) == ignored
|
|
20
|
+
when Regexp; remove_prefix_and_suffix(view_name) =~ ignored
|
|
21
|
+
else
|
|
22
|
+
raise StandardError, "ActiveRecord::SchemaDumper.ignore_tables accepts an array of String and / or Regexp values."
|
|
23
|
+
end
|
|
24
|
+
end
|
|
25
|
+
view(view_name, stream)
|
|
26
|
+
end
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def view(name, stream)
|
|
30
|
+
stream.puts(<<-DEFINITION)
|
|
31
|
+
create_view :#{name}, sql_definition:<<-\SQL
|
|
32
|
+
#{views_with_definitions[name]}
|
|
33
|
+
SQL
|
|
34
|
+
DEFINITION
|
|
35
|
+
stream
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def defined_views
|
|
39
|
+
views_with_definitions.keys
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
def views_with_definitions
|
|
43
|
+
@views_with_definitions ||=
|
|
44
|
+
Hash[@connection.execute(<<-SQL, 'SCHEMA').values]
|
|
45
|
+
SELECT viewname, definition
|
|
46
|
+
FROM pg_views
|
|
47
|
+
WHERE schemaname = ANY (current_schemas(false))
|
|
48
|
+
SQL
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
end
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
module Scenic
|
|
2
|
+
module ActiveRecord
|
|
3
|
+
module Statements
|
|
4
|
+
def create_view(name, version: 1, sql_definition: nil)
|
|
5
|
+
if version.nil? && sql_definition.nil?
|
|
6
|
+
raise(
|
|
7
|
+
ArgumentError,
|
|
8
|
+
"view_definition or version_number must be specified"
|
|
9
|
+
)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
sql_definition ||= definition(name, version)
|
|
13
|
+
|
|
14
|
+
execute "CREATE VIEW #{name} AS #{sql_definition};"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
def drop_view(name, revert_to_version: nil)
|
|
18
|
+
execute "DROP VIEW #{name};"
|
|
19
|
+
end
|
|
20
|
+
|
|
21
|
+
def update_view(name, version: nil, revert_to_version: nil)
|
|
22
|
+
if version.nil?
|
|
23
|
+
raise ArgumentError, "version is required"
|
|
24
|
+
end
|
|
25
|
+
|
|
26
|
+
drop_view(name)
|
|
27
|
+
create_view(name, version: version)
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
private
|
|
31
|
+
|
|
32
|
+
def definition(name, version)
|
|
33
|
+
File.read(::Rails.root.join("db", "views", "#{name}_v#{version}.sql"))
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
data/lib/scenic.rb
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
require "scenic/version"
|
|
2
|
+
require "scenic/railtie"
|
|
3
|
+
require "scenic/active_record/command_recorder"
|
|
4
|
+
require "scenic/active_record/schema_dumper"
|
|
5
|
+
require "scenic/active_record/statements"
|
|
6
|
+
|
|
7
|
+
module Scenic
|
|
8
|
+
def self.load
|
|
9
|
+
::ActiveRecord::ConnectionAdapters::AbstractAdapter.class_eval do
|
|
10
|
+
include Scenic::ActiveRecord::Statements
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
::ActiveRecord::Migration::CommandRecorder.class_eval do
|
|
14
|
+
include Scenic::ActiveRecord::CommandRecorder
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
::ActiveRecord::SchemaDumper.class_eval do
|
|
18
|
+
include Scenic::ActiveRecord::SchemaDumper
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
end
|
data/scenic.gemspec
ADDED
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
# coding: utf-8
|
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
|
4
|
+
require 'scenic/version'
|
|
5
|
+
|
|
6
|
+
Gem::Specification.new do |spec|
|
|
7
|
+
spec.name = 'scenic'
|
|
8
|
+
spec.version = Scenic::VERSION
|
|
9
|
+
spec.authors = ['Derek Prior', 'Caleb Thompson']
|
|
10
|
+
spec.email = ['derekprior@gmail.com', 'caleb@calebthompson.io']
|
|
11
|
+
spec.summary = %q{Support for database views in Rails migrations}
|
|
12
|
+
spec.description = <<-DESCRIPTION
|
|
13
|
+
Adds methods to ActiveRecord::Migration to create and manage database views
|
|
14
|
+
in Rails
|
|
15
|
+
DESCRIPTION
|
|
16
|
+
spec.homepage = 'https://github.com/thoughtbot/scenic'
|
|
17
|
+
spec.license = 'MIT'
|
|
18
|
+
|
|
19
|
+
spec.files = `git ls-files -z`.split("\x0")
|
|
20
|
+
spec.test_files = spec.files.grep(%r{^spec/})
|
|
21
|
+
spec.require_paths = ['lib']
|
|
22
|
+
|
|
23
|
+
spec.add_development_dependency 'bundler', '>= 1.5'
|
|
24
|
+
spec.add_development_dependency 'database_cleaner'
|
|
25
|
+
spec.add_development_dependency 'rake'
|
|
26
|
+
spec.add_development_dependency 'rspec', '~> 3.0'
|
|
27
|
+
spec.add_development_dependency 'pg'
|
|
28
|
+
spec.add_development_dependency 'pry'
|
|
29
|
+
spec.add_development_dependency 'ammeter'
|
|
30
|
+
|
|
31
|
+
spec.add_dependency 'activerecord', '>= 4.0.0'
|
|
32
|
+
spec.add_dependency 'railties', '>= 4.0.0'
|
|
33
|
+
|
|
34
|
+
spec.required_ruby_version = '~> 2.0'
|
|
35
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
# See https://help.github.com/articles/ignoring-files for more about ignoring files.
|
|
2
|
+
#
|
|
3
|
+
# If you find yourself ignoring temporary files generated by your text editor
|
|
4
|
+
# or operating system, you probably want to add a global ignore instead:
|
|
5
|
+
# git config --global core.excludesfile '~/.gitignore_global'
|
|
6
|
+
|
|
7
|
+
# Ignore bundler config.
|
|
8
|
+
/.bundle
|
|
9
|
+
|
|
10
|
+
# Ignore the default SQLite database.
|
|
11
|
+
/db/*.sqlite3
|
|
12
|
+
/db/*.sqlite3-journal
|
|
13
|
+
|
|
14
|
+
# Ignore all logfiles and tempfiles.
|
|
15
|
+
/log/*.log
|
|
16
|
+
/tmp
|
data/spec/dummy/Rakefile
ADDED
data/spec/dummy/bin/rake
ADDED
|
File without changes
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "generators/scenic/model/model_generator"
|
|
3
|
+
|
|
4
|
+
describe Scenic::Generators::ModelGenerator, :generator do
|
|
5
|
+
before do
|
|
6
|
+
allow(Scenic::Generators::ViewGenerator).to receive(:new)
|
|
7
|
+
.and_return(
|
|
8
|
+
instance_double("Scenic::Generators::ViewGenerator").as_null_object
|
|
9
|
+
)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "invokes the view generator" do
|
|
13
|
+
run_generator ["current_customer"]
|
|
14
|
+
|
|
15
|
+
expect(Scenic::Generators::ViewGenerator).to have_received(:new)
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "creates a migration to create the view" do
|
|
19
|
+
run_generator ["current_customer"]
|
|
20
|
+
model_definition = file("app/models/current_customer.rb")
|
|
21
|
+
expect(model_definition).to exist
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
require "generators/scenic/view/view_generator"
|
|
3
|
+
|
|
4
|
+
describe Scenic::Generators::ViewGenerator, :generator do
|
|
5
|
+
it "creates a view definition file" do
|
|
6
|
+
run_generator ["search"]
|
|
7
|
+
view_definition = file("db/views/searches_v1.sql")
|
|
8
|
+
expect(view_definition).to exist
|
|
9
|
+
end
|
|
10
|
+
|
|
11
|
+
it "creates a migration to create the view" do
|
|
12
|
+
run_generator ["search"]
|
|
13
|
+
migration = file("db/migrate/create_searches.rb")
|
|
14
|
+
expect(migration).to be_a_migration
|
|
15
|
+
end
|
|
16
|
+
end
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe "Reverting scenic schema statements", :db do
|
|
4
|
+
around do |example|
|
|
5
|
+
with_view_definition :greetings, 1, "SELECT text 'hola' AS greeting" do
|
|
6
|
+
example.run
|
|
7
|
+
end
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "reverts dropped view to specified version" do
|
|
11
|
+
run_migration(migration_for_create, :up)
|
|
12
|
+
run_migration(migration_for_drop, :up)
|
|
13
|
+
run_migration(migration_for_drop, :down)
|
|
14
|
+
|
|
15
|
+
expect { execute("SELECT * from greetings") }
|
|
16
|
+
.not_to raise_error
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
it "reverts updated view to specified version" do
|
|
20
|
+
with_view_definition :greetings, 2, "SELECT text 'good day' AS greeting" do
|
|
21
|
+
run_migration(migration_for_create, :up)
|
|
22
|
+
run_migration(migration_for_update, :up)
|
|
23
|
+
run_migration(migration_for_update, :down)
|
|
24
|
+
|
|
25
|
+
greeting = execute("SELECT * from greetings")[0]["greeting"]
|
|
26
|
+
|
|
27
|
+
expect(greeting).to eq "hola"
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
def migration_for_create
|
|
32
|
+
Class.new(::ActiveRecord::Migration) do
|
|
33
|
+
def change
|
|
34
|
+
create_view :greetings
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def migration_for_drop
|
|
40
|
+
Class.new(::ActiveRecord::Migration) do
|
|
41
|
+
def change
|
|
42
|
+
drop_view :greetings, revert_to_version: 1
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
def migration_for_update
|
|
48
|
+
Class.new(::ActiveRecord::Migration) do
|
|
49
|
+
def change
|
|
50
|
+
update_view :greetings, version: 2, revert_to_version: 1
|
|
51
|
+
end
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
def run_migration(migration, directions)
|
|
56
|
+
silence_stream(STDOUT) do
|
|
57
|
+
Array.wrap(directions).each do |direction|
|
|
58
|
+
migration.migrate(direction)
|
|
59
|
+
end
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
def execute(sql)
|
|
64
|
+
ActiveRecord::Base.connection.execute(sql)
|
|
65
|
+
end
|
|
66
|
+
end
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
module Scenic::ActiveRecord::CommandRecorder
|
|
4
|
+
describe StatementArguments do
|
|
5
|
+
describe "#view" do
|
|
6
|
+
it "is the view name" do
|
|
7
|
+
raw_args = [:spaceships, { foo: :bar }]
|
|
8
|
+
args = StatementArguments.new(raw_args)
|
|
9
|
+
|
|
10
|
+
expect(args.view).to eq :spaceships
|
|
11
|
+
end
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
describe "#revert_to_version" do
|
|
15
|
+
it "is the revert_to_version from the keyword arguments" do
|
|
16
|
+
raw_args = [:spaceships, { revert_to_version: 42 }]
|
|
17
|
+
args = StatementArguments.new(raw_args)
|
|
18
|
+
|
|
19
|
+
expect(args.revert_to_version).to eq 42
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "is nil if the revert_to_version was not supplied" do
|
|
23
|
+
raw_args = [:spaceships, { foo: :bar }]
|
|
24
|
+
args = StatementArguments.new(raw_args)
|
|
25
|
+
|
|
26
|
+
expect(args.revert_to_version).to be nil
|
|
27
|
+
end
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
describe "#invert_version" do
|
|
31
|
+
it "returns object with version set to revert_to_version" do
|
|
32
|
+
raw_args = [:meatballs, { version: 42, revert_to_version: 15 }]
|
|
33
|
+
|
|
34
|
+
inverted_args = StatementArguments.new(raw_args).invert_version
|
|
35
|
+
|
|
36
|
+
expect(inverted_args.version).to eq 15
|
|
37
|
+
expect(inverted_args.revert_to_version).to be nil
|
|
38
|
+
end
|
|
39
|
+
end
|
|
40
|
+
end
|
|
41
|
+
end
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
describe Scenic::ActiveRecord::CommandRecorder do
|
|
4
|
+
describe "#create_view" do
|
|
5
|
+
it "records the created view" do
|
|
6
|
+
recorder = ActiveRecord::Migration::CommandRecorder.new
|
|
7
|
+
|
|
8
|
+
recorder.create_view :greetings
|
|
9
|
+
|
|
10
|
+
expect(recorder.commands).to eq [[:create_view, [:greetings], nil]]
|
|
11
|
+
end
|
|
12
|
+
|
|
13
|
+
it "reverts to drop_view" do
|
|
14
|
+
recorder = ActiveRecord::Migration::CommandRecorder.new
|
|
15
|
+
|
|
16
|
+
recorder.revert { recorder.create_view :greetings }
|
|
17
|
+
|
|
18
|
+
expect(recorder.commands).to eq [[:drop_view, [:greetings]]]
|
|
19
|
+
end
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
describe "#drop_view" do
|
|
23
|
+
it "records the dropped view" do
|
|
24
|
+
recorder = ActiveRecord::Migration::CommandRecorder.new
|
|
25
|
+
|
|
26
|
+
recorder.drop_view :users
|
|
27
|
+
|
|
28
|
+
expect(recorder.commands).to eq [[:drop_view, [:users], nil]]
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "reverts to create_view with specified revert_to_version" do
|
|
32
|
+
recorder = ActiveRecord::Migration::CommandRecorder.new
|
|
33
|
+
args = [:users, { revert_to_version: 3 }]
|
|
34
|
+
revert_args = [:users, { version: 3 }]
|
|
35
|
+
|
|
36
|
+
recorder.revert { recorder.drop_view(*args) }
|
|
37
|
+
|
|
38
|
+
expect(recorder.commands).to eq [[:create_view, revert_args]]
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "raises when reverting without revert_to_version set" do
|
|
42
|
+
recorder = ActiveRecord::Migration::CommandRecorder.new
|
|
43
|
+
args = [:users, { another_argument: 1 }]
|
|
44
|
+
|
|
45
|
+
expect { recorder.revert { recorder.drop_view(*args) } }
|
|
46
|
+
.to raise_error(ActiveRecord::IrreversibleMigration)
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
describe "#update_view" do
|
|
51
|
+
it "records the updated view" do
|
|
52
|
+
recorder = ActiveRecord::Migration::CommandRecorder.new
|
|
53
|
+
args = [:users, { version: 2 }]
|
|
54
|
+
|
|
55
|
+
recorder.update_view(*args)
|
|
56
|
+
|
|
57
|
+
expect(recorder.commands).to eq [[:update_view, args, nil]]
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "reverts to update_view with the specified revert_to_version" do
|
|
61
|
+
recorder = ActiveRecord::Migration::CommandRecorder.new
|
|
62
|
+
args = [:users, { version: 2, revert_to_version: 1 }]
|
|
63
|
+
revert_args = [:users, { version: 1 }]
|
|
64
|
+
|
|
65
|
+
recorder.revert { recorder.update_view(*args) }
|
|
66
|
+
|
|
67
|
+
expect(recorder.commands).to eq [[:update_view, revert_args]]
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
it "raises when reverting without revert_to_version set" do
|
|
71
|
+
recorder = ActiveRecord::Migration::CommandRecorder.new
|
|
72
|
+
args = [:users, { version: 42, another_argument: 1 }]
|
|
73
|
+
|
|
74
|
+
expect { recorder.revert { recorder.update_view(*args) } }
|
|
75
|
+
.to raise_error(ActiveRecord::IrreversibleMigration)
|
|
76
|
+
end
|
|
77
|
+
end
|
|
78
|
+
end
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
class Search < ActiveRecord::Base; end
|
|
4
|
+
|
|
5
|
+
describe Scenic::ActiveRecord::SchemaDumper, :db do
|
|
6
|
+
it "dumps a create_view for a view in the database" do
|
|
7
|
+
view_definition = "SELECT 'needle'::text AS haystack"
|
|
8
|
+
Search.connection.create_view :searches, sql_definition: view_definition
|
|
9
|
+
stream = StringIO.new
|
|
10
|
+
|
|
11
|
+
ActiveRecord::SchemaDumper.dump(Search.connection, stream)
|
|
12
|
+
|
|
13
|
+
output = stream.string
|
|
14
|
+
expect(output).to include "create_view :searches"
|
|
15
|
+
expect(output).to include view_definition
|
|
16
|
+
|
|
17
|
+
Search.connection.drop_view :searches
|
|
18
|
+
|
|
19
|
+
silence_stream(STDOUT) { eval(output) }
|
|
20
|
+
|
|
21
|
+
expect(Search.first.haystack).to eq "needle"
|
|
22
|
+
end
|
|
23
|
+
end
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
require "spec_helper"
|
|
2
|
+
|
|
3
|
+
class View < ActiveRecord::Base
|
|
4
|
+
end
|
|
5
|
+
|
|
6
|
+
describe Scenic::ActiveRecord::Statements, :db do
|
|
7
|
+
describe "create_view" do
|
|
8
|
+
it "creates a view from a file" do
|
|
9
|
+
with_view_definition :views, 1, "SELECT text 'Hello World' AS hello" do
|
|
10
|
+
View.connection.create_view :views
|
|
11
|
+
|
|
12
|
+
expect(View.all.pluck(:hello)).to eq ["Hello World"]
|
|
13
|
+
end
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "creates a view from a text definition" do
|
|
17
|
+
View.connection.create_view :views,
|
|
18
|
+
sql_definition: "SELECT text 'Goodbye' AS hello"
|
|
19
|
+
|
|
20
|
+
expect(View.all.pluck(:hello)).to eq ["Goodbye"]
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
it "creates a view from a specific version" do
|
|
24
|
+
with_view_definition :views, 15, "SELECT text 'Hello Earth East 15' AS hello" do
|
|
25
|
+
View.connection.create_view :views, version: 15
|
|
26
|
+
|
|
27
|
+
expect(View.all.pluck(:hello)).to eq ["Hello Earth East 15"]
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "raises an error if both arguments are nil" do
|
|
32
|
+
expect do
|
|
33
|
+
View.connection.create_view :whatever,
|
|
34
|
+
version: nil,
|
|
35
|
+
sql_definition: nil
|
|
36
|
+
end.to raise_error ArgumentError
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
describe "drop_view" do
|
|
41
|
+
it "removes a view from the database" do
|
|
42
|
+
with_view_definition :things, 1, "SELECT text 'Hi' AS greeting" do
|
|
43
|
+
View.connection.create_view :things
|
|
44
|
+
|
|
45
|
+
View.connection.drop_view :things
|
|
46
|
+
|
|
47
|
+
expect(views).not_to include "things"
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
describe "update_view" do
|
|
53
|
+
it "updates an existing view in the database" do
|
|
54
|
+
with_view_definition :views, 1, "SELECT text 'Hi' AS greeting" do
|
|
55
|
+
View.connection.create_view :views
|
|
56
|
+
with_view_definition :views, 2, "SELECT text 'Hello' AS greeting" do
|
|
57
|
+
View.connection.update_view :views, version: 2
|
|
58
|
+
|
|
59
|
+
expect(View.all.pluck(:greeting)).to eq ['Hello']
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "raises an error if not supplied a version" do
|
|
65
|
+
expect { View.connection.update_view :views }
|
|
66
|
+
.to raise_error(ArgumentError, /version is required/)
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
it "raises an error if the view to be updated does not exist" do
|
|
70
|
+
with_view_definition :views, 2, "SELECT text 'Hi' as greeting" do
|
|
71
|
+
expect { View.connection.update_view :views, version: 2 }
|
|
72
|
+
.to raise_error(ActiveRecord::StatementInvalid, /does not exist/)
|
|
73
|
+
end
|
|
74
|
+
end
|
|
75
|
+
end
|
|
76
|
+
|
|
77
|
+
def views
|
|
78
|
+
ActiveRecord::Base.connection
|
|
79
|
+
.execute("SELECT table_name FROM INFORMATION_SCHEMA.views")
|
|
80
|
+
.map(&:values).flatten
|
|
81
|
+
end
|
|
82
|
+
end
|
data/spec/spec_helper.rb
ADDED
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
ENV["RAILS_ENV"] = "test"
|
|
2
|
+
require "database_cleaner"
|
|
3
|
+
|
|
4
|
+
require File.expand_path("../dummy/config/environment", __FILE__)
|
|
5
|
+
require "support/generator_spec_setup"
|
|
6
|
+
require "support/view_definition_helpers"
|
|
7
|
+
|
|
8
|
+
RSpec.configure do |config|
|
|
9
|
+
config.order = "random"
|
|
10
|
+
config.include ViewDefinitionHelpers
|
|
11
|
+
DatabaseCleaner.strategy = :transaction
|
|
12
|
+
|
|
13
|
+
config.around(:each, db: true) do |example|
|
|
14
|
+
DatabaseCleaner.start
|
|
15
|
+
example.run
|
|
16
|
+
DatabaseCleaner.clean
|
|
17
|
+
end
|
|
18
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,241 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: scenic
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 0.1.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- Derek Prior
|
|
8
|
+
- Caleb Thompson
|
|
9
|
+
autorequire:
|
|
10
|
+
bindir: bin
|
|
11
|
+
cert_chain: []
|
|
12
|
+
date: 2014-08-04 00:00:00.000000000 Z
|
|
13
|
+
dependencies:
|
|
14
|
+
- !ruby/object:Gem::Dependency
|
|
15
|
+
name: bundler
|
|
16
|
+
requirement: !ruby/object:Gem::Requirement
|
|
17
|
+
requirements:
|
|
18
|
+
- - ">="
|
|
19
|
+
- !ruby/object:Gem::Version
|
|
20
|
+
version: '1.5'
|
|
21
|
+
type: :development
|
|
22
|
+
prerelease: false
|
|
23
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
24
|
+
requirements:
|
|
25
|
+
- - ">="
|
|
26
|
+
- !ruby/object:Gem::Version
|
|
27
|
+
version: '1.5'
|
|
28
|
+
- !ruby/object:Gem::Dependency
|
|
29
|
+
name: database_cleaner
|
|
30
|
+
requirement: !ruby/object:Gem::Requirement
|
|
31
|
+
requirements:
|
|
32
|
+
- - ">="
|
|
33
|
+
- !ruby/object:Gem::Version
|
|
34
|
+
version: '0'
|
|
35
|
+
type: :development
|
|
36
|
+
prerelease: false
|
|
37
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
38
|
+
requirements:
|
|
39
|
+
- - ">="
|
|
40
|
+
- !ruby/object:Gem::Version
|
|
41
|
+
version: '0'
|
|
42
|
+
- !ruby/object:Gem::Dependency
|
|
43
|
+
name: rake
|
|
44
|
+
requirement: !ruby/object:Gem::Requirement
|
|
45
|
+
requirements:
|
|
46
|
+
- - ">="
|
|
47
|
+
- !ruby/object:Gem::Version
|
|
48
|
+
version: '0'
|
|
49
|
+
type: :development
|
|
50
|
+
prerelease: false
|
|
51
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
52
|
+
requirements:
|
|
53
|
+
- - ">="
|
|
54
|
+
- !ruby/object:Gem::Version
|
|
55
|
+
version: '0'
|
|
56
|
+
- !ruby/object:Gem::Dependency
|
|
57
|
+
name: rspec
|
|
58
|
+
requirement: !ruby/object:Gem::Requirement
|
|
59
|
+
requirements:
|
|
60
|
+
- - "~>"
|
|
61
|
+
- !ruby/object:Gem::Version
|
|
62
|
+
version: '3.0'
|
|
63
|
+
type: :development
|
|
64
|
+
prerelease: false
|
|
65
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
66
|
+
requirements:
|
|
67
|
+
- - "~>"
|
|
68
|
+
- !ruby/object:Gem::Version
|
|
69
|
+
version: '3.0'
|
|
70
|
+
- !ruby/object:Gem::Dependency
|
|
71
|
+
name: pg
|
|
72
|
+
requirement: !ruby/object:Gem::Requirement
|
|
73
|
+
requirements:
|
|
74
|
+
- - ">="
|
|
75
|
+
- !ruby/object:Gem::Version
|
|
76
|
+
version: '0'
|
|
77
|
+
type: :development
|
|
78
|
+
prerelease: false
|
|
79
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
80
|
+
requirements:
|
|
81
|
+
- - ">="
|
|
82
|
+
- !ruby/object:Gem::Version
|
|
83
|
+
version: '0'
|
|
84
|
+
- !ruby/object:Gem::Dependency
|
|
85
|
+
name: pry
|
|
86
|
+
requirement: !ruby/object:Gem::Requirement
|
|
87
|
+
requirements:
|
|
88
|
+
- - ">="
|
|
89
|
+
- !ruby/object:Gem::Version
|
|
90
|
+
version: '0'
|
|
91
|
+
type: :development
|
|
92
|
+
prerelease: false
|
|
93
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
94
|
+
requirements:
|
|
95
|
+
- - ">="
|
|
96
|
+
- !ruby/object:Gem::Version
|
|
97
|
+
version: '0'
|
|
98
|
+
- !ruby/object:Gem::Dependency
|
|
99
|
+
name: ammeter
|
|
100
|
+
requirement: !ruby/object:Gem::Requirement
|
|
101
|
+
requirements:
|
|
102
|
+
- - ">="
|
|
103
|
+
- !ruby/object:Gem::Version
|
|
104
|
+
version: '0'
|
|
105
|
+
type: :development
|
|
106
|
+
prerelease: false
|
|
107
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
108
|
+
requirements:
|
|
109
|
+
- - ">="
|
|
110
|
+
- !ruby/object:Gem::Version
|
|
111
|
+
version: '0'
|
|
112
|
+
- !ruby/object:Gem::Dependency
|
|
113
|
+
name: activerecord
|
|
114
|
+
requirement: !ruby/object:Gem::Requirement
|
|
115
|
+
requirements:
|
|
116
|
+
- - ">="
|
|
117
|
+
- !ruby/object:Gem::Version
|
|
118
|
+
version: 4.0.0
|
|
119
|
+
type: :runtime
|
|
120
|
+
prerelease: false
|
|
121
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
122
|
+
requirements:
|
|
123
|
+
- - ">="
|
|
124
|
+
- !ruby/object:Gem::Version
|
|
125
|
+
version: 4.0.0
|
|
126
|
+
- !ruby/object:Gem::Dependency
|
|
127
|
+
name: railties
|
|
128
|
+
requirement: !ruby/object:Gem::Requirement
|
|
129
|
+
requirements:
|
|
130
|
+
- - ">="
|
|
131
|
+
- !ruby/object:Gem::Version
|
|
132
|
+
version: 4.0.0
|
|
133
|
+
type: :runtime
|
|
134
|
+
prerelease: false
|
|
135
|
+
version_requirements: !ruby/object:Gem::Requirement
|
|
136
|
+
requirements:
|
|
137
|
+
- - ">="
|
|
138
|
+
- !ruby/object:Gem::Version
|
|
139
|
+
version: 4.0.0
|
|
140
|
+
description: |2
|
|
141
|
+
Adds methods to ActiveRecord::Migration to create and manage database views
|
|
142
|
+
in Rails
|
|
143
|
+
email:
|
|
144
|
+
- derekprior@gmail.com
|
|
145
|
+
- caleb@calebthompson.io
|
|
146
|
+
executables: []
|
|
147
|
+
extensions: []
|
|
148
|
+
extra_rdoc_files: []
|
|
149
|
+
files:
|
|
150
|
+
- ".gitignore"
|
|
151
|
+
- ".hound.yml"
|
|
152
|
+
- ".travis.yml"
|
|
153
|
+
- Gemfile
|
|
154
|
+
- LICENSE.txt
|
|
155
|
+
- README.md
|
|
156
|
+
- Rakefile
|
|
157
|
+
- lib/generators/scenic/model/USAGE
|
|
158
|
+
- lib/generators/scenic/model/model_generator.rb
|
|
159
|
+
- lib/generators/scenic/model/templates/model.erb
|
|
160
|
+
- lib/generators/scenic/view/USAGE
|
|
161
|
+
- lib/generators/scenic/view/templates/db/migrate/create_view.erb
|
|
162
|
+
- lib/generators/scenic/view/view_generator.rb
|
|
163
|
+
- lib/scenic.rb
|
|
164
|
+
- lib/scenic/active_record/command_recorder.rb
|
|
165
|
+
- lib/scenic/active_record/command_recorder/statement_arguments.rb
|
|
166
|
+
- lib/scenic/active_record/schema_dumper.rb
|
|
167
|
+
- lib/scenic/active_record/statements.rb
|
|
168
|
+
- lib/scenic/railtie.rb
|
|
169
|
+
- lib/scenic/version.rb
|
|
170
|
+
- scenic.gemspec
|
|
171
|
+
- spec/dummy/.gitignore
|
|
172
|
+
- spec/dummy/Rakefile
|
|
173
|
+
- spec/dummy/bin/bundle
|
|
174
|
+
- spec/dummy/bin/rails
|
|
175
|
+
- spec/dummy/bin/rake
|
|
176
|
+
- spec/dummy/config.ru
|
|
177
|
+
- spec/dummy/config/application.rb
|
|
178
|
+
- spec/dummy/config/boot.rb
|
|
179
|
+
- spec/dummy/config/database.yml
|
|
180
|
+
- spec/dummy/config/environment.rb
|
|
181
|
+
- spec/dummy/config/environments/development.rb
|
|
182
|
+
- spec/dummy/config/environments/test.rb
|
|
183
|
+
- spec/dummy/db/views/.keep
|
|
184
|
+
- spec/generators/scenic/model/model_generator_spec.rb
|
|
185
|
+
- spec/generators/scenic/view/view_generator_spec.rb
|
|
186
|
+
- spec/integration/revert_spec.rb
|
|
187
|
+
- spec/scenic/active_record/command_recorder/statement_arguments_spec.rb
|
|
188
|
+
- spec/scenic/active_record/command_recorder_spec.rb
|
|
189
|
+
- spec/scenic/active_record/schema_dumper_spec.rb
|
|
190
|
+
- spec/scenic/active_record/statements_spec.rb
|
|
191
|
+
- spec/spec_helper.rb
|
|
192
|
+
- spec/support/generator_spec_setup.rb
|
|
193
|
+
- spec/support/view_definition_helpers.rb
|
|
194
|
+
homepage: https://github.com/thoughtbot/scenic
|
|
195
|
+
licenses:
|
|
196
|
+
- MIT
|
|
197
|
+
metadata: {}
|
|
198
|
+
post_install_message:
|
|
199
|
+
rdoc_options: []
|
|
200
|
+
require_paths:
|
|
201
|
+
- lib
|
|
202
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
203
|
+
requirements:
|
|
204
|
+
- - "~>"
|
|
205
|
+
- !ruby/object:Gem::Version
|
|
206
|
+
version: '2.0'
|
|
207
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
208
|
+
requirements:
|
|
209
|
+
- - ">="
|
|
210
|
+
- !ruby/object:Gem::Version
|
|
211
|
+
version: '0'
|
|
212
|
+
requirements: []
|
|
213
|
+
rubyforge_project:
|
|
214
|
+
rubygems_version: 2.2.2
|
|
215
|
+
signing_key:
|
|
216
|
+
specification_version: 4
|
|
217
|
+
summary: Support for database views in Rails migrations
|
|
218
|
+
test_files:
|
|
219
|
+
- spec/dummy/.gitignore
|
|
220
|
+
- spec/dummy/Rakefile
|
|
221
|
+
- spec/dummy/bin/bundle
|
|
222
|
+
- spec/dummy/bin/rails
|
|
223
|
+
- spec/dummy/bin/rake
|
|
224
|
+
- spec/dummy/config.ru
|
|
225
|
+
- spec/dummy/config/application.rb
|
|
226
|
+
- spec/dummy/config/boot.rb
|
|
227
|
+
- spec/dummy/config/database.yml
|
|
228
|
+
- spec/dummy/config/environment.rb
|
|
229
|
+
- spec/dummy/config/environments/development.rb
|
|
230
|
+
- spec/dummy/config/environments/test.rb
|
|
231
|
+
- spec/dummy/db/views/.keep
|
|
232
|
+
- spec/generators/scenic/model/model_generator_spec.rb
|
|
233
|
+
- spec/generators/scenic/view/view_generator_spec.rb
|
|
234
|
+
- spec/integration/revert_spec.rb
|
|
235
|
+
- spec/scenic/active_record/command_recorder/statement_arguments_spec.rb
|
|
236
|
+
- spec/scenic/active_record/command_recorder_spec.rb
|
|
237
|
+
- spec/scenic/active_record/schema_dumper_spec.rb
|
|
238
|
+
- spec/scenic/active_record/statements_spec.rb
|
|
239
|
+
- spec/spec_helper.rb
|
|
240
|
+
- spec/support/generator_spec_setup.rb
|
|
241
|
+
- spec/support/view_definition_helpers.rb
|