{"id":24649560,"url":"https://github.com/electrumsv/electrumsv-database","last_synced_at":"2026-05-08T04:34:01.252Z","repository":{"id":57425990,"uuid":"462497293","full_name":"electrumsv/electrumsv-database","owner":"electrumsv","description":"Database abstraction for SQLite usage from Python","archived":false,"fork":false,"pushed_at":"2023-01-09T22:14:51.000Z","size":29,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-20T19:11:12.073Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/electrumsv.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2022-02-22T22:33:22.000Z","updated_at":"2022-02-22T22:59:21.000Z","dependencies_parsed_at":"2023-02-08T14:35:12.935Z","dependency_job_id":null,"html_url":"https://github.com/electrumsv/electrumsv-database","commit_stats":null,"previous_names":[],"tags_count":3,"template":false,"template_full_name":null,"purl":"pkg:github/electrumsv/electrumsv-database","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electrumsv%2Felectrumsv-database","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electrumsv%2Felectrumsv-database/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electrumsv%2Felectrumsv-database/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electrumsv%2Felectrumsv-database/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/electrumsv","download_url":"https://codeload.github.com/electrumsv/electrumsv-database/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/electrumsv%2Felectrumsv-database/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261380908,"owners_count":23149966,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-01-25T17:17:39.465Z","updated_at":"2026-05-08T04:33:56.229Z","avatar_url":"https://github.com/electrumsv.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ElectrumSV Database\n\n    Licence: MIT License\n    Maintainers: Roger Taylor, AustEcon\n    Project Lead: Roger Taylor\n    Homepage: https://electrumsv.io/\n\n\n# Overview\n\nThis is the database support library for ElectrumSV. This functionality has been extracted into\nan independent package so that it can be used by other projects.\n\n## Usage\n\n### Reads\n\nIt is envisioned that most reads will be done with the aid of the\n`replace_db_context_with_connection` decorator. The calling logic will have a reference to a\ndatabase context, and the decorator will inject a database connection as the first argument to\nthe wrapped function. These can happen inline in the calling context.\n\nIf a read query is one that will take more than a nominal amount of time, the developer should\nuse worker threads to farm out the query. There is a good argument that we should add that to\nthis library in order to deal with the typing complications.\n\n### Writes\n\nSQLite has a [well known limitation](https://www.sqlite.org/faq.html#q5) in that only one\nconnection can be making changes, or writes, at a time. What this package does is use one\nwriter thread to apply write queries sequentially through it's connection. This is all managed\nas part of the `DatabaseContext` class, which creates the `SqliteWriteDispatcher` and\n`SqliteExecutor` for you.\n\nCreating a database context:\n\n```\nfrom electrumsv_database import DatabaseContext\ndatabase_context = DatabaseContext(database_path)\n```\n\nBlock executing a writer callback as a transaction:\n\n```\ndef write(a: int, s: str, db: Optional[sqlite3.Connection]=None) -\u003e str:\n    assert db is not None and isinstance(db, sqlite3.Connection)\n    db.execute(\"INSERT INTO SomeTable(a, s) VALUES (?, ?)\", (a, s))\n    return \"whatever return value\"\n\ns = database_context.run_in_thread(write, 5, \"test\")\nassert s == \"whatever return value\"\n```\n\nPost a writer callback to be executed as a transaction:\n\n```\ndef write(a: int, s: str, db: Optional[sqlite3.Connection]=None) -\u003e str:\n    assert db is not None and isinstance(db, sqlite3.Connection)\n    db.execute(\"INSERT INTO SomeTable(a, s) VALUES (?, ?)\", (a, s))\n    return \"whatever return value\"\n\nfuture = database_context.post_to_thread(write, 5, \"test\")\n# Perform whatever other logic.\ns = future.result()\nassert s == \"whatever return value\"\n```\n\nAsynchronously block executing a writer callback as a transaction:\n\n```\ndef write(a: int, s: str, db: Optional[sqlite3.Connection]=None) -\u003e str:\n    assert db is not None and isinstance(db, sqlite3.Connection)\n    db.execute(\"INSERT INTO SomeTable(a, s) VALUES (?, ?)\", (a, s))\n    return \"whatever return value\"\n\ns = await database_context.run_in_thread_async(write, 5, \"test\")\nassert s == \"whatever return value\"\n```\n\n\n## Typing\n\nPython has flawed problematic typing. It is very easy to have code that is wrong and not being\nchecked, but be unaware of it. This package makes various choices to try and ensure that all\nof it's operations are typed.\n\n### Write functions\n\nQueries that do write operations are executed using callbacks, and this means that we want to\ncheck the types of the arguments in the application logic. We use `ParamSpec` for this, but it has\na limitation in that the typing of its `args` and `kwargs` attributes are atomic.\n\n```\nP1 = ParamSpec(\"P1\")\nT1 = TypeVar(\"T1\")\n\n    async def run_in_thread_async(self, func: Callable[P1, T1], *args: P1.args, \\\n            **kwargs: P1.kwargs) -\u003e T1:\n        ...\n```\n\nIt is not possible to remove or add arguments to take into account perhaps extra ones added in\nthe writer thread - like a reference to the database connection which the write callback should\nuse to execute it's query. For this reason we use the following pattern, the write callback\nadds an optional `db` keyword argument to the end of it's argument list, the write dispatcher\nprovides that adding it as an extra argument over the one the application provided.\n\nThe following pattern should be used:\n\n```\ndef set_payment_channel_closed(channel_id: int, channel_state: ChannelState,\n        db: Optional[sqlite3.Connection]=None) -\u003e None:\n    assert db is not None and isinstance(db, sqlite3.Connection)\n    ...\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felectrumsv%2Felectrumsv-database","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Felectrumsv%2Felectrumsv-database","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Felectrumsv%2Felectrumsv-database/lists"}