scenic 1.7.0 → 1.9.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/.github/workflows/ci.yml +29 -4
- data/.gitignore +1 -0
- data/CHANGELOG.md +55 -17
- data/CONTRIBUTING.md +1 -0
- data/FUNDING.yml +1 -0
- data/Gemfile +4 -4
- data/README.md +84 -25
- data/Rakefile +1 -1
- data/bin/standardrb +27 -0
- data/lib/generators/scenic/materializable.rb +27 -1
- data/lib/generators/scenic/model/model_generator.rb +7 -16
- data/lib/generators/scenic/model/templates/model.erb +4 -0
- data/lib/generators/scenic/view/templates/db/migrate/update_view.erb +2 -2
- data/lib/generators/scenic/view/view_generator.rb +5 -5
- data/lib/scenic/adapters/postgres/index_creation.rb +68 -0
- data/lib/scenic/adapters/postgres/index_migration.rb +70 -0
- data/lib/scenic/adapters/postgres/index_reapplication.rb +3 -28
- data/lib/scenic/adapters/postgres/indexes.rb +1 -1
- data/lib/scenic/adapters/postgres/refresh_dependencies.rb +3 -3
- data/lib/scenic/adapters/postgres/side_by_side.rb +50 -0
- data/lib/scenic/adapters/postgres/temporary_name.rb +34 -0
- data/lib/scenic/adapters/postgres/views.rb +85 -12
- data/lib/scenic/adapters/postgres.rb +64 -16
- data/lib/scenic/definition.rb +1 -1
- data/lib/scenic/schema_dumper.rb +0 -14
- data/lib/scenic/statements.rb +49 -16
- data/lib/scenic/version.rb +1 -1
- data/scenic.gemspec +15 -11
- data/spec/acceptance/user_manages_views_spec.rb +11 -0
- data/spec/dummy/Rakefile +5 -5
- data/spec/dummy/bin/bundle +2 -2
- data/spec/dummy/bin/rails +3 -3
- data/spec/dummy/bin/rake +2 -2
- data/spec/dummy/config/application.rb +4 -0
- data/spec/dummy/config.ru +1 -1
- data/spec/dummy/db/migrate/20220112154220_add_pg_stat_statements_extension.rb +1 -1
- data/spec/dummy/db/schema.rb +0 -2
- data/spec/generators/scenic/model/model_generator_spec.rb +9 -1
- data/spec/generators/scenic/view/view_generator_spec.rb +28 -2
- data/spec/integration/revert_spec.rb +1 -1
- data/spec/scenic/adapters/postgres/connection_spec.rb +1 -1
- data/spec/scenic/adapters/postgres/index_creation_spec.rb +54 -0
- data/spec/scenic/adapters/postgres/index_migration_spec.rb +24 -0
- data/spec/scenic/adapters/postgres/refresh_dependencies_spec.rb +9 -9
- data/spec/scenic/adapters/postgres/side_by_side_spec.rb +24 -0
- data/spec/scenic/adapters/postgres/temporary_name_spec.rb +23 -0
- data/spec/scenic/adapters/postgres_spec.rb +95 -8
- data/spec/scenic/command_recorder/statement_arguments_spec.rb +4 -4
- data/spec/scenic/command_recorder_spec.rb +30 -12
- data/spec/scenic/schema_dumper_spec.rb +35 -14
- data/spec/scenic/statements_spec.rb +66 -8
- data/spec/spec_helper.rb +19 -4
- data/spec/support/database_schema_helpers.rb +28 -0
- data/spec/support/generator_spec_setup.rb +2 -2
- data/spec/support/view_definition_helpers.rb +1 -1
- metadata +35 -48
- data/.hound.yml +0 -2
- data/.rubocop.yml +0 -129
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 772babaa9c177e3f24e45e0b61c7bed0475b5267806bea563d4a7ec1e97830c9
|
4
|
+
data.tar.gz: af0d81ab175baa0b0ac35d11216f76bb9d1663f3483fde733a862cff92067a01
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: ac9d6aa1abb1bea6d69d50de6aad86e0a567abd2b1631645b2f62d1bbd687b362e5af7ebe6fde7ad94fc6203a76df57fb3893a4f677b0def61740bc7af1f92a5
|
7
|
+
data.tar.gz: 59b77cb6f2b51334a3cefb6ef121a25354c7d202bef2c9898202da84d4a6b889898cc6d6b5bcd7e38b37b020501cff80628c843467d6d3a03dee6f309fb0a860
|
data/.github/workflows/ci.yml
CHANGED
@@ -7,15 +7,40 @@ on:
|
|
7
7
|
branches: "*"
|
8
8
|
|
9
9
|
jobs:
|
10
|
+
standard:
|
11
|
+
name: Lint with Standard
|
12
|
+
runs-on: ubuntu-latest
|
13
|
+
|
14
|
+
steps:
|
15
|
+
- name: Checkout
|
16
|
+
uses: actions/checkout@v4
|
17
|
+
|
18
|
+
- name: Run standardrb
|
19
|
+
uses: standardrb/standard-ruby-action@f533e61f461ccb766b2d9c235abf59be02aea793
|
20
|
+
env:
|
21
|
+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
22
|
+
|
23
|
+
permissions:
|
24
|
+
checks: write
|
25
|
+
contents: read
|
26
|
+
|
10
27
|
build:
|
11
28
|
name: Ruby ${{ matrix.ruby }}, Rails ${{ matrix.rails }}
|
29
|
+
continue-on-error: ${{ matrix.continue-on-error }}
|
12
30
|
|
13
31
|
strategy:
|
14
32
|
fail-fast: false
|
15
33
|
matrix:
|
16
|
-
ruby: ["
|
17
|
-
rails: ["
|
34
|
+
ruby: ["3.4", "3.3"]
|
35
|
+
rails: ["8.0", "7.2"]
|
18
36
|
continue-on-error: [false]
|
37
|
+
include:
|
38
|
+
- ruby: "3.4"
|
39
|
+
rails: "main"
|
40
|
+
continue-on-error: true
|
41
|
+
- ruby: "head"
|
42
|
+
rails: "main"
|
43
|
+
continue-on-error: true
|
19
44
|
|
20
45
|
runs-on: ubuntu-latest
|
21
46
|
|
@@ -40,7 +65,7 @@ jobs:
|
|
40
65
|
|
41
66
|
steps:
|
42
67
|
- name: Checkout
|
43
|
-
uses: actions/checkout@
|
68
|
+
uses: actions/checkout@v4
|
44
69
|
|
45
70
|
- name: Install Ruby ${{ matrix.ruby }}
|
46
71
|
uses: ruby/setup-ruby@v1
|
@@ -54,7 +79,7 @@ jobs:
|
|
54
79
|
run: bundle lock
|
55
80
|
|
56
81
|
- name: Cache dependencies
|
57
|
-
uses: actions/cache@
|
82
|
+
uses: actions/cache@v4
|
58
83
|
with:
|
59
84
|
path: vendor/bundle
|
60
85
|
key: bundle-${{ hashFiles('Gemfile.lock') }}
|
data/.gitignore
CHANGED
data/CHANGELOG.md
CHANGED
@@ -5,19 +5,44 @@ changelog, see the [commits] for each version via the version links.
|
|
5
5
|
|
6
6
|
[commits]: https://github.com/scenic-views/scenic/commits/master
|
7
7
|
|
8
|
+
## [1.9.0] - June 30, 2025
|
9
|
+
|
10
|
+
[1.9.0]: https://github.com/scenic-views/scenic/compare/v1.8.0...v1.9.0
|
11
|
+
|
12
|
+
### Added
|
13
|
+
|
14
|
+
- Added topological sorting of views when dumping schema. This should limit
|
15
|
+
unrelated changes to schema.rb once the views are sorted the first time.
|
16
|
+
- Added `side_by_side` mode to materialized view updates. This creates the
|
17
|
+
updated materialized view with a temporary name before swapping it with the
|
18
|
+
live view, minimizing the time the view is locked for updating.
|
19
|
+
|
20
|
+
### Fixed
|
21
|
+
|
22
|
+
- Only refresh concurrently if the materialized view is populated.
|
23
|
+
|
24
|
+
## [1.8.0] - March 28, 2024
|
25
|
+
|
26
|
+
[1.8.0]: https://github.com/scenic-views/scenic/compare/v1.7.0...v1.8.0
|
27
|
+
|
28
|
+
### Added
|
29
|
+
|
30
|
+
- Added `#populated?` to check the state of materialized views - _Daisuke
|
31
|
+
Fujimura_, _Dr Nic Williams_
|
32
|
+
|
8
33
|
## [1.7.0] - December 8, 2022
|
9
34
|
|
10
35
|
[1.7.0]: https://github.com/scenic-views/scenic/compare/v1.6.0...v1.7.0
|
11
36
|
|
12
37
|
### Added
|
13
38
|
|
14
|
-
|
15
|
-
`replace_view` schema statement -
|
39
|
+
- Added the `--replace` CLI flag to generate a migration that uses the
|
40
|
+
`replace_view` schema statement - _Dan Hixon_
|
16
41
|
|
17
42
|
### Fixed
|
18
43
|
|
19
|
-
|
20
|
-
generators -
|
44
|
+
- Fixed deprecation notice from newer versions of ERB when using scenic
|
45
|
+
generators - _Ali Ismayilov_
|
21
46
|
|
22
47
|
## [1.6.0] - February 13, 2022
|
23
48
|
|
@@ -25,9 +50,9 @@ changelog, see the [commits] for each version via the version links.
|
|
25
50
|
|
26
51
|
### Fixed
|
27
52
|
|
28
|
-
|
29
|
-
|
30
|
-
|
53
|
+
- Exclude pg*stat_statements_info (#349) 76bface - \_Caleb Hearth*
|
54
|
+
- Fix serialization of views with backslashes c625d1b - _Ben Sheldon_
|
55
|
+
- Handle ActiveRecord table name prefix and suffix b1544dc - _Derek Prior_
|
31
56
|
|
32
57
|
## [1.5.5] - December 15, 2021
|
33
58
|
|
@@ -100,7 +125,6 @@ changelog, see the [commits] for each version via the version links.
|
|
100
125
|
- Fixed a cascading refresh issue when the name of the view to trigger the
|
101
126
|
refresh is a substring of one of its dependencies.
|
102
127
|
|
103
|
-
|
104
128
|
[1.5.0]: https://github.com/scenic-views/scenic/compare/v1.4.1...v1.5.0
|
105
129
|
|
106
130
|
## [1.4.1] - December 15, 2017
|
@@ -135,26 +159,30 @@ changelog, see the [commits] for each version via the version links.
|
|
135
159
|
## [1.3.0] - May 27, 2016
|
136
160
|
|
137
161
|
### Added
|
162
|
+
|
138
163
|
- Add `replace_view` migration statement, which issues `CREATE OR REPLACE
|
139
|
-
|
164
|
+
VIEW` rather than `CREATE VIEW` or `DROP VIEW` and `CREATE VIEW`.
|
140
165
|
- Schema-qualify views outside the 'public' namespace, such as
|
141
166
|
`scenic.searches`
|
142
167
|
|
143
168
|
### Fixed
|
144
|
-
|
169
|
+
|
170
|
+
- Singularize generated model name when injecting into class.
|
145
171
|
Previously, pluralized names would issue a warning and Scenic would
|
146
172
|
attempt to insert model code into the pluralized model file.
|
147
|
-
|
173
|
+
- Convert shell-based smoke tests to RSpec syntax.
|
148
174
|
|
149
175
|
[1.3.0]: https://github.com/scenic-views/scenic/compare/v1.2.0...v1.3.0
|
150
176
|
|
151
177
|
## [1.2.0] - February 5, 2016
|
152
178
|
|
153
179
|
### Added
|
180
|
+
|
154
181
|
- The generators now accept namespaced view definitions. For example: `rails
|
155
|
-
|
182
|
+
generate scenic:view my_app.users`.
|
156
183
|
|
157
184
|
### Fixed
|
185
|
+
|
158
186
|
- Materialized view indexes are now properly dumped to `db/schema.rb`. This was
|
159
187
|
an oversight in previous releases, meaning `rake db:schema:load` was missing
|
160
188
|
indexes.
|
@@ -163,7 +191,7 @@ changelog, see the [commits] for each version via the version links.
|
|
163
191
|
returning no indexes.
|
164
192
|
|
165
193
|
**Note**: Dumping materialized view indexes will produce an invalid
|
166
|
-
`db/schema.rb` file
|
194
|
+
`db/schema.rb` file under Rails 5 beta 1 and beta 2. This is fixed on Rails
|
167
195
|
master.
|
168
196
|
|
169
197
|
[1.2.0]: https://github.com/scenic-views/scenic/compare/v1.1.1...v1.2.0
|
@@ -171,8 +199,9 @@ master.
|
|
171
199
|
## [1.1.1] - January 29, 2016
|
172
200
|
|
173
201
|
### Fixed
|
202
|
+
|
174
203
|
- Some schema operations were failing with a `PG::ConnectionBad: connection is
|
175
|
-
|
204
|
+
closed` error. This has been fixed by ensuring we grab a fresh connection for
|
176
205
|
all operations.
|
177
206
|
|
178
207
|
[1.1.1]: https://github.com/scenic-views/scenic/compare/v1.1.0...v1.1.1
|
@@ -180,12 +209,14 @@ master.
|
|
180
209
|
## [1.1.0] - January 8, 2016
|
181
210
|
|
182
211
|
### Added
|
212
|
+
|
183
213
|
- Added support for updating materialized view definitions while maintaining
|
184
214
|
existing indexes that are still applicable after the update.
|
185
215
|
- Added support for refreshing materialized views concurrently (requires
|
186
216
|
Postgres 9.4 or newer).
|
187
217
|
|
188
218
|
### Fixed
|
219
|
+
|
189
220
|
- The schema dumper will now dump views and materialized views together in the
|
190
221
|
order they are returned by Postgres. This fixes issues when loading views that
|
191
222
|
depend on other views via `rake db:schema:load`.
|
@@ -200,26 +231,30 @@ master.
|
|
200
231
|
## [1.0.0] - November 23, 2015
|
201
232
|
|
202
233
|
### Added
|
234
|
+
|
203
235
|
- Added support for [materialized views].
|
204
236
|
- Allow changing the database adapter via `Scenic::Configuration`.
|
205
237
|
|
206
238
|
### Fixed
|
239
|
+
|
207
240
|
- Improved formatting of the view when dumped to `schema.rb`.
|
208
241
|
- Fixed generation of namespaced models by using ActiveRecord's own model
|
209
242
|
generator.
|
210
243
|
- Eliminated `alias_method_chain` deprecation when running with Rails master
|
211
244
|
(5.0).
|
212
245
|
|
213
|
-
[materialized views]:https://github.com/scenic-views/scenic/blob/v1.0.0/README.md
|
246
|
+
[materialized views]: https://github.com/scenic-views/scenic/blob/v1.0.0/README.md
|
214
247
|
[1.0.0]: https://github.com/scenic-views/scenic/compare/v0.3.0...v1.0.0
|
215
248
|
|
216
249
|
## [0.3.0] - January 23, 2015
|
217
250
|
|
218
251
|
### Added
|
252
|
+
|
219
253
|
- Previous view definition is copied into new view definition file when updating
|
220
254
|
an existing view.
|
221
255
|
|
222
256
|
### Fixed
|
257
|
+
|
223
258
|
- We avoid dumping views that belong to Postgres extensions.
|
224
259
|
- `db/schema.rb` is prettier thanks to a blank line after each view definition.
|
225
260
|
|
@@ -228,6 +263,7 @@ master.
|
|
228
263
|
## [0.2.1] - January 5, 2015
|
229
264
|
|
230
265
|
### Fixed
|
266
|
+
|
231
267
|
- View generator will now create `db/views` directory if necessary.
|
232
268
|
|
233
269
|
[0.2.1]: https://github.com/scenic-views/scenic/compare/v0.2.0...v0.2.1
|
@@ -235,9 +271,11 @@ master.
|
|
235
271
|
## [0.2.0] - August 11, 2014
|
236
272
|
|
237
273
|
### Added
|
274
|
+
|
238
275
|
- Teach view generator to update existing views.
|
239
276
|
|
240
277
|
### Fixed
|
278
|
+
|
241
279
|
- Raise an error if view definition is empty.
|
242
280
|
|
243
281
|
[0.2.0]: https://github.com/scenic-views/scenic/compare/v0.1.0...v0.2.0
|
@@ -247,8 +285,8 @@ master.
|
|
247
285
|
Scenic makes it easier to work with Postgres views in Rails.
|
248
286
|
|
249
287
|
It introduces view methods to ActiveRecord::Migration and allows views to be
|
250
|
-
dumped to db/schema.rb.
|
251
|
-
and migrations.
|
288
|
+
dumped to db/schema.rb. It provides generators for models, view definitions,
|
289
|
+
and migrations. It is built around a basic versioning system for view
|
252
290
|
definition files.
|
253
291
|
|
254
292
|
In short, go add a view to your app.
|
data/CONTRIBUTING.md
CHANGED
@@ -13,6 +13,7 @@ agree to abide by our [code of conduct].
|
|
13
13
|
3. Run `rake` to verify that the tests pass against the version of Rails you are
|
14
14
|
running locally.
|
15
15
|
4. Make your change with new passing tests, following existing style.
|
16
|
+
5. Run `standardrb --fix` to ensure your code is formatted correctly.
|
16
17
|
5. Write a [good commit message], push your fork, and submit a pull request.
|
17
18
|
6. CI will run the test suite on all configured versions of Ruby and Rails.
|
18
19
|
Address any failures.
|
data/FUNDING.yml
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
github: [calebhearth, derekprior]
|
data/Gemfile
CHANGED
@@ -3,12 +3,12 @@ source "https://rubygems.org"
|
|
3
3
|
# Specify your gem's dependencies in scenic.gemspec
|
4
4
|
gemspec
|
5
5
|
|
6
|
-
rails_version = ENV.fetch("RAILS_VERSION", "
|
6
|
+
rails_version = ENV.fetch("RAILS_VERSION", "8.0")
|
7
7
|
|
8
|
-
if rails_version == "
|
9
|
-
|
8
|
+
rails_constraint = if rails_version == "main"
|
9
|
+
{github: "rails/rails"}
|
10
10
|
else
|
11
|
-
|
11
|
+
"~> #{rails_version}.0"
|
12
12
|
end
|
13
13
|
|
14
14
|
gem "rails", rails_constraint
|
data/README.md
CHANGED
@@ -4,7 +4,6 @@
|
|
4
4
|
|
5
5
|
[](https://github.com/scenic-views/scenic/actions/workflows/ci.yml)
|
6
6
|
[](http://inch-ci.org/github/scenic-views/scenic)
|
7
|
-
[](https://houndci.com)
|
8
7
|
|
9
8
|
Scenic adds methods to `ActiveRecord::Migration` to create and manage database
|
10
9
|
views in Rails.
|
@@ -25,7 +24,7 @@ Scenic ships with support for PostgreSQL. The adapter is configurable (see
|
|
25
24
|
|
26
25
|
If you're using Postgres, Add `gem "scenic"` to your Gemfile and run `bundle
|
27
26
|
install`. If you're using something other than Postgres, check out the available
|
28
|
-
[third
|
27
|
+
[third-party adapters](https://github.com/scenic-views/scenic#when-will-you-support-mysql-sqlite-or-other-databases).
|
29
28
|
|
30
29
|
## Great, how do I create a view?
|
31
30
|
|
@@ -86,14 +85,17 @@ schema in the new definition and run the `update_view` migration.
|
|
86
85
|
|
87
86
|
## What if I want to change a view without dropping it?
|
88
87
|
|
89
|
-
The `update_view` statement used by default will drop your view then create
|
90
|
-
|
88
|
+
The `update_view` statement used by default will drop your view then create a
|
89
|
+
new version of it. This may not be desirable when you have complicated
|
90
|
+
hierarchies of dependent views.
|
91
91
|
|
92
|
-
|
93
|
-
|
92
|
+
Scenic offers a `replace_view` schema statement, resulting in a `CREATE OR
|
93
|
+
REPLACE VIEW` SQL query which will update the supplied view in place, retaining
|
94
|
+
all dependencies. Materialized views cannot be replaced in this fashion, though
|
95
|
+
the `side_by_side` update strategy may yield similar results (see below).
|
94
96
|
|
95
|
-
You can
|
96
|
-
|
97
|
+
You can generate a migration that uses the `replace_view` schema statement by
|
98
|
+
passing the `--replace` option to the `scenic:view` generator:
|
97
99
|
|
98
100
|
```sh
|
99
101
|
$ rails generate scenic:view search_results --replace
|
@@ -101,9 +103,6 @@ $ rails generate scenic:view search_results --replace
|
|
101
103
|
create db/migrate/[TIMESTAMP]_update_search_results_to_version_2.rb
|
102
104
|
```
|
103
105
|
|
104
|
-
See Postgres documentation on how this works:
|
105
|
-
http://www.postgresql.org/docs/current/static/sql-createview.html
|
106
|
-
|
107
106
|
The migration will look something like this:
|
108
107
|
|
109
108
|
```ruby
|
@@ -114,8 +113,6 @@ class UpdateSearchResultsToVersion2 < ActiveRecord::Migration
|
|
114
113
|
end
|
115
114
|
```
|
116
115
|
|
117
|
-
You can run the migration and the view will be replaced instead.
|
118
|
-
|
119
116
|
## Can I use this view to back a model?
|
120
117
|
|
121
118
|
You bet! Using view-backed models can help promote concepts hidden in your
|
@@ -127,6 +124,11 @@ no different than a table.
|
|
127
124
|
class SearchResult < ApplicationRecord
|
128
125
|
belongs_to :searchable, polymorphic: true
|
129
126
|
|
127
|
+
# If you want to be able to call +Model.find+, you
|
128
|
+
# must declare the primary key. It can not be
|
129
|
+
# inferred from column information.
|
130
|
+
# self.primary_key = :id
|
131
|
+
|
130
132
|
# this isn't strictly necessary, but it will prevent
|
131
133
|
# rails from calling save, which would fail anyway.
|
132
134
|
def readonly?
|
@@ -136,7 +138,7 @@ end
|
|
136
138
|
```
|
137
139
|
|
138
140
|
Scenic even provides a `scenic:model` generator that is a superset of
|
139
|
-
`scenic:view`.
|
141
|
+
`scenic:view`. It will act identically to the Rails `model` generator except
|
140
142
|
that it will create a Scenic view migration rather than a table migration.
|
141
143
|
|
142
144
|
There is no special base class or mixin needed. If desired, any code the model
|
@@ -184,6 +186,44 @@ you would need to refresh view B first, then right after refresh view A. If you
|
|
184
186
|
would like this cascading refresh of materialized views, set `cascade: true`
|
185
187
|
when you refresh your materialized view.
|
186
188
|
|
189
|
+
## Can I update the definition of a materialized view without dropping it?
|
190
|
+
|
191
|
+
No, but Scenic can help you approximate this behavior with its `side_by_side`
|
192
|
+
update strategy.
|
193
|
+
|
194
|
+
Generally, changing the definition of a materialized view requires dropping it
|
195
|
+
and recreating it, either without data or with a non-concurrent refresh. The
|
196
|
+
materialized view will be locked for selects during the refresh process, which
|
197
|
+
can cause problems in your application if the refresh is not fast.
|
198
|
+
|
199
|
+
The `side_by_side` update strategy prepares the new version of the view under a
|
200
|
+
temporary name. This includes copying the indexes from the original view and
|
201
|
+
refreshing the data. Once prepared, the original view is dropped and the new
|
202
|
+
view is renamed to the original view's name. This process minimizes the time the
|
203
|
+
view is locked for selects at the cost of additional disk space.
|
204
|
+
|
205
|
+
You can generate a migration that uses the `side_by_side` strategy by passing
|
206
|
+
the `--side-by-side` option to the `scenic:view` generator:
|
207
|
+
|
208
|
+
```sh
|
209
|
+
$ rails generate scenic:view search_results --materialized --side-by-side
|
210
|
+
create db/views/search_results_v02.sql
|
211
|
+
create db/migrate/[TIMESTAMP]_update_search_results_to_version_2.rb
|
212
|
+
```
|
213
|
+
|
214
|
+
The migration will look something like this:
|
215
|
+
|
216
|
+
```ruby
|
217
|
+
class UpdateSearchResultsToVersion2 < ActiveRecord::Migration
|
218
|
+
def change
|
219
|
+
update_view :search_results,
|
220
|
+
version: 2,
|
221
|
+
revert_to_version: 1,
|
222
|
+
materialized: { side_by_side: true }
|
223
|
+
end
|
224
|
+
end
|
225
|
+
```
|
226
|
+
|
187
227
|
## I don't need this view anymore. Make it go away.
|
188
228
|
|
189
229
|
Scenic gives you `drop_view` too:
|
@@ -197,7 +237,7 @@ end
|
|
197
237
|
|
198
238
|
## FAQs
|
199
239
|
|
200
|
-
|
240
|
+
### Why do I get an error when querying a view-backed model with `find`, `last`, or `first`?
|
201
241
|
|
202
242
|
ActiveRecord's `find` method expects to query based on your model's primary key,
|
203
243
|
but views do not have primary keys. Additionally, the `first` and `last` methods
|
@@ -212,7 +252,7 @@ class People < ApplicationRecord
|
|
212
252
|
end
|
213
253
|
```
|
214
254
|
|
215
|
-
|
255
|
+
### Why is my view missing columns from the underlying table?
|
216
256
|
|
217
257
|
Did you create the view with `SELECT [table_name].*`? Most (possibly all)
|
218
258
|
relational databases freeze the view definition at the time of creation. New
|
@@ -225,7 +265,7 @@ add_column :posts, :title, :string
|
|
225
265
|
update_view :posts_with_aggregate_data, version: 2, revert_to_version: 2
|
226
266
|
```
|
227
267
|
|
228
|
-
|
268
|
+
### When will you support MySQL, SQLite, or other databases?
|
229
269
|
|
230
270
|
We have no plans to add first-party adapters for other relational databases at
|
231
271
|
this time because we (the maintainers) do not currently have a use for them.
|
@@ -233,7 +273,7 @@ It's our experience that maintaining a library effectively requires regular use
|
|
233
273
|
of its features. We're not in a good position to support MySQL, SQLite or other
|
234
274
|
database users.
|
235
275
|
|
236
|
-
Scenic
|
276
|
+
Scenic _does_ support configuring different database adapters and should be
|
237
277
|
extendable with adapter libraries. If you implement such an adapter, we're happy
|
238
278
|
to review and link to it. We're also happy to make changes that would better
|
239
279
|
accommodate adapter gems.
|
@@ -241,20 +281,39 @@ accommodate adapter gems.
|
|
241
281
|
We are aware of the following existing adapter libraries for Scenic which may
|
242
282
|
meet your needs:
|
243
283
|
|
244
|
-
|
245
|
-
|
246
|
-
|
247
|
-
|
284
|
+
- [`scenic_sqlite_adapter`](https://github.com/pdebelak/scenic_sqlite_adapter)
|
285
|
+
- [`scenic-mysql_adapter`](https://github.com/cainlevy/scenic-mysql_adapter)
|
286
|
+
- [`scenic-sqlserver-adapter`](https://github.com/ClickMechanic/scenic_sqlserver_adapter)
|
287
|
+
- [`scenic-oracle_adapter`](https://github.com/cdinger/scenic-oracle_adapter)
|
248
288
|
|
249
289
|
Please note that the maintainers of Scenic make no assertions about the
|
250
290
|
quality or security of the above adapters.
|
251
291
|
|
252
292
|
## About
|
253
293
|
|
294
|
+
### Used By
|
295
|
+
|
254
296
|
Scenic is used by some popular open source Rails apps:
|
255
|
-
[Mastodon](
|
256
|
-
[Code.org](
|
257
|
-
[Lobste.rs](
|
297
|
+
[Mastodon](https://github.com/mastodon/mastodon/),
|
298
|
+
[Code.org](https://github.com/code-dot-org/code-dot-org), and
|
299
|
+
[Lobste.rs](https://github.com/lobsters/lobsters/).
|
300
|
+
|
301
|
+
### Related projects
|
302
|
+
|
303
|
+
- [`fx`](https://github.com/teoljungberg/fx) Versioned database functions and
|
304
|
+
triggers for Rails
|
305
|
+
|
306
|
+
### Media
|
307
|
+
|
308
|
+
Here are a few posts we've seen discussing Scenic:
|
309
|
+
|
310
|
+
- [Announcing Scenic - Versioned Database Views for Rails](https://thoughtbot.com/blog/announcing-scenic--versioned-database-views-for-rails) by Derek Prior for thoughtbot
|
311
|
+
- [Effectively Using Materialized Views in Ruby on Rails](https://pganalyze.com/blog/materialized-views-ruby-rails) by Leigh Halliday for pganalyze
|
312
|
+
- [Optimizing String Concatenation in Ruby on Rails](https://dev.to/pimp_my_ruby/from-slow-to-lightning-fast-optimizing-string-concatenation-in-ruby-on-rails-28nk)
|
313
|
+
- [Materialized Views In Ruby On Rails With Scenic](https://www.ideamotive.co/blog/materialized-views-ruby-rails-scenic) by Dawid Karczewski for Ideamotive
|
314
|
+
- [Using Scenic and SQL views to aggregate data](https://dev.to/weareredlight/using-scenic-and-sql-views-to-aggregate-data-226k) by André Perdigão for Redlight Software
|
315
|
+
|
316
|
+
### Maintainers
|
258
317
|
|
259
318
|
Scenic is maintained by [Derek Prior], [Caleb Hearth], and you, our
|
260
319
|
contributors.
|
data/Rakefile
CHANGED
data/bin/standardrb
ADDED
@@ -0,0 +1,27 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
#
|
5
|
+
# This file was generated by Bundler.
|
6
|
+
#
|
7
|
+
# The application 'standardrb' is installed as part of a gem, and
|
8
|
+
# this file is here to facilitate running it.
|
9
|
+
#
|
10
|
+
|
11
|
+
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../Gemfile", __dir__)
|
12
|
+
|
13
|
+
bundle_binstub = File.expand_path("bundle", __dir__)
|
14
|
+
|
15
|
+
if File.file?(bundle_binstub)
|
16
|
+
if File.read(bundle_binstub, 300).include?("This file was generated by Bundler")
|
17
|
+
load(bundle_binstub)
|
18
|
+
else
|
19
|
+
abort("Your `bin/bundle` was not generated by Bundler, so this binstub cannot run.
|
20
|
+
Replace `bin/bundle` by running `bundle binstubs bundler --force`, then run this command again.")
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
require "rubygems"
|
25
|
+
require "bundler/setup"
|
26
|
+
|
27
|
+
load Gem.bin_path("standard", "standardrb")
|
@@ -14,7 +14,14 @@ module Scenic
|
|
14
14
|
type: :boolean,
|
15
15
|
required: false,
|
16
16
|
desc: "Adds WITH NO DATA when materialized view creates/updates",
|
17
|
-
default: false
|
17
|
+
default: false,
|
18
|
+
aliases: ["--no-data"]
|
19
|
+
class_option :side_by_side,
|
20
|
+
type: :boolean,
|
21
|
+
required: false,
|
22
|
+
desc: "Uses side-by-side strategy to update materialized view",
|
23
|
+
default: false,
|
24
|
+
aliases: ["--side-by-side"]
|
18
25
|
class_option :replace,
|
19
26
|
type: :boolean,
|
20
27
|
required: false,
|
@@ -35,6 +42,25 @@ module Scenic
|
|
35
42
|
def no_data?
|
36
43
|
options[:no_data]
|
37
44
|
end
|
45
|
+
|
46
|
+
def side_by_side?
|
47
|
+
options[:side_by_side]
|
48
|
+
end
|
49
|
+
|
50
|
+
def materialized_view_update_options
|
51
|
+
set_options = {no_data: no_data?, side_by_side: side_by_side?}
|
52
|
+
.select { |_, v| v }
|
53
|
+
|
54
|
+
if set_options.empty?
|
55
|
+
"true"
|
56
|
+
else
|
57
|
+
string_options = set_options.reduce("") do |memo, (key, value)|
|
58
|
+
memo + "#{key}: #{value}, "
|
59
|
+
end
|
60
|
+
|
61
|
+
"{ #{string_options.chomp(", ")} }"
|
62
|
+
end
|
63
|
+
end
|
38
64
|
end
|
39
65
|
end
|
40
66
|
end
|
@@ -15,7 +15,7 @@ module Scenic
|
|
15
15
|
[file_path.singularize],
|
16
16
|
options.merge(
|
17
17
|
fixture_replacement: false,
|
18
|
-
migration: false
|
18
|
+
migration: false
|
19
19
|
)
|
20
20
|
end
|
21
21
|
|
@@ -34,23 +34,14 @@ module Scenic
|
|
34
34
|
private
|
35
35
|
|
36
36
|
def evaluate_template(source)
|
37
|
-
source
|
37
|
+
source = File.expand_path(find_in_source_paths(source.to_s))
|
38
38
|
context = instance_eval("binding", __FILE__, __LINE__)
|
39
39
|
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
)
|
46
|
-
else
|
47
|
-
erb = ERB.new(
|
48
|
-
::File.binread(source),
|
49
|
-
nil,
|
50
|
-
"-",
|
51
|
-
"@output_buffer",
|
52
|
-
)
|
53
|
-
end
|
40
|
+
erb = ERB.new(
|
41
|
+
::File.binread(source),
|
42
|
+
trim_mode: "-",
|
43
|
+
eoutvar: "@output_buffer"
|
44
|
+
)
|
54
45
|
|
55
46
|
erb.result(context)
|
56
47
|
end
|
@@ -1,11 +1,11 @@
|
|
1
1
|
class <%= migration_class_name %> < <%= activerecord_migration_class %>
|
2
2
|
def change
|
3
|
-
|
3
|
+
<%- method_name = replace_view? ? 'replace_view' : 'update_view' -%>
|
4
4
|
<%- if materialized? -%>
|
5
5
|
<%= method_name %> <%= formatted_plural_name %>,
|
6
6
|
version: <%= version %>,
|
7
7
|
revert_to_version: <%= previous_version %>,
|
8
|
-
materialized: <%=
|
8
|
+
materialized: <%= materialized_view_update_options %>
|
9
9
|
<%- else -%>
|
10
10
|
<%= method_name %> <%= formatted_plural_name %>, version: <%= version %>, revert_to_version: <%= previous_version %>
|
11
11
|
<%- end -%>
|