scenic 1.6.0 → 1.8.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 +24 -4
- data/CHANGELOG.md +25 -8
- data/CONTRIBUTING.md +1 -0
- data/Gemfile +3 -3
- data/README.md +29 -29
- data/Rakefile +1 -1
- data/bin/standardrb +27 -0
- data/lib/generators/scenic/materializable.rb +9 -0
- data/lib/generators/scenic/model/model_generator.rb +9 -7
- data/lib/generators/scenic/model/templates/model.erb +4 -0
- data/lib/generators/scenic/view/templates/db/migrate/update_view.erb +3 -2
- data/lib/generators/scenic/view/view_generator.rb +5 -5
- data/lib/scenic/adapters/postgres/indexes.rb +1 -1
- data/lib/scenic/adapters/postgres/refresh_dependencies.rb +3 -3
- data/lib/scenic/adapters/postgres/views.rb +5 -5
- data/lib/scenic/adapters/postgres.rb +28 -3
- data/lib/scenic/definition.rb +1 -1
- data/lib/scenic/statements.rb +5 -5
- data/lib/scenic/version.rb +1 -1
- data/lib/scenic/view.rb +1 -1
- data/scenic.gemspec +10 -10
- 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.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 +13 -1
- data/spec/integration/revert_spec.rb +1 -1
- data/spec/scenic/adapters/postgres/connection_spec.rb +1 -1
- data/spec/scenic/adapters/postgres/refresh_dependencies_spec.rb +9 -9
- data/spec/scenic/adapters/postgres_spec.rb +52 -6
- data/spec/scenic/command_recorder/statement_arguments_spec.rb +4 -4
- data/spec/scenic/command_recorder_spec.rb +12 -12
- data/spec/scenic/schema_dumper_spec.rb +6 -6
- data/spec/scenic/statements_spec.rb +4 -4
- data/spec/support/generator_spec_setup.rb +2 -2
- data/spec/support/view_definition_helpers.rb +1 -1
- metadata +19 -40
- 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: a9085d1f24783682a52d5874ce82bf44543b2a60d6edbfd72b026bf84b4bc0ab
         | 
| 4 | 
            +
              data.tar.gz: fd7efd82eb88c0550c410f50e363db99eaf3e7fc6b5e3ac4eb374bd681afd7cd
         | 
| 5 5 | 
             
            SHA512:
         | 
| 6 | 
            -
              metadata.gz:  | 
| 7 | 
            -
              data.tar.gz:  | 
| 6 | 
            +
              metadata.gz: d0c624619ae62c1c9e8186b8cde870e81dde6f47c8eacc93faad863c38d8fc57c3f15b81c0f1a515bad57318d2bef56f8a57b83934346542e4fbe9bbc6315209
         | 
| 7 | 
            +
              data.tar.gz: 6a4e9ae269ee6ffb86a4e23fa1d0e741ee2b3ed12fabca23696d2d462c4359d9fceea53ffbf696f72357bfa10a4abf66ede72b1bfa1a37ce7fcf5fdc5f6aeca7
         | 
    
        data/.github/workflows/ci.yml
    CHANGED
    
    | @@ -7,15 +7,35 @@ 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@v3
         | 
| 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 }}
         | 
| 12 29 |  | 
| 13 30 | 
             
                strategy:
         | 
| 14 31 | 
             
                  fail-fast: false
         | 
| 15 32 | 
             
                  matrix:
         | 
| 16 | 
            -
                    ruby: ["2.7", "3.0", "3.1"]
         | 
| 17 | 
            -
                    rails: ["6.1", "7.0" | 
| 33 | 
            +
                    ruby: ["2.7", "3.0", "3.1", "3.2"]
         | 
| 34 | 
            +
                    rails: ["6.1", "7.0"]
         | 
| 18 35 | 
             
                    continue-on-error: [false]
         | 
| 36 | 
            +
                    exclude:
         | 
| 37 | 
            +
                      - ruby: "3.2"
         | 
| 38 | 
            +
                        rails: "6.1"
         | 
| 19 39 |  | 
| 20 40 | 
             
                runs-on: ubuntu-latest
         | 
| 21 41 |  | 
| @@ -40,7 +60,7 @@ jobs: | |
| 40 60 |  | 
| 41 61 | 
             
                steps:
         | 
| 42 62 | 
             
                  - name: Checkout
         | 
| 43 | 
            -
                    uses: actions/checkout@ | 
| 63 | 
            +
                    uses: actions/checkout@v3
         | 
| 44 64 |  | 
| 45 65 | 
             
                  - name: Install Ruby ${{ matrix.ruby }}
         | 
| 46 66 | 
             
                    uses: ruby/setup-ruby@v1
         | 
| @@ -54,7 +74,7 @@ jobs: | |
| 54 74 | 
             
                    run: bundle lock
         | 
| 55 75 |  | 
| 56 76 | 
             
                  - name: Cache dependencies
         | 
| 57 | 
            -
                    uses: actions/cache@ | 
| 77 | 
            +
                    uses: actions/cache@v3
         | 
| 58 78 | 
             
                    with:
         | 
| 59 79 | 
             
                      path: vendor/bundle
         | 
| 60 80 | 
             
                      key: bundle-${{ hashFiles('Gemfile.lock') }}
         | 
    
        data/CHANGELOG.md
    CHANGED
    
    | @@ -5,21 +5,38 @@ 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. | 
| 8 | 
            +
            ## [1.8.0] - March 28, 2024
         | 
| 9 9 |  | 
| 10 | 
            -
             | 
| 10 | 
            +
            [1.8.0]: https://github.com/scenic-views/scenic/compare/v1.7.0...v1.8.0
         | 
| 11 | 
            +
             | 
| 12 | 
            +
            ### Added
         | 
| 11 13 |  | 
| 12 | 
            -
            *  | 
| 14 | 
            +
            * Added `#populated?` to check the state of materialized views - *Daisuke
         | 
| 15 | 
            +
              Fujimura*, *Dr Nic Williams*
         | 
| 13 16 |  | 
| 14 | 
            -
             | 
| 17 | 
            +
            ## [1.7.0] - December 8, 2022
         | 
| 15 18 |  | 
| 16 | 
            -
             | 
| 19 | 
            +
            [1.7.0]: https://github.com/scenic-views/scenic/compare/v1.6.0...v1.7.0
         | 
| 17 20 |  | 
| 18 | 
            -
             | 
| 21 | 
            +
            ### Added
         | 
| 22 | 
            +
             | 
| 23 | 
            +
            * Added the `--replace` CLI flag to generate a migration that uses the
         | 
| 24 | 
            +
              `replace_view` schema statement - *Dan Hixon*
         | 
| 19 25 |  | 
| 20 | 
            -
             | 
| 26 | 
            +
            ### Fixed
         | 
| 27 | 
            +
             | 
| 28 | 
            +
            * Fixed deprecation notice from newer versions of ERB when using scenic
         | 
| 29 | 
            +
              generators - *Ali Ismayilov*
         | 
| 30 | 
            +
             | 
| 31 | 
            +
            ## [1.6.0] - February 13, 2022
         | 
| 32 | 
            +
             | 
| 33 | 
            +
            [1.6.0]: https://github.com/scenic-views/scenic/compare/v1.5.5...v1.6.0
         | 
| 34 | 
            +
             | 
| 35 | 
            +
            ### Fixed
         | 
| 21 36 |  | 
| 22 | 
            -
             | 
| 37 | 
            +
            * Exclude pg_stat_statements_info (#349) 76bface - *Caleb Hearth*
         | 
| 38 | 
            +
            * Fix serialization of views with backslashes c625d1b - *Ben Sheldon*
         | 
| 39 | 
            +
            * Handle ActiveRecord table name prefix and suffix b1544dc - *Derek Prior*
         | 
| 23 40 |  | 
| 24 41 | 
             
            ## [1.5.5] - December 15, 2021
         | 
| 25 42 |  | 
    
        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/Gemfile
    CHANGED
    
    | @@ -5,10 +5,10 @@ gemspec | |
| 5 5 |  | 
| 6 6 | 
             
            rails_version = ENV.fetch("RAILS_VERSION", "6.1")
         | 
| 7 7 |  | 
| 8 | 
            -
            if rails_version == "master"
         | 
| 9 | 
            -
               | 
| 8 | 
            +
            rails_constraint = if rails_version == "master"
         | 
| 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.
         | 
| @@ -86,36 +85,24 @@ 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.
         | 
| 94 95 |  | 
| 95 | 
            -
            You can  | 
| 96 | 
            -
             | 
| 97 | 
            -
            See Postgres documentation on how this works:
         | 
| 98 | 
            -
            http://www.postgresql.org/docs/current/static/sql-createview.html
         | 
| 99 | 
            -
             | 
| 100 | 
            -
            To start replacing a view run the generator like for a regular change:
         | 
| 96 | 
            +
            You can generate a migration that uses the `replace_view` schema statement by
         | 
| 97 | 
            +
            passing the `--replace` option to the `scenic:view` generator:
         | 
| 101 98 |  | 
| 102 99 | 
             
            ```sh
         | 
| 103 | 
            -
            $ rails generate scenic:view search_results
         | 
| 100 | 
            +
            $ rails generate scenic:view search_results --replace
         | 
| 104 101 | 
             
                  create  db/views/search_results_v02.sql
         | 
| 105 102 | 
             
                  create  db/migrate/[TIMESTAMP]_update_search_results_to_version_2.rb
         | 
| 106 103 | 
             
            ```
         | 
| 107 104 |  | 
| 108 | 
            -
             | 
| 109 | 
            -
             | 
| 110 | 
            -
            ```ruby
         | 
| 111 | 
            -
            class UpdateSearchResultsToVersion2 < ActiveRecord::Migration
         | 
| 112 | 
            -
              def change
         | 
| 113 | 
            -
                update_view :search_results, version: 2, revert_to_version: 1
         | 
| 114 | 
            -
              end
         | 
| 115 | 
            -
            end
         | 
| 116 | 
            -
            ```
         | 
| 117 | 
            -
             | 
| 118 | 
            -
            Update it to use replace view:
         | 
| 105 | 
            +
            The migration will look something like this:
         | 
| 119 106 |  | 
| 120 107 | 
             
            ```ruby
         | 
| 121 108 | 
             
            class UpdateSearchResultsToVersion2 < ActiveRecord::Migration
         | 
| @@ -125,8 +112,6 @@ class UpdateSearchResultsToVersion2 < ActiveRecord::Migration | |
| 125 112 | 
             
            end
         | 
| 126 113 | 
             
            ```
         | 
| 127 114 |  | 
| 128 | 
            -
            Now you can run the migration like normal.
         | 
| 129 | 
            -
             | 
| 130 115 | 
             
            ## Can I use this view to back a model?
         | 
| 131 116 |  | 
| 132 117 | 
             
            You bet! Using view-backed models can help promote concepts hidden in your
         | 
| @@ -138,6 +123,11 @@ no different than a table. | |
| 138 123 | 
             
            class SearchResult < ApplicationRecord
         | 
| 139 124 | 
             
              belongs_to :searchable, polymorphic: true
         | 
| 140 125 |  | 
| 126 | 
            +
              # If you want to be able to call +Model.find+, you
         | 
| 127 | 
            +
              # must declare the primary key. It can not be
         | 
| 128 | 
            +
              # inferred from column information.
         | 
| 129 | 
            +
              # self.primary_key = :id
         | 
| 130 | 
            +
             | 
| 141 131 | 
             
              # this isn't strictly necessary, but it will prevent
         | 
| 142 132 | 
             
              # rails from calling save, which would fail anyway.
         | 
| 143 133 | 
             
              def readonly?
         | 
| @@ -252,16 +242,26 @@ accommodate adapter gems. | |
| 252 242 | 
             
            We are aware of the following existing adapter libraries for Scenic which may
         | 
| 253 243 | 
             
            meet your needs:
         | 
| 254 244 |  | 
| 255 | 
            -
            * [scenic_sqlite_adapter](https://github.com/pdebelak/scenic_sqlite_adapter)
         | 
| 256 | 
            -
            * [scenic-mysql_adapter](https://github.com/EmpaticoOrg/scenic-mysql_adapter)
         | 
| 257 | 
            -
            * [scenic-sqlserver-adapter](https://github.com/ClickMechanic/scenic_sqlserver_adapter)
         | 
| 258 | 
            -
            * [scenic-oracle_adapter](https://github.com/cdinger/scenic-oracle_adapter)
         | 
| 245 | 
            +
            * [`scenic_sqlite_adapter`](<https://github.com/pdebelak/scenic_sqlite_adapter>)
         | 
| 246 | 
            +
            * [`scenic-mysql_adapter`](<https://github.com/EmpaticoOrg/scenic-mysql_adapter>)
         | 
| 247 | 
            +
            * [`scenic-sqlserver-adapter`](<https://github.com/ClickMechanic/scenic_sqlserver_adapter>)
         | 
| 248 | 
            +
            * [`scenic-oracle_adapter`](<https://github.com/cdinger/scenic-oracle_adapter>)
         | 
| 259 249 |  | 
| 260 250 | 
             
            Please note that the maintainers of Scenic make no assertions about the
         | 
| 261 251 | 
             
            quality or security of the above adapters.
         | 
| 262 252 |  | 
| 253 | 
            +
            **Related projects**
         | 
| 254 | 
            +
             | 
| 255 | 
            +
            - [`fx`](<https://github.com/teoljungberg/fx>) Versioned database functions and
         | 
| 256 | 
            +
              triggers for Rails
         | 
| 257 | 
            +
             | 
| 263 258 | 
             
            ## About
         | 
| 264 259 |  | 
| 260 | 
            +
            Scenic is used by some popular open source Rails apps:
         | 
| 261 | 
            +
            [Mastodon](<https://github.com/mastodon/mastodon/>),
         | 
| 262 | 
            +
            [Code.org](<https://github.com/code-dot-org/code-dot-org>), and
         | 
| 263 | 
            +
            [Lobste.rs](<https://github.com/lobsters/lobsters/>).
         | 
| 264 | 
            +
             | 
| 265 265 | 
             
            Scenic is maintained by [Derek Prior], [Caleb Hearth], and you, our
         | 
| 266 266 | 
             
            contributors.
         | 
| 267 267 |  | 
    
        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")
         | 
| @@ -15,6 +15,11 @@ module Scenic | |
| 15 15 | 
             
                      required: false,
         | 
| 16 16 | 
             
                      desc: "Adds WITH NO DATA when materialized view creates/updates",
         | 
| 17 17 | 
             
                      default: false
         | 
| 18 | 
            +
                    class_option :replace,
         | 
| 19 | 
            +
                      type: :boolean,
         | 
| 20 | 
            +
                      required: false,
         | 
| 21 | 
            +
                      desc: "Uses replace_view instead of update_view",
         | 
| 22 | 
            +
                      default: false
         | 
| 18 23 | 
             
                  end
         | 
| 19 24 |  | 
| 20 25 | 
             
                  private
         | 
| @@ -23,6 +28,10 @@ module Scenic | |
| 23 28 | 
             
                    options[:materialized]
         | 
| 24 29 | 
             
                  end
         | 
| 25 30 |  | 
| 31 | 
            +
                  def replace_view?
         | 
| 32 | 
            +
                    options[:replace]
         | 
| 33 | 
            +
                  end
         | 
| 34 | 
            +
             | 
| 26 35 | 
             
                  def no_data?
         | 
| 27 36 | 
             
                    options[:no_data]
         | 
| 28 37 | 
             
                  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,14 +34,16 @@ 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 | 
            +
                    erb = ERB.new(
         | 
| 40 41 | 
             
                      ::File.binread(source),
         | 
| 41 | 
            -
                       | 
| 42 | 
            -
                      " | 
| 43 | 
            -
             | 
| 44 | 
            -
             | 
| 42 | 
            +
                      trim_mode: "-",
         | 
| 43 | 
            +
                      eoutvar: "@output_buffer"
         | 
| 44 | 
            +
                    )
         | 
| 45 | 
            +
             | 
| 46 | 
            +
                    erb.result(context)
         | 
| 45 47 | 
             
                  end
         | 
| 46 48 |  | 
| 47 49 | 
             
                  def generating?
         | 
| @@ -1,12 +1,13 @@ | |
| 1 1 | 
             
            class <%= migration_class_name %> < <%= activerecord_migration_class %>
         | 
| 2 2 | 
             
              def change
         | 
| 3 | 
            +
              <%- method_name = replace_view? ? 'replace_view' : 'update_view' -%>
         | 
| 3 4 | 
             
              <%- if materialized? -%>
         | 
| 4 | 
            -
                 | 
| 5 | 
            +
                <%= method_name %> <%= formatted_plural_name %>,
         | 
| 5 6 | 
             
                  version: <%= version %>,
         | 
| 6 7 | 
             
                  revert_to_version: <%= previous_version %>,
         | 
| 7 8 | 
             
                  materialized: <%= no_data? ? "{ no_data: true }" : true %>
         | 
| 8 9 | 
             
              <%- else -%>
         | 
| 9 | 
            -
                 | 
| 10 | 
            +
                <%= method_name %> <%= formatted_plural_name %>, version: <%= version %>, revert_to_version: <%= previous_version %>
         | 
| 10 11 | 
             
              <%- end -%>
         | 
| 11 12 | 
             
              end
         | 
| 12 13 | 
             
            end
         | 
| @@ -28,12 +28,12 @@ module Scenic | |
| 28 28 | 
             
                    if creating_new_view? || destroying_initial_view?
         | 
| 29 29 | 
             
                      migration_template(
         | 
| 30 30 | 
             
                        "db/migrate/create_view.erb",
         | 
| 31 | 
            -
                        "db/migrate/create_#{plural_file_name}.rb" | 
| 31 | 
            +
                        "db/migrate/create_#{plural_file_name}.rb"
         | 
| 32 32 | 
             
                      )
         | 
| 33 33 | 
             
                    else
         | 
| 34 34 | 
             
                      migration_template(
         | 
| 35 35 | 
             
                        "db/migrate/update_view.erb",
         | 
| 36 | 
            -
                        "db/migrate/update_#{plural_file_name}_to_version_#{version}.rb" | 
| 36 | 
            +
                        "db/migrate/update_#{plural_file_name}_to_version_#{version}.rb"
         | 
| 37 37 | 
             
                      )
         | 
| 38 38 | 
             
                    end
         | 
| 39 39 | 
             
                  end
         | 
| @@ -56,7 +56,7 @@ module Scenic | |
| 56 56 |  | 
| 57 57 | 
             
                    def migration_class_name
         | 
| 58 58 | 
             
                      if creating_new_view?
         | 
| 59 | 
            -
                        "Create#{class_name.tr( | 
| 59 | 
            +
                        "Create#{class_name.tr(".", "").pluralize}"
         | 
| 60 60 | 
             
                      else
         | 
| 61 61 | 
             
                        "Update#{class_name.pluralize}ToVersion#{version}"
         | 
| 62 62 | 
             
                      end
         | 
| @@ -73,7 +73,7 @@ module Scenic | |
| 73 73 |  | 
| 74 74 | 
             
                  private
         | 
| 75 75 |  | 
| 76 | 
            -
                   | 
| 76 | 
            +
                  alias_method :singular_name, :file_name
         | 
| 77 77 |  | 
| 78 78 | 
             
                  def file_name
         | 
| 79 79 | 
             
                    super.tr(".", "_")
         | 
| @@ -113,7 +113,7 @@ module Scenic | |
| 113 113 |  | 
| 114 114 | 
             
                  def create_view_options
         | 
| 115 115 | 
             
                    if materialized?
         | 
| 116 | 
            -
                      ", materialized: #{no_data? ?  | 
| 116 | 
            +
                      ", materialized: #{no_data? ? "{ no_data: true }" : true}"
         | 
| 117 117 | 
             
                    else
         | 
| 118 118 | 
             
                      ""
         | 
| 119 119 | 
             
                    end
         | 
| @@ -17,7 +17,7 @@ module Scenic | |
| 17 17 | 
             
                      dependencies.each do |dependency|
         | 
| 18 18 | 
             
                        adapter.refresh_materialized_view(
         | 
| 19 19 | 
             
                          dependency,
         | 
| 20 | 
            -
                          concurrently: concurrently | 
| 20 | 
            +
                          concurrently: concurrently
         | 
| 21 21 | 
             
                        )
         | 
| 22 22 | 
             
                      end
         | 
| 23 23 | 
             
                    end
         | 
| @@ -103,8 +103,8 @@ module Scenic | |
| 103 103 | 
             
                      ORDER BY class_for_rewrite.relname;
         | 
| 104 104 | 
             
                    SQL
         | 
| 105 105 |  | 
| 106 | 
            -
                    private_constant  | 
| 107 | 
            -
                    private_constant  | 
| 106 | 
            +
                    private_constant :DependencyParser
         | 
| 107 | 
            +
                    private_constant :DEPENDENCY_SQL
         | 
| 108 108 |  | 
| 109 109 | 
             
                    def dependencies
         | 
| 110 110 | 
             
                      raw_dependency_info = connection.select_rows(DEPENDENCY_SQL)
         | 
| @@ -43,21 +43,21 @@ module Scenic | |
| 43 43 | 
             
                    def to_scenic_view(result)
         | 
| 44 44 | 
             
                      namespace, viewname = result.values_at "namespace", "viewname"
         | 
| 45 45 |  | 
| 46 | 
            -
                      if namespace != "public"
         | 
| 47 | 
            -
                         | 
| 46 | 
            +
                      namespaced_viewname = if namespace != "public"
         | 
| 47 | 
            +
                        "#{pg_identifier(namespace)}.#{pg_identifier(viewname)}"
         | 
| 48 48 | 
             
                      else
         | 
| 49 | 
            -
                         | 
| 49 | 
            +
                        pg_identifier(viewname)
         | 
| 50 50 | 
             
                      end
         | 
| 51 51 |  | 
| 52 52 | 
             
                      Scenic::View.new(
         | 
| 53 53 | 
             
                        name: namespaced_viewname,
         | 
| 54 54 | 
             
                        definition: result["definition"].strip,
         | 
| 55 | 
            -
                        materialized: result["kind"] == "m" | 
| 55 | 
            +
                        materialized: result["kind"] == "m"
         | 
| 56 56 | 
             
                      )
         | 
| 57 57 | 
             
                    end
         | 
| 58 58 |  | 
| 59 59 | 
             
                    def pg_identifier(name)
         | 
| 60 | 
            -
                      return name if  | 
| 60 | 
            +
                      return name if /^[a-zA-Z_][a-zA-Z0-9_]*$/.match?(name)
         | 
| 61 61 |  | 
| 62 62 | 
             
                      pgconn.quote_ident(name)
         | 
| 63 63 | 
             
                    end
         | 
| @@ -137,8 +137,8 @@ module Scenic | |
| 137 137 |  | 
| 138 138 | 
             
                    execute <<-SQL
         | 
| 139 139 | 
             
              CREATE MATERIALIZED VIEW #{quote_table_name(name)} AS
         | 
| 140 | 
            -
              #{sql_definition.rstrip.chomp( | 
| 141 | 
            -
              #{ | 
| 140 | 
            +
              #{sql_definition.rstrip.chomp(";")}
         | 
| 141 | 
            +
              #{"WITH NO DATA" if no_data};
         | 
| 142 142 | 
             
                    SQL
         | 
| 143 143 | 
             
                  end
         | 
| 144 144 |  | 
| @@ -222,6 +222,31 @@ module Scenic | |
| 222 222 | 
             
                    end
         | 
| 223 223 | 
             
                  end
         | 
| 224 224 |  | 
| 225 | 
            +
                  # True if supplied relation name is populated. Useful for checking the
         | 
| 226 | 
            +
                  # state of materialized views which may error if created `WITH NO DATA`
         | 
| 227 | 
            +
                  # and used before they are refreshed. True for all other relation types.
         | 
| 228 | 
            +
                  #
         | 
| 229 | 
            +
                  # @param name The name of the relation
         | 
| 230 | 
            +
                  #
         | 
| 231 | 
            +
                  # @raise [MaterializedViewsNotSupportedError] if the version of Postgres
         | 
| 232 | 
            +
                  #   in use does not support materialized views.
         | 
| 233 | 
            +
                  #
         | 
| 234 | 
            +
                  # @return [boolean]
         | 
| 235 | 
            +
                  def populated?(name)
         | 
| 236 | 
            +
                    raise_unless_materialized_views_supported
         | 
| 237 | 
            +
             | 
| 238 | 
            +
                    schemaless_name = name.split(".").last
         | 
| 239 | 
            +
             | 
| 240 | 
            +
                    sql = "SELECT relispopulated FROM pg_class WHERE relname = '#{schemaless_name}'"
         | 
| 241 | 
            +
                    relations = execute(sql)
         | 
| 242 | 
            +
             | 
| 243 | 
            +
                    if relations.count.positive?
         | 
| 244 | 
            +
                      relations.first["relispopulated"].in?(["t", true])
         | 
| 245 | 
            +
                    else
         | 
| 246 | 
            +
                      false
         | 
| 247 | 
            +
                    end
         | 
| 248 | 
            +
                  end
         | 
| 249 | 
            +
             | 
| 225 250 | 
             
                  private
         | 
| 226 251 |  | 
| 227 252 | 
             
                  attr_reader :connectable
         | 
| @@ -248,7 +273,7 @@ module Scenic | |
| 248 273 | 
             
                      name,
         | 
| 249 274 | 
             
                      self,
         | 
| 250 275 | 
             
                      connection,
         | 
| 251 | 
            -
                      concurrently: concurrently | 
| 276 | 
            +
                      concurrently: concurrently
         | 
| 252 277 | 
             
                    )
         | 
| 253 278 | 
             
                  end
         | 
| 254 279 | 
             
                end
         | 
    
        data/lib/scenic/definition.rb
    CHANGED
    
    
    
        data/lib/scenic/statements.rb
    CHANGED
    
    | @@ -26,7 +26,7 @@ module Scenic | |
| 26 26 | 
             
                  if version.present? && sql_definition.present?
         | 
| 27 27 | 
             
                    raise(
         | 
| 28 28 | 
             
                      ArgumentError,
         | 
| 29 | 
            -
                      "sql_definition and version cannot both be set" | 
| 29 | 
            +
                      "sql_definition and version cannot both be set"
         | 
| 30 30 | 
             
                    )
         | 
| 31 31 | 
             
                  end
         | 
| 32 32 |  | 
| @@ -40,7 +40,7 @@ module Scenic | |
| 40 40 | 
             
                    Scenic.database.create_materialized_view(
         | 
| 41 41 | 
             
                      name,
         | 
| 42 42 | 
             
                      sql_definition,
         | 
| 43 | 
            -
                      no_data: no_data(materialized) | 
| 43 | 
            +
                      no_data: no_data(materialized)
         | 
| 44 44 | 
             
                    )
         | 
| 45 45 | 
             
                  else
         | 
| 46 46 | 
             
                    Scenic.database.create_view(name, sql_definition)
         | 
| @@ -92,14 +92,14 @@ module Scenic | |
| 92 92 | 
             
                  if version.blank? && sql_definition.blank?
         | 
| 93 93 | 
             
                    raise(
         | 
| 94 94 | 
             
                      ArgumentError,
         | 
| 95 | 
            -
                      "sql_definition or version must be specified" | 
| 95 | 
            +
                      "sql_definition or version must be specified"
         | 
| 96 96 | 
             
                    )
         | 
| 97 97 | 
             
                  end
         | 
| 98 98 |  | 
| 99 99 | 
             
                  if version.present? && sql_definition.present?
         | 
| 100 100 | 
             
                    raise(
         | 
| 101 101 | 
             
                      ArgumentError,
         | 
| 102 | 
            -
                      "sql_definition and version cannot both be set" | 
| 102 | 
            +
                      "sql_definition and version cannot both be set"
         | 
| 103 103 | 
             
                    )
         | 
| 104 104 | 
             
                  end
         | 
| 105 105 |  | 
| @@ -109,7 +109,7 @@ module Scenic | |
| 109 109 | 
             
                    Scenic.database.update_materialized_view(
         | 
| 110 110 | 
             
                      name,
         | 
| 111 111 | 
             
                      sql_definition,
         | 
| 112 | 
            -
                      no_data: no_data(materialized) | 
| 112 | 
            +
                      no_data: no_data(materialized)
         | 
| 113 113 | 
             
                    )
         | 
| 114 114 | 
             
                  else
         | 
| 115 115 | 
             
                    Scenic.database.update_view(name, sql_definition)
         | 
    
        data/lib/scenic/version.rb
    CHANGED
    
    
    
        data/lib/scenic/view.rb
    CHANGED
    
    | @@ -26,7 +26,7 @@ module Scenic | |
| 26 26 | 
             
                #
         | 
| 27 27 | 
             
                # @param name [String] The name of the view.
         | 
| 28 28 | 
             
                # @param definition [String] The SQL for the query that defines the view.
         | 
| 29 | 
            -
                # @param materialized [ | 
| 29 | 
            +
                # @param materialized [Boolean] `true` if the view is materialized.
         | 
| 30 30 | 
             
                def initialize(name:, definition:, materialized:)
         | 
| 31 31 | 
             
                  @name = name
         | 
| 32 32 | 
             
                  @definition = definition
         | 
    
        data/scenic.gemspec
    CHANGED
    
    | @@ -3,20 +3,19 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib) | |
| 3 3 | 
             
            require "scenic/version"
         | 
| 4 4 |  | 
| 5 5 | 
             
            Gem::Specification.new do |spec|
         | 
| 6 | 
            -
              spec.name | 
| 7 | 
            -
              spec.version | 
| 8 | 
            -
              spec.authors | 
| 9 | 
            -
              spec.email | 
| 10 | 
            -
              spec.summary | 
| 11 | 
            -
              spec.description | 
| 6 | 
            +
              spec.name = "scenic"
         | 
| 7 | 
            +
              spec.version = Scenic::VERSION
         | 
| 8 | 
            +
              spec.authors = ["Derek Prior", "Caleb Hearth"]
         | 
| 9 | 
            +
              spec.email = ["derekprior@gmail.com", "caleb@calebhearth.com"]
         | 
| 10 | 
            +
              spec.summary = "Support for database views in Rails migrations"
         | 
| 11 | 
            +
              spec.description = <<-DESCRIPTION
         | 
| 12 12 | 
             
                Adds methods to ActiveRecord::Migration to create and manage database views
         | 
| 13 13 | 
             
                in Rails
         | 
| 14 14 | 
             
              DESCRIPTION
         | 
| 15 | 
            -
              spec.homepage | 
| 16 | 
            -
              spec.license | 
| 15 | 
            +
              spec.homepage = "https://github.com/scenic-views/scenic"
         | 
| 16 | 
            +
              spec.license = "MIT"
         | 
| 17 17 |  | 
| 18 | 
            -
              spec.files | 
| 19 | 
            -
              spec.test_files    = spec.files.grep(%r{^spec/})
         | 
| 18 | 
            +
              spec.files = `git ls-files -z`.split("\x0")
         | 
| 20 19 | 
             
              spec.require_paths = ["lib"]
         | 
| 21 20 |  | 
| 22 21 | 
             
              spec.add_development_dependency "bundler", ">= 1.5"
         | 
| @@ -28,6 +27,7 @@ Gem::Specification.new do |spec| | |
| 28 27 | 
             
              spec.add_development_dependency "ammeter", ">= 1.1.3"
         | 
| 29 28 | 
             
              spec.add_development_dependency "yard"
         | 
| 30 29 | 
             
              spec.add_development_dependency "redcarpet"
         | 
| 30 | 
            +
              spec.add_development_dependency "standard"
         | 
| 31 31 |  | 
| 32 32 | 
             
              spec.add_dependency "activerecord", ">= 4.0.0"
         | 
| 33 33 | 
             
              spec.add_dependency "railties", ">= 4.0.0"
         | 
    
        data/spec/dummy/Rakefile
    CHANGED
    
    | @@ -1,13 +1,13 @@ | |
| 1 1 | 
             
            # Add your own tasks in files placed in lib/tasks ending in .rake,
         | 
| 2 2 | 
             
            # for example lib/tasks/capistrano.rake, and they will automatically be available to Rake.
         | 
| 3 3 |  | 
| 4 | 
            -
            require File.expand_path( | 
| 4 | 
            +
            require File.expand_path("../config/application", __FILE__)
         | 
| 5 5 |  | 
| 6 6 | 
             
            Rails.application.load_tasks
         | 
| 7 7 |  | 
| 8 | 
            -
            unless Rake::Task.task_defined?( | 
| 9 | 
            -
              desc  | 
| 10 | 
            -
              task  | 
| 11 | 
            -
                #no op
         | 
| 8 | 
            +
            unless Rake::Task.task_defined?("db:environment:set")
         | 
| 9 | 
            +
              desc "dummy task for rails versions where this task does not exist"
         | 
| 10 | 
            +
              task "db:environment:set" do
         | 
| 11 | 
            +
                # no op
         | 
| 12 12 | 
             
              end
         | 
| 13 13 | 
             
            end
         | 
    
        data/spec/dummy/bin/bundle
    CHANGED
    
    | @@ -1,3 +1,3 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 | 
            -
            ENV[ | 
| 3 | 
            -
            load Gem.bin_path( | 
| 2 | 
            +
            ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
         | 
| 3 | 
            +
            load Gem.bin_path("bundler", "bundle")
         | 
    
        data/spec/dummy/bin/rails
    CHANGED
    
    | @@ -1,4 +1,4 @@ | |
| 1 1 | 
             
            #!/usr/bin/env ruby
         | 
| 2 | 
            -
            APP_PATH = File.expand_path( | 
| 3 | 
            -
            require_relative  | 
| 4 | 
            -
            require  | 
| 2 | 
            +
            APP_PATH = File.expand_path("../../config/application", __FILE__)
         | 
| 3 | 
            +
            require_relative "../config/boot"
         | 
| 4 | 
            +
            require "rails/commands"
         |