mongo-entity-orm 0.1.1__tar.gz → 0.1.3__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.
- mongo_entity_orm-0.1.3/PKG-INFO +261 -0
- mongo_entity_orm-0.1.3/README.md +236 -0
- {mongo_entity_orm-0.1.1 → mongo_entity_orm-0.1.3}/pyproject.toml +4 -4
- {mongo_entity_orm-0.1.1 → mongo_entity_orm-0.1.3}/src/mongo_orm/core.py +31 -19
- mongo_entity_orm-0.1.1/PKG-INFO +0 -94
- mongo_entity_orm-0.1.1/README.md +0 -69
- {mongo_entity_orm-0.1.1 → mongo_entity_orm-0.1.3}/LICENSE +0 -0
- {mongo_entity_orm-0.1.1 → mongo_entity_orm-0.1.3}/src/mongo_orm/__init__.py +0 -0
- {mongo_entity_orm-0.1.1 → mongo_entity_orm-0.1.3}/src/mongo_orm/utils.py +0 -0
|
@@ -0,0 +1,261 @@
|
|
|
1
|
+
Metadata-Version: 2.3
|
|
2
|
+
Name: mongo-entity-orm
|
|
3
|
+
Version: 0.1.3
|
|
4
|
+
Summary: A MongoDB ORM for Python
|
|
5
|
+
License: MIT
|
|
6
|
+
Keywords: mongodb,orm,mongo,async
|
|
7
|
+
Author: Juraj Bezdek
|
|
8
|
+
Author-email: juraj.bezdek@gmail.com
|
|
9
|
+
Requires-Python: >=3.9,<4.0
|
|
10
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
+
Classifier: Operating System :: OS Independent
|
|
12
|
+
Classifier: Programming Language :: Python :: 3
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
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 :: Only
|
|
19
|
+
Requires-Dist: motor (>=3.7.1,<4.0.0)
|
|
20
|
+
Requires-Dist: pymongo (>=4.13.2,<5.0.0)
|
|
21
|
+
Project-URL: Documentation, https://github.com/ju-bezdek/mongo-orm#readme
|
|
22
|
+
Project-URL: Homepage, https://github.com/ju-bezdek/mongo-orm
|
|
23
|
+
Project-URL: Repository, https://github.com/ju-bezdek/mongo-orm
|
|
24
|
+
Description-Content-Type: text/markdown
|
|
25
|
+
|
|
26
|
+
# mongo-orm
|
|
27
|
+
|
|
28
|
+
A MongoDB ORM for Python
|
|
29
|
+
|
|
30
|
+
## Installation
|
|
31
|
+
|
|
32
|
+
```
|
|
33
|
+
pip install mongo-entity-orm
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
or
|
|
37
|
+
|
|
38
|
+
```
|
|
39
|
+
uv add mongo-entity-orm
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
## Configuration
|
|
43
|
+
|
|
44
|
+
Set the following environment variables before using the ORM:
|
|
45
|
+
|
|
46
|
+
| Variable | Description |
|
|
47
|
+
|---|---|
|
|
48
|
+
| `MONGODB_URI` | MongoDB connection string |
|
|
49
|
+
| `MONGO_DATABASE_NAME` | Name of the database |
|
|
50
|
+
|
|
51
|
+
## Usage
|
|
52
|
+
|
|
53
|
+
### Defining an Entity
|
|
54
|
+
|
|
55
|
+
Use the `@entity` decorator to map a class to a MongoDB collection. Your class should inherit from `BaseEntity`.
|
|
56
|
+
|
|
57
|
+
```python
|
|
58
|
+
from mongo_orm import BaseEntity, entity
|
|
59
|
+
|
|
60
|
+
@entity(collection_name="users")
|
|
61
|
+
class User(BaseEntity):
|
|
62
|
+
name: str
|
|
63
|
+
email: str
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Every entity automatically has an `id` field (UUID string) and a `tenant_id` field (defaults to `"-"`).
|
|
67
|
+
|
|
68
|
+
### CRUD Operations
|
|
69
|
+
|
|
70
|
+
All operations are available in both async (`a`-prefixed) and sync variants.
|
|
71
|
+
|
|
72
|
+
#### Get by ID
|
|
73
|
+
|
|
74
|
+
```python
|
|
75
|
+
# async
|
|
76
|
+
user = await User.aget(id=user_id, tenant_id=tenant_id)
|
|
77
|
+
|
|
78
|
+
# sync
|
|
79
|
+
user = User.get(id=user_id, tenant_id=tenant_id)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Pass `raise_not_found=True` to raise an exception instead of returning `None` when the entity is not found.
|
|
83
|
+
|
|
84
|
+
#### Save
|
|
85
|
+
|
|
86
|
+
```python
|
|
87
|
+
user = User(name="Alice", email="alice@example.com", tenant_id="acme")
|
|
88
|
+
|
|
89
|
+
# async
|
|
90
|
+
await user.asave()
|
|
91
|
+
|
|
92
|
+
# sync
|
|
93
|
+
user.save()
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
`save()` / `asave()` performs an upsert based on `id`, so it works for both creating and updating.
|
|
97
|
+
|
|
98
|
+
#### Update fields
|
|
99
|
+
|
|
100
|
+
```python
|
|
101
|
+
# Update in-memory only
|
|
102
|
+
user.update(name="Bob")
|
|
103
|
+
|
|
104
|
+
# Update and immediately save (async)
|
|
105
|
+
await user.aupdate(name="Bob", auto_save=True)
|
|
106
|
+
|
|
107
|
+
# Update and immediately save (sync)
|
|
108
|
+
user.update(name="Bob", auto_save=True)
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
#### Delete
|
|
112
|
+
|
|
113
|
+
```python
|
|
114
|
+
# Delete an entity instance
|
|
115
|
+
user.delete()
|
|
116
|
+
|
|
117
|
+
# Delete by ID
|
|
118
|
+
User.delete_by_id(id=user_id, tenant_id=tenant_id)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Pass `ignore_not_found=True` to suppress an exception when the entity does not exist.
|
|
122
|
+
|
|
123
|
+
### Querying
|
|
124
|
+
|
|
125
|
+
#### Find (filter)
|
|
126
|
+
|
|
127
|
+
`filter` accepts a standard MongoDB query dict.
|
|
128
|
+
|
|
129
|
+
```python
|
|
130
|
+
# async
|
|
131
|
+
users = await User.afind(tenant_id=tenant_id, filter={"name": "Alice"})
|
|
132
|
+
|
|
133
|
+
# sync
|
|
134
|
+
users = User.find(tenant_id=tenant_id, filter={"name": "Alice"})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
MongoDB operators work as expected:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
users = await User.afind(
|
|
141
|
+
tenant_id=tenant_id,
|
|
142
|
+
filter={"name": {"$in": ["Alice", "Bob"]}, "email": {"$regex": "@example.com$"}},
|
|
143
|
+
)
|
|
144
|
+
```
|
|
145
|
+
|
|
146
|
+
Use `tenant_id="*"` to query across all tenants.
|
|
147
|
+
|
|
148
|
+
#### Pagination
|
|
149
|
+
|
|
150
|
+
```python
|
|
151
|
+
users = await User.afind(tenant_id=tenant_id, filter={}, skip=0, limit=20)
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
#### Sorting
|
|
155
|
+
|
|
156
|
+
```python
|
|
157
|
+
# Ascending
|
|
158
|
+
users = await User.afind(tenant_id=tenant_id, order_by="name")
|
|
159
|
+
|
|
160
|
+
# Descending (prefix with "-")
|
|
161
|
+
users = await User.afind(tenant_id=tenant_id, order_by="-name")
|
|
162
|
+
|
|
163
|
+
# Multiple sort fields
|
|
164
|
+
users = await User.afind(tenant_id=tenant_id, order_by=["-created_at", "name"])
|
|
165
|
+
```
|
|
166
|
+
|
|
167
|
+
#### Find first
|
|
168
|
+
|
|
169
|
+
```python
|
|
170
|
+
user = await User.afind_first(tenant_id=tenant_id, filter={"email": "alice@example.com"})
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
Returns `None` if no match is found.
|
|
174
|
+
|
|
175
|
+
#### Count
|
|
176
|
+
|
|
177
|
+
```python
|
|
178
|
+
# async
|
|
179
|
+
total = await User.acount(tenant_id=tenant_id, filter={"name": "Alice"})
|
|
180
|
+
|
|
181
|
+
# sync
|
|
182
|
+
total = User.count(tenant_id=tenant_id, filter={"name": "Alice"})
|
|
183
|
+
```
|
|
184
|
+
|
|
185
|
+
#### Scroll pages (batch iteration)
|
|
186
|
+
|
|
187
|
+
```python
|
|
188
|
+
# async
|
|
189
|
+
async for page in User.ascroll_pages(tenant_id=tenant_id, page_size=50):
|
|
190
|
+
for user in page:
|
|
191
|
+
...
|
|
192
|
+
|
|
193
|
+
# sync
|
|
194
|
+
for page in User.scroll_pages(tenant_id=tenant_id, page_size=50):
|
|
195
|
+
for user in page:
|
|
196
|
+
...
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
#### Bulk save
|
|
200
|
+
|
|
201
|
+
```python
|
|
202
|
+
await User.bulk_save([user1, user2, user3])
|
|
203
|
+
```
|
|
204
|
+
|
|
205
|
+
### Index Management
|
|
206
|
+
|
|
207
|
+
Define indexes on the entity class using `__indexes__`:
|
|
208
|
+
|
|
209
|
+
```python
|
|
210
|
+
@entity(collection_name="users")
|
|
211
|
+
class User(BaseEntity):
|
|
212
|
+
name: str
|
|
213
|
+
email: str
|
|
214
|
+
|
|
215
|
+
__indexes__ = [
|
|
216
|
+
{"keys": [("email", 1)], "unique": True},
|
|
217
|
+
{"keys": [("name", 1)]},
|
|
218
|
+
{"keys": [("tenant_id", 1), ("name", 1)]},
|
|
219
|
+
]
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
Index management is controlled by the `MONGODB_INDEX_AUTOAPPLY` environment variable:
|
|
223
|
+
|
|
224
|
+
| Value | Behaviour |
|
|
225
|
+
|---|---|
|
|
226
|
+
| `never` (default) | No automatic index management |
|
|
227
|
+
| `always` | Checks and applies indexes on every startup |
|
|
228
|
+
| `auto-lock` | Applies indexes once; writes a hash to `mongo-orm.lock` and skips on subsequent startups |
|
|
229
|
+
|
|
230
|
+
#### Manual application
|
|
231
|
+
|
|
232
|
+
```python
|
|
233
|
+
from mongo_orm.utils import apply_all_indexes
|
|
234
|
+
|
|
235
|
+
# Respects MONGODB_INDEX_AUTOAPPLY
|
|
236
|
+
apply_all_indexes()
|
|
237
|
+
|
|
238
|
+
# Force a specific mode
|
|
239
|
+
apply_all_indexes(mode="always")
|
|
240
|
+
```
|
|
241
|
+
|
|
242
|
+
## Development
|
|
243
|
+
|
|
244
|
+
```bash
|
|
245
|
+
# Install dependencies
|
|
246
|
+
poetry install
|
|
247
|
+
|
|
248
|
+
# Run tests
|
|
249
|
+
poetry run pytest
|
|
250
|
+
|
|
251
|
+
# Format code
|
|
252
|
+
poetry run black .
|
|
253
|
+
poetry run isort .
|
|
254
|
+
|
|
255
|
+
# Type checking
|
|
256
|
+
poetry run mypy src/
|
|
257
|
+
```
|
|
258
|
+
|
|
259
|
+
## License
|
|
260
|
+
|
|
261
|
+
MIT
|
|
@@ -0,0 +1,236 @@
|
|
|
1
|
+
# mongo-orm
|
|
2
|
+
|
|
3
|
+
A MongoDB ORM for Python
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
pip install mongo-entity-orm
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
or
|
|
12
|
+
|
|
13
|
+
```
|
|
14
|
+
uv add mongo-entity-orm
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Configuration
|
|
18
|
+
|
|
19
|
+
Set the following environment variables before using the ORM:
|
|
20
|
+
|
|
21
|
+
| Variable | Description |
|
|
22
|
+
|---|---|
|
|
23
|
+
| `MONGODB_URI` | MongoDB connection string |
|
|
24
|
+
| `MONGO_DATABASE_NAME` | Name of the database |
|
|
25
|
+
|
|
26
|
+
## Usage
|
|
27
|
+
|
|
28
|
+
### Defining an Entity
|
|
29
|
+
|
|
30
|
+
Use the `@entity` decorator to map a class to a MongoDB collection. Your class should inherit from `BaseEntity`.
|
|
31
|
+
|
|
32
|
+
```python
|
|
33
|
+
from mongo_orm import BaseEntity, entity
|
|
34
|
+
|
|
35
|
+
@entity(collection_name="users")
|
|
36
|
+
class User(BaseEntity):
|
|
37
|
+
name: str
|
|
38
|
+
email: str
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Every entity automatically has an `id` field (UUID string) and a `tenant_id` field (defaults to `"-"`).
|
|
42
|
+
|
|
43
|
+
### CRUD Operations
|
|
44
|
+
|
|
45
|
+
All operations are available in both async (`a`-prefixed) and sync variants.
|
|
46
|
+
|
|
47
|
+
#### Get by ID
|
|
48
|
+
|
|
49
|
+
```python
|
|
50
|
+
# async
|
|
51
|
+
user = await User.aget(id=user_id, tenant_id=tenant_id)
|
|
52
|
+
|
|
53
|
+
# sync
|
|
54
|
+
user = User.get(id=user_id, tenant_id=tenant_id)
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
Pass `raise_not_found=True` to raise an exception instead of returning `None` when the entity is not found.
|
|
58
|
+
|
|
59
|
+
#### Save
|
|
60
|
+
|
|
61
|
+
```python
|
|
62
|
+
user = User(name="Alice", email="alice@example.com", tenant_id="acme")
|
|
63
|
+
|
|
64
|
+
# async
|
|
65
|
+
await user.asave()
|
|
66
|
+
|
|
67
|
+
# sync
|
|
68
|
+
user.save()
|
|
69
|
+
```
|
|
70
|
+
|
|
71
|
+
`save()` / `asave()` performs an upsert based on `id`, so it works for both creating and updating.
|
|
72
|
+
|
|
73
|
+
#### Update fields
|
|
74
|
+
|
|
75
|
+
```python
|
|
76
|
+
# Update in-memory only
|
|
77
|
+
user.update(name="Bob")
|
|
78
|
+
|
|
79
|
+
# Update and immediately save (async)
|
|
80
|
+
await user.aupdate(name="Bob", auto_save=True)
|
|
81
|
+
|
|
82
|
+
# Update and immediately save (sync)
|
|
83
|
+
user.update(name="Bob", auto_save=True)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
#### Delete
|
|
87
|
+
|
|
88
|
+
```python
|
|
89
|
+
# Delete an entity instance
|
|
90
|
+
user.delete()
|
|
91
|
+
|
|
92
|
+
# Delete by ID
|
|
93
|
+
User.delete_by_id(id=user_id, tenant_id=tenant_id)
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
Pass `ignore_not_found=True` to suppress an exception when the entity does not exist.
|
|
97
|
+
|
|
98
|
+
### Querying
|
|
99
|
+
|
|
100
|
+
#### Find (filter)
|
|
101
|
+
|
|
102
|
+
`filter` accepts a standard MongoDB query dict.
|
|
103
|
+
|
|
104
|
+
```python
|
|
105
|
+
# async
|
|
106
|
+
users = await User.afind(tenant_id=tenant_id, filter={"name": "Alice"})
|
|
107
|
+
|
|
108
|
+
# sync
|
|
109
|
+
users = User.find(tenant_id=tenant_id, filter={"name": "Alice"})
|
|
110
|
+
```
|
|
111
|
+
|
|
112
|
+
MongoDB operators work as expected:
|
|
113
|
+
|
|
114
|
+
```python
|
|
115
|
+
users = await User.afind(
|
|
116
|
+
tenant_id=tenant_id,
|
|
117
|
+
filter={"name": {"$in": ["Alice", "Bob"]}, "email": {"$regex": "@example.com$"}},
|
|
118
|
+
)
|
|
119
|
+
```
|
|
120
|
+
|
|
121
|
+
Use `tenant_id="*"` to query across all tenants.
|
|
122
|
+
|
|
123
|
+
#### Pagination
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
users = await User.afind(tenant_id=tenant_id, filter={}, skip=0, limit=20)
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
#### Sorting
|
|
130
|
+
|
|
131
|
+
```python
|
|
132
|
+
# Ascending
|
|
133
|
+
users = await User.afind(tenant_id=tenant_id, order_by="name")
|
|
134
|
+
|
|
135
|
+
# Descending (prefix with "-")
|
|
136
|
+
users = await User.afind(tenant_id=tenant_id, order_by="-name")
|
|
137
|
+
|
|
138
|
+
# Multiple sort fields
|
|
139
|
+
users = await User.afind(tenant_id=tenant_id, order_by=["-created_at", "name"])
|
|
140
|
+
```
|
|
141
|
+
|
|
142
|
+
#### Find first
|
|
143
|
+
|
|
144
|
+
```python
|
|
145
|
+
user = await User.afind_first(tenant_id=tenant_id, filter={"email": "alice@example.com"})
|
|
146
|
+
```
|
|
147
|
+
|
|
148
|
+
Returns `None` if no match is found.
|
|
149
|
+
|
|
150
|
+
#### Count
|
|
151
|
+
|
|
152
|
+
```python
|
|
153
|
+
# async
|
|
154
|
+
total = await User.acount(tenant_id=tenant_id, filter={"name": "Alice"})
|
|
155
|
+
|
|
156
|
+
# sync
|
|
157
|
+
total = User.count(tenant_id=tenant_id, filter={"name": "Alice"})
|
|
158
|
+
```
|
|
159
|
+
|
|
160
|
+
#### Scroll pages (batch iteration)
|
|
161
|
+
|
|
162
|
+
```python
|
|
163
|
+
# async
|
|
164
|
+
async for page in User.ascroll_pages(tenant_id=tenant_id, page_size=50):
|
|
165
|
+
for user in page:
|
|
166
|
+
...
|
|
167
|
+
|
|
168
|
+
# sync
|
|
169
|
+
for page in User.scroll_pages(tenant_id=tenant_id, page_size=50):
|
|
170
|
+
for user in page:
|
|
171
|
+
...
|
|
172
|
+
```
|
|
173
|
+
|
|
174
|
+
#### Bulk save
|
|
175
|
+
|
|
176
|
+
```python
|
|
177
|
+
await User.bulk_save([user1, user2, user3])
|
|
178
|
+
```
|
|
179
|
+
|
|
180
|
+
### Index Management
|
|
181
|
+
|
|
182
|
+
Define indexes on the entity class using `__indexes__`:
|
|
183
|
+
|
|
184
|
+
```python
|
|
185
|
+
@entity(collection_name="users")
|
|
186
|
+
class User(BaseEntity):
|
|
187
|
+
name: str
|
|
188
|
+
email: str
|
|
189
|
+
|
|
190
|
+
__indexes__ = [
|
|
191
|
+
{"keys": [("email", 1)], "unique": True},
|
|
192
|
+
{"keys": [("name", 1)]},
|
|
193
|
+
{"keys": [("tenant_id", 1), ("name", 1)]},
|
|
194
|
+
]
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
Index management is controlled by the `MONGODB_INDEX_AUTOAPPLY` environment variable:
|
|
198
|
+
|
|
199
|
+
| Value | Behaviour |
|
|
200
|
+
|---|---|
|
|
201
|
+
| `never` (default) | No automatic index management |
|
|
202
|
+
| `always` | Checks and applies indexes on every startup |
|
|
203
|
+
| `auto-lock` | Applies indexes once; writes a hash to `mongo-orm.lock` and skips on subsequent startups |
|
|
204
|
+
|
|
205
|
+
#### Manual application
|
|
206
|
+
|
|
207
|
+
```python
|
|
208
|
+
from mongo_orm.utils import apply_all_indexes
|
|
209
|
+
|
|
210
|
+
# Respects MONGODB_INDEX_AUTOAPPLY
|
|
211
|
+
apply_all_indexes()
|
|
212
|
+
|
|
213
|
+
# Force a specific mode
|
|
214
|
+
apply_all_indexes(mode="always")
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Development
|
|
218
|
+
|
|
219
|
+
```bash
|
|
220
|
+
# Install dependencies
|
|
221
|
+
poetry install
|
|
222
|
+
|
|
223
|
+
# Run tests
|
|
224
|
+
poetry run pytest
|
|
225
|
+
|
|
226
|
+
# Format code
|
|
227
|
+
poetry run black .
|
|
228
|
+
poetry run isort .
|
|
229
|
+
|
|
230
|
+
# Type checking
|
|
231
|
+
poetry run mypy src/
|
|
232
|
+
```
|
|
233
|
+
|
|
234
|
+
## License
|
|
235
|
+
|
|
236
|
+
MIT
|
|
@@ -4,7 +4,7 @@ build-backend = "poetry.core.masonry.api"
|
|
|
4
4
|
|
|
5
5
|
[tool.poetry]
|
|
6
6
|
name = "mongo-entity-orm"
|
|
7
|
-
version = "0.1.
|
|
7
|
+
version = "0.1.3"
|
|
8
8
|
description = "A MongoDB ORM for Python"
|
|
9
9
|
readme = "README.md"
|
|
10
10
|
authors = ["Juraj Bezdek <juraj.bezdek@gmail.com>"]
|
|
@@ -12,7 +12,7 @@ license = "MIT"
|
|
|
12
12
|
packages = [{include = "mongo_orm", from = "src"}]
|
|
13
13
|
keywords = ["mongodb", "orm", "mongo", "async"]
|
|
14
14
|
homepage = "https://github.com/ju-bezdek/mongo-orm"
|
|
15
|
-
repository = "https://github.com/ju-bezdek/mongo"
|
|
15
|
+
repository = "https://github.com/ju-bezdek/mongo-orm"
|
|
16
16
|
|
|
17
17
|
classifiers = [
|
|
18
18
|
"Programming Language :: Python :: 3",
|
|
@@ -25,8 +25,8 @@ classifiers = [
|
|
|
25
25
|
]
|
|
26
26
|
|
|
27
27
|
[tool.poetry.urls]
|
|
28
|
-
Repository = "https://github.com/ju-bezdek/mongo"
|
|
29
|
-
Documentation = "https://github.com/ju-bezdek/mongo#readme"
|
|
28
|
+
Repository = "https://github.com/ju-bezdek/mongo-orm"
|
|
29
|
+
Documentation = "https://github.com/ju-bezdek/mongo-orm#readme"
|
|
30
30
|
|
|
31
31
|
[tool.poetry.dependencies]
|
|
32
32
|
python = ">=3.9,<4.0"
|
|
@@ -60,18 +60,26 @@ class Repository:
|
|
|
60
60
|
if mongo_db:
|
|
61
61
|
self.mongo_db = mongo_db
|
|
62
62
|
else:
|
|
63
|
+
mongodb_uri = Config.MONGODB_URI()
|
|
64
|
+
mongo_db_name = Config.MONGO_DATABASE_NAME()
|
|
65
|
+
if not mongodb_uri and not mongo_db_name:
|
|
66
|
+
raise ValueError(
|
|
67
|
+
"MONGODB_URI and MONGO_DATABASE_NAME environment variables are not set"
|
|
68
|
+
)
|
|
69
|
+
if not mongodb_uri:
|
|
70
|
+
raise ValueError("MONGODB_URI environment variable is not set")
|
|
71
|
+
if not mongo_db_name:
|
|
72
|
+
raise ValueError("MONGO_DATABASE_NAME environment variable is not set")
|
|
63
73
|
|
|
64
74
|
self.mongo_client = MongoClient(
|
|
65
|
-
|
|
75
|
+
mongodb_uri, tlsAllowInvalidCertificates=True
|
|
66
76
|
)
|
|
67
77
|
self.async_mongo_client = AsyncIOMotorClient(
|
|
68
|
-
|
|
78
|
+
mongodb_uri, tls=True, tlsAllowInvalidCertificates=True
|
|
69
79
|
)
|
|
70
80
|
self.mongo_client.admin.command("ping")
|
|
71
|
-
self.mongo_db = self.mongo_client[str(
|
|
72
|
-
self.async_mongo_db = self.async_mongo_client[
|
|
73
|
-
str(Config.MONGO_DATABASE_NAME())
|
|
74
|
-
]
|
|
81
|
+
self.mongo_db = self.mongo_client[str(mongo_db_name)]
|
|
82
|
+
self.async_mongo_db = self.async_mongo_client[str(mongo_db_name)]
|
|
75
83
|
|
|
76
84
|
|
|
77
85
|
REPOSITORY = Repository()
|
|
@@ -301,7 +309,7 @@ class BaseEntity(BaseModel):
|
|
|
301
309
|
)
|
|
302
310
|
|
|
303
311
|
@classmethod
|
|
304
|
-
def delete_by_id(cls, id, tenant_id: str):
|
|
312
|
+
def delete_by_id(cls, id, tenant_id: str = "*") -> bool:
|
|
305
313
|
|
|
306
314
|
filter = {"_id": id}
|
|
307
315
|
if tenant_id != "*":
|
|
@@ -313,7 +321,7 @@ class BaseEntity(BaseModel):
|
|
|
313
321
|
def get(
|
|
314
322
|
cls: Type[T],
|
|
315
323
|
id: str,
|
|
316
|
-
tenant_id: str,
|
|
324
|
+
tenant_id: str = "*",
|
|
317
325
|
namespace: str = None,
|
|
318
326
|
raise_not_found: bool = False,
|
|
319
327
|
) -> T | None:
|
|
@@ -334,7 +342,7 @@ class BaseEntity(BaseModel):
|
|
|
334
342
|
async def aget(
|
|
335
343
|
cls: Type[T],
|
|
336
344
|
id: str,
|
|
337
|
-
tenant_id: str,
|
|
345
|
+
tenant_id: str = "*",
|
|
338
346
|
namespace: str = None,
|
|
339
347
|
raise_not_found: bool = False,
|
|
340
348
|
) -> T | None:
|
|
@@ -370,7 +378,7 @@ class BaseEntity(BaseModel):
|
|
|
370
378
|
return entity
|
|
371
379
|
|
|
372
380
|
@classmethod
|
|
373
|
-
def count(cls, tenant_id: str, filter: dict = None, limit=None) -> int:
|
|
381
|
+
def count(cls, tenant_id: str = "*", filter: dict = None, limit=None) -> int:
|
|
374
382
|
|
|
375
383
|
if not filter:
|
|
376
384
|
_filter = {}
|
|
@@ -386,7 +394,7 @@ class BaseEntity(BaseModel):
|
|
|
386
394
|
return cls.collection.count_documents(_filter, **extra)
|
|
387
395
|
|
|
388
396
|
@classmethod
|
|
389
|
-
async def acount(cls, tenant_id: str, filter: dict = None, limit=None) -> int:
|
|
397
|
+
async def acount(cls, tenant_id: str = "*", filter: dict = None, limit=None) -> int:
|
|
390
398
|
|
|
391
399
|
if not filter:
|
|
392
400
|
_filter = {}
|
|
@@ -404,7 +412,7 @@ class BaseEntity(BaseModel):
|
|
|
404
412
|
@classmethod
|
|
405
413
|
async def afind(
|
|
406
414
|
cls: Type[T],
|
|
407
|
-
tenant_id: str,
|
|
415
|
+
tenant_id: str = "*",
|
|
408
416
|
namespace: str = None,
|
|
409
417
|
skip: int = 0,
|
|
410
418
|
limit: int = 100,
|
|
@@ -414,8 +422,10 @@ class BaseEntity(BaseModel):
|
|
|
414
422
|
) -> List[T]:
|
|
415
423
|
if not filter:
|
|
416
424
|
filter = {}
|
|
425
|
+
else:
|
|
426
|
+
filter = {**filter}
|
|
417
427
|
if tenant_id != "*":
|
|
418
|
-
filter.update({"tenant_id": tenant_id
|
|
428
|
+
filter.update({"tenant_id": tenant_id})
|
|
419
429
|
|
|
420
430
|
filter.update(additional_filters)
|
|
421
431
|
if "id" in filter:
|
|
@@ -446,7 +456,7 @@ class BaseEntity(BaseModel):
|
|
|
446
456
|
@classmethod
|
|
447
457
|
def scroll_pages(
|
|
448
458
|
cls: Type[T],
|
|
449
|
-
tenant_id: str,
|
|
459
|
+
tenant_id: str = "*",
|
|
450
460
|
filter: dict = None,
|
|
451
461
|
order_by: str = None,
|
|
452
462
|
page_size: int = 100,
|
|
@@ -468,7 +478,7 @@ class BaseEntity(BaseModel):
|
|
|
468
478
|
@classmethod
|
|
469
479
|
async def ascroll_pages(
|
|
470
480
|
cls: Type[T],
|
|
471
|
-
tenant_id: str,
|
|
481
|
+
tenant_id: str = "*",
|
|
472
482
|
filter: dict = None,
|
|
473
483
|
order_by: str = None,
|
|
474
484
|
page_size: int = 100,
|
|
@@ -490,7 +500,7 @@ class BaseEntity(BaseModel):
|
|
|
490
500
|
@classmethod
|
|
491
501
|
def find(
|
|
492
502
|
cls: Type[T],
|
|
493
|
-
tenant_id: str,
|
|
503
|
+
tenant_id: str = "*",
|
|
494
504
|
namespace: str = None,
|
|
495
505
|
skip: int = 0,
|
|
496
506
|
limit: int | None = 100,
|
|
@@ -503,7 +513,7 @@ class BaseEntity(BaseModel):
|
|
|
503
513
|
else:
|
|
504
514
|
filter = {**filter}
|
|
505
515
|
if tenant_id != "*":
|
|
506
|
-
filter.update({"tenant_id": tenant_id
|
|
516
|
+
filter.update({"tenant_id": tenant_id})
|
|
507
517
|
|
|
508
518
|
filter.update(additional_filters)
|
|
509
519
|
if "id" in filter:
|
|
@@ -536,13 +546,15 @@ class BaseEntity(BaseModel):
|
|
|
536
546
|
return res
|
|
537
547
|
|
|
538
548
|
@classmethod
|
|
539
|
-
def find_first(cls, tenant_id, filter=None, order_by=None, **kwargs):
|
|
549
|
+
def find_first(cls, tenant_id: str = "*", filter=None, order_by=None, **kwargs):
|
|
540
550
|
kwargs.pop("limit", None)
|
|
541
551
|
items = cls.find(tenant_id, filter=filter, order_by=order_by, limit=1, **kwargs)
|
|
542
552
|
return items[0] if items else None
|
|
543
553
|
|
|
544
554
|
@classmethod
|
|
545
|
-
async def afind_first(
|
|
555
|
+
async def afind_first(
|
|
556
|
+
cls, tenant_id: str = "*", filter=None, order_by=None, **kwargs
|
|
557
|
+
):
|
|
546
558
|
items = await cls.afind(
|
|
547
559
|
tenant_id, filter=filter, order_by=order_by, limit=1, **kwargs
|
|
548
560
|
)
|
mongo_entity_orm-0.1.1/PKG-INFO
DELETED
|
@@ -1,94 +0,0 @@
|
|
|
1
|
-
Metadata-Version: 2.3
|
|
2
|
-
Name: mongo-entity-orm
|
|
3
|
-
Version: 0.1.1
|
|
4
|
-
Summary: A MongoDB ORM for Python
|
|
5
|
-
License: MIT
|
|
6
|
-
Keywords: mongodb,orm,mongo,async
|
|
7
|
-
Author: Juraj Bezdek
|
|
8
|
-
Author-email: juraj.bezdek@gmail.com
|
|
9
|
-
Requires-Python: >=3.9,<4.0
|
|
10
|
-
Classifier: License :: OSI Approved :: MIT License
|
|
11
|
-
Classifier: Operating System :: OS Independent
|
|
12
|
-
Classifier: Programming Language :: Python :: 3
|
|
13
|
-
Classifier: Programming Language :: Python :: 3.9
|
|
14
|
-
Classifier: Programming Language :: Python :: 3.10
|
|
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 :: Only
|
|
19
|
-
Requires-Dist: motor (>=3.7.1,<4.0.0)
|
|
20
|
-
Requires-Dist: pymongo (>=4.13.2,<5.0.0)
|
|
21
|
-
Project-URL: Documentation, https://github.com/ju-bezdek/mongo#readme
|
|
22
|
-
Project-URL: Homepage, https://github.com/ju-bezdek/mongo-orm
|
|
23
|
-
Project-URL: Repository, https://github.com/ju-bezdek/mongo
|
|
24
|
-
Description-Content-Type: text/markdown
|
|
25
|
-
|
|
26
|
-
# mongo-orm
|
|
27
|
-
|
|
28
|
-
A MongoDB ORM for Python
|
|
29
|
-
|
|
30
|
-
## Usage
|
|
31
|
-
|
|
32
|
-
### Defining an Entity
|
|
33
|
-
|
|
34
|
-
Use the `@entity` decorator to map a class to a MongoDB collection. Your class should inherit from `BaseEntity`.
|
|
35
|
-
|
|
36
|
-
```python
|
|
37
|
-
from mongo_orm import BaseEntity, entity
|
|
38
|
-
|
|
39
|
-
@entity("users")
|
|
40
|
-
class User(BaseEntity):
|
|
41
|
-
name: str
|
|
42
|
-
email: str
|
|
43
|
-
|
|
44
|
-
# Define indexes
|
|
45
|
-
__indexes__ = [
|
|
46
|
-
{"keys": [("email", 1)], "unique": True},
|
|
47
|
-
{"keys": [("name", 1)]}
|
|
48
|
-
]
|
|
49
|
-
```
|
|
50
|
-
|
|
51
|
-
### Index Management
|
|
52
|
-
|
|
53
|
-
The ORM can automatically manage your MongoDB indexes based on the `__indexes__` attribute. This behavior is controlled by the `MONGODB_INDEX_AUTOAPPLY` environment variable.
|
|
54
|
-
|
|
55
|
-
#### Configuration (`MONGODB_INDEX_AUTOAPPLY`)
|
|
56
|
-
|
|
57
|
-
- `never` (default): No automatic index management.
|
|
58
|
-
- `always`: Checks and applies indexes every time an entity class is initialized (on startup).
|
|
59
|
-
- `auto-lock`: Checks and applies indexes once. After a successful check, it writes a hash of the index to `mongo-orm.lock`. Subsequent startups will skip the check if the hash is present in the lock file.
|
|
60
|
-
|
|
61
|
-
#### Manual Index Application
|
|
62
|
-
|
|
63
|
-
You can also trigger index application manually for all registered entities:
|
|
64
|
-
|
|
65
|
-
```python
|
|
66
|
-
from mongo_orm.utils import apply_all_indexes
|
|
67
|
-
|
|
68
|
-
# Apply indexes using the current environment configuration
|
|
69
|
-
apply_all_indexes()
|
|
70
|
-
|
|
71
|
-
# Or force a specific mode
|
|
72
|
-
apply_all_indexes(mode="always")
|
|
73
|
-
```
|
|
74
|
-
|
|
75
|
-
## Development
|
|
76
|
-
|
|
77
|
-
```bash
|
|
78
|
-
# Install dependencies
|
|
79
|
-
poetry install
|
|
80
|
-
|
|
81
|
-
# Run tests
|
|
82
|
-
poetry run pytest
|
|
83
|
-
|
|
84
|
-
# Format code
|
|
85
|
-
poetry run black .
|
|
86
|
-
poetry run isort .
|
|
87
|
-
|
|
88
|
-
# Type checking
|
|
89
|
-
poetry run mypy src/
|
|
90
|
-
```
|
|
91
|
-
|
|
92
|
-
## License
|
|
93
|
-
|
|
94
|
-
MIT
|
mongo_entity_orm-0.1.1/README.md
DELETED
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
# mongo-orm
|
|
2
|
-
|
|
3
|
-
A MongoDB ORM for Python
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
### Defining an Entity
|
|
8
|
-
|
|
9
|
-
Use the `@entity` decorator to map a class to a MongoDB collection. Your class should inherit from `BaseEntity`.
|
|
10
|
-
|
|
11
|
-
```python
|
|
12
|
-
from mongo_orm import BaseEntity, entity
|
|
13
|
-
|
|
14
|
-
@entity("users")
|
|
15
|
-
class User(BaseEntity):
|
|
16
|
-
name: str
|
|
17
|
-
email: str
|
|
18
|
-
|
|
19
|
-
# Define indexes
|
|
20
|
-
__indexes__ = [
|
|
21
|
-
{"keys": [("email", 1)], "unique": True},
|
|
22
|
-
{"keys": [("name", 1)]}
|
|
23
|
-
]
|
|
24
|
-
```
|
|
25
|
-
|
|
26
|
-
### Index Management
|
|
27
|
-
|
|
28
|
-
The ORM can automatically manage your MongoDB indexes based on the `__indexes__` attribute. This behavior is controlled by the `MONGODB_INDEX_AUTOAPPLY` environment variable.
|
|
29
|
-
|
|
30
|
-
#### Configuration (`MONGODB_INDEX_AUTOAPPLY`)
|
|
31
|
-
|
|
32
|
-
- `never` (default): No automatic index management.
|
|
33
|
-
- `always`: Checks and applies indexes every time an entity class is initialized (on startup).
|
|
34
|
-
- `auto-lock`: Checks and applies indexes once. After a successful check, it writes a hash of the index to `mongo-orm.lock`. Subsequent startups will skip the check if the hash is present in the lock file.
|
|
35
|
-
|
|
36
|
-
#### Manual Index Application
|
|
37
|
-
|
|
38
|
-
You can also trigger index application manually for all registered entities:
|
|
39
|
-
|
|
40
|
-
```python
|
|
41
|
-
from mongo_orm.utils import apply_all_indexes
|
|
42
|
-
|
|
43
|
-
# Apply indexes using the current environment configuration
|
|
44
|
-
apply_all_indexes()
|
|
45
|
-
|
|
46
|
-
# Or force a specific mode
|
|
47
|
-
apply_all_indexes(mode="always")
|
|
48
|
-
```
|
|
49
|
-
|
|
50
|
-
## Development
|
|
51
|
-
|
|
52
|
-
```bash
|
|
53
|
-
# Install dependencies
|
|
54
|
-
poetry install
|
|
55
|
-
|
|
56
|
-
# Run tests
|
|
57
|
-
poetry run pytest
|
|
58
|
-
|
|
59
|
-
# Format code
|
|
60
|
-
poetry run black .
|
|
61
|
-
poetry run isort .
|
|
62
|
-
|
|
63
|
-
# Type checking
|
|
64
|
-
poetry run mypy src/
|
|
65
|
-
```
|
|
66
|
-
|
|
67
|
-
## License
|
|
68
|
-
|
|
69
|
-
MIT
|
|
File without changes
|
|
File without changes
|
|
File without changes
|