feat: Implement a prepare_connection plugin hook

This commit is contained in:
Alex Garcia 2023-07-22 15:31:53 -07:00
commit ae973e794b
4 changed files with 78 additions and 2 deletions

View file

@ -84,7 +84,7 @@ Your command will also be listed in the output of ``sqlite-utils --help``.
Plugin hooks
------------
Plugin hooks allow ``sqlite-utils`` to be customized. There is currently one hook.
Plugin hooks allow ``sqlite-utils`` to be customized.
.. _plugins_hooks_register_commands:
@ -107,3 +107,29 @@ Example implementation:
"Say hello world"
click.echo("Hello world!")
prepare_connection(conncl)
~~~~~~~~~~~~~~~~~~~~~~
This hook is called when a new SQLite database connection is created. You can
use it to `register custom SQL functions <https://docs.python.org/2/library/sqlite3.html#sqlite3.Connection.create_function>`_,
aggregates and collations. For example:
Example implementation:
.. code-block:: python
import click
import sqlite_utils
@sqlite_utils.hookimpl
def prepare_connection(self, conn):
conn.create_function(
"hello", 1, lambda name: f"Hello, {name}!"
)
This registers a SQL function called ``hello`` which takes a single
argument and can be called like this::
.. code-block:: sql
select hello("world"); -- "Hello, world!"

View file

@ -37,6 +37,7 @@ from typing import (
Tuple,
)
import uuid
from sqlite_utils.plugins import pm
try:
from sqlite_dump import iterdump
@ -342,6 +343,8 @@ class Database:
self._registered_functions: set = set()
self.use_counts_table = use_counts_table
pm.hook.prepare_connection(conn=self.conn)
def close(self):
"Close the SQLite connection, and the underlying database file"
self.conn.close()

View file

@ -8,3 +8,8 @@ hookimpl = HookimplMarker("sqlite_utils")
@hookspec
def register_commands(cli):
"""Register additional CLI commands, e.g. 'sqlite-utils mycommand ...'"""
@hookspec
def prepare_connection(conn):
"""Modify SQLite connection in some way e.g. register custom SQL functions"""

View file

@ -1,7 +1,7 @@
from click.testing import CliRunner
import click
import importlib
from sqlite_utils import cli, hookimpl, plugins
from sqlite_utils import cli, Database, hookimpl, plugins
def test_register_commands():
@ -35,3 +35,45 @@ def test_register_commands():
plugins.pm.unregister(name="HelloWorldPlugin")
importlib.reload(cli)
assert plugins.get_plugins() == []
def test_prepare_connection():
importlib.reload(cli)
assert plugins.get_plugins() == []
class HelloFunctionPlugin:
__name__ = "HelloFunctionPlugin"
@hookimpl
def prepare_connection(self, conn):
conn.create_function("hello", 1, lambda name: f"Hello, {name}!")
db = Database(memory=True)
functions = db.execute(
"select distinct name from pragma_function_list order by 1"
).fetchall()
assert "hello" not in functions
try:
plugins.pm.register(HelloFunctionPlugin(), name="HelloFunctionPlugin")
assert plugins.get_plugins() == [
{"name": "HelloFunctionPlugin", "hooks": ["prepare_connection"]}
]
db = Database(memory=True)
functions = [
row[0]
for row in db.execute(
"select distinct name from pragma_function_list order by 1"
).fetchall()
]
assert "hello" in functions
result = db.execute('select hello("world")').fetchone()[0]
assert result == "Hello, world!"
finally:
plugins.pm.unregister(name="HelloFunctionPlugin")
assert plugins.get_plugins() == []