Skip to content

Commit dbf88a8

Browse files
authored
feat: adds a bigquery config and driver (#28)
Implements a `bigquery` config and driver with Export to parquet and `select_arrow`
1 parent 4dadafc commit dbf88a8

File tree

11 files changed

+1171
-1
lines changed

11 files changed

+1171
-1
lines changed

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ msgspec = ["msgspec"]
2424
nanoid = ["fastnanoid>=0.4.1"]
2525
oracledb = ["oracledb"]
2626
orjson = ["orjson"]
27-
performance = ["sqlglot[rs]"]
27+
performance = ["sqlglot[rs]", "msgspec"]
2828
psqlpy = ["psqlpy"]
2929
psycopg = ["psycopg[binary,pool]"]
3030
pydantic = ["pydantic", "pydantic-extra-types"]
Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
from sqlspec.adapters.bigquery.config import BigQueryConfig, BigQueryConnectionConfig
2+
from sqlspec.adapters.bigquery.driver import BigQueryConnection, BigQueryDriver
3+
4+
__all__ = ("BigQueryConfig", "BigQueryConnection", "BigQueryConnectionConfig", "BigQueryDriver")
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
from sqlspec.adapters.bigquery.config._sync import BigQueryConfig, BigQueryConnectionConfig
2+
3+
__all__ = ("BigQueryConfig", "BigQueryConnectionConfig")
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
from dataclasses import dataclass, field
2+
from typing import TYPE_CHECKING, Optional
3+
4+
from google.cloud.bigquery import LoadJobConfig, QueryJobConfig
5+
6+
if TYPE_CHECKING:
7+
from google.api_core.client_info import ClientInfo
8+
from google.api_core.client_options import ClientOptions
9+
from google.auth.credentials import Credentials
10+
11+
__all__ = ("BigQueryConnectionConfigCommon",)
12+
13+
14+
@dataclass
15+
class BigQueryConnectionConfigCommon:
16+
"""Common configuration options for BigQuery."""
17+
18+
project: "Optional[str]" = field(default=None)
19+
"""Google Cloud project ID."""
20+
location: "Optional[str]" = field(default=None)
21+
"""Default geographic location for jobs and datasets."""
22+
credentials: "Optional[Credentials]" = field(default=None, hash=False)
23+
"""Credentials to use for authentication."""
24+
dataset_id: "Optional[str]" = field(default=None)
25+
"""Default dataset ID to use if not specified in queries."""
26+
credentials_path: "Optional[str]" = field(default=None)
27+
"""Path to Google Cloud service account key file (JSON). If None, attempts default authentication."""
28+
client_options: "Optional[ClientOptions]" = field(default=None, hash=False)
29+
"""Client options used to set user options on the client (e.g., api_endpoint)."""
30+
default_query_job_config: "Optional[QueryJobConfig]" = field(default=None, hash=False)
31+
"""Default QueryJobConfig settings."""
32+
default_load_job_config: "Optional[LoadJobConfig]" = field(default=None, hash=False)
33+
"""Default LoadJobConfig settings."""
34+
client_info: "Optional[ClientInfo]" = field(default=None, hash=False)
35+
"""Client info used to send a user-agent string along with API requests."""
36+
37+
def __post_init__(self) -> None:
38+
"""Post-initialization hook."""
39+
if self.default_query_job_config is None:
40+
self.default_query_job_config = QueryJobConfig(default_dataset=self.dataset_id)
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
import contextlib
2+
from dataclasses import dataclass, field
3+
from typing import TYPE_CHECKING, Any, Optional
4+
5+
from sqlspec.adapters.bigquery.config._common import BigQueryConnectionConfigCommon
6+
from sqlspec.adapters.bigquery.driver import BigQueryConnection, BigQueryDriver
7+
from sqlspec.base import NoPoolSyncConfig
8+
from sqlspec.typing import dataclass_to_dict
9+
10+
if TYPE_CHECKING:
11+
from collections.abc import Iterator
12+
13+
__all__ = ("BigQueryConfig", "BigQueryConnectionConfig")
14+
15+
16+
class BigQueryConnectionConfig(BigQueryConnectionConfigCommon):
17+
"""BigQuery Connection Configuration."""
18+
19+
20+
@dataclass
21+
class BigQueryConfig(NoPoolSyncConfig["BigQueryConnection", "BigQueryDriver"]):
22+
"""BigQuery Synchronous Driver Configuration."""
23+
24+
connection_config: "BigQueryConnectionConfig" = field(default_factory=BigQueryConnectionConfig)
25+
"""BigQuery Connection Configuration."""
26+
driver_type: "type[BigQueryDriver]" = field(init=False, repr=False, default=BigQueryDriver)
27+
"""BigQuery Driver Type."""
28+
connection_type: "type[BigQueryConnection]" = field(init=False, repr=False, default=BigQueryConnection)
29+
"""BigQuery Connection Type."""
30+
pool_instance: "None" = field(init=False, repr=False, default=None, hash=False)
31+
"""This is set to have a init=False since BigQuery does not support pooling."""
32+
connection_instance: "Optional[BigQueryConnection]" = field(init=False, repr=False, default=None, hash=False)
33+
"""BigQuery Connection Instance."""
34+
35+
@property
36+
def connection_config_dict(self) -> "dict[str, Any]":
37+
"""Return the connection configuration as a dict.
38+
39+
Returns:
40+
A string keyed dict of config kwargs for the BigQueryConnection constructor.
41+
"""
42+
return dataclass_to_dict(
43+
self.connection_config,
44+
exclude_empty=True,
45+
exclude_none=True,
46+
exclude={"dataset_id", "credentials_path"},
47+
)
48+
49+
def create_connection(self) -> "BigQueryConnection":
50+
"""Create a BigQuery Client instance.
51+
52+
Returns:
53+
A BigQuery Client instance.
54+
"""
55+
if self.connection_instance is not None:
56+
return self.connection_instance
57+
58+
self.connection_instance = self.connection_type(**self.connection_config_dict)
59+
return self.connection_instance
60+
61+
@contextlib.contextmanager
62+
def provide_connection(self, *args: Any, **kwargs: Any) -> "Iterator[BigQueryConnection]":
63+
"""Provide a BigQuery client within a context manager.
64+
65+
Args:
66+
*args: Additional arguments to pass to the connection.
67+
**kwargs: Additional keyword arguments to pass to the connection.
68+
69+
Yields:
70+
An iterator of BigQuery Client instances.
71+
"""
72+
conn = self.create_connection()
73+
yield conn
74+
75+
@contextlib.contextmanager
76+
def provide_session(self, *args: Any, **kwargs: Any) -> "Iterator[BigQueryDriver]":
77+
"""Provide a BigQuery driver session within a context manager.
78+
79+
Args:
80+
*args: Additional arguments to pass to the driver.
81+
**kwargs: Additional keyword arguments to pass to the driver.
82+
83+
Yields:
84+
An iterator of BigQueryDriver instances.
85+
"""
86+
conn = self.create_connection()
87+
yield self.driver_type(connection=conn)

0 commit comments

Comments
 (0)