|
1 | | -import logging |
2 | 1 | import decimal |
3 | 2 | from abc import ABC, abstractmethod |
4 | 3 | from typing import Sequence, Optional, Tuple, Union, Dict, List |
5 | 4 | from datetime import datetime |
6 | 5 |
|
7 | 6 | from runtype import dataclass |
8 | 7 |
|
9 | | -from ..utils import CaseAwareMapping, CaseInsensitiveDict, CaseSensitiveDict, ArithAlphanumeric, ArithUUID |
| 8 | +from ..utils import ArithAlphanumeric, ArithUUID |
10 | 9 |
|
11 | 10 |
|
12 | 11 | DbPath = Tuple[str, ...] |
13 | 12 | DbKey = Union[int, str, bytes, ArithUUID, ArithAlphanumeric] |
14 | 13 | DbTime = datetime |
15 | 14 |
|
16 | | -logger = logging.getLogger("databases") |
17 | | - |
18 | 15 |
|
19 | 16 | class ColType: |
20 | 17 | supported = True |
@@ -214,94 +211,6 @@ def parse_type( |
214 | 211 | "Parse type info as returned by the database" |
215 | 212 |
|
216 | 213 |
|
217 | | -class AbstractMixin_NormalizeValue(ABC): |
218 | | - @abstractmethod |
219 | | - def normalize_timestamp(self, value: str, coltype: TemporalType) -> str: |
220 | | - """Creates an SQL expression, that converts 'value' to a normalized timestamp. |
221 | | -
|
222 | | - The returned expression must accept any SQL datetime/timestamp, and return a string. |
223 | | -
|
224 | | - Date format: ``YYYY-MM-DD HH:mm:SS.FFFFFF`` |
225 | | -
|
226 | | - Precision of dates should be rounded up/down according to coltype.rounds |
227 | | - """ |
228 | | - ... |
229 | | - |
230 | | - @abstractmethod |
231 | | - def normalize_number(self, value: str, coltype: FractionalType) -> str: |
232 | | - """Creates an SQL expression, that converts 'value' to a normalized number. |
233 | | -
|
234 | | - The returned expression must accept any SQL int/numeric/float, and return a string. |
235 | | -
|
236 | | - Floats/Decimals are expected in the format |
237 | | - "I.P" |
238 | | -
|
239 | | - Where I is the integer part of the number (as many digits as necessary), |
240 | | - and must be at least one digit (0). |
241 | | - P is the fractional digits, the amount of which is specified with |
242 | | - coltype.precision. Trailing zeroes may be necessary. |
243 | | - If P is 0, the dot is omitted. |
244 | | -
|
245 | | - Note: We use 'precision' differently than most databases. For decimals, |
246 | | - it's the same as ``numeric_scale``, and for floats, who use binary precision, |
247 | | - it can be calculated as ``log10(2**numeric_precision)``. |
248 | | - """ |
249 | | - ... |
250 | | - |
251 | | - @abstractmethod |
252 | | - def normalize_uuid(self, value: str, coltype: ColType_UUID) -> str: |
253 | | - """Creates an SQL expression, that converts 'value' to a normalized uuid. |
254 | | -
|
255 | | - i.e. just makes sure there is no trailing whitespace. |
256 | | - """ |
257 | | - ... |
258 | | - |
259 | | - def normalize_boolean(self, value: str, coltype: Boolean) -> str: |
260 | | - """Creates an SQL expression, that converts 'value' to either '0' or '1'.""" |
261 | | - return self.to_string(value) |
262 | | - |
263 | | - def normalize_uuid(self, value: str, coltype: ColType_UUID) -> str: |
264 | | - """Creates an SQL expression, that strips uuids of artifacts like whitespace.""" |
265 | | - if isinstance(coltype, String_UUID): |
266 | | - return f"TRIM({value})" |
267 | | - return self.to_string(value) |
268 | | - |
269 | | - def normalize_value_by_type(self, value: str, coltype: ColType) -> str: |
270 | | - """Creates an SQL expression, that converts 'value' to a normalized representation. |
271 | | -
|
272 | | - The returned expression must accept any SQL value, and return a string. |
273 | | -
|
274 | | - The default implementation dispatches to a method according to `coltype`: |
275 | | -
|
276 | | - :: |
277 | | -
|
278 | | - TemporalType -> normalize_timestamp() |
279 | | - FractionalType -> normalize_number() |
280 | | - *else* -> to_string() |
281 | | -
|
282 | | - (`Integer` falls in the *else* category) |
283 | | -
|
284 | | - """ |
285 | | - if isinstance(coltype, TemporalType): |
286 | | - return self.normalize_timestamp(value, coltype) |
287 | | - elif isinstance(coltype, FractionalType): |
288 | | - return self.normalize_number(value, coltype) |
289 | | - elif isinstance(coltype, ColType_UUID): |
290 | | - return self.normalize_uuid(value, coltype) |
291 | | - elif isinstance(coltype, Boolean): |
292 | | - return self.normalize_boolean(value, coltype) |
293 | | - return self.to_string(value) |
294 | | - |
295 | | - |
296 | | -class AbstractMixin_MD5(ABC): |
297 | | - """Dialect-dependent query expressions, that are specific to data-diff""" |
298 | | - |
299 | | - @abstractmethod |
300 | | - def md5_as_int(self, s: str) -> str: |
301 | | - "Provide SQL for computing md5 and returning an int" |
302 | | - ... |
303 | | - |
304 | | - |
305 | 214 | class AbstractDatabase: |
306 | 215 | @property |
307 | 216 | @abstractmethod |
@@ -374,18 +283,3 @@ def _normalize_table_path(self, path: DbPath) -> DbPath: |
374 | 283 | @abstractmethod |
375 | 284 | def is_autocommit(self) -> bool: |
376 | 285 | "Return whether the database autocommits changes. When false, COMMIT statements are skipped." |
377 | | - |
378 | | - |
379 | | -Schema = CaseAwareMapping |
380 | | - |
381 | | - |
382 | | -def create_schema(db: AbstractDatabase, table_path: DbPath, schema: dict, case_sensitive: bool) -> CaseAwareMapping: |
383 | | - logger.debug(f"[{db.name}] Schema = {schema}") |
384 | | - |
385 | | - if case_sensitive: |
386 | | - return CaseSensitiveDict(schema) |
387 | | - |
388 | | - if len({k.lower() for k in schema}) < len(schema): |
389 | | - logger.warning(f'Ambiguous schema for {db}:{".".join(table_path)} | Columns = {", ".join(list(schema))}') |
390 | | - logger.warning("We recommend to disable case-insensitivity (set --case-sensitive).") |
391 | | - return CaseInsensitiveDict(schema) |
0 commit comments