MySQLX 2.1.1__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.
- mysqlx-2.1.1/PKG-INFO +182 -0
- mysqlx-2.1.1/README.rst +167 -0
- mysqlx-2.1.1/mysqlx/__init__.py +41 -0
- mysqlx-2.1.1/mysqlx/db.py +8 -0
- mysqlx-2.1.1/mysqlx/dbx.py +2 -0
- mysqlx-2.1.1/mysqlx/log_support.py +14 -0
- mysqlx-2.1.1/mysqlx/orm.py +142 -0
- mysqlx-2.1.1/mysqlx.egg-info/PKG-INFO +182 -0
- mysqlx-2.1.1/mysqlx.egg-info/SOURCES.txt +13 -0
- mysqlx-2.1.1/mysqlx.egg-info/dependency_links.txt +1 -0
- mysqlx-2.1.1/mysqlx.egg-info/not-zip-safe +1 -0
- mysqlx-2.1.1/mysqlx.egg-info/requires.txt +1 -0
- mysqlx-2.1.1/mysqlx.egg-info/top_level.txt +1 -0
- mysqlx-2.1.1/setup.cfg +4 -0
- mysqlx-2.1.1/setup.py +38 -0
mysqlx-2.1.1/PKG-INFO
ADDED
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: mysqlx
|
|
3
|
+
Version: 2.1.1
|
|
4
|
+
Summary: A thread safe sql executor for MySQL like MyBatis with connection pool. It helps you automatically manage database connections and transactions. It also provides ORM operations for single tables.
|
|
5
|
+
Home-page: https://gitee.com/summry/mysqlx
|
|
6
|
+
Author: summy
|
|
7
|
+
Author-email: xiazhongbiao@126.com
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Keywords: sql,MySQL,MyBatis,python
|
|
10
|
+
Platform: UNKNOWN
|
|
11
|
+
Requires-Python: >=3.5
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
Mapper file
|
|
15
|
+
'''''''''''
|
|
16
|
+
|
|
17
|
+
Create a mapper file in 'mapper' folder, you can named
|
|
18
|
+
'user_mapper.xml', like follow:
|
|
19
|
+
|
|
20
|
+
.. code:: xml
|
|
21
|
+
|
|
22
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
23
|
+
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://gitee.com/summry/mysqlx/blob/master/dtd/mapper.dtd">
|
|
24
|
+
<mapper namespace="user">
|
|
25
|
+
<select id="select_all">
|
|
26
|
+
select id, name, age from user
|
|
27
|
+
</select>
|
|
28
|
+
|
|
29
|
+
<select id="select_by_name">
|
|
30
|
+
select id, name, age from user where name = ?
|
|
31
|
+
</select>
|
|
32
|
+
|
|
33
|
+
<select id="select_by_name2">
|
|
34
|
+
select id, name, age from user where name = :name
|
|
35
|
+
</select>
|
|
36
|
+
|
|
37
|
+
<select id="select_include" include="select_all">
|
|
38
|
+
{{ select_all }}
|
|
39
|
+
{% if name -%}
|
|
40
|
+
where name = :name
|
|
41
|
+
{%- endif -%}
|
|
42
|
+
</select>
|
|
43
|
+
</mapper>
|
|
44
|
+
|
|
45
|
+
Usage Sample
|
|
46
|
+
''''''''''''
|
|
47
|
+
|
|
48
|
+
.. code:: python
|
|
49
|
+
|
|
50
|
+
from mysqlx.orm import Model
|
|
51
|
+
from typing import List, Tuple, Mapping
|
|
52
|
+
from mysqlx import mapper, sql, db, dbx, init_db
|
|
53
|
+
|
|
54
|
+
@mapper(namespace='user')
|
|
55
|
+
def select_all(): List
|
|
56
|
+
|
|
57
|
+
@mapper(namespace='user')
|
|
58
|
+
def select_by_name(name: str): List
|
|
59
|
+
|
|
60
|
+
@mapper(namespace='user')
|
|
61
|
+
def select_by_name2(name: str): List
|
|
62
|
+
|
|
63
|
+
@mapper(namespace='user')
|
|
64
|
+
def select_include(name: str): List
|
|
65
|
+
|
|
66
|
+
@sql('select id, name, age from user where name = ?')
|
|
67
|
+
def query_by_name(name: str): List(Mapping)
|
|
68
|
+
|
|
69
|
+
@sql('select id, name, age from user where name = :name')
|
|
70
|
+
def query_by_name2(name: str): List(Mapping)
|
|
71
|
+
|
|
72
|
+
if __name__ == '__main__':
|
|
73
|
+
init_db(host='127.0.0.1', port='3306', user='xxx', password='xxx', database='test', pool_size=5, show_sql=True, mapper_path='./mapper')
|
|
74
|
+
|
|
75
|
+
users = select_all()
|
|
76
|
+
# result:
|
|
77
|
+
# (3, 'zhangsan', 15)
|
|
78
|
+
# (4, 'lisi', 26)
|
|
79
|
+
# (5, 'wangwu', 38)
|
|
80
|
+
|
|
81
|
+
users = select_by_name('zhangsan')
|
|
82
|
+
# result:
|
|
83
|
+
# (3, 'zhangsan', 15)
|
|
84
|
+
|
|
85
|
+
users = select_by_name2(name='zhangsan')
|
|
86
|
+
# result:
|
|
87
|
+
# (3, 'zhangsan', 15)
|
|
88
|
+
|
|
89
|
+
users = select_include(name='zhangsan')
|
|
90
|
+
# result:
|
|
91
|
+
# (3, 'zhangsan', 15)
|
|
92
|
+
|
|
93
|
+
users = query_by_name('zhangsan')
|
|
94
|
+
# result:
|
|
95
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
96
|
+
|
|
97
|
+
users = query_by_name2(name='zhangsan')
|
|
98
|
+
# result:
|
|
99
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
100
|
+
|
|
101
|
+
# you can use dbx execte mapper sql with full sql id: namespace join sql id
|
|
102
|
+
users = dbx.select('user.select_all') # 'user' is namespace, 'select_all' is sql id
|
|
103
|
+
# result:
|
|
104
|
+
# (3, 'zhangsan', 15)
|
|
105
|
+
# (4, 'lisi', 26)
|
|
106
|
+
# (5, 'wangwu', 38)
|
|
107
|
+
|
|
108
|
+
users = dbx.select('user.select_by_name', name='zhangsan')
|
|
109
|
+
# result:
|
|
110
|
+
# (3, 'zhangsan', 15)
|
|
111
|
+
|
|
112
|
+
users = dbx.sql('user.select_by_name').select(name='zhangsan')
|
|
113
|
+
# result:
|
|
114
|
+
# (3, 'zhangsan', 15)
|
|
115
|
+
|
|
116
|
+
# you can direct execute sql with db
|
|
117
|
+
effected_rowcount = db.insert(table='user', name='zhaoliu', age=66)
|
|
118
|
+
|
|
119
|
+
users = db.select('select id, name, age from user')
|
|
120
|
+
# result:
|
|
121
|
+
# (3, 'zhangsan', 15)
|
|
122
|
+
# (4, 'lisi', 26)
|
|
123
|
+
# (5, 'wangwu', 38)
|
|
124
|
+
|
|
125
|
+
users = db.query('select id, name, age from user name = :name', name='zhangsan')
|
|
126
|
+
# result:
|
|
127
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
128
|
+
|
|
129
|
+
users = db.sql('select id, name, age from user name = :name').query(name='zhangsan')
|
|
130
|
+
# result:
|
|
131
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
132
|
+
|
|
133
|
+
# you can use orm to operate a single table
|
|
134
|
+
class User(Model):
|
|
135
|
+
__key__ = 'id'
|
|
136
|
+
__table__ = 'user'
|
|
137
|
+
|
|
138
|
+
def __init__(self, id: int = None, name: str = None, age: int = None):
|
|
139
|
+
self.id = id
|
|
140
|
+
self.name = name
|
|
141
|
+
self.age = age
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
effected_rowcount = User.insert(name='tianqi', age=77)
|
|
145
|
+
|
|
146
|
+
users = User.query(name='tianqi')
|
|
147
|
+
# select id, name, age from user where name = :name
|
|
148
|
+
# result:
|
|
149
|
+
# {'id': 7, 'name': 'tianqi', 'age': 77}
|
|
150
|
+
|
|
151
|
+
users = User.query(name__eq='zhangsan')
|
|
152
|
+
# select id, name, age from user where name = :name
|
|
153
|
+
# result:
|
|
154
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
155
|
+
|
|
156
|
+
Transaction
|
|
157
|
+
'''''''''''
|
|
158
|
+
|
|
159
|
+
.. code:: python
|
|
160
|
+
|
|
161
|
+
from mysqlx import with_transaction, transaction
|
|
162
|
+
|
|
163
|
+
@with_transaction
|
|
164
|
+
def test_transaction():
|
|
165
|
+
insert_func(....)
|
|
166
|
+
update_func(....)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_transaction2():
|
|
170
|
+
with transaction():
|
|
171
|
+
insert_func(....)
|
|
172
|
+
update_func(....)
|
|
173
|
+
|
|
174
|
+
You can generate model class with mysqlx-generator: https://pypi.org/project/mysqlx-generator
|
|
175
|
+
|
|
176
|
+
If you want to operate PostgreSQL database, may be you need PgSqlx: https://pypi.org/project/pgsqlx
|
|
177
|
+
|
|
178
|
+
If you just wanted a simple sql executor, may be you need sqlx-exec: https://pypi.org/project/sqlx-exec
|
|
179
|
+
|
|
180
|
+
If you wanted simultaneously support MySQL and PostgreSQL, may be you need sqlx-batis: https://pypi.org/project/sqlx-batis
|
|
181
|
+
|
|
182
|
+
|
mysqlx-2.1.1/README.rst
ADDED
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
Mapper file
|
|
2
|
+
'''''''''''
|
|
3
|
+
|
|
4
|
+
Create a mapper file in 'mapper' folder, you can named
|
|
5
|
+
'user_mapper.xml', like follow:
|
|
6
|
+
|
|
7
|
+
.. code:: xml
|
|
8
|
+
|
|
9
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
10
|
+
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://gitee.com/summry/mysqlx/blob/master/dtd/mapper.dtd">
|
|
11
|
+
<mapper namespace="user">
|
|
12
|
+
<select id="select_all">
|
|
13
|
+
select id, name, age from user
|
|
14
|
+
</select>
|
|
15
|
+
|
|
16
|
+
<select id="select_by_name">
|
|
17
|
+
select id, name, age from user where name = ?
|
|
18
|
+
</select>
|
|
19
|
+
|
|
20
|
+
<select id="select_by_name2">
|
|
21
|
+
select id, name, age from user where name = :name
|
|
22
|
+
</select>
|
|
23
|
+
|
|
24
|
+
<select id="select_include" include="select_all">
|
|
25
|
+
{{ select_all }}
|
|
26
|
+
{% if name -%}
|
|
27
|
+
where name = :name
|
|
28
|
+
{%- endif -%}
|
|
29
|
+
</select>
|
|
30
|
+
</mapper>
|
|
31
|
+
|
|
32
|
+
Usage Sample
|
|
33
|
+
''''''''''''
|
|
34
|
+
|
|
35
|
+
.. code:: python
|
|
36
|
+
|
|
37
|
+
from mysqlx.orm import Model
|
|
38
|
+
from typing import List, Tuple, Mapping
|
|
39
|
+
from mysqlx import mapper, sql, db, dbx, init_db
|
|
40
|
+
|
|
41
|
+
@mapper(namespace='user')
|
|
42
|
+
def select_all(): List
|
|
43
|
+
|
|
44
|
+
@mapper(namespace='user')
|
|
45
|
+
def select_by_name(name: str): List
|
|
46
|
+
|
|
47
|
+
@mapper(namespace='user')
|
|
48
|
+
def select_by_name2(name: str): List
|
|
49
|
+
|
|
50
|
+
@mapper(namespace='user')
|
|
51
|
+
def select_include(name: str): List
|
|
52
|
+
|
|
53
|
+
@sql('select id, name, age from user where name = ?')
|
|
54
|
+
def query_by_name(name: str): List(Mapping)
|
|
55
|
+
|
|
56
|
+
@sql('select id, name, age from user where name = :name')
|
|
57
|
+
def query_by_name2(name: str): List(Mapping)
|
|
58
|
+
|
|
59
|
+
if __name__ == '__main__':
|
|
60
|
+
init_db(host='127.0.0.1', port='3306', user='xxx', password='xxx', database='test', pool_size=5, show_sql=True, mapper_path='./mapper')
|
|
61
|
+
|
|
62
|
+
users = select_all()
|
|
63
|
+
# result:
|
|
64
|
+
# (3, 'zhangsan', 15)
|
|
65
|
+
# (4, 'lisi', 26)
|
|
66
|
+
# (5, 'wangwu', 38)
|
|
67
|
+
|
|
68
|
+
users = select_by_name('zhangsan')
|
|
69
|
+
# result:
|
|
70
|
+
# (3, 'zhangsan', 15)
|
|
71
|
+
|
|
72
|
+
users = select_by_name2(name='zhangsan')
|
|
73
|
+
# result:
|
|
74
|
+
# (3, 'zhangsan', 15)
|
|
75
|
+
|
|
76
|
+
users = select_include(name='zhangsan')
|
|
77
|
+
# result:
|
|
78
|
+
# (3, 'zhangsan', 15)
|
|
79
|
+
|
|
80
|
+
users = query_by_name('zhangsan')
|
|
81
|
+
# result:
|
|
82
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
83
|
+
|
|
84
|
+
users = query_by_name2(name='zhangsan')
|
|
85
|
+
# result:
|
|
86
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
87
|
+
|
|
88
|
+
# you can use dbx execte mapper sql with full sql id: namespace join sql id
|
|
89
|
+
users = dbx.select('user.select_all') # 'user' is namespace, 'select_all' is sql id
|
|
90
|
+
# result:
|
|
91
|
+
# (3, 'zhangsan', 15)
|
|
92
|
+
# (4, 'lisi', 26)
|
|
93
|
+
# (5, 'wangwu', 38)
|
|
94
|
+
|
|
95
|
+
users = dbx.select('user.select_by_name', name='zhangsan')
|
|
96
|
+
# result:
|
|
97
|
+
# (3, 'zhangsan', 15)
|
|
98
|
+
|
|
99
|
+
users = dbx.sql('user.select_by_name').select(name='zhangsan')
|
|
100
|
+
# result:
|
|
101
|
+
# (3, 'zhangsan', 15)
|
|
102
|
+
|
|
103
|
+
# you can direct execute sql with db
|
|
104
|
+
effected_rowcount = db.insert(table='user', name='zhaoliu', age=66)
|
|
105
|
+
|
|
106
|
+
users = db.select('select id, name, age from user')
|
|
107
|
+
# result:
|
|
108
|
+
# (3, 'zhangsan', 15)
|
|
109
|
+
# (4, 'lisi', 26)
|
|
110
|
+
# (5, 'wangwu', 38)
|
|
111
|
+
|
|
112
|
+
users = db.query('select id, name, age from user name = :name', name='zhangsan')
|
|
113
|
+
# result:
|
|
114
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
115
|
+
|
|
116
|
+
users = db.sql('select id, name, age from user name = :name').query(name='zhangsan')
|
|
117
|
+
# result:
|
|
118
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
119
|
+
|
|
120
|
+
# you can use orm to operate a single table
|
|
121
|
+
class User(Model):
|
|
122
|
+
__key__ = 'id'
|
|
123
|
+
__table__ = 'user'
|
|
124
|
+
|
|
125
|
+
def __init__(self, id: int = None, name: str = None, age: int = None):
|
|
126
|
+
self.id = id
|
|
127
|
+
self.name = name
|
|
128
|
+
self.age = age
|
|
129
|
+
|
|
130
|
+
|
|
131
|
+
effected_rowcount = User.insert(name='tianqi', age=77)
|
|
132
|
+
|
|
133
|
+
users = User.query(name='tianqi')
|
|
134
|
+
# select id, name, age from user where name = :name
|
|
135
|
+
# result:
|
|
136
|
+
# {'id': 7, 'name': 'tianqi', 'age': 77}
|
|
137
|
+
|
|
138
|
+
users = User.query(name__eq='zhangsan')
|
|
139
|
+
# select id, name, age from user where name = :name
|
|
140
|
+
# result:
|
|
141
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
142
|
+
|
|
143
|
+
Transaction
|
|
144
|
+
'''''''''''
|
|
145
|
+
|
|
146
|
+
.. code:: python
|
|
147
|
+
|
|
148
|
+
from mysqlx import with_transaction, transaction
|
|
149
|
+
|
|
150
|
+
@with_transaction
|
|
151
|
+
def test_transaction():
|
|
152
|
+
insert_func(....)
|
|
153
|
+
update_func(....)
|
|
154
|
+
|
|
155
|
+
|
|
156
|
+
def test_transaction2():
|
|
157
|
+
with transaction():
|
|
158
|
+
insert_func(....)
|
|
159
|
+
update_func(....)
|
|
160
|
+
|
|
161
|
+
You can generate model class with mysqlx-generator: https://pypi.org/project/mysqlx-generator
|
|
162
|
+
|
|
163
|
+
If you want to operate PostgreSQL database, may be you need PgSqlx: https://pypi.org/project/pgsqlx
|
|
164
|
+
|
|
165
|
+
If you just wanted a simple sql executor, may be you need sqlx-exec: https://pypi.org/project/sqlx-exec
|
|
166
|
+
|
|
167
|
+
If you wanted simultaneously support MySQL and PostgreSQL, may be you need sqlx-batis: https://pypi.org/project/sqlx-batis
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
from sqlbatis import (
|
|
2
|
+
connection,
|
|
3
|
+
transaction,
|
|
4
|
+
with_connection,
|
|
5
|
+
with_transaction,
|
|
6
|
+
get_connection,
|
|
7
|
+
close,
|
|
8
|
+
Driver,
|
|
9
|
+
sql,
|
|
10
|
+
mapper,
|
|
11
|
+
init_snowflake,
|
|
12
|
+
get_snowflake_id,
|
|
13
|
+
init_db as _init_db
|
|
14
|
+
)
|
|
15
|
+
from sqlexec import Dialect, Engine
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
def init_db(*args, **kwargs):
|
|
19
|
+
"""
|
|
20
|
+
Compliant with the Python DB API 2.0 (PEP-249).
|
|
21
|
+
|
|
22
|
+
from mysqlx import init_db
|
|
23
|
+
init_db('test.db', driver='sqlite3', show_sql=True, debug=True)
|
|
24
|
+
or
|
|
25
|
+
init_db("postgres://user:password@127.0.0.1:5432/testdb", mapper_path='./mapper', driver='psycopg2', pool_size=5, show_sql=True, debug=True)
|
|
26
|
+
or
|
|
27
|
+
init_db(user='root', password='xxx', host='127.0.0.1', port=3306, database='testdb', mapper_path='./mapper', driver='pymysql', pool_size=5, show_sql=True, debug=True)
|
|
28
|
+
|
|
29
|
+
Addition parameters:
|
|
30
|
+
:param mapper_path: str, path of mapper files
|
|
31
|
+
:param driver=None: str, import driver, 'import pymysql'
|
|
32
|
+
:param pool_size=0: int, default 0, size of connection pool
|
|
33
|
+
:param show_sql=False: bool, if True, print sql
|
|
34
|
+
:param debug=False: bool, if True, print debug context
|
|
35
|
+
:param trans_placeholder=True: bool, if True, sql placeholder '?' --> '%s'
|
|
36
|
+
|
|
37
|
+
Other parameters of connection pool refer to DBUtils: https://webwareforpython.github.io/DBUtils/main.html#pooleddb-pooled-db
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
Dialect.init(Engine.MYSQL)
|
|
41
|
+
_init_db(*args, **kwargs)
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
|
|
2
|
+
# Don't remove. Import for not repetitive implementation
|
|
3
|
+
from sqlbatis.db import insert, save, save_sql, execute, batch_insert, batch_execute, get, query, query_one, select, select_one, do_execute,\
|
|
4
|
+
do_save_sql, do_get, do_query, do_query_one, do_select, do_select_one, do_query_page, do_select_page, query_page, select_page, sql, page, table,\
|
|
5
|
+
drop, truncate
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
# Don't remove. Import for not repetitive implementation
|
|
2
|
+
from sqlbatis.log_support import logger
|
|
3
|
+
|
|
4
|
+
|
|
5
|
+
def save_log(table, **kwargs):
|
|
6
|
+
logger.debug("Exec func 'mysqlx.db.save' \n\t Table: '%s', kwargs: %s" % (table, kwargs))
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def sql_id_log(function: str, sql_id: str, *args, **kwargs):
|
|
10
|
+
logger.debug("Exec func 'mysqlx.dbx.%s', sql_id: %s, args: %s, kwargs: %s" % (function, sql_id.strip(), args, kwargs))
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def orm_insert_log(function, class_name, **kwargs):
|
|
14
|
+
logger.debug("Exec func 'mysqlx.orm.Model.%s' \n\t Class: '%s', kwargs: %s" % (function, class_name, kwargs))
|
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
from datetime import datetime
|
|
2
|
+
from . import get_snowflake_id
|
|
3
|
+
from typing import Union, Sequence
|
|
4
|
+
from sqlbatis.constant import LIMIT_1
|
|
5
|
+
from .db import insert, do_execute, save
|
|
6
|
+
from .log_support import orm_insert_log, logger
|
|
7
|
+
import warnings
|
|
8
|
+
|
|
9
|
+
# Don't remove. Import for not repetitive implementation
|
|
10
|
+
from sqlbatis.orm import DelFlag, KeyStrategy, Model as BaseModel
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Model(BaseModel):
|
|
14
|
+
"""
|
|
15
|
+
Create a class extends Model:
|
|
16
|
+
|
|
17
|
+
class Person(Model):
|
|
18
|
+
__key__ = 'id'
|
|
19
|
+
__table__ = 'person'
|
|
20
|
+
__update_by__ = 'update_by'
|
|
21
|
+
__update_time__ = 'update_time'
|
|
22
|
+
__del_flag__ = 'del_flag'
|
|
23
|
+
|
|
24
|
+
def __init__(self, id: int = None, name: str = None, age: int = None, update_by: int = None, update_time: datetime = None, del_flag: int = None):
|
|
25
|
+
self.id = id
|
|
26
|
+
|
|
27
|
+
self.update_by = update_by
|
|
28
|
+
self.update_time = update_time
|
|
29
|
+
self.del_flag = del_flag
|
|
30
|
+
self.name = name
|
|
31
|
+
self.age = age
|
|
32
|
+
|
|
33
|
+
then you can use like follow:
|
|
34
|
+
init_db(person='xxx', password='xxx', database='xxx', host='xxx', ...) # or dbx.init_db(...) init db first,
|
|
35
|
+
person = Person(name='张三', age=55)
|
|
36
|
+
effect_rowcount = person.persist()
|
|
37
|
+
id = person.inst_save()
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
@classmethod
|
|
41
|
+
def save(cls, **kwargs):
|
|
42
|
+
"""
|
|
43
|
+
id = Person.save(name='张三', age=20)
|
|
44
|
+
:return: Primary key
|
|
45
|
+
"""
|
|
46
|
+
orm_insert_log('save', cls.__name__, **kwargs)
|
|
47
|
+
key, table = cls._get_key_and_table()
|
|
48
|
+
if key in kwargs:
|
|
49
|
+
insert(table, **kwargs)
|
|
50
|
+
return kwargs[key]
|
|
51
|
+
|
|
52
|
+
key_strategy = cls._get_key_strategy()
|
|
53
|
+
if key_strategy == KeyStrategy.SNOWFLAKE:
|
|
54
|
+
kwargs[key] = get_snowflake_id()
|
|
55
|
+
insert(table, **kwargs)
|
|
56
|
+
return kwargs[key]
|
|
57
|
+
else:
|
|
58
|
+
return save(table, **kwargs)
|
|
59
|
+
|
|
60
|
+
@classmethod
|
|
61
|
+
def update_by_id(cls, _id: Union[int, str], **kwargs):
|
|
62
|
+
"""
|
|
63
|
+
rowcount = User.update_by_id(id=1, name='王五')
|
|
64
|
+
return: Effect rowcount
|
|
65
|
+
"""
|
|
66
|
+
logger.debug("Exec func 'mysqlx.orm.Model.%s' \n\t Class: '%s', id: %d, kwargs: %s" % ('update_by_id', cls.__name__, _id, kwargs))
|
|
67
|
+
assert kwargs, 'Must set update kv'
|
|
68
|
+
key = cls._get_key()
|
|
69
|
+
where = '`%s` = ?' % key
|
|
70
|
+
cols, args = zip(*kwargs.items())
|
|
71
|
+
sql, update_time_arg = cls._update_sql(where, *cols)
|
|
72
|
+
if update_time_arg:
|
|
73
|
+
args = [*args, update_time_arg]
|
|
74
|
+
return do_execute(sql, *args, _id, LIMIT_1)
|
|
75
|
+
|
|
76
|
+
@classmethod
|
|
77
|
+
def delete_by_id(cls, _id: Union[int, str]):
|
|
78
|
+
"""
|
|
79
|
+
Physical delete
|
|
80
|
+
rowcount = User.delete_by_id(id=1)
|
|
81
|
+
return: Effect rowcount
|
|
82
|
+
"""
|
|
83
|
+
logger.debug("Exec func 'mysqlx.orm.Model.%s' \n\t Class: '%s', id: %d" % ('delete_by_id', cls.__name__, _id))
|
|
84
|
+
key, table = cls._get_key_and_table()
|
|
85
|
+
sql = 'DELETE FROM `%s` WHERE `%s` = ? LIMIT ?' % (table, key)
|
|
86
|
+
return do_execute(sql, _id, LIMIT_1)
|
|
87
|
+
|
|
88
|
+
@classmethod
|
|
89
|
+
def _update_sql(cls, where, *update_fields):
|
|
90
|
+
update_time_arg = None
|
|
91
|
+
table = cls.get_table()
|
|
92
|
+
update_time_field = cls._get_update_time_field()
|
|
93
|
+
if update_time_field is not None and update_time_field not in update_fields:
|
|
94
|
+
update_fields = [*update_fields, update_time_field]
|
|
95
|
+
update_time_arg = datetime.now()
|
|
96
|
+
|
|
97
|
+
update_fields = ','.join(['`{}` = ?'.format(col) for col in update_fields])
|
|
98
|
+
return 'UPDATE `{}` SET {} WHERE {} LIMIT ?'.format(table, update_fields, where), update_time_arg
|
|
99
|
+
|
|
100
|
+
@classmethod
|
|
101
|
+
def _logical_delete_by_id_op(cls, _id: Union[int, str], update_by: Union[int, str] = None, del_status=DelFlag.DELETED):
|
|
102
|
+
key, table = cls._get_key_and_table()
|
|
103
|
+
del_flag_field = cls._get_del_flag_field()
|
|
104
|
+
update_by_field = cls._get_update_by_field()
|
|
105
|
+
|
|
106
|
+
where = '`%s` = ?' % key
|
|
107
|
+
if update_by is not None and update_by_field is not None:
|
|
108
|
+
sql, update_time_arg = cls._update_sql(where, del_flag_field, update_by_field)
|
|
109
|
+
if update_time_arg:
|
|
110
|
+
return do_execute(sql, del_status.value, update_by, update_time_arg, _id, LIMIT_1)
|
|
111
|
+
return do_execute(sql, del_status.value, update_by, _id, LIMIT_1)
|
|
112
|
+
else:
|
|
113
|
+
sql, update_time_arg = cls._update_sql(where, del_flag_field)
|
|
114
|
+
if update_time_arg:
|
|
115
|
+
return do_execute(sql, del_status.value, update_time_arg, _id, LIMIT_1)
|
|
116
|
+
return do_execute(sql, del_status.value, _id, LIMIT_1)
|
|
117
|
+
|
|
118
|
+
@classmethod
|
|
119
|
+
def _do_logical_delete_by_ids(cls, ids: Union[Sequence[int], Sequence[str]], update_by: Union[int, str] = None, del_status=DelFlag.DELETED):
|
|
120
|
+
ids_size = len(ids)
|
|
121
|
+
key = cls._get_key()
|
|
122
|
+
del_flag_field = cls._get_del_flag_field()
|
|
123
|
+
update_by_field = cls._get_update_by_field()
|
|
124
|
+
|
|
125
|
+
where = '`%s` in (%s)' % (key, ','.join(['?' for _ in range(ids_size)]))
|
|
126
|
+
if update_by is not None and update_by_field is not None:
|
|
127
|
+
sql, update_time_arg = cls._update_sql(where, del_flag_field, update_by_field)
|
|
128
|
+
if update_time_arg:
|
|
129
|
+
return do_execute(sql, del_status.value, update_by, update_time_arg, *ids, ids_size)
|
|
130
|
+
return do_execute(sql, del_status.value, update_by, *ids, ids_size)
|
|
131
|
+
else:
|
|
132
|
+
sql, update_time_arg = cls._update_sql(where, del_flag_field)
|
|
133
|
+
if update_time_arg:
|
|
134
|
+
return do_execute(sql, del_status.value, update_time_arg, *ids, ids_size)
|
|
135
|
+
return do_execute(sql, del_status.value, *ids, ids_size)
|
|
136
|
+
|
|
137
|
+
@classmethod
|
|
138
|
+
def _delete_by_ids(cls, ids: Union[Sequence[int], Sequence[str]]):
|
|
139
|
+
ids_size = len(ids)
|
|
140
|
+
key, table = cls._get_key_and_table()
|
|
141
|
+
sql = 'DELETE FROM `{}` WHERE `{}` in ({}) LIMIT ?'.format(table, key, ','.join(['?' for _ in range(ids_size)]))
|
|
142
|
+
return do_execute(sql, *ids, ids_size)
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: mysqlx
|
|
3
|
+
Version: 2.1.1
|
|
4
|
+
Summary: A thread safe sql executor for MySQL like MyBatis with connection pool. It helps you automatically manage database connections and transactions. It also provides ORM operations for single tables.
|
|
5
|
+
Home-page: https://gitee.com/summry/mysqlx
|
|
6
|
+
Author: summy
|
|
7
|
+
Author-email: xiazhongbiao@126.com
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Keywords: sql,MySQL,MyBatis,python
|
|
10
|
+
Platform: UNKNOWN
|
|
11
|
+
Requires-Python: >=3.5
|
|
12
|
+
Description-Content-Type: text/markdown
|
|
13
|
+
|
|
14
|
+
Mapper file
|
|
15
|
+
'''''''''''
|
|
16
|
+
|
|
17
|
+
Create a mapper file in 'mapper' folder, you can named
|
|
18
|
+
'user_mapper.xml', like follow:
|
|
19
|
+
|
|
20
|
+
.. code:: xml
|
|
21
|
+
|
|
22
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
23
|
+
<!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "https://gitee.com/summry/mysqlx/blob/master/dtd/mapper.dtd">
|
|
24
|
+
<mapper namespace="user">
|
|
25
|
+
<select id="select_all">
|
|
26
|
+
select id, name, age from user
|
|
27
|
+
</select>
|
|
28
|
+
|
|
29
|
+
<select id="select_by_name">
|
|
30
|
+
select id, name, age from user where name = ?
|
|
31
|
+
</select>
|
|
32
|
+
|
|
33
|
+
<select id="select_by_name2">
|
|
34
|
+
select id, name, age from user where name = :name
|
|
35
|
+
</select>
|
|
36
|
+
|
|
37
|
+
<select id="select_include" include="select_all">
|
|
38
|
+
{{ select_all }}
|
|
39
|
+
{% if name -%}
|
|
40
|
+
where name = :name
|
|
41
|
+
{%- endif -%}
|
|
42
|
+
</select>
|
|
43
|
+
</mapper>
|
|
44
|
+
|
|
45
|
+
Usage Sample
|
|
46
|
+
''''''''''''
|
|
47
|
+
|
|
48
|
+
.. code:: python
|
|
49
|
+
|
|
50
|
+
from mysqlx.orm import Model
|
|
51
|
+
from typing import List, Tuple, Mapping
|
|
52
|
+
from mysqlx import mapper, sql, db, dbx, init_db
|
|
53
|
+
|
|
54
|
+
@mapper(namespace='user')
|
|
55
|
+
def select_all(): List
|
|
56
|
+
|
|
57
|
+
@mapper(namespace='user')
|
|
58
|
+
def select_by_name(name: str): List
|
|
59
|
+
|
|
60
|
+
@mapper(namespace='user')
|
|
61
|
+
def select_by_name2(name: str): List
|
|
62
|
+
|
|
63
|
+
@mapper(namespace='user')
|
|
64
|
+
def select_include(name: str): List
|
|
65
|
+
|
|
66
|
+
@sql('select id, name, age from user where name = ?')
|
|
67
|
+
def query_by_name(name: str): List(Mapping)
|
|
68
|
+
|
|
69
|
+
@sql('select id, name, age from user where name = :name')
|
|
70
|
+
def query_by_name2(name: str): List(Mapping)
|
|
71
|
+
|
|
72
|
+
if __name__ == '__main__':
|
|
73
|
+
init_db(host='127.0.0.1', port='3306', user='xxx', password='xxx', database='test', pool_size=5, show_sql=True, mapper_path='./mapper')
|
|
74
|
+
|
|
75
|
+
users = select_all()
|
|
76
|
+
# result:
|
|
77
|
+
# (3, 'zhangsan', 15)
|
|
78
|
+
# (4, 'lisi', 26)
|
|
79
|
+
# (5, 'wangwu', 38)
|
|
80
|
+
|
|
81
|
+
users = select_by_name('zhangsan')
|
|
82
|
+
# result:
|
|
83
|
+
# (3, 'zhangsan', 15)
|
|
84
|
+
|
|
85
|
+
users = select_by_name2(name='zhangsan')
|
|
86
|
+
# result:
|
|
87
|
+
# (3, 'zhangsan', 15)
|
|
88
|
+
|
|
89
|
+
users = select_include(name='zhangsan')
|
|
90
|
+
# result:
|
|
91
|
+
# (3, 'zhangsan', 15)
|
|
92
|
+
|
|
93
|
+
users = query_by_name('zhangsan')
|
|
94
|
+
# result:
|
|
95
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
96
|
+
|
|
97
|
+
users = query_by_name2(name='zhangsan')
|
|
98
|
+
# result:
|
|
99
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
100
|
+
|
|
101
|
+
# you can use dbx execte mapper sql with full sql id: namespace join sql id
|
|
102
|
+
users = dbx.select('user.select_all') # 'user' is namespace, 'select_all' is sql id
|
|
103
|
+
# result:
|
|
104
|
+
# (3, 'zhangsan', 15)
|
|
105
|
+
# (4, 'lisi', 26)
|
|
106
|
+
# (5, 'wangwu', 38)
|
|
107
|
+
|
|
108
|
+
users = dbx.select('user.select_by_name', name='zhangsan')
|
|
109
|
+
# result:
|
|
110
|
+
# (3, 'zhangsan', 15)
|
|
111
|
+
|
|
112
|
+
users = dbx.sql('user.select_by_name').select(name='zhangsan')
|
|
113
|
+
# result:
|
|
114
|
+
# (3, 'zhangsan', 15)
|
|
115
|
+
|
|
116
|
+
# you can direct execute sql with db
|
|
117
|
+
effected_rowcount = db.insert(table='user', name='zhaoliu', age=66)
|
|
118
|
+
|
|
119
|
+
users = db.select('select id, name, age from user')
|
|
120
|
+
# result:
|
|
121
|
+
# (3, 'zhangsan', 15)
|
|
122
|
+
# (4, 'lisi', 26)
|
|
123
|
+
# (5, 'wangwu', 38)
|
|
124
|
+
|
|
125
|
+
users = db.query('select id, name, age from user name = :name', name='zhangsan')
|
|
126
|
+
# result:
|
|
127
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
128
|
+
|
|
129
|
+
users = db.sql('select id, name, age from user name = :name').query(name='zhangsan')
|
|
130
|
+
# result:
|
|
131
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
132
|
+
|
|
133
|
+
# you can use orm to operate a single table
|
|
134
|
+
class User(Model):
|
|
135
|
+
__key__ = 'id'
|
|
136
|
+
__table__ = 'user'
|
|
137
|
+
|
|
138
|
+
def __init__(self, id: int = None, name: str = None, age: int = None):
|
|
139
|
+
self.id = id
|
|
140
|
+
self.name = name
|
|
141
|
+
self.age = age
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
effected_rowcount = User.insert(name='tianqi', age=77)
|
|
145
|
+
|
|
146
|
+
users = User.query(name='tianqi')
|
|
147
|
+
# select id, name, age from user where name = :name
|
|
148
|
+
# result:
|
|
149
|
+
# {'id': 7, 'name': 'tianqi', 'age': 77}
|
|
150
|
+
|
|
151
|
+
users = User.query(name__eq='zhangsan')
|
|
152
|
+
# select id, name, age from user where name = :name
|
|
153
|
+
# result:
|
|
154
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
155
|
+
|
|
156
|
+
Transaction
|
|
157
|
+
'''''''''''
|
|
158
|
+
|
|
159
|
+
.. code:: python
|
|
160
|
+
|
|
161
|
+
from mysqlx import with_transaction, transaction
|
|
162
|
+
|
|
163
|
+
@with_transaction
|
|
164
|
+
def test_transaction():
|
|
165
|
+
insert_func(....)
|
|
166
|
+
update_func(....)
|
|
167
|
+
|
|
168
|
+
|
|
169
|
+
def test_transaction2():
|
|
170
|
+
with transaction():
|
|
171
|
+
insert_func(....)
|
|
172
|
+
update_func(....)
|
|
173
|
+
|
|
174
|
+
You can generate model class with mysqlx-generator: https://pypi.org/project/mysqlx-generator
|
|
175
|
+
|
|
176
|
+
If you want to operate PostgreSQL database, may be you need PgSqlx: https://pypi.org/project/pgsqlx
|
|
177
|
+
|
|
178
|
+
If you just wanted a simple sql executor, may be you need sqlx-exec: https://pypi.org/project/sqlx-exec
|
|
179
|
+
|
|
180
|
+
If you wanted simultaneously support MySQL and PostgreSQL, may be you need sqlx-batis: https://pypi.org/project/sqlx-batis
|
|
181
|
+
|
|
182
|
+
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
README.rst
|
|
2
|
+
setup.py
|
|
3
|
+
mysqlx/__init__.py
|
|
4
|
+
mysqlx/db.py
|
|
5
|
+
mysqlx/dbx.py
|
|
6
|
+
mysqlx/log_support.py
|
|
7
|
+
mysqlx/orm.py
|
|
8
|
+
mysqlx.egg-info/PKG-INFO
|
|
9
|
+
mysqlx.egg-info/SOURCES.txt
|
|
10
|
+
mysqlx.egg-info/dependency_links.txt
|
|
11
|
+
mysqlx.egg-info/not-zip-safe
|
|
12
|
+
mysqlx.egg-info/requires.txt
|
|
13
|
+
mysqlx.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
sqlx-batis>=2.1.1
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mysqlx
|
mysqlx-2.1.1/setup.cfg
ADDED
mysqlx-2.1.1/setup.py
ADDED
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
import os
|
|
2
|
+
from setuptools import setup
|
|
3
|
+
|
|
4
|
+
# INSTALL_PACKAGES = open(path.join(DIR, 'requirements.txt')).read().splitlines()
|
|
5
|
+
def read(rel_path: str) -> str:
|
|
6
|
+
here = os.path.abspath(os.path.dirname(__file__))
|
|
7
|
+
# intentionally *not* adding an encoding option to open, See:
|
|
8
|
+
# https://github.com/pypa/virtualenv/issues/201#issuecomment-3145690
|
|
9
|
+
with open(os.path.join(here, rel_path), 'r', encoding='UTF-8') as fp:
|
|
10
|
+
return fp.read()
|
|
11
|
+
|
|
12
|
+
long_description = read("README.rst")
|
|
13
|
+
|
|
14
|
+
setup(
|
|
15
|
+
name='mysqlx',
|
|
16
|
+
packages=['mysqlx'],
|
|
17
|
+
description="A thread safe sql executor for MySQL like MyBatis with connection pool. It helps you automatically manage database connections and transactions. It also provides ORM operations for single tables.",
|
|
18
|
+
long_description=long_description,
|
|
19
|
+
long_description_content_type='text/markdown',
|
|
20
|
+
install_requires=[
|
|
21
|
+
# 'Jinja2>=2.7.0',
|
|
22
|
+
'sqlx-batis>=2.1.1',
|
|
23
|
+
# 'mysql-connector-python>=8.0.13',
|
|
24
|
+
],
|
|
25
|
+
version='2.1.1',
|
|
26
|
+
url='https://gitee.com/summry/mysqlx',
|
|
27
|
+
author='summy',
|
|
28
|
+
author_email='xiazhongbiao@126.com',
|
|
29
|
+
keywords=['sql', 'MySQL', 'MyBatis', 'python'],
|
|
30
|
+
package_data={
|
|
31
|
+
# include json and txt files
|
|
32
|
+
'': ['*.rst', '*.dtd', '*.tpl'],
|
|
33
|
+
},
|
|
34
|
+
include_package_data=True,
|
|
35
|
+
python_requires='>=3.5',
|
|
36
|
+
zip_safe=False
|
|
37
|
+
)
|
|
38
|
+
|