cloudoll 2.2.23__tar.gz → 2.2.24__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.
- {cloudoll-2.2.23 → cloudoll-2.2.24}/PKG-INFO +1 -1
- cloudoll-2.2.24/cloudoll/__init__.py +1 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/__init__.py +107 -17
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/base.py +8 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/model.py +65 -11
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/robot/feishu.py +2 -1
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/utils/m2d.py +2 -1
- cloudoll-2.2.24/cloudoll/utils/snowflake.py +86 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/PKG-INFO +1 -1
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/SOURCES.txt +1 -0
- cloudoll-2.2.23/cloudoll/__init__.py +0 -1
- {cloudoll-2.2.23 → cloudoll-2.2.24}/LICENSE +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/README.md +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/__main__.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/cli.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/error/__init__.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/error/errors.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/logging/__init__.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/mail/__init__.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/mail/smtp.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/err.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/field.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/mysql.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/parse.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/orm/postgres.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/robot/__init__.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/robot/dingtalk.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/robot/slack.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/utils/__init__.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/utils/common.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/utils/patch_loop.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/utils/watch.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/__init__.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/exception.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/html.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/http.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/jwt.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll/web/settings.py +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/dependency_links.txt +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/entry_points.txt +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/requires.txt +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/cloudoll.egg-info/top_level.txt +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/setup.cfg +0 -0
- {cloudoll-2.2.23 → cloudoll-2.2.24}/setup.py +0 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
__version__ = "2.2.24"
|
|
@@ -1,13 +1,20 @@
|
|
|
1
1
|
from redis import asyncio as aioredis
|
|
2
2
|
from .parse import parse_coon
|
|
3
|
-
import aiopg, aiomysql
|
|
4
3
|
from .base import MeteBase, QueryTypes
|
|
5
4
|
from typing import Any
|
|
6
5
|
from ..logging import print_info, print_error
|
|
7
6
|
import traceback
|
|
7
|
+
import aiomysql
|
|
8
8
|
from aiomysql import Pool as MYPool
|
|
9
|
+
|
|
10
|
+
import aiopg as pg
|
|
9
11
|
from aiopg.pool import Pool as PGPool
|
|
10
12
|
|
|
13
|
+
# import asyncpg as pg
|
|
14
|
+
# from asyncpg.pool import Pool as PGPool
|
|
15
|
+
|
|
16
|
+
__ALL__ = "create_engine"
|
|
17
|
+
|
|
11
18
|
|
|
12
19
|
async def create_engine(**kw):
|
|
13
20
|
url = kw.get("url")
|
|
@@ -48,6 +55,65 @@ class Postgres(MeteBase):
|
|
|
48
55
|
def __call__(self, *args: Any, **kwds: Any) -> Any:
|
|
49
56
|
self.__init__(*args, **kwds)
|
|
50
57
|
|
|
58
|
+
# async def query(self, sql, params=None, query_type: QueryTypes = 2, size: int = 10):
|
|
59
|
+
# sql = sql.replace("?", "%s").replace("`", "")
|
|
60
|
+
# print_info("sql", sql, params)
|
|
61
|
+
# if not self.pool:
|
|
62
|
+
# raise ValueError("must be create_engine first.")
|
|
63
|
+
# if self.pool._closing or self.pool._closed:
|
|
64
|
+
# return None
|
|
65
|
+
|
|
66
|
+
# # async with self.pool.acquire() as conn:
|
|
67
|
+
# async with self.pool.acquire() as conn:
|
|
68
|
+
# # current_cursor = getattr(cursor, 'lastrowid', None)
|
|
69
|
+
# if (
|
|
70
|
+
# query_type == QueryTypes.CREATEBATCH
|
|
71
|
+
# or query_type == QueryTypes.UPDATEBATCH
|
|
72
|
+
# ):
|
|
73
|
+
# result = await conn.executemany(sql, params) # aiopg don't support executemany
|
|
74
|
+
# else:
|
|
75
|
+
# result = await conn.execute(sql, params)
|
|
76
|
+
|
|
77
|
+
# # result = None
|
|
78
|
+
|
|
79
|
+
# return result
|
|
80
|
+
|
|
81
|
+
# if query_type == QueryTypes.ALL:
|
|
82
|
+
# columns = [desc[0] for desc in cursor.description]
|
|
83
|
+
# rows = await cursor.fetchall()
|
|
84
|
+
# result = [dict(zip(columns, row)) for row in rows]
|
|
85
|
+
# return result
|
|
86
|
+
# elif query_type == QueryTypes.ONE:
|
|
87
|
+
# columns = [desc[0] for desc in cursor.description]
|
|
88
|
+
# row = await cursor.fetchone()
|
|
89
|
+
# # print("rows_reuslt", rows)
|
|
90
|
+
# result = dict(zip(columns, row)) if row else {}
|
|
91
|
+
# return result
|
|
92
|
+
# elif query_type == QueryTypes.MANY:
|
|
93
|
+
# columns = [desc[0] for desc in cursor.description]
|
|
94
|
+
# rows = await cursor.fetchmany(size)
|
|
95
|
+
# result = [dict(zip(columns, row)) for row in rows]
|
|
96
|
+
# return result
|
|
97
|
+
# elif query_type == QueryTypes.COUNT:
|
|
98
|
+
# rs = await cursor.fetchone()
|
|
99
|
+
# return rs[0] if row else 0
|
|
100
|
+
# elif query_type == QueryTypes.CREATE:
|
|
101
|
+
# result = cursor.rowcount > 0
|
|
102
|
+
# id = cursor.lastrowid
|
|
103
|
+
# return result, id
|
|
104
|
+
# elif query_type == QueryTypes.CREATEBATCH:
|
|
105
|
+
# count = cursor.rowcount
|
|
106
|
+
# id = cursor.lastrowid
|
|
107
|
+
# return count, id
|
|
108
|
+
# elif query_type == QueryTypes.UPDATE:
|
|
109
|
+
# return cursor.rowcount > 0
|
|
110
|
+
# elif query_type == QueryTypes.UPDATEBATCH:
|
|
111
|
+
# return cursor.rowcount
|
|
112
|
+
# elif query_type == QueryTypes.DELETE:
|
|
113
|
+
# return cursor.rowcount > 0
|
|
114
|
+
|
|
115
|
+
# self.pool.release(cursor)
|
|
116
|
+
|
|
51
117
|
async def query(self, sql, params=None, query_type: QueryTypes = 2, size: int = 10):
|
|
52
118
|
sql = sql.replace("?", "%s").replace("`", "")
|
|
53
119
|
print_info("sql", sql, params)
|
|
@@ -55,16 +121,19 @@ class Postgres(MeteBase):
|
|
|
55
121
|
raise ValueError("must be create_engine first.")
|
|
56
122
|
if self.pool._closing or self.pool._closed:
|
|
57
123
|
return None
|
|
124
|
+
|
|
58
125
|
async with self.pool.acquire() as conn:
|
|
59
126
|
async with conn.cursor() as cursor:
|
|
60
127
|
# current_cursor = getattr(cursor, 'lastrowid', None)
|
|
61
|
-
|
|
128
|
+
if (
|
|
129
|
+
query_type == QueryTypes.CREATEBATCH
|
|
130
|
+
or query_type == QueryTypes.UPDATEBATCH
|
|
131
|
+
):
|
|
132
|
+
# aiopg don't support executemany
|
|
133
|
+
await cursor.executemany(sql, params)
|
|
134
|
+
else:
|
|
135
|
+
await cursor.execute(sql, params)
|
|
62
136
|
|
|
63
|
-
# if query_type.value > 4:
|
|
64
|
-
# if self.driver == "mysql":
|
|
65
|
-
# print(columns)
|
|
66
|
-
# await conn.commit()
|
|
67
|
-
# elif self.driver == "postgres":
|
|
68
137
|
result = None
|
|
69
138
|
|
|
70
139
|
if query_type == QueryTypes.ALL:
|
|
@@ -90,12 +159,18 @@ class Postgres(MeteBase):
|
|
|
90
159
|
result = cursor.rowcount > 0
|
|
91
160
|
id = cursor.lastrowid
|
|
92
161
|
return result, id
|
|
162
|
+
elif query_type == QueryTypes.CREATEBATCH:
|
|
163
|
+
count = cursor.rowcount
|
|
164
|
+
id = cursor.lastrowid
|
|
165
|
+
return count, id
|
|
93
166
|
elif query_type == QueryTypes.UPDATE:
|
|
94
167
|
return cursor.rowcount > 0
|
|
168
|
+
elif query_type == QueryTypes.UPDATEBATCH:
|
|
169
|
+
return cursor.rowcount
|
|
95
170
|
elif query_type == QueryTypes.DELETE:
|
|
96
171
|
return cursor.rowcount > 0
|
|
97
172
|
|
|
98
|
-
self.pool.release(
|
|
173
|
+
self.pool.release(cursor)
|
|
99
174
|
|
|
100
175
|
async def create_engine(self, **kw):
|
|
101
176
|
try:
|
|
@@ -104,17 +179,20 @@ class Postgres(MeteBase):
|
|
|
104
179
|
user = (kw.get("username"),)
|
|
105
180
|
password = (str(kw.get("password", "")),)
|
|
106
181
|
db = (kw.get("db"),)
|
|
107
|
-
dsn = f"dbname={db[0]} user={user[0]} password={password[0]} host={host[0]} port={port[0]}"
|
|
108
|
-
|
|
182
|
+
dsn = f"dbname={db[0]} user={user[0]} password={password[0]} host={host[0]} port={port[0]}" # aiopg
|
|
183
|
+
# dsn = f"postgres://{user[0]}:{password[0]}@{host[0]}:{port[0]}/{db[0]}" #asyncpg
|
|
184
|
+
self.pool = await pg.create_pool(
|
|
109
185
|
dsn=dsn,
|
|
110
186
|
timeout=kw.get("timeout"),
|
|
111
|
-
echo=kw.get("echo", False),
|
|
112
|
-
|
|
113
|
-
|
|
187
|
+
echo=kw.get("echo", False), # aiopg
|
|
188
|
+
# max_size=kw.get("maxsize", 10), #asyncpg
|
|
189
|
+
# min_size=kw.get("minsize", 5), #asyncpg
|
|
190
|
+
maxsize=kw.get("maxsize", 10), # aiopg
|
|
191
|
+
minsize=kw.get("minsize", 5), # aiopg
|
|
114
192
|
)
|
|
115
193
|
print_info(f"Database connection successfuly for postgres/{kw.get('db')}")
|
|
116
194
|
except Exception as e:
|
|
117
|
-
|
|
195
|
+
print_error(e)
|
|
118
196
|
# print(traceback.format_exc())
|
|
119
197
|
print_error(
|
|
120
198
|
f"Database connection failed,the instance : postgres/{kw.get('db')}"
|
|
@@ -148,7 +226,7 @@ class Mysql(MeteBase):
|
|
|
148
226
|
|
|
149
227
|
async def query(self, sql, params=None, query_type: QueryTypes = 2, size: int = 10):
|
|
150
228
|
sql = sql.replace("?", "%s")
|
|
151
|
-
print_info("sql", sql, params)
|
|
229
|
+
# print_info("sql", sql, params)
|
|
152
230
|
if not self.pool:
|
|
153
231
|
raise ValueError("must be create_engine first.")
|
|
154
232
|
if self.pool._closing or self.pool._closed:
|
|
@@ -156,7 +234,13 @@ class Mysql(MeteBase):
|
|
|
156
234
|
async with self.pool.acquire() as conn:
|
|
157
235
|
async with conn.cursor() as cursor:
|
|
158
236
|
# current_cursor = getattr(cursor, 'lastrowid', None)
|
|
159
|
-
|
|
237
|
+
if (
|
|
238
|
+
query_type == QueryTypes.CREATEBATCH
|
|
239
|
+
or query_type == QueryTypes.UPDATEBATCH
|
|
240
|
+
):
|
|
241
|
+
await cursor.executemany(sql, params)
|
|
242
|
+
else:
|
|
243
|
+
await cursor.execute(sql, params)
|
|
160
244
|
|
|
161
245
|
# if query_type.value > 4:
|
|
162
246
|
# if self.driver == "mysql":
|
|
@@ -180,8 +264,14 @@ class Mysql(MeteBase):
|
|
|
180
264
|
result = cursor.rowcount > 0
|
|
181
265
|
id = cursor.lastrowid
|
|
182
266
|
return result, id
|
|
267
|
+
elif query_type == QueryTypes.CREATEBATCH:
|
|
268
|
+
count = cursor.rowcount
|
|
269
|
+
id = cursor.lastrowid
|
|
270
|
+
return count, id
|
|
183
271
|
elif query_type == QueryTypes.UPDATE:
|
|
184
272
|
return cursor.rowcount > 0
|
|
273
|
+
elif query_type == QueryTypes.UPDATEBATCH:
|
|
274
|
+
return cursor.rowcount
|
|
185
275
|
elif query_type == QueryTypes.DELETE:
|
|
186
276
|
return cursor.rowcount > 0
|
|
187
277
|
|
|
@@ -199,7 +289,7 @@ class Mysql(MeteBase):
|
|
|
199
289
|
charset=kw.get("charset", "utf8"),
|
|
200
290
|
autocommit=False, # kw.get("autocommit", False),
|
|
201
291
|
maxsize=kw.get("maxsize", 10),
|
|
202
|
-
minsize=kw.get("
|
|
292
|
+
minsize=kw.get("minsize", 5),
|
|
203
293
|
cursorclass=AttrDictCursor,
|
|
204
294
|
loop=loop,
|
|
205
295
|
)
|
|
@@ -9,6 +9,8 @@ class QueryTypes(Enum):
|
|
|
9
9
|
CREATE = 5
|
|
10
10
|
UPDATE = 6
|
|
11
11
|
DELETE = 7
|
|
12
|
+
CREATEBATCH = 8
|
|
13
|
+
UPDATEBATCH = 9
|
|
12
14
|
|
|
13
15
|
|
|
14
16
|
class MeteBase:
|
|
@@ -60,9 +62,15 @@ class MeteBase:
|
|
|
60
62
|
|
|
61
63
|
async def update(self, sql, params):
|
|
62
64
|
return await self.query(sql, params, QueryTypes.UPDATE)
|
|
65
|
+
|
|
66
|
+
async def update_batch(self, sql, params):
|
|
67
|
+
return await self.query(sql, params, QueryTypes.UPDATEBATCH)
|
|
63
68
|
|
|
64
69
|
async def delete(self, sql, params):
|
|
65
70
|
return await self.query(sql, params, QueryTypes.DELETE)
|
|
66
71
|
|
|
67
72
|
async def create(self, sql, params):
|
|
68
73
|
return await self.query(sql, params, QueryTypes.CREATE)
|
|
74
|
+
|
|
75
|
+
async def create_batch(self, sql, params):
|
|
76
|
+
return await self.query(sql, params, QueryTypes.CREATEBATCH)
|
|
@@ -7,6 +7,8 @@ import re
|
|
|
7
7
|
import datetime
|
|
8
8
|
from ..utils.common import Object
|
|
9
9
|
|
|
10
|
+
__ALL__ = ("models", "Model")
|
|
11
|
+
|
|
10
12
|
|
|
11
13
|
class ModelMetaclass(type):
|
|
12
14
|
# def __init__(self, **kw):
|
|
@@ -197,9 +199,7 @@ class Model(metaclass=ModelMetaclass):
|
|
|
197
199
|
if isinstance(f, str):
|
|
198
200
|
by.append(f)
|
|
199
201
|
else:
|
|
200
|
-
by.append(
|
|
201
|
-
f"{f.lhs.name if self.__ispg else f.lhs.full_name} {f.op}"
|
|
202
|
-
)
|
|
202
|
+
by.append(f"{f.lhs.name if self.__ispg else f.lhs.full_name} {f.op}")
|
|
203
203
|
if self.__order_by__ is not None:
|
|
204
204
|
by = self.__order_by__ + by
|
|
205
205
|
self.__order_by__ = by
|
|
@@ -214,9 +214,8 @@ class Model(metaclass=ModelMetaclass):
|
|
|
214
214
|
self.__group_by__ = by
|
|
215
215
|
return self
|
|
216
216
|
|
|
217
|
-
def
|
|
217
|
+
def _format_data(self, action, args):
|
|
218
218
|
data = dict()
|
|
219
|
-
md = None
|
|
220
219
|
if args is None or not args:
|
|
221
220
|
for k in self.__fields__:
|
|
222
221
|
f = getattr(self, k)
|
|
@@ -226,15 +225,19 @@ class Model(metaclass=ModelMetaclass):
|
|
|
226
225
|
data = args
|
|
227
226
|
else:
|
|
228
227
|
for item in args:
|
|
229
|
-
md = item
|
|
230
228
|
if isinstance(item, Model):
|
|
231
229
|
for k in item.__dict__:
|
|
232
|
-
if (action ==
|
|
230
|
+
if (action == "u" and item[k].value) or action == "i":
|
|
233
231
|
data[k] = item[k]
|
|
234
232
|
|
|
235
233
|
else: # for object
|
|
236
234
|
for k, v in item.items():
|
|
237
235
|
data[k] = v
|
|
236
|
+
|
|
237
|
+
return data
|
|
238
|
+
|
|
239
|
+
def _get_update_key_args(self, action, args):
|
|
240
|
+
data = self._format_data(action, args)
|
|
238
241
|
keys = []
|
|
239
242
|
params = []
|
|
240
243
|
for k, v in data.items():
|
|
@@ -251,7 +254,48 @@ class Model(metaclass=ModelMetaclass):
|
|
|
251
254
|
elif v is not None: # fix sql format %s
|
|
252
255
|
keys.append("`%s`=?" % k)
|
|
253
256
|
params.append(v)
|
|
254
|
-
return ",".join(keys), params
|
|
257
|
+
return ",".join(keys), params
|
|
258
|
+
|
|
259
|
+
def _get_insert_key_args(self, action, args):
|
|
260
|
+
data = self._format_data(action, args)
|
|
261
|
+
keys = []
|
|
262
|
+
params = []
|
|
263
|
+
for k, v in data.items():
|
|
264
|
+
if isinstance(v, Field):
|
|
265
|
+
value = v.value
|
|
266
|
+
if value is None:
|
|
267
|
+
if v.created_generated == True or v.update_generated == True:
|
|
268
|
+
value = datetime.datetime.now()
|
|
269
|
+
else:
|
|
270
|
+
value = v.default
|
|
271
|
+
if value is not None:
|
|
272
|
+
keys.append(k)
|
|
273
|
+
params.append(value)
|
|
274
|
+
elif v is not None: # fix sql format %s
|
|
275
|
+
keys.append(k)
|
|
276
|
+
params.append(v)
|
|
277
|
+
return keys, params
|
|
278
|
+
|
|
279
|
+
def _get_batch_keys_values(self, items: list):
|
|
280
|
+
keys = []
|
|
281
|
+
values = []
|
|
282
|
+
item = items[0]
|
|
283
|
+
if isinstance(item, Model):
|
|
284
|
+
keys = item.__dict__.keys()
|
|
285
|
+
elif isinstance(item, dict):
|
|
286
|
+
keys = item.keys()
|
|
287
|
+
|
|
288
|
+
for item in items:
|
|
289
|
+
value = []
|
|
290
|
+
if isinstance(item, Model):
|
|
291
|
+
for k in item.__dict__:
|
|
292
|
+
value.append(item[k].value)
|
|
293
|
+
elif isinstance(item, dict): # for object
|
|
294
|
+
for k, v in item.items():
|
|
295
|
+
value.append(v)
|
|
296
|
+
value = tuple(key for key in value)
|
|
297
|
+
values.append(value)
|
|
298
|
+
return keys, values
|
|
255
299
|
|
|
256
300
|
def _merge_params(self, p):
|
|
257
301
|
if p is not None:
|
|
@@ -343,7 +387,7 @@ class Model(metaclass=ModelMetaclass):
|
|
|
343
387
|
# where = self.__where__
|
|
344
388
|
where = self._literal("WHERE", self.__where__)
|
|
345
389
|
|
|
346
|
-
keys, params
|
|
390
|
+
keys, params = self._get_update_key_args("u", args or kw)
|
|
347
391
|
|
|
348
392
|
sql = f"update `{table}` set {keys} {where}"
|
|
349
393
|
|
|
@@ -389,11 +433,21 @@ class Model(metaclass=ModelMetaclass):
|
|
|
389
433
|
|
|
390
434
|
async def insert(self, *args, **kw):
|
|
391
435
|
table = self.__table__
|
|
392
|
-
keys, params
|
|
393
|
-
sql = f"insert into `{table}`
|
|
436
|
+
keys, params = self._get_insert_key_args("i", args or kw)
|
|
437
|
+
sql = f"insert into `{table}` ({','.join(keys)}) values ({','.join(['?' for k in keys])})"
|
|
394
438
|
self._reset()
|
|
439
|
+
params = tuple(key for key in params)
|
|
395
440
|
return await self.__pool__.create(sql, params)
|
|
396
441
|
|
|
442
|
+
async def insert_batch(self, items: list):
|
|
443
|
+
table = self.__table__
|
|
444
|
+
if len(items) == 0:
|
|
445
|
+
return 0
|
|
446
|
+
keys, params = self._get_batch_keys_values(items)
|
|
447
|
+
sql = f"insert into `{table}` ({','.join(keys)}) values ({','.join(['?' for k in keys])})"
|
|
448
|
+
self._reset()
|
|
449
|
+
return await self.__pool__.create_batch(sql, params)
|
|
450
|
+
|
|
397
451
|
async def count(self):
|
|
398
452
|
__where__ = copy.copy(self.__where__)
|
|
399
453
|
__join__ = copy.copy(self.__join__)
|
|
@@ -5,7 +5,8 @@ __author__ = "chuchur/chuchur.com"
|
|
|
5
5
|
|
|
6
6
|
import hashlib, hmac, time, base64
|
|
7
7
|
from curl_cffi import requests as http
|
|
8
|
-
from ..logging import print_error,print_info
|
|
8
|
+
from ..logging import print_error, print_info
|
|
9
|
+
|
|
9
10
|
|
|
10
11
|
class Client(object):
|
|
11
12
|
def __init__(self, **kw):
|
|
@@ -253,7 +253,8 @@ def get_col_sql(field):
|
|
|
253
253
|
if field.primary_key:
|
|
254
254
|
sql += " PRIMARY KEY"
|
|
255
255
|
if field.auto_increment:
|
|
256
|
-
|
|
256
|
+
# todo: postgres SERIAL
|
|
257
|
+
sql += " AUTO_INCREMENT"
|
|
257
258
|
if field.NOT_NULL:
|
|
258
259
|
sql += " NOT NULL"
|
|
259
260
|
if field.default:
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
|
|
2
|
+
import time
|
|
3
|
+
import threading
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
"""
|
|
7
|
+
雪花算法(全局唯一id)
|
|
8
|
+
|
|
9
|
+
# 最早是Twitter公司在其内部用于分布式环境下生成唯一ID
|
|
10
|
+
|
|
11
|
+
# Twitter's Snowflake algorithm implementation which is used to generate distributed IDs.
|
|
12
|
+
|
|
13
|
+
# https://github.com/twitter-archive/snowflake/blob/snowflake-2010/src/main/scala/com/twitter/service/snowflake/IdWorker.scala
|
|
14
|
+
"""
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class IdWorker:
|
|
18
|
+
def __init__(self, worker_id, datacenter_id, sequence=0):
|
|
19
|
+
# 位移值
|
|
20
|
+
self.worker_id_bits = 5
|
|
21
|
+
self.datacenter_id_bits = 5
|
|
22
|
+
self.sequence_bits = 12
|
|
23
|
+
|
|
24
|
+
self.max_worker_id = -1 ^ (-1 << self.worker_id_bits)
|
|
25
|
+
self.max_datacenter_id = -1 ^ (-1 << self.datacenter_id_bits)
|
|
26
|
+
|
|
27
|
+
# 参数校验
|
|
28
|
+
if worker_id > self.max_worker_id or worker_id < 0:
|
|
29
|
+
raise ValueError(f'worker_id must be between 0 and {self.max_worker_id}')
|
|
30
|
+
if datacenter_id > self.max_datacenter_id or datacenter_id < 0:
|
|
31
|
+
raise ValueError(f'datacenter_id must be between 0 and {self.max_datacenter_id}')
|
|
32
|
+
|
|
33
|
+
self.worker_id = worker_id
|
|
34
|
+
self.datacenter_id = datacenter_id
|
|
35
|
+
self.sequence = sequence
|
|
36
|
+
self.lock = threading.Lock()
|
|
37
|
+
|
|
38
|
+
# Twitter Epoch (2010-11-04 01:42:54 UTC)
|
|
39
|
+
self.twepoch = 1288834974657
|
|
40
|
+
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
self.worker_id_shift = self.sequence_bits
|
|
45
|
+
self.datacenter_id_shift = self.sequence_bits + self.worker_id_bits
|
|
46
|
+
self.timestamp_left_shift = self.sequence_bits + self.worker_id_bits + self.datacenter_id_bits
|
|
47
|
+
self.sequence_mask = -1 ^ (-1 << self.sequence_bits)
|
|
48
|
+
|
|
49
|
+
self.last_timestamp = -1
|
|
50
|
+
|
|
51
|
+
def _time_gen(self):
|
|
52
|
+
return int(time.time() * 1000)
|
|
53
|
+
|
|
54
|
+
def _til_next_millis(self, last_timestamp):
|
|
55
|
+
timestamp = self._time_gen()
|
|
56
|
+
while timestamp <= last_timestamp:
|
|
57
|
+
timestamp = self._time_gen()
|
|
58
|
+
return timestamp
|
|
59
|
+
|
|
60
|
+
def next_id(self):
|
|
61
|
+
with self.lock:
|
|
62
|
+
timestamp = self._time_gen()
|
|
63
|
+
|
|
64
|
+
if timestamp < self.last_timestamp:
|
|
65
|
+
raise Exception(f'Clock moved backwards. Refusing to generate id for {self.last_timestamp - timestamp} milliseconds')
|
|
66
|
+
|
|
67
|
+
if self.last_timestamp == timestamp:
|
|
68
|
+
self.sequence = (self.sequence + 1) & self.sequence_mask
|
|
69
|
+
if self.sequence == 0:
|
|
70
|
+
timestamp = self._til_next_millis(self.last_timestamp)
|
|
71
|
+
else:
|
|
72
|
+
self.sequence = 0
|
|
73
|
+
|
|
74
|
+
self.last_timestamp = timestamp
|
|
75
|
+
|
|
76
|
+
id = ((timestamp - self.twepoch) << self.timestamp_left_shift) | \
|
|
77
|
+
(self.datacenter_id << self.datacenter_id_shift) | \
|
|
78
|
+
(self.worker_id << self.worker_id_shift) | \
|
|
79
|
+
self.sequence
|
|
80
|
+
|
|
81
|
+
return id
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
# 示例使用
|
|
85
|
+
worker = IdWorker(worker_id=1, datacenter_id=1)
|
|
86
|
+
print(worker.next_id())
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
__version__ = "2.2.23"
|
|
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
|
|
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
|
|
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
|
|
File without changes
|
|
File without changes
|
|
File without changes
|