Use triggers to maintain a chronicle table of updated/deleted timestamps in SQLite
Project description
sqlite-chronicle
Use triggers to track when rows in a SQLite table were updated or deleted
Installation
pip install sqlite-chronicle
enable_chronicle(conn, table_name)
This module provides a function: sqlite_chronicle.enable_chronicle(conn, table_name)
, which does the following:
- Checks if a
_chronicle_{table_name}
table exists already. If so, it does nothing. Otherwise... - Creates that table, with the same primary key columns as the original table plus integer columns
added_ms
,updated_ms
,version
anddeleted
- Creates a new row in the chronicle table corresponding to every row in the original table, setting
added_ms
andupdated_ms
to the current timestamp in milliseconds, andversion
column that starts at 1 and increments for each subsequent row - Sets up three triggers on the table:
- An after insert trigger, which creates a new row in the chronicle table, sets
added_ms
andupdated_ms
to the current time and increments theversion
- An after update trigger, which updates the
updated_ms
timestamp and also updates any primary keys if they have changed (likely extremely rare) plus increments theversion
- An after delete trigger, which updates the
updated_ms
, increments theversion
and places a1
in thedeleted
column
The function will raise a sqlite_chronicle.ChronicleError
exception if the table does not have a single or compound primary key.
Note that the version
for a table is a globally incrementing number, so every time it is set it will be set to the current max(version)
+ 1 for that entire table.
The end result is a chronicle table that looks something like this:
id | added_ms | updated_ms | version | deleted |
---|---|---|---|---|
47 | 1694408890954 | 1694408890954 | 2 | 0 |
48 | 1694408874863 | 1694408874863 | 3 | 1 |
1 | 1694408825192 | 1694408825192 | 4 | 0 |
2 | 1694408825192 | 1694408825192 | 5 | 0 |
3 | 1694408825192 | 1694408825192 | 6 | 0 |
updates_since(conn, table_name, since=None, batch_size=1000)
The sqlite_chronicle.updates_since()
function returns a generator over a list of Change
objects.
These objects represent changes that have occurred to rows in the table since the since
version number, or since the beginning of time if since
is not provided.
conn
is a SQLite connection objecttable_name
is a string containing the name of the table to get changes forsince
is an optional integer version number - if not provided, all changes will be returnedbatch_size
is an internal detail, controlling the number of rows that are returned from the database at a time. You should not need to change this as the function implements its own internal pagination.
Each Change
returned from the generator looks something like this:
Change(
pks=(5,),
added_ms=1701836971223,
updated_ms=1701836971223,
version=5,
row={'id': 5, 'name': 'Simon'},
deleted=0
)
A Change
is a dataclass with the following properties:
pks
is a tuple of the primary key values for the row - this will be a tuple with a single item for normal primary keys, or multiple items for compound primary keysadded_ms
is the timestamp in milliseconds when the row was addedupdated_ms
is the timestamp in milliseconds when the row was last updatedversion
is the version number for the row - you can use this as asince
value to get changes since that pointrow
is a dictionary containing the current values for the row - these will beNone
if the row has been deleted (except for the primary keys)deleted
is0
if the row has not been deleted, or1
if it has been deleted
Any time you call this you should track the last version
number that you see, so you can pass it as the since
value in future calls to get changes that occurred since that point.
Note that if a row had multiple updates in between calls to this function you will still only see one Change
object for that row - the updated_ms
and version
will reflect the most recent update.
Potential applications
Chronicle tables can be used to efficiently answer the question "what rows have been inserted, updated or deleted since I last checked" - by looking at the version
column which has an index to make it fast to answer that question.
This has numerous potential applications, including:
- Synchronization and replication: other databases can "subscribe" to tables, keeping track of when they last refreshed their copy and requesting just rows that changed since the last time - and deleting rows that have been marked as deleted.
- Indexing: if you need to update an Elasticsearch index or a vector database embeddings index or similar you can run against just the records that changed since your last run - see also The denormalized query engine design pattern
- Enrichments: datasette-enrichments needs to to persist something that says "every address column should be geocoded" - then have an enrichment that runs every X seconds and looks for newly inserted or updated rows and enriches just those.
- Showing people what has changed since their last visit - "52 rows have been updated and 16 deleted since yesterday" kind of thing.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file sqlite-chronicle-0.2.1.tar.gz
.
File metadata
- Download URL: sqlite-chronicle-0.2.1.tar.gz
- Upload date:
- Size: 7.2 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 2661610ea9c7541932af4039a9b65fa100ea864ce701e8748073afac3afda8a0 |
|
MD5 | 87ace732e205ce6eeba5ba5c388edbee |
|
BLAKE2b-256 | 22d4488f162900b8e74cb35233de13f09ea721e648fb730084b4f014426c7c47 |
File details
Details for the file sqlite_chronicle-0.2.1-py3-none-any.whl
.
File metadata
- Download URL: sqlite_chronicle-0.2.1-py3-none-any.whl
- Upload date:
- Size: 5.5 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/4.0.2 CPython/3.11.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | 94253e1c92ac2b9c73fdd6ff0afd3bf7295c90318dd64fa256695db1f348bd62 |
|
MD5 | e32f6f65368c5425defd43555b2ec846 |
|
BLAKE2b-256 | 0b90e58d5ea301c22cec50193444e2b35dfc9b930311a7dcbcaf55885b8af764 |