Skip to content

Commit

Permalink
chore: rewrite sqlite parse
Browse files Browse the repository at this point in the history
  • Loading branch information
kszucs authored and cpcloud committed Sep 4, 2023
1 parent 468bed1 commit f5490c3
Show file tree
Hide file tree
Showing 3 changed files with 11 additions and 35 deletions.
4 changes: 4 additions & 0 deletions ibis/backends/base/sql/glot/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -340,3 +340,7 @@ class OracleType(SqlglotType):

class SnowflakeType(SqlglotType):
dialect = "snowflake"


class SQLiteType(SqlglotType):
dialect = "sqlite"
4 changes: 2 additions & 2 deletions ibis/backends/sqlite/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@
from ibis.backends.base.sql.alchemy import BaseAlchemyBackend
from ibis.backends.sqlite import udf
from ibis.backends.sqlite.compiler import SQLiteCompiler
from ibis.backends.sqlite.datatypes import ISODATETIME, SqliteType, parse
from ibis.backends.sqlite.datatypes import ISODATETIME, SqliteType

if TYPE_CHECKING:
from collections.abc import Iterator
Expand Down Expand Up @@ -204,7 +204,7 @@ def _metadata(self, query: str) -> Iterator[tuple[str, dt.DataType]]:
for name, notnull, raw_typ, typ in zip(
names, notnulls, raw_types, single_row_types
):
ibis_type = parse(raw_typ or typ)
ibis_type = SqliteType.from_string(raw_typ or typ)
yield name, ibis_type(nullable=not notnull)

# drop the view when we're done with it
Expand Down
38 changes: 5 additions & 33 deletions ibis/backends/sqlite/datatypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,39 +9,7 @@

import ibis.expr.datatypes as dt
from ibis.backends.base.sql.alchemy.datatypes import AlchemyType


def parse(text: str) -> dt.DataType:
"""Parse `text` into an ibis data type."""
text = text.strip().upper()

# SQLite affinity rules
# (see https://www.sqlite.org/datatype3.html).

# 1. If the declared type contains the string "INT" then it is
# assigned INTEGER affinity.
if "INT" in text:
return dt.int64

# 2. If the declared type of the column contains any of the
# strings "CHAR", "CLOB", or "TEXT" then that column has TEXT
# affinity. Notice that the type VARCHAR contains the string
# "CHAR" and is thus assigned TEXT affinity.
if "CHAR" in text or "CLOB" in text or "TEXT" in text:
return dt.string

# 3. If the declared type for a column contains the string "BLOB"
# or if no type is specified then the column has affinity BLOB.
if not text or "BLOB" in text:
return dt.binary

# 4. If the declared type for a column contains any of the strings
# "REAL", "FLOA", or "DOUB" then the column has REAL affinity.
if "REAL" in text or "FLOA" in text or "DOUB" in text:
return dt.float64

# 5. Otherwise, the affinity is NUMERIC.
return dt.decimal
from ibis.backends.base.sql.glot.datatypes import SQLiteType as SqlglotSQLiteType


class SqliteType(AlchemyType):
Expand All @@ -63,6 +31,10 @@ def to_ibis(cls, typ: sat.TypeEngine, nullable: bool = True) -> dt.DataType:
else:
return super().to_ibis(typ, nullable=nullable)

@classmethod
def from_string(cls, type_string, nullable=True):
return SqlglotSQLiteType.from_string(type_string, nullable=nullable)


class ISODATETIME(sqlite.DATETIME):
"""A thin `datetime` type to override sqlalchemy's datetime parsing.
Expand Down

0 comments on commit f5490c3

Please sign in to comment.