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.
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mlmongo
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: mongodb数据库操作工具类
5
5
  Home-page: https://www.python.org
6
6
  Author: mengling
@@ -1,8 +1,8 @@
1
1
  import warnings
2
2
  from pydantic import BaseModel
3
3
  import asyncio
4
- from typing import Any, AsyncGenerator, Self
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
- @_limit_iterator
74
- async def mg_find_all(cls, *querys: dict, cig:dict=None, is_get_dt:bool=False,
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
- async for dt in cursor:
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
- @_limit_iterator
85
- async def mg_find_onekey_all(cls, key:str, *querys: dict,
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 for dt in cursor:
92
- yield dt[key]
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.id_ = (await cls.MGConfig.getConnect().insert_one(data if isinstance(data, dict) else data.model_dump())).inserted_id
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.model_dump() if isinstance(data, BaseModel) else data) for data in datas])
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
- @_limit_iterator
168
- async def mg_aggregate(cls, data:list)->AsyncGenerator[Any, None]:
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(value)
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.id_ = (await self.MGConfig.getConnect().insert_one(self.model_dump())).inserted_id
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.model_dump(), upsert=True)
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.model_dump()}, upsert=True)
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.id_ = None
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
- return {'$set': data if isinstance(data, dict) else data.model_dump()}
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)->Generator[Self|dict, None, 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
- for dt in cursor:
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)->Generator[Any, None, 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
- for dt in cursor:
58
- yield dt[key]
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.id_ = (cls.MGConfig.getConnect().insert_one(data if isinstance(data, dict) else data.model_dump())).inserted_id
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.model_dump() if isinstance(data, BaseModel) else data) for data in datas])
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)->Generator[Any, None, None]:
120
- for d in cls.MGConfig.getConnect().aggregate(data):
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(value)
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.id_ = (self.MGConfig.getConnect().insert_one(self.model_dump())).inserted_id
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.model_dump(), upsert=True)
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.model_dump()}, upsert=True)
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.id_ = None
154
+ self.mgt_set_id(None)
153
155
  return result
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mlmongo
3
- Version: 2.0.0
3
+ Version: 2.0.2
4
4
  Summary: mongodb数据库操作工具类
5
5
  Home-page: https://www.python.org
6
6
  Author: mengling
File without changes
File without changes
File without changes
File without changes