scenic 0.3.0 → 1.0.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 +4 -4
- data/.travis.yml +6 -4
- data/.yardopts +5 -0
- data/CONTRIBUTING.md +25 -0
- data/LICENSE.txt +1 -1
- data/NEWS.md +61 -9
- data/README.md +98 -62
- data/Rakefile +5 -0
- data/bin/setup +7 -0
- data/lib/generators/scenic/generators.rb +11 -0
- data/lib/generators/scenic/materializable.rb +22 -0
- data/lib/generators/scenic/model/USAGE +2 -0
- data/lib/generators/scenic/model/model_generator.rb +31 -4
- data/lib/generators/scenic/model/templates/model.erb +3 -2
- data/lib/generators/scenic/view/USAGE +2 -0
- data/lib/generators/scenic/view/templates/db/migrate/create_view.erb +1 -1
- data/lib/generators/scenic/view/templates/db/migrate/update_view.erb +7 -0
- data/lib/generators/scenic/view/view_generator.rb +5 -2
- data/lib/scenic.rb +13 -2
- data/lib/scenic/adapters/postgres.rb +74 -7
- data/lib/scenic/command_recorder.rb +1 -0
- data/lib/scenic/command_recorder/statement_arguments.rb +1 -0
- data/lib/scenic/configuration.rb +37 -0
- data/lib/scenic/definition.rb +2 -1
- data/lib/scenic/railtie.rb +4 -0
- data/lib/scenic/schema_dumper.rb +3 -6
- data/lib/scenic/statements.rb +61 -41
- data/lib/scenic/version.rb +1 -1
- data/lib/scenic/view.rb +41 -9
- data/scenic.gemspec +2 -2
- data/spec/dummy/db/views/.keep +0 -0
- data/spec/generators/scenic/model/model_generator_spec.rb +11 -0
- data/spec/generators/scenic/view/view_generator_spec.rb +13 -0
- data/spec/scenic/adapters/postgres_spec.rb +57 -14
- data/spec/scenic/configuration_spec.rb +27 -0
- data/spec/scenic/statements_spec.rb +33 -2
- data/spec/smoke +92 -67
- data/spec/support/generator_spec_setup.rb +1 -0
- metadata +19 -10
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: aad0218a7caab0f7bb48d964a0b2fb7b45d3da68
|
4
|
+
data.tar.gz: 567bf836c969e9a5287a19c10a5dcd40b9a0d03d
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 57c9ba2f5803667e7f256730881e75f95ffa113b6a75d3cb94b1ef884d9e258a26c696697840a4118a88ba010fb759d339e2c89f30a903ad967e700aeb227690
|
7
|
+
data.tar.gz: bb6f28f0b4a24ac0e737c98fe4081e4f2a67bf9205bf89701a4deb2d1fc7ccdb1bc5d4fe5d52a002b5cc4f99154ff64d7906ea53ccd49f2e420a87c96f5bce31
|
data/.travis.yml
CHANGED
@@ -1,19 +1,21 @@
|
|
1
|
+
addons:
|
2
|
+
postgresql: "9.3"
|
1
3
|
before_install:
|
2
4
|
- "echo '--colour' > ~/.rspec"
|
3
5
|
- "echo 'gem: --no-document' > ~/.gemrc"
|
4
6
|
- git config --global user.name 'Travis CI'
|
5
7
|
- git config --global user.email 'travis-ci@example.com'
|
6
|
-
before_script:
|
7
|
-
- pushd spec/dummy && bundle exec rake db:create && mkdir db/views && popd
|
8
8
|
branches:
|
9
9
|
only:
|
10
10
|
- master
|
11
|
+
install:
|
12
|
+
- travis_retry bin/setup
|
11
13
|
language:
|
12
14
|
- ruby
|
13
15
|
notifications:
|
14
16
|
email:
|
15
17
|
- false
|
16
18
|
rvm:
|
17
|
-
- 2.1.
|
18
|
-
- 2.2.
|
19
|
+
- 2.1.7
|
20
|
+
- 2.2.3
|
19
21
|
sudo: false
|
data/.yardopts
ADDED
data/CONTRIBUTING.md
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# Contributing
|
2
|
+
|
3
|
+
We love pull requests from everyone. By participating in this project, you
|
4
|
+
agree to abide by the thoughtbot [code of conduct].
|
5
|
+
|
6
|
+
[code of conduct]: https://thoughtbot.com/open-source-code-of-conduct
|
7
|
+
|
8
|
+
We expect everyone to follow the code of conduct anywhere in thoughtbot's
|
9
|
+
project codebases, issue trackers, chatrooms, and mailing lists.
|
10
|
+
|
11
|
+
## Setting Up for Development
|
12
|
+
|
13
|
+
1. For the repository.
|
14
|
+
2. Run `bin/setup`, which will install dependencies and create the dummy
|
15
|
+
application database.
|
16
|
+
3. Run `rake` to verify that the tests pass.
|
17
|
+
4. Make your change with new passing tests, following the [style guide].
|
18
|
+
5. Write a [good commit message], push your fork, and submit a pull request.
|
19
|
+
|
20
|
+
[style guide]: https://github.com/thoughtbot/guides/tree/master/style
|
21
|
+
[good commit message]: http://tbaggery.com/2008/04/19/a-note-about-git-commit-messages.html
|
22
|
+
|
23
|
+
Others will give constructive feedback. This is a time for discussion and
|
24
|
+
improvements, and making the necessary changes will be required before we can
|
25
|
+
merge the contribution.
|
data/LICENSE.txt
CHANGED
data/NEWS.md
CHANGED
@@ -1,12 +1,64 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
# News
|
2
|
+
|
3
|
+
The noteworthy changes for each Scenic version are included here. For a complete
|
4
|
+
changelog, see the [CHANGELOG] for each version via the version links.
|
5
|
+
|
6
|
+
[CHANGELOG]: https://github.com/thoughtbot/scenic/commits/master
|
7
|
+
|
8
|
+
## [1.0.0] - November 23, 2015
|
9
|
+
|
10
|
+
### Added
|
11
|
+
- Added support for [materialized views].
|
12
|
+
- Allow changing the database adapter via `Scenic::Configuration`.
|
13
|
+
|
14
|
+
### Fixed
|
15
|
+
- Improved formatting of the view when dumped to `schema.rb`.
|
16
|
+
- Fixed generation of namespaced models by using ActiveRecord's own model
|
17
|
+
generator.
|
18
|
+
- Eliminated `alias_method_chain` deprecation when running with Rails master
|
19
|
+
(5.0).
|
20
|
+
|
21
|
+
[materialized views]:https://github.com/thoughtbot/scenic/blob/v1.0.0/README.md
|
22
|
+
[1.0.0]: https://github.com/thoughtbot/scenic/compare/v0.3.0...v1.0.0
|
23
|
+
|
24
|
+
## [0.3.0] - January 23, 2015
|
25
|
+
|
26
|
+
### Added
|
27
|
+
- Previous view definition is copied into new view definition file when updating
|
3
28
|
an existing view.
|
4
|
-
* We avoid dumping views that belong to Postgres extensions
|
5
|
-
* `db/schema.rb` is prettier thanks to a blank line after each view definition.
|
6
29
|
|
7
|
-
|
8
|
-
|
30
|
+
### Fixed
|
31
|
+
- We avoid dumping views that belong to Postgres extensions.
|
32
|
+
- `db/schema.rb` is prettier thanks to a blank line after each view definition.
|
33
|
+
|
34
|
+
[0.3.0]: https://github.com/thoughtbot/scenic/compare/v0.2.1...v0.3.0
|
35
|
+
|
36
|
+
## [0.2.1] - January 5, 2015
|
37
|
+
|
38
|
+
### Fixed
|
39
|
+
- View generator will now create `db/views` directory if necessary.
|
40
|
+
|
41
|
+
[0.2.1]: https://github.com/thoughtbot/scenic/compare/v0.2.0...v0.2.1
|
42
|
+
|
43
|
+
## [0.2.0] - August 11, 2014
|
44
|
+
|
45
|
+
### Added
|
46
|
+
- Teach view generator to update existing views.
|
47
|
+
|
48
|
+
### Fixed
|
49
|
+
- Raise an error if view definition is empty.
|
50
|
+
|
51
|
+
[0.2.0]: https://github.com/thoughtbot/scenic/compare/v0.1.0...v0.2.0
|
52
|
+
|
53
|
+
## [0.1.0] - August 4, 2014
|
54
|
+
|
55
|
+
Scenic makes it easier to work with Postgres views in Rails.
|
56
|
+
|
57
|
+
It introduces view methods to ActiveRecord::Migration and allows views to be
|
58
|
+
dumped to db/schema.rb. It provides generators for models, view definitions,
|
59
|
+
and migrations. It is built around a basic versioning system for view
|
60
|
+
definition files.
|
61
|
+
|
62
|
+
In short, go add a view to your app.
|
9
63
|
|
10
|
-
|
11
|
-
* Teach view generator to update existing views [683361d](https://github.com/thoughtbot/scenic/commit/683361d59410f46aba508a3ceb850161dd0be027)
|
12
|
-
* Raise an error if view definition is empty. [PR #38](https://github.com/thoughtbot/scenic/issues/38)
|
64
|
+
[0.1.0]: https://github.com/thoughtbot/scenic/compare/8599daa132880cd6c07efb0395c0fb023b171f47...v0.1.0
|
data/README.md
CHANGED
@@ -1,27 +1,34 @@
|
|
1
1
|
# Scenic
|
2
2
|
|
3
|
-
|
3
|
+
Scenic adds methods to `ActiveRecord::Migration` to create and manage database
|
4
|
+
views in Rails.
|
4
5
|
|
5
|
-
|
6
|
-
|
7
|
-
|
6
|
+
Using Scenic, you can bring the power of SQL views to your Rails application
|
7
|
+
without having to switch your schema format to SQL. Scenic provides a convention
|
8
|
+
for versioning views that keeps your migration history consistent and reversible
|
9
|
+
and avoids having to duplicate SQL strings across migrations. As an added bonus,
|
10
|
+
you define the structure of your view in a SQL file, meaning you get full SQL
|
11
|
+
syntax highlighting in the editor of your choice and can easily test your SQL in
|
12
|
+
the database console during development.
|
8
13
|
|
9
|
-
|
14
|
+
Scenic ships with support for PostgreSQL. The adapter is configurable (see
|
15
|
+
`Scenic::Configuration`) and has a minimal interface (see
|
16
|
+
`Scenic::Adapters::Postgres`) that other gems can provide.
|
10
17
|
|
11
|
-
|
12
|
-
views in Rails.
|
18
|
+
## Great, how do I create a view?
|
13
19
|
|
14
|
-
|
15
|
-
|
16
|
-
|
17
|
-
an added bonus, you define the structure of your view in a SQL file, meaning you
|
18
|
-
get full SQL syntax highlighting support in the editor of your choice.
|
20
|
+
You've got this great idea for a view you'd like to call `searches`. You can
|
21
|
+
create the migration and the corresponding view definition file with the
|
22
|
+
following command:
|
19
23
|
|
20
|
-
|
24
|
+
```sh
|
25
|
+
$ rails generate scenic:view searches
|
26
|
+
create db/views/searches_v01.sql
|
27
|
+
create db/migrate/[TIMESTAMP]_create_searches.rb
|
28
|
+
```
|
21
29
|
|
22
|
-
|
23
|
-
|
24
|
-
like to build your view with. Perhaps that looks something like this:
|
30
|
+
Edit the `db/views/searches_v01.sql` file with the SQL statement that defines
|
31
|
+
your view. In our example, this might look something like this:
|
25
32
|
|
26
33
|
```sql
|
27
34
|
SELECT
|
@@ -40,34 +47,37 @@ SELECT
|
|
40
47
|
FROM statuses
|
41
48
|
```
|
42
49
|
|
43
|
-
|
50
|
+
The generated migration will contain a `create_view` statement. Run the
|
51
|
+
migration, and [baby, you got a view going][carl]. The migration is reversible
|
52
|
+
and the schema will be dumped into your `schema.rb` file.
|
44
53
|
|
45
|
-
|
46
|
-
def change
|
47
|
-
create_view :searches
|
48
|
-
end
|
49
|
-
```
|
54
|
+
[carl]: https://www.youtube.com/watch?v=Sr2PlqXw03Y
|
50
55
|
|
51
|
-
|
52
|
-
|
56
|
+
```sh
|
57
|
+
$ rake db:migrate
|
58
|
+
```
|
53
59
|
|
54
60
|
## Cool, but what if I need to change that view?
|
55
61
|
|
56
|
-
|
57
|
-
the following `change` method:
|
62
|
+
Here's where Scenic really shines. Run that same view generator once more:
|
58
63
|
|
59
|
-
```
|
60
|
-
|
61
|
-
|
62
|
-
|
64
|
+
```sh
|
65
|
+
$ rails generate scenic:view searches
|
66
|
+
create db/views/searches_v02.sql
|
67
|
+
create db/migrate/[TIMESTAMP]_update_searches_to_version_2.rb
|
63
68
|
```
|
64
69
|
|
65
|
-
|
66
|
-
|
70
|
+
Scenic detected that we already had an existing `searches` view at version 1,
|
71
|
+
created a copy of that definition as version 2, and created a migration to
|
72
|
+
update to the version 2 schema. All that's left for you to do is tweak the
|
73
|
+
schema in the new definition and run the `update_view` migration.
|
67
74
|
|
68
75
|
## Can I use this view to back a model?
|
69
76
|
|
70
|
-
You bet!
|
77
|
+
You bet! Using view-backed models can help promote concepts hidden in your
|
78
|
+
relational data to first-class domain objects and can clean up complex
|
79
|
+
ActiveRecord or ARel queries. As far as ActiveRecord is concerned, you a view is
|
80
|
+
no different than a table.
|
71
81
|
|
72
82
|
```ruby
|
73
83
|
class Search < ActiveRecord::Base
|
@@ -81,50 +91,76 @@ class Search < ActiveRecord::Base
|
|
81
91
|
end
|
82
92
|
```
|
83
93
|
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
94
|
+
Scenic even provides a `scenic:model` generator that is a superset of
|
95
|
+
`scenic:view`. It will act identically to the Rails `model` generator except
|
96
|
+
that it will create a Scenic view migration rather than a table migration.
|
97
|
+
|
98
|
+
There is no special base class or mixin needed. If desired, any code the model
|
99
|
+
generator adds can be removed without worry.
|
100
|
+
|
101
|
+
```sh
|
102
|
+
$ rails generate scenic:model recent_status
|
103
|
+
invoke active_record
|
104
|
+
create app/models/recent_status.rb
|
105
|
+
invoke test_unit
|
106
|
+
create test/models/recent_status_test.rb
|
107
|
+
create test/fixtures/recent_statuses.yml
|
108
|
+
create db/views/recent_statuses_v01.sql
|
109
|
+
create db/migrate/20151112015036_create_recent_statuses.rb
|
110
|
+
```
|
89
111
|
|
90
|
-
|
91
|
-
scratch. `db/views/[model]_v01.sql` wil be an empty file that you fill in only
|
92
|
-
the [query] portion of the view with.
|
112
|
+
### When I query that model with `find` I get an error. What gives?
|
93
113
|
|
94
|
-
|
114
|
+
Your view cannot have a primary key, but ActiveRecord's `find` method expects to
|
115
|
+
query based on one. You can use `find_by!` or you can explicitly set the primary
|
116
|
+
key column on your model like so:
|
95
117
|
|
118
|
+
```ruby
|
119
|
+
class People < ActiveRecord::Base
|
120
|
+
self.primary_key = :id
|
121
|
+
end
|
96
122
|
```
|
97
|
-
$ rails generate scenic:model search
|
98
|
-
create app/models/search.rb
|
99
|
-
create db/views/searches_v01.sql
|
100
|
-
create db/migrate/[TIMESTAMP]_create_searches.rb
|
101
|
-
```
|
102
|
-
|
103
|
-
### View generator
|
104
123
|
|
105
|
-
|
106
|
-
that it doesn't create the model. Convenient.
|
124
|
+
## What about materialized views?
|
107
125
|
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
create db/migrate/[TIMESTAMP]_create_searches.rb
|
112
|
-
```
|
126
|
+
Materialized views are essentially SQL queries whose results can be cached to a
|
127
|
+
table, indexed, and periodically refreshed when desired. Does Scenic support
|
128
|
+
those? Of course!
|
113
129
|
|
114
|
-
|
130
|
+
The `scenic:view` and `scenic:model` generators accept a `--materialized`
|
131
|
+
option for this purpose. When used with the model generator, your model will
|
132
|
+
have the following method defined as a convenience to aid in scheduling
|
133
|
+
refreshes:
|
115
134
|
|
116
|
-
```
|
117
|
-
|
118
|
-
|
119
|
-
|
135
|
+
```ruby
|
136
|
+
def self.refresh
|
137
|
+
Scenic.database.refresh_materialized_view(table_name)
|
138
|
+
end
|
120
139
|
```
|
121
140
|
|
122
141
|
## I don't need this view anymore. Make it go away.
|
123
142
|
|
124
|
-
|
143
|
+
Scenic gives you `drop_view` too:
|
125
144
|
|
126
145
|
```ruby
|
127
146
|
def change
|
128
147
|
drop_view :searches, revert_to_version: 2
|
129
148
|
end
|
130
149
|
```
|
150
|
+
|
151
|
+
## About
|
152
|
+
|
153
|
+
Scenic is maintained by [Derek Prior] and [Caleb Thompson], funded by
|
154
|
+
thoughtbot, inc. The names and logos for thoughtbot are trademarks of
|
155
|
+
thoughtbot, inc.
|
156
|
+
|
157
|
+
[Derek Prior]: http://prioritized.net
|
158
|
+
[Caleb Thompson]: http://calebthompson.io
|
159
|
+
|
160
|
+

|
161
|
+
|
162
|
+
We love open source software! See [our other projects][community] or [hire
|
163
|
+
us][hire] to help build your product.
|
164
|
+
|
165
|
+
[community]: https://thoughtbot.com/community?utm_source=github
|
166
|
+
[hire]: https://thoughtbot.com/hire-us?utm_source=github
|
data/Rakefile
CHANGED
data/bin/setup
ADDED
@@ -0,0 +1,11 @@
|
|
1
|
+
module Scenic
|
2
|
+
# Scenic provides generators for creating and updating views and ActiveRecord
|
3
|
+
# models that are backed by views.
|
4
|
+
#
|
5
|
+
# See:
|
6
|
+
# * {file:lib/generators/scenic/model/USAGE Model Generator}
|
7
|
+
# * {file:lib/generators/scenic/view/USAGE View Generator}
|
8
|
+
# * {file:README.md README}
|
9
|
+
module Generators
|
10
|
+
end
|
11
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Scenic
|
2
|
+
module Generators
|
3
|
+
# @api private
|
4
|
+
module Materializable
|
5
|
+
extend ActiveSupport::Concern
|
6
|
+
|
7
|
+
included do
|
8
|
+
class_option :materialized,
|
9
|
+
type: :boolean,
|
10
|
+
required: false,
|
11
|
+
desc: "Makes the view materialized",
|
12
|
+
default: false
|
13
|
+
end
|
14
|
+
|
15
|
+
private
|
16
|
+
|
17
|
+
def materialized?
|
18
|
+
options[:materialized]
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -1,19 +1,46 @@
|
|
1
1
|
require "rails/generators"
|
2
|
+
require "rails/generators/rails/model/model_generator"
|
2
3
|
require "generators/scenic/view/view_generator"
|
4
|
+
require "generators/scenic/materializable"
|
3
5
|
|
4
6
|
module Scenic
|
5
7
|
module Generators
|
8
|
+
# @api private
|
6
9
|
class ModelGenerator < Rails::Generators::NamedBase
|
10
|
+
include Scenic::Generators::Materializable
|
7
11
|
source_root File.expand_path("../templates", __FILE__)
|
8
12
|
|
9
|
-
|
13
|
+
def invoke_rails_model_generator
|
14
|
+
invoke "model", [name], options.merge(migration: false)
|
15
|
+
end
|
10
16
|
|
11
|
-
def
|
12
|
-
|
17
|
+
def inject_model_methods
|
18
|
+
if materialized? && generating?
|
19
|
+
inject_into_class "app/models/#{file_path}.rb", class_name do
|
20
|
+
evaluate_template("model.erb")
|
21
|
+
end
|
22
|
+
end
|
13
23
|
end
|
14
24
|
|
15
25
|
def invoke_view_generator
|
16
|
-
invoke "scenic:view", [
|
26
|
+
invoke "scenic:view", [table_name], options
|
27
|
+
end
|
28
|
+
|
29
|
+
private
|
30
|
+
|
31
|
+
def evaluate_template(source)
|
32
|
+
source = File.expand_path(find_in_source_paths(source.to_s))
|
33
|
+
context = instance_eval("binding")
|
34
|
+
ERB.new(
|
35
|
+
::File.binread(source),
|
36
|
+
nil,
|
37
|
+
"-",
|
38
|
+
"@output_buffer",
|
39
|
+
).result(context)
|
40
|
+
end
|
41
|
+
|
42
|
+
def generating?
|
43
|
+
behavior != :revoke
|
17
44
|
end
|
18
45
|
end
|
19
46
|
end
|