mirror of
https://github.com/simonw/sqlite-utils.git
synced 2026-09-12 19:44:13 +02:00
Add more STRICT table support per https://github.com/simonw/sqlite-utils/issues/344#issuecomment-982014776.
Make table.transform() preserve STRICT mode.
This commit is contained in:
parent
9286c1ba43
commit
e4b9b582cd
9 changed files with 182 additions and 4 deletions
|
|
@ -300,6 +300,7 @@ class Database:
|
|||
``sql, parameters`` every time a SQL query is executed
|
||||
:param use_counts_table: set to ``True`` to use a cached counts table, if available. See
|
||||
:ref:`python_api_cached_table_counts`
|
||||
:param strict: Apply STRICT mode to all created tables (unless overridden)
|
||||
"""
|
||||
|
||||
_counts_table_name = "_counts"
|
||||
|
|
@ -315,6 +316,7 @@ class Database:
|
|||
tracer: Optional[Callable] = None,
|
||||
use_counts_table: bool = False,
|
||||
execute_plugins: bool = True,
|
||||
strict: bool = False,
|
||||
):
|
||||
assert (filename_or_conn is not None and (not memory and not memory_name)) or (
|
||||
filename_or_conn is None and (memory or memory_name)
|
||||
|
|
@ -348,6 +350,7 @@ class Database:
|
|||
self.use_counts_table = use_counts_table
|
||||
if execute_plugins:
|
||||
pm.hook.prepare_connection(conn=self.conn)
|
||||
self.strict = strict
|
||||
|
||||
def close(self):
|
||||
"Close the SQLite connection, and the underlying database file"
|
||||
|
|
@ -534,7 +537,11 @@ class Database:
|
|||
|
||||
:param table_name: Name of the table
|
||||
"""
|
||||
klass = View if table_name in self.view_names() else Table
|
||||
if table_name in self.view_names():
|
||||
klass = View
|
||||
else:
|
||||
klass = Table
|
||||
kwargs.setdefault("strict", self.strict)
|
||||
return klass(self, table_name, **kwargs)
|
||||
|
||||
def quote(self, value: str) -> str:
|
||||
|
|
@ -821,6 +828,7 @@ class Database:
|
|||
hash_id_columns: Optional[Iterable[str]] = None,
|
||||
extracts: Optional[Union[Dict[str, str], List[str]]] = None,
|
||||
if_not_exists: bool = False,
|
||||
strict: bool = False,
|
||||
) -> str:
|
||||
"""
|
||||
Returns the SQL ``CREATE TABLE`` statement for creating the specified table.
|
||||
|
|
@ -836,6 +844,7 @@ class Database:
|
|||
:param hash_id_columns: List of columns to be used when calculating the hash ID for a row
|
||||
:param extracts: List or dictionary of columns to be extracted during inserts, see :ref:`python_api_extracts`
|
||||
:param if_not_exists: Use ``CREATE TABLE IF NOT EXISTS``
|
||||
:param strict: Apply STRICT mode to table
|
||||
"""
|
||||
if hash_id_columns and (hash_id is None):
|
||||
hash_id = "id"
|
||||
|
|
@ -932,12 +941,13 @@ class Database:
|
|||
columns_sql = ",\n".join(column_defs)
|
||||
sql = """CREATE TABLE {if_not_exists}[{table}] (
|
||||
{columns_sql}{extra_pk}
|
||||
);
|
||||
){strict};
|
||||
""".format(
|
||||
if_not_exists="IF NOT EXISTS " if if_not_exists else "",
|
||||
table=name,
|
||||
columns_sql=columns_sql,
|
||||
extra_pk=extra_pk,
|
||||
strict=" STRICT" if strict and self.supports_strict else "",
|
||||
)
|
||||
return sql
|
||||
|
||||
|
|
@ -957,6 +967,7 @@ class Database:
|
|||
replace: bool = False,
|
||||
ignore: bool = False,
|
||||
transform: bool = False,
|
||||
strict: bool = False,
|
||||
) -> "Table":
|
||||
"""
|
||||
Create a table with the specified name and the specified ``{column_name: type}`` columns.
|
||||
|
|
@ -977,6 +988,7 @@ class Database:
|
|||
:param replace: Drop and replace table if it already exists
|
||||
:param ignore: Silently do nothing if table already exists
|
||||
:param transform: If table already exists transform it to fit the specified schema
|
||||
:param strict: Apply STRICT mode to table
|
||||
"""
|
||||
# Transform table to match the new definition if table already exists:
|
||||
if self[name].exists():
|
||||
|
|
@ -1048,6 +1060,7 @@ class Database:
|
|||
hash_id_columns=hash_id_columns,
|
||||
extracts=extracts,
|
||||
if_not_exists=if_not_exists,
|
||||
strict=strict,
|
||||
)
|
||||
self.execute(sql)
|
||||
created_table = self.table(
|
||||
|
|
@ -1416,6 +1429,7 @@ class Table(Queryable):
|
|||
:param extracts: Dictionary or list of column names to extract into a separate table on inserts
|
||||
:param conversions: Dictionary of column names and conversion functions
|
||||
:param columns: Dictionary of column names to column types
|
||||
:param strict: If True, apply STRICT mode to table
|
||||
"""
|
||||
|
||||
#: The ``rowid`` of the last inserted, updated or selected row.
|
||||
|
|
@ -1441,6 +1455,7 @@ class Table(Queryable):
|
|||
extracts: Optional[Union[Dict[str, str], List[str]]] = None,
|
||||
conversions: Optional[dict] = None,
|
||||
columns: Optional[Dict[str, Any]] = None,
|
||||
strict: bool = False,
|
||||
):
|
||||
super().__init__(db, name)
|
||||
self._defaults = dict(
|
||||
|
|
@ -1458,6 +1473,7 @@ class Table(Queryable):
|
|||
extracts=extracts,
|
||||
conversions=conversions or {},
|
||||
columns=columns,
|
||||
strict=strict,
|
||||
)
|
||||
|
||||
def __repr__(self) -> str:
|
||||
|
|
@ -1639,6 +1655,7 @@ class Table(Queryable):
|
|||
replace: bool = False,
|
||||
ignore: bool = False,
|
||||
transform: bool = False,
|
||||
strict: bool = False,
|
||||
) -> "Table":
|
||||
"""
|
||||
Create a table with the specified columns.
|
||||
|
|
@ -1658,6 +1675,7 @@ class Table(Queryable):
|
|||
:param replace: Drop and replace table if it already exists
|
||||
:param ignore: Silently do nothing if table already exists
|
||||
:param transform: If table already exists transform it to fit the specified schema
|
||||
:param strict: Apply STRICT mode to table
|
||||
"""
|
||||
columns = {name: value for (name, value) in columns.items()}
|
||||
with self.db.conn:
|
||||
|
|
@ -1676,6 +1694,7 @@ class Table(Queryable):
|
|||
replace=replace,
|
||||
ignore=ignore,
|
||||
transform=transform,
|
||||
strict=strict,
|
||||
)
|
||||
return self
|
||||
|
||||
|
|
@ -1909,6 +1928,7 @@ class Table(Queryable):
|
|||
defaults=create_table_defaults,
|
||||
foreign_keys=create_table_foreign_keys,
|
||||
column_order=column_order,
|
||||
strict=self.strict,
|
||||
).strip()
|
||||
)
|
||||
|
||||
|
|
@ -3111,6 +3131,7 @@ class Table(Queryable):
|
|||
extracts: Optional[Union[Dict[str, str], List[str], Default]] = DEFAULT,
|
||||
conversions: Optional[Union[Dict[str, str], Default]] = DEFAULT,
|
||||
columns: Optional[Union[Dict[str, Any], Default]] = DEFAULT,
|
||||
strict: Optional[Union[bool, Default]] = DEFAULT,
|
||||
) -> "Table":
|
||||
"""
|
||||
Insert a single record into the table. The table will be created with a schema that matches
|
||||
|
|
@ -3143,6 +3164,7 @@ class Table(Queryable):
|
|||
is being inserted, for example ``{"name": "upper(?)"}``. See :ref:`python_api_conversions`.
|
||||
:param columns: Dictionary over-riding the detected types used for the columns, for example
|
||||
``{"age": int, "weight": float}``.
|
||||
:param strict: Boolean, apply STRICT mode if creating the table.
|
||||
"""
|
||||
return self.insert_all(
|
||||
[record],
|
||||
|
|
@ -3159,6 +3181,7 @@ class Table(Queryable):
|
|||
extracts=extracts,
|
||||
conversions=conversions,
|
||||
columns=columns,
|
||||
strict=strict,
|
||||
)
|
||||
|
||||
def insert_all(
|
||||
|
|
@ -3181,6 +3204,7 @@ class Table(Queryable):
|
|||
columns=DEFAULT,
|
||||
upsert=False,
|
||||
analyze=False,
|
||||
strict=DEFAULT,
|
||||
) -> "Table":
|
||||
"""
|
||||
Like ``.insert()`` but takes a list of records and ensures that the table
|
||||
|
|
@ -3202,6 +3226,7 @@ class Table(Queryable):
|
|||
extracts = self.value_or_default("extracts", extracts)
|
||||
conversions = self.value_or_default("conversions", conversions) or {}
|
||||
columns = self.value_or_default("columns", columns)
|
||||
strict = self.value_or_default("strict", strict)
|
||||
|
||||
if hash_id_columns and hash_id is None:
|
||||
hash_id = "id"
|
||||
|
|
@ -3257,6 +3282,7 @@ class Table(Queryable):
|
|||
hash_id=hash_id,
|
||||
hash_id_columns=hash_id_columns,
|
||||
extracts=extracts,
|
||||
strict=strict,
|
||||
)
|
||||
all_columns_set = set()
|
||||
for record in chunk:
|
||||
|
|
@ -3307,6 +3333,7 @@ class Table(Queryable):
|
|||
extracts=DEFAULT,
|
||||
conversions=DEFAULT,
|
||||
columns=DEFAULT,
|
||||
strict=DEFAULT,
|
||||
) -> "Table":
|
||||
"""
|
||||
Like ``.insert()`` but performs an ``UPSERT``, where records are inserted if they do
|
||||
|
|
@ -3327,6 +3354,7 @@ class Table(Queryable):
|
|||
extracts=extracts,
|
||||
conversions=conversions,
|
||||
columns=columns,
|
||||
strict=strict,
|
||||
)
|
||||
|
||||
def upsert_all(
|
||||
|
|
@ -3345,6 +3373,7 @@ class Table(Queryable):
|
|||
conversions=DEFAULT,
|
||||
columns=DEFAULT,
|
||||
analyze=False,
|
||||
strict=DEFAULT,
|
||||
) -> "Table":
|
||||
"""
|
||||
Like ``.upsert()`` but can be applied to a list of records.
|
||||
|
|
@ -3365,6 +3394,7 @@ class Table(Queryable):
|
|||
columns=columns,
|
||||
upsert=True,
|
||||
analyze=analyze,
|
||||
strict=strict,
|
||||
)
|
||||
|
||||
def add_missing_columns(self, records: Iterable[Dict[str, Any]]) -> "Table":
|
||||
|
|
@ -3387,6 +3417,7 @@ class Table(Queryable):
|
|||
extracts: Optional[Union[Dict[str, str], List[str]]] = None,
|
||||
conversions: Optional[Dict[str, str]] = None,
|
||||
columns: Optional[Dict[str, Any]] = None,
|
||||
strict: Optional[bool] = False,
|
||||
):
|
||||
"""
|
||||
Create or populate a lookup table with the specified values.
|
||||
|
|
@ -3409,6 +3440,7 @@ class Table(Queryable):
|
|||
|
||||
:param lookup_values: Dictionary specifying column names and values to use for the lookup
|
||||
:param extra_values: Additional column values to be used only if creating a new record
|
||||
:param strict: Boolean, apply STRICT mode if creating the table.
|
||||
"""
|
||||
assert isinstance(lookup_values, dict)
|
||||
if extra_values is not None:
|
||||
|
|
@ -3440,6 +3472,7 @@ class Table(Queryable):
|
|||
extracts=extracts,
|
||||
conversions=conversions,
|
||||
columns=columns,
|
||||
strict=strict,
|
||||
).last_pk
|
||||
else:
|
||||
pk = self.insert(
|
||||
|
|
@ -3452,6 +3485,7 @@ class Table(Queryable):
|
|||
extracts=extracts,
|
||||
conversions=conversions,
|
||||
columns=columns,
|
||||
strict=strict,
|
||||
).last_pk
|
||||
self.create_index(lookup_values.keys(), unique=True)
|
||||
return pk
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue