diff --git a/docs/changelog.rst b/docs/changelog.rst index 9da938b0..2ba713ee 100644 --- a/docs/changelog.rst +++ b/docs/changelog.rst @@ -29,7 +29,7 @@ Plugin API changes ~~~~~~~~~~~~~~~~~~ - The ``top_canned_query()`` plugin hook has been renamed to :ref:`top_stored_query() `. (:issue:`2747`) -- The ``canned_queries()`` plugin hook has been removed. Plugins can use the new stored query methods together with :ref:`startup() ` to register queries. (:issue:`2735`) +- The ``canned_queries()`` plugin hook has been removed. Plugins can use the new :ref:`stored query management methods ` together with :ref:`startup() ` to register queries. (:issue:`2735`) Bug fixes ~~~~~~~~~ diff --git a/docs/internals.rst b/docs/internals.rst index 084922f8..66724aa9 100644 --- a/docs/internals.rst +++ b/docs/internals.rst @@ -927,6 +927,200 @@ Adds a new metadata entry for the specified column. Any previous column-level metadata entry with the same ``key`` will be overwritten. Internally upserts the value into the the ``metadata_columns`` table inside the :ref:`internal database `. +.. _datasette_stored_queries: + +Stored queries +-------------- + +:ref:`Stored queries ` are stored in the ``queries`` table in the :ref:`internal database `. Plugins can use the following methods to add, update, list and remove stored queries. + +.. _datasette_add_query: + +await .add_query(database, name, sql, ...) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Adds a stored query. + +.. code-block:: python + + async def add_query( + self, + database, + name, + sql, + *, + title=None, + description=None, + description_html=None, + hide_sql=False, + fragment=None, + parameters=None, + is_write=False, + is_private=False, + is_trusted=False, + source="plugin", + owner_id=None, + on_success_message=None, + on_success_message_sql=None, + on_success_redirect=None, + on_error_message=None, + on_error_redirect=None, + replace=True, + ): ... + +``database`` - string + The name of the database this query should belong to. +``name`` - string + The name of the stored query, used in the URL for that query. +``sql`` - string + The SQL for the stored query. +``title`` - string, optional + A display title for the query. +``description`` - string, optional + A plain text description. +``description_html`` - string, optional + An HTML description. +``hide_sql`` - boolean, optional + Set to ``True`` to hide the SQL by default on the query page. +``fragment`` - string, optional + A URL fragment to append to query links, for example ``"chart"``. +``parameters`` - list of strings, optional + Explicit parameter names for the query form. If omitted, Datasette derives parameters from the SQL. +``is_write`` - boolean, optional + Set to ``True`` for writable queries. They will the run against the SQLite write connection for the database. +``is_private`` - boolean, optional + Set to ``True`` for private queries. Private queries can only be viewed, updated or deleted by their owner. +``is_trusted`` - boolean, optional + Set to ``True`` for :ref:`trusted stored queries `. +``source`` - string, optional + Identifies where the query came from. Defaults to ``"plugin"``. +``owner_id`` - string, optional + Actor ID of the query owner, used by private query permissions. +``on_success_message``, ``on_success_message_sql``, ``on_success_redirect``, ``on_error_message``, ``on_error_redirect`` - strings, optional + Options for :ref:`writable queries `. +``replace`` - boolean, optional + Defaults to ``True``, which replaces any existing stored query with the same ``database`` and ``name``. Set this to ``False`` to raise a SQLite integrity error if the query already exists. + +Example: + +.. code-block:: python + + await datasette.add_query( + database="fixtures", + name="recent_rows", + sql="select * from facetable order by created desc limit 10", + title="Recent rows", + source="my-plugin", + ) + +.. _datasette_update_query: + +await .update_query(database, name, ...) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Updates fields for an existing stored query. Only keyword arguments that are provided will be changed. + +The available keyword arguments are the same as those for :ref:`datasette_add_query`, except for ``replace``. Pass ``None`` to clear optional text fields and options such as ``on_success_redirect``. Passing ``hide_sql=False`` removes the ``hide_sql`` option. + +Example: + +.. code-block:: python + + await datasette.update_query( + database="fixtures", + name="recent_rows", + title="Latest rows", + is_private=True, + owner_id="alice", + ) + +.. _datasette_get_query: + +await .get_query(database, name) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Returns a stored query dictionary, or ``None`` if the query does not exist. + +The dictionary contains ``database``, ``name``, ``sql``, ``title``, ``description``, ``description_html``, ``hide_sql``, ``fragment``, ``parameters``, ``params``, ``is_write``, ``is_private``, ``is_trusted``, ``source``, ``owner_id``, ``on_success_message``, ``on_success_message_sql``, ``on_success_redirect``, ``on_error_message`` and ``on_error_redirect``. + +``parameters`` and ``params`` contain the same list of explicit parameter names. + +.. _datasette_list_queries: + +await .list_queries(database=None, ...) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Lists stored queries visible to the specified actor. + +.. code-block:: python + + async def list_queries( + self, + database=None, + *, + actor=None, + limit=50, + cursor=None, + q=None, + is_write=None, + is_private=None, + is_trusted=None, + source=None, + owner_id=None, + include_private=False, + ): ... + +``database`` - string, optional + Restrict results to a specific database. Omit this to list queries across all databases. +``actor`` - dictionary, optional + The authenticated actor. Results are filtered using that actor's ``view-query`` permission. +``limit`` - integer, optional + Number of queries to return. Values are clamped to the range 1-1000. +``cursor`` - string, optional + Pagination cursor from the previous page's ``next`` value. +``q`` - string, optional + Search string matched against query name, title, description and SQL. +``is_write``, ``is_private``, ``is_trusted`` - boolean, optional + Filter by those stored query flags. +``source`` - string, optional + Filter by query source. +``owner_id`` - string, optional + Filter by owner actor ID. +``include_private`` - boolean, optional + Set to ``True`` to include a ``private`` boolean in each returned query dictionary indicating if anonymous users would be unable to view that query. + +The return value is a dictionary with these keys: + +``queries`` - list of dictionaries + Stored query dictionaries, in the same format returned by :ref:`datasette_get_query`. +``next`` - string or None + Pagination cursor for the next page, if one exists. +``has_more`` - boolean + ``True`` if another page of results is available. +``limit`` - integer + The limit used for this page. + +.. _datasette_count_queries: + +await .count_queries(database=None, ...) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Counts stored queries visible to the specified actor. This accepts the same filtering keyword arguments as :ref:`datasette_list_queries`, except for ``limit``, ``cursor`` and ``include_private``. + +.. _datasette_remove_query: + +await .remove_query(database, name, source=None) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + +Removes a stored query. + +``database`` - string + The database the query belongs to. +``name`` - string + The query name. +``source`` - string, optional + If provided, only a query with this source will be removed. + .. _datasette_column_types: Column types @@ -2239,8 +2433,8 @@ Note that the space character is a special case: it will be replaced with a ``+` .. _internals_utils_call_with_supported_arguments: -call_with_supported_arguments(fn, **kwargs) -------------------------------------------- +call_with_supported_arguments(fn, \*\*kwargs) +--------------------------------------------- Call ``fn``, passing it only those keyword arguments that match its function signature. This implements a dependency injection pattern - the caller provides all available arguments, and the function receives only the ones it declares as parameters. @@ -2267,8 +2461,8 @@ This is useful in plugins that want to define callback functions that only decla .. _internals_utils_async_call_with_supported_arguments: -await async_call_with_supported_arguments(fn, **kwargs) -------------------------------------------------------- +await async_call_with_supported_arguments(fn, \*\*kwargs) +--------------------------------------------------------- Async version of :ref:`call_with_supported_arguments `. Use this for ``async def`` callback functions.