Skip to content
This repository was archived by the owner on May 17, 2024. It is now read-only.

Commit 8472467

Browse files
authored
Merge pull request #714 from datafold/simplify-collapse-abcs
Squash the redundant abstract classes into their "base" counterparts
2 parents f3dc52b + 7aec378 commit 8472467

11 files changed

Lines changed: 208 additions & 480 deletions

File tree

data_diff/abcs/database_types.py

Lines changed: 1 addition & 255 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
import decimal
22
from abc import ABC, abstractmethod
3-
from typing import Sequence, Optional, Tuple, Union, Dict, List
3+
from typing import Tuple, Union
44
from datetime import datetime
55

66
from runtype import dataclass
7-
from typing_extensions import Self
87

9-
from data_diff.abcs.compiler import AbstractCompiler
108
from data_diff.utils import ArithAlphanumeric, ArithUUID, Unknown
119

1210

@@ -172,255 +170,3 @@ class UnknownColType(ColType):
172170
text: str
173171

174172
supported = False
175-
176-
177-
class AbstractDialect(ABC):
178-
"""Dialect-dependent query expressions"""
179-
180-
@abstractmethod
181-
def compile(self, compiler: AbstractCompiler, elem, params=None) -> str:
182-
raise NotImplementedError
183-
184-
@abstractmethod
185-
def parse_table_name(self, name: str) -> DbPath:
186-
"Parse the given table name into a DbPath"
187-
188-
@property
189-
@abstractmethod
190-
def name(self) -> str:
191-
"Name of the dialect"
192-
193-
@classmethod
194-
@abstractmethod
195-
def load_mixins(cls, *abstract_mixins) -> Self:
196-
"Load a list of mixins that implement the given abstract mixins"
197-
198-
@property
199-
@abstractmethod
200-
def ROUNDS_ON_PREC_LOSS(self) -> bool:
201-
"True if db rounds real values when losing precision, False if it truncates."
202-
203-
@abstractmethod
204-
def quote(self, s: str):
205-
"Quote SQL name"
206-
207-
@abstractmethod
208-
def concat(self, items: List[str]) -> str:
209-
"Provide SQL for concatenating a bunch of columns into a string"
210-
211-
@abstractmethod
212-
def is_distinct_from(self, a: str, b: str) -> str:
213-
"Provide SQL for a comparison where NULL = NULL is true"
214-
215-
@abstractmethod
216-
def to_string(self, s: str) -> str:
217-
# TODO rewrite using cast_to(x, str)
218-
"Provide SQL for casting a column to string"
219-
220-
@abstractmethod
221-
def random(self) -> str:
222-
"Provide SQL for generating a random number betweein 0..1"
223-
224-
@abstractmethod
225-
def current_timestamp(self) -> str:
226-
"Provide SQL for returning the current timestamp, aka now"
227-
228-
@abstractmethod
229-
def current_database(self) -> str:
230-
"Provide SQL for returning the current default database."
231-
232-
@abstractmethod
233-
def current_schema(self) -> str:
234-
"Provide SQL for returning the current default schema."
235-
236-
@abstractmethod
237-
def offset_limit(
238-
self, offset: Optional[int] = None, limit: Optional[int] = None, has_order_by: Optional[bool] = None
239-
) -> str:
240-
"Provide SQL fragment for limit and offset inside a select"
241-
242-
@abstractmethod
243-
def explain_as_text(self, query: str) -> str:
244-
"Provide SQL for explaining a query, returned as table(varchar)"
245-
246-
@abstractmethod
247-
def timestamp_value(self, t: datetime) -> str:
248-
"Provide SQL for the given timestamp value"
249-
250-
@abstractmethod
251-
def set_timezone_to_utc(self) -> str:
252-
"Provide SQL for setting the session timezone to UTC"
253-
254-
@abstractmethod
255-
def parse_type(
256-
self,
257-
table_path: DbPath,
258-
col_name: str,
259-
type_repr: str,
260-
datetime_precision: int = None,
261-
numeric_precision: int = None,
262-
numeric_scale: int = None,
263-
) -> ColType:
264-
"Parse type info as returned by the database"
265-
266-
@abstractmethod
267-
def to_comparable(self, value: str, coltype: ColType) -> str:
268-
"""Ensure that the expression is comparable in ``IS DISTINCT FROM``."""
269-
270-
271-
from typing import TypeVar, Generic
272-
273-
T_Dialect = TypeVar("T_Dialect", bound=AbstractDialect)
274-
275-
276-
class AbstractDatabase(Generic[T_Dialect]):
277-
@property
278-
@abstractmethod
279-
def dialect(self) -> T_Dialect:
280-
"The dialect of the database. Used internally by Database, and also available publicly."
281-
282-
@classmethod
283-
@abstractmethod
284-
def load_mixins(cls, *abstract_mixins) -> type:
285-
"Extend the dialect with a list of mixins that implement the given abstract mixins."
286-
287-
@property
288-
@abstractmethod
289-
def CONNECT_URI_HELP(self) -> str:
290-
"Example URI to show the user in help and error messages"
291-
292-
@property
293-
@abstractmethod
294-
def CONNECT_URI_PARAMS(self) -> List[str]:
295-
"List of parameters given in the path of the URI"
296-
297-
@abstractmethod
298-
def _query(self, sql_code: str) -> list:
299-
"Send query to database and return result"
300-
301-
@abstractmethod
302-
def query_table_schema(self, path: DbPath) -> Dict[str, tuple]:
303-
"""Query the table for its schema for table in 'path', and return {column: tuple}
304-
where the tuple is (table_name, col_name, type_repr, datetime_precision?, numeric_precision?, numeric_scale?)
305-
306-
Note: This method exists instead of select_table_schema(), just because not all databases support
307-
accessing the schema using a SQL query.
308-
"""
309-
310-
@abstractmethod
311-
def select_table_unique_columns(self, path: DbPath) -> str:
312-
"Provide SQL for selecting the names of unique columns in the table"
313-
314-
@abstractmethod
315-
def query_table_unique_columns(self, path: DbPath) -> List[str]:
316-
"""Query the table for its unique columns for table in 'path', and return {column}"""
317-
318-
@abstractmethod
319-
def _process_table_schema(
320-
self, path: DbPath, raw_schema: Dict[str, tuple], filter_columns: Sequence[str], where: str = None
321-
):
322-
"""Process the result of query_table_schema().
323-
324-
Done in a separate step, to minimize the amount of processed columns.
325-
Needed because processing each column may:
326-
* throw errors and warnings
327-
* query the database to sample values
328-
329-
"""
330-
331-
@abstractmethod
332-
def close(self):
333-
"Close connection(s) to the database instance. Querying will stop functioning."
334-
335-
@property
336-
@abstractmethod
337-
def is_autocommit(self) -> bool:
338-
"Return whether the database autocommits changes. When false, COMMIT statements are skipped."
339-
340-
341-
class AbstractTable(ABC):
342-
@abstractmethod
343-
def select(self, *exprs, distinct=False, **named_exprs) -> "AbstractTable":
344-
"""Choose new columns, based on the old ones. (aka Projection)
345-
346-
Parameters:
347-
exprs: List of expressions to constitute the columns of the new table.
348-
If not provided, returns all columns in source table (i.e. ``select *``)
349-
distinct: 'select' or 'select distinct'
350-
named_exprs: More expressions to constitute the columns of the new table, aliased to keyword name.
351-
352-
"""
353-
# XXX distinct=SKIP
354-
355-
@abstractmethod
356-
def where(self, *exprs) -> "AbstractTable":
357-
"""Filter the rows, based on the given predicates. (aka Selection)"""
358-
359-
@abstractmethod
360-
def order_by(self, *exprs) -> "AbstractTable":
361-
"""Order the rows lexicographically, according to the given expressions."""
362-
363-
@abstractmethod
364-
def limit(self, limit: int) -> "AbstractTable":
365-
"""Stop yielding rows after the given limit. i.e. take the first 'n=limit' rows"""
366-
367-
@abstractmethod
368-
def join(self, target) -> "AbstractTable":
369-
"""Join the current table with the target table, returning a new table containing both side-by-side.
370-
371-
When joining, it's recommended to use explicit tables names, instead of `this`, in order to avoid potential name collisions.
372-
373-
Example:
374-
::
375-
376-
person = table('person')
377-
city = table('city')
378-
379-
name_and_city = (
380-
person
381-
.join(city)
382-
.on(person['city_id'] == city['id'])
383-
.select(person['id'], city['name'])
384-
)
385-
"""
386-
387-
@abstractmethod
388-
def group_by(self, *keys):
389-
"""Behaves like in SQL, except for a small change in syntax:
390-
391-
A call to `.agg()` must follow every call to `.group_by()`.
392-
393-
Example:
394-
::
395-
396-
# SELECT a, sum(b) FROM tmp GROUP BY 1
397-
table('tmp').group_by(this.a).agg(this.b.sum())
398-
399-
# SELECT a, sum(b) FROM a GROUP BY 1 HAVING (b > 10)
400-
(table('tmp')
401-
.group_by(this.a)
402-
.agg(this.b.sum())
403-
.having(this.b > 10)
404-
)
405-
406-
"""
407-
408-
@abstractmethod
409-
def count(self) -> int:
410-
"""SELECT count() FROM self"""
411-
412-
@abstractmethod
413-
def union(self, other: "ITable"):
414-
"""SELECT * FROM self UNION other"""
415-
416-
@abstractmethod
417-
def union_all(self, other: "ITable"):
418-
"""SELECT * FROM self UNION ALL other"""
419-
420-
@abstractmethod
421-
def minus(self, other: "ITable"):
422-
"""SELECT * FROM self EXCEPT other"""
423-
424-
@abstractmethod
425-
def intersect(self, other: "ITable"):
426-
"""SELECT * FROM self INTERSECT other"""

data_diff/abcs/mixins.py

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,12 +134,6 @@ def list_tables(self, table_schema: str, like: Compilable = None) -> Compilable:
134134
"""
135135

136136

137-
class AbstractMixin_Regex(AbstractMixin):
138-
@abstractmethod
139-
def test_regex(self, string: Compilable, pattern: Compilable) -> Compilable:
140-
"""Tests whether the regex pattern matches the string. Returns a bool expression."""
141-
142-
143137
class AbstractMixin_RandomSample(AbstractMixin):
144138
@abstractmethod
145139
def random_sample_n(self, tbl: str, size: int) -> str:
@@ -152,7 +146,7 @@ def random_sample_ratio_approx(self, tbl: str, ratio: float) -> str:
152146
i.e. the actual mount of rows returned may vary by standard deviation.
153147
"""
154148

155-
# def random_sample_ratio(self, table: AbstractTable, ratio: float):
149+
# def random_sample_ratio(self, table: ITable, ratio: float):
156150
# """Take a random sample of the size determined by the ratio (0..1), where 0 means no rows, and 1 means all rows
157151
# """
158152

data_diff/bound_exprs.py

Lines changed: 0 additions & 94 deletions
This file was deleted.

0 commit comments

Comments
 (0)