2019-07-22 15:39:35 -07:00
|
|
|
try:
|
|
|
|
|
import pysqlite3 as sqlite3
|
2019-07-28 17:51:49 +03:00
|
|
|
import pysqlite3.dbapi2
|
|
|
|
|
|
|
|
|
|
OperationalError = pysqlite3.dbapi2.OperationalError
|
2019-07-22 15:39:35 -07:00
|
|
|
except ImportError:
|
|
|
|
|
import sqlite3
|
2019-07-28 17:51:49 +03:00
|
|
|
|
|
|
|
|
OperationalError = sqlite3.OperationalError
|
2020-02-01 13:38:26 -08:00
|
|
|
|
|
|
|
|
|
|
|
|
|
def suggest_column_types(records):
|
|
|
|
|
all_column_types = {}
|
|
|
|
|
for record in records:
|
|
|
|
|
for key, value in record.items():
|
2020-03-23 12:57:02 -07:00
|
|
|
if value is not None:
|
|
|
|
|
all_column_types.setdefault(key, set()).add(type(value))
|
2020-02-01 13:38:26 -08:00
|
|
|
column_types = {}
|
|
|
|
|
for key, types in all_column_types.items():
|
|
|
|
|
if len(types) == 1:
|
|
|
|
|
t = list(types)[0]
|
2020-02-15 18:20:39 -08:00
|
|
|
# But if it's a subclass of list / tuple / dict, use str
|
|
|
|
|
# instead as we will be storing it as JSON in the table
|
|
|
|
|
for superclass in (list, tuple, dict):
|
|
|
|
|
if issubclass(t, superclass):
|
|
|
|
|
t = str
|
2020-02-01 13:38:26 -08:00
|
|
|
elif {int, bool}.issuperset(types):
|
|
|
|
|
t = int
|
|
|
|
|
elif {int, float, bool}.issuperset(types):
|
|
|
|
|
t = float
|
|
|
|
|
elif {bytes, str}.issuperset(types):
|
|
|
|
|
t = bytes
|
|
|
|
|
else:
|
|
|
|
|
t = str
|
|
|
|
|
column_types[key] = t
|
|
|
|
|
return column_types
|
2020-03-14 13:04:06 -07:00
|
|
|
|
|
|
|
|
|
|
|
|
|
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
|