diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py index 746978a..15fdcfb 100644 --- a/sqlite_utils/db.py +++ b/sqlite_utils/db.py @@ -1,4 +1,4 @@ -from .utils import sqlite3, OperationalError, suggest_column_types +from .utils import sqlite3, OperationalError, suggest_column_types, column_affinity from collections import namedtuple, OrderedDict import datetime import hashlib @@ -65,15 +65,6 @@ if np: ) -REVERSE_COLUMN_TYPE_MAPPING = { - "": str, # Columns in views sometimes have type = '' - "TEXT": str, - "BLOB": bytes, - "INTEGER": int, - "FLOAT": float, -} - - class AlterError(Exception): pass @@ -457,10 +448,7 @@ class Queryable: @property def columns_dict(self): "Returns {column: python-type} dictionary" - return { - column.name: REVERSE_COLUMN_TYPE_MAPPING[column.type] - for column in self.columns - } + return {column.name: column_affinity(column.type) for column in self.columns} @property def schema(self): diff --git a/sqlite_utils/utils.py b/sqlite_utils/utils.py index 6da6d47..8968a05 100644 --- a/sqlite_utils/utils.py +++ b/sqlite_utils/utils.py @@ -33,3 +33,22 @@ def suggest_column_types(records): t = str column_types[key] = t return column_types + + +def column_affinity(column_type): + # Implementation of SQLite affinity rules from + # https://www.sqlite.org/datatype3.html#determination_of_column_affinity + assert isinstance(column_type, str) + column_type = column_type.upper().strip() + if column_type == "": + return str # We differ from spec, which says it should be BLOB + if "INT" in column_type: + return int + if "CHAR" in column_type or "CLOB" in column_type or "TEXT" in column_type: + return str + if "BLOB" in column_type: + return bytes + if "REAL" in column_type or "FLOA" in column_type or "DOUB" in column_type: + return float + # Default is 'NUMERIC', which we currently also treat as float + return float