Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rely on search_path (instead of "public") when deciding to fully-qualify view name #401

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

smudge
Copy link
Contributor

@smudge smudge commented Jan 17, 2024

This should resolve the discrepancies in #327 and #325, and is in response to a behavior introduced in #152.

The heart of the issue is in how "public" was hardcoded in #152, because it assumes that "public" will be at the front of the search path (and is therefore the reason a view name should or should not be fully-qualified in schema.rb). But "public" being first in the search path is just a default configuration1 that can be overridden in a few different ways (e.g. schema_search_path in database.yml, or by setting it at the user/connection level, which some PAAS providers do).

In reality, PostgreSQL will create unqualified tables/views in current_schema(), and so we can rely on that to determine whether a view was created in the observer's default schema. (This is how Rails handles enum names when returning a list of all defined enums, a lookup case which otherwise appears very similar to what the scenic gem does for views.2)

This should resolve issues where laptop 1 and laptop 2 have different default schemas (or where different environments/deployments use different default schema names) but must share a schema.rb file; as long as the view is locally created in the (local's) default schema, the view will go unnamespaced in the generated schema file, but for anyone who writes a migration that explicitly creates a view in a non-default schema, that explicit schema name will survive the round-trip, as desired. Win-win 👍 .

Footnotes

  1. Technically "$user" (which resolves to the current PG user's name) is first by default, but that schema also doesn't exist by default, so current_schema() ends up being "public" by default.

  2. This was introduced in Support schemas in Postgresql enum_types rails/rails#45740

@@ -41,9 +42,9 @@ def views_from_postgres
end

def to_scenic_view(result)
namespace, viewname = result.values_at "namespace", "viewname"
namespace, viewname, current_schema = result.values_at "namespace", "viewname", "current_schema"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [106/80]

view_definition = "SELECT 'needle'::text AS haystack"
Search.connection.execute "CREATE SCHEMA scenic; SET search_path TO scenic, public"
Search.connection.create_view :"scenic.searches", sql_definition: view_definition
Search.connection.create_view :"public.searches", sql_definition: view_definition
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [89/80]

it "dumps a create_view including namespace for a view in the database" do
view_definition = "SELECT 'needle'::text AS haystack"
Search.connection.execute "CREATE SCHEMA scenic; SET search_path TO scenic, public"
Search.connection.create_view :"scenic.searches", sql_definition: view_definition
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [89/80]

context 'when "public" is not the primary search path' do
it "dumps a create_view including namespace for a view in the database" do
view_definition = "SELECT 'needle'::text AS haystack"
Search.connection.execute "CREATE SCHEMA scenic; SET search_path TO scenic, public"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [91/80]

Search.connection.create_view :"scenic.searches", sql_definition: view_definition
Search.connection.create_view :"public.searches", sql_definition: view_definition
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [87/80]

@@ -58,16 +58,38 @@ class SearchInAHaystack < ActiveRecord::Base
context "with views in non public schemas" do
it "dumps a create_view including namespace for a view in the database" do
view_definition = "SELECT 'needle'::text AS haystack"
Search.connection.execute "CREATE SCHEMA scenic; SET search_path TO scenic, public"
Search.connection.execute "CREATE SCHEMA scenic; SET search_path TO public, scenic"
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Metrics/LineLength: Line is too long. [89/80]

@smudge
Copy link
Contributor Author

smudge commented Jan 17, 2024

Hmm, it seems the existing code was already in violation of the line length -- I assume hound only runs on the changed lines? 🤔

@calebhearth
Copy link
Contributor

calebhearth commented Jan 17, 2024 via email

@smudge
Copy link
Contributor Author

smudge commented Jan 19, 2024

(rebased due to file conflicts)

@teoljungberg
Copy link
Contributor

I'd be interesting in hearing what you reason about this @calebhearth - as @smudge has laid forth a similar proposal in fx (teoljungberg/fx#140). I'd like if Scenic and fx handled this the same way.

@calebhearth calebhearth added this to the 2.0 milestone Jan 20, 2024
@derekprior
Copy link
Contributor

My thought right now is that adding specific handling of schema to scenic was a mistake and that we should remove it. It has led to a number of issues raised by users. I think it makes sense to behave exactly as rails behaves with tables. If you want to store views in a different schema then you need a different search path. I think #402 would make that something that could be done rather trivially and in line with Rails conventions.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants