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.utils.dtypes import MRSM_PRECISION_UNITS_ABBREVIATIONS as _MRSM_PRECISION_UNITS_ABBREVIATIONS 13 14NUMERIC_PRECISION_FLAVORS: Dict[str, Tuple[int, int]] = { 15 'mariadb': (38, 20), 16 'mysql': (38, 20), 17 'mssql': (28, 10), 18} 19NUMERIC_AS_TEXT_FLAVORS = {'sqlite', 'duckdb', 'geopackage'} 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': 'GEOMETRY', 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': 'TEXT', 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': 'UnicodeText', 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 from meerschaum.utils.dtypes import are_dtypes_equal, get_geometry_type_srid 1179 def parse_custom(_pd_type: str, _db_type: str) -> str: 1180 if 'json' in _db_type.lower(): 1181 return 'json' 1182 if are_dtypes_equal(_pd_type, 'numeric') and _pd_type != 'object': 1183 precision, scale = get_numeric_precision_scale(None, dtype=_db_type.upper()) 1184 if precision and scale: 1185 return f"numeric[{precision},{scale}]" 1186 if are_dtypes_equal(_pd_type, 'geometry') and _pd_type != 'object': 1187 geometry_type, srid = get_geometry_type_srid(_db_type.upper()) 1188 modifiers = [str(modifier) for modifier in (geometry_type, srid) if modifier] 1189 typ = "geometry" if 'geography' not in _pd_type.lower() else 'geography' 1190 if not modifiers: 1191 return typ 1192 return f"{typ}[{', '.join(modifiers)}]" 1193 return _pd_type 1194 1195 pd_type = DB_TO_PD_DTYPES.get(db_type.upper().split('(', maxsplit=1)[0].strip(), None) 1196 if pd_type is not None: 1197 return ( 1198 parse_custom(pd_type, db_type) 1199 if allow_custom_dtypes 1200 else pd_type 1201 ) 1202 for db_t, pd_t in DB_TO_PD_DTYPES['substrings'].items(): 1203 if db_t in db_type.upper(): 1204 return ( 1205 parse_custom(pd_t, db_t) 1206 if allow_custom_dtypes 1207 else pd_t 1208 ) 1209 return DB_TO_PD_DTYPES['default'] 1210 1211 1212def get_db_type_from_pd_type( 1213 pd_type: str, 1214 flavor: str = 'default', 1215 as_sqlalchemy: bool = False, 1216) -> Union[str, 'sqlalchemy.sql.visitors.TraversibleType']: 1217 """ 1218 Parse a Pandas data type into a flavor's database type. 1219 1220 Parameters 1221 ---------- 1222 pd_type: str 1223 The Pandas datatype. This must be a string, not the actual dtype object. 1224 1225 flavor: str, default 'default' 1226 The flavor of the database to be mapped to. 1227 1228 as_sqlalchemy: bool, default False 1229 If `True`, return a type from `sqlalchemy.types`. 1230 1231 Returns 1232 ------- 1233 The database data type for the incoming Pandas data type. 1234 If nothing can be found, a warning will be thrown and 'TEXT' will be returned. 1235 """ 1236 from meerschaum.utils.warnings import warn 1237 from meerschaum.utils.packages import attempt_import 1238 from meerschaum.utils.dtypes import are_dtypes_equal, MRSM_ALIAS_DTYPES, get_geometry_type_srid 1239 from meerschaum.utils.misc import parse_arguments_str 1240 sqlalchemy_types = attempt_import('sqlalchemy.types', lazy=False) 1241 1242 types_registry = ( 1243 PD_TO_DB_DTYPES_FLAVORS 1244 if not as_sqlalchemy 1245 else PD_TO_SQLALCHEMY_DTYPES_FLAVORS 1246 ) 1247 1248 precision, scale = None, None 1249 geometry_type, geometry_srid = None, None 1250 og_pd_type = pd_type 1251 if pd_type in MRSM_ALIAS_DTYPES: 1252 pd_type = MRSM_ALIAS_DTYPES[pd_type] 1253 1254 ### Check whether we are able to match this type (e.g. pyarrow support). 1255 found_db_type = False 1256 if ( 1257 pd_type not in types_registry 1258 and not any( 1259 pd_type.startswith(f'{typ}[') 1260 for typ in ('numeric', 'geometry', 'geography') 1261 ) 1262 ): 1263 for mapped_pd_type in types_registry: 1264 if are_dtypes_equal(mapped_pd_type, pd_type): 1265 pd_type = mapped_pd_type 1266 found_db_type = True 1267 break 1268 elif (pd_type.startswith('geometry[') or pd_type.startswith('geography[')): 1269 og_pd_type = pd_type 1270 pd_type = 'geometry' if 'geometry' in pd_type else 'geography' 1271 geometry_type, geometry_srid = get_geometry_type_srid(og_pd_type) 1272 found_db_type = True 1273 elif pd_type.startswith('numeric['): 1274 og_pd_type = pd_type 1275 pd_type = 'numeric' 1276 precision, scale = get_numeric_precision_scale(flavor, og_pd_type) 1277 found_db_type = True 1278 else: 1279 found_db_type = True 1280 1281 if not found_db_type: 1282 warn(f"Unknown Pandas data type '{pd_type}'. Falling back to 'TEXT'.", stacklevel=3) 1283 return ( 1284 'TEXT' 1285 if not as_sqlalchemy 1286 else sqlalchemy_types.UnicodeText 1287 ) 1288 flavor_types = types_registry.get( 1289 pd_type, 1290 { 1291 'default': ( 1292 'TEXT' 1293 if not as_sqlalchemy 1294 else 'UnicodeText' 1295 ), 1296 }, 1297 ) 1298 default_flavor_type = flavor_types.get( 1299 'default', 1300 ( 1301 'TEXT' 1302 if not as_sqlalchemy 1303 else 'UnicodeText' 1304 ), 1305 ) 1306 if flavor not in flavor_types: 1307 warn(f"Unknown flavor '{flavor}'. Falling back to '{default_flavor_type}' (default).") 1308 db_type = flavor_types.get(flavor, default_flavor_type) 1309 if not as_sqlalchemy: 1310 if precision is not None and scale is not None: 1311 db_type_bare = db_type.split('(', maxsplit=1)[0] 1312 return f"{db_type_bare}({precision},{scale})" 1313 if geometry_type is not None and geometry_srid is not None: 1314 if 'geometry' not in db_type.lower() and 'geography' not in db_type.lower(): 1315 return db_type 1316 db_type_bare = db_type.split('(', maxsplit=1)[0] 1317 return f"{db_type_bare}({geometry_type.upper()}, {geometry_srid})" 1318 return db_type 1319 1320 if db_type.startswith('sqlalchemy.dialects'): 1321 dialect, typ_class_name = db_type.replace('sqlalchemy.dialects.', '').split('.', maxsplit=2) 1322 cls_args, cls_kwargs = None, None 1323 if '(' in typ_class_name: 1324 typ_class_name, args_str = typ_class_name.split('(', maxsplit=1) 1325 args_str = args_str.rstrip(')') 1326 cls_args, cls_kwargs = parse_arguments_str(args_str) 1327 sqlalchemy_dialects_flavor_module = attempt_import(f'sqlalchemy.dialects.{dialect}') 1328 cls = getattr(sqlalchemy_dialects_flavor_module, typ_class_name) 1329 if cls_args is None: 1330 return cls 1331 return cls(*cls_args, **cls_kwargs) 1332 1333 if 'geometry' in db_type.lower() or 'geography' in db_type.lower(): 1334 geoalchemy2 = attempt_import('geoalchemy2', lazy=False) 1335 geometry_class = ( 1336 geoalchemy2.Geometry 1337 if 'geometry' in db_type.lower() 1338 else geoalchemy2.Geography 1339 ) 1340 if geometry_type is None or geometry_srid is None: 1341 return geometry_class 1342 return geometry_class(geometry_type=geometry_type, srid=geometry_srid) 1343 1344 if 'numeric' in db_type.lower(): 1345 if precision is None or scale is None: 1346 return sqlalchemy_types.Numeric 1347 return sqlalchemy_types.Numeric(precision, scale) 1348 1349 cls_args, cls_kwargs = None, None 1350 typ_class_name = db_type 1351 if '(' in db_type: 1352 typ_class_name, args_str = db_type.split('(', maxsplit=1) 1353 args_str = args_str.rstrip(')') 1354 cls_args, cls_kwargs = parse_arguments_str(args_str) 1355 1356 cls = getattr(sqlalchemy_types, typ_class_name) 1357 if cls_args is None: 1358 return cls 1359 return cls(*cls_args, **cls_kwargs) 1360 1361 1362def get_numeric_precision_scale( 1363 flavor: str, 1364 dtype: Optional[str] = None, 1365) -> Union[Tuple[int, int], Tuple[None, None]]: 1366 """ 1367 Return the precision and scale to use for a numeric column for a given database flavor. 1368 1369 Parameters 1370 ---------- 1371 flavor: str 1372 The database flavor for which to return the precision and scale. 1373 1374 dtype: Optional[str], default None 1375 If provided, return the precision and scale provided in the dtype (if applicable). 1376 If all caps, treat this as a DB type. 1377 1378 Returns 1379 ------- 1380 A tuple of ints or a tuple of Nones. 1381 """ 1382 if not dtype: 1383 return None, None 1384 1385 lbracket = '[' if '[' in dtype else '(' 1386 rbracket = ']' if lbracket == '[' else ')' 1387 if lbracket in dtype and dtype.count(',') == 1 and dtype.endswith(rbracket): 1388 try: 1389 parts = dtype.split(lbracket, maxsplit=1)[-1].rstrip(rbracket).split(',', maxsplit=1) 1390 return int(parts[0].strip()), int(parts[1].strip()) 1391 except Exception: 1392 pass 1393 1394 return NUMERIC_PRECISION_FLAVORS.get(flavor, (None, None))
NUMERIC_PRECISION_FLAVORS: Dict[str, Tuple[int, int]] =
{'mariadb': (38, 20), 'mysql': (38, 20), 'mssql': (28, 10)}
NUMERIC_AS_TEXT_FLAVORS =
{'geopackage', 'sqlite', 'duckdb'}
TIMEZONE_NAIVE_FLAVORS =
{'mariadb', 'mysql', 'oracle'}
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, Union[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': 'GEOMETRY', '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': 'TEXT', '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': 'UnicodeText', '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 from meerschaum.utils.dtypes import are_dtypes_equal, get_geometry_type_srid 1180 def parse_custom(_pd_type: str, _db_type: str) -> str: 1181 if 'json' in _db_type.lower(): 1182 return 'json' 1183 if are_dtypes_equal(_pd_type, 'numeric') and _pd_type != 'object': 1184 precision, scale = get_numeric_precision_scale(None, dtype=_db_type.upper()) 1185 if precision and scale: 1186 return f"numeric[{precision},{scale}]" 1187 if are_dtypes_equal(_pd_type, 'geometry') and _pd_type != 'object': 1188 geometry_type, srid = get_geometry_type_srid(_db_type.upper()) 1189 modifiers = [str(modifier) for modifier in (geometry_type, srid) if modifier] 1190 typ = "geometry" if 'geography' not in _pd_type.lower() else 'geography' 1191 if not modifiers: 1192 return typ 1193 return f"{typ}[{', '.join(modifiers)}]" 1194 return _pd_type 1195 1196 pd_type = DB_TO_PD_DTYPES.get(db_type.upper().split('(', maxsplit=1)[0].strip(), None) 1197 if pd_type is not None: 1198 return ( 1199 parse_custom(pd_type, db_type) 1200 if allow_custom_dtypes 1201 else pd_type 1202 ) 1203 for db_t, pd_t in DB_TO_PD_DTYPES['substrings'].items(): 1204 if db_t in db_type.upper(): 1205 return ( 1206 parse_custom(pd_t, db_t) 1207 if allow_custom_dtypes 1208 else pd_t 1209 ) 1210 return DB_TO_PD_DTYPES['default']
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 likejson
andstr
.
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']":
1213def get_db_type_from_pd_type( 1214 pd_type: str, 1215 flavor: str = 'default', 1216 as_sqlalchemy: bool = False, 1217) -> Union[str, 'sqlalchemy.sql.visitors.TraversibleType']: 1218 """ 1219 Parse a Pandas data type into a flavor's database type. 1220 1221 Parameters 1222 ---------- 1223 pd_type: str 1224 The Pandas datatype. This must be a string, not the actual dtype object. 1225 1226 flavor: str, default 'default' 1227 The flavor of the database to be mapped to. 1228 1229 as_sqlalchemy: bool, default False 1230 If `True`, return a type from `sqlalchemy.types`. 1231 1232 Returns 1233 ------- 1234 The database data type for the incoming Pandas data type. 1235 If nothing can be found, a warning will be thrown and 'TEXT' will be returned. 1236 """ 1237 from meerschaum.utils.warnings import warn 1238 from meerschaum.utils.packages import attempt_import 1239 from meerschaum.utils.dtypes import are_dtypes_equal, MRSM_ALIAS_DTYPES, get_geometry_type_srid 1240 from meerschaum.utils.misc import parse_arguments_str 1241 sqlalchemy_types = attempt_import('sqlalchemy.types', lazy=False) 1242 1243 types_registry = ( 1244 PD_TO_DB_DTYPES_FLAVORS 1245 if not as_sqlalchemy 1246 else PD_TO_SQLALCHEMY_DTYPES_FLAVORS 1247 ) 1248 1249 precision, scale = None, None 1250 geometry_type, geometry_srid = None, None 1251 og_pd_type = pd_type 1252 if pd_type in MRSM_ALIAS_DTYPES: 1253 pd_type = MRSM_ALIAS_DTYPES[pd_type] 1254 1255 ### Check whether we are able to match this type (e.g. pyarrow support). 1256 found_db_type = False 1257 if ( 1258 pd_type not in types_registry 1259 and not any( 1260 pd_type.startswith(f'{typ}[') 1261 for typ in ('numeric', 'geometry', 'geography') 1262 ) 1263 ): 1264 for mapped_pd_type in types_registry: 1265 if are_dtypes_equal(mapped_pd_type, pd_type): 1266 pd_type = mapped_pd_type 1267 found_db_type = True 1268 break 1269 elif (pd_type.startswith('geometry[') or pd_type.startswith('geography[')): 1270 og_pd_type = pd_type 1271 pd_type = 'geometry' if 'geometry' in pd_type else 'geography' 1272 geometry_type, geometry_srid = get_geometry_type_srid(og_pd_type) 1273 found_db_type = True 1274 elif pd_type.startswith('numeric['): 1275 og_pd_type = pd_type 1276 pd_type = 'numeric' 1277 precision, scale = get_numeric_precision_scale(flavor, og_pd_type) 1278 found_db_type = True 1279 else: 1280 found_db_type = True 1281 1282 if not found_db_type: 1283 warn(f"Unknown Pandas data type '{pd_type}'. Falling back to 'TEXT'.", stacklevel=3) 1284 return ( 1285 'TEXT' 1286 if not as_sqlalchemy 1287 else sqlalchemy_types.UnicodeText 1288 ) 1289 flavor_types = types_registry.get( 1290 pd_type, 1291 { 1292 'default': ( 1293 'TEXT' 1294 if not as_sqlalchemy 1295 else 'UnicodeText' 1296 ), 1297 }, 1298 ) 1299 default_flavor_type = flavor_types.get( 1300 'default', 1301 ( 1302 'TEXT' 1303 if not as_sqlalchemy 1304 else 'UnicodeText' 1305 ), 1306 ) 1307 if flavor not in flavor_types: 1308 warn(f"Unknown flavor '{flavor}'. Falling back to '{default_flavor_type}' (default).") 1309 db_type = flavor_types.get(flavor, default_flavor_type) 1310 if not as_sqlalchemy: 1311 if precision is not None and scale is not None: 1312 db_type_bare = db_type.split('(', maxsplit=1)[0] 1313 return f"{db_type_bare}({precision},{scale})" 1314 if geometry_type is not None and geometry_srid is not None: 1315 if 'geometry' not in db_type.lower() and 'geography' not in db_type.lower(): 1316 return db_type 1317 db_type_bare = db_type.split('(', maxsplit=1)[0] 1318 return f"{db_type_bare}({geometry_type.upper()}, {geometry_srid})" 1319 return db_type 1320 1321 if db_type.startswith('sqlalchemy.dialects'): 1322 dialect, typ_class_name = db_type.replace('sqlalchemy.dialects.', '').split('.', maxsplit=2) 1323 cls_args, cls_kwargs = None, None 1324 if '(' in typ_class_name: 1325 typ_class_name, args_str = typ_class_name.split('(', maxsplit=1) 1326 args_str = args_str.rstrip(')') 1327 cls_args, cls_kwargs = parse_arguments_str(args_str) 1328 sqlalchemy_dialects_flavor_module = attempt_import(f'sqlalchemy.dialects.{dialect}') 1329 cls = getattr(sqlalchemy_dialects_flavor_module, typ_class_name) 1330 if cls_args is None: 1331 return cls 1332 return cls(*cls_args, **cls_kwargs) 1333 1334 if 'geometry' in db_type.lower() or 'geography' in db_type.lower(): 1335 geoalchemy2 = attempt_import('geoalchemy2', lazy=False) 1336 geometry_class = ( 1337 geoalchemy2.Geometry 1338 if 'geometry' in db_type.lower() 1339 else geoalchemy2.Geography 1340 ) 1341 if geometry_type is None or geometry_srid is None: 1342 return geometry_class 1343 return geometry_class(geometry_type=geometry_type, srid=geometry_srid) 1344 1345 if 'numeric' in db_type.lower(): 1346 if precision is None or scale is None: 1347 return sqlalchemy_types.Numeric 1348 return sqlalchemy_types.Numeric(precision, scale) 1349 1350 cls_args, cls_kwargs = None, None 1351 typ_class_name = db_type 1352 if '(' in db_type: 1353 typ_class_name, args_str = db_type.split('(', maxsplit=1) 1354 args_str = args_str.rstrip(')') 1355 cls_args, cls_kwargs = parse_arguments_str(args_str) 1356 1357 cls = getattr(sqlalchemy_types, typ_class_name) 1358 if cls_args is None: 1359 return cls 1360 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: Optional[str] = None) -> Union[Tuple[int, int], Tuple[NoneType, NoneType]]:
1363def get_numeric_precision_scale( 1364 flavor: str, 1365 dtype: Optional[str] = None, 1366) -> Union[Tuple[int, int], Tuple[None, None]]: 1367 """ 1368 Return the precision and scale to use for a numeric column for a given database flavor. 1369 1370 Parameters 1371 ---------- 1372 flavor: str 1373 The database flavor for which to return the precision and scale. 1374 1375 dtype: Optional[str], default None 1376 If provided, return the precision and scale provided in the dtype (if applicable). 1377 If all caps, treat this as a DB type. 1378 1379 Returns 1380 ------- 1381 A tuple of ints or a tuple of Nones. 1382 """ 1383 if not dtype: 1384 return None, None 1385 1386 lbracket = '[' if '[' in dtype else '(' 1387 rbracket = ']' if lbracket == '[' else ')' 1388 if lbracket in dtype and dtype.count(',') == 1 and dtype.endswith(rbracket): 1389 try: 1390 parts = dtype.split(lbracket, maxsplit=1)[-1].rstrip(rbracket).split(',', maxsplit=1) 1391 return int(parts[0].strip()), int(parts[1].strip()) 1392 except Exception: 1393 pass 1394 1395 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.