diff --git a/README.rst b/README.rst index d6cfa80..8037971 100644 --- a/README.rst +++ b/README.rst @@ -11,6 +11,9 @@ Getting Started - Write access to an empty `PostgreSQL `_ database. - A Python installation with `Jupyter Notebook `_ >= 5.0. +PGContents will put its table in the `pgcontents` namespace. When you log onto the PostgreSQL database server, make +sure the `pgcontents` schema is in the search path (e.g., `set search_path to 'pgcontents'`; see `PostgreSQL documentation`_). + **Installation:** 0. Install ``pgcontents`` from PyPI via ``pip install pgcontents``. @@ -23,3 +26,4 @@ Demo Video You can see a demo of PGContents in action in `this presentation from JupyterCon 2017`_. .. _`this presentation from JupyterCon 2017` : https://youtu.be/TtsbspKHJGo?t=917 +.. _`PostgreSQL documentation` : https://www.postgresql.org/docs/14/ddl-schemas.html#DDL-SCHEMAS-PATH \ No newline at end of file diff --git a/pgcontents/query.py b/pgcontents/query.py index 2969f64..749d0af 100644 --- a/pgcontents/query.py +++ b/pgcontents/query.py @@ -10,6 +10,7 @@ select, Unicode, ) +from sqlalchemy.dialects.postgresql import insert from sqlalchemy.exc import IntegrityError @@ -500,8 +501,6 @@ def rename_directory(db, user_id, old_api_path, new_api_path): def save_file(db, user_id, path, content, encrypt_func, max_size_bytes): """ Save a file. - - TODO: Update-then-insert is probably cheaper than insert-then-update. """ content = preprocess_incoming_content( content, @@ -509,32 +508,20 @@ def save_file(db, user_id, path, content, encrypt_func, max_size_bytes): max_size_bytes, ) directory, name = split_api_filepath(path) - with db.begin_nested() as savepoint: - try: - res = db.execute( - files.insert().values( - name=name, - user_id=user_id, - parent_name=directory, - content=content, - ) + with db.begin_nested(): + res = db.execute( + insert(files) + .values( + name=name, + user_id=user_id, + parent_name=directory, + content=content, ) - except IntegrityError as error: - # The file already exists, so overwrite its content with the newer - # version. - if is_unique_violation(error): - savepoint.rollback() - res = db.execute( - files.update().where( - _file_where(user_id, path), - ).values( - content=content, - created_at=func.now(), - ) - ) - else: - # Unknown error. Reraise - raise + .on_conflict_do_update(constraint="uix_filepath_username", set_={ + "content": content, + "created_at": func.now() + }) + ) return res