jxORM 0.1.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.
jxORM/__init__.py ADDED
@@ -0,0 +1,10 @@
1
+
2
+ import os
3
+
4
+ os.makedirs("logs", exist_ok=True)
5
+
6
+ from .orm.jxUtils import set_host_id, logger as jxORMLogger
7
+ from .orm.orm import ORM, get_by_type_id, get_by_type_name, select
8
+ from .orm.common import DBDataType, ColType, jxDB, DBType, set_default_db, get_default_db, get_db, register_create_db
9
+
10
+ __all__ = ['set_host_id', 'jxORMLogger', 'ORM', 'select', 'DBDataType', 'ColType', 'jxDB', 'DBType', 'set_default_db', 'get_default_db', 'get_db', 'register_create_db', ]
jxORM/orm/__init__.py ADDED
@@ -0,0 +1,5 @@
1
+
2
+ import jxORM.orm.jxUtils
3
+ import jxORM.orm.common
4
+ import jxORM.orm.orm
5
+ import jxORM.orm.query
jxORM/orm/common.py ADDED
@@ -0,0 +1,426 @@
1
+ #!/usr/bin/python
2
+ # -*- coding: UTF-8 -*-
3
+
4
+ import traceback
5
+ import datetime
6
+ import json
7
+
8
+ from functools import wraps
9
+ from threading import RLock
10
+ import datetime
11
+ import enum
12
+
13
+ from jxORM.orm.jxUtils import logger, checkAssert, transValue2Datetime, transValue2Dict, transValue2String, stringAdd, trip_quotes
14
+
15
+ class DBType(enum.IntEnum):
16
+ No = 0
17
+ SQLite = 1
18
+ MySQL = 2
19
+
20
+ @classmethod
21
+ def from_string(cls, s):
22
+ if s == 'mysql':
23
+ return DBType.MySQL
24
+ if s == 'sqlite':
25
+ return DBType.SQLite
26
+ return DBType.No
27
+
28
+ class ColType(enum.IntEnum):
29
+ PrimaryKey = 0
30
+ Index = 1
31
+
32
+ class DBDataType(enum.IntEnum):
33
+ No = -1
34
+ Int = 1
35
+ Long = 2
36
+ Float = 3
37
+ Double = 4
38
+ Bool = 5
39
+ Chars = 6
40
+ String = 7
41
+ DataTime = 8
42
+ Json = 9
43
+
44
+ @classmethod
45
+ def from_string(cls, s):
46
+ if s == 'int':
47
+ return DBDataType.Int
48
+ if s == 'long':
49
+ return DBDataType.Long
50
+ if s == 'float':
51
+ return DBDataType.Float
52
+ if s == 'double':
53
+ return DBDataType.Double
54
+ if s == 'bool':
55
+ return DBDataType.Bool
56
+ if s == 'chars':
57
+ return DBDataType.Chars
58
+ if s == 'string':
59
+ return DBDataType.String
60
+ if s == 'datetime':
61
+ return DBDataType.DataTime
62
+ if s == 'json':
63
+ return DBDataType.Json
64
+ return DBDataType.No
65
+
66
+
67
+ _dbConfig = {}
68
+ _db_create_funcs = {}
69
+ _dbPool = {}
70
+ _db_name = None
71
+ def set_default_db(dbName):
72
+ global _db_name
73
+ _db_name = dbName
74
+ def get_default_dbname():
75
+ return _db_name
76
+ def register_create_db(db_type, func):
77
+ _db_create_funcs[db_type] = func
78
+ def get_ty(cl, attr):
79
+ for c in cl:
80
+ dt = c.get_ty_with_field(attr)
81
+ if dt is not None:
82
+ return dt
83
+ return None
84
+ def get_db_result(result_list, descriptions, cls_list:list, need_trans=True):
85
+ if result_list is None:
86
+ return None
87
+ if not need_trans or descriptions is None:
88
+ return result_list
89
+ column_names = [description[0] for description in descriptions]
90
+ rs = []
91
+ for r in result_list:
92
+ result = dict(zip(column_names, r))
93
+ d = {}
94
+ rs.append(d)
95
+ for k, v in result.items():
96
+ dt = get_ty(cls_list, k)
97
+ if dt is not None:
98
+ d[k] = transFromDB(dt, v)
99
+ continue
100
+ d[k] = v
101
+ return rs
102
+
103
+ def transFromDB(dt: DBDataType, dv):
104
+ if dt == DBDataType.Int:
105
+ return int(dv)
106
+ if dt == DBDataType.Long:
107
+ return int(dv)
108
+ if dt == DBDataType.Float:
109
+ return float(dv)
110
+ if dt == DBDataType.Double:
111
+ return float(dv)
112
+ if dt == DBDataType.Bool:
113
+ try:
114
+ return bool(dv)
115
+ except:
116
+ return False
117
+ if dt == DBDataType.String:
118
+ s = str(dv)
119
+ return trip_quotes(s)
120
+ if dt == DBDataType.Chars:
121
+ s = str(dv)
122
+ return trip_quotes(s)
123
+ if dt == DBDataType.DataTime:
124
+ if isinstance(dv, str):
125
+ dv = trip_quotes(dv)
126
+ return transValue2Datetime(dv)
127
+ if dt == DBDataType.Json:
128
+ if isinstance(dv, str):
129
+ dv = dv[1:-1]
130
+ return transValue2Dict(dv)
131
+ return None
132
+
133
+ def transToDB(dt: DBDataType, dv):
134
+ if dt == DBDataType.Int:
135
+ return int(dv)
136
+ if dt == DBDataType.Long:
137
+ return int(dv)
138
+ if dt == DBDataType.Float:
139
+ return float(dv)
140
+ if dt == DBDataType.Double:
141
+ return float(dv)
142
+ if dt == DBDataType.Bool:
143
+ try:
144
+ b = bool(dv)
145
+ if b:
146
+ return 1
147
+ return 0
148
+ except:
149
+ return 0
150
+ if dt == DBDataType.String:
151
+ return f'\"{str(dv)}\"'
152
+ if dt == DBDataType.Chars:
153
+ return f'\"{str(dv)}\"'
154
+ if dt == DBDataType.DataTime:
155
+ if isinstance(dv, datetime.datetime):
156
+ return f'\"{dv.strftime("%Y-%m-%d %H:%M:%S")}\"'
157
+ elif isinstance(dv, str):
158
+ return f'\"{dv}\"'
159
+ else:
160
+ try:
161
+ dv = int(dv)
162
+ dt = datetime.datetime.fromtimestamp(dv)
163
+ return f'\"{dt.strftime("%Y-%m-%d %H:%M:%S")}\"'
164
+ except:
165
+ return ''
166
+ if dt == DBDataType.Json:
167
+ s = json.dumps(dv)
168
+ return f"'{s}'"
169
+ return None
170
+
171
+ class jxDB:
172
+ @classmethod
173
+ def set(cls, dbName, type=DBType.MySQL, is_default=True, host='127.0.0.1', port=3306, user='root', password='root', **kwargs):
174
+ dc = jxDB(type=type, host=host, port=port, user=user, password=password)
175
+ dc.attrs = kwargs
176
+ _dbConfig[dbName] = dc
177
+ if is_default:
178
+ set_default_db(dbName)
179
+
180
+ def __init__(self, type=DBType.MySQL, host='127.0.0.1', port=3306, user='root', password='root'):
181
+ self.type = type
182
+ self.host = host
183
+ self.port = port
184
+ self.user = user
185
+ self.password = password
186
+ self.attrs = {}
187
+
188
+ class DB_interface:
189
+ def __init__(self):
190
+ self.conn = None
191
+ self.cursor = None
192
+ self._name = None
193
+
194
+ def type(self):
195
+ # 数据库类型
196
+ return None
197
+
198
+ def name(self):
199
+ # 数据库类型
200
+ return self._name
201
+
202
+ def need_trans(self):
203
+ return False
204
+
205
+ def description(self):
206
+ return None
207
+
208
+ def _get_create_table_sql(self, table_name, fields, keys, indexs):
209
+ return []
210
+ def create_table(self, table_name, fields, keys, indexs):
211
+ sl = self._get_create_table_sql(table_name, fields, keys, indexs)
212
+ for sql in sl:
213
+ self.execute(sql)
214
+
215
+ def commit(self):
216
+ self.conn.commit()
217
+
218
+ def get_db_type(self, ty):
219
+ return ''
220
+
221
+ def rollback(self):
222
+ self.conn.rollback()
223
+
224
+ def execute(self, sql):
225
+ logger.info(f'execute sql:{sql}')
226
+ return self.cursor.execute(sql)
227
+
228
+ def fetchone(self):
229
+ return self.cursor.fetchone()
230
+
231
+ def fetchall(self):
232
+ return self.cursor.fetchall()
233
+
234
+ def trans2String(self, vt, v):
235
+ return transValue2String(vt, v, withQuote=True, to_db=True)
236
+
237
+ def transaction(self):
238
+ return DB_interface._transaction(self)
239
+
240
+ def __enter__(self):
241
+ if self.conn is not None:
242
+ self.cursor = self.conn.cursor()
243
+ self.conn.begin()
244
+ return self
245
+
246
+ def __exit__(self, type, value, trace):
247
+ if self.conn is not None:
248
+ self.cursor.close()
249
+ self.conn.close()
250
+
251
+ class _transaction:
252
+ def __init__(self, db):
253
+ self.db = db
254
+ def __enter__(self):
255
+ self.db.__enter__()
256
+ def __exit__(self, type, value, trace):
257
+ if type is None:
258
+ self.db.commit()
259
+ else:
260
+ self.db.rollback()
261
+ self.db.__exit__(type, value, trace)
262
+
263
+ class DB_mysql(DB_interface):
264
+ def __init__(self, dbname):
265
+ super().__init__()
266
+ self._name = dbname
267
+ self._pool = _dbPool.get(dbname)
268
+ if self._pool is None:
269
+ dc = _dbConfig.get(dbname)
270
+ import pymysql
271
+ from dbutils.pooled_db import PooledDB
272
+ config = {
273
+ 'creator': pymysql,
274
+ 'host': dc.host,
275
+ 'port': dc.port,
276
+ 'user': dc.user,
277
+ 'password': dc.password,
278
+ 'db': dbname,
279
+ 'charset': "utf8",
280
+ 'cursorclass': pymysql.cursors.DictCursor
281
+ }
282
+ config.update(dc.attrs)
283
+ self._pool = PooledDB(**config)
284
+ _dbPool[dbname] = self._pool
285
+ self.conn = self._pool.connection()
286
+
287
+ def type(self):
288
+ # 数据库类型
289
+ return 'mysql'
290
+
291
+ def get_db_type(self, ty):
292
+ if ty == DBDataType.Int:
293
+ return 'int'
294
+ if ty == DBDataType.Long:
295
+ return 'bigint'
296
+ if ty == DBDataType.Float:
297
+ return 'float'
298
+ if ty == DBDataType.Double:
299
+ return 'double'
300
+ if ty == DBDataType.Bool:
301
+ return 'tinyint'
302
+ if ty == DBDataType.Chars:
303
+ return 'varchar(126)'
304
+ if ty == DBDataType.String:
305
+ return 'mediumtext'
306
+ if ty == DBDataType.DataTime:
307
+ return 'datetime'
308
+ if ty == DBDataType.Json:
309
+ return 'mediumtext'
310
+ return 'mediumtext'
311
+
312
+ def _get_create_table_sql(self, table_name, fields, keys, indexs):
313
+ rs = []
314
+ fl = {}
315
+ pk = None
316
+ il = []
317
+ for k, dt in fields.items():
318
+ fs = f'`{k}` {self.get_db_type(dt)} NOT NULL'
319
+ fl[k] = fs
320
+ if len(keys) > 0:
321
+ ks = None
322
+ for k in keys:
323
+ ks = stringAdd(ks, f'`{k}`', ',')
324
+ pk = f'PRIMARY KEY ({ks})'
325
+ if len(indexs) > 0:
326
+ for i, ins in indexs.items():
327
+ ifs = None
328
+ for ikn in ins:
329
+ ifs = stringAdd(ifs, f'`{ikn}`', ',')
330
+ tis = f'KEY `{table_name}_index_{i}` ({ifs})'
331
+ il.append(tis)
332
+ fs = ','.join(fl.values())
333
+ fs = stringAdd(fs, pk, ',')
334
+ ils = ','.join(il)
335
+ fs = stringAdd(fs, ils, ',')
336
+ cs = f'CREATE TABLE `{table_name}` ({fs}) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_0900_ai_ci;'
337
+ rs.append(cs)
338
+ return rs
339
+
340
+ class DB_sqlite(DB_interface):
341
+ def __init__(self, dbname):
342
+ super().__init__()
343
+ self._name = dbname
344
+ self._pool = _dbPool.get(dbname)
345
+ if self._pool is None:
346
+ import sqlite3
347
+ from dbutils.pooled_db import PooledDB
348
+ config = {
349
+ 'creator': sqlite3,
350
+ 'mincached': 5,
351
+ 'maxcached': 30,
352
+ 'check_same_thread': False,
353
+ 'database': f'{dbname}.db',
354
+ }
355
+ self._pool = PooledDB(**config)
356
+ _dbPool[dbname] = self._pool
357
+ self.conn = self._pool.connection()
358
+
359
+ def type(self):
360
+ # 数据库类型
361
+ return 'sqlite'
362
+
363
+ def need_trans(self):
364
+ return True
365
+
366
+ def description(self):
367
+ return self.cursor.description
368
+
369
+ def get_db_type(self, ty):
370
+ if ty in [DBDataType.Int, DBDataType.Long, DBDataType.Float, DBDataType.Double,DBDataType.Bool]:
371
+ return 'INTEGER'
372
+ return 'TEXT'
373
+
374
+ def _get_create_table_sql(self, table_name, fields, keys, indexs):
375
+ rs = []
376
+ fl = {}
377
+ for k, dt in fields.items():
378
+ fs = f'`{k}` {self.get_db_type(dt)} NOT NULL'
379
+ fl[k] = fs
380
+ for k in keys:
381
+ fs = fl.get(k, None)
382
+ fs += ' PRIMARY KEY'
383
+ fl[k] = fs
384
+ fls = ','.join(fl.values())
385
+ cs = f'CREATE TABLE `{table_name}` ({fls});'
386
+ rs.append(cs)
387
+
388
+ for i, il in indexs.items():
389
+ fs = None
390
+ for ikn in il:
391
+ fs = stringAdd(fs, f'`{ikn}`', ',')
392
+ cis = f'CREATE INDEX {table_name}_index_{i} ON {table_name} ({fs});'
393
+ rs.append(cis)
394
+ return rs
395
+
396
+ def get_default_db():
397
+ return get_db(_db_name)
398
+
399
+ def get_db(dbname=None):
400
+ if dbname is None:
401
+ dbname = _db_name
402
+ if dbname is not None:
403
+ dc = _dbConfig.get(dbname)
404
+ if dc is not None:
405
+ func = _db_create_funcs.get(dc.type, None)
406
+ if func is not None:
407
+ return func(dbname)
408
+ return None
409
+
410
+ def DB(func):
411
+ @wraps(func)
412
+ def wrapper(obj, dbname, *args, **kw):
413
+ db = get_db(dbname)
414
+ checkAssert(not db is None, '数据库未配置:{}', dbname)
415
+ with db:
416
+ try:
417
+ result = func(obj, db, *args, **kw)
418
+ db.commit()
419
+ return result
420
+ except Exception as e:
421
+ db.rollback()
422
+ raise e
423
+ return wrapper
424
+
425
+ register_create_db(DBType.MySQL, lambda dbname:DB_mysql(dbname))
426
+ register_create_db(DBType.SQLite, lambda dbname:DB_sqlite(dbname))