mirror of
https://github.com/simonw/sqlite-utils.git
synced 2026-09-28 04:44:26 +02:00
New columns= parameter for over-riding column types, closes #100
This commit is contained in:
parent
cd146bbbfa
commit
2ab62bcd54
3 changed files with 66 additions and 3 deletions
|
|
@ -157,6 +157,8 @@ If the record does not exist a ``NotFoundError`` will be raised:
|
||||||
except NotFoundError:
|
except NotFoundError:
|
||||||
print("Dog not found")
|
print("Dog not found")
|
||||||
|
|
||||||
|
.. _python_api_creating_tables:
|
||||||
|
|
||||||
Creating tables
|
Creating tables
|
||||||
===============
|
===============
|
||||||
|
|
||||||
|
|
@ -197,6 +199,15 @@ You can also specify a primary key by passing the ``pk=`` parameter to the ``.in
|
||||||
"is_good_dog": True,
|
"is_good_dog": True,
|
||||||
}, pk="id")
|
}, pk="id")
|
||||||
|
|
||||||
|
After inserting a row like this, the ``dogs.last_rowid`` property will return the SQLite ``rowid`` assigned to the most recently inserted record.
|
||||||
|
|
||||||
|
The ``dogs.last_pk`` property will return the last inserted primary key value, if you specified one. This can be very useful when writing code that creates foreign keys or many-to-many relationships.
|
||||||
|
|
||||||
|
.. _python_api_custom_columns:
|
||||||
|
|
||||||
|
Custom column order and column types
|
||||||
|
------------------------------------
|
||||||
|
|
||||||
The order of the columns in the table will be derived from the order of the keys in the dictionary, provided you are using Python 3.6 or later.
|
The order of the columns in the table will be derived from the order of the keys in the dictionary, provided you are using Python 3.6 or later.
|
||||||
|
|
||||||
If you want to explicitly set the order of the columns you can do so using the ``column_order=`` parameter:
|
If you want to explicitly set the order of the columns you can do so using the ``column_order=`` parameter:
|
||||||
|
|
@ -213,9 +224,26 @@ If you want to explicitly set the order of the columns you can do so using the `
|
||||||
|
|
||||||
You don't need to pass all of the columns to the ``column_order`` parameter. If you only pass a subset of the columns the remaining columns will be ordered based on the key order of the dictionary.
|
You don't need to pass all of the columns to the ``column_order`` parameter. If you only pass a subset of the columns the remaining columns will be ordered based on the key order of the dictionary.
|
||||||
|
|
||||||
After inserting a row like this, the ``dogs.last_rowid`` property will return the SQLite ``rowid`` assigned to the most recently inserted record.
|
Column types are detected based on the example data provided. Sometimes you may find you need to over-ride these detected types - to create an integer column for data that was provided as a string for example, or to ensure that a table where the first example was ``None`` is created as an ``INTEGER`` rather than a ``TEXT`` column. You can do this using the ``columns=`` parameter:
|
||||||
|
|
||||||
The ``dogs.last_pk`` property will return the last inserted primary key value, if you specified one. This can be very useful when writing code that creates foreign keys or many-to-many relationships.
|
.. code-block:: python
|
||||||
|
|
||||||
|
dogs.insert({
|
||||||
|
"id": 1,
|
||||||
|
"name": "Cleo",
|
||||||
|
"age": "5",
|
||||||
|
}, pk="id", columns={"age": int, "weight": float})
|
||||||
|
|
||||||
|
This will create a table with the following schema:
|
||||||
|
|
||||||
|
.. code-block:: sql
|
||||||
|
|
||||||
|
CREATE TABLE [dogs] (
|
||||||
|
[id] INTEGER PRIMARY KEY,
|
||||||
|
[name] TEXT,
|
||||||
|
[age] INTEGER,
|
||||||
|
[weight] FLOAT
|
||||||
|
)
|
||||||
|
|
||||||
.. _python_api_explicit_create:
|
.. _python_api_explicit_create:
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -491,6 +491,7 @@ class Table(Queryable):
|
||||||
replace=False,
|
replace=False,
|
||||||
extracts=None,
|
extracts=None,
|
||||||
conversions=None,
|
conversions=None,
|
||||||
|
columns=None,
|
||||||
):
|
):
|
||||||
super().__init__(db, name)
|
super().__init__(db, name)
|
||||||
self._defaults = dict(
|
self._defaults = dict(
|
||||||
|
|
@ -506,6 +507,7 @@ class Table(Queryable):
|
||||||
replace=replace,
|
replace=replace,
|
||||||
extracts=extracts,
|
extracts=extracts,
|
||||||
conversions=conversions or {},
|
conversions=conversions or {},
|
||||||
|
columns=columns,
|
||||||
)
|
)
|
||||||
|
|
||||||
def __repr__(self):
|
def __repr__(self):
|
||||||
|
|
@ -932,6 +934,7 @@ class Table(Queryable):
|
||||||
replace=DEFAULT,
|
replace=DEFAULT,
|
||||||
extracts=DEFAULT,
|
extracts=DEFAULT,
|
||||||
conversions=DEFAULT,
|
conversions=DEFAULT,
|
||||||
|
columns=DEFAULT,
|
||||||
):
|
):
|
||||||
return self.insert_all(
|
return self.insert_all(
|
||||||
[record],
|
[record],
|
||||||
|
|
@ -946,6 +949,7 @@ class Table(Queryable):
|
||||||
replace=replace,
|
replace=replace,
|
||||||
extracts=extracts,
|
extracts=extracts,
|
||||||
conversions=conversions,
|
conversions=conversions,
|
||||||
|
columns=columns,
|
||||||
)
|
)
|
||||||
|
|
||||||
def insert_all(
|
def insert_all(
|
||||||
|
|
@ -963,6 +967,7 @@ class Table(Queryable):
|
||||||
replace=DEFAULT,
|
replace=DEFAULT,
|
||||||
extracts=DEFAULT,
|
extracts=DEFAULT,
|
||||||
conversions=DEFAULT,
|
conversions=DEFAULT,
|
||||||
|
columns=DEFAULT,
|
||||||
upsert=False,
|
upsert=False,
|
||||||
):
|
):
|
||||||
"""
|
"""
|
||||||
|
|
@ -982,6 +987,7 @@ class Table(Queryable):
|
||||||
replace = self.value_or_default("replace", replace)
|
replace = self.value_or_default("replace", replace)
|
||||||
extracts = self.value_or_default("extracts", extracts)
|
extracts = self.value_or_default("extracts", extracts)
|
||||||
conversions = self.value_or_default("conversions", conversions)
|
conversions = self.value_or_default("conversions", conversions)
|
||||||
|
columns = self.value_or_default("columns", columns)
|
||||||
|
|
||||||
if upsert and (not pk and not hash_id):
|
if upsert and (not pk and not hash_id):
|
||||||
raise PrimaryKeyRequired("upsert() requires a pk")
|
raise PrimaryKeyRequired("upsert() requires a pk")
|
||||||
|
|
@ -1016,8 +1022,10 @@ class Table(Queryable):
|
||||||
if first:
|
if first:
|
||||||
if not self.exists():
|
if not self.exists():
|
||||||
# Use the first batch to derive the table names
|
# Use the first batch to derive the table names
|
||||||
|
column_types = suggest_column_types(chunk)
|
||||||
|
column_types.update(columns or {})
|
||||||
self.create(
|
self.create(
|
||||||
suggest_column_types(chunk),
|
column_types,
|
||||||
pk,
|
pk,
|
||||||
foreign_keys,
|
foreign_keys,
|
||||||
column_order=column_order,
|
column_order=column_order,
|
||||||
|
|
@ -1154,6 +1162,7 @@ class Table(Queryable):
|
||||||
alter=DEFAULT,
|
alter=DEFAULT,
|
||||||
extracts=DEFAULT,
|
extracts=DEFAULT,
|
||||||
conversions=DEFAULT,
|
conversions=DEFAULT,
|
||||||
|
columns=DEFAULT,
|
||||||
):
|
):
|
||||||
return self.upsert_all(
|
return self.upsert_all(
|
||||||
[record],
|
[record],
|
||||||
|
|
@ -1166,6 +1175,7 @@ class Table(Queryable):
|
||||||
alter=alter,
|
alter=alter,
|
||||||
extracts=extracts,
|
extracts=extracts,
|
||||||
conversions=conversions,
|
conversions=conversions,
|
||||||
|
columns=columns,
|
||||||
)
|
)
|
||||||
|
|
||||||
def upsert_all(
|
def upsert_all(
|
||||||
|
|
@ -1181,6 +1191,7 @@ class Table(Queryable):
|
||||||
alter=DEFAULT,
|
alter=DEFAULT,
|
||||||
extracts=DEFAULT,
|
extracts=DEFAULT,
|
||||||
conversions=DEFAULT,
|
conversions=DEFAULT,
|
||||||
|
columns=DEFAULT,
|
||||||
):
|
):
|
||||||
return self.insert_all(
|
return self.insert_all(
|
||||||
records,
|
records,
|
||||||
|
|
@ -1194,6 +1205,7 @@ class Table(Queryable):
|
||||||
alter=alter,
|
alter=alter,
|
||||||
extracts=extracts,
|
extracts=extracts,
|
||||||
conversions=conversions,
|
conversions=conversions,
|
||||||
|
columns=columns,
|
||||||
upsert=True,
|
upsert=True,
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -154,6 +154,29 @@ def test_create_table_from_example_with_compound_primary_keys(fresh_db):
|
||||||
assert record == table.get(("staff", 2))
|
assert record == table.get(("staff", 2))
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.mark.parametrize(
|
||||||
|
"method_name", ("insert", "upsert", "insert_all", "upsert_all")
|
||||||
|
)
|
||||||
|
def test_create_table_with_custom_columns(fresh_db, method_name):
|
||||||
|
table = fresh_db["dogs"]
|
||||||
|
method = getattr(table, method_name)
|
||||||
|
record = {"id": 1, "name": "Cleo", "age": "5"}
|
||||||
|
if method_name.endswith("_all"):
|
||||||
|
record = [record]
|
||||||
|
method(record, pk="id", columns={"age": int, "weight": float})
|
||||||
|
assert ["dogs"] == fresh_db.table_names()
|
||||||
|
expected_columns = [
|
||||||
|
{"name": "id", "type": "INTEGER"},
|
||||||
|
{"name": "name", "type": "TEXT"},
|
||||||
|
{"name": "age", "type": "INTEGER"},
|
||||||
|
{"name": "weight", "type": "FLOAT"},
|
||||||
|
]
|
||||||
|
assert expected_columns == [
|
||||||
|
{"name": col.name, "type": col.type} for col in table.columns
|
||||||
|
]
|
||||||
|
assert [{"id": 1, "name": "Cleo", "age": 5, "weight": None}] == list(table.rows)
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize("use_table_factory", [True, False])
|
@pytest.mark.parametrize("use_table_factory", [True, False])
|
||||||
def test_create_table_column_order(fresh_db, use_table_factory):
|
def test_create_table_column_order(fresh_db, use_table_factory):
|
||||||
row = collections.OrderedDict(
|
row = collections.OrderedDict(
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue