meerschaum.utils.dtypes.sql
Utility functions for working with SQL data types.
1#! /usr/bin/env python3 2# -*- coding: utf-8 -*- 3# vim:fenc=utf-8 4 5""" 6Utility functions for working with SQL data types. 7""" 8 9from __future__ import annotations 10from meerschaum.utils.typing import Dict, Union, Tuple, Optional 11from meerschaum._internal.static import STATIC_CONFIG as _STATIC_CONFIG 12from meerschaum import _core 13from meerschaum.utils.dtypes import MRSM_PRECISION_UNITS_ABBREVIATIONS as _MRSM_PRECISION_UNITS_ABBREVIATIONS 14 15NUMERIC_PRECISION_FLAVORS: Dict[str, Tuple[int, int]] = { 16 'mariadb': (38, 20), 17 'mysql': (38, 20), 18 'mssql': (28, 10), 19} 20TIMEZONE_NAIVE_FLAVORS = {'oracle', 'mysql', 'mariadb'} 21 22### MySQL doesn't allow for casting as BIGINT, so this is a workaround. 23DB_FLAVORS_CAST_DTYPES = { 24 'mariadb': { 25 'BIGINT': 'DECIMAL', 26 'TINYINT': 'SIGNED INT', 27 'TEXT': 'CHAR(10000) CHARACTER SET utf8', 28 'BOOL': 'SIGNED INT', 29 'BOOLEAN': 'SIGNED INT', 30 'DOUBLE PRECISION': 'DECIMAL', 31 'DOUBLE': 'DECIMAL', 32 'FLOAT': 'DECIMAL', 33 }, 34 'mysql': { 35 'BIGINT': 'DECIMAL', 36 'TINYINT': 'SIGNED INT', 37 'TEXT': 'CHAR(10000) CHARACTER SET utf8', 38 'INT': 'SIGNED INT', 39 'INTEGER': 'SIGNED INT', 40 'BOOL': 'SIGNED INT', 41 'BOOLEAN': 'SIGNED INT', 42 'DOUBLE PRECISION': 'DECIMAL', 43 'DOUBLE': 'DECIMAL', 44 'FLOAT': 'DECIMAL', 45 }, 46 'sqlite': { 47 'BOOLEAN': 'INTEGER', 48 'REAL': 'FLOAT', 49 }, 50 'geopackage': { 51 'BOOLEAN': 'INTEGER', 52 'REAL': 'FLOAT', 53 }, 54 'oracle': { 55 'NVARCHAR(2000)': 'NVARCHAR2(2000)', 56 'NVARCHAR': 'NVARCHAR2(2000)', 57 'NVARCHAR2': 'NVARCHAR2(2000)', 58 'CHAR': 'CHAR(36)', # UUID columns 59 }, 60 'mssql': { 61 'NVARCHAR COLLATE "SQL Latin1 General CP1 CI AS"': 'NVARCHAR(MAX)', 62 'NVARCHAR COLLATE "SQL_Latin1_General_CP1_CI_AS"': 'NVARCHAR(MAX)', 63 'VARCHAR COLLATE "SQL Latin1 General CP1 CI AS"': 'NVARCHAR(MAX)', 64 'VARCHAR COLLATE "SQL_Latin1_General_CP1_CI_AS"': 'NVARCHAR(MAX)', 65 'NVARCHAR': 'NVARCHAR(MAX)', 66 }, 67} 68for _flavor, (_precision, _scale) in NUMERIC_PRECISION_FLAVORS.items(): 69 if _flavor not in DB_FLAVORS_CAST_DTYPES: 70 DB_FLAVORS_CAST_DTYPES[_flavor] = {} 71 DB_FLAVORS_CAST_DTYPES[_flavor].update({ 72 'NUMERIC': f"NUMERIC({_precision}, {_scale})", 73 'DECIMAL': f"DECIMAL({_precision}, {_scale})", 74 }) 75 76_default_precision_unit = _STATIC_CONFIG['dtypes']['datetime']['default_precision_unit'] 77_default_precision_abbreviation = _MRSM_PRECISION_UNITS_ABBREVIATIONS[_default_precision_unit] 78 79DB_TO_PD_DTYPES: Dict[str, Union[str, Dict[str, str]]] = { 80 'FLOAT': 'float64[pyarrow]', 81 'REAL': 'float64[pyarrow]', 82 'DOUBLE_PRECISION': 'float64[pyarrow]', 83 'DOUBLE': 'float64[pyarrow]', 84 'DECIMAL': 'numeric', 85 'BIGINT': 'int64[pyarrow]', 86 'INT': 'int32[pyarrow]', 87 'INTEGER': 'int32[pyarrow]', 88 'NUMBER': 'numeric', 89 'NUMERIC': 'numeric', 90 'GEOMETRY': 'geometry', 91 'GEOMETRY(GEOMETRY)': 'geometry', 92 'TIMESTAMP': f'datetime64[{_default_precision_abbreviation}]', 93 'TIMESTAMP WITHOUT TIMEZONE': f'datetime64[{_default_precision_abbreviation}]', 94 'TIMESTAMP WITH TIMEZONE': f'datetime64[{_default_precision_abbreviation}, UTC]', 95 'TIMESTAMP WITH TIME ZONE': f'datetime64[{_default_precision_abbreviation}, UTC]', 96 'TIMESTAMPTZ': f'datetime64[{_default_precision_abbreviation}, UTC]', 97 'DATE': 'date', 98 'DATETIME': f'datetime64[{_default_precision_abbreviation}]', 99 'DATETIME2': 'datetime64[us]', 100 'DATETIME2(6)': 'datetime64[us]', 101 'DATETIME2(3)': 'datetime64[ms]', 102 'DATETIME2(0)': 'datetime64[s]', 103 'DATETIMEOFFSET': 'datetime64[us, UTC]', 104 'DATETIMEOFFSET(6)': 'datetime64[us, UTC]', 105 'DATETIMEOFFSET(3)': 'datetime64[ms, UTC]', 106 'DATETIMEOFFSET(0)': 'datetime64[s, UTC]', 107 'TEXT': 'string[pyarrow]', 108 'VARCHAR': 'string[pyarrow]', 109 'CLOB': 'string[pyarrow]', 110 'BOOL': 'bool[pyarrow]', 111 'BOOLEAN': 'bool[pyarrow]', 112 'BOOLEAN()': 'bool[pyarrow]', 113 'TINYINT': 'bool[pyarrow]', 114 'TINYINT(1)': 'bool[pyarrow]', 115 'BIT': 'bool[pyarrow]', 116 'BIT(1)': 'bool[pyarrow]', 117 'JSON': 'json', 118 'JSONB': 'json', 119 'UUID': 'uuid', 120 'UNIQUEIDENTIFIER': 'uuid', 121 'BYTEA': 'bytes', 122 'BLOB': 'bytes', 123 'VARBINARY': 'bytes', 124 'VARBINARY(MAX)': 'bytes', 125 'substrings': { 126 'CHAR': 'string[pyarrow]', 127 'TIMESTAMP': f'datetime64[{_default_precision_abbreviation}]', 128 'TIME': f'datetime64[{_default_precision_abbreviation}]', 129 'DATE': 'date', 130 'DOUBLE': 'double[pyarrow]', 131 'DECIMAL': 'numeric', 132 'NUMERIC': 'numeric', 133 'NUMBER': 'numeric', 134 'INT': 'int64[pyarrow]', 135 'BOOL': 'bool[pyarrow]', 136 'JSON': 'json', 137 'BYTE': 'bytes', 138 'LOB': 'bytes', 139 'BINARY': 'bytes', 140 'GEOMETRY': 'geometry', 141 'GEOGRAPHY': 'geography', 142 }, 143 'default': 'object', 144} 145### Map pandas dtypes to flavor-specific dtypes. 146PD_TO_DB_DTYPES_FLAVORS: Dict[str, Dict[str, str]] = { 147 'int': { 148 'timescaledb': 'BIGINT', 149 'timescaledb-ha': 'BIGINT', 150 'postgresql': 'BIGINT', 151 'postgis': 'BIGINT', 152 'mariadb': 'BIGINT', 153 'mysql': 'BIGINT', 154 'mssql': 'BIGINT', 155 'oracle': 'INT', 156 'sqlite': 'BIGINT', 157 'geopackage': 'BIGINT', 158 'duckdb': 'BIGINT', 159 'citus': 'BIGINT', 160 'cockroachdb': 'BIGINT', 161 'default': 'INT', 162 }, 163 'uint': { 164 'timescaledb': 'BIGINT', 165 'timescaledb-ha': 'BIGINT', 166 'postgresql': 'BIGINT', 167 'postgis': 'BIGINT', 168 'mariadb': 'BIGINT', 169 'mysql': 'BIGINT', 170 'mssql': 'BIGINT', 171 'oracle': 'INT', 172 'sqlite': 'BIGINT', 173 'geopackage': 'BIGINT', 174 'duckdb': 'BIGINT', 175 'citus': 'BIGINT', 176 'cockroachdb': 'BIGINT', 177 'default': 'INT', 178 }, 179 'int8': { 180 'timescaledb': 'SMALLINT', 181 'timescaledb-ha': 'SMALLINT', 182 'postgresql': 'SMALLINT', 183 'postgis': 'SMALLINT', 184 'mariadb': 'SMALLINT', 185 'mysql': 'SMALLINT', 186 'mssql': 'SMALLINT', 187 'oracle': 'INT', 188 'sqlite': 'INT', 189 'geopackage': 'INT', 190 'duckdb': 'SMALLINT', 191 'citus': 'SMALLINT', 192 'cockroachdb': 'SMALLINT', 193 'default': 'INT', 194 }, 195 'uint8': { 196 'timescaledb': 'SMALLINT', 197 'timescaledb-ha': 'SMALLINT', 198 'postgresql': 'SMALLINT', 199 'postgis': 'SMALLINT', 200 'mariadb': 'SMALLINT', 201 'mysql': 'SMALLINT', 202 'mssql': 'SMALLINT', 203 'oracle': 'INT', 204 'sqlite': 'INT', 205 'geopackage': 'INT', 206 'duckdb': 'SMALLINT', 207 'citus': 'SMALLINT', 208 'cockroachdb': 'SMALLINT', 209 'default': 'INT', 210 }, 211 'int16': { 212 'timescaledb': 'SMALLINT', 213 'timescaledb-ha': 'SMALLINT', 214 'postgresql': 'SMALLINT', 215 'postgis': 'SMALLINT', 216 'mariadb': 'SMALLINT', 217 'mysql': 'SMALLINT', 218 'mssql': 'SMALLINT', 219 'oracle': 'INT', 220 'sqlite': 'INT', 221 'geopackage': 'INT', 222 'duckdb': 'SMALLINT', 223 'citus': 'SMALLINT', 224 'cockroachdb': 'SMALLINT', 225 'default': 'INT', 226 }, 227 'int32': { 228 'timescaledb': 'INT', 229 'timescaledb-ha': 'INT', 230 'postgresql': 'INT', 231 'postgis': 'INT', 232 'mariadb': 'INT', 233 'mysql': 'INT', 234 'mssql': 'INT', 235 'oracle': 'INT', 236 'sqlite': 'INT', 237 'geopackage': 'INT', 238 'duckdb': 'INT', 239 'citus': 'INT', 240 'cockroachdb': 'INT', 241 'default': 'INT', 242 }, 243 'int64': { 244 'timescaledb': 'BIGINT', 245 'timescaledb-ha': 'BIGINT', 246 'postgresql': 'BIGINT', 247 'postgis': 'BIGINT', 248 'mariadb': 'BIGINT', 249 'mysql': 'BIGINT', 250 'mssql': 'BIGINT', 251 'oracle': 'INT', 252 'sqlite': 'BIGINT', 253 'geopackage': 'BIGINT', 254 'duckdb': 'BIGINT', 255 'citus': 'BIGINT', 256 'cockroachdb': 'BIGINT', 257 'default': 'INT', 258 }, 259 'float': { 260 'timescaledb': 'DOUBLE PRECISION', 261 'timescaledb-ha': 'DOUBLE PRECISION', 262 'postgresql': 'DOUBLE PRECISION', 263 'postgis': 'DOUBLE PRECISION', 264 'mariadb': 'DOUBLE PRECISION', 265 'mysql': 'DOUBLE PRECISION', 266 'mssql': 'FLOAT', 267 'oracle': 'FLOAT', 268 'sqlite': 'FLOAT', 269 'geopackage': 'FLOAT', 270 'duckdb': 'DOUBLE PRECISION', 271 'citus': 'DOUBLE PRECISION', 272 'cockroachdb': 'DOUBLE PRECISION', 273 'default': 'DOUBLE', 274 }, 275 'double': { 276 'timescaledb': 'DOUBLE PRECISION', 277 'timescaledb-ha': 'DOUBLE PRECISION', 278 'postgresql': 'DOUBLE PRECISION', 279 'postgis': 'DOUBLE PRECISION', 280 'mariadb': 'DOUBLE PRECISION', 281 'mysql': 'DOUBLE PRECISION', 282 'mssql': 'FLOAT', 283 'oracle': 'FLOAT', 284 'sqlite': 'FLOAT', 285 'geopackage': 'FLOAT', 286 'duckdb': 'DOUBLE PRECISION', 287 'citus': 'DOUBLE PRECISION', 288 'cockroachdb': 'DOUBLE PRECISION', 289 'default': 'DOUBLE', 290 }, 291 'datetime64[ns]': { 292 'timescaledb': 'TIMESTAMP(6)', 293 'timescaledb-ha': 'TIMESTAMP(6)', 294 'postgresql': 'TIMESTAMP(6)', 295 'postgis': 'TIMESTAMP(6)', 296 'mariadb': 'DATETIME', 297 'mysql': 'DATETIME', 298 'mssql': 'DATETIME2(7)', 299 'oracle': 'TIMESTAMP(9)', 300 'sqlite': 'DATETIME', 301 'geopackage': 'DATETIME', 302 'duckdb': 'TIMESTAMP(6)', 303 'citus': 'TIMESTAMP(6)', 304 'cockroachdb': 'TIMESTAMP(6)', 305 'default': 'DATETIME', 306 }, 307 'datetime64[ns, UTC]': { 308 'timescaledb': 'TIMESTAMPTZ(6)', 309 'timescaledb-ha': 'TIMESTAMPTZ(6)', 310 'postgresql': 'TIMESTAMPTZ(9)', 311 'postgis': 'TIMESTAMPTZ(6)', 312 'mariadb': 'DATETIME', 313 'mysql': 'DATETIME', 314 'mssql': 'DATETIMEOFFSET(7)', 315 'oracle': 'TIMESTAMP(9)', 316 'sqlite': 'TIMESTAMP', 317 'geopackage': 'TIMESTAMP', 318 'duckdb': 'TIMESTAMPTZ', 319 'citus': 'TIMESTAMPTZ(6)', 320 'cockroachdb': 'TIMESTAMPTZ(6)', 321 'default': 'TIMESTAMPTZ', 322 }, 323 'datetime64[us]': { 324 'timescaledb': 'TIMESTAMP(6)', 325 'timescaledb-ha': 'TIMESTAMP(6)', 326 'postgresql': 'TIMESTAMP(6)', 327 'postgis': 'TIMESTAMP(6)', 328 'mariadb': 'DATETIME', 329 'mysql': 'DATETIME', 330 'mssql': 'DATETIME2(6)', 331 'oracle': 'TIMESTAMP(6)', 332 'sqlite': 'DATETIME', 333 'geopackage': 'DATETIME', 334 'duckdb': 'TIMESTAMP(6)', 335 'citus': 'TIMESTAMP(6)', 336 'cockroachdb': 'TIMESTAMP', 337 'default': 'DATETIME', 338 }, 339 'datetime64[us, UTC]': { 340 'timescaledb': 'TIMESTAMPTZ(6)', 341 'timescaledb-ha': 'TIMESTAMPTZ(6)', 342 'postgresql': 'TIMESTAMPTZ(6)', 343 'postgis': 'TIMESTAMPTZ(6)', 344 'mariadb': 'DATETIME', 345 'mysql': 'DATETIME', 346 'mssql': 'DATETIMEOFFSET(6)', 347 'oracle': 'TIMESTAMP(6)', 348 'sqlite': 'TIMESTAMP', 349 'geopackage': 'TIMESTAMP', 350 'duckdb': 'TIMESTAMPTZ', 351 'citus': 'TIMESTAMPTZ(6)', 352 'cockroachdb': 'TIMESTAMPTZ(6)', 353 'default': 'TIMESTAMPTZ', 354 }, 355 'datetime64[ms]': { 356 'timescaledb': 'TIMESTAMP(3)', 357 'timescaledb-ha': 'TIMESTAMP(3)', 358 'postgresql': 'TIMESTAMP(3)', 359 'postgis': 'TIMESTAMP(3)', 360 'mariadb': 'DATETIME', 361 'mysql': 'DATETIME', 362 'mssql': 'DATETIME2(3)', 363 'oracle': 'TIMESTAMP(3)', 364 'sqlite': 'DATETIME', 365 'geopackage': 'DATETIME', 366 'duckdb': 'TIMESTAMP(3)', 367 'citus': 'TIMESTAMP(3)', 368 'cockroachdb': 'TIMESTAMP(3)', 369 'default': 'DATETIME', 370 }, 371 'datetime64[ms, UTC]': { 372 'timescaledb': 'TIMESTAMPTZ(3)', 373 'timescaledb-ha': 'TIMESTAMPTZ(3)', 374 'postgresql': 'TIMESTAMPTZ(3)', 375 'postgis': 'TIMESTAMPTZ(3)', 376 'mariadb': 'DATETIME', 377 'mysql': 'DATETIME', 378 'mssql': 'DATETIMEOFFSET(3)', 379 'oracle': 'TIMESTAMP(3)', 380 'sqlite': 'TIMESTAMP', 381 'geopackage': 'TIMESTAMP', 382 'duckdb': 'TIMESTAMPTZ', 383 'citus': 'TIMESTAMPTZ(3)', 384 'cockroachdb': 'TIMESTAMPTZ(3)', 385 'default': 'TIMESTAMPTZ', 386 }, 387 'datetime64[s]': { 388 'timescaledb': 'TIMESTAMP(0)', 389 'timescaledb-ha': 'TIMESTAMP(0)', 390 'postgresql': 'TIMESTAMP(0)', 391 'postgis': 'TIMESTAMP(0)', 392 'mariadb': 'DATETIME', 393 'mysql': 'DATETIME', 394 'mssql': 'DATETIME2(0)', 395 'oracle': 'TIMESTAMP(0)', 396 'sqlite': 'DATETIME', 397 'geopackage': 'DATETIME', 398 'duckdb': 'TIMESTAMP(0)', 399 'citus': 'TIMESTAMP(0)', 400 'cockroachdb': 'TIMESTAMP(0)', 401 'default': 'DATETIME', 402 }, 403 'datetime64[s, UTC]': { 404 'timescaledb': 'TIMESTAMPTZ(0)', 405 'timescaledb-ha': 'TIMESTAMPTZ(0)', 406 'postgresql': 'TIMESTAMPTZ(0)', 407 'postgis': 'TIMESTAMPTZ(0)', 408 'mariadb': 'DATETIME', 409 'mysql': 'DATETIME', 410 'mssql': 'DATETIMEOFFSET(0)', 411 'oracle': 'TIMESTAMP(0)', 412 'sqlite': 'TIMESTAMP', 413 'geopackage': 'TIMESTAMP', 414 'duckdb': 'TIMESTAMPTZ', 415 'citus': 'TIMESTAMPTZ(0)', 416 'cockroachdb': 'TIMESTAMPTZ(0)', 417 'default': 'TIMESTAMPTZ(0)', 418 }, 419 'datetime': { 420 'timescaledb': 'TIMESTAMPTZ', 421 'timescaledb-ha': 'TIMESTAMPTZ', 422 'postgresql': 'TIMESTAMPTZ', 423 'postgis': 'TIMESTAMPTZ', 424 'mariadb': 'DATETIME', 425 'mysql': 'DATETIME', 426 'mssql': 'DATETIMEOFFSET', 427 'oracle': 'TIMESTAMP', 428 'sqlite': 'TIMESTAMP', 429 'geopackage': 'TIMESTAMP', 430 'duckdb': 'TIMESTAMPTZ', 431 'citus': 'TIMESTAMPTZ', 432 'cockroachdb': 'TIMESTAMPTZ', 433 'default': 'TIMESTAMPTZ', 434 }, 435 'datetimetz': { 436 'timescaledb': 'TIMESTAMPTZ', 437 'timescaledb-ha': 'TIMESTAMPTZ', 438 'postgresql': 'TIMESTAMPTZ', 439 'postgis': 'TIMESTAMPTZ', 440 'mariadb': 'DATETIME', 441 'mysql': 'DATETIME', 442 'mssql': 'DATETIMEOFFSET', 443 'oracle': 'TIMESTAMP', 444 'sqlite': 'TIMESTAMP', 445 'geopackage': 'TIMESTAMP', 446 'duckdb': 'TIMESTAMPTZ', 447 'citus': 'TIMESTAMPTZ', 448 'cockroachdb': 'TIMESTAMPTZ', 449 'default': 'TIMESTAMPTZ', 450 }, 451 'date': { 452 'timescaledb': 'DATE', 453 'timescaledb-ha': 'DATE', 454 'postgresql': 'DATE', 455 'postgis': 'DATE', 456 'mariadb': 'DATE', 457 'mysql': 'DATE', 458 'mssql': 'DATE', 459 'oracle': 'DATE', 460 'sqlite': 'DATE', 461 'geopackage': 'DATE', 462 'duckdb': 'DATE', 463 'citus': 'DATE', 464 'cockroachdb': 'DATE', 465 'default': 'DATE', 466 }, 467 'bool': { 468 'timescaledb': 'BOOLEAN', 469 'timescaledb-ha': 'BOOLEAN', 470 'postgresql': 'BOOLEAN', 471 'postgis': 'BOOLEAN', 472 'mariadb': 'BOOLEAN', 473 'mysql': 'BOOLEAN', 474 'mssql': 'BIT', 475 'oracle': 'INTEGER', 476 'sqlite': 'FLOAT', 477 'geopackage': 'FLOAT', 478 'duckdb': 'BOOLEAN', 479 'citus': 'BOOLEAN', 480 'cockroachdb': 'BOOLEAN', 481 'default': 'BOOLEAN', 482 }, 483 'bool[pyarrow]': { 484 'timescaledb': 'BOOLEAN', 485 'timescaledb-ha': 'BOOLEAN', 486 'postgresql': 'BOOLEAN', 487 'postgis': 'BOOLEAN', 488 'mariadb': 'BOOLEAN', 489 'mysql': 'BOOLEAN', 490 'mssql': 'BIT', 491 'oracle': 'INTEGER', 492 'sqlite': 'FLOAT', 493 'geopackage': 'FLOAT', 494 'duckdb': 'BOOLEAN', 495 'citus': 'BOOLEAN', 496 'cockroachdb': 'BOOLEAN', 497 'default': 'BOOLEAN', 498 }, 499 'boolean': { 500 'timescaledb': 'BOOLEAN', 501 'timescaledb-ha': 'BOOLEAN', 502 'postgresql': 'BOOLEAN', 503 'postgis': 'BOOLEAN', 504 'mariadb': 'BOOLEAN', 505 'mysql': 'BOOLEAN', 506 'mssql': 'BIT', 507 'oracle': 'INTEGER', 508 'sqlite': 'FLOAT', 509 'geopackage': 'FLOAT', 510 'duckdb': 'BOOLEAN', 511 'citus': 'BOOLEAN', 512 'cockroachdb': 'BOOLEAN', 513 'default': 'BOOLEAN', 514 }, 515 'object': { 516 'timescaledb': 'TEXT', 517 'timescaledb-ha': 'TEXT', 518 'postgresql': 'TEXT', 519 'postgis': 'TEXT', 520 'mariadb': 'TEXT', 521 'mysql': 'TEXT', 522 'mssql': 'NVARCHAR(MAX)', 523 'oracle': 'NVARCHAR2(2000)', 524 'sqlite': 'TEXT', 525 'geopackage': 'TEXT', 526 'duckdb': 'TEXT', 527 'citus': 'TEXT', 528 'cockroachdb': 'TEXT', 529 'default': 'TEXT', 530 }, 531 'string': { 532 'timescaledb': 'TEXT', 533 'timescaledb-ha': 'TEXT', 534 'postgresql': 'TEXT', 535 'postgis': 'TEXT', 536 'mariadb': 'TEXT', 537 'mysql': 'TEXT', 538 'mssql': 'NVARCHAR(MAX)', 539 'oracle': 'NVARCHAR2(2000)', 540 'sqlite': 'TEXT', 541 'geopackage': 'TEXT', 542 'duckdb': 'TEXT', 543 'citus': 'TEXT', 544 'cockroachdb': 'TEXT', 545 'default': 'TEXT', 546 }, 547 'unicode': { 548 'timescaledb': 'TEXT', 549 'timescaledb-ha': 'TEXT', 550 'postgresql': 'TEXT', 551 'postgis': 'TEXT', 552 'mariadb': 'TEXT', 553 'mysql': 'TEXT', 554 'mssql': 'NVARCHAR(MAX)', 555 'oracle': 'NVARCHAR2(2000)', 556 'sqlite': 'TEXT', 557 'geopackage': 'TEXT', 558 'duckdb': 'TEXT', 559 'citus': 'TEXT', 560 'cockroachdb': 'TEXT', 561 'default': 'TEXT', 562 }, 563 'json': { 564 'timescaledb': 'JSONB', 565 'timescaledb-ha': 'JSONB', 566 'postgresql': 'JSONB', 567 'postgis': 'JSONB', 568 'mariadb': 'TEXT', 569 'mysql': 'TEXT', 570 'mssql': 'NVARCHAR(MAX)', 571 'oracle': 'NVARCHAR2(2000)', 572 'sqlite': 'TEXT', 573 'geopackage': 'TEXT', 574 'duckdb': 'TEXT', 575 'citus': 'JSONB', 576 'cockroachdb': 'JSONB', 577 'default': 'TEXT', 578 }, 579 'numeric': { 580 'timescaledb': 'NUMERIC', 581 'timescaledb-ha': 'NUMERIC', 582 'postgresql': 'NUMERIC', 583 'postgis': 'NUMERIC', 584 'mariadb': f'DECIMAL{NUMERIC_PRECISION_FLAVORS["mariadb"]}', 585 'mysql': f'DECIMAL{NUMERIC_PRECISION_FLAVORS["mysql"]}', 586 'mssql': f'NUMERIC{NUMERIC_PRECISION_FLAVORS["mssql"]}', 587 'oracle': 'NUMBER', 588 'sqlite': 'TEXT', 589 'geopackage': 'TEXT', 590 'duckdb': 'TEXT', 591 'citus': 'NUMERIC', 592 'cockroachdb': 'NUMERIC', 593 'default': 'NUMERIC', 594 }, 595 'uuid': { 596 'timescaledb': 'UUID', 597 'timescaledb-ha': 'UUID', 598 'postgresql': 'UUID', 599 'postgis': 'UUID', 600 'mariadb': 'CHAR(36)', 601 'mysql': 'CHAR(36)', 602 'mssql': 'UNIQUEIDENTIFIER', 603 ### I know this is too much space, but erring on the side of caution. 604 'oracle': 'CHAR(36)', 605 'sqlite': 'TEXT', 606 'geopackage': 'TEXT', 607 'duckdb': 'VARCHAR', 608 'citus': 'UUID', 609 'cockroachdb': 'UUID', 610 'default': 'TEXT', 611 }, 612 'bytes': { 613 'timescaledb': 'BYTEA', 614 'timescaledb-ha': 'BYTEA', 615 'postgresql': 'BYTEA', 616 'postgis': 'BYTEA', 617 'mariadb': 'BLOB', 618 'mysql': 'BLOB', 619 'mssql': 'VARBINARY(MAX)', 620 'oracle': 'BLOB', 621 'sqlite': 'BLOB', 622 'geopackage': 'BLOB', 623 'duckdb': 'BLOB', 624 'citus': 'BYTEA', 625 'cockroachdb': 'BYTEA', 626 'default': 'BLOB', 627 }, 628 'geometry': { 629 'timescaledb': 'TEXT', 630 'timescaledb-ha': 'GEOMETRY', 631 'postgresql': 'TEXT', 632 'postgis': 'GEOMETRY', 633 'mariadb': 'TEXT', 634 'mysql': 'TEXT', 635 'mssql': 'NVARCHAR(MAX)', 636 'oracle': 'NVARCHAR2(2000)', 637 'sqlite': 'TEXT', 638 'geopackage': 'BLOB', 639 'duckdb': 'TEXT', 640 'citus': 'TEXT', 641 'cockroachdb': 'TEXT', 642 'default': 'TEXT', 643 }, 644 'geography': { 645 'timescaledb': 'TEXT', 646 'timescaledb-ha': 'GEOGRAPHY', 647 'postgresql': 'TEXT', 648 'postgis': 'GEOGRAPHY', 649 'mariadb': 'TEXT', 650 'mysql': 'TEXT', 651 'mssql': 'NVARCHAR(MAX)', 652 'oracle': 'NVARCHAR2(2000)', 653 'sqlite': 'TEXT', 654 'geopackage': 'BLOB', 655 'duckdb': 'TEXT', 656 'citus': 'TEXT', 657 'cockroachdb': 'TEXT', 658 'default': 'TEXT', 659 }, 660} 661PD_TO_SQLALCHEMY_DTYPES_FLAVORS: Dict[str, Dict[str, str]] = { 662 'int': { 663 'timescaledb': 'BigInteger', 664 'timescaledb-ha': 'BigInteger', 665 'postgresql': 'BigInteger', 666 'postgis': 'BigInteger', 667 'mariadb': 'BigInteger', 668 'mysql': 'BigInteger', 669 'mssql': 'BigInteger', 670 'oracle': 'BigInteger', 671 'sqlite': 'BigInteger', 672 'geopackage': 'BigInteger', 673 'duckdb': 'BigInteger', 674 'citus': 'BigInteger', 675 'cockroachdb': 'BigInteger', 676 'default': 'BigInteger', 677 }, 678 'uint': { 679 'timescaledb': 'BigInteger', 680 'timescaledb-ha': 'BigInteger', 681 'postgresql': 'BigInteger', 682 'postgis': 'BigInteger', 683 'mariadb': 'BigInteger', 684 'mysql': 'BigInteger', 685 'mssql': 'BigInteger', 686 'oracle': 'BigInteger', 687 'sqlite': 'BigInteger', 688 'geopackage': 'BigInteger', 689 'duckdb': 'BigInteger', 690 'citus': 'BigInteger', 691 'cockroachdb': 'BigInteger', 692 'default': 'BigInteger', 693 }, 694 'int8': { 695 'timescaledb': 'SmallInteger', 696 'timescaledb-ha': 'SmallInteger', 697 'postgresql': 'SmallInteger', 698 'postgis': 'SmallInteger', 699 'mariadb': 'SmallInteger', 700 'mysql': 'SmallInteger', 701 'mssql': 'SmallInteger', 702 'oracle': 'SmallInteger', 703 'sqlite': 'SmallInteger', 704 'geopackage': 'SmallInteger', 705 'duckdb': 'SmallInteger', 706 'citus': 'SmallInteger', 707 'cockroachdb': 'SmallInteger', 708 'default': 'SmallInteger', 709 }, 710 'uint8': { 711 'timescaledb': 'SmallInteger', 712 'timescaledb-ha': 'SmallInteger', 713 'postgresql': 'SmallInteger', 714 'postgis': 'SmallInteger', 715 'mariadb': 'SmallInteger', 716 'mysql': 'SmallInteger', 717 'mssql': 'SmallInteger', 718 'oracle': 'SmallInteger', 719 'sqlite': 'SmallInteger', 720 'geopackage': 'SmallInteger', 721 'duckdb': 'SmallInteger', 722 'citus': 'SmallInteger', 723 'cockroachdb': 'SmallInteger', 724 'default': 'SmallInteger', 725 }, 726 'int16': { 727 'timescaledb': 'SmallInteger', 728 'timescaledb-ha': 'SmallInteger', 729 'postgresql': 'SmallInteger', 730 'postgis': 'SmallInteger', 731 'mariadb': 'SmallInteger', 732 'mysql': 'SmallInteger', 733 'mssql': 'SmallInteger', 734 'oracle': 'SmallInteger', 735 'sqlite': 'SmallInteger', 736 'geopackage': 'SmallInteger', 737 'duckdb': 'SmallInteger', 738 'citus': 'SmallInteger', 739 'cockroachdb': 'SmallInteger', 740 'default': 'SmallInteger', 741 }, 742 'int32': { 743 'timescaledb': 'Integer', 744 'timescaledb-ha': 'Integer', 745 'postgresql': 'Integer', 746 'postgis': 'Integer', 747 'mariadb': 'Integer', 748 'mysql': 'Integer', 749 'mssql': 'Integer', 750 'oracle': 'Integer', 751 'sqlite': 'Integer', 752 'geopackage': 'Integer', 753 'duckdb': 'Integer', 754 'citus': 'Integer', 755 'cockroachdb': 'Integer', 756 'default': 'Integer', 757 }, 758 'int64': { 759 'timescaledb': 'BigInteger', 760 'timescaledb-ha': 'BigInteger', 761 'postgresql': 'BigInteger', 762 'postgis': 'BigInteger', 763 'mariadb': 'BigInteger', 764 'mysql': 'BigInteger', 765 'mssql': 'BigInteger', 766 'oracle': 'BigInteger', 767 'sqlite': 'BigInteger', 768 'geopackage': 'BigInteger', 769 'duckdb': 'BigInteger', 770 'citus': 'BigInteger', 771 'cockroachdb': 'BigInteger', 772 'default': 'BigInteger', 773 }, 774 'float': { 775 'timescaledb': 'Float', 776 'timescaledb-ha': 'Float', 777 'postgresql': 'Float', 778 'postgis': 'Float', 779 'mariadb': 'Float', 780 'mysql': 'Float', 781 'mssql': 'Float', 782 'oracle': 'Float', 783 'sqlite': 'Float', 784 'geopackage': 'Float', 785 'duckdb': 'Float', 786 'citus': 'Float', 787 'cockroachdb': 'Float', 788 'default': 'Float', 789 }, 790 'datetime': { 791 'timescaledb': 'DateTime(timezone=True)', 792 'timescaledb-ha': 'DateTime(timezone=True)', 793 'postgresql': 'DateTime(timezone=True)', 794 'postgis': 'DateTime(timezone=True)', 795 'mariadb': 'DateTime(timezone=True)', 796 'mysql': 'DateTime(timezone=True)', 797 'mssql': 'sqlalchemy.dialects.mssql.DATETIMEOFFSET', 798 'oracle': 'sqlalchemy.dialects.oracle.TIMESTAMP', 799 'sqlite': 'DateTime(timezone=True)', 800 'geopackage': 'DateTime(timezone=True)', 801 'duckdb': 'DateTime(timezone=True)', 802 'citus': 'DateTime(timezone=True)', 803 'cockroachdb': 'DateTime(timezone=True)', 804 'default': 'DateTime(timezone=True)', 805 }, 806 'datetime64[ns]': { 807 'timescaledb': 'DateTime', 808 'timescaledb-ha': 'DateTime', 809 'postgresql': 'DateTime', 810 'postgis': 'DateTime', 811 'mariadb': 'DateTime', 812 'mysql': 'DateTime', 813 'mssql': 'sqlalchemy.dialects.mssql.DATETIME2', 814 'oracle': 'DateTime', 815 'sqlite': 'DateTime', 816 'geopackage': 'DateTime', 817 'duckdb': 'DateTime', 818 'citus': 'DateTime', 819 'cockroachdb': 'DateTime', 820 'default': 'DateTime', 821 }, 822 'datetime64[ns, UTC]': { 823 'timescaledb': 'DateTime(timezone=True)', 824 'timescaledb-ha': 'DateTime(timezone=True)', 825 'postgresql': 'DateTime(timezone=True)', 826 'postgis': 'DateTime(timezone=True)', 827 'mariadb': 'DateTime(timezone=True)', 828 'mysql': 'DateTime(timezone=True)', 829 'mssql': 'sqlalchemy.dialects.mssql.DATETIMEOFFSET', 830 'oracle': 'sqlalchemy.dialects.oracle.TIMESTAMP', 831 'sqlite': 'DateTime(timezone=True)', 832 'geopackage': 'DateTime(timezone=True)', 833 'duckdb': 'DateTime(timezone=True)', 834 'citus': 'DateTime(timezone=True)', 835 'cockroachdb': 'DateTime(timezone=True)', 836 'default': 'DateTime(timezone=True)', 837 }, 838 'datetime64[us]': { 839 'timescaledb': 'DateTime', 840 'timescaledb-ha': 'DateTime', 841 'postgresql': 'DateTime', 842 'postgis': 'DateTime', 843 'mariadb': 'DateTime', 844 'mysql': 'DateTime', 845 'mssql': 'sqlalchemy.dialects.mssql.DATETIME2', 846 'oracle': 'DateTime', 847 'sqlite': 'DateTime', 848 'geopackage': 'DateTime', 849 'duckdb': 'DateTime', 850 'citus': 'DateTime', 851 'cockroachdb': 'DateTime', 852 'default': 'DateTime', 853 }, 854 'datetime64[us, UTC]': { 855 'timescaledb': 'DateTime(timezone=True)', 856 'timescaledb-ha': 'DateTime(timezone=True)', 857 'postgresql': 'DateTime(timezone=True)', 858 'postgis': 'DateTime(timezone=True)', 859 'mariadb': 'DateTime(timezone=True)', 860 'mysql': 'DateTime(timezone=True)', 861 'mssql': 'sqlalchemy.dialects.mssql.DATETIMEOFFSET', 862 'oracle': 'sqlalchemy.dialects.oracle.TIMESTAMP', 863 'sqlite': 'DateTime(timezone=True)', 864 'geopackage': 'DateTime(timezone=True)', 865 'duckdb': 'DateTime(timezone=True)', 866 'citus': 'DateTime(timezone=True)', 867 'cockroachdb': 'DateTime(timezone=True)', 868 'default': 'DateTime(timezone=True)', 869 }, 870 'datetime64[ms]': { 871 'timescaledb': 'DateTime', 872 'timescaledb-ha': 'DateTime', 873 'postgresql': 'DateTime', 874 'postgis': 'DateTime', 875 'mariadb': 'DateTime', 876 'mysql': 'DateTime', 877 'mssql': 'sqlalchemy.dialects.mssql.DATETIME2', 878 'oracle': 'DateTime', 879 'sqlite': 'DateTime', 880 'geopackage': 'DateTime', 881 'duckdb': 'DateTime', 882 'citus': 'DateTime', 883 'cockroachdb': 'DateTime', 884 'default': 'DateTime', 885 }, 886 'datetime64[ms, UTC]': { 887 'timescaledb': 'DateTime(timezone=True)', 888 'timescaledb-ha': 'DateTime(timezone=True)', 889 'postgresql': 'DateTime(timezone=True)', 890 'postgis': 'DateTime(timezone=True)', 891 'mariadb': 'DateTime(timezone=True)', 892 'mysql': 'DateTime(timezone=True)', 893 'mssql': 'sqlalchemy.dialects.mssql.DATETIMEOFFSET', 894 'oracle': 'sqlalchemy.dialects.oracle.TIMESTAMP', 895 'sqlite': 'DateTime(timezone=True)', 896 'geopackage': 'DateTime(timezone=True)', 897 'duckdb': 'DateTime(timezone=True)', 898 'citus': 'DateTime(timezone=True)', 899 'cockroachdb': 'DateTime(timezone=True)', 900 'default': 'DateTime(timezone=True)', 901 }, 902 'datetime64[s]': { 903 'timescaledb': 'DateTime', 904 'timescaledb-ha': 'DateTime', 905 'postgresql': 'DateTime', 906 'postgis': 'DateTime', 907 'mariadb': 'DateTime', 908 'mysql': 'DateTime', 909 'mssql': 'sqlalchemy.dialects.mssql.DATETIME2', 910 'oracle': 'DateTime', 911 'sqlite': 'DateTime', 912 'geopackage': 'DateTime', 913 'duckdb': 'DateTime', 914 'citus': 'DateTime', 915 'cockroachdb': 'DateTime', 916 'default': 'DateTime', 917 }, 918 'datetime64[s, UTC]': { 919 'timescaledb': 'DateTime(timezone=True)', 920 'timescaledb-ha': 'DateTime(timezone=True)', 921 'postgresql': 'DateTime(timezone=True)', 922 'postgis': 'DateTime(timezone=True)', 923 'mariadb': 'DateTime(timezone=True)', 924 'mysql': 'DateTime(timezone=True)', 925 'mssql': 'sqlalchemy.dialects.mssql.DATETIMEOFFSET', 926 'oracle': 'sqlalchemy.dialects.oracle.TIMESTAMP', 927 'sqlite': 'DateTime(timezone=True)', 928 'geopackage': 'DateTime(timezone=True)', 929 'duckdb': 'DateTime(timezone=True)', 930 'citus': 'DateTime(timezone=True)', 931 'cockroachdb': 'DateTime(timezone=True)', 932 'default': 'DateTime(timezone=True)', 933 }, 934 'date': { 935 'timescaledb': 'Date', 936 'timescaledb-ha': 'Date', 937 'postgresql': 'Date', 938 'postgis': 'Date', 939 'mariadb': 'Date', 940 'mysql': 'Date', 941 'mssql': 'Date', 942 'oracle': 'Date', 943 'sqlite': 'Date', 944 'geopackage': 'Date', 945 'duckdb': 'Date', 946 'citus': 'Date', 947 'cockroachdb': 'Date', 948 'default': 'Date', 949 }, 950 'bool': { 951 'timescaledb': 'Boolean', 952 'timescaledb-ha': 'Boolean', 953 'postgresql': 'Boolean', 954 'postgis': 'Boolean', 955 'mariadb': 'Integer', 956 'mysql': 'Integer', 957 'mssql': 'sqlalchemy.dialects.mssql.BIT', 958 'oracle': 'Integer', 959 'sqlite': 'Float', 960 'geopackage': 'Float', 961 'duckdb': 'Boolean', 962 'citus': 'Boolean', 963 'cockroachdb': 'Boolean', 964 'default': 'Boolean', 965 }, 966 'bool[pyarrow]': { 967 'timescaledb': 'Boolean', 968 'timescaledb-ha': 'Boolean', 969 'postgresql': 'Boolean', 970 'postgis': 'Boolean', 971 'mariadb': 'Integer', 972 'mysql': 'Integer', 973 'mssql': 'sqlalchemy.dialects.mssql.BIT', 974 'oracle': 'Integer', 975 'sqlite': 'Float', 976 'geopackage': 'Float', 977 'duckdb': 'Boolean', 978 'citus': 'Boolean', 979 'cockroachdb': 'Boolean', 980 'default': 'Boolean', 981 }, 982 'boolean': { 983 'timescaledb': 'Boolean', 984 'timescaledb-ha': 'Boolean', 985 'postgresql': 'Boolean', 986 'postgis': 'Boolean', 987 'mariadb': 'Integer', 988 'mysql': 'Integer', 989 'mssql': 'sqlalchemy.dialects.mssql.BIT', 990 'oracle': 'Integer', 991 'sqlite': 'Float', 992 'geopackage': 'Float', 993 'duckdb': 'Boolean', 994 'citus': 'Boolean', 995 'cockroachdb': 'Boolean', 996 'default': 'Boolean', 997 }, 998 'object': { 999 'timescaledb': 'UnicodeText', 1000 'timescaledb-ha': 'UnicodeText', 1001 'postgresql': 'UnicodeText', 1002 'postgis': 'UnicodeText', 1003 'mariadb': 'UnicodeText', 1004 'mysql': 'UnicodeText', 1005 'mssql': 'UnicodeText', 1006 'oracle': 'UnicodeText', 1007 'sqlite': 'UnicodeText', 1008 'geopackage': 'UnicodeText', 1009 'duckdb': 'UnicodeText', 1010 'citus': 'UnicodeText', 1011 'cockroachdb': 'UnicodeText', 1012 'default': 'UnicodeText', 1013 }, 1014 'string': { 1015 'timescaledb': 'UnicodeText', 1016 'timescaledb-ha': 'UnicodeText', 1017 'postgresql': 'UnicodeText', 1018 'postgis': 'UnicodeText', 1019 'mariadb': 'UnicodeText', 1020 'mysql': 'UnicodeText', 1021 'mssql': 'UnicodeText', 1022 'oracle': 'UnicodeText', 1023 'sqlite': 'UnicodeText', 1024 'geopackage': 'UnicodeText', 1025 'duckdb': 'UnicodeText', 1026 'citus': 'UnicodeText', 1027 'cockroachdb': 'UnicodeText', 1028 'default': 'UnicodeText', 1029 }, 1030 'json': { 1031 'timescaledb': 'sqlalchemy.dialects.postgresql.JSONB', 1032 'timescaledb-ha': 'sqlalchemy.dialects.postgresql.JSONB', 1033 'postgresql': 'sqlalchemy.dialects.postgresql.JSONB', 1034 'postgis': 'sqlalchemy.dialects.postgresql.JSONB', 1035 'mariadb': 'UnicodeText', 1036 'mysql': 'UnicodeText', 1037 'mssql': 'UnicodeText', 1038 'oracle': 'UnicodeText', 1039 'sqlite': 'UnicodeText', 1040 'geopackage': 'UnicodeText', 1041 'duckdb': 'TEXT', 1042 'citus': 'sqlalchemy.dialects.postgresql.JSONB', 1043 'cockroachdb': 'sqlalchemy.dialects.postgresql.JSONB', 1044 'default': 'UnicodeText', 1045 }, 1046 'numeric': { 1047 'timescaledb': 'Numeric', 1048 'timescaledb-ha': 'Numeric', 1049 'postgresql': 'Numeric', 1050 'postgis': 'Numeric', 1051 'mariadb': 'Numeric', 1052 'mysql': 'Numeric', 1053 'mssql': 'Numeric', 1054 'oracle': 'Numeric', 1055 'sqlite': 'UnicodeText', 1056 'geopackage': 'UnicodeText', 1057 'duckdb': 'Numeric', 1058 'citus': 'Numeric', 1059 'cockroachdb': 'Numeric', 1060 'default': 'Numeric', 1061 }, 1062 'uuid': { 1063 'timescaledb': 'Uuid', 1064 'timescaledb-ha': 'Uuid', 1065 'postgresql': 'Uuid', 1066 'postgis': 'Uuid', 1067 'mariadb': 'sqlalchemy.dialects.mysql.CHAR(36)', 1068 'mysql': 'sqlalchemy.dialects.mysql.CHAR(36)', 1069 'mssql': 'Uuid', 1070 'oracle': 'sqlalchemy.dialects.oracle.CHAR(36)', 1071 'sqlite': 'UnicodeText', 1072 'geopackage': 'UnicodeText', 1073 'duckdb': 'UnicodeText', 1074 'citus': 'Uuid', 1075 'cockroachdb': 'Uuid', 1076 'default': 'Uuid', 1077 }, 1078 'binary[pyarrow]': { 1079 'timescaledb': 'LargeBinary', 1080 'timescaledb-ha': 'LargeBinary', 1081 'postgresql': 'LargeBinary', 1082 'postgis': 'LargeBinary', 1083 'mariadb': 'LargeBinary', 1084 'mysql': 'LargeBinary', 1085 'mssql': 'LargeBinary', 1086 'oracle': 'LargeBinary', 1087 'sqlite': 'LargeBinary', 1088 'geopackage': 'LargeBinary', 1089 'duckdb': 'LargeBinary', 1090 'citus': 'LargeBinary', 1091 'cockroachdb': 'LargeBinary', 1092 'default': 'LargeBinary', 1093 }, 1094 'bytes': { 1095 'timescaledb': 'LargeBinary', 1096 'timescaledb-ha': 'LargeBinary', 1097 'postgresql': 'LargeBinary', 1098 'postgis': 'LargeBinary', 1099 'mariadb': 'LargeBinary', 1100 'mysql': 'LargeBinary', 1101 'mssql': 'LargeBinary', 1102 'oracle': 'LargeBinary', 1103 'sqlite': 'LargeBinary', 1104 'geopackage': 'LargeBinary', 1105 'duckdb': 'LargeBinary', 1106 'citus': 'LargeBinary', 1107 'cockroachdb': 'LargeBinary', 1108 'default': 'LargeBinary', 1109 }, 1110 'geometry': { 1111 'timescaledb': 'UnicodeText', 1112 'timescaledb-ha': 'geoalchemy2.Geometry', 1113 'postgresql': 'UnicodeText', 1114 'postgis': 'geoalchemy2.Geometry', 1115 'mariadb': 'UnicodeText', 1116 'mysql': 'UnicodeText', 1117 'mssql': 'UnicodeText', 1118 'oracle': 'UnicodeText', 1119 'sqlite': 'UnicodeText', 1120 'geopackage': 'LargeBinary', 1121 'duckdb': 'UnicodeText', 1122 'citus': 'UnicodeText', 1123 'cockroachdb': 'UnicodeText', 1124 'default': 'UnicodeText', 1125 }, 1126 'geography': { 1127 'timescaledb': 'UnicodeText', 1128 'timescaledb-ha': 'geoalchemy2.Geography', 1129 'postgresql': 'UnicodeText', 1130 'postgis': 'geoalchemy2.Geography', 1131 'mariadb': 'UnicodeText', 1132 'mysql': 'UnicodeText', 1133 'mssql': 'UnicodeText', 1134 'oracle': 'UnicodeText', 1135 'sqlite': 'UnicodeText', 1136 'geopackage': 'LargeBinary', 1137 'duckdb': 'UnicodeText', 1138 'citus': 'UnicodeText', 1139 'cockroachdb': 'UnicodeText', 1140 'default': 'UnicodeText', 1141 }, 1142} 1143 1144AUTO_INCREMENT_COLUMN_FLAVORS: Dict[str, str] = { 1145 'timescaledb': 'GENERATED BY DEFAULT AS IDENTITY', 1146 'timescaledb-ha': 'GENERATED BY DEFAULT AS IDENTITY', 1147 'postgresql': 'GENERATED BY DEFAULT AS IDENTITY', 1148 'postgis': 'GENERATED BY DEFAULT AS IDENTITY', 1149 'mariadb': 'AUTO_INCREMENT', 1150 'mysql': 'AUTO_INCREMENT', 1151 'mssql': 'IDENTITY(1,1)', 1152 'oracle': 'GENERATED BY DEFAULT ON NULL AS IDENTITY', 1153 'sqlite': 'AUTOINCREMENT', 1154 'geopackage': 'AUTOINCREMENT', 1155 'duckdb': 'GENERATED BY DEFAULT', 1156 'citus': 'GENERATED BY DEFAULT', 1157 'cockroachdb': 'GENERATED BY DEFAULT AS IDENTITY', 1158 'default': 'GENERATED BY DEFAULT AS IDENTITY', 1159} 1160 1161 1162def get_pd_type_from_db_type(db_type: str, allow_custom_dtypes: bool = True) -> str: 1163 """ 1164 Parse a database type to a pandas data type. 1165 1166 Parameters 1167 ---------- 1168 db_type: str 1169 The database type, e.g. `DATETIME`, `BIGINT`, etc. 1170 1171 allow_custom_dtypes: bool, default False 1172 If `True`, allow for custom data types like `json` and `str`. 1173 1174 Returns 1175 ------- 1176 The equivalent datatype for a pandas DataFrame. 1177 """ 1178 _rust = _core.get_pd_type_from_db_type 1179 return _rust(db_type, allow_custom_dtypes=allow_custom_dtypes) 1180 1181 1182def get_db_type_from_pd_type( 1183 pd_type: str, 1184 flavor: str = 'default', 1185 as_sqlalchemy: bool = False, 1186) -> Union[str, 'sqlalchemy.sql.visitors.TraversibleType']: 1187 """ 1188 Parse a Pandas data type into a flavor's database type. 1189 1190 Parameters 1191 ---------- 1192 pd_type: str 1193 The Pandas datatype. This must be a string, not the actual dtype object. 1194 1195 flavor: str, default 'default' 1196 The flavor of the database to be mapped to. 1197 1198 as_sqlalchemy: bool, default False 1199 If `True`, return a type from `sqlalchemy.types`. 1200 1201 Returns 1202 ------- 1203 The database data type for the incoming Pandas data type. 1204 If nothing can be found, a warning will be thrown and 'TEXT' will be returned. 1205 """ 1206 from meerschaum.utils.warnings import warn 1207 from meerschaum.utils.packages import attempt_import 1208 from meerschaum.utils.dtypes import are_dtypes_equal, MRSM_ALIAS_DTYPES, get_geometry_type_srid 1209 from meerschaum.utils.misc import parse_arguments_str 1210 sqlalchemy_types = attempt_import('sqlalchemy.types', lazy=False) 1211 1212 types_registry = ( 1213 PD_TO_DB_DTYPES_FLAVORS 1214 if not as_sqlalchemy 1215 else PD_TO_SQLALCHEMY_DTYPES_FLAVORS 1216 ) 1217 1218 precision, scale = None, None 1219 geometry_type, geometry_srid = None, None 1220 og_pd_type = pd_type 1221 if pd_type in MRSM_ALIAS_DTYPES: 1222 pd_type = MRSM_ALIAS_DTYPES[pd_type] 1223 1224 ### Check whether we are able to match this type (e.g. pyarrow support). 1225 found_db_type = False 1226 if ( 1227 pd_type not in types_registry 1228 and not any( 1229 pd_type.startswith(f'{typ}[') 1230 for typ in ('numeric', 'geometry', 'geography') 1231 ) 1232 ): 1233 for mapped_pd_type in types_registry: 1234 if are_dtypes_equal(mapped_pd_type, pd_type): 1235 pd_type = mapped_pd_type 1236 found_db_type = True 1237 break 1238 elif (pd_type.startswith('geometry[') or pd_type.startswith('geography[')): 1239 og_pd_type = pd_type 1240 pd_type = 'geometry' if 'geometry' in pd_type else 'geography' 1241 geometry_type, geometry_srid = get_geometry_type_srid(og_pd_type) 1242 if isinstance(geometry_srid, str): 1243 geometry_srid = int(geometry_srid.split(':', maxsplit=1)[-1]) 1244 found_db_type = True 1245 elif pd_type.startswith('numeric['): 1246 og_pd_type = pd_type 1247 pd_type = 'numeric' 1248 precision, scale = get_numeric_precision_scale(flavor, og_pd_type) 1249 found_db_type = True 1250 else: 1251 found_db_type = True 1252 1253 if not found_db_type: 1254 warn(f"Unknown Pandas data type '{pd_type}'. Falling back to 'TEXT'.", stacklevel=3) 1255 return ( 1256 'TEXT' 1257 if not as_sqlalchemy 1258 else sqlalchemy_types.UnicodeText 1259 ) 1260 flavor_types = types_registry.get( 1261 pd_type, 1262 { 1263 'default': ( 1264 'TEXT' 1265 if not as_sqlalchemy 1266 else 'UnicodeText' 1267 ), 1268 }, 1269 ) 1270 default_flavor_type = flavor_types.get( 1271 'default', 1272 ( 1273 'TEXT' 1274 if not as_sqlalchemy 1275 else 'UnicodeText' 1276 ), 1277 ) 1278 if flavor not in flavor_types: 1279 warn(f"Unknown flavor '{flavor}'. Falling back to '{default_flavor_type}' (default).") 1280 db_type = flavor_types.get(flavor, default_flavor_type) 1281 if not as_sqlalchemy: 1282 if precision is not None and scale is not None: 1283 db_type_bare = db_type.split('(', maxsplit=1)[0] 1284 return f"{db_type_bare}({precision},{scale})" 1285 if geometry_type is not None and geometry_srid is not None: 1286 if 'geometry' not in db_type.lower() and 'geography' not in db_type.lower(): 1287 return db_type 1288 db_type_bare = db_type.split('(', maxsplit=1)[0] 1289 if isinstance(geometry_srid, str): 1290 geometry_srid = int(geometry_srid.split(':')[-1]) 1291 return f"{db_type_bare}({geometry_type.upper()}, {geometry_srid})" 1292 return db_type 1293 1294 if db_type.startswith('sqlalchemy.dialects'): 1295 dialect, typ_class_name = db_type.replace('sqlalchemy.dialects.', '').split('.', maxsplit=2) 1296 cls_args, cls_kwargs = None, None 1297 if '(' in typ_class_name: 1298 typ_class_name, args_str = typ_class_name.split('(', maxsplit=1) 1299 args_str = args_str.rstrip(')') 1300 cls_args, cls_kwargs = parse_arguments_str(args_str) 1301 sqlalchemy_dialects_flavor_module = attempt_import(f'sqlalchemy.dialects.{dialect}') 1302 cls = getattr(sqlalchemy_dialects_flavor_module, typ_class_name) 1303 if cls_args is None: 1304 return cls 1305 return cls(*cls_args, **cls_kwargs) 1306 1307 if 'geometry' in db_type.lower() or 'geography' in db_type.lower(): 1308 geoalchemy2 = attempt_import('geoalchemy2', lazy=False) 1309 geometry_class = ( 1310 geoalchemy2.Geometry 1311 if 'geometry' in db_type.lower() 1312 else geoalchemy2.Geography 1313 ) 1314 if geometry_type is None or geometry_srid is None: 1315 return geometry_class 1316 return geometry_class(geometry_type=geometry_type, srid=geometry_srid) 1317 1318 if 'numeric' in db_type.lower(): 1319 if precision is None or scale is None: 1320 return sqlalchemy_types.Numeric 1321 return sqlalchemy_types.Numeric(precision, scale) 1322 1323 cls_args, cls_kwargs = None, None 1324 typ_class_name = db_type 1325 if '(' in db_type: 1326 typ_class_name, args_str = db_type.split('(', maxsplit=1) 1327 args_str = args_str.rstrip(')') 1328 cls_args, cls_kwargs = parse_arguments_str(args_str) 1329 1330 cls = getattr(sqlalchemy_types, typ_class_name) 1331 if cls_args is None: 1332 return cls 1333 return cls(*cls_args, **cls_kwargs) 1334 1335 1336def get_numeric_precision_scale( 1337 flavor: str, 1338 dtype: Optional[str] = None, 1339) -> Union[Tuple[int, int], Tuple[None, None]]: 1340 """ 1341 Return the precision and scale to use for a numeric column for a given database flavor. 1342 1343 Parameters 1344 ---------- 1345 flavor: str 1346 The database flavor for which to return the precision and scale. 1347 1348 dtype: Optional[str], default None 1349 If provided, return the precision and scale provided in the dtype (if applicable). 1350 If all caps, treat this as a DB type. 1351 1352 Returns 1353 ------- 1354 A tuple of ints or a tuple of Nones. 1355 """ 1356 if not dtype: 1357 return None, None 1358 1359 lbracket = '[' if '[' in dtype else '(' 1360 rbracket = ']' if lbracket == '[' else ')' 1361 if lbracket in dtype and dtype.count(',') == 1 and dtype.endswith(rbracket): 1362 try: 1363 parts = dtype.split(lbracket, maxsplit=1)[-1].rstrip(rbracket).split(',', maxsplit=1) 1364 return int(parts[0].strip()), int(parts[1].strip()) 1365 except Exception: 1366 pass 1367 1368 return NUMERIC_PRECISION_FLAVORS.get(flavor, (None, None)) 1369 1370 1371NUMERIC_AS_TEXT_FLAVORS = {'sqlite', 'duckdb', 'geopackage'}
NUMERIC_PRECISION_FLAVORS: Dict[str, Tuple[int, int]] =
{'mariadb': (38, 20), 'mysql': (38, 20), 'mssql': (28, 10)}
TIMEZONE_NAIVE_FLAVORS =
{'oracle', 'mariadb', 'mysql'}
DB_FLAVORS_CAST_DTYPES =
{'mariadb': {'BIGINT': 'DECIMAL', 'TINYINT': 'SIGNED INT', 'TEXT': 'CHAR(10000) CHARACTER SET utf8', 'BOOL': 'SIGNED INT', 'BOOLEAN': 'SIGNED INT', 'DOUBLE PRECISION': 'DECIMAL', 'DOUBLE': 'DECIMAL', 'FLOAT': 'DECIMAL', 'NUMERIC': 'NUMERIC(38, 20)', 'DECIMAL': 'DECIMAL(38, 20)'}, 'mysql': {'BIGINT': 'DECIMAL', 'TINYINT': 'SIGNED INT', 'TEXT': 'CHAR(10000) CHARACTER SET utf8', 'INT': 'SIGNED INT', 'INTEGER': 'SIGNED INT', 'BOOL': 'SIGNED INT', 'BOOLEAN': 'SIGNED INT', 'DOUBLE PRECISION': 'DECIMAL', 'DOUBLE': 'DECIMAL', 'FLOAT': 'DECIMAL', 'NUMERIC': 'NUMERIC(38, 20)', 'DECIMAL': 'DECIMAL(38, 20)'}, 'sqlite': {'BOOLEAN': 'INTEGER', 'REAL': 'FLOAT'}, 'geopackage': {'BOOLEAN': 'INTEGER', 'REAL': 'FLOAT'}, 'oracle': {'NVARCHAR(2000)': 'NVARCHAR2(2000)', 'NVARCHAR': 'NVARCHAR2(2000)', 'NVARCHAR2': 'NVARCHAR2(2000)', 'CHAR': 'CHAR(36)'}, 'mssql': {'NVARCHAR COLLATE "SQL Latin1 General CP1 CI AS"': 'NVARCHAR(MAX)', 'NVARCHAR COLLATE "SQL_Latin1_General_CP1_CI_AS"': 'NVARCHAR(MAX)', 'VARCHAR COLLATE "SQL Latin1 General CP1 CI AS"': 'NVARCHAR(MAX)', 'VARCHAR COLLATE "SQL_Latin1_General_CP1_CI_AS"': 'NVARCHAR(MAX)', 'NVARCHAR': 'NVARCHAR(MAX)', 'NUMERIC': 'NUMERIC(28, 10)', 'DECIMAL': 'DECIMAL(28, 10)'}}
DB_TO_PD_DTYPES: Dict[str, str | Dict[str, str]] =
{'FLOAT': 'float64[pyarrow]', 'REAL': 'float64[pyarrow]', 'DOUBLE_PRECISION': 'float64[pyarrow]', 'DOUBLE': 'float64[pyarrow]', 'DECIMAL': 'numeric', 'BIGINT': 'int64[pyarrow]', 'INT': 'int32[pyarrow]', 'INTEGER': 'int32[pyarrow]', 'NUMBER': 'numeric', 'NUMERIC': 'numeric', 'GEOMETRY': 'geometry', 'GEOMETRY(GEOMETRY)': 'geometry', 'TIMESTAMP': 'datetime64[us]', 'TIMESTAMP WITHOUT TIMEZONE': 'datetime64[us]', 'TIMESTAMP WITH TIMEZONE': 'datetime64[us, UTC]', 'TIMESTAMP WITH TIME ZONE': 'datetime64[us, UTC]', 'TIMESTAMPTZ': 'datetime64[us, UTC]', 'DATE': 'date', 'DATETIME': 'datetime64[us]', 'DATETIME2': 'datetime64[us]', 'DATETIME2(6)': 'datetime64[us]', 'DATETIME2(3)': 'datetime64[ms]', 'DATETIME2(0)': 'datetime64[s]', 'DATETIMEOFFSET': 'datetime64[us, UTC]', 'DATETIMEOFFSET(6)': 'datetime64[us, UTC]', 'DATETIMEOFFSET(3)': 'datetime64[ms, UTC]', 'DATETIMEOFFSET(0)': 'datetime64[s, UTC]', 'TEXT': 'string[pyarrow]', 'VARCHAR': 'string[pyarrow]', 'CLOB': 'string[pyarrow]', 'BOOL': 'bool[pyarrow]', 'BOOLEAN': 'bool[pyarrow]', 'BOOLEAN()': 'bool[pyarrow]', 'TINYINT': 'bool[pyarrow]', 'TINYINT(1)': 'bool[pyarrow]', 'BIT': 'bool[pyarrow]', 'BIT(1)': 'bool[pyarrow]', 'JSON': 'json', 'JSONB': 'json', 'UUID': 'uuid', 'UNIQUEIDENTIFIER': 'uuid', 'BYTEA': 'bytes', 'BLOB': 'bytes', 'VARBINARY': 'bytes', 'VARBINARY(MAX)': 'bytes', 'substrings': {'CHAR': 'string[pyarrow]', 'TIMESTAMP': 'datetime64[us]', 'TIME': 'datetime64[us]', 'DATE': 'date', 'DOUBLE': 'double[pyarrow]', 'DECIMAL': 'numeric', 'NUMERIC': 'numeric', 'NUMBER': 'numeric', 'INT': 'int64[pyarrow]', 'BOOL': 'bool[pyarrow]', 'JSON': 'json', 'BYTE': 'bytes', 'LOB': 'bytes', 'BINARY': 'bytes', 'GEOMETRY': 'geometry', 'GEOGRAPHY': 'geography'}, 'default': 'object'}
PD_TO_DB_DTYPES_FLAVORS: Dict[str, Dict[str, str]] =
{'int': {'timescaledb': 'BIGINT', 'timescaledb-ha': 'BIGINT', 'postgresql': 'BIGINT', 'postgis': 'BIGINT', 'mariadb': 'BIGINT', 'mysql': 'BIGINT', 'mssql': 'BIGINT', 'oracle': 'INT', 'sqlite': 'BIGINT', 'geopackage': 'BIGINT', 'duckdb': 'BIGINT', 'citus': 'BIGINT', 'cockroachdb': 'BIGINT', 'default': 'INT'}, 'uint': {'timescaledb': 'BIGINT', 'timescaledb-ha': 'BIGINT', 'postgresql': 'BIGINT', 'postgis': 'BIGINT', 'mariadb': 'BIGINT', 'mysql': 'BIGINT', 'mssql': 'BIGINT', 'oracle': 'INT', 'sqlite': 'BIGINT', 'geopackage': 'BIGINT', 'duckdb': 'BIGINT', 'citus': 'BIGINT', 'cockroachdb': 'BIGINT', 'default': 'INT'}, 'int8': {'timescaledb': 'SMALLINT', 'timescaledb-ha': 'SMALLINT', 'postgresql': 'SMALLINT', 'postgis': 'SMALLINT', 'mariadb': 'SMALLINT', 'mysql': 'SMALLINT', 'mssql': 'SMALLINT', 'oracle': 'INT', 'sqlite': 'INT', 'geopackage': 'INT', 'duckdb': 'SMALLINT', 'citus': 'SMALLINT', 'cockroachdb': 'SMALLINT', 'default': 'INT'}, 'uint8': {'timescaledb': 'SMALLINT', 'timescaledb-ha': 'SMALLINT', 'postgresql': 'SMALLINT', 'postgis': 'SMALLINT', 'mariadb': 'SMALLINT', 'mysql': 'SMALLINT', 'mssql': 'SMALLINT', 'oracle': 'INT', 'sqlite': 'INT', 'geopackage': 'INT', 'duckdb': 'SMALLINT', 'citus': 'SMALLINT', 'cockroachdb': 'SMALLINT', 'default': 'INT'}, 'int16': {'timescaledb': 'SMALLINT', 'timescaledb-ha': 'SMALLINT', 'postgresql': 'SMALLINT', 'postgis': 'SMALLINT', 'mariadb': 'SMALLINT', 'mysql': 'SMALLINT', 'mssql': 'SMALLINT', 'oracle': 'INT', 'sqlite': 'INT', 'geopackage': 'INT', 'duckdb': 'SMALLINT', 'citus': 'SMALLINT', 'cockroachdb': 'SMALLINT', 'default': 'INT'}, 'int32': {'timescaledb': 'INT', 'timescaledb-ha': 'INT', 'postgresql': 'INT', 'postgis': 'INT', 'mariadb': 'INT', 'mysql': 'INT', 'mssql': 'INT', 'oracle': 'INT', 'sqlite': 'INT', 'geopackage': 'INT', 'duckdb': 'INT', 'citus': 'INT', 'cockroachdb': 'INT', 'default': 'INT'}, 'int64': {'timescaledb': 'BIGINT', 'timescaledb-ha': 'BIGINT', 'postgresql': 'BIGINT', 'postgis': 'BIGINT', 'mariadb': 'BIGINT', 'mysql': 'BIGINT', 'mssql': 'BIGINT', 'oracle': 'INT', 'sqlite': 'BIGINT', 'geopackage': 'BIGINT', 'duckdb': 'BIGINT', 'citus': 'BIGINT', 'cockroachdb': 'BIGINT', 'default': 'INT'}, 'float': {'timescaledb': 'DOUBLE PRECISION', 'timescaledb-ha': 'DOUBLE PRECISION', 'postgresql': 'DOUBLE PRECISION', 'postgis': 'DOUBLE PRECISION', 'mariadb': 'DOUBLE PRECISION', 'mysql': 'DOUBLE PRECISION', 'mssql': 'FLOAT', 'oracle': 'FLOAT', 'sqlite': 'FLOAT', 'geopackage': 'FLOAT', 'duckdb': 'DOUBLE PRECISION', 'citus': 'DOUBLE PRECISION', 'cockroachdb': 'DOUBLE PRECISION', 'default': 'DOUBLE'}, 'double': {'timescaledb': 'DOUBLE PRECISION', 'timescaledb-ha': 'DOUBLE PRECISION', 'postgresql': 'DOUBLE PRECISION', 'postgis': 'DOUBLE PRECISION', 'mariadb': 'DOUBLE PRECISION', 'mysql': 'DOUBLE PRECISION', 'mssql': 'FLOAT', 'oracle': 'FLOAT', 'sqlite': 'FLOAT', 'geopackage': 'FLOAT', 'duckdb': 'DOUBLE PRECISION', 'citus': 'DOUBLE PRECISION', 'cockroachdb': 'DOUBLE PRECISION', 'default': 'DOUBLE'}, 'datetime64[ns]': {'timescaledb': 'TIMESTAMP(6)', 'timescaledb-ha': 'TIMESTAMP(6)', 'postgresql': 'TIMESTAMP(6)', 'postgis': 'TIMESTAMP(6)', 'mariadb': 'DATETIME', 'mysql': 'DATETIME', 'mssql': 'DATETIME2(7)', 'oracle': 'TIMESTAMP(9)', 'sqlite': 'DATETIME', 'geopackage': 'DATETIME', 'duckdb': 'TIMESTAMP(6)', 'citus': 'TIMESTAMP(6)', 'cockroachdb': 'TIMESTAMP(6)', 'default': 'DATETIME'}, 'datetime64[ns, UTC]': {'timescaledb': 'TIMESTAMPTZ(6)', 'timescaledb-ha': 'TIMESTAMPTZ(6)', 'postgresql': 'TIMESTAMPTZ(9)', 'postgis': 'TIMESTAMPTZ(6)', 'mariadb': 'DATETIME', 'mysql': 'DATETIME', 'mssql': 'DATETIMEOFFSET(7)', 'oracle': 'TIMESTAMP(9)', 'sqlite': 'TIMESTAMP', 'geopackage': 'TIMESTAMP', 'duckdb': 'TIMESTAMPTZ', 'citus': 'TIMESTAMPTZ(6)', 'cockroachdb': 'TIMESTAMPTZ(6)', 'default': 'TIMESTAMPTZ'}, 'datetime64[us]': {'timescaledb': 'TIMESTAMP(6)', 'timescaledb-ha': 'TIMESTAMP(6)', 'postgresql': 'TIMESTAMP(6)', 'postgis': 'TIMESTAMP(6)', 'mariadb': 'DATETIME', 'mysql': 'DATETIME', 'mssql': 'DATETIME2(6)', 'oracle': 'TIMESTAMP(6)', 'sqlite': 'DATETIME', 'geopackage': 'DATETIME', 'duckdb': 'TIMESTAMP(6)', 'citus': 'TIMESTAMP(6)', 'cockroachdb': 'TIMESTAMP', 'default': 'DATETIME'}, 'datetime64[us, UTC]': {'timescaledb': 'TIMESTAMPTZ(6)', 'timescaledb-ha': 'TIMESTAMPTZ(6)', 'postgresql': 'TIMESTAMPTZ(6)', 'postgis': 'TIMESTAMPTZ(6)', 'mariadb': 'DATETIME', 'mysql': 'DATETIME', 'mssql': 'DATETIMEOFFSET(6)', 'oracle': 'TIMESTAMP(6)', 'sqlite': 'TIMESTAMP', 'geopackage': 'TIMESTAMP', 'duckdb': 'TIMESTAMPTZ', 'citus': 'TIMESTAMPTZ(6)', 'cockroachdb': 'TIMESTAMPTZ(6)', 'default': 'TIMESTAMPTZ'}, 'datetime64[ms]': {'timescaledb': 'TIMESTAMP(3)', 'timescaledb-ha': 'TIMESTAMP(3)', 'postgresql': 'TIMESTAMP(3)', 'postgis': 'TIMESTAMP(3)', 'mariadb': 'DATETIME', 'mysql': 'DATETIME', 'mssql': 'DATETIME2(3)', 'oracle': 'TIMESTAMP(3)', 'sqlite': 'DATETIME', 'geopackage': 'DATETIME', 'duckdb': 'TIMESTAMP(3)', 'citus': 'TIMESTAMP(3)', 'cockroachdb': 'TIMESTAMP(3)', 'default': 'DATETIME'}, 'datetime64[ms, UTC]': {'timescaledb': 'TIMESTAMPTZ(3)', 'timescaledb-ha': 'TIMESTAMPTZ(3)', 'postgresql': 'TIMESTAMPTZ(3)', 'postgis': 'TIMESTAMPTZ(3)', 'mariadb': 'DATETIME', 'mysql': 'DATETIME', 'mssql': 'DATETIMEOFFSET(3)', 'oracle': 'TIMESTAMP(3)', 'sqlite': 'TIMESTAMP', 'geopackage': 'TIMESTAMP', 'duckdb': 'TIMESTAMPTZ', 'citus': 'TIMESTAMPTZ(3)', 'cockroachdb': 'TIMESTAMPTZ(3)', 'default': 'TIMESTAMPTZ'}, 'datetime64[s]': {'timescaledb': 'TIMESTAMP(0)', 'timescaledb-ha': 'TIMESTAMP(0)', 'postgresql': 'TIMESTAMP(0)', 'postgis': 'TIMESTAMP(0)', 'mariadb': 'DATETIME', 'mysql': 'DATETIME', 'mssql': 'DATETIME2(0)', 'oracle': 'TIMESTAMP(0)', 'sqlite': 'DATETIME', 'geopackage': 'DATETIME', 'duckdb': 'TIMESTAMP(0)', 'citus': 'TIMESTAMP(0)', 'cockroachdb': 'TIMESTAMP(0)', 'default': 'DATETIME'}, 'datetime64[s, UTC]': {'timescaledb': 'TIMESTAMPTZ(0)', 'timescaledb-ha': 'TIMESTAMPTZ(0)', 'postgresql': 'TIMESTAMPTZ(0)', 'postgis': 'TIMESTAMPTZ(0)', 'mariadb': 'DATETIME', 'mysql': 'DATETIME', 'mssql': 'DATETIMEOFFSET(0)', 'oracle': 'TIMESTAMP(0)', 'sqlite': 'TIMESTAMP', 'geopackage': 'TIMESTAMP', 'duckdb': 'TIMESTAMPTZ', 'citus': 'TIMESTAMPTZ(0)', 'cockroachdb': 'TIMESTAMPTZ(0)', 'default': 'TIMESTAMPTZ(0)'}, 'datetime': {'timescaledb': 'TIMESTAMPTZ', 'timescaledb-ha': 'TIMESTAMPTZ', 'postgresql': 'TIMESTAMPTZ', 'postgis': 'TIMESTAMPTZ', 'mariadb': 'DATETIME', 'mysql': 'DATETIME', 'mssql': 'DATETIMEOFFSET', 'oracle': 'TIMESTAMP', 'sqlite': 'TIMESTAMP', 'geopackage': 'TIMESTAMP', 'duckdb': 'TIMESTAMPTZ', 'citus': 'TIMESTAMPTZ', 'cockroachdb': 'TIMESTAMPTZ', 'default': 'TIMESTAMPTZ'}, 'datetimetz': {'timescaledb': 'TIMESTAMPTZ', 'timescaledb-ha': 'TIMESTAMPTZ', 'postgresql': 'TIMESTAMPTZ', 'postgis': 'TIMESTAMPTZ', 'mariadb': 'DATETIME', 'mysql': 'DATETIME', 'mssql': 'DATETIMEOFFSET', 'oracle': 'TIMESTAMP', 'sqlite': 'TIMESTAMP', 'geopackage': 'TIMESTAMP', 'duckdb': 'TIMESTAMPTZ', 'citus': 'TIMESTAMPTZ', 'cockroachdb': 'TIMESTAMPTZ', 'default': 'TIMESTAMPTZ'}, 'date': {'timescaledb': 'DATE', 'timescaledb-ha': 'DATE', 'postgresql': 'DATE', 'postgis': 'DATE', 'mariadb': 'DATE', 'mysql': 'DATE', 'mssql': 'DATE', 'oracle': 'DATE', 'sqlite': 'DATE', 'geopackage': 'DATE', 'duckdb': 'DATE', 'citus': 'DATE', 'cockroachdb': 'DATE', 'default': 'DATE'}, 'bool': {'timescaledb': 'BOOLEAN', 'timescaledb-ha': 'BOOLEAN', 'postgresql': 'BOOLEAN', 'postgis': 'BOOLEAN', 'mariadb': 'BOOLEAN', 'mysql': 'BOOLEAN', 'mssql': 'BIT', 'oracle': 'INTEGER', 'sqlite': 'FLOAT', 'geopackage': 'FLOAT', 'duckdb': 'BOOLEAN', 'citus': 'BOOLEAN', 'cockroachdb': 'BOOLEAN', 'default': 'BOOLEAN'}, 'bool[pyarrow]': {'timescaledb': 'BOOLEAN', 'timescaledb-ha': 'BOOLEAN', 'postgresql': 'BOOLEAN', 'postgis': 'BOOLEAN', 'mariadb': 'BOOLEAN', 'mysql': 'BOOLEAN', 'mssql': 'BIT', 'oracle': 'INTEGER', 'sqlite': 'FLOAT', 'geopackage': 'FLOAT', 'duckdb': 'BOOLEAN', 'citus': 'BOOLEAN', 'cockroachdb': 'BOOLEAN', 'default': 'BOOLEAN'}, 'boolean': {'timescaledb': 'BOOLEAN', 'timescaledb-ha': 'BOOLEAN', 'postgresql': 'BOOLEAN', 'postgis': 'BOOLEAN', 'mariadb': 'BOOLEAN', 'mysql': 'BOOLEAN', 'mssql': 'BIT', 'oracle': 'INTEGER', 'sqlite': 'FLOAT', 'geopackage': 'FLOAT', 'duckdb': 'BOOLEAN', 'citus': 'BOOLEAN', 'cockroachdb': 'BOOLEAN', 'default': 'BOOLEAN'}, 'object': {'timescaledb': 'TEXT', 'timescaledb-ha': 'TEXT', 'postgresql': 'TEXT', 'postgis': 'TEXT', 'mariadb': 'TEXT', 'mysql': 'TEXT', 'mssql': 'NVARCHAR(MAX)', 'oracle': 'NVARCHAR2(2000)', 'sqlite': 'TEXT', 'geopackage': 'TEXT', 'duckdb': 'TEXT', 'citus': 'TEXT', 'cockroachdb': 'TEXT', 'default': 'TEXT'}, 'string': {'timescaledb': 'TEXT', 'timescaledb-ha': 'TEXT', 'postgresql': 'TEXT', 'postgis': 'TEXT', 'mariadb': 'TEXT', 'mysql': 'TEXT', 'mssql': 'NVARCHAR(MAX)', 'oracle': 'NVARCHAR2(2000)', 'sqlite': 'TEXT', 'geopackage': 'TEXT', 'duckdb': 'TEXT', 'citus': 'TEXT', 'cockroachdb': 'TEXT', 'default': 'TEXT'}, 'unicode': {'timescaledb': 'TEXT', 'timescaledb-ha': 'TEXT', 'postgresql': 'TEXT', 'postgis': 'TEXT', 'mariadb': 'TEXT', 'mysql': 'TEXT', 'mssql': 'NVARCHAR(MAX)', 'oracle': 'NVARCHAR2(2000)', 'sqlite': 'TEXT', 'geopackage': 'TEXT', 'duckdb': 'TEXT', 'citus': 'TEXT', 'cockroachdb': 'TEXT', 'default': 'TEXT'}, 'json': {'timescaledb': 'JSONB', 'timescaledb-ha': 'JSONB', 'postgresql': 'JSONB', 'postgis': 'JSONB', 'mariadb': 'TEXT', 'mysql': 'TEXT', 'mssql': 'NVARCHAR(MAX)', 'oracle': 'NVARCHAR2(2000)', 'sqlite': 'TEXT', 'geopackage': 'TEXT', 'duckdb': 'TEXT', 'citus': 'JSONB', 'cockroachdb': 'JSONB', 'default': 'TEXT'}, 'numeric': {'timescaledb': 'NUMERIC', 'timescaledb-ha': 'NUMERIC', 'postgresql': 'NUMERIC', 'postgis': 'NUMERIC', 'mariadb': 'DECIMAL(38, 20)', 'mysql': 'DECIMAL(38, 20)', 'mssql': 'NUMERIC(28, 10)', 'oracle': 'NUMBER', 'sqlite': 'TEXT', 'geopackage': 'TEXT', 'duckdb': 'TEXT', 'citus': 'NUMERIC', 'cockroachdb': 'NUMERIC', 'default': 'NUMERIC'}, 'uuid': {'timescaledb': 'UUID', 'timescaledb-ha': 'UUID', 'postgresql': 'UUID', 'postgis': 'UUID', 'mariadb': 'CHAR(36)', 'mysql': 'CHAR(36)', 'mssql': 'UNIQUEIDENTIFIER', 'oracle': 'CHAR(36)', 'sqlite': 'TEXT', 'geopackage': 'TEXT', 'duckdb': 'VARCHAR', 'citus': 'UUID', 'cockroachdb': 'UUID', 'default': 'TEXT'}, 'bytes': {'timescaledb': 'BYTEA', 'timescaledb-ha': 'BYTEA', 'postgresql': 'BYTEA', 'postgis': 'BYTEA', 'mariadb': 'BLOB', 'mysql': 'BLOB', 'mssql': 'VARBINARY(MAX)', 'oracle': 'BLOB', 'sqlite': 'BLOB', 'geopackage': 'BLOB', 'duckdb': 'BLOB', 'citus': 'BYTEA', 'cockroachdb': 'BYTEA', 'default': 'BLOB'}, 'geometry': {'timescaledb': 'TEXT', 'timescaledb-ha': 'GEOMETRY', 'postgresql': 'TEXT', 'postgis': 'GEOMETRY', 'mariadb': 'TEXT', 'mysql': 'TEXT', 'mssql': 'NVARCHAR(MAX)', 'oracle': 'NVARCHAR2(2000)', 'sqlite': 'TEXT', 'geopackage': 'BLOB', 'duckdb': 'TEXT', 'citus': 'TEXT', 'cockroachdb': 'TEXT', 'default': 'TEXT'}, 'geography': {'timescaledb': 'TEXT', 'timescaledb-ha': 'GEOGRAPHY', 'postgresql': 'TEXT', 'postgis': 'GEOGRAPHY', 'mariadb': 'TEXT', 'mysql': 'TEXT', 'mssql': 'NVARCHAR(MAX)', 'oracle': 'NVARCHAR2(2000)', 'sqlite': 'TEXT', 'geopackage': 'BLOB', 'duckdb': 'TEXT', 'citus': 'TEXT', 'cockroachdb': 'TEXT', 'default': 'TEXT'}}
PD_TO_SQLALCHEMY_DTYPES_FLAVORS: Dict[str, Dict[str, str]] =
{'int': {'timescaledb': 'BigInteger', 'timescaledb-ha': 'BigInteger', 'postgresql': 'BigInteger', 'postgis': 'BigInteger', 'mariadb': 'BigInteger', 'mysql': 'BigInteger', 'mssql': 'BigInteger', 'oracle': 'BigInteger', 'sqlite': 'BigInteger', 'geopackage': 'BigInteger', 'duckdb': 'BigInteger', 'citus': 'BigInteger', 'cockroachdb': 'BigInteger', 'default': 'BigInteger'}, 'uint': {'timescaledb': 'BigInteger', 'timescaledb-ha': 'BigInteger', 'postgresql': 'BigInteger', 'postgis': 'BigInteger', 'mariadb': 'BigInteger', 'mysql': 'BigInteger', 'mssql': 'BigInteger', 'oracle': 'BigInteger', 'sqlite': 'BigInteger', 'geopackage': 'BigInteger', 'duckdb': 'BigInteger', 'citus': 'BigInteger', 'cockroachdb': 'BigInteger', 'default': 'BigInteger'}, 'int8': {'timescaledb': 'SmallInteger', 'timescaledb-ha': 'SmallInteger', 'postgresql': 'SmallInteger', 'postgis': 'SmallInteger', 'mariadb': 'SmallInteger', 'mysql': 'SmallInteger', 'mssql': 'SmallInteger', 'oracle': 'SmallInteger', 'sqlite': 'SmallInteger', 'geopackage': 'SmallInteger', 'duckdb': 'SmallInteger', 'citus': 'SmallInteger', 'cockroachdb': 'SmallInteger', 'default': 'SmallInteger'}, 'uint8': {'timescaledb': 'SmallInteger', 'timescaledb-ha': 'SmallInteger', 'postgresql': 'SmallInteger', 'postgis': 'SmallInteger', 'mariadb': 'SmallInteger', 'mysql': 'SmallInteger', 'mssql': 'SmallInteger', 'oracle': 'SmallInteger', 'sqlite': 'SmallInteger', 'geopackage': 'SmallInteger', 'duckdb': 'SmallInteger', 'citus': 'SmallInteger', 'cockroachdb': 'SmallInteger', 'default': 'SmallInteger'}, 'int16': {'timescaledb': 'SmallInteger', 'timescaledb-ha': 'SmallInteger', 'postgresql': 'SmallInteger', 'postgis': 'SmallInteger', 'mariadb': 'SmallInteger', 'mysql': 'SmallInteger', 'mssql': 'SmallInteger', 'oracle': 'SmallInteger', 'sqlite': 'SmallInteger', 'geopackage': 'SmallInteger', 'duckdb': 'SmallInteger', 'citus': 'SmallInteger', 'cockroachdb': 'SmallInteger', 'default': 'SmallInteger'}, 'int32': {'timescaledb': 'Integer', 'timescaledb-ha': 'Integer', 'postgresql': 'Integer', 'postgis': 'Integer', 'mariadb': 'Integer', 'mysql': 'Integer', 'mssql': 'Integer', 'oracle': 'Integer', 'sqlite': 'Integer', 'geopackage': 'Integer', 'duckdb': 'Integer', 'citus': 'Integer', 'cockroachdb': 'Integer', 'default': 'Integer'}, 'int64': {'timescaledb': 'BigInteger', 'timescaledb-ha': 'BigInteger', 'postgresql': 'BigInteger', 'postgis': 'BigInteger', 'mariadb': 'BigInteger', 'mysql': 'BigInteger', 'mssql': 'BigInteger', 'oracle': 'BigInteger', 'sqlite': 'BigInteger', 'geopackage': 'BigInteger', 'duckdb': 'BigInteger', 'citus': 'BigInteger', 'cockroachdb': 'BigInteger', 'default': 'BigInteger'}, 'float': {'timescaledb': 'Float', 'timescaledb-ha': 'Float', 'postgresql': 'Float', 'postgis': 'Float', 'mariadb': 'Float', 'mysql': 'Float', 'mssql': 'Float', 'oracle': 'Float', 'sqlite': 'Float', 'geopackage': 'Float', 'duckdb': 'Float', 'citus': 'Float', 'cockroachdb': 'Float', 'default': 'Float'}, 'datetime': {'timescaledb': 'DateTime(timezone=True)', 'timescaledb-ha': 'DateTime(timezone=True)', 'postgresql': 'DateTime(timezone=True)', 'postgis': 'DateTime(timezone=True)', 'mariadb': 'DateTime(timezone=True)', 'mysql': 'DateTime(timezone=True)', 'mssql': 'sqlalchemy.dialects.mssql.DATETIMEOFFSET', 'oracle': 'sqlalchemy.dialects.oracle.TIMESTAMP', 'sqlite': 'DateTime(timezone=True)', 'geopackage': 'DateTime(timezone=True)', 'duckdb': 'DateTime(timezone=True)', 'citus': 'DateTime(timezone=True)', 'cockroachdb': 'DateTime(timezone=True)', 'default': 'DateTime(timezone=True)'}, 'datetime64[ns]': {'timescaledb': 'DateTime', 'timescaledb-ha': 'DateTime', 'postgresql': 'DateTime', 'postgis': 'DateTime', 'mariadb': 'DateTime', 'mysql': 'DateTime', 'mssql': 'sqlalchemy.dialects.mssql.DATETIME2', 'oracle': 'DateTime', 'sqlite': 'DateTime', 'geopackage': 'DateTime', 'duckdb': 'DateTime', 'citus': 'DateTime', 'cockroachdb': 'DateTime', 'default': 'DateTime'}, 'datetime64[ns, UTC]': {'timescaledb': 'DateTime(timezone=True)', 'timescaledb-ha': 'DateTime(timezone=True)', 'postgresql': 'DateTime(timezone=True)', 'postgis': 'DateTime(timezone=True)', 'mariadb': 'DateTime(timezone=True)', 'mysql': 'DateTime(timezone=True)', 'mssql': 'sqlalchemy.dialects.mssql.DATETIMEOFFSET', 'oracle': 'sqlalchemy.dialects.oracle.TIMESTAMP', 'sqlite': 'DateTime(timezone=True)', 'geopackage': 'DateTime(timezone=True)', 'duckdb': 'DateTime(timezone=True)', 'citus': 'DateTime(timezone=True)', 'cockroachdb': 'DateTime(timezone=True)', 'default': 'DateTime(timezone=True)'}, 'datetime64[us]': {'timescaledb': 'DateTime', 'timescaledb-ha': 'DateTime', 'postgresql': 'DateTime', 'postgis': 'DateTime', 'mariadb': 'DateTime', 'mysql': 'DateTime', 'mssql': 'sqlalchemy.dialects.mssql.DATETIME2', 'oracle': 'DateTime', 'sqlite': 'DateTime', 'geopackage': 'DateTime', 'duckdb': 'DateTime', 'citus': 'DateTime', 'cockroachdb': 'DateTime', 'default': 'DateTime'}, 'datetime64[us, UTC]': {'timescaledb': 'DateTime(timezone=True)', 'timescaledb-ha': 'DateTime(timezone=True)', 'postgresql': 'DateTime(timezone=True)', 'postgis': 'DateTime(timezone=True)', 'mariadb': 'DateTime(timezone=True)', 'mysql': 'DateTime(timezone=True)', 'mssql': 'sqlalchemy.dialects.mssql.DATETIMEOFFSET', 'oracle': 'sqlalchemy.dialects.oracle.TIMESTAMP', 'sqlite': 'DateTime(timezone=True)', 'geopackage': 'DateTime(timezone=True)', 'duckdb': 'DateTime(timezone=True)', 'citus': 'DateTime(timezone=True)', 'cockroachdb': 'DateTime(timezone=True)', 'default': 'DateTime(timezone=True)'}, 'datetime64[ms]': {'timescaledb': 'DateTime', 'timescaledb-ha': 'DateTime', 'postgresql': 'DateTime', 'postgis': 'DateTime', 'mariadb': 'DateTime', 'mysql': 'DateTime', 'mssql': 'sqlalchemy.dialects.mssql.DATETIME2', 'oracle': 'DateTime', 'sqlite': 'DateTime', 'geopackage': 'DateTime', 'duckdb': 'DateTime', 'citus': 'DateTime', 'cockroachdb': 'DateTime', 'default': 'DateTime'}, 'datetime64[ms, UTC]': {'timescaledb': 'DateTime(timezone=True)', 'timescaledb-ha': 'DateTime(timezone=True)', 'postgresql': 'DateTime(timezone=True)', 'postgis': 'DateTime(timezone=True)', 'mariadb': 'DateTime(timezone=True)', 'mysql': 'DateTime(timezone=True)', 'mssql': 'sqlalchemy.dialects.mssql.DATETIMEOFFSET', 'oracle': 'sqlalchemy.dialects.oracle.TIMESTAMP', 'sqlite': 'DateTime(timezone=True)', 'geopackage': 'DateTime(timezone=True)', 'duckdb': 'DateTime(timezone=True)', 'citus': 'DateTime(timezone=True)', 'cockroachdb': 'DateTime(timezone=True)', 'default': 'DateTime(timezone=True)'}, 'datetime64[s]': {'timescaledb': 'DateTime', 'timescaledb-ha': 'DateTime', 'postgresql': 'DateTime', 'postgis': 'DateTime', 'mariadb': 'DateTime', 'mysql': 'DateTime', 'mssql': 'sqlalchemy.dialects.mssql.DATETIME2', 'oracle': 'DateTime', 'sqlite': 'DateTime', 'geopackage': 'DateTime', 'duckdb': 'DateTime', 'citus': 'DateTime', 'cockroachdb': 'DateTime', 'default': 'DateTime'}, 'datetime64[s, UTC]': {'timescaledb': 'DateTime(timezone=True)', 'timescaledb-ha': 'DateTime(timezone=True)', 'postgresql': 'DateTime(timezone=True)', 'postgis': 'DateTime(timezone=True)', 'mariadb': 'DateTime(timezone=True)', 'mysql': 'DateTime(timezone=True)', 'mssql': 'sqlalchemy.dialects.mssql.DATETIMEOFFSET', 'oracle': 'sqlalchemy.dialects.oracle.TIMESTAMP', 'sqlite': 'DateTime(timezone=True)', 'geopackage': 'DateTime(timezone=True)', 'duckdb': 'DateTime(timezone=True)', 'citus': 'DateTime(timezone=True)', 'cockroachdb': 'DateTime(timezone=True)', 'default': 'DateTime(timezone=True)'}, 'date': {'timescaledb': 'Date', 'timescaledb-ha': 'Date', 'postgresql': 'Date', 'postgis': 'Date', 'mariadb': 'Date', 'mysql': 'Date', 'mssql': 'Date', 'oracle': 'Date', 'sqlite': 'Date', 'geopackage': 'Date', 'duckdb': 'Date', 'citus': 'Date', 'cockroachdb': 'Date', 'default': 'Date'}, 'bool': {'timescaledb': 'Boolean', 'timescaledb-ha': 'Boolean', 'postgresql': 'Boolean', 'postgis': 'Boolean', 'mariadb': 'Integer', 'mysql': 'Integer', 'mssql': 'sqlalchemy.dialects.mssql.BIT', 'oracle': 'Integer', 'sqlite': 'Float', 'geopackage': 'Float', 'duckdb': 'Boolean', 'citus': 'Boolean', 'cockroachdb': 'Boolean', 'default': 'Boolean'}, 'bool[pyarrow]': {'timescaledb': 'Boolean', 'timescaledb-ha': 'Boolean', 'postgresql': 'Boolean', 'postgis': 'Boolean', 'mariadb': 'Integer', 'mysql': 'Integer', 'mssql': 'sqlalchemy.dialects.mssql.BIT', 'oracle': 'Integer', 'sqlite': 'Float', 'geopackage': 'Float', 'duckdb': 'Boolean', 'citus': 'Boolean', 'cockroachdb': 'Boolean', 'default': 'Boolean'}, 'boolean': {'timescaledb': 'Boolean', 'timescaledb-ha': 'Boolean', 'postgresql': 'Boolean', 'postgis': 'Boolean', 'mariadb': 'Integer', 'mysql': 'Integer', 'mssql': 'sqlalchemy.dialects.mssql.BIT', 'oracle': 'Integer', 'sqlite': 'Float', 'geopackage': 'Float', 'duckdb': 'Boolean', 'citus': 'Boolean', 'cockroachdb': 'Boolean', 'default': 'Boolean'}, 'object': {'timescaledb': 'UnicodeText', 'timescaledb-ha': 'UnicodeText', 'postgresql': 'UnicodeText', 'postgis': 'UnicodeText', 'mariadb': 'UnicodeText', 'mysql': 'UnicodeText', 'mssql': 'UnicodeText', 'oracle': 'UnicodeText', 'sqlite': 'UnicodeText', 'geopackage': 'UnicodeText', 'duckdb': 'UnicodeText', 'citus': 'UnicodeText', 'cockroachdb': 'UnicodeText', 'default': 'UnicodeText'}, 'string': {'timescaledb': 'UnicodeText', 'timescaledb-ha': 'UnicodeText', 'postgresql': 'UnicodeText', 'postgis': 'UnicodeText', 'mariadb': 'UnicodeText', 'mysql': 'UnicodeText', 'mssql': 'UnicodeText', 'oracle': 'UnicodeText', 'sqlite': 'UnicodeText', 'geopackage': 'UnicodeText', 'duckdb': 'UnicodeText', 'citus': 'UnicodeText', 'cockroachdb': 'UnicodeText', 'default': 'UnicodeText'}, 'json': {'timescaledb': 'sqlalchemy.dialects.postgresql.JSONB', 'timescaledb-ha': 'sqlalchemy.dialects.postgresql.JSONB', 'postgresql': 'sqlalchemy.dialects.postgresql.JSONB', 'postgis': 'sqlalchemy.dialects.postgresql.JSONB', 'mariadb': 'UnicodeText', 'mysql': 'UnicodeText', 'mssql': 'UnicodeText', 'oracle': 'UnicodeText', 'sqlite': 'UnicodeText', 'geopackage': 'UnicodeText', 'duckdb': 'TEXT', 'citus': 'sqlalchemy.dialects.postgresql.JSONB', 'cockroachdb': 'sqlalchemy.dialects.postgresql.JSONB', 'default': 'UnicodeText'}, 'numeric': {'timescaledb': 'Numeric', 'timescaledb-ha': 'Numeric', 'postgresql': 'Numeric', 'postgis': 'Numeric', 'mariadb': 'Numeric', 'mysql': 'Numeric', 'mssql': 'Numeric', 'oracle': 'Numeric', 'sqlite': 'UnicodeText', 'geopackage': 'UnicodeText', 'duckdb': 'Numeric', 'citus': 'Numeric', 'cockroachdb': 'Numeric', 'default': 'Numeric'}, 'uuid': {'timescaledb': 'Uuid', 'timescaledb-ha': 'Uuid', 'postgresql': 'Uuid', 'postgis': 'Uuid', 'mariadb': 'sqlalchemy.dialects.mysql.CHAR(36)', 'mysql': 'sqlalchemy.dialects.mysql.CHAR(36)', 'mssql': 'Uuid', 'oracle': 'sqlalchemy.dialects.oracle.CHAR(36)', 'sqlite': 'UnicodeText', 'geopackage': 'UnicodeText', 'duckdb': 'UnicodeText', 'citus': 'Uuid', 'cockroachdb': 'Uuid', 'default': 'Uuid'}, 'binary[pyarrow]': {'timescaledb': 'LargeBinary', 'timescaledb-ha': 'LargeBinary', 'postgresql': 'LargeBinary', 'postgis': 'LargeBinary', 'mariadb': 'LargeBinary', 'mysql': 'LargeBinary', 'mssql': 'LargeBinary', 'oracle': 'LargeBinary', 'sqlite': 'LargeBinary', 'geopackage': 'LargeBinary', 'duckdb': 'LargeBinary', 'citus': 'LargeBinary', 'cockroachdb': 'LargeBinary', 'default': 'LargeBinary'}, 'bytes': {'timescaledb': 'LargeBinary', 'timescaledb-ha': 'LargeBinary', 'postgresql': 'LargeBinary', 'postgis': 'LargeBinary', 'mariadb': 'LargeBinary', 'mysql': 'LargeBinary', 'mssql': 'LargeBinary', 'oracle': 'LargeBinary', 'sqlite': 'LargeBinary', 'geopackage': 'LargeBinary', 'duckdb': 'LargeBinary', 'citus': 'LargeBinary', 'cockroachdb': 'LargeBinary', 'default': 'LargeBinary'}, 'geometry': {'timescaledb': 'UnicodeText', 'timescaledb-ha': 'geoalchemy2.Geometry', 'postgresql': 'UnicodeText', 'postgis': 'geoalchemy2.Geometry', 'mariadb': 'UnicodeText', 'mysql': 'UnicodeText', 'mssql': 'UnicodeText', 'oracle': 'UnicodeText', 'sqlite': 'UnicodeText', 'geopackage': 'LargeBinary', 'duckdb': 'UnicodeText', 'citus': 'UnicodeText', 'cockroachdb': 'UnicodeText', 'default': 'UnicodeText'}, 'geography': {'timescaledb': 'UnicodeText', 'timescaledb-ha': 'geoalchemy2.Geography', 'postgresql': 'UnicodeText', 'postgis': 'geoalchemy2.Geography', 'mariadb': 'UnicodeText', 'mysql': 'UnicodeText', 'mssql': 'UnicodeText', 'oracle': 'UnicodeText', 'sqlite': 'UnicodeText', 'geopackage': 'LargeBinary', 'duckdb': 'UnicodeText', 'citus': 'UnicodeText', 'cockroachdb': 'UnicodeText', 'default': 'UnicodeText'}}
AUTO_INCREMENT_COLUMN_FLAVORS: Dict[str, str] =
{'timescaledb': 'GENERATED BY DEFAULT AS IDENTITY', 'timescaledb-ha': 'GENERATED BY DEFAULT AS IDENTITY', 'postgresql': 'GENERATED BY DEFAULT AS IDENTITY', 'postgis': 'GENERATED BY DEFAULT AS IDENTITY', 'mariadb': 'AUTO_INCREMENT', 'mysql': 'AUTO_INCREMENT', 'mssql': 'IDENTITY(1,1)', 'oracle': 'GENERATED BY DEFAULT ON NULL AS IDENTITY', 'sqlite': 'AUTOINCREMENT', 'geopackage': 'AUTOINCREMENT', 'duckdb': 'GENERATED BY DEFAULT', 'citus': 'GENERATED BY DEFAULT', 'cockroachdb': 'GENERATED BY DEFAULT AS IDENTITY', 'default': 'GENERATED BY DEFAULT AS IDENTITY'}
def
get_pd_type_from_db_type(db_type: str, allow_custom_dtypes: bool = True) -> str:
1163def get_pd_type_from_db_type(db_type: str, allow_custom_dtypes: bool = True) -> str: 1164 """ 1165 Parse a database type to a pandas data type. 1166 1167 Parameters 1168 ---------- 1169 db_type: str 1170 The database type, e.g. `DATETIME`, `BIGINT`, etc. 1171 1172 allow_custom_dtypes: bool, default False 1173 If `True`, allow for custom data types like `json` and `str`. 1174 1175 Returns 1176 ------- 1177 The equivalent datatype for a pandas DataFrame. 1178 """ 1179 _rust = _core.get_pd_type_from_db_type 1180 return _rust(db_type, allow_custom_dtypes=allow_custom_dtypes)
Parse a database type to a pandas data type.
Parameters
- db_type (str):
The database type, e.g.
DATETIME,BIGINT, etc. - allow_custom_dtypes (bool, default False):
If
True, allow for custom data types likejsonandstr.
Returns
- The equivalent datatype for a pandas DataFrame.
def
get_db_type_from_pd_type( pd_type: str, flavor: str = 'default', as_sqlalchemy: bool = False) -> "Union[str, 'sqlalchemy.sql.visitors.TraversibleType']":
1183def get_db_type_from_pd_type( 1184 pd_type: str, 1185 flavor: str = 'default', 1186 as_sqlalchemy: bool = False, 1187) -> Union[str, 'sqlalchemy.sql.visitors.TraversibleType']: 1188 """ 1189 Parse a Pandas data type into a flavor's database type. 1190 1191 Parameters 1192 ---------- 1193 pd_type: str 1194 The Pandas datatype. This must be a string, not the actual dtype object. 1195 1196 flavor: str, default 'default' 1197 The flavor of the database to be mapped to. 1198 1199 as_sqlalchemy: bool, default False 1200 If `True`, return a type from `sqlalchemy.types`. 1201 1202 Returns 1203 ------- 1204 The database data type for the incoming Pandas data type. 1205 If nothing can be found, a warning will be thrown and 'TEXT' will be returned. 1206 """ 1207 from meerschaum.utils.warnings import warn 1208 from meerschaum.utils.packages import attempt_import 1209 from meerschaum.utils.dtypes import are_dtypes_equal, MRSM_ALIAS_DTYPES, get_geometry_type_srid 1210 from meerschaum.utils.misc import parse_arguments_str 1211 sqlalchemy_types = attempt_import('sqlalchemy.types', lazy=False) 1212 1213 types_registry = ( 1214 PD_TO_DB_DTYPES_FLAVORS 1215 if not as_sqlalchemy 1216 else PD_TO_SQLALCHEMY_DTYPES_FLAVORS 1217 ) 1218 1219 precision, scale = None, None 1220 geometry_type, geometry_srid = None, None 1221 og_pd_type = pd_type 1222 if pd_type in MRSM_ALIAS_DTYPES: 1223 pd_type = MRSM_ALIAS_DTYPES[pd_type] 1224 1225 ### Check whether we are able to match this type (e.g. pyarrow support). 1226 found_db_type = False 1227 if ( 1228 pd_type not in types_registry 1229 and not any( 1230 pd_type.startswith(f'{typ}[') 1231 for typ in ('numeric', 'geometry', 'geography') 1232 ) 1233 ): 1234 for mapped_pd_type in types_registry: 1235 if are_dtypes_equal(mapped_pd_type, pd_type): 1236 pd_type = mapped_pd_type 1237 found_db_type = True 1238 break 1239 elif (pd_type.startswith('geometry[') or pd_type.startswith('geography[')): 1240 og_pd_type = pd_type 1241 pd_type = 'geometry' if 'geometry' in pd_type else 'geography' 1242 geometry_type, geometry_srid = get_geometry_type_srid(og_pd_type) 1243 if isinstance(geometry_srid, str): 1244 geometry_srid = int(geometry_srid.split(':', maxsplit=1)[-1]) 1245 found_db_type = True 1246 elif pd_type.startswith('numeric['): 1247 og_pd_type = pd_type 1248 pd_type = 'numeric' 1249 precision, scale = get_numeric_precision_scale(flavor, og_pd_type) 1250 found_db_type = True 1251 else: 1252 found_db_type = True 1253 1254 if not found_db_type: 1255 warn(f"Unknown Pandas data type '{pd_type}'. Falling back to 'TEXT'.", stacklevel=3) 1256 return ( 1257 'TEXT' 1258 if not as_sqlalchemy 1259 else sqlalchemy_types.UnicodeText 1260 ) 1261 flavor_types = types_registry.get( 1262 pd_type, 1263 { 1264 'default': ( 1265 'TEXT' 1266 if not as_sqlalchemy 1267 else 'UnicodeText' 1268 ), 1269 }, 1270 ) 1271 default_flavor_type = flavor_types.get( 1272 'default', 1273 ( 1274 'TEXT' 1275 if not as_sqlalchemy 1276 else 'UnicodeText' 1277 ), 1278 ) 1279 if flavor not in flavor_types: 1280 warn(f"Unknown flavor '{flavor}'. Falling back to '{default_flavor_type}' (default).") 1281 db_type = flavor_types.get(flavor, default_flavor_type) 1282 if not as_sqlalchemy: 1283 if precision is not None and scale is not None: 1284 db_type_bare = db_type.split('(', maxsplit=1)[0] 1285 return f"{db_type_bare}({precision},{scale})" 1286 if geometry_type is not None and geometry_srid is not None: 1287 if 'geometry' not in db_type.lower() and 'geography' not in db_type.lower(): 1288 return db_type 1289 db_type_bare = db_type.split('(', maxsplit=1)[0] 1290 if isinstance(geometry_srid, str): 1291 geometry_srid = int(geometry_srid.split(':')[-1]) 1292 return f"{db_type_bare}({geometry_type.upper()}, {geometry_srid})" 1293 return db_type 1294 1295 if db_type.startswith('sqlalchemy.dialects'): 1296 dialect, typ_class_name = db_type.replace('sqlalchemy.dialects.', '').split('.', maxsplit=2) 1297 cls_args, cls_kwargs = None, None 1298 if '(' in typ_class_name: 1299 typ_class_name, args_str = typ_class_name.split('(', maxsplit=1) 1300 args_str = args_str.rstrip(')') 1301 cls_args, cls_kwargs = parse_arguments_str(args_str) 1302 sqlalchemy_dialects_flavor_module = attempt_import(f'sqlalchemy.dialects.{dialect}') 1303 cls = getattr(sqlalchemy_dialects_flavor_module, typ_class_name) 1304 if cls_args is None: 1305 return cls 1306 return cls(*cls_args, **cls_kwargs) 1307 1308 if 'geometry' in db_type.lower() or 'geography' in db_type.lower(): 1309 geoalchemy2 = attempt_import('geoalchemy2', lazy=False) 1310 geometry_class = ( 1311 geoalchemy2.Geometry 1312 if 'geometry' in db_type.lower() 1313 else geoalchemy2.Geography 1314 ) 1315 if geometry_type is None or geometry_srid is None: 1316 return geometry_class 1317 return geometry_class(geometry_type=geometry_type, srid=geometry_srid) 1318 1319 if 'numeric' in db_type.lower(): 1320 if precision is None or scale is None: 1321 return sqlalchemy_types.Numeric 1322 return sqlalchemy_types.Numeric(precision, scale) 1323 1324 cls_args, cls_kwargs = None, None 1325 typ_class_name = db_type 1326 if '(' in db_type: 1327 typ_class_name, args_str = db_type.split('(', maxsplit=1) 1328 args_str = args_str.rstrip(')') 1329 cls_args, cls_kwargs = parse_arguments_str(args_str) 1330 1331 cls = getattr(sqlalchemy_types, typ_class_name) 1332 if cls_args is None: 1333 return cls 1334 return cls(*cls_args, **cls_kwargs)
Parse a Pandas data type into a flavor's database type.
Parameters
- pd_type (str): The Pandas datatype. This must be a string, not the actual dtype object.
- flavor (str, default 'default'): The flavor of the database to be mapped to.
- as_sqlalchemy (bool, default False):
If
True, return a type fromsqlalchemy.types.
Returns
- The database data type for the incoming Pandas data type.
- If nothing can be found, a warning will be thrown and 'TEXT' will be returned.
def
get_numeric_precision_scale( flavor: str, dtype: str | None = None) -> Tuple[int, int] | Tuple[NoneType, NoneType]:
1337def get_numeric_precision_scale( 1338 flavor: str, 1339 dtype: Optional[str] = None, 1340) -> Union[Tuple[int, int], Tuple[None, None]]: 1341 """ 1342 Return the precision and scale to use for a numeric column for a given database flavor. 1343 1344 Parameters 1345 ---------- 1346 flavor: str 1347 The database flavor for which to return the precision and scale. 1348 1349 dtype: Optional[str], default None 1350 If provided, return the precision and scale provided in the dtype (if applicable). 1351 If all caps, treat this as a DB type. 1352 1353 Returns 1354 ------- 1355 A tuple of ints or a tuple of Nones. 1356 """ 1357 if not dtype: 1358 return None, None 1359 1360 lbracket = '[' if '[' in dtype else '(' 1361 rbracket = ']' if lbracket == '[' else ')' 1362 if lbracket in dtype and dtype.count(',') == 1 and dtype.endswith(rbracket): 1363 try: 1364 parts = dtype.split(lbracket, maxsplit=1)[-1].rstrip(rbracket).split(',', maxsplit=1) 1365 return int(parts[0].strip()), int(parts[1].strip()) 1366 except Exception: 1367 pass 1368 1369 return NUMERIC_PRECISION_FLAVORS.get(flavor, (None, None))
Return the precision and scale to use for a numeric column for a given database flavor.
Parameters
- flavor (str): The database flavor for which to return the precision and scale.
- dtype (Optional[str], default None): If provided, return the precision and scale provided in the dtype (if applicable). If all caps, treat this as a DB type.
Returns
- A tuple of ints or a tuple of Nones.
NUMERIC_AS_TEXT_FLAVORS =
{'sqlite', 'duckdb', 'geopackage'}