|
1 | | -# SQLAlchemy bind manager |
2 | | - |
3 | | -[](https://pypi.org/project/sqlalchemy-bind-manager/) |
4 | | -[](https://github.com/mkenney/software-guides/blob/master/STABILITY-BADGES.md#beta) |
5 | | - |
6 | | -[](https://github.com/febus982/sqlalchemy-bind-manager/actions/workflows/python-tests.yml) |
7 | | -[](https://codeclimate.com/github/febus982/sqlalchemy-bind-manager/maintainability) |
8 | | -[](https://codeclimate.com/github/febus982/sqlalchemy-bind-manager/test_coverage) |
9 | | - |
10 | | -[](https://mypy-lang.org/) |
11 | | -[](https://github.com/psf/black) |
12 | | -[](https://github.com/charliermarsh/ruff) |
13 | | -[](https://github.com/PyCQA/bandit) |
14 | | - |
15 | | -This package provides an easy way to configure and use SQLAlchemy without |
16 | | -depending on frameworks. |
17 | | - |
18 | | -It is composed by two main components: |
19 | | - |
20 | | -* A manager class for SQLAlchemy engine and session configuration |
21 | | -* A repository/unit-of-work pattern implementation for model retrieval and persistence |
22 | | - |
23 | | -## Why another SQLAlchemy helper package? |
24 | | - |
25 | | -There are some existing plugins that help the creation of the standard SQLAlchemy boilerplate |
26 | | -code for engine, session and base declarative model, but they mainly aim to integrate |
27 | | -with existing frameworks. |
28 | | - |
29 | | -In order to create a maintainable application it is important to use a framework, but to |
30 | | -not be limited by it. It might be desirable to switch to more modern technologies |
31 | | -and binding the storage layer with the framework would bring a high degree of complexity. |
32 | | - |
33 | | -Also implementing a highly decoupled application would use abstractions between the application |
34 | | -logic and the storage, therefore this package provides a base implementation of a storage |
35 | | -abstraction layer (Repository). |
36 | | - |
37 | | -The scope of this package is to: |
38 | | - |
39 | | -* Be able to setup a basic application with a few lines of code |
40 | | -* Avoid common pitfalls found in other plugins for session lifecycle |
41 | | -* Allow to build a [decoupled application](https://github.com/febus982/bootstrap-python-fastapi) without being bound to HTTP frameworks |
42 | | - |
43 | | -## Components maturity |
44 | | - |
45 | | -The components have a high test coverage, and it should not be necessary to change the interfaces, |
46 | | -however this might be necessary until version `1.0` is released. |
47 | | - |
48 | | -[//]: # (https://github.com/mkenney/software-guides/blob/master/STABILITY-BADGES.md) |
49 | | -* [](https://github.com/mkenney/software-guides/blob/master/STABILITY-BADGES.md#beta) **SQLAlchemy manager:** Implementation is mostly finalised, needs testing in production. |
50 | | -* [](https://github.com/mkenney/software-guides/blob/master/STABILITY-BADGES.md#beta) **Repository:** Implementation is mostly finalised, needs testing in production. |
51 | | -* [](https://github.com/mkenney/software-guides/blob/master/STABILITY-BADGES.md#experimental) **Unit of work:** The implementation is working but limited to repositories using the same engine. Distributed transactions across different engines are not yet supported. |
52 | | - |
53 | | -## Installation |
54 | | - |
55 | | -```bash |
56 | | -pip install sqlalchemy-bind-manager |
57 | | -``` |
58 | | - |
59 | | -## Quick start |
60 | | - |
61 | | -```python |
62 | | -from sqlalchemy_bind_manager import SQLAlchemyConfig, SQLAlchemyBindManager |
63 | | -from sqlalchemy.orm import Mapped, mapped_column |
64 | | -from sqlalchemy import String |
65 | | - |
66 | | -config = SQLAlchemyConfig( |
67 | | - engine_url="sqlite:///./sqlite.db", |
68 | | - engine_options=dict(connect_args={"check_same_thread": False}, echo=True), |
69 | | - session_options=dict(expire_on_commit=False), |
70 | | -) |
71 | | - |
72 | | -# Initialise the bind manager |
73 | | -sa_manager = SQLAlchemyBindManager(config) |
74 | | - |
75 | | -# Declare a model |
76 | | -class MyModel(sa_manager.get_bind().declarative_base): |
77 | | - id: Mapped[int] = mapped_column(primary_key=True) |
78 | | - name: Mapped[str] = mapped_column(String(30)) |
79 | | - |
80 | | -# Initialise the tables in the db |
81 | | -bind = sa_manager.get_bind() |
82 | | -bind.registry_mapper.metadata.create_all(bind.engine) |
83 | | - |
84 | | -# Create and save a model |
85 | | -o = MyModel() |
86 | | -o.name = "John" |
87 | | -with sa_manager.get_session() as session: |
88 | | - session.add(o) |
89 | | - session.commit() |
90 | | -``` |
91 | | - |
92 | | -/// details | Long lived sessions and multithreading |
93 | | - type: warning |
94 | | - |
95 | | -It's not recommended to create long-lived sessions like: |
96 | | - |
97 | | -``` |
98 | | -session = sa_manager.get_session() |
99 | | -``` |
100 | | - |
101 | | -This can create unexpected behaviours because of global variables and multi-threading. |
102 | | -More details can be found in the [session page](manager/session.md#note-on-multithreaded-applications) |
103 | | -/// |
| 1 | +--8<-- "./README.md" |
0 commit comments