panther 3.8.2__py3-none-any.whl → 4.0.0__py3-none-any.whl
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.
- panther/__init__.py +1 -1
- panther/_load_configs.py +168 -171
- panther/_utils.py +26 -49
- panther/app.py +85 -105
- panther/authentications.py +86 -55
- panther/background_tasks.py +25 -14
- panther/base_request.py +38 -14
- panther/base_websocket.py +172 -94
- panther/caching.py +60 -25
- panther/cli/create_command.py +20 -10
- panther/cli/monitor_command.py +63 -37
- panther/cli/template.py +40 -20
- panther/cli/utils.py +32 -18
- panther/configs.py +65 -58
- panther/db/connections.py +139 -0
- panther/db/cursor.py +43 -0
- panther/db/models.py +64 -29
- panther/db/queries/__init__.py +1 -1
- panther/db/queries/base_queries.py +127 -0
- panther/db/queries/mongodb_queries.py +77 -38
- panther/db/queries/pantherdb_queries.py +59 -30
- panther/db/queries/queries.py +232 -117
- panther/db/utils.py +17 -18
- panther/events.py +44 -0
- panther/exceptions.py +26 -12
- panther/file_handler.py +2 -2
- panther/generics.py +163 -0
- panther/logging.py +7 -2
- panther/main.py +111 -188
- panther/middlewares/base.py +3 -0
- panther/monitoring.py +8 -5
- panther/pagination.py +48 -0
- panther/panel/apis.py +32 -5
- panther/panel/urls.py +2 -1
- panther/permissions.py +3 -3
- panther/request.py +6 -13
- panther/response.py +114 -34
- panther/routings.py +83 -66
- panther/serializer.py +214 -33
- panther/test.py +31 -21
- panther/utils.py +28 -16
- panther/websocket.py +7 -4
- {panther-3.8.2.dist-info → panther-4.0.0.dist-info}/METADATA +93 -71
- panther-4.0.0.dist-info/RECORD +57 -0
- {panther-3.8.2.dist-info → panther-4.0.0.dist-info}/WHEEL +1 -1
- panther/db/connection.py +0 -92
- panther/middlewares/db.py +0 -18
- panther/middlewares/redis.py +0 -47
- panther-3.8.2.dist-info/RECORD +0 -54
- {panther-3.8.2.dist-info → panther-4.0.0.dist-info}/LICENSE +0 -0
- {panther-3.8.2.dist-info → panther-4.0.0.dist-info}/entry_points.txt +0 -0
- {panther-3.8.2.dist-info → panther-4.0.0.dist-info}/top_level.txt +0 -0
@@ -1,7 +1,12 @@
|
|
1
1
|
from sys import version_info
|
2
|
+
from typing import Iterable
|
2
3
|
|
3
|
-
from
|
4
|
-
|
4
|
+
from pantherdb import Cursor
|
5
|
+
|
6
|
+
from panther.db.connections import db
|
7
|
+
from panther.db.queries.base_queries import BaseQuery
|
8
|
+
from panther.db.utils import prepare_id_for_query
|
9
|
+
from panther.exceptions import DatabaseError
|
5
10
|
|
6
11
|
if version_info >= (3, 11):
|
7
12
|
from typing import Self
|
@@ -11,71 +16,95 @@ else:
|
|
11
16
|
Self = TypeVar('Self', bound='BasePantherDBQuery')
|
12
17
|
|
13
18
|
|
14
|
-
class BasePantherDBQuery:
|
19
|
+
class BasePantherDBQuery(BaseQuery):
|
15
20
|
@classmethod
|
16
|
-
def _merge(cls, *args) -> dict:
|
17
|
-
|
18
|
-
return merge_dicts(*args)
|
21
|
+
def _merge(cls, *args, is_mongo: bool = False) -> dict:
|
22
|
+
return super()._merge(*args, is_mongo=is_mongo)
|
19
23
|
|
20
24
|
# # # # # Find # # # # #
|
21
25
|
@classmethod
|
22
|
-
def find_one(cls,
|
23
|
-
if document := db.session.collection(cls.__name__).find_one(**cls._merge(
|
26
|
+
async def find_one(cls, _filter: dict | None = None, /, **kwargs) -> Self | None:
|
27
|
+
if document := db.session.collection(cls.__name__).find_one(**cls._merge(_filter, kwargs)):
|
24
28
|
return cls._create_model_instance(document=document)
|
25
29
|
return None
|
26
30
|
|
27
31
|
@classmethod
|
28
|
-
def find(cls,
|
29
|
-
|
30
|
-
|
32
|
+
async def find(cls, _filter: dict | None = None, /, **kwargs) -> Cursor:
|
33
|
+
cursor = db.session.collection(cls.__name__).find(**cls._merge(_filter, kwargs))
|
34
|
+
cursor.response_type = cls._create_model_instance
|
35
|
+
cursor.cls = cls
|
36
|
+
return cursor
|
31
37
|
|
32
38
|
@classmethod
|
33
|
-
def first(cls,
|
34
|
-
if document := db.session.collection(cls.__name__).first(**cls._merge(
|
39
|
+
async def first(cls, _filter: dict | None = None, /, **kwargs) -> Self | None:
|
40
|
+
if document := db.session.collection(cls.__name__).first(**cls._merge(_filter, kwargs)):
|
35
41
|
return cls._create_model_instance(document=document)
|
36
42
|
return None
|
37
43
|
|
38
44
|
@classmethod
|
39
|
-
def last(cls,
|
40
|
-
if document := db.session.collection(cls.__name__).last(**cls._merge(
|
45
|
+
async def last(cls, _filter: dict | None = None, /, **kwargs) -> Self | None:
|
46
|
+
if document := db.session.collection(cls.__name__).last(**cls._merge(_filter, kwargs)):
|
41
47
|
return cls._create_model_instance(document=document)
|
42
48
|
return None
|
43
49
|
|
50
|
+
@classmethod
|
51
|
+
async def aggregate(cls, *args, **kwargs):
|
52
|
+
msg = 'aggregate() does not supported in `PantherDB`.'
|
53
|
+
raise DatabaseError(msg) from None
|
54
|
+
|
44
55
|
# # # # # Count # # # # #
|
45
56
|
@classmethod
|
46
|
-
def count(cls,
|
47
|
-
return db.session.collection(cls.__name__).count(**cls._merge(
|
57
|
+
async def count(cls, _filter: dict | None = None, /, **kwargs) -> int:
|
58
|
+
return db.session.collection(cls.__name__).count(**cls._merge(_filter, kwargs))
|
48
59
|
|
49
60
|
# # # # # Insert # # # # #
|
50
61
|
@classmethod
|
51
|
-
def insert_one(cls,
|
52
|
-
|
62
|
+
async def insert_one(cls, _document: dict | None = None, /, **kwargs) -> Self:
|
63
|
+
_document = cls._merge(_document, kwargs)
|
64
|
+
cls._validate_data(data=_document)
|
65
|
+
|
66
|
+
document = db.session.collection(cls.__name__).insert_one(**_document)
|
53
67
|
return cls._create_model_instance(document=document)
|
54
68
|
|
69
|
+
@classmethod
|
70
|
+
async def insert_many(cls, documents: Iterable[dict]) -> list[Self]:
|
71
|
+
result = []
|
72
|
+
for document in documents:
|
73
|
+
prepare_id_for_query(document, is_mongo=False)
|
74
|
+
cls._validate_data(data=document)
|
75
|
+
inserted_document = db.session.collection(cls.__name__).insert_one(**document)
|
76
|
+
document['_id'] = inserted_document['_id']
|
77
|
+
result.append(cls._create_model_instance(document=document))
|
78
|
+
return result
|
79
|
+
|
55
80
|
# # # # # Delete # # # # #
|
56
|
-
def delete(self) -> None:
|
81
|
+
async def delete(self) -> None:
|
57
82
|
db.session.collection(self.__class__.__name__).delete_one(_id=self._id)
|
58
83
|
|
59
84
|
@classmethod
|
60
|
-
def delete_one(cls,
|
61
|
-
return db.session.collection(cls.__name__).delete_one(**cls._merge(
|
85
|
+
async def delete_one(cls, _filter: dict | None = None, /, **kwargs) -> bool:
|
86
|
+
return db.session.collection(cls.__name__).delete_one(**cls._merge(_filter, kwargs))
|
62
87
|
|
63
88
|
@classmethod
|
64
|
-
def delete_many(cls,
|
65
|
-
return db.session.collection(cls.__name__).delete_many(**cls._merge(
|
89
|
+
async def delete_many(cls, _filter: dict | None = None, /, **kwargs) -> int:
|
90
|
+
return db.session.collection(cls.__name__).delete_many(**cls._merge(_filter, kwargs))
|
66
91
|
|
67
92
|
# # # # # Update # # # # #
|
68
|
-
def update(self, **kwargs) -> None:
|
69
|
-
|
93
|
+
async def update(self, _update: dict | None = None, /, **kwargs) -> None:
|
94
|
+
document = self._merge(_update, kwargs)
|
95
|
+
document.pop('_id', None)
|
96
|
+
self._validate_data(data=kwargs, is_updating=True)
|
97
|
+
|
98
|
+
for field, value in document.items():
|
70
99
|
setattr(self, field, value)
|
71
|
-
db.session.collection(self.__class__.__name__).update_one({'_id': self._id}, **
|
100
|
+
db.session.collection(self.__class__.__name__).update_one({'_id': self._id}, **document)
|
72
101
|
|
73
102
|
@classmethod
|
74
|
-
def update_one(cls, _filter: dict,
|
103
|
+
async def update_one(cls, _filter: dict, _update: dict | None = None, /, **kwargs) -> bool:
|
75
104
|
prepare_id_for_query(_filter)
|
76
|
-
return db.session.collection(cls.__name__).update_one(_filter, **cls._merge(
|
105
|
+
return db.session.collection(cls.__name__).update_one(_filter, **cls._merge(_update, kwargs))
|
77
106
|
|
78
107
|
@classmethod
|
79
|
-
def update_many(cls, _filter: dict, _data: dict | None = None, /, **kwargs) -> int:
|
108
|
+
async def update_many(cls, _filter: dict, _data: dict | None = None, /, **kwargs) -> int:
|
80
109
|
prepare_id_for_query(_filter)
|
81
110
|
return db.session.collection(cls.__name__).update_many(_filter, **cls._merge(_data, kwargs))
|
panther/db/queries/queries.py
CHANGED
@@ -1,11 +1,13 @@
|
|
1
1
|
import sys
|
2
|
+
from typing import Sequence, Iterable
|
2
3
|
|
3
|
-
from
|
4
|
+
from pantherdb import Cursor as PantherDBCursor
|
4
5
|
|
5
|
-
from panther import status
|
6
6
|
from panther.configs import QueryObservable
|
7
|
+
from panther.db.cursor import Cursor
|
8
|
+
from panther.db.queries.base_queries import BaseQuery
|
7
9
|
from panther.db.utils import log_query, check_connection
|
8
|
-
from panther.exceptions import
|
10
|
+
from panther.exceptions import NotFoundAPIError
|
9
11
|
|
10
12
|
__all__ = ('Query',)
|
11
13
|
|
@@ -17,12 +19,16 @@ else:
|
|
17
19
|
Self = TypeVar('Self', bound='Query')
|
18
20
|
|
19
21
|
|
20
|
-
class Query:
|
22
|
+
class Query(BaseQuery):
|
21
23
|
def __init_subclass__(cls, **kwargs):
|
22
24
|
QueryObservable.observe(cls)
|
23
25
|
|
24
26
|
@classmethod
|
25
27
|
def _reload_bases(cls, parent):
|
28
|
+
if not issubclass(parent, BaseQuery):
|
29
|
+
msg = f'Invalid Query Class: `{parent.__name__}` should be subclass of `BaseQuery`'
|
30
|
+
raise ValueError(msg)
|
31
|
+
|
26
32
|
if cls.__bases__.count(Query):
|
27
33
|
cls.__bases__ = (*cls.__bases__[: cls.__bases__.index(Query) + 1], parent)
|
28
34
|
else:
|
@@ -30,247 +36,356 @@ class Query:
|
|
30
36
|
if kls.__bases__.count(Query):
|
31
37
|
kls.__bases__ = (*kls.__bases__[:kls.__bases__.index(Query) + 1], parent)
|
32
38
|
|
39
|
+
# # # # # Find # # # # #
|
33
40
|
@classmethod
|
34
|
-
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
try:
|
40
|
-
cls(**data)
|
41
|
-
except ValidationError as validation_error:
|
42
|
-
error = {
|
43
|
-
'.'.join(loc for loc in e['loc']): e['msg']
|
44
|
-
for e in validation_error.errors()
|
45
|
-
if not is_updating or e['type'] != 'missing'
|
46
|
-
}
|
47
|
-
if error:
|
48
|
-
raise APIException(detail=error, status_code=status.HTTP_400_BAD_REQUEST)
|
41
|
+
@check_connection
|
42
|
+
@log_query
|
43
|
+
async def find_one(cls, _filter: dict | None = None, /, **kwargs) -> Self | None:
|
44
|
+
"""
|
45
|
+
Get a single document from the database.
|
49
46
|
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
)
|
59
|
-
|
60
|
-
|
61
|
-
raise DBException(message)
|
47
|
+
Example:
|
48
|
+
-------
|
49
|
+
>>> from app.models import User
|
50
|
+
|
51
|
+
>>> await User.find_one(id=1, name='Ali')
|
52
|
+
or
|
53
|
+
>>> await User.find_one({'id': 1, 'name': 'Ali'})
|
54
|
+
or
|
55
|
+
>>> await User.find_one({'id': 1}, name='Ali')
|
56
|
+
"""
|
57
|
+
return await super().find_one(_filter, **kwargs)
|
62
58
|
|
63
|
-
# # # # # Find # # # # #
|
64
59
|
@classmethod
|
65
60
|
@check_connection
|
66
61
|
@log_query
|
67
|
-
def
|
62
|
+
async def find(cls, _filter: dict | None = None, /, **kwargs) -> PantherDBCursor | Cursor:
|
68
63
|
"""
|
64
|
+
Get documents from the database.
|
65
|
+
|
69
66
|
Example:
|
70
67
|
-------
|
71
|
-
>>> from
|
72
|
-
|
68
|
+
>>> from app.models import User
|
69
|
+
|
70
|
+
>>> await User.find(age=18, name='Ali')
|
71
|
+
or
|
72
|
+
>>> await User.find({'age': 18, 'name': 'Ali'})
|
73
|
+
or
|
74
|
+
>>> await User.find({'age': 18}, name='Ali')
|
73
75
|
"""
|
74
|
-
return super().
|
76
|
+
return await super().find(_filter, **kwargs)
|
75
77
|
|
76
78
|
@classmethod
|
77
79
|
@check_connection
|
78
80
|
@log_query
|
79
|
-
def
|
81
|
+
async def first(cls, _filter: dict | None = None, /, **kwargs) -> Self | None:
|
80
82
|
"""
|
83
|
+
Get the first document from the database.
|
84
|
+
|
81
85
|
Example:
|
82
86
|
-------
|
83
|
-
>>> from
|
84
|
-
|
87
|
+
>>> from app.models import User
|
88
|
+
|
89
|
+
>>> await User.first(age=18, name='Ali')
|
90
|
+
or
|
91
|
+
>>> await User.first({'age': 18, 'name': 'Ali'})
|
92
|
+
or
|
93
|
+
>>> await User.first({'age': 18}, name='Ali')
|
85
94
|
"""
|
86
|
-
return super().
|
95
|
+
return await super().first(_filter, **kwargs)
|
87
96
|
|
88
97
|
@classmethod
|
89
98
|
@check_connection
|
90
99
|
@log_query
|
91
|
-
def
|
100
|
+
async def last(cls, _filter: dict | None = None, /, **kwargs) -> Self | None:
|
92
101
|
"""
|
102
|
+
Get the last document from the database.
|
103
|
+
|
93
104
|
Example:
|
94
105
|
-------
|
95
|
-
>>> from
|
96
|
-
|
97
|
-
|
106
|
+
>>> from app.models import User
|
107
|
+
|
108
|
+
>>> await User.last(age=18, name='Ali')
|
109
|
+
or
|
110
|
+
>>> await User.last({'age': 18, 'name': 'Ali'})
|
111
|
+
or
|
112
|
+
>>> await User.last({'age': 18}, name='Ali')
|
98
113
|
"""
|
99
|
-
return super().
|
114
|
+
return await super().last(_filter, **kwargs)
|
100
115
|
|
101
116
|
@classmethod
|
102
117
|
@check_connection
|
103
118
|
@log_query
|
104
|
-
def
|
119
|
+
async def aggregate(cls, pipeline: Sequence[dict]) -> Iterable[dict]:
|
105
120
|
"""
|
121
|
+
Perform an aggregation using the aggregation framework on this collection.
|
122
|
+
|
106
123
|
Example:
|
107
124
|
-------
|
108
|
-
>>> from
|
109
|
-
|
125
|
+
>>> from app.models import User
|
126
|
+
|
127
|
+
>>> pipeline = [
|
128
|
+
>>> {'$match': {...}},
|
129
|
+
>>> {'$unwind': ...},
|
130
|
+
>>> {'$group': {...}},
|
131
|
+
>>> {'$project': {...}},
|
132
|
+
>>> {'$sort': {...}}
|
133
|
+
>>> ...
|
134
|
+
>>> ]
|
135
|
+
|
136
|
+
>>> await User.aggregate(pipeline)
|
110
137
|
"""
|
111
|
-
return super().
|
138
|
+
return await super().aggregate(pipeline)
|
112
139
|
|
113
140
|
# # # # # Count # # # # #
|
114
141
|
@classmethod
|
115
142
|
@check_connection
|
116
143
|
@log_query
|
117
|
-
def count(cls,
|
144
|
+
async def count(cls, _filter: dict | None = None, /, **kwargs) -> int:
|
118
145
|
"""
|
146
|
+
Count the number of documents in this collection.
|
147
|
+
|
119
148
|
Example:
|
120
149
|
-------
|
121
|
-
>>> from
|
122
|
-
|
150
|
+
>>> from app.models import User
|
151
|
+
|
152
|
+
>>> await User.count(age=18, name='Ali')
|
153
|
+
or
|
154
|
+
>>> await User.count({'age': 18, 'name': 'Ali'})
|
155
|
+
or
|
156
|
+
>>> await User.count({'age': 18}, name='Ali')
|
123
157
|
"""
|
124
|
-
return super().count(
|
158
|
+
return await super().count(_filter, **kwargs)
|
125
159
|
|
126
160
|
# # # # # Insert # # # # #
|
127
161
|
@classmethod
|
128
162
|
@check_connection
|
129
163
|
@log_query
|
130
|
-
def insert_one(cls,
|
164
|
+
async def insert_one(cls, _document: dict | None = None, /, **kwargs) -> Self:
|
131
165
|
"""
|
166
|
+
Insert a single document.
|
167
|
+
|
132
168
|
Example:
|
133
169
|
-------
|
134
|
-
>>> from
|
135
|
-
|
170
|
+
>>> from app.models import User
|
171
|
+
|
172
|
+
>>> await User.insert_one(age=18, name='Ali')
|
173
|
+
or
|
174
|
+
>>> await User.insert_one({'age': 18, 'name': 'Ali'})
|
175
|
+
or
|
176
|
+
>>> await User.insert_one({'age': 18}, name='Ali')
|
136
177
|
"""
|
137
|
-
|
138
|
-
return super().insert_one(_data, **kwargs)
|
178
|
+
return await super().insert_one(_document, **kwargs)
|
139
179
|
|
140
180
|
@classmethod
|
141
181
|
@check_connection
|
142
182
|
@log_query
|
143
|
-
def insert_many(cls,
|
144
|
-
|
145
|
-
|
183
|
+
async def insert_many(cls, documents: Iterable[dict]) -> list[Self]:
|
184
|
+
"""
|
185
|
+
Insert an iterable of documents.
|
186
|
+
|
187
|
+
Example:
|
188
|
+
-------
|
189
|
+
>>> from app.models import User
|
190
|
+
|
191
|
+
>>> users = [
|
192
|
+
>>> {'age': 18, 'name': 'Ali'},
|
193
|
+
>>> {'age': 17, 'name': 'Saba'},
|
194
|
+
>>> {'age': 16, 'name': 'Amin'}
|
195
|
+
>>> ]
|
196
|
+
>>> await User.insert_many(users)
|
197
|
+
"""
|
198
|
+
return await super().insert_many(documents)
|
146
199
|
|
147
200
|
# # # # # Delete # # # # #
|
148
201
|
@check_connection
|
149
202
|
@log_query
|
150
|
-
def delete(self) -> None:
|
203
|
+
async def delete(self) -> None:
|
151
204
|
"""
|
205
|
+
Delete the document.
|
206
|
+
|
152
207
|
Example:
|
153
208
|
-------
|
154
|
-
>>> from
|
155
|
-
|
156
|
-
>>> user.
|
209
|
+
>>> from app.models import User
|
210
|
+
|
211
|
+
>>> user = await User.find_one(name='Ali')
|
212
|
+
|
213
|
+
>>> await user.delete()
|
157
214
|
"""
|
158
|
-
|
215
|
+
await super().delete()
|
159
216
|
|
160
217
|
@classmethod
|
161
218
|
@check_connection
|
162
219
|
@log_query
|
163
|
-
def delete_one(cls,
|
220
|
+
async def delete_one(cls, _filter: dict | None = None, /, **kwargs) -> bool:
|
164
221
|
"""
|
222
|
+
Delete a single document matching the filter.
|
223
|
+
|
165
224
|
Example:
|
166
225
|
-------
|
167
|
-
>>> from
|
168
|
-
|
226
|
+
>>> from app.models import User
|
227
|
+
|
228
|
+
>>> await User.delete_one(age=18, name='Ali')
|
229
|
+
or
|
230
|
+
>>> await User.delete_one({'age': 18, 'name': 'Ali'})
|
231
|
+
or
|
232
|
+
>>> await User.delete_one({'age': 18}, name='Ali')
|
169
233
|
"""
|
170
|
-
return super().delete_one(
|
234
|
+
return await super().delete_one(_filter, **kwargs)
|
171
235
|
|
172
236
|
@classmethod
|
173
237
|
@check_connection
|
174
238
|
@log_query
|
175
|
-
def delete_many(cls,
|
239
|
+
async def delete_many(cls, _filter: dict | None = None, /, **kwargs) -> int:
|
176
240
|
"""
|
241
|
+
Delete one or more documents matching the filter.
|
242
|
+
|
177
243
|
Example:
|
178
244
|
-------
|
179
|
-
>>> from
|
180
|
-
|
245
|
+
>>> from app.models import User
|
246
|
+
|
247
|
+
>>> await User.delete_many(age=18, name='Ali')
|
248
|
+
or
|
249
|
+
>>> await User.delete_many({'age': 18, 'name': 'Ali'})
|
250
|
+
or
|
251
|
+
>>> await User.delete_many({'age': 18}, name='Ali')
|
181
252
|
"""
|
182
|
-
return super().delete_many(
|
253
|
+
return await super().delete_many(_filter, **kwargs)
|
183
254
|
|
184
255
|
# # # # # Update # # # # #
|
185
256
|
@check_connection
|
186
257
|
@log_query
|
187
|
-
def update(self, **kwargs) -> None:
|
258
|
+
async def update(self, _update: dict | None = None, /, **kwargs) -> None:
|
188
259
|
"""
|
260
|
+
Update the document.
|
261
|
+
|
189
262
|
Example:
|
190
263
|
-------
|
191
|
-
>>> from
|
192
|
-
|
193
|
-
>>> user.
|
264
|
+
>>> from app.models import User
|
265
|
+
|
266
|
+
>>> user = await User.find_one(age=18, name='Ali')
|
267
|
+
|
268
|
+
>>> await user.update(name='Saba', age=19)
|
269
|
+
or
|
270
|
+
>>> await user.update({'name': 'Saba'}, age=19)
|
271
|
+
or
|
272
|
+
>>> await user.update({'name': 'Saba', 'age': 19})
|
194
273
|
"""
|
195
|
-
|
196
|
-
return super().update(**kwargs)
|
274
|
+
await super().update(_update, **kwargs)
|
197
275
|
|
198
276
|
@classmethod
|
199
277
|
@check_connection
|
200
278
|
@log_query
|
201
|
-
def update_one(cls, _filter: dict,
|
279
|
+
async def update_one(cls, _filter: dict, _update: dict | None = None, /, **kwargs) -> bool:
|
202
280
|
"""
|
281
|
+
Update a single document matching the filter.
|
282
|
+
|
203
283
|
Example:
|
204
284
|
-------
|
205
|
-
>>> from
|
206
|
-
|
207
|
-
>>> User.update_one({'id':
|
285
|
+
>>> from app.models import User
|
286
|
+
|
287
|
+
>>> await User.update_one({'id': 1}, age=18, name='Ali')
|
288
|
+
or
|
289
|
+
>>> await User.update_one({'id': 1}, {'age': 18, 'name': 'Ali'})
|
290
|
+
or
|
291
|
+
>>> await User.update_one({'id': 1}, {'age': 18}, name='Ali')
|
208
292
|
"""
|
209
|
-
return super().update_one(_filter,
|
293
|
+
return await super().update_one(_filter, _update, **kwargs)
|
210
294
|
|
211
295
|
@classmethod
|
212
296
|
@check_connection
|
213
297
|
@log_query
|
214
|
-
def update_many(cls, _filter: dict,
|
298
|
+
async def update_many(cls, _filter: dict, _update: dict | None = None, /, **kwargs) -> int:
|
215
299
|
"""
|
300
|
+
Update one or more documents that match the filter.
|
301
|
+
|
216
302
|
Example:
|
217
303
|
-------
|
218
|
-
>>> from
|
219
|
-
|
220
|
-
>>> User.update_many({'name': '
|
304
|
+
>>> from app.models import User
|
305
|
+
|
306
|
+
>>> await User.update_many({'name': 'Saba'}, age=18, name='Ali')
|
307
|
+
or
|
308
|
+
>>> await User.update_many({'name': 'Saba'}, {'age': 18, 'name': 'Ali'})
|
309
|
+
or
|
310
|
+
>>> await User.update_many({'name': 'Saba'}, {'age': 18}, name='Ali')
|
221
311
|
"""
|
222
|
-
return super().update_many(_filter,
|
312
|
+
return await super().update_many(_filter, _update, **kwargs)
|
223
313
|
|
224
314
|
# # # # # Other # # # # #
|
225
315
|
@classmethod
|
226
|
-
def all(cls) -> list[Self]:
|
316
|
+
async def all(cls) -> list[Self] | Cursor:
|
227
317
|
"""
|
318
|
+
Alias of find() without args
|
319
|
+
|
228
320
|
Example:
|
229
321
|
-------
|
230
|
-
>>> from
|
231
|
-
|
232
|
-
|
322
|
+
>>> from app.models import User
|
323
|
+
|
324
|
+
>>> await User.all()
|
233
325
|
"""
|
234
|
-
return cls.find()
|
326
|
+
return await cls.find()
|
235
327
|
|
236
328
|
@classmethod
|
237
|
-
def
|
329
|
+
async def find_one_or_insert(cls, _filter: dict | None = None, /, **kwargs) -> tuple[Self, bool]:
|
238
330
|
"""
|
331
|
+
Get a single document from the database.
|
332
|
+
or
|
333
|
+
Insert a single document.
|
334
|
+
|
239
335
|
Example:
|
240
336
|
-------
|
241
|
-
>>> from
|
242
|
-
|
243
|
-
|
244
|
-
|
245
|
-
|
246
|
-
|
337
|
+
>>> from app.models import User
|
338
|
+
|
339
|
+
>>> await User.find_one_or_insert(age=18, name='Ali')
|
340
|
+
or
|
341
|
+
>>> await User.find_one_or_insert({'age': 18, 'name': 'Ali'})
|
342
|
+
or
|
343
|
+
>>> await User.find_one_or_insert({'age': 18}, name='Ali')
|
344
|
+
"""
|
345
|
+
if obj := await cls.find_one(_filter, **kwargs):
|
346
|
+
return obj, False
|
347
|
+
return await cls.insert_one(_filter, **kwargs), True
|
247
348
|
|
248
349
|
@classmethod
|
249
|
-
def find_one_or_raise(cls, **kwargs) -> Self:
|
350
|
+
async def find_one_or_raise(cls, _filter: dict | None = None, /, **kwargs) -> Self:
|
250
351
|
"""
|
251
352
|
Example:
|
252
353
|
-------
|
253
|
-
>>> from
|
254
|
-
|
354
|
+
>>> from app.models import User
|
355
|
+
|
356
|
+
>>> await User.find_one_or_raise(age=18, name='Ali')
|
357
|
+
or
|
358
|
+
>>> await User.find_one_or_raise({'age': 18, 'name': 'Ali'})
|
359
|
+
or
|
360
|
+
>>> await User.find_one_or_raise({'age': 18}, name='Ali')
|
255
361
|
"""
|
256
|
-
if obj := cls.find_one(**kwargs):
|
362
|
+
if obj := await cls.find_one(_filter, **kwargs):
|
257
363
|
return obj
|
258
364
|
|
259
|
-
raise
|
260
|
-
detail=f'{cls.__name__} Does Not Exists',
|
261
|
-
status_code=status.HTTP_404_NOT_FOUND,
|
262
|
-
)
|
365
|
+
raise NotFoundAPIError(detail=f'{cls.__name__} Does Not Exist')
|
263
366
|
|
264
367
|
@check_connection
|
265
368
|
@log_query
|
266
|
-
def save(self) -> None:
|
369
|
+
async def save(self) -> None:
|
267
370
|
"""
|
371
|
+
Save the document
|
372
|
+
If it has `id` --> Update It
|
373
|
+
else --> Insert It
|
268
374
|
Example:
|
269
375
|
-------
|
270
|
-
>>> from
|
271
|
-
|
376
|
+
>>> from app.models import User
|
377
|
+
|
378
|
+
# Update
|
379
|
+
>>> user = await User.find_one(name='Ali')
|
272
380
|
>>> user.name = 'Saba'
|
273
|
-
>>> user.save()
|
274
|
-
|
275
|
-
|
276
|
-
|
381
|
+
>>> await user.save()
|
382
|
+
or
|
383
|
+
# Insert
|
384
|
+
>>> user = User(name='Ali')
|
385
|
+
>>> await user.save()
|
386
|
+
"""
|
387
|
+
document = self.model_dump(exclude=['_id'])
|
388
|
+
if self.id:
|
389
|
+
await self.update(document)
|
390
|
+
else:
|
391
|
+
await self.insert_one(document)
|