mlmongo 2.0.0__tar.gz → 2.0.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.
- {mlmongo-2.0.0 → mlmongo-2.0.2}/PKG-INFO +1 -1
- {mlmongo-2.0.0 → mlmongo-2.0.2}/mlmongo/asyncs.py +23 -32
- {mlmongo-2.0.0 → mlmongo-2.0.2}/mlmongo/model.py +68 -3
- {mlmongo-2.0.0 → mlmongo-2.0.2}/mlmongo/sync.py +21 -19
- {mlmongo-2.0.0 → mlmongo-2.0.2}/mlmongo.egg-info/PKG-INFO +1 -1
- {mlmongo-2.0.0 → mlmongo-2.0.2}/MANIFEST.in +0 -0
- {mlmongo-2.0.0 → mlmongo-2.0.2}/mlmongo/__init__.py +0 -0
- {mlmongo-2.0.0 → mlmongo-2.0.2}/mlmongo/__pycache__/asyncs.cpython-312.pyc +0 -0
- {mlmongo-2.0.0 → mlmongo-2.0.2}/mlmongo/__pycache__/model.cpython-312.pyc +0 -0
- {mlmongo-2.0.0 → mlmongo-2.0.2}/mlmongo.egg-info/SOURCES.txt +0 -0
- {mlmongo-2.0.0 → mlmongo-2.0.2}/mlmongo.egg-info/dependency_links.txt +0 -0
- {mlmongo-2.0.0 → mlmongo-2.0.2}/mlmongo.egg-info/requires.txt +0 -0
- {mlmongo-2.0.0 → mlmongo-2.0.2}/mlmongo.egg-info/top_level.txt +0 -0
- {mlmongo-2.0.0 → mlmongo-2.0.2}/setup.cfg +0 -0
- {mlmongo-2.0.0 → mlmongo-2.0.2}/setup.py +0 -0
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import warnings
|
|
2
2
|
from pydantic import BaseModel
|
|
3
3
|
import asyncio
|
|
4
|
-
from typing import Any,
|
|
5
|
-
from .model import MGField, MGFunction, MGConfig as _MGConfig, MongoModel as _MongoModel
|
|
4
|
+
from typing import Any, Self
|
|
5
|
+
from .model import AMGIt, MGField, MGFunction, MGConfig as _MGConfig, MongoModel as _MongoModel
|
|
6
6
|
try:
|
|
7
7
|
from motor.motor_asyncio import AsyncIOMotorClient, AsyncIOMotorCollection
|
|
8
8
|
except:
|
|
@@ -15,15 +15,7 @@ def _limit(afunc):
|
|
|
15
15
|
return await afunc(self, *args, **kwargs)
|
|
16
16
|
|
|
17
17
|
return _main
|
|
18
|
-
|
|
19
|
-
def _limit_iterator(afunc):
|
|
20
|
-
async def _main(self:'AMongoModel', *args, **kwargs):
|
|
21
|
-
async with self.MGConfig.getSem():
|
|
22
|
-
async for result in afunc(self, *args, **kwargs):
|
|
23
|
-
yield result
|
|
24
18
|
|
|
25
|
-
return _main
|
|
26
|
-
|
|
27
19
|
class MGConfig(_MGConfig):
|
|
28
20
|
limit:int = 300
|
|
29
21
|
# _client:AsyncIOMotorCollection=None
|
|
@@ -70,27 +62,27 @@ class AMongoModel(_MongoModel):
|
|
|
70
62
|
return result and (result if cig or is_get_dt else cls(**result))
|
|
71
63
|
|
|
72
64
|
@classmethod
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
sort_map: dict[str, int]=None, skip:int=None, limit:int=None)->AsyncGenerator[Self|dict, None]:
|
|
65
|
+
def mg_find_all(cls, *querys: dict, cig:dict=None, is_get_dt:bool=False,
|
|
66
|
+
sort_map: dict[str, int]=None, skip:int=None, limit:int=None)->AMGIt[Self|dict]:
|
|
76
67
|
cursor = cls.MGConfig.getConnect().find(MGFunction.and_(*querys), cig if cig else {})
|
|
77
68
|
if sort_map: cursor=cursor.sort(sort_map)
|
|
78
69
|
if skip: cursor=cursor.skip(skip)
|
|
79
70
|
if limit: cursor=cursor.limit(limit)
|
|
80
|
-
|
|
81
|
-
yield dt if cig or is_get_dt else cls(**dt)
|
|
71
|
+
return AMGIt(cursor, cls, if_get_cls=not is_get_dt and not cig)
|
|
82
72
|
|
|
83
73
|
@classmethod
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
sort_map: dict[str, int]=None, skip:int=None, limit:int=None)->AsyncGenerator[Any, None]:
|
|
74
|
+
def mg_find_onekey_all(cls, key:str, *querys: dict,
|
|
75
|
+
sort_map: dict[str, int]=None, skip:int=None, limit:int=None)->AMGIt[Any]:
|
|
87
76
|
cursor = cls.MGConfig.getConnect().find(MGFunction.and_(*querys), {'_id':0, key:1})
|
|
88
77
|
if sort_map: cursor=cursor.sort(sort_map)
|
|
89
78
|
if skip: cursor=cursor.skip(skip)
|
|
90
79
|
if limit: cursor=cursor.limit(limit)
|
|
91
|
-
async
|
|
92
|
-
|
|
93
|
-
|
|
80
|
+
async def temp():
|
|
81
|
+
async for dt in cursor:
|
|
82
|
+
yield dt[key]
|
|
83
|
+
|
|
84
|
+
return AMGIt(temp(), cls)
|
|
85
|
+
|
|
94
86
|
@classmethod
|
|
95
87
|
@_limit
|
|
96
88
|
async def mg_find_onecol(cls, key:str, *querys: dict, default=None):
|
|
@@ -144,14 +136,14 @@ class AMongoModel(_MongoModel):
|
|
|
144
136
|
@_limit
|
|
145
137
|
async def mg_insert(cls, data:Self|dict)-> Self:
|
|
146
138
|
data = cls(**data) if isinstance(data, dict) else data
|
|
147
|
-
data.
|
|
139
|
+
data.mgt_set_id((await cls.MGConfig.getConnect().insert_one(data if isinstance(data, dict) else data.mgt_model_dump())).inserted_id)
|
|
148
140
|
return data
|
|
149
141
|
|
|
150
142
|
@classmethod
|
|
151
143
|
@_limit
|
|
152
144
|
async def mg_insert_many(cls, datas: list[Self|dict]):
|
|
153
145
|
if not datas: return None
|
|
154
|
-
return await cls.MGConfig.getConnect().insert_many([(data.
|
|
146
|
+
return await cls.MGConfig.getConnect().insert_many([(data.mgt_model_dump() if isinstance(data, BaseModel) else data) for data in datas])
|
|
155
147
|
|
|
156
148
|
@classmethod
|
|
157
149
|
@_limit
|
|
@@ -164,20 +156,19 @@ class AMongoModel(_MongoModel):
|
|
|
164
156
|
return (await cls.MGConfig.getConnect().delete_many(cls.mgt_get_id_query(ids))).raw_result
|
|
165
157
|
|
|
166
158
|
@classmethod
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
async for d in cls.MGConfig.getConnect().aggregate(data):
|
|
170
|
-
yield d
|
|
159
|
+
def mg_aggregate(cls, data:list)->AMGIt[dict]:
|
|
160
|
+
return AMGIt(cls.MGConfig.getConnect().aggregate(data), cls)
|
|
171
161
|
|
|
172
162
|
@_limit
|
|
173
163
|
async def mg_self_sync(self):
|
|
174
164
|
"""同步数据库到对象"""
|
|
175
165
|
kv = self.mgt_get_key_value()
|
|
176
166
|
if isinstance(kv, str): return warnings.warn(f'{kv} is None')
|
|
177
|
-
newer = await self.mg_id_find(
|
|
167
|
+
newer = await self.mg_id_find(*[kv[k] for k in self.MGConfig.default_ids])
|
|
178
168
|
if newer:
|
|
179
169
|
for key, value in newer.model_dump().items():
|
|
180
170
|
if hasattr(self, key): setattr(self, key, value)
|
|
171
|
+
self.mgt_set_id(newer.id_)
|
|
181
172
|
else:
|
|
182
173
|
warnings.warn(f'数据库中没有对应数据 - keys: {kv}')
|
|
183
174
|
|
|
@@ -187,12 +178,12 @@ class AMongoModel(_MongoModel):
|
|
|
187
178
|
kv = self.mgt_get_key_value()
|
|
188
179
|
if check_id and isinstance(kv, str): raise ValueError(f'{kv} is None')
|
|
189
180
|
if is_force_new or kv=='_id':
|
|
190
|
-
self.
|
|
181
|
+
self.mgt_set_id((await self.MGConfig.getConnect().insert_one(self.mgt_model_dump())).inserted_id)
|
|
191
182
|
elif isinstance(kv, dict):
|
|
192
183
|
if is_replace:
|
|
193
|
-
await self.MGConfig.getConnect().replace_one(kv, self.
|
|
184
|
+
await self.MGConfig.getConnect().replace_one(kv, self.mgt_model_dump(), upsert=True)
|
|
194
185
|
else:
|
|
195
|
-
await self.MGConfig.getConnect().update_one(kv, {'$set': self.
|
|
186
|
+
await self.MGConfig.getConnect().update_one(kv, {'$set': self.mgt_model_dump()}, upsert=True)
|
|
196
187
|
else:
|
|
197
188
|
raise ValueError(f'{kv} is None')
|
|
198
189
|
|
|
@@ -201,7 +192,7 @@ class AMongoModel(_MongoModel):
|
|
|
201
192
|
kv = self.mgt_get_key_value()
|
|
202
193
|
if isinstance(kv, str): return warnings.warn(f'{kv} is None')
|
|
203
194
|
result = (await self.MGConfig.getConnect().delete_many(kv)).raw_result
|
|
204
|
-
self.
|
|
195
|
+
self.mgt_set_id(None)
|
|
205
196
|
return result
|
|
206
197
|
|
|
207
198
|
|
|
@@ -5,10 +5,58 @@ from bson import ObjectId
|
|
|
5
5
|
from pydantic import AliasChoices, AliasPath, BaseModel, PydanticUserError
|
|
6
6
|
from pydantic.fields import FieldInfo
|
|
7
7
|
from pydantic.config import JsonDict
|
|
8
|
-
from typing import Any, Callable, Literal, overload
|
|
8
|
+
from typing import Any, Callable, Generic, Literal, overload, TypeVar
|
|
9
9
|
from pydantic_core import PydanticUndefined
|
|
10
10
|
|
|
11
11
|
|
|
12
|
+
T = TypeVar('T')
|
|
13
|
+
|
|
14
|
+
class AMGIt(Generic[T]):
|
|
15
|
+
def __init__(self, ait, cls:T, if_get_cls=False):
|
|
16
|
+
self._it = ait
|
|
17
|
+
self.if_get_cls = if_get_cls
|
|
18
|
+
self._cls = cls
|
|
19
|
+
self._sem = cls.MGConfig.getSem()
|
|
20
|
+
|
|
21
|
+
async def __anext__(self)->T|Any:
|
|
22
|
+
async with self._sem:
|
|
23
|
+
value = await self._it.__anext__()
|
|
24
|
+
return self._cls(**value) if self.if_get_cls else value
|
|
25
|
+
|
|
26
|
+
def __aiter__(self):
|
|
27
|
+
return self
|
|
28
|
+
|
|
29
|
+
async def to_list(self)->list[T|Any]:
|
|
30
|
+
return [mes async for mes in self]
|
|
31
|
+
|
|
32
|
+
async def first(self)->T|Any:
|
|
33
|
+
return await self.__anext__()
|
|
34
|
+
|
|
35
|
+
async def last(self)->T|Any:
|
|
36
|
+
return (await self.to_list())[-1]
|
|
37
|
+
|
|
38
|
+
class MGIt(Generic[T]):
|
|
39
|
+
def __init__(self, it, cls:T, if_get_cls=False):
|
|
40
|
+
self._it = it
|
|
41
|
+
self.if_get_cls = if_get_cls
|
|
42
|
+
self._cls = cls
|
|
43
|
+
|
|
44
|
+
def __next__(self)->T|Any:
|
|
45
|
+
value = self._it.__next__()
|
|
46
|
+
return self._cls(**value) if self.if_get_cls else value
|
|
47
|
+
|
|
48
|
+
def __iter__(self):
|
|
49
|
+
return self
|
|
50
|
+
|
|
51
|
+
def to_list(self)->list[T|Any]:
|
|
52
|
+
return [mes for mes in self]
|
|
53
|
+
|
|
54
|
+
def first(self)->T|Any:
|
|
55
|
+
return self.__next__()
|
|
56
|
+
|
|
57
|
+
def last(self)->T|Any:
|
|
58
|
+
return self.to_list()[-1]
|
|
59
|
+
|
|
12
60
|
class _MGFieldInfo(FieldInfo):
|
|
13
61
|
def __init__(self, **kwargs):
|
|
14
62
|
super().__init__(**kwargs)
|
|
@@ -319,6 +367,8 @@ class MGConfig:
|
|
|
319
367
|
db:str
|
|
320
368
|
col:str
|
|
321
369
|
default_ids:tuple[str] = ('_id',)
|
|
370
|
+
# 用于同步_id字段的内容
|
|
371
|
+
sync_ids: tuple[str] = ()
|
|
322
372
|
|
|
323
373
|
class MGFunction:
|
|
324
374
|
@staticmethod
|
|
@@ -339,7 +389,11 @@ class MGFunction:
|
|
|
339
389
|
|
|
340
390
|
@staticmethod
|
|
341
391
|
def data_set_(data:dict|BaseModel):
|
|
342
|
-
|
|
392
|
+
if isinstance(data, MongoModel):
|
|
393
|
+
data = data.mgt_model_dump()
|
|
394
|
+
elif isinstance(data, BaseModel):
|
|
395
|
+
data = data.model_dump()
|
|
396
|
+
return {'$set': data}
|
|
343
397
|
|
|
344
398
|
@staticmethod
|
|
345
399
|
def set_(field:_MGFieldInfo|str, value):
|
|
@@ -383,6 +437,10 @@ class MGFunction:
|
|
|
383
437
|
class MongoModel(BaseModel):
|
|
384
438
|
id_: object|None = MGField(default=None, exclude=True, alias='_id')
|
|
385
439
|
|
|
440
|
+
def __init__(self, /, **kwargs):
|
|
441
|
+
super().__init__(**kwargs)
|
|
442
|
+
self.mgt_set_id(self.id_)
|
|
443
|
+
|
|
386
444
|
class MGConfig(MGConfig):
|
|
387
445
|
pass
|
|
388
446
|
|
|
@@ -413,4 +471,11 @@ class MongoModel(BaseModel):
|
|
|
413
471
|
else:
|
|
414
472
|
# 如果操作符不存在,直接添加
|
|
415
473
|
merged[op] = value
|
|
416
|
-
return merged
|
|
474
|
+
return merged
|
|
475
|
+
|
|
476
|
+
def mgt_set_id(self, id_: ObjectId|None):
|
|
477
|
+
self.id_ = id_
|
|
478
|
+
for field in self.MGConfig.sync_ids: setattr(self, field, self._id)
|
|
479
|
+
|
|
480
|
+
def mgt_model_dump(self)->dict:
|
|
481
|
+
return self.model_dump(exclude=self.MGConfig.sync_ids or None)
|
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
import warnings
|
|
2
2
|
from pydantic import BaseModel
|
|
3
3
|
from typing import Any, Generator, Self
|
|
4
|
-
from .model import MGField, MGFunction, MGConfig as _MGConfig, MongoModel as _MongoModel
|
|
4
|
+
from .model import MGIt, MGField, MGFunction, MGConfig as _MGConfig, MongoModel as _MongoModel
|
|
5
5
|
from pymongo import MongoClient
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
|
|
8
8
|
class MGConfig(_MGConfig):
|
|
9
9
|
@classmethod
|
|
10
10
|
def _getClient(cls):
|
|
@@ -15,7 +15,7 @@ class MGConfig(_MGConfig):
|
|
|
15
15
|
def getConnect(cls):
|
|
16
16
|
if not hasattr(cls, '_client'): cls._client=cls._getClient()
|
|
17
17
|
return cls._client
|
|
18
|
-
|
|
18
|
+
|
|
19
19
|
class MongoModel(_MongoModel):
|
|
20
20
|
class MGConfig(MGConfig):
|
|
21
21
|
pass
|
|
@@ -39,23 +39,25 @@ class MongoModel(_MongoModel):
|
|
|
39
39
|
|
|
40
40
|
@classmethod
|
|
41
41
|
def mg_find_all(cls, *querys: dict, cig:dict=None, is_get_dt:bool=False,
|
|
42
|
-
sort_map: dict[str, int]=None, skip:int=None, limit:int=None)->
|
|
42
|
+
sort_map: dict[str, int]=None, skip:int=None, limit:int=None)->MGIt[Self|dict]:
|
|
43
43
|
cursor = cls.MGConfig.getConnect().find(MGFunction.and_(*querys), cig if cig else {})
|
|
44
44
|
if sort_map: cursor=cursor.sort(sort_map)
|
|
45
45
|
if skip: cursor=cursor.skip(skip)
|
|
46
46
|
if limit: cursor=cursor.limit(limit)
|
|
47
|
-
|
|
48
|
-
yield dt if cig or is_get_dt else cls(**dt)
|
|
47
|
+
return MGIt(cursor, cls, if_get_cls=not is_get_dt and not cig)
|
|
49
48
|
|
|
50
49
|
@classmethod
|
|
51
50
|
def mg_find_onekey_all(cls, key:str, *querys: dict,
|
|
52
|
-
sort_map: dict[str, int]=None, skip:int=None, limit:int=None)->
|
|
51
|
+
sort_map: dict[str, int]=None, skip:int=None, limit:int=None)->MGIt[Any]:
|
|
53
52
|
cursor = cls.MGConfig.getConnect().find(MGFunction.and_(*querys), {'_id':0, key:1})
|
|
54
53
|
if sort_map: cursor=cursor.sort(sort_map)
|
|
55
54
|
if skip: cursor=cursor.skip(skip)
|
|
56
55
|
if limit: cursor=cursor.limit(limit)
|
|
57
|
-
|
|
58
|
-
|
|
56
|
+
def temp():
|
|
57
|
+
for dt in cursor:
|
|
58
|
+
yield dt[key]
|
|
59
|
+
|
|
60
|
+
return MGIt(temp(), cls)
|
|
59
61
|
|
|
60
62
|
@classmethod
|
|
61
63
|
def mg_find_onecol(cls, key:str, *querys: dict, default=None):
|
|
@@ -99,13 +101,13 @@ class MongoModel(_MongoModel):
|
|
|
99
101
|
@classmethod
|
|
100
102
|
def mg_insert(cls, data:Self|dict)-> Self:
|
|
101
103
|
data = cls(**data) if isinstance(data, dict) else data
|
|
102
|
-
data.
|
|
104
|
+
data.mgt_set_id(cls.MGConfig.getConnect().insert_one(data if isinstance(data, dict) else data.mgt_model_dump()).inserted_id)
|
|
103
105
|
return data
|
|
104
106
|
|
|
105
107
|
@classmethod
|
|
106
108
|
def mg_insert_many(cls, datas: list[Self|dict]):
|
|
107
109
|
if not datas: return None
|
|
108
|
-
return cls.MGConfig.getConnect().insert_many([(data.
|
|
110
|
+
return cls.MGConfig.getConnect().insert_many([(data.mgt_model_dump() if isinstance(data, BaseModel) else data) for data in datas])
|
|
109
111
|
|
|
110
112
|
@classmethod
|
|
111
113
|
def mg_delete(cls, *querys: dict)->dict:
|
|
@@ -116,18 +118,18 @@ class MongoModel(_MongoModel):
|
|
|
116
118
|
return cls.MGConfig.getConnect().delete_many(cls.mgt_get_id_query(ids)).raw_result
|
|
117
119
|
|
|
118
120
|
@classmethod
|
|
119
|
-
def mg_aggregate(cls, data:list)->
|
|
120
|
-
|
|
121
|
-
yield d
|
|
121
|
+
def mg_aggregate(cls, data:list)->MGIt[dict]:
|
|
122
|
+
return MGIt(cls.MGConfig.getConnect().aggregate(data), cls)
|
|
122
123
|
|
|
123
124
|
def mg_self_sync(self):
|
|
124
125
|
"""同步数据库到对象"""
|
|
125
126
|
kv = self.mgt_get_key_value()
|
|
126
127
|
if isinstance(kv, str): return warnings.warn(f'{kv} is None')
|
|
127
|
-
newer = self.mg_id_find(
|
|
128
|
+
newer = self.mg_id_find(*[kv[k] for k in self.MGConfig.default_ids])
|
|
128
129
|
if newer:
|
|
129
130
|
for key, value in newer.model_dump().items():
|
|
130
131
|
if hasattr(self, key): setattr(self, key, value)
|
|
132
|
+
self.mgt_set_id(newer.id_)
|
|
131
133
|
else:
|
|
132
134
|
warnings.warn(f'数据库中没有对应数据 - keys: {kv}')
|
|
133
135
|
|
|
@@ -136,12 +138,12 @@ class MongoModel(_MongoModel):
|
|
|
136
138
|
kv = self.mgt_get_key_value()
|
|
137
139
|
if check_id and isinstance(kv, str): raise ValueError(f'{kv} is None')
|
|
138
140
|
if is_force_new or kv=='_id':
|
|
139
|
-
self.
|
|
141
|
+
self.mgt_set_id(self.MGConfig.getConnect().insert_one(self.mgt_model_dump()).inserted_id)
|
|
140
142
|
elif isinstance(kv, dict):
|
|
141
143
|
if is_replace:
|
|
142
|
-
self.MGConfig.getConnect().replace_one(kv, self.
|
|
144
|
+
self.MGConfig.getConnect().replace_one(kv, self.mgt_model_dump(), upsert=True)
|
|
143
145
|
else:
|
|
144
|
-
self.MGConfig.getConnect().update_one(kv, {'$set': self.
|
|
146
|
+
self.MGConfig.getConnect().update_one(kv, {'$set': self.mgt_model_dump()}, upsert=True)
|
|
145
147
|
else:
|
|
146
148
|
raise ValueError(f'{kv} is None')
|
|
147
149
|
|
|
@@ -149,5 +151,5 @@ class MongoModel(_MongoModel):
|
|
|
149
151
|
kv = self.mgt_get_key_value()
|
|
150
152
|
if isinstance(kv, str): return warnings.warn(f'{kv} is None')
|
|
151
153
|
result = (self.MGConfig.getConnect().delete_many(kv)).raw_result
|
|
152
|
-
self.
|
|
154
|
+
self.mgt_set_id(None)
|
|
153
155
|
return result
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|