mirror of
https://github.com/simonw/sqlite-utils.git
synced 2026-09-09 18:14:09 +02:00
--not-null-default and not_null_default=, refs #24
This commit is contained in:
parent
7a3041b1ad
commit
2fed87da6e
7 changed files with 87 additions and 16 deletions
|
|
@ -280,6 +280,10 @@ You can explicitly specify the column you wish to reference using ``--fk-col``::
|
||||||
|
|
||||||
$ sqlite-utils add-column mydb.db dogs species_id --fk species --fk-col ref
|
$ sqlite-utils add-column mydb.db dogs species_id --fk species --fk-col ref
|
||||||
|
|
||||||
|
You can set a ``NOT NULL DEFAULT 'x'`` constraint on the new column using ``--not-null-default``::
|
||||||
|
|
||||||
|
$ sqlite-utils add-column mydb.db dogs friends_count integer --not-null-default 0
|
||||||
|
|
||||||
.. _cli_add_column_alter:
|
.. _cli_add_column_alter:
|
||||||
|
|
||||||
Adding columns automatically on insert/update
|
Adding columns automatically on insert/update
|
||||||
|
|
|
||||||
|
|
@ -284,6 +284,12 @@ You can explicitly specify the column you wish to reference using ``fk_col``:
|
||||||
|
|
||||||
db["dogs"].add_column("species_id", fk="species", fk_col="ref")
|
db["dogs"].add_column("species_id", fk="species", fk_col="ref")
|
||||||
|
|
||||||
|
You can set a ``NOT NULL DEFAULT 'x'`` constraint on the new column using ``not_null_default``:
|
||||||
|
|
||||||
|
.. code-block:: python
|
||||||
|
|
||||||
|
db["dogs"].add_column("friends_count", int, not_null_default=0)
|
||||||
|
|
||||||
.. _python_api_add_column_alter:
|
.. _python_api_add_column_alter:
|
||||||
|
|
||||||
Adding columns automatically on insert/update
|
Adding columns automatically on insert/update
|
||||||
|
|
|
||||||
|
|
@ -169,12 +169,27 @@ def optimize(path, no_vacuum):
|
||||||
),
|
),
|
||||||
required=False,
|
required=False,
|
||||||
)
|
)
|
||||||
@click.option("--fk", type=str, required=False)
|
@click.option(
|
||||||
@click.option("--fk-col", type=str, required=False)
|
"--fk", type=str, required=False, help="Table to reference as a foreign key"
|
||||||
def add_column(path, table, col_name, col_type, fk, fk_col):
|
)
|
||||||
|
@click.option(
|
||||||
|
"--fk-col",
|
||||||
|
type=str,
|
||||||
|
required=False,
|
||||||
|
help="Referenced column on that foreign key table - if omitted will automatically use the primary key",
|
||||||
|
)
|
||||||
|
@click.option(
|
||||||
|
"--not-null-default",
|
||||||
|
type=str,
|
||||||
|
required=False,
|
||||||
|
help="Add NOT NULL DEFAULT 'TEXT' constraint",
|
||||||
|
)
|
||||||
|
def add_column(path, table, col_name, col_type, fk, fk_col, not_null_default):
|
||||||
"Add a column to the specified table"
|
"Add a column to the specified table"
|
||||||
db = sqlite_utils.Database(path)
|
db = sqlite_utils.Database(path)
|
||||||
db[table].add_column(col_name, col_type, fk=fk, fk_col=fk_col)
|
db[table].add_column(
|
||||||
|
col_name, col_type, fk=fk, fk_col=fk_col, not_null_default=not_null_default
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
@cli.command(name="add-foreign-key")
|
@cli.command(name="add-foreign-key")
|
||||||
|
|
|
||||||
|
|
@ -292,7 +292,9 @@ class Table:
|
||||||
self.db.conn.execute(sql)
|
self.db.conn.execute(sql)
|
||||||
return self
|
return self
|
||||||
|
|
||||||
def add_column(self, col_name, col_type=None, fk=None, fk_col=None):
|
def add_column(
|
||||||
|
self, col_name, col_type=None, fk=None, fk_col=None, not_null_default=None
|
||||||
|
):
|
||||||
fk_col_type = None
|
fk_col_type = None
|
||||||
if fk is not None:
|
if fk is not None:
|
||||||
# fk must be a valid table
|
# fk must be a valid table
|
||||||
|
|
@ -313,10 +315,19 @@ class Table:
|
||||||
fk_col_type = "INTEGER"
|
fk_col_type = "INTEGER"
|
||||||
if col_type is None:
|
if col_type is None:
|
||||||
col_type = str
|
col_type = str
|
||||||
sql = "ALTER TABLE [{table}] ADD COLUMN [{col_name}] {col_type};".format(
|
not_null_sql = None
|
||||||
|
if not_null_default is not None:
|
||||||
|
not_null_sql = "NOT NULL DEFAULT {}".format(
|
||||||
|
# Use SQLite itself to correctly escape this string:
|
||||||
|
self.db.conn.execute(
|
||||||
|
"SELECT quote(:default)", {"default": not_null_default}
|
||||||
|
).fetchone()[0]
|
||||||
|
)
|
||||||
|
sql = "ALTER TABLE [{table}] ADD COLUMN [{col_name}] {col_type}{not_null_default};".format(
|
||||||
table=self.name,
|
table=self.name,
|
||||||
col_name=col_name,
|
col_name=col_name,
|
||||||
col_type=fk_col_type or COLUMN_TYPE_MAPPING[col_type],
|
col_type=fk_col_type or COLUMN_TYPE_MAPPING[col_type],
|
||||||
|
not_null_default=(" " + not_null_sql) if not_null_sql else "",
|
||||||
)
|
)
|
||||||
self.db.conn.execute(sql)
|
self.db.conn.execute(sql)
|
||||||
if fk is not None:
|
if fk is not None:
|
||||||
|
|
|
||||||
BIN
tests/.DS_Store
vendored
Normal file
BIN
tests/.DS_Store
vendored
Normal file
Binary file not shown.
|
|
@ -199,6 +199,27 @@ def test_add_column(db_path, col_name, col_type, expected_schema):
|
||||||
assert expected_schema == collapse_whitespace(db["dogs"].schema)
|
assert expected_schema == collapse_whitespace(db["dogs"].schema)
|
||||||
|
|
||||||
|
|
||||||
|
def test_add_column_not_null_default(db_path):
|
||||||
|
db = Database(db_path)
|
||||||
|
db.create_table("dogs", {"name": str})
|
||||||
|
assert "CREATE TABLE [dogs] ( [name] TEXT )" == collapse_whitespace(
|
||||||
|
db["dogs"].schema
|
||||||
|
)
|
||||||
|
args = [
|
||||||
|
"add-column",
|
||||||
|
db_path,
|
||||||
|
"dogs",
|
||||||
|
"nickname",
|
||||||
|
"--not-null-default",
|
||||||
|
"dogs'dawg",
|
||||||
|
]
|
||||||
|
assert 0 == CliRunner().invoke(cli.cli, args).exit_code
|
||||||
|
assert (
|
||||||
|
"CREATE TABLE [dogs] ( [name] TEXT , [nickname] TEXT NOT NULL DEFAULT 'dogs''dawg')"
|
||||||
|
== collapse_whitespace(db["dogs"].schema)
|
||||||
|
)
|
||||||
|
|
||||||
|
|
||||||
def test_add_foreign_key(db_path):
|
def test_add_foreign_key(db_path):
|
||||||
db = Database(db_path)
|
db = Database(db_path)
|
||||||
db["authors"].insert_all(
|
db["authors"].insert_all(
|
||||||
|
|
|
||||||
|
|
@ -131,33 +131,47 @@ def test_create_error_if_invalid_foreign_keys(fresh_db):
|
||||||
|
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"col_name,col_type,expected_schema",
|
"col_name,col_type,not_null_default,expected_schema",
|
||||||
(
|
(
|
||||||
("nickname", str, "CREATE TABLE [dogs] ( [name] TEXT , [nickname] TEXT)"),
|
("nickname", str, None, "CREATE TABLE [dogs] ( [name] TEXT , [nickname] TEXT)"),
|
||||||
("dob", datetime.date, "CREATE TABLE [dogs] ( [name] TEXT , [dob] TEXT)"),
|
("dob", datetime.date, None, "CREATE TABLE [dogs] ( [name] TEXT , [dob] TEXT)"),
|
||||||
("age", int, "CREATE TABLE [dogs] ( [name] TEXT , [age] INTEGER)"),
|
("age", int, None, "CREATE TABLE [dogs] ( [name] TEXT , [age] INTEGER)"),
|
||||||
("weight", float, "CREATE TABLE [dogs] ( [name] TEXT , [weight] FLOAT)"),
|
("weight", float, None, "CREATE TABLE [dogs] ( [name] TEXT , [weight] FLOAT)"),
|
||||||
("text", "TEXT", "CREATE TABLE [dogs] ( [name] TEXT , [text] TEXT)"),
|
("text", "TEXT", None, "CREATE TABLE [dogs] ( [name] TEXT , [text] TEXT)"),
|
||||||
(
|
(
|
||||||
"integer",
|
"integer",
|
||||||
"INTEGER",
|
"INTEGER",
|
||||||
|
None,
|
||||||
"CREATE TABLE [dogs] ( [name] TEXT , [integer] INTEGER)",
|
"CREATE TABLE [dogs] ( [name] TEXT , [integer] INTEGER)",
|
||||||
),
|
),
|
||||||
("float", "FLOAT", "CREATE TABLE [dogs] ( [name] TEXT , [float] FLOAT)"),
|
("float", "FLOAT", None, "CREATE TABLE [dogs] ( [name] TEXT , [float] FLOAT)"),
|
||||||
("blob", "blob", "CREATE TABLE [dogs] ( [name] TEXT , [blob] BLOB)"),
|
("blob", "blob", None, "CREATE TABLE [dogs] ( [name] TEXT , [blob] BLOB)"),
|
||||||
(
|
(
|
||||||
"default_str",
|
"default_str",
|
||||||
None,
|
None,
|
||||||
|
None,
|
||||||
"CREATE TABLE [dogs] ( [name] TEXT , [default_str] TEXT)",
|
"CREATE TABLE [dogs] ( [name] TEXT , [default_str] TEXT)",
|
||||||
),
|
),
|
||||||
|
(
|
||||||
|
"nickname",
|
||||||
|
str,
|
||||||
|
"",
|
||||||
|
"CREATE TABLE [dogs] ( [name] TEXT , [nickname] TEXT NOT NULL DEFAULT '')",
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"nickname",
|
||||||
|
str,
|
||||||
|
"dawg's dawg",
|
||||||
|
"CREATE TABLE [dogs] ( [name] TEXT , [nickname] TEXT NOT NULL DEFAULT 'dawg''s dawg')",
|
||||||
|
),
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
def test_add_column(fresh_db, col_name, col_type, expected_schema):
|
def test_add_column(fresh_db, col_name, col_type, not_null_default, expected_schema):
|
||||||
fresh_db.create_table("dogs", {"name": str})
|
fresh_db.create_table("dogs", {"name": str})
|
||||||
assert "CREATE TABLE [dogs] ( [name] TEXT )" == collapse_whitespace(
|
assert "CREATE TABLE [dogs] ( [name] TEXT )" == collapse_whitespace(
|
||||||
fresh_db["dogs"].schema
|
fresh_db["dogs"].schema
|
||||||
)
|
)
|
||||||
fresh_db["dogs"].add_column(col_name, col_type)
|
fresh_db["dogs"].add_column(col_name, col_type, not_null_default=not_null_default)
|
||||||
assert expected_schema == collapse_whitespace(fresh_db["dogs"].schema)
|
assert expected_schema == collapse_whitespace(fresh_db["dogs"].schema)
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue