depeche-db


Namedepeche-db JSON
Version 0.8.0 PyPI version JSON
download
home_pagehttps://github.com/depeche-py/depeche-db
SummaryA library for building event-based systems on top of PostgreSQL
upload_time2024-01-20 19:31:23
maintainer
docs_urlNone
authorMartin Vielsmaier
requires_python>=3.9,<4.0
licenseMIT
keywords sqlalchemy postgresql event-driven event store message store event sourcing
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            

<p align="center">
  <img src="https://depeche-py.github.io/depeche-db/assets/logo-bg.png" width="200" />
</p>

# Depeche DB

A library for building event-based systems on top of PostgreSQL

[![Tests](https://github.com/depeche-py/depeche-db/actions/workflows/tests.yml/badge.svg)](https://github.com/depeche-py/depeche-db/actions/workflows/tests.yml)
[![pypi](https://img.shields.io/pypi/v/depeche-db.svg)](https://pypi.python.org/pypi/depeche-db)
[![versions](https://img.shields.io/pypi/pyversions/depeche-db.svg)](https://github.com/depeche-py/depeche-db)
[![Docs](https://img.shields.io/badge/docs-here-green.svg)](https://depeche-py.github.io/depeche-db/)
[![license](https://img.shields.io/github/license/depeche-py/depeche-db.svg)](https://github.com/depeche-py/depeche-db/blob/main/LICENSE)

---

**Documentation**: [https://depeche-py.github.io/depeche-db/](https://depeche-py.github.io/depeche-db/)

**Source code**: [https://github.com/depeche-py/depeche-db](https://github.com/depeche-py/depeche-db)

---

Depeche DB is modern Python library for building event-based systems

Key features:

* Message store with optimistic concurrency control & strong ordering guarantees
* Subscriptions with "at least once" semantics
* Parallel processing of (partitioned) subscriptions
* No database polling

## Requirements

Python 3.9+

SQLAlchemy 1.4 or 2+

PostgreSQL 12+


## Installation

```bash
pip install depeche-db
# OR
poetry add depeche-db
```

## Example

```python
import pydantic, sqlalchemy, uuid, datetime as dt

from depeche_db import (
    MessageStore,
    StoredMessage,
    MessageHandler,
    SubscriptionMessage,
)
from depeche_db.tools import PydanticMessageSerializer

DB_DSN = "postgresql://depeche:depeche@localhost:4888/depeche_demo"
db_engine = sqlalchemy.create_engine(DB_DSN)


class MyMessage(pydantic.BaseModel):
    content: int
    message_id: uuid.UUID = pydantic.Field(default_factory=uuid.uuid4)
    sent_at: dt.datetime = pydantic.Field(default_factory=dt.datetime.utcnow)

    def get_message_id(self) -> uuid.UUID:
        return self.message_id

    def get_message_time(self) -> dt.datetime:
        return self.sent_at


message_store = MessageStore[MyMessage](
    name="example_store",
    engine=db_engine,
    serializer=PydanticMessageSerializer(MyMessage),
)
message_store.write(stream="aggregate-me-1", message=MyMessage(content=2))
print(list(message_store.read(stream="aggregate-me-1")))
# [StoredMessage(message_id=UUID('...'), stream='aggregate-me-1', version=1, message=MyMessage(content=2, message_id=UUID('...'), sent_at=datetime.datetime(...)), global_position=1)]


class ContentMessagePartitioner:
    def get_partition(self, message: StoredMessage[MyMessage]) -> int:
        return message.message.content % 10


class MyHandlers(MessageHandler[MyMessage]):
    @MessageHandler.register
    def handle_message(self, message: SubscriptionMessage[MyMessage]):
        print(message)


aggregated_stream = message_store.aggregated_stream(
    name="aggregated",
    partitioner=ContentMessagePartitioner(),
    stream_wildcards=["aggregate-me-%"],
)
subscription = aggregated_stream.subscription(
    name="example_subscription",
    handlers=MyHandlers(),
)

aggregated_stream.projector.run()
subscription.runner.run()
# MyHandlers.handle_message prints:
# SubscriptionMessage(partition=2, position=0, stored_message=StoredMessage(...))

```


## Contribute

Contributions in the form of issues, questions, feedback and pull requests are
welcome. Before investing a lot of time, let me know what you are up to so
we can see if your contribution fits the vision of the project.


            

Raw data

            {
    "_id": null,
    "home_page": "https://github.com/depeche-py/depeche-db",
    "name": "depeche-db",
    "maintainer": "",
    "docs_url": null,
    "requires_python": ">=3.9,<4.0",
    "maintainer_email": "",
    "keywords": "sqlalchemy,postgresql,event-driven,event store,message store,event sourcing",
    "author": "Martin Vielsmaier",
    "author_email": "martin@vielsmaier.net",
    "download_url": "https://files.pythonhosted.org/packages/59/71/fc822397a51d52bdb0aa8a67fa47062fd1629bf2b06ed8449c0df7431725/depeche_db-0.8.0.tar.gz",
    "platform": null,
    "description": "\n\n<p align=\"center\">\n  <img src=\"https://depeche-py.github.io/depeche-db/assets/logo-bg.png\" width=\"200\" />\n</p>\n\n# Depeche DB\n\nA library for building event-based systems on top of PostgreSQL\n\n[![Tests](https://github.com/depeche-py/depeche-db/actions/workflows/tests.yml/badge.svg)](https://github.com/depeche-py/depeche-db/actions/workflows/tests.yml)\n[![pypi](https://img.shields.io/pypi/v/depeche-db.svg)](https://pypi.python.org/pypi/depeche-db)\n[![versions](https://img.shields.io/pypi/pyversions/depeche-db.svg)](https://github.com/depeche-py/depeche-db)\n[![Docs](https://img.shields.io/badge/docs-here-green.svg)](https://depeche-py.github.io/depeche-db/)\n[![license](https://img.shields.io/github/license/depeche-py/depeche-db.svg)](https://github.com/depeche-py/depeche-db/blob/main/LICENSE)\n\n---\n\n**Documentation**: [https://depeche-py.github.io/depeche-db/](https://depeche-py.github.io/depeche-db/)\n\n**Source code**: [https://github.com/depeche-py/depeche-db](https://github.com/depeche-py/depeche-db)\n\n---\n\nDepeche DB is modern Python library for building event-based systems\n\nKey features:\n\n* Message store with optimistic concurrency control & strong ordering guarantees\n* Subscriptions with \"at least once\" semantics\n* Parallel processing of (partitioned) subscriptions\n* No database polling\n\n## Requirements\n\nPython 3.9+\n\nSQLAlchemy 1.4 or 2+\n\nPostgreSQL 12+\n\n\n## Installation\n\n```bash\npip install depeche-db\n# OR\npoetry add depeche-db\n```\n\n## Example\n\n```python\nimport pydantic, sqlalchemy, uuid, datetime as dt\n\nfrom depeche_db import (\n    MessageStore,\n    StoredMessage,\n    MessageHandler,\n    SubscriptionMessage,\n)\nfrom depeche_db.tools import PydanticMessageSerializer\n\nDB_DSN = \"postgresql://depeche:depeche@localhost:4888/depeche_demo\"\ndb_engine = sqlalchemy.create_engine(DB_DSN)\n\n\nclass MyMessage(pydantic.BaseModel):\n    content: int\n    message_id: uuid.UUID = pydantic.Field(default_factory=uuid.uuid4)\n    sent_at: dt.datetime = pydantic.Field(default_factory=dt.datetime.utcnow)\n\n    def get_message_id(self) -> uuid.UUID:\n        return self.message_id\n\n    def get_message_time(self) -> dt.datetime:\n        return self.sent_at\n\n\nmessage_store = MessageStore[MyMessage](\n    name=\"example_store\",\n    engine=db_engine,\n    serializer=PydanticMessageSerializer(MyMessage),\n)\nmessage_store.write(stream=\"aggregate-me-1\", message=MyMessage(content=2))\nprint(list(message_store.read(stream=\"aggregate-me-1\")))\n# [StoredMessage(message_id=UUID('...'), stream='aggregate-me-1', version=1, message=MyMessage(content=2, message_id=UUID('...'), sent_at=datetime.datetime(...)), global_position=1)]\n\n\nclass ContentMessagePartitioner:\n    def get_partition(self, message: StoredMessage[MyMessage]) -> int:\n        return message.message.content % 10\n\n\nclass MyHandlers(MessageHandler[MyMessage]):\n    @MessageHandler.register\n    def handle_message(self, message: SubscriptionMessage[MyMessage]):\n        print(message)\n\n\naggregated_stream = message_store.aggregated_stream(\n    name=\"aggregated\",\n    partitioner=ContentMessagePartitioner(),\n    stream_wildcards=[\"aggregate-me-%\"],\n)\nsubscription = aggregated_stream.subscription(\n    name=\"example_subscription\",\n    handlers=MyHandlers(),\n)\n\naggregated_stream.projector.run()\nsubscription.runner.run()\n# MyHandlers.handle_message prints:\n# SubscriptionMessage(partition=2, position=0, stored_message=StoredMessage(...))\n\n```\n\n\n## Contribute\n\nContributions in the form of issues, questions, feedback and pull requests are\nwelcome. Before investing a lot of time, let me know what you are up to so\nwe can see if your contribution fits the vision of the project.\n\n",
    "bugtrack_url": null,
    "license": "MIT",
    "summary": "A library for building event-based systems on top of PostgreSQL",
    "version": "0.8.0",
    "project_urls": {
        "Changelog": "https://depeche-py.github.io/depeche-db/CHANGELOG/",
        "Documentation": "https://depeche-py.github.io/depeche-db/",
        "Homepage": "https://github.com/depeche-py/depeche-db",
        "Repository": "https://github.com/depeche-py/depeche-db"
    },
    "split_keywords": [
        "sqlalchemy",
        "postgresql",
        "event-driven",
        "event store",
        "message store",
        "event sourcing"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "6f26ff2484ed52e4817eb6eb063eeaa6e705144ebffd445b646ed0a398687ffb",
                "md5": "d757d05fbcea6db62c6dc5eb442a3c75",
                "sha256": "92f054b0d992abf8066c20f58a1a74b9d7f1b40793cabae7a5f2dc70b14fd0d7"
            },
            "downloads": -1,
            "filename": "depeche_db-0.8.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "d757d05fbcea6db62c6dc5eb442a3c75",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9,<4.0",
            "size": 32743,
            "upload_time": "2024-01-20T19:31:22",
            "upload_time_iso_8601": "2024-01-20T19:31:22.196156Z",
            "url": "https://files.pythonhosted.org/packages/6f/26/ff2484ed52e4817eb6eb063eeaa6e705144ebffd445b646ed0a398687ffb/depeche_db-0.8.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "5971fc822397a51d52bdb0aa8a67fa47062fd1629bf2b06ed8449c0df7431725",
                "md5": "6c9621db14622ede5cf0311d040565d9",
                "sha256": "be1ff87a860546aaa0b9fac120ca81357ecc1048de7d44927404fe868e201c90"
            },
            "downloads": -1,
            "filename": "depeche_db-0.8.0.tar.gz",
            "has_sig": false,
            "md5_digest": "6c9621db14622ede5cf0311d040565d9",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9,<4.0",
            "size": 26635,
            "upload_time": "2024-01-20T19:31:23",
            "upload_time_iso_8601": "2024-01-20T19:31:23.815201Z",
            "url": "https://files.pythonhosted.org/packages/59/71/fc822397a51d52bdb0aa8a67fa47062fd1629bf2b06ed8449c0df7431725/depeche_db-0.8.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-01-20 19:31:23",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "depeche-py",
    "github_project": "depeche-db",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "depeche-db"
}
        
Elapsed time: 2.96412s