mongo-entity-orm 0.1.1__tar.gz → 0.1.2__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.
@@ -0,0 +1,261 @@
1
+ Metadata-Version: 2.3
2
+ Name: mongo-entity-orm
3
+ Version: 0.1.2
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.1"
7
+ version = "0.1.2"
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
- Config.MONGODB_URI(), tlsAllowInvalidCertificates=True
75
+ mongodb_uri, tlsAllowInvalidCertificates=True
66
76
  )
67
77
  self.async_mongo_client = AsyncIOMotorClient(
68
- Config.MONGODB_URI(), tls=True, tlsAllowInvalidCertificates=True
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(Config.MONGO_DATABASE_NAME())]
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()
@@ -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
@@ -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