sqlframe 3.13.4__py3-none-any.whl → 3.14.1__py3-none-any.whl

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.
sqlframe/base/table.py ADDED
@@ -0,0 +1,238 @@
1
+ import sys
2
+ import typing as t
3
+ from enum import IntEnum
4
+ from uuid import uuid4
5
+
6
+ from sqlglot import exp
7
+ from sqlglot.expressions import _to_s
8
+ from sqlglot.helper import object_to_dict
9
+
10
+ from sqlframe.base.dataframe import DF, SESSION, BaseDataFrame
11
+
12
+ if sys.version_info >= (3, 11):
13
+ from typing import Self
14
+ else:
15
+ from typing_extensions import Self
16
+
17
+ if t.TYPE_CHECKING:
18
+ from sqlframe.base._typing import ColumnOrLiteral
19
+ from sqlframe.base.column import Column
20
+ from sqlframe.base.types import Row
21
+
22
+
23
+ class Clause(IntEnum):
24
+ UPDATE = 1
25
+ UPDATE_ALL = 2
26
+ DELETE = 3
27
+ INSERT = 4
28
+ INSERT_ALL = 5
29
+
30
+
31
+ class MergeClause:
32
+ def __init__(
33
+ self,
34
+ clause_type: Clause,
35
+ condition: t.Optional[t.Union[str, t.List[str], "Column", t.List["Column"], bool]] = None,
36
+ assignments: t.Optional[
37
+ t.Dict[t.Union["Column", str], t.Union["Column", "ColumnOrLiteral", exp.Expression]]
38
+ ] = None,
39
+ matched: bool = True,
40
+ by_source: bool = False,
41
+ ):
42
+ self.clause_type = clause_type
43
+ self.condition = condition
44
+ self.assignments = assignments
45
+ self.matched = matched
46
+ self.by_source = by_source
47
+
48
+
49
+ class WhenMatched:
50
+ def __init__(
51
+ self,
52
+ condition: t.Optional[t.Union[str, t.List[str], "Column", t.List["Column"], bool]] = None,
53
+ ):
54
+ self._condition = condition
55
+ self._clause: t.Union[MergeClause, None] = None
56
+
57
+ def update(
58
+ self,
59
+ set_: t.Dict[t.Union["Column", str], t.Union["Column", "ColumnOrLiteral", exp.Expression]],
60
+ ) -> Self:
61
+ if self._clause:
62
+ clause = self._clause.clause_type.name.lower()
63
+ raise ValueError(f"WhenMatched already has an '{clause}' clause")
64
+ self._clause = MergeClause(
65
+ Clause.UPDATE,
66
+ self._condition,
67
+ {k: v for k, v in set_.items()},
68
+ matched=True,
69
+ by_source=False,
70
+ )
71
+ return self
72
+
73
+ def update_all(self) -> Self:
74
+ if self._clause:
75
+ clause = self._clause.clause_type.name.lower()
76
+ raise ValueError(f"WhenMatched already has an '{clause}' clause")
77
+ self._clause = MergeClause(
78
+ Clause.UPDATE_ALL,
79
+ self._condition,
80
+ {},
81
+ matched=True,
82
+ by_source=False,
83
+ )
84
+ return self
85
+
86
+ def delete(self) -> Self:
87
+ if self._clause:
88
+ clause = self._clause.clause_type.name.lower()
89
+ raise ValueError(f"WhenMatched already has an '{clause}' clause")
90
+ self._clause = MergeClause(Clause.DELETE, self._condition, matched=True, by_source=False)
91
+ return self
92
+
93
+ @property
94
+ def clause(self):
95
+ return self._clause
96
+
97
+
98
+ class WhenNotMatched:
99
+ def __init__(
100
+ self,
101
+ condition: t.Optional[t.Union[str, t.List[str], "Column", t.List["Column"], bool]] = None,
102
+ ):
103
+ self._condition = condition
104
+ self._clause: t.Union[MergeClause, None] = None
105
+
106
+ def insert(
107
+ self,
108
+ values: t.Dict[
109
+ t.Union["Column", str], t.Union["Column", "ColumnOrLiteral", exp.Expression]
110
+ ],
111
+ ) -> Self:
112
+ if self._clause:
113
+ clause = self._clause.clause_type.name.lower()
114
+ raise ValueError(f"WhenNotMatched already has an '{clause}' clause")
115
+ self._clause = MergeClause(
116
+ Clause.INSERT,
117
+ self._condition,
118
+ {k: v for k, v in values.items()},
119
+ matched=False,
120
+ by_source=False,
121
+ )
122
+ return self
123
+
124
+ def insert_all(self) -> Self:
125
+ if self._clause:
126
+ clause = self._clause.clause_type.name.lower()
127
+ raise ValueError(f"WhenNotMatched already has an '{clause}' clause")
128
+ self._clause = MergeClause(
129
+ Clause.INSERT_ALL,
130
+ self._condition,
131
+ {},
132
+ matched=False,
133
+ by_source=False,
134
+ )
135
+ return self
136
+
137
+ @property
138
+ def clause(self):
139
+ return self._clause
140
+
141
+
142
+ class WhenNotMatchedBySource(object):
143
+ def __init__(
144
+ self,
145
+ condition: t.Optional[t.Union[str, t.List[str], "Column", t.List["Column"], bool]] = None,
146
+ ):
147
+ self._condition = condition
148
+ self._clause: t.Union[MergeClause, None] = None
149
+
150
+ def update(
151
+ self,
152
+ set_: t.Dict[t.Union["Column", str], t.Union["Column", "ColumnOrLiteral", exp.Expression]],
153
+ ) -> Self:
154
+ if self._clause:
155
+ clause = self._clause.clause_type.name.lower()
156
+ raise ValueError(f"WhenNotMatchedBySource already has an '{clause}' clause")
157
+ self._clause = MergeClause(
158
+ Clause.UPDATE,
159
+ self._condition,
160
+ {k: v for k, v in set_.items()},
161
+ matched=False,
162
+ by_source=True,
163
+ )
164
+ return self
165
+
166
+ def delete(self) -> Self:
167
+ if self._clause:
168
+ clause = self._clause.clause_type.name.lower()
169
+ raise ValueError(f"WhenNotMatchedBySource already has an '{clause}' clause")
170
+ self._clause = MergeClause(Clause.DELETE, self._condition, matched=False, by_source=True)
171
+ return self
172
+
173
+ @property
174
+ def clause(self):
175
+ return self._clause
176
+
177
+
178
+ class LazyExpression:
179
+ def __init__(
180
+ self,
181
+ expression: exp.Expression,
182
+ session: SESSION,
183
+ ):
184
+ self._expression = expression
185
+ self._session = session
186
+
187
+ def execute(self) -> t.List["Row"]:
188
+ return self._session._collect(self._expression)
189
+
190
+ @property
191
+ def expression(self) -> exp.Expression:
192
+ return self._expression
193
+
194
+ def __str__(self) -> str:
195
+ return self._expression.sql()
196
+
197
+ def __repr__(self) -> str:
198
+ return _to_s(self._expression)
199
+
200
+
201
+ class _BaseTable(BaseDataFrame, t.Generic[DF]):
202
+ _df: t.Type[DF]
203
+
204
+ def copy(self, **kwargs):
205
+ kwargs["join_on_uuid"] = str(uuid4())
206
+ return self._df(**object_to_dict(self, **kwargs))
207
+
208
+ def __copy__(self):
209
+ return self.copy()
210
+
211
+ def table_copy(self):
212
+ return self.__class__(**object_to_dict(self))
213
+
214
+ def alias(self, name: str, **kwargs) -> Self:
215
+ df = BaseDataFrame.alias(self, name, **kwargs)
216
+ new_df = self.__class__(**object_to_dict(df))
217
+ return new_df
218
+
219
+ def update(
220
+ self,
221
+ set_: t.Dict[t.Union["Column", str], t.Union["Column", "ColumnOrLiteral", exp.Expression]],
222
+ where: t.Optional[t.Union["Column", str, bool]] = None,
223
+ ) -> LazyExpression:
224
+ raise NotImplementedError()
225
+
226
+ def merge(
227
+ self,
228
+ source: DF,
229
+ condition: t.Union[str, t.List[str], "Column", t.List["Column"], bool],
230
+ clauses: t.Iterable[t.Union[WhenMatched, WhenNotMatched, WhenNotMatchedBySource]],
231
+ ) -> LazyExpression:
232
+ raise NotImplementedError()
233
+
234
+ def delete(
235
+ self,
236
+ where: t.Optional[t.Union["Column", str, bool]] = None,
237
+ ) -> LazyExpression:
238
+ raise NotImplementedError()
@@ -51,6 +51,7 @@ class BigQueryCatalog(
51
51
  from_dialect=self.session.execution_dialect,
52
52
  to_dialect=self.session.output_dialect,
53
53
  is_schema=True,
54
+ quote_identifiers=True,
54
55
  )
55
56
  return to_schema(current_database, dialect=self.session.output_dialect).db
56
57
 
@@ -13,11 +13,12 @@ from sqlframe.base.readerwriter import (
13
13
  if t.TYPE_CHECKING:
14
14
  from sqlframe.bigquery.session import BigQuerySession # noqa
15
15
  from sqlframe.bigquery.dataframe import BigQueryDataFrame # noqa
16
+ from sqlframe.bigquery.table import BigQueryTable # noqa
16
17
 
17
18
 
18
19
  class BigQueryDataFrameReader(
19
20
  PandasLoaderMixin["BigQuerySession", "BigQueryDataFrame"],
20
- _BaseDataFrameReader["BigQuerySession", "BigQueryDataFrame"],
21
+ _BaseDataFrameReader["BigQuerySession", "BigQueryDataFrame", "BigQueryTable"],
21
22
  ):
22
23
  pass
23
24
 
@@ -9,6 +9,7 @@ from sqlframe.bigquery.readwriter import (
9
9
  BigQueryDataFrameReader,
10
10
  BigQueryDataFrameWriter,
11
11
  )
12
+ from sqlframe.bigquery.table import BigQueryTable
12
13
  from sqlframe.bigquery.udf import BigQueryUDFRegistration
13
14
 
14
15
  if t.TYPE_CHECKING:
@@ -25,6 +26,7 @@ class BigQuerySession(
25
26
  BigQueryDataFrameReader,
26
27
  BigQueryDataFrameWriter,
27
28
  BigQueryDataFrame,
29
+ BigQueryTable,
28
30
  BigQueryConnection,
29
31
  BigQueryUDFRegistration,
30
32
  ],
@@ -33,6 +35,7 @@ class BigQuerySession(
33
35
  _reader = BigQueryDataFrameReader
34
36
  _writer = BigQueryDataFrameWriter
35
37
  _df = BigQueryDataFrame
38
+ _table = BigQueryTable
36
39
  _udf_registration = BigQueryUDFRegistration
37
40
 
38
41
  QUALIFY_INFO_SCHEMA_WITH_DATABASE = True
@@ -0,0 +1,24 @@
1
+ from sqlframe.base.mixins.table_mixins import (
2
+ DeleteSupportMixin,
3
+ MergeSupportMixin,
4
+ UpdateSupportMixin,
5
+ )
6
+ from sqlframe.base.table import (
7
+ WhenMatched,
8
+ WhenNotMatched,
9
+ WhenNotMatchedBySource,
10
+ _BaseTable,
11
+ )
12
+ from sqlframe.bigquery.dataframe import BigQueryDataFrame
13
+
14
+
15
+ class BigQueryTable(
16
+ BigQueryDataFrame,
17
+ UpdateSupportMixin["BigQueryDataFrame"],
18
+ DeleteSupportMixin["BigQueryDataFrame"],
19
+ MergeSupportMixin["BigQueryDataFrame"],
20
+ _BaseTable["BigQueryDataFrame"],
21
+ ):
22
+ _df = BigQueryDataFrame
23
+ _merge_supported_clauses = [WhenMatched, WhenNotMatched, WhenNotMatchedBySource]
24
+ _merge_support_star = False
@@ -23,11 +23,12 @@ from sqlframe.base.util import normalize_string
23
23
  if t.TYPE_CHECKING:
24
24
  from sqlframe.databricks.session import DatabricksSession # noqa
25
25
  from sqlframe.databricks.dataframe import DatabricksDataFrame # noqa
26
+ from sqlframe.databricks.table import DatabricksTable # noqa
26
27
 
27
28
 
28
29
  class DatabricksDataFrameReader(
29
30
  PandasLoaderMixin["DatabricksSession", "DatabricksDataFrame"],
30
- _BaseDataFrameReader["DatabricksSession", "DatabricksDataFrame"],
31
+ _BaseDataFrameReader["DatabricksSession", "DatabricksDataFrame", "DatabricksTable"],
31
32
  ):
32
33
  pass
33
34
 
@@ -10,6 +10,7 @@ from sqlframe.databricks.readwriter import (
10
10
  DatabricksDataFrameReader,
11
11
  DatabricksDataFrameWriter,
12
12
  )
13
+ from sqlframe.databricks.table import DatabricksTable
13
14
  from sqlframe.databricks.udf import DatabricksUDFRegistration
14
15
 
15
16
  if t.TYPE_CHECKING:
@@ -24,6 +25,7 @@ class DatabricksSession(
24
25
  DatabricksDataFrameReader,
25
26
  DatabricksDataFrameWriter,
26
27
  DatabricksDataFrame,
28
+ DatabricksTable,
27
29
  DatabricksConnection,
28
30
  DatabricksUDFRegistration,
29
31
  ],
@@ -32,6 +34,7 @@ class DatabricksSession(
32
34
  _reader = DatabricksDataFrameReader
33
35
  _writer = DatabricksDataFrameWriter
34
36
  _df = DatabricksDataFrame
37
+ _table = DatabricksTable
35
38
  _udf_registration = DatabricksUDFRegistration
36
39
 
37
40
  def __init__(
@@ -0,0 +1,24 @@
1
+ from sqlframe.base.mixins.table_mixins import (
2
+ DeleteSupportMixin,
3
+ MergeSupportMixin,
4
+ UpdateSupportMixin,
5
+ )
6
+ from sqlframe.base.table import (
7
+ WhenMatched,
8
+ WhenNotMatched,
9
+ WhenNotMatchedBySource,
10
+ _BaseTable,
11
+ )
12
+ from sqlframe.databricks.dataframe import DatabricksDataFrame
13
+
14
+
15
+ class DatabricksTable(
16
+ DatabricksDataFrame,
17
+ UpdateSupportMixin["DatabricksDataFrame"],
18
+ DeleteSupportMixin["DatabricksDataFrame"],
19
+ MergeSupportMixin["DatabricksDataFrame"],
20
+ _BaseTable["DatabricksDataFrame"],
21
+ ):
22
+ _df = DatabricksDataFrame
23
+ _merge_supported_clauses = [WhenMatched, WhenNotMatched, WhenNotMatchedBySource]
24
+ _merge_support_star = True
@@ -16,11 +16,14 @@ if t.TYPE_CHECKING:
16
16
  from sqlframe.base.types import StructType
17
17
  from sqlframe.duckdb.dataframe import DuckDBDataFrame
18
18
  from sqlframe.duckdb.session import DuckDBSession # noqa
19
+ from sqlframe.duckdb.table import DuckDBTable # noqa
19
20
 
20
21
  logger = logging.getLogger(__name__)
21
22
 
22
23
 
23
- class DuckDBDataFrameReader(_BaseDataFrameReader["DuckDBSession", "DuckDBDataFrame"]):
24
+ class DuckDBDataFrameReader(
25
+ _BaseDataFrameReader["DuckDBSession", "DuckDBDataFrame", "DuckDBTable"]
26
+ ):
24
27
  def load(
25
28
  self,
26
29
  path: t.Optional[PathOrPaths] = None,
@@ -11,6 +11,7 @@ from sqlframe.duckdb.readwriter import (
11
11
  DuckDBDataFrameReader,
12
12
  DuckDBDataFrameWriter,
13
13
  )
14
+ from sqlframe.duckdb.table import DuckDBTable
14
15
  from sqlframe.duckdb.udf import DuckDBUDFRegistration
15
16
 
16
17
  if t.TYPE_CHECKING:
@@ -26,6 +27,7 @@ class DuckDBSession(
26
27
  DuckDBDataFrameReader,
27
28
  DuckDBDataFrameWriter,
28
29
  DuckDBDataFrame,
30
+ DuckDBTable,
29
31
  DuckDBPyConnection,
30
32
  DuckDBUDFRegistration,
31
33
  ]
@@ -34,6 +36,7 @@ class DuckDBSession(
34
36
  _reader = DuckDBDataFrameReader
35
37
  _writer = DuckDBDataFrameWriter
36
38
  _df = DuckDBDataFrame
39
+ _table = DuckDBTable
37
40
  _udf_registration = DuckDBUDFRegistration
38
41
 
39
42
  def __init__(self, conn: t.Optional[DuckDBPyConnection] = None, *args, **kwargs):
@@ -0,0 +1,16 @@
1
+ from sqlframe.base.mixins.table_mixins import (
2
+ DeleteSupportMixin,
3
+ MergeSupportMixin,
4
+ UpdateSupportMixin,
5
+ )
6
+ from sqlframe.base.table import _BaseTable
7
+ from sqlframe.duckdb.dataframe import DuckDBDataFrame
8
+
9
+
10
+ class DuckDBTable(
11
+ DuckDBDataFrame,
12
+ UpdateSupportMixin["DuckDBDataFrame"],
13
+ DeleteSupportMixin["DuckDBDataFrame"],
14
+ _BaseTable["DuckDBDataFrame"],
15
+ ):
16
+ _df = DuckDBDataFrame
@@ -13,11 +13,12 @@ from sqlframe.base.readerwriter import (
13
13
  if t.TYPE_CHECKING:
14
14
  from sqlframe.postgres.session import PostgresSession # noqa
15
15
  from sqlframe.postgres.dataframe import PostgresDataFrame # noqa
16
+ from sqlframe.postgres.table import PostgresTable # noqa
16
17
 
17
18
 
18
19
  class PostgresDataFrameReader(
19
20
  PandasLoaderMixin["PostgresSession", "PostgresDataFrame"],
20
- _BaseDataFrameReader["PostgresSession", "PostgresDataFrame"],
21
+ _BaseDataFrameReader["PostgresSession", "PostgresDataFrame", "PostgresTable"],
21
22
  ):
22
23
  pass
23
24
 
@@ -11,6 +11,7 @@ from sqlframe.postgres.readwriter import (
11
11
  PostgresDataFrameReader,
12
12
  PostgresDataFrameWriter,
13
13
  )
14
+ from sqlframe.postgres.table import PostgresTable
14
15
  from sqlframe.postgres.udf import PostgresUDFRegistration
15
16
 
16
17
  if t.TYPE_CHECKING:
@@ -27,6 +28,7 @@ class PostgresSession(
27
28
  PostgresDataFrameReader,
28
29
  PostgresDataFrameWriter,
29
30
  PostgresDataFrame,
31
+ PostgresTable,
30
32
  psycopg2_connection,
31
33
  PostgresUDFRegistration,
32
34
  ],
@@ -35,6 +37,7 @@ class PostgresSession(
35
37
  _reader = PostgresDataFrameReader
36
38
  _writer = PostgresDataFrameWriter
37
39
  _df = PostgresDataFrame
40
+ _table = PostgresTable
38
41
  _udf_registration = PostgresUDFRegistration
39
42
 
40
43
  def __init__(self, conn: t.Optional[psycopg2_connection] = None):
@@ -0,0 +1,24 @@
1
+ from sqlframe.base.mixins.table_mixins import (
2
+ DeleteSupportMixin,
3
+ MergeSupportMixin,
4
+ UpdateSupportMixin,
5
+ )
6
+ from sqlframe.base.table import (
7
+ WhenMatched,
8
+ WhenNotMatched,
9
+ WhenNotMatchedBySource,
10
+ _BaseTable,
11
+ )
12
+ from sqlframe.postgres.dataframe import PostgresDataFrame
13
+
14
+
15
+ class PostgresTable(
16
+ PostgresDataFrame,
17
+ UpdateSupportMixin["PostgresDataFrame"],
18
+ DeleteSupportMixin["PostgresDataFrame"],
19
+ MergeSupportMixin["PostgresDataFrame"],
20
+ _BaseTable["PostgresDataFrame"],
21
+ ):
22
+ _df = PostgresDataFrame
23
+ _merge_supported_clauses = [WhenMatched, WhenNotMatched, WhenNotMatchedBySource]
24
+ _merge_support_star = False
@@ -13,11 +13,12 @@ from sqlframe.base.readerwriter import (
13
13
  if t.TYPE_CHECKING:
14
14
  from sqlframe.redshift.session import RedshiftSession # noqa
15
15
  from sqlframe.redshift.dataframe import RedshiftDataFrame # noqa
16
+ from sqlframe.redshift.table import RedshiftTable # noqa
16
17
 
17
18
 
18
19
  class RedshiftDataFrameReader(
19
20
  PandasLoaderMixin["RedshiftSession", "RedshiftDataFrame"],
20
- _BaseDataFrameReader["RedshiftSession", "RedshiftDataFrame"],
21
+ _BaseDataFrameReader["RedshiftSession", "RedshiftDataFrame", "RedshiftTable"],
21
22
  ):
22
23
  pass
23
24
 
@@ -10,6 +10,7 @@ from sqlframe.redshift.readwriter import (
10
10
  RedshiftDataFrameReader,
11
11
  RedshiftDataFrameWriter,
12
12
  )
13
+ from sqlframe.redshift.table import RedshiftTable
13
14
  from sqlframe.redshift.udf import RedshiftUDFRegistration
14
15
 
15
16
  if t.TYPE_CHECKING:
@@ -24,6 +25,7 @@ class RedshiftSession(
24
25
  RedshiftDataFrameReader,
25
26
  RedshiftDataFrameWriter,
26
27
  RedshiftDataFrame,
28
+ RedshiftTable,
27
29
  RedshiftConnection,
28
30
  RedshiftUDFRegistration,
29
31
  ],
@@ -32,6 +34,7 @@ class RedshiftSession(
32
34
  _reader = RedshiftDataFrameReader
33
35
  _writer = RedshiftDataFrameWriter
34
36
  _df = RedshiftDataFrame
37
+ _table = RedshiftTable
35
38
  _udf_registration = RedshiftUDFRegistration
36
39
 
37
40
  def __init__(self, conn: t.Optional[RedshiftConnection] = None):
@@ -0,0 +1,15 @@
1
+ from sqlframe.base.mixins.table_mixins import (
2
+ DeleteSupportMixin,
3
+ UpdateSupportMixin,
4
+ )
5
+ from sqlframe.base.table import _BaseTable
6
+ from sqlframe.redshift.dataframe import RedshiftDataFrame
7
+
8
+
9
+ class RedshiftTable(
10
+ RedshiftDataFrame,
11
+ UpdateSupportMixin["RedshiftDataFrame"],
12
+ DeleteSupportMixin["RedshiftDataFrame"],
13
+ _BaseTable["RedshiftDataFrame"],
14
+ ):
15
+ _df = RedshiftDataFrame
@@ -13,11 +13,12 @@ from sqlframe.base.readerwriter import (
13
13
  if t.TYPE_CHECKING:
14
14
  from sqlframe.snowflake.session import SnowflakeSession # noqa
15
15
  from sqlframe.snowflake.dataframe import SnowflakeDataFrame # noqa
16
+ from sqlframe.snowflake.table import SnowflakeTable # noqa
16
17
 
17
18
 
18
19
  class SnowflakeDataFrameReader(
19
20
  PandasLoaderMixin["SnowflakeSession", "SnowflakeDataFrame"],
20
- _BaseDataFrameReader["SnowflakeSession", "SnowflakeDataFrame"],
21
+ _BaseDataFrameReader["SnowflakeSession", "SnowflakeDataFrame", "SnowflakeTable"],
21
22
  ):
22
23
  pass
23
24
 
@@ -18,6 +18,7 @@ from sqlframe.snowflake.readwriter import (
18
18
  SnowflakeDataFrameReader,
19
19
  SnowflakeDataFrameWriter,
20
20
  )
21
+ from sqlframe.snowflake.table import SnowflakeTable
21
22
 
22
23
  if t.TYPE_CHECKING:
23
24
  from snowflake.connector import SnowflakeConnection
@@ -51,6 +52,7 @@ class SnowflakeSession(
51
52
  SnowflakeDataFrameReader,
52
53
  SnowflakeDataFrameWriter,
53
54
  SnowflakeDataFrame,
55
+ SnowflakeTable,
54
56
  SnowflakeConnection,
55
57
  SnowflakeUDFRegistration,
56
58
  ],
@@ -59,6 +61,7 @@ class SnowflakeSession(
59
61
  _reader = SnowflakeDataFrameReader
60
62
  _writer = SnowflakeDataFrameWriter
61
63
  _df = SnowflakeDataFrame
64
+ _table = SnowflakeTable
62
65
  _udf_registration = SnowflakeUDFRegistration
63
66
 
64
67
  def __init__(self, conn: t.Optional[SnowflakeConnection] = None):
@@ -0,0 +1,23 @@
1
+ from sqlframe.base.mixins.table_mixins import (
2
+ DeleteSupportMixin,
3
+ MergeSupportMixin,
4
+ UpdateSupportMixin,
5
+ )
6
+ from sqlframe.base.table import (
7
+ WhenMatched,
8
+ WhenNotMatched,
9
+ _BaseTable,
10
+ )
11
+ from sqlframe.snowflake.dataframe import SnowflakeDataFrame
12
+
13
+
14
+ class SnowflakeTable(
15
+ SnowflakeDataFrame,
16
+ UpdateSupportMixin["SnowflakeDataFrame"],
17
+ DeleteSupportMixin["SnowflakeDataFrame"],
18
+ MergeSupportMixin["SnowflakeDataFrame"],
19
+ _BaseTable["SnowflakeDataFrame"],
20
+ ):
21
+ _df = SnowflakeDataFrame
22
+ _merge_supported_clauses = [WhenMatched, WhenNotMatched]
23
+ _merge_support_star = False
@@ -13,11 +13,12 @@ from sqlframe.base.readerwriter import (
13
13
  if t.TYPE_CHECKING:
14
14
  from sqlframe.spark.dataframe import SparkDataFrame
15
15
  from sqlframe.spark.session import SparkSession
16
+ from sqlframe.spark.table import SparkTable
16
17
 
17
18
 
18
19
  class SparkDataFrameReader(
19
20
  PandasLoaderMixin["SparkSession", "SparkDataFrame"],
20
- _BaseDataFrameReader["SparkSession", "SparkDataFrame"],
21
+ _BaseDataFrameReader["SparkSession", "SparkDataFrame", "SparkTable"],
21
22
  ):
22
23
  pass
23
24
 
sqlframe/spark/session.py CHANGED
@@ -13,6 +13,7 @@ from sqlframe.spark.readwriter import (
13
13
  SparkDataFrameReader,
14
14
  SparkDataFrameWriter,
15
15
  )
16
+ from sqlframe.spark.table import SparkTable
16
17
  from sqlframe.spark.types import Row
17
18
  from sqlframe.spark.udf import SparkUDFRegistration
18
19
 
@@ -32,6 +33,7 @@ class SparkSession(
32
33
  SparkDataFrameReader,
33
34
  SparkDataFrameWriter,
34
35
  SparkDataFrame,
36
+ SparkTable,
35
37
  PySparkSession,
36
38
  SparkUDFRegistration,
37
39
  ],
@@ -40,6 +42,7 @@ class SparkSession(
40
42
  _reader = SparkDataFrameReader
41
43
  _writer = SparkDataFrameWriter
42
44
  _df = SparkDataFrame
45
+ _table = SparkTable
43
46
  _udf_registration = SparkUDFRegistration
44
47
 
45
48
  def __init__(self, conn: t.Optional[PySparkSession] = None, *args, **kwargs):
@@ -0,0 +1,6 @@
1
+ from sqlframe.base.table import _BaseTable
2
+ from sqlframe.spark.dataframe import SparkDataFrame
3
+
4
+
5
+ class SparkTable(SparkDataFrame, _BaseTable["SparkDataFrame"]):
6
+ _df = SparkDataFrame
@@ -9,9 +9,12 @@ from sqlframe.base.readerwriter import _BaseDataFrameReader, _BaseDataFrameWrite
9
9
  if t.TYPE_CHECKING:
10
10
  from sqlframe.standalone.dataframe import StandaloneDataFrame
11
11
  from sqlframe.standalone.session import StandaloneSession
12
+ from sqlframe.standalone.table import StandaloneTable
12
13
 
13
14
 
14
- class StandaloneDataFrameReader(_BaseDataFrameReader["StandaloneSession", "StandaloneDataFrame"]):
15
+ class StandaloneDataFrameReader(
16
+ _BaseDataFrameReader["StandaloneSession", "StandaloneDataFrame", "StandaloneTable"]
17
+ ):
15
18
  pass
16
19
 
17
20