Skip to content

feat: allow disabling SQL view discovery#3670

Open
Dexter2099 wants to merge 1 commit into
meltano:mainfrom
Dexter2099:codex/sql-discovery-view-settings
Open

feat: allow disabling SQL view discovery#3670
Dexter2099 wants to merge 1 commit into
meltano:mainfrom
Dexter2099:codex/sql-discovery-view-settings

Conversation

@Dexter2099

@Dexter2099 Dexter2099 commented Jun 6, 2026

Copy link
Copy Markdown

Fixes #2806.

Summary

  • Add built-in SQL tap settings for discover_views and discover_materialized_views.
  • Pass those settings from SQLTap into catalog discovery.
  • Let SQLConnector.discover_catalog_entries() reflect tables, views, and materialized views according to those flags while preserving the existing default behavior.
  • Add connector and tap-level regression coverage.

Validation

  • uv run pytest tests/sql/test_connector.py::TestDummySQLConnector::test_discover_catalog_entries_can_exclude_views tests/sql/test_connector.py::TestDummySQLConnector::test_discover_catalog_entries_can_filter_materialized_views tests/sql/test_connector.py::test_sql_tap_passes_discovery_settings_from_config -q
  • uv run pytest tests/sql/test_connector.py -q
  • uv run pytest tests/sql -q
  • pre-commit run --files singer_sdk/helpers/capabilities.py singer_sdk/sql/connector.py singer_sdk/sql/tap.py tests/sql/test_connector.py
  • NOX_DEFAULT_VENV_BACKEND=uv nox -rs tests-3.11 -- tests/sql
  • uv run pytest tests/packages/test_tap_sqlite.py -m packages -q

Summary by Sourcery

Allow SQL taps and connectors to control whether views and materialized views are included during catalog discovery while preserving existing default behavior.

New Features:

  • Add SQL tap configuration options to toggle discovery of views and materialized views.
  • Expose discovery flags on SQLConnector.discover_catalog_entries to control reflection of tables, views, and materialized views.

Tests:

  • Add regression tests for SQLConnector discovery filtering of views and materialized views and for passing tap-level discovery settings into the connector.

@sourcery-ai

sourcery-ai Bot commented Jun 6, 2026

Copy link
Copy Markdown
Contributor

Reviewer's Guide

Adds configurable flags to control whether SQL catalog discovery includes views and materialized views, wires those flags through the SQL tap configuration and connector discovery logic, and adds regression tests to validate behavior and configuration plumbing.

Sequence diagram for SQL tap discovery with view flags

sequenceDiagram
    actor User
    participant SQLTap
    participant SQLConnector
    participant SAInspector

    User->>SQLTap: catalog_dict()
    SQLTap->>SQLTap: config.get(discover_views)
    SQLTap->>SQLTap: config.get(discover_materialized_views)
    SQLTap->>SQLConnector: discover_catalog_entries(exclude_schemas, discover_views, discover_materialized_views)

    SQLConnector->>SAInspector: sa.inspect(engine)
    SQLConnector->>SQLConnector: object_kinds = [(ObjectKind.TABLE, False)]
    opt [discover_views enabled]
        SQLConnector->>SQLConnector: object_kinds.append((ObjectKind.VIEW, True))
    end
    opt [discover_materialized_views enabled]
        SQLConnector->>SQLConnector: object_kinds.append((ObjectKind.MATERIALIZED_VIEW, True))
    end

    loop schemas from get_schema_names()
        SQLConnector->>SQLConnector: skip if schema in exclude_schemas
        SQLConnector->>SQLConnector: reflect object_kinds into catalog entries
    end

    SQLConnector-->>SQLTap: list[dict] streams
    SQLTap-->>User: catalog_dict
Loading

File-Level Changes

Change Details Files
Introduce tap-level configuration options to control discovery of views and materialized views and expose them in SQL taps' built-in config schema.
  • Add SQL_TAP_DISCOVERY_CONFIG with discover_views and discover_materialized_views boolean properties, both defaulting to true.
  • Extend SQLTap.append_builtin_config to merge the new discovery config schema into tap configs alongside existing SQL_TAP_USE_SINGER_DECIMAL settings.
singer_sdk/helpers/capabilities.py
singer_sdk/sql/tap.py
Plumb discovery configuration flags from SQL taps into the SQL connector and adjust catalog discovery to conditionally include views and materialized views.
  • Update SQLTap.catalog_dict to pass discover_views and discover_materialized_views from tap config (with true defaults) into connector.discover_catalog_entries along with exclude_schemas.
  • Extend SQLConnector.discover_catalog_entries signature with discover_views and discover_materialized_views keyword-only parameters defaulting to true.
  • Change discovery object_kinds so that tables are always reflected, while views and materialized views are only reflected when their respective flags are enabled, replacing the previous ANY_VIEW behavior.
singer_sdk/sql/tap.py
singer_sdk/sql/connector.py
Add regression tests and test helpers to validate discovery filtering behavior and configuration plumbing from taps to connectors.
  • Introduce SpySQLConnector, SpySQLStream, and SpySQLTap test doubles to capture discovery kwargs from a SQL tap run.
  • Add tests verifying that discover_catalog_entries can exclude views and can separately control materialized view reflection via flags.
  • Add a test confirming that SQLTap passes discover_views and discover_materialized_views from tap configuration to the connector discovery call, with exclude_schemas propagated as expected.
tests/sql/test_connector.py

Assessment against linked issues

Issue Objective Addressed Explanation
#2806 Add configurable SQL tap settings discover_views and discover_materialized_views (with appropriate defaults and schema documentation) to control discovery behavior.
#2806 Update SQL catalog discovery logic so that SQLConnector.discover_catalog_entries selectively includes views and materialized views according to the discover_views and discover_materialized_views settings, preserving default behavior when both are true.

Possibly linked issues


Tips and commands

Interacting with Sourcery

  • Trigger a new review: Comment @sourcery-ai review on the pull request.
  • Continue discussions: Reply directly to Sourcery's review comments.
  • Generate a GitHub issue from a review comment: Ask Sourcery to create an
    issue from a review comment by replying to it. You can also reply to a
    review comment with @sourcery-ai issue to create an issue from it.
  • Generate a pull request title: Write @sourcery-ai anywhere in the pull
    request title to generate a title at any time. You can also comment
    @sourcery-ai title on the pull request to (re-)generate the title at any time.
  • Generate a pull request summary: Write @sourcery-ai summary anywhere in
    the pull request body to generate a PR summary at any time exactly where you
    want it. You can also comment @sourcery-ai summary on the pull request to
    (re-)generate the summary at any time.
  • Generate reviewer's guide: Comment @sourcery-ai guide on the pull
    request to (re-)generate the reviewer's guide at any time.
  • Resolve all Sourcery comments: Comment @sourcery-ai resolve on the
    pull request to resolve all Sourcery comments. Useful if you've already
    addressed all the comments and don't want to see them anymore.
  • Dismiss all Sourcery reviews: Comment @sourcery-ai dismiss on the pull
    request to dismiss all existing Sourcery reviews. Especially useful if you
    want to start fresh with a new review - don't forget to comment
    @sourcery-ai review to trigger a new review!

Customizing Your Experience

Access your dashboard to:

  • Enable or disable review features such as the Sourcery-generated pull request
    summary, the reviewer's guide, and others.
  • Change the review language.
  • Add, remove or edit custom review instructions.
  • Adjust other review settings.

Getting Help

@read-the-docs-community

read-the-docs-community Bot commented Jun 6, 2026

Copy link
Copy Markdown

Documentation build overview

📚 Meltano SDK | 🛠️ Build #33022849 | 📁 Comparing 6dafa1e against latest (bf02d4f)

  🔍 Preview build  

1 file changed
± classes/singer_sdk.sql.SQLConnector.html

@sourcery-ai sourcery-ai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Hey - I've found 1 issue, and left some high level feedback:

  • Passing discover_views and discover_materialized_views as new keyword-only arguments from SQLTap.catalog_dict() into SQLConnector.discover_catalog_entries() may break custom connectors that override discover_catalog_entries without accepting these parameters; consider either keeping the call signature backward-compatible (e.g., passing only exclude_schemas for now or using a helper/**kwargs pattern) or adding a compatibility shim in the base connector.
  • The default values for discover_views and discover_materialized_views are now duplicated between SQL_TAP_DISCOVERY_CONFIG (JSON schema defaults) and the config.get(..., True) calls in SQLTap.catalog_dict; consider relying on a single source of truth (e.g., the schema-driven config) to avoid drift in future changes.
Prompt for AI Agents
Please address the comments from this code review:

## Overall Comments
- Passing `discover_views` and `discover_materialized_views` as new keyword-only arguments from `SQLTap.catalog_dict()` into `SQLConnector.discover_catalog_entries()` may break custom connectors that override `discover_catalog_entries` without accepting these parameters; consider either keeping the call signature backward-compatible (e.g., passing only `exclude_schemas` for now or using a helper/`**kwargs` pattern) or adding a compatibility shim in the base connector.
- The default values for `discover_views` and `discover_materialized_views` are now duplicated between `SQL_TAP_DISCOVERY_CONFIG` (JSON schema defaults) and the `config.get(..., True)` calls in `SQLTap.catalog_dict`; consider relying on a single source of truth (e.g., the schema-driven config) to avoid drift in future changes.

## Individual Comments

### Comment 1
<location path="tests/sql/test_connector.py" line_range="68-75" />
<code_context>
         )


+class SpySQLConnector(SQLConnector):
+    """SQL connector that captures discovery options."""
+
+    discovery_kwargs: t.ClassVar[dict[str, t.Any]] = {}
+
+    def discover_catalog_entries(self, **kwargs: t.Any) -> list[dict]:
+        self.__class__.discovery_kwargs = kwargs
+        return []
+
+
</code_context>
<issue_to_address>
**suggestion (testing):** Reset `SpySQLConnector.discovery_kwargs` between tests to avoid cross-test coupling

Since `discovery_kwargs` is a class variable, its state will persist across test runs and can be shared between tests that use `SpySQLConnector`. To keep tests isolated and order-independent, reset `SpySQLConnector.discovery_kwargs` (for example, to `{}`) in the relevant test or via a fixture before instantiating `SpySQLTap`, so the assertion on `discovery_kwargs` remains reliable as more tests are added.

Suggested implementation:

```python
import typing as t

import pytest
from singer_sdk.exceptions import ConfigValidationError

```

```python
class SpySQLConnector(SQLConnector):
    """SQL connector that captures discovery options."""

    discovery_kwargs: t.ClassVar[dict[str, t.Any]] = {}

    def discover_catalog_entries(self, **kwargs: t.Any) -> list[dict]:
        """Capture discovery kwargs and return an empty catalog."""
        self.__class__.discovery_kwargs = kwargs
        return []


@pytest.fixture(autouse=True)
def reset_spy_sql_connector_discovery_kwargs() -> None:
    """Reset SpySQLConnector discovery state between tests in this module."""
    SpySQLConnector.discovery_kwargs = {}

```
</issue_to_address>

Sourcery is free for open source - if you like our reviews please consider sharing them ✨
Help me be more useful! Please click 👍 or 👎 on each comment and I'll use the feedback to improve your reviews.

Comment on lines +68 to +75
class SpySQLConnector(SQLConnector):
"""SQL connector that captures discovery options."""

discovery_kwargs: t.ClassVar[dict[str, t.Any]] = {}

def discover_catalog_entries(self, **kwargs: t.Any) -> list[dict]:
self.__class__.discovery_kwargs = kwargs
return []

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

suggestion (testing): Reset SpySQLConnector.discovery_kwargs between tests to avoid cross-test coupling

Since discovery_kwargs is a class variable, its state will persist across test runs and can be shared between tests that use SpySQLConnector. To keep tests isolated and order-independent, reset SpySQLConnector.discovery_kwargs (for example, to {}) in the relevant test or via a fixture before instantiating SpySQLTap, so the assertion on discovery_kwargs remains reliable as more tests are added.

Suggested implementation:

import typing as t

import pytest
from singer_sdk.exceptions import ConfigValidationError
class SpySQLConnector(SQLConnector):
    """SQL connector that captures discovery options."""

    discovery_kwargs: t.ClassVar[dict[str, t.Any]] = {}

    def discover_catalog_entries(self, **kwargs: t.Any) -> list[dict]:
        """Capture discovery kwargs and return an empty catalog."""
        self.__class__.discovery_kwargs = kwargs
        return []


@pytest.fixture(autouse=True)
def reset_spy_sql_connector_discovery_kwargs() -> None:
    """Reset SpySQLConnector discovery state between tests in this module."""
    SpySQLConnector.discovery_kwargs = {}

@codspeed-hq

codspeed-hq Bot commented Jun 6, 2026

Copy link
Copy Markdown

Merging this PR will not alter performance

✅ 8 untouched benchmarks


Comparing Dexter2099:codex/sql-discovery-view-settings (6dafa1e) with main (bf02d4f)

Open in CodSpeed

@Dexter2099 Dexter2099 force-pushed the codex/sql-discovery-view-settings branch from 272d8bf to de52726 Compare June 6, 2026 22:47
@Dexter2099 Dexter2099 force-pushed the codex/sql-discovery-view-settings branch from de52726 to 6dafa1e Compare June 6, 2026 22:51
@Dexter2099

Copy link
Copy Markdown
Author

Note on the currently failing coverage jobs: all test, typing, CodeQL, Sourcery, and benchmark checks are passing on the latest head. The three coverage jobs are failing after coverage xml succeeds, during the Codecov upload step with:

Could not verify signature. Please contact Codecov if problem continues

I force-pushed once to rerun the checks and the same Codecov CLI signature failure repeated, so this appears external to the PR code.

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

feat: Allow users to disable discovery of SQL views (and materialized views)

1 participant