persistence-kit 0.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- persistence_kit-0.1.0/LICENSE +21 -0
- persistence_kit-0.1.0/PKG-INFO +154 -0
- persistence_kit-0.1.0/README.md +123 -0
- persistence_kit-0.1.0/persistence_kit/__init__.py +5 -0
- persistence_kit-0.1.0/persistence_kit/abstract_repository.py +45 -0
- persistence_kit-0.1.0/persistence_kit/abstract_view_repo.py +43 -0
- persistence_kit-0.1.0/persistence_kit/config.py +26 -0
- persistence_kit-0.1.0/persistence_kit/py.typed +1 -0
- persistence_kit-0.1.0/persistence_kit/repository/.idea/inspectionProfiles/profiles_settings.xml +6 -0
- persistence_kit-0.1.0/persistence_kit/repository/.idea/misc.xml +4 -0
- persistence_kit-0.1.0/persistence_kit/repository/.idea/modules.xml +8 -0
- persistence_kit-0.1.0/persistence_kit/repository/.idea/repository.iml +8 -0
- persistence_kit-0.1.0/persistence_kit/repository/.idea/workspace.xml +48 -0
- persistence_kit-0.1.0/persistence_kit/repository/__init__.py +18 -0
- persistence_kit-0.1.0/persistence_kit/repository/filter_ops.py +32 -0
- persistence_kit-0.1.0/persistence_kit/repository/memory_repo/__init__.py +3 -0
- persistence_kit-0.1.0/persistence_kit/repository/memory_repo/memory_repo.py +163 -0
- persistence_kit-0.1.0/persistence_kit/repository/mongo_repo/__init__.py +4 -0
- persistence_kit-0.1.0/persistence_kit/repository/mongo_repo/mongo_mapper.py +51 -0
- persistence_kit-0.1.0/persistence_kit/repository/mongo_repo/mongo_repo.py +205 -0
- persistence_kit-0.1.0/persistence_kit/repository/sqlalchemy_repo/__init__.py +11 -0
- persistence_kit-0.1.0/persistence_kit/repository/sqlalchemy_repo/schema_evolve.py +40 -0
- persistence_kit-0.1.0/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_dataclass_mapper.py +64 -0
- persistence_kit-0.1.0/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_engine.py +11 -0
- persistence_kit-0.1.0/persistence_kit/repository/sqlalchemy_repo/sqlalchemy_repo.py +259 -0
- persistence_kit-0.1.0/persistence_kit/repository/sqlalchemy_repo/table_factory.py +63 -0
- persistence_kit-0.1.0/persistence_kit/repository_factory/.idea/inspectionProfiles/profiles_settings.xml +6 -0
- persistence_kit-0.1.0/persistence_kit/repository_factory/.idea/misc.xml +4 -0
- persistence_kit-0.1.0/persistence_kit/repository_factory/.idea/modules.xml +8 -0
- persistence_kit-0.1.0/persistence_kit/repository_factory/.idea/repository_factory.iml +8 -0
- persistence_kit-0.1.0/persistence_kit/repository_factory/.idea/workspace.xml +49 -0
- persistence_kit-0.1.0/persistence_kit/repository_factory/__init__.py +12 -0
- persistence_kit-0.1.0/persistence_kit/repository_factory/entity_registry.py +38 -0
- persistence_kit-0.1.0/persistence_kit/repository_factory/populating_repo.py +163 -0
- persistence_kit-0.1.0/persistence_kit/repository_factory/repo_factory.py +113 -0
- persistence_kit-0.1.0/pyproject.toml +36 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Andres Felipe Serrano Barrios
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: persistence-kit
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: Reusable persistence and repository toolkit
|
|
5
|
+
License: MIT
|
|
6
|
+
License-File: LICENSE
|
|
7
|
+
Keywords: repository,persistence,mongodb,sqlalchemy,async
|
|
8
|
+
Author: Andres Felipe Serrano Barrios
|
|
9
|
+
Author-email: andresfserrano1@gmail.com
|
|
10
|
+
Requires-Python: >=3.11,<4.0
|
|
11
|
+
Classifier: Development Status :: 3 - Alpha
|
|
12
|
+
Classifier: Intended Audience :: Developers
|
|
13
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
14
|
+
Classifier: Programming Language :: Python :: 3
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
19
|
+
Classifier: Topic :: Database
|
|
20
|
+
Classifier: Typing :: Typed
|
|
21
|
+
Requires-Dist: asyncpg (>=0.30.0,<0.31.0)
|
|
22
|
+
Requires-Dist: motor (>=3.7.1,<4.0.0)
|
|
23
|
+
Requires-Dist: pydantic-settings (>=2.3.0,<3.0.0)
|
|
24
|
+
Requires-Dist: sqlalchemy[asyncio] (>=2.0.43,<3.0.0)
|
|
25
|
+
Requires-Dist: typing-extensions (>=4.12.0,<5.0.0)
|
|
26
|
+
Project-URL: Documentation, https://github.com/andresfserrano/persistence-kit#readme
|
|
27
|
+
Project-URL: Homepage, https://pypi.org/project/persistence-kit/
|
|
28
|
+
Project-URL: Repository, https://github.com/andresfserrano/persistence-kit
|
|
29
|
+
Description-Content-Type: text/markdown
|
|
30
|
+
|
|
31
|
+
# persistence-kit
|
|
32
|
+
|
|
33
|
+
Reusable persistence toolkit with async repository implementations for:
|
|
34
|
+
|
|
35
|
+
- `memory`
|
|
36
|
+
- `mongo` (Motor)
|
|
37
|
+
- `postgres` (SQLAlchemy async + asyncpg)
|
|
38
|
+
|
|
39
|
+
Author: Andres Felipe Serrano Barrios
|
|
40
|
+
|
|
41
|
+
## Installation
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
pip install persistence-kit
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Quick Start
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
from persistence_kit.repository_factory import register_entity, get_repo
|
|
51
|
+
from persistence_kit.config import Database
|
|
52
|
+
|
|
53
|
+
# register entities during application startup
|
|
54
|
+
register_entity(
|
|
55
|
+
"user",
|
|
56
|
+
{
|
|
57
|
+
"entity": User,
|
|
58
|
+
"collection": "users",
|
|
59
|
+
"database": Database.MEMORY,
|
|
60
|
+
"unique": {"email": "email"},
|
|
61
|
+
},
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
repo = get_repo("user")
|
|
65
|
+
```
|
|
66
|
+
|
|
67
|
+
## Supported Environment Variables
|
|
68
|
+
|
|
69
|
+
- `REPO_DATABASE=memory|mongo|postgres`
|
|
70
|
+
- `MONGO_DSN`
|
|
71
|
+
- `MONGO_DB`
|
|
72
|
+
- `POSTGRES_USER`
|
|
73
|
+
- `POSTGRES_PASSWORD`
|
|
74
|
+
- `POSTGRES_HOST`
|
|
75
|
+
- `POSTGRES_PORT`
|
|
76
|
+
- `POSTGRES_DB`
|
|
77
|
+
|
|
78
|
+
## Publish to PyPI (Manual)
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
python -m pip install --upgrade build twine
|
|
82
|
+
python -m build
|
|
83
|
+
python -m twine check dist/*
|
|
84
|
+
python -m twine upload dist/*
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
## Automated Publish via GitHub Actions
|
|
88
|
+
|
|
89
|
+
This repository includes a workflow at `.github/workflows/publish-pypi.yml`.
|
|
90
|
+
|
|
91
|
+
It publishes to PyPI when:
|
|
92
|
+
|
|
93
|
+
- a GitHub Release is published
|
|
94
|
+
- the release tag points to the current `main` HEAD
|
|
95
|
+
|
|
96
|
+
Prerequisite:
|
|
97
|
+
|
|
98
|
+
- Configure PyPI Trusted Publishing for this repository and workflow file.
|
|
99
|
+
|
|
100
|
+
## Preview Releases Without PRs
|
|
101
|
+
|
|
102
|
+
Use `.github/workflows/publish-preview.yml` to publish directly from GitHub Actions
|
|
103
|
+
without merging a PR.
|
|
104
|
+
|
|
105
|
+
How it works:
|
|
106
|
+
|
|
107
|
+
- Trigger `Publish Preview Package` manually from the Actions tab.
|
|
108
|
+
- Enter a `version` (for example `0.1.1.dev1` or `0.1.2.dev1`).
|
|
109
|
+
- Choose target repository: `testpypi` (recommended) or `pypi`.
|
|
110
|
+
- The workflow patches `pyproject.toml` version only inside the CI run, builds, and publishes.
|
|
111
|
+
- No commit and no PR are required for this preview publish flow.
|
|
112
|
+
|
|
113
|
+
Important:
|
|
114
|
+
|
|
115
|
+
- Prefer `*.devN` versions for preview builds.
|
|
116
|
+
- PyPI/TestPyPI do not allow re-uploading the same file version.
|
|
117
|
+
|
|
118
|
+
## Local Test Releases (No PR Required)
|
|
119
|
+
|
|
120
|
+
If you want to test changes from your machine in external projects without opening a PR,
|
|
121
|
+
publish a prerelease from local code to TestPyPI.
|
|
122
|
+
|
|
123
|
+
### 1. Create a TestPyPI token
|
|
124
|
+
|
|
125
|
+
- Create an API token in TestPyPI.
|
|
126
|
+
- Export it as environment variable:
|
|
127
|
+
|
|
128
|
+
```bash
|
|
129
|
+
export TWINE_PASSWORD="pypi-***"
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
### 2. Publish from local code
|
|
133
|
+
|
|
134
|
+
```bash
|
|
135
|
+
bash ./scripts/publish-local.sh 0.1.1.dev1 testpypi
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
You can publish another local iteration with a new version:
|
|
139
|
+
|
|
140
|
+
```bash
|
|
141
|
+
bash ./scripts/publish-local.sh 0.1.1.dev2 testpypi
|
|
142
|
+
```
|
|
143
|
+
|
|
144
|
+
### 3. Install from external projects
|
|
145
|
+
|
|
146
|
+
```bash
|
|
147
|
+
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple persistence-kit==0.1.1.dev1
|
|
148
|
+
```
|
|
149
|
+
|
|
150
|
+
## Recommended Release Strategy
|
|
151
|
+
|
|
152
|
+
- Local experimental testing: publish `0.x.y.devN` to TestPyPI from local machine.
|
|
153
|
+
- Official release: publish `0.x.y` to PyPI through GitHub Release (`publish-pypi.yml`).
|
|
154
|
+
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
# persistence-kit
|
|
2
|
+
|
|
3
|
+
Reusable persistence toolkit with async repository implementations for:
|
|
4
|
+
|
|
5
|
+
- `memory`
|
|
6
|
+
- `mongo` (Motor)
|
|
7
|
+
- `postgres` (SQLAlchemy async + asyncpg)
|
|
8
|
+
|
|
9
|
+
Author: Andres Felipe Serrano Barrios
|
|
10
|
+
|
|
11
|
+
## Installation
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
pip install persistence-kit
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
```python
|
|
20
|
+
from persistence_kit.repository_factory import register_entity, get_repo
|
|
21
|
+
from persistence_kit.config import Database
|
|
22
|
+
|
|
23
|
+
# register entities during application startup
|
|
24
|
+
register_entity(
|
|
25
|
+
"user",
|
|
26
|
+
{
|
|
27
|
+
"entity": User,
|
|
28
|
+
"collection": "users",
|
|
29
|
+
"database": Database.MEMORY,
|
|
30
|
+
"unique": {"email": "email"},
|
|
31
|
+
},
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
repo = get_repo("user")
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## Supported Environment Variables
|
|
38
|
+
|
|
39
|
+
- `REPO_DATABASE=memory|mongo|postgres`
|
|
40
|
+
- `MONGO_DSN`
|
|
41
|
+
- `MONGO_DB`
|
|
42
|
+
- `POSTGRES_USER`
|
|
43
|
+
- `POSTGRES_PASSWORD`
|
|
44
|
+
- `POSTGRES_HOST`
|
|
45
|
+
- `POSTGRES_PORT`
|
|
46
|
+
- `POSTGRES_DB`
|
|
47
|
+
|
|
48
|
+
## Publish to PyPI (Manual)
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
python -m pip install --upgrade build twine
|
|
52
|
+
python -m build
|
|
53
|
+
python -m twine check dist/*
|
|
54
|
+
python -m twine upload dist/*
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
## Automated Publish via GitHub Actions
|
|
58
|
+
|
|
59
|
+
This repository includes a workflow at `.github/workflows/publish-pypi.yml`.
|
|
60
|
+
|
|
61
|
+
It publishes to PyPI when:
|
|
62
|
+
|
|
63
|
+
- a GitHub Release is published
|
|
64
|
+
- the release tag points to the current `main` HEAD
|
|
65
|
+
|
|
66
|
+
Prerequisite:
|
|
67
|
+
|
|
68
|
+
- Configure PyPI Trusted Publishing for this repository and workflow file.
|
|
69
|
+
|
|
70
|
+
## Preview Releases Without PRs
|
|
71
|
+
|
|
72
|
+
Use `.github/workflows/publish-preview.yml` to publish directly from GitHub Actions
|
|
73
|
+
without merging a PR.
|
|
74
|
+
|
|
75
|
+
How it works:
|
|
76
|
+
|
|
77
|
+
- Trigger `Publish Preview Package` manually from the Actions tab.
|
|
78
|
+
- Enter a `version` (for example `0.1.1.dev1` or `0.1.2.dev1`).
|
|
79
|
+
- Choose target repository: `testpypi` (recommended) or `pypi`.
|
|
80
|
+
- The workflow patches `pyproject.toml` version only inside the CI run, builds, and publishes.
|
|
81
|
+
- No commit and no PR are required for this preview publish flow.
|
|
82
|
+
|
|
83
|
+
Important:
|
|
84
|
+
|
|
85
|
+
- Prefer `*.devN` versions for preview builds.
|
|
86
|
+
- PyPI/TestPyPI do not allow re-uploading the same file version.
|
|
87
|
+
|
|
88
|
+
## Local Test Releases (No PR Required)
|
|
89
|
+
|
|
90
|
+
If you want to test changes from your machine in external projects without opening a PR,
|
|
91
|
+
publish a prerelease from local code to TestPyPI.
|
|
92
|
+
|
|
93
|
+
### 1. Create a TestPyPI token
|
|
94
|
+
|
|
95
|
+
- Create an API token in TestPyPI.
|
|
96
|
+
- Export it as environment variable:
|
|
97
|
+
|
|
98
|
+
```bash
|
|
99
|
+
export TWINE_PASSWORD="pypi-***"
|
|
100
|
+
```
|
|
101
|
+
|
|
102
|
+
### 2. Publish from local code
|
|
103
|
+
|
|
104
|
+
```bash
|
|
105
|
+
bash ./scripts/publish-local.sh 0.1.1.dev1 testpypi
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
You can publish another local iteration with a new version:
|
|
109
|
+
|
|
110
|
+
```bash
|
|
111
|
+
bash ./scripts/publish-local.sh 0.1.1.dev2 testpypi
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 3. Install from external projects
|
|
115
|
+
|
|
116
|
+
```bash
|
|
117
|
+
pip install --index-url https://test.pypi.org/simple/ --extra-index-url https://pypi.org/simple persistence-kit==0.1.1.dev1
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
## Recommended Release Strategy
|
|
121
|
+
|
|
122
|
+
- Local experimental testing: publish `0.x.y.devN` to TestPyPI from local machine.
|
|
123
|
+
- Official release: publish `0.x.y` to PyPI through GitHub Release (`publish-pypi.yml`).
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
from typing import Optional, Sequence, TypeVar, Generic, Hashable, Mapping, Any
|
|
6
|
+
|
|
7
|
+
T = TypeVar("T")
|
|
8
|
+
TId = TypeVar("TId", bound=Hashable)
|
|
9
|
+
|
|
10
|
+
class Repository(ABC, Generic[T, TId]):
|
|
11
|
+
@abstractmethod
|
|
12
|
+
async def add(self, entity: T) -> None: ...
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
async def get(self, entity_id: TId) -> Optional[T]: ...
|
|
16
|
+
|
|
17
|
+
@abstractmethod
|
|
18
|
+
async def list(
|
|
19
|
+
self,
|
|
20
|
+
*,
|
|
21
|
+
offset: int = 0,
|
|
22
|
+
limit: int = 50,
|
|
23
|
+
sort_by: str | None = None,
|
|
24
|
+
sort_desc: bool = False,
|
|
25
|
+
) -> Sequence[T]: ...
|
|
26
|
+
|
|
27
|
+
@abstractmethod
|
|
28
|
+
async def update(self, entity: T) -> None: ...
|
|
29
|
+
|
|
30
|
+
@abstractmethod
|
|
31
|
+
async def delete(self, entity_id: TId) -> None: ...
|
|
32
|
+
|
|
33
|
+
@abstractmethod
|
|
34
|
+
async def get_by_index(self, index: str, value: Hashable) -> Optional[T]: ...
|
|
35
|
+
|
|
36
|
+
@abstractmethod
|
|
37
|
+
async def list_by_fields(
|
|
38
|
+
self,
|
|
39
|
+
criteria: Mapping[str, Hashable | list[Hashable] | Mapping[str, Any]],
|
|
40
|
+
*,
|
|
41
|
+
offset: int = 0,
|
|
42
|
+
limit: Optional[int] = 50,
|
|
43
|
+
sort_by: str | None = None,
|
|
44
|
+
sort_desc: bool = False,
|
|
45
|
+
) -> Sequence[T]: ...
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from abc import ABC, abstractmethod
|
|
4
|
+
|
|
5
|
+
from typing import Optional, Sequence, TypeVar, Generic, Hashable, Mapping, Any
|
|
6
|
+
|
|
7
|
+
T = TypeVar("T")
|
|
8
|
+
TId = TypeVar("TId", bound=Hashable)
|
|
9
|
+
|
|
10
|
+
class ViewRepository(ABC, Generic[T, TId]):
|
|
11
|
+
@abstractmethod
|
|
12
|
+
async def get_with(self, entity_id: TId, include: Sequence[str]) -> Optional[dict]: ...
|
|
13
|
+
|
|
14
|
+
@abstractmethod
|
|
15
|
+
async def get_by_index_with(
|
|
16
|
+
self,
|
|
17
|
+
index: str,
|
|
18
|
+
value: Hashable,
|
|
19
|
+
include: Sequence[str],
|
|
20
|
+
) -> Optional[dict]: ...
|
|
21
|
+
|
|
22
|
+
@abstractmethod
|
|
23
|
+
async def list_with(
|
|
24
|
+
self,
|
|
25
|
+
*,
|
|
26
|
+
offset: int = 0,
|
|
27
|
+
limit: int = 50,
|
|
28
|
+
include: Sequence[str] = (),
|
|
29
|
+
sort_by: str | None = None,
|
|
30
|
+
sort_desc: bool = False,
|
|
31
|
+
) -> list[dict]: ...
|
|
32
|
+
|
|
33
|
+
@abstractmethod
|
|
34
|
+
async def list_by_fields(
|
|
35
|
+
self,
|
|
36
|
+
criteria: Mapping[str, Hashable | list[Hashable] | Mapping[str, Any]],
|
|
37
|
+
*,
|
|
38
|
+
offset: int = 0,
|
|
39
|
+
limit: Optional[int] = 50,
|
|
40
|
+
include: Sequence[str] = (),
|
|
41
|
+
sort_by: str | None = None,
|
|
42
|
+
sort_desc: bool = False,
|
|
43
|
+
) -> list[dict]: ...
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
from enum import Enum
|
|
2
|
+
|
|
3
|
+
from pydantic_settings import BaseSettings, SettingsConfigDict
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class Database(str, Enum):
|
|
7
|
+
MEMORY = "memory"
|
|
8
|
+
MONGO = "mongo"
|
|
9
|
+
POSTGRES = "postgres"
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
class RepoSettings(BaseSettings):
|
|
13
|
+
repo_database: Database = Database.MEMORY
|
|
14
|
+
|
|
15
|
+
mongo_dsn: str | None = None
|
|
16
|
+
mongo_db: str | None = None
|
|
17
|
+
|
|
18
|
+
postgres_user: str | None = None
|
|
19
|
+
postgres_password: str | None = None
|
|
20
|
+
postgres_host: str | None = None
|
|
21
|
+
postgres_port: int | None = 5432
|
|
22
|
+
postgres_db: str | None = None
|
|
23
|
+
|
|
24
|
+
# Keep the library environment-agnostic. Host applications decide
|
|
25
|
+
# whether settings come from .env, process env vars, secret stores, etc.
|
|
26
|
+
model_config = SettingsConfigDict(extra="ignore")
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ProjectModuleManager">
|
|
4
|
+
<modules>
|
|
5
|
+
<module fileurl="file://$PROJECT_DIR$/.idea/repository.iml" filepath="$PROJECT_DIR$/.idea/repository.iml" />
|
|
6
|
+
</modules>
|
|
7
|
+
</component>
|
|
8
|
+
</project>
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<module type="PYTHON_MODULE" version="4">
|
|
3
|
+
<component name="NewModuleRootManager">
|
|
4
|
+
<content url="file://$MODULE_DIR$" />
|
|
5
|
+
<orderEntry type="jdk" jdkName="Python 3.11 virtualenv at C:\Users\andre\OneDrive\Escritorio\SIGA\Backend\.venv" jdkType="Python SDK" />
|
|
6
|
+
<orderEntry type="sourceFolder" forTests="false" />
|
|
7
|
+
</component>
|
|
8
|
+
</module>
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<project version="4">
|
|
3
|
+
<component name="ChangeListManager">
|
|
4
|
+
<list default="true" id="3353231d-cbff-4250-b6f6-e702a244cb73" name="Changes" comment="" />
|
|
5
|
+
<option name="SHOW_DIALOG" value="false" />
|
|
6
|
+
<option name="HIGHLIGHT_CONFLICTS" value="true" />
|
|
7
|
+
<option name="HIGHLIGHT_NON_ACTIVE_CHANGELIST" value="false" />
|
|
8
|
+
<option name="LAST_RESOLUTION" value="IGNORE" />
|
|
9
|
+
</component>
|
|
10
|
+
<component name="ProjectColorInfo"><![CDATA[{
|
|
11
|
+
"associatedIndex": 7
|
|
12
|
+
}]]></component>
|
|
13
|
+
<component name="ProjectId" id="3A5AquY2AKyR9xwjoFWX4R6KC9b" />
|
|
14
|
+
<component name="ProjectViewState">
|
|
15
|
+
<option name="hideEmptyMiddlePackages" value="true" />
|
|
16
|
+
<option name="showLibraryContents" value="true" />
|
|
17
|
+
</component>
|
|
18
|
+
<component name="PropertiesComponent"><![CDATA[{
|
|
19
|
+
"keyToString": {
|
|
20
|
+
"ModuleVcsDetector.initialDetectionPerformed": "true",
|
|
21
|
+
"RunOnceActivity.ShowReadmeOnStart": "true",
|
|
22
|
+
"last_opened_file_path": "C:/Users/andre/OneDrive/Escritorio/aux programación udea/persistence_kit/repository",
|
|
23
|
+
"vue.rearranger.settings.migration": "true"
|
|
24
|
+
}
|
|
25
|
+
}]]></component>
|
|
26
|
+
<component name="SharedIndexes">
|
|
27
|
+
<attachedChunks>
|
|
28
|
+
<set>
|
|
29
|
+
<option value="bundled-js-predefined-d6986cc7102b-9c94529fcfe0-JavaScript-PY-252.26199.168" />
|
|
30
|
+
<option value="bundled-python-sdk-b3d66beaba9a-c6efb3732140-com.jetbrains.pycharm.pro.sharedIndexes.bundled-PY-252.26199.168" />
|
|
31
|
+
</set>
|
|
32
|
+
</attachedChunks>
|
|
33
|
+
</component>
|
|
34
|
+
<component name="TaskManager">
|
|
35
|
+
<task active="true" id="Default" summary="Default task">
|
|
36
|
+
<changelist id="3353231d-cbff-4250-b6f6-e702a244cb73" name="Changes" comment="" />
|
|
37
|
+
<created>1771872251986</created>
|
|
38
|
+
<option name="number" value="Default" />
|
|
39
|
+
<option name="presentableId" value="Default" />
|
|
40
|
+
<updated>1771872251986</updated>
|
|
41
|
+
<workItem from="1771872254661" duration="18000" />
|
|
42
|
+
</task>
|
|
43
|
+
<servers />
|
|
44
|
+
</component>
|
|
45
|
+
<component name="TypeScriptGeneratedFilesManager">
|
|
46
|
+
<option name="version" value="3" />
|
|
47
|
+
</component>
|
|
48
|
+
</project>
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from .memory_repo import MemoryRepository
|
|
2
|
+
from .mongo_repo import DataclassMapper, MongoRepository
|
|
3
|
+
from .sqlalchemy_repo import (
|
|
4
|
+
SqlAlchemyRepository,
|
|
5
|
+
SqlDataclassMapper,
|
|
6
|
+
build_table_from_dataclass,
|
|
7
|
+
get_engine,
|
|
8
|
+
)
|
|
9
|
+
|
|
10
|
+
__all__ = [
|
|
11
|
+
"MemoryRepository",
|
|
12
|
+
"MongoRepository",
|
|
13
|
+
"DataclassMapper",
|
|
14
|
+
"SqlAlchemyRepository",
|
|
15
|
+
"SqlDataclassMapper",
|
|
16
|
+
"build_table_from_dataclass",
|
|
17
|
+
"get_engine",
|
|
18
|
+
]
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from __future__ import annotations
|
|
2
|
+
|
|
3
|
+
from typing import Any, Iterable, Mapping
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
_SIMPLE_OPS = {"gte", "gt", "lte", "lt", "eq", "ne"}
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def is_multi_value(value: Any) -> bool:
|
|
10
|
+
return isinstance(value, list)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def is_range_dict(value: Any) -> bool:
|
|
14
|
+
return isinstance(value, dict)
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def iter_range_ops(value: Mapping[str, Any]) -> Iterable[tuple[str, Any]]:
|
|
18
|
+
if not value:
|
|
19
|
+
return []
|
|
20
|
+
items = list(value.items())
|
|
21
|
+
for op, v in items:
|
|
22
|
+
if op == "between":
|
|
23
|
+
if not isinstance(v, list) or len(v) != 2:
|
|
24
|
+
raise ValueError("between expects a list with exactly two values")
|
|
25
|
+
elif op == "in":
|
|
26
|
+
if not isinstance(v, list):
|
|
27
|
+
raise ValueError("in expects a list")
|
|
28
|
+
elif op in _SIMPLE_OPS:
|
|
29
|
+
continue
|
|
30
|
+
else:
|
|
31
|
+
raise ValueError(f"Unsupported operator: {op}")
|
|
32
|
+
return items
|