Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
129 changes: 90 additions & 39 deletions poetry.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,15 @@ packages = [
[tool.poetry.dependencies]
python = ">=3.9,<3.13"
importlib-resources = { version = "==6.4.*", python = "<3.9" }
singer-sdk = "^0.41.0"
singer-sdk = "^0.48.1"
fs-s3fs = { version = "^1.1.1", optional = true }
sqlalchemy-bigquery = "^1.8.0"
google-cloud-bigquery = "^3.25.0"
gcsfs = "^2024.9.0.post1"

[tool.poetry.group.dev.dependencies]
pytest = "^7.4.4"
singer-sdk = { version="^0.41.0", extras = ["testing"] }
pytest = "^8"
singer-sdk = { version="^0.48.1", extras = ["testing"] }

[tool.poetry.extras]
s3 = ["fs-s3fs"]
Expand Down
32 changes: 30 additions & 2 deletions tap_bigquery/connector.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@
import sqlalchemy
from singer_sdk import SQLConnector
from singer_sdk import typing as th # JSON schema typing helpers
from singer_sdk._singerlib import CatalogEntry, MetadataMapping, Schema
from singer_sdk.singerlib import CatalogEntry, MetadataMapping, Schema
from sqlalchemy_bigquery import (
ARRAY,
FLOAT,
Expand Down Expand Up @@ -157,6 +157,33 @@ def to_jsonschema_type(
return jsonschema.type_dict
return super().to_jsonschema_type(sql_type)

def discover_catalog_entries(self, **kwargs: dict[str, t.Any]) -> list[dict]: # noqa: ARG002
"""Return a list of catalog entries from discovery.

Returns:
The discovered catalog entries as a list.
"""
result: list[dict] = []
engine = self._engine
inspected = sqlalchemy.inspect(engine)
for schema_name in self.get_schema_names(engine, inspected):
# Iterate through each table and view
for table_name, is_view in self.get_object_names(
engine,
inspected,
schema_name,
):
catalog_entry = self.discover_catalog_entry(
engine,
inspected,
schema_name,
table_name,
is_view,
)
result.append(catalog_entry.to_dict())

return result

# TODO this only needs a column filtering capability in the singer-sdk
# as sqlalchemy returns additional columns on bigquery for all the json
# it has natively understood.
Expand All @@ -167,6 +194,7 @@ def discover_catalog_entry(
schema_name: str,
table_name: str,
is_view: bool, # noqa: FBT001
**kwargs: dict[str, t.Any], # noqa: ARG002
) -> CatalogEntry:
"""Create `CatalogEntry` object for the given table or a view.

Expand Down Expand Up @@ -295,4 +323,4 @@ def get_schema_names(self, engine: Engine, inspected: Inspector) -> list[str]:
return self.config["filter_schemas"]
return super().get_schema_names(engine, inspected)

__all__ = ["TapBigQuery", "BigQueryConnector", "BigQueryStream"]
__all__ = ["BigQueryConnector", "BigQueryStream", "TapBigQuery"]
8 changes: 4 additions & 4 deletions tests/test_client.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
from sqlalchemy.types import String, Double, Float
from sqlalchemy_bigquery import ARRAY

from singer_sdk._singerlib import Catalog, CatalogEntry
from singer_sdk.singerlib import Catalog, CatalogEntry
from tap_bigquery.tap import TapBigQuery
from tap_bigquery.client import BigQueryConnector

Expand All @@ -34,7 +34,7 @@ def setUp(self):
['mock-schema'],
['mock_table'],
{
'mock-schema.mock_table': [
('mock-schema', 'mock_table'): [
{ 'name': 'double_field', 'type': Double },
{ 'name': 'double_infinity', 'type': Double },
{ 'name': 'float_field', 'type': Float },
Expand Down Expand Up @@ -79,7 +79,7 @@ def test_record_serialisable_post_processing(self, mock_engine, mock_inspector):
['mock-schema'],
['mock_table'],
{
'mock-schema.mock_table': [
('mock-schema', 'mock_table'): [
{ 'name': 'string_field', 'type': String(50) },
{ 'name': 'float_field', 'type': Float },
{ 'name': 'float_none', 'type': Float },
Expand Down Expand Up @@ -171,7 +171,7 @@ def test_catalog_supplied(self, mock_engine, mock_inspector, mock_sql_tap):
['mock-schema'],
['mock_table'],
{
'mock-schema.mock_table': [
('mock-schema', 'mock_table'): [
{ 'name': 'string_field', 'type': String(50) },
],
},
Expand Down
17 changes: 14 additions & 3 deletions tests/utils/mockinspector.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,9 @@
from __future__ import annotations

from typing import List
from sqlalchemy import Inspector, Column

from sqlalchemy import Column, Inspector


class MockInspector(Inspector):
def __init__(
Expand All @@ -27,7 +29,16 @@ def get_indexes(self, table_name: str, schema: str) -> List[str]:
return []

def get_columns(self, table_name: str, schema: str) -> dict[str, Column]:
return self.table_columns[schema + '.' + table_name]
return self.table_columns[(schema, table_name)]

def get_pk_constraint(self, table_name: str, schema: str) -> dict:
return {}
return {}

def get_multi_pk_constraint(self, *args, **kwargs):
return {}

def get_multi_indexes(self, *args, **kwargs):
return {}

def get_multi_columns(self, *args, **kwargs):
return self.table_columns