diff --git a/docs/python-api.rst b/docs/python-api.rst index cc34505..039a00a 100644 --- a/docs/python-api.rst +++ b/docs/python-api.rst @@ -522,7 +522,9 @@ This will create a table with the following schema: Explicitly creating a table --------------------------- -You can directly create a new table without inserting any data into it using the ``.create()`` method:: +You can directly create a new table without inserting any data into it using the ``.create()`` method: + +.. code-block:: python db["cats"].create({ "id": int, @@ -534,6 +536,17 @@ The first argument here is a dictionary specifying the columns you would like to This method takes optional arguments ``pk=``, ``column_order=``, ``foreign_keys=``, ``not_null=set()`` and ``defaults=dict()`` - explained below. +A ``sqlite_utils.utils.sqlite3.OperationalError`` will be raised if a table of that name already exists. + +To do nothing if the table already exists, add ``if_not_exists=True``: + +.. code-block:: python + + db["cats"].create({ + "id": int, + "name": str, + }, pk="id", if_not_exists=True) + .. _python_api_compound_primary_keys: Compound primary keys diff --git a/sqlite_utils/db.py b/sqlite_utils/db.py index 4ab8862..1927f41 100644 --- a/sqlite_utils/db.py +++ b/sqlite_utils/db.py @@ -658,6 +658,7 @@ class Database: defaults: Optional[Dict[str, Any]] = None, hash_id: Optional[str] = None, extracts: Optional[Union[Dict[str, str], List[str]]] = None, + if_not_exists: bool = False, ) -> str: "Returns the SQL ``CREATE TABLE`` statement for creating the specified table." foreign_keys = self.resolve_foreign_keys(name, foreign_keys or []) @@ -748,11 +749,14 @@ class Database: pks=", ".join(["[{}]".format(p) for p in pk]) ) columns_sql = ",\n".join(column_defs) - sql = """CREATE TABLE [{table}] ( + sql = """CREATE TABLE {if_not_exists}[{table}] ( {columns_sql}{extra_pk} ); """.format( - table=name, columns_sql=columns_sql, extra_pk=extra_pk + if_not_exists="IF NOT EXISTS " if if_not_exists else "", + table=name, + columns_sql=columns_sql, + extra_pk=extra_pk, ) return sql @@ -767,6 +771,7 @@ class Database: defaults: Optional[Dict[str, Any]] = None, hash_id: Optional[str] = None, extracts: Optional[Union[Dict[str, str], List[str]]] = None, + if_not_exists: bool = False, ) -> "Table": """ Create a table with the specified name and the specified ``{column_name: type}`` columns. @@ -783,6 +788,7 @@ class Database: defaults=defaults, hash_id=hash_id, extracts=extracts, + if_not_exists=if_not_exists, ) self.execute(sql) table = self.table( @@ -1300,6 +1306,7 @@ class Table(Queryable): defaults: Optional[Dict[str, Any]] = None, hash_id: Optional[str] = None, extracts: Optional[Union[Dict[str, str], List[str]]] = None, + if_not_exists: bool = False, ) -> "Table": """ Create a table with the specified columns. @@ -1318,6 +1325,7 @@ class Table(Queryable): defaults=defaults, hash_id=hash_id, extracts=extracts, + if_not_exists=if_not_exists, ) return self diff --git a/tests/test_create.py b/tests/test_create.py index d946d99..35844a1 100644 --- a/tests/test_create.py +++ b/tests/test_create.py @@ -1114,3 +1114,12 @@ def test_create(fresh_db): " [bytes] BLOB\n" ")" ) + + +def test_create_if_not_exists(fresh_db): + fresh_db["t"].create({"id": int}) + # This should error + with pytest.raises(sqlite3.OperationalError): + fresh_db["t"].create({"id": int}) + # This should not + fresh_db["t"].create({"id": int}, if_not_exists=True)