BatisX 2.2.0__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.
- batisx-2.2.0/PKG-INFO +165 -0
- batisx-2.2.0/README.rst +150 -0
- batisx-2.2.0/batisx/__init__.py +13 -0
- batisx-2.2.0/batisx/db.py +33 -0
- batisx-2.2.0/batisx/dbx.py +32 -0
- batisx-2.2.0/batisx/log_support.py +13 -0
- batisx-2.2.0/batisx/sql_id_exec.py +25 -0
- batisx-2.2.0/batisx/sql_mapper.py +82 -0
- batisx-2.2.0/batisx/sql_page_exec.py +12 -0
- batisx-2.2.0/batisx.egg-info/PKG-INFO +165 -0
- batisx-2.2.0/batisx.egg-info/SOURCES.txt +15 -0
- batisx-2.2.0/batisx.egg-info/dependency_links.txt +1 -0
- batisx-2.2.0/batisx.egg-info/not-zip-safe +1 -0
- batisx-2.2.0/batisx.egg-info/requires.txt +1 -0
- batisx-2.2.0/batisx.egg-info/top_level.txt +1 -0
- batisx-2.2.0/setup.cfg +4 -0
- batisx-2.2.0/setup.py +36 -0
batisx-2.2.0/PKG-INFO
ADDED
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: batisx
|
|
3
|
+
Version: 2.2.0
|
|
4
|
+
Summary: A thread safe sql executor for Python 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/sqlx-batis
|
|
6
|
+
Author: summy
|
|
7
|
+
Author-email: xiazhongbiao@126.com
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Keywords: sql,MySQL,PostgreSQL,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
|
+
'person_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/sqlx-batis/blob/master/dtd/mapper.dtd">
|
|
24
|
+
<mapper namespace="person">
|
|
25
|
+
<select id="select_all">
|
|
26
|
+
select id, name, age from person
|
|
27
|
+
</select>
|
|
28
|
+
|
|
29
|
+
<select id="select_by_name">
|
|
30
|
+
select id, name, age from person where name = ?
|
|
31
|
+
</select>
|
|
32
|
+
|
|
33
|
+
<select id="select_by_name2">
|
|
34
|
+
select id, name, age from person 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 typing import List, Tuple, Mapping
|
|
51
|
+
from batisx import mapper, sql, dbx, init_db
|
|
52
|
+
|
|
53
|
+
@mapper(namespace='person')
|
|
54
|
+
def select_all(): List
|
|
55
|
+
|
|
56
|
+
@mapper(namespace='person')
|
|
57
|
+
def select_by_name(name: str): List
|
|
58
|
+
|
|
59
|
+
@mapper(namespace='person')
|
|
60
|
+
def select_by_name2(name: str): List
|
|
61
|
+
|
|
62
|
+
@mapper(namespace='person')
|
|
63
|
+
def select_include(name: str): List
|
|
64
|
+
|
|
65
|
+
@sql('select id, name, age from person where name = ?')
|
|
66
|
+
def query_by_name(name: str): List(Mapping)
|
|
67
|
+
|
|
68
|
+
@sql('select id, name, age from person where name = :name')
|
|
69
|
+
def query_by_name2(name: str): List(Mapping)
|
|
70
|
+
|
|
71
|
+
if __name__ == '__main__':
|
|
72
|
+
# init_db('test.db', driver='sqlite3', show_sql=True, debug=True, mapper_path='./mapper')
|
|
73
|
+
# init_db("postgres://user:password@127.0.0.1:5432/testdb", driver='psycopg2', pool_size=5, mapper_path='./mapper')
|
|
74
|
+
init_db(host='127.0.0.1', port='3306', user='xxx', password='xxx', database='test', pool_size=5, show_sql=True, mapper_path='./mapper')
|
|
75
|
+
|
|
76
|
+
persons = select_all()
|
|
77
|
+
# result:
|
|
78
|
+
# (3, 'zhangsan', 15)
|
|
79
|
+
# (4, 'lisi', 26)
|
|
80
|
+
# (5, 'wangwu', 38)
|
|
81
|
+
|
|
82
|
+
persons = select_by_name('zhangsan')
|
|
83
|
+
# result:
|
|
84
|
+
# (3, 'zhangsan', 15)
|
|
85
|
+
|
|
86
|
+
persons = select_by_name2(name='zhangsan')
|
|
87
|
+
# result:
|
|
88
|
+
# (3, 'zhangsan', 15)
|
|
89
|
+
|
|
90
|
+
persons = select_include(name='zhangsan')
|
|
91
|
+
# result:
|
|
92
|
+
# (3, 'zhangsan', 15)
|
|
93
|
+
|
|
94
|
+
persons = query_by_name('zhangsan')
|
|
95
|
+
# result:
|
|
96
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
97
|
+
|
|
98
|
+
persons = query_by_name2(name='zhangsan')
|
|
99
|
+
# result:
|
|
100
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
101
|
+
|
|
102
|
+
# you can use dbx execute mapper sql with full sql id: namespace join sql id
|
|
103
|
+
persons = dbx.select('person.select_all') # 'person' is namespace, 'select_all' is sql id
|
|
104
|
+
# result:
|
|
105
|
+
# (3, 'zhangsan', 15)
|
|
106
|
+
# (4, 'lisi', 26)
|
|
107
|
+
# (5, 'wangwu', 38)
|
|
108
|
+
|
|
109
|
+
persons = dbx.select('person.select_by_name', name='zhangsan')
|
|
110
|
+
# result:
|
|
111
|
+
# (3, 'zhangsan', 15)
|
|
112
|
+
|
|
113
|
+
persons = dbx.sql('person.select_by_name').select(name='zhangsan')
|
|
114
|
+
# result:
|
|
115
|
+
# (3, 'zhangsan', 15)
|
|
116
|
+
|
|
117
|
+
# you can direct execute sql with db
|
|
118
|
+
effected_rowcount = db.insert(table='person', name='zhaoliu', age=66)
|
|
119
|
+
|
|
120
|
+
persons = db.select('select id, name, age from person')
|
|
121
|
+
# result:
|
|
122
|
+
# (3, 'zhangsan', 15)
|
|
123
|
+
# (4, 'lisi', 26)
|
|
124
|
+
# (5, 'wangwu', 38)
|
|
125
|
+
# (6, 'zhaoliu', 45)
|
|
126
|
+
|
|
127
|
+
persons = db.query('select id, name, age from person name = :name', name='zhangsan')
|
|
128
|
+
# result:
|
|
129
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
130
|
+
|
|
131
|
+
persons = db.sql('select id, name, age from person name = :name').query(name='zhangsan')
|
|
132
|
+
# result:
|
|
133
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
134
|
+
|
|
135
|
+
persons = db.select('select id, name, age from person where name = ?', 'zhangsan')
|
|
136
|
+
# result:
|
|
137
|
+
# [(3, 'zhangsan', 15)]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
Transaction
|
|
141
|
+
'''''''''''
|
|
142
|
+
|
|
143
|
+
.. code:: python
|
|
144
|
+
|
|
145
|
+
from batisx import with_transaction, transaction
|
|
146
|
+
|
|
147
|
+
@with_transaction
|
|
148
|
+
def test_transaction():
|
|
149
|
+
insert_func(....)
|
|
150
|
+
update_func(....)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_transaction2():
|
|
154
|
+
with transaction():
|
|
155
|
+
insert_func(....)
|
|
156
|
+
update_func(....)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
If you want to operate MySQL database, may be you need MySqlx: https://pypi.org/project/mysqlx
|
|
160
|
+
|
|
161
|
+
If you want to operate PostgreSQL database, may be you need MySqlx: https://pypi.org/project/pgsqlx
|
|
162
|
+
|
|
163
|
+
If you just wanted a simple sql executor, may be you need sqlx-exec: https://pypi.org/project/sqlx-exec
|
|
164
|
+
|
|
165
|
+
|
batisx-2.2.0/README.rst
ADDED
|
@@ -0,0 +1,150 @@
|
|
|
1
|
+
Mapper file
|
|
2
|
+
'''''''''''
|
|
3
|
+
|
|
4
|
+
Create a mapper file in 'mapper' folder, you can named
|
|
5
|
+
'person_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/sqlx-batis/blob/master/dtd/mapper.dtd">
|
|
11
|
+
<mapper namespace="person">
|
|
12
|
+
<select id="select_all">
|
|
13
|
+
select id, name, age from person
|
|
14
|
+
</select>
|
|
15
|
+
|
|
16
|
+
<select id="select_by_name">
|
|
17
|
+
select id, name, age from person where name = ?
|
|
18
|
+
</select>
|
|
19
|
+
|
|
20
|
+
<select id="select_by_name2">
|
|
21
|
+
select id, name, age from person 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 typing import List, Tuple, Mapping
|
|
38
|
+
from batisx import mapper, sql, dbx, init_db
|
|
39
|
+
|
|
40
|
+
@mapper(namespace='person')
|
|
41
|
+
def select_all(): List
|
|
42
|
+
|
|
43
|
+
@mapper(namespace='person')
|
|
44
|
+
def select_by_name(name: str): List
|
|
45
|
+
|
|
46
|
+
@mapper(namespace='person')
|
|
47
|
+
def select_by_name2(name: str): List
|
|
48
|
+
|
|
49
|
+
@mapper(namespace='person')
|
|
50
|
+
def select_include(name: str): List
|
|
51
|
+
|
|
52
|
+
@sql('select id, name, age from person where name = ?')
|
|
53
|
+
def query_by_name(name: str): List(Mapping)
|
|
54
|
+
|
|
55
|
+
@sql('select id, name, age from person where name = :name')
|
|
56
|
+
def query_by_name2(name: str): List(Mapping)
|
|
57
|
+
|
|
58
|
+
if __name__ == '__main__':
|
|
59
|
+
# init_db('test.db', driver='sqlite3', show_sql=True, debug=True, mapper_path='./mapper')
|
|
60
|
+
# init_db("postgres://user:password@127.0.0.1:5432/testdb", driver='psycopg2', pool_size=5, mapper_path='./mapper')
|
|
61
|
+
init_db(host='127.0.0.1', port='3306', user='xxx', password='xxx', database='test', pool_size=5, show_sql=True, mapper_path='./mapper')
|
|
62
|
+
|
|
63
|
+
persons = select_all()
|
|
64
|
+
# result:
|
|
65
|
+
# (3, 'zhangsan', 15)
|
|
66
|
+
# (4, 'lisi', 26)
|
|
67
|
+
# (5, 'wangwu', 38)
|
|
68
|
+
|
|
69
|
+
persons = select_by_name('zhangsan')
|
|
70
|
+
# result:
|
|
71
|
+
# (3, 'zhangsan', 15)
|
|
72
|
+
|
|
73
|
+
persons = select_by_name2(name='zhangsan')
|
|
74
|
+
# result:
|
|
75
|
+
# (3, 'zhangsan', 15)
|
|
76
|
+
|
|
77
|
+
persons = select_include(name='zhangsan')
|
|
78
|
+
# result:
|
|
79
|
+
# (3, 'zhangsan', 15)
|
|
80
|
+
|
|
81
|
+
persons = query_by_name('zhangsan')
|
|
82
|
+
# result:
|
|
83
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
84
|
+
|
|
85
|
+
persons = query_by_name2(name='zhangsan')
|
|
86
|
+
# result:
|
|
87
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
88
|
+
|
|
89
|
+
# you can use dbx execute mapper sql with full sql id: namespace join sql id
|
|
90
|
+
persons = dbx.select('person.select_all') # 'person' is namespace, 'select_all' is sql id
|
|
91
|
+
# result:
|
|
92
|
+
# (3, 'zhangsan', 15)
|
|
93
|
+
# (4, 'lisi', 26)
|
|
94
|
+
# (5, 'wangwu', 38)
|
|
95
|
+
|
|
96
|
+
persons = dbx.select('person.select_by_name', name='zhangsan')
|
|
97
|
+
# result:
|
|
98
|
+
# (3, 'zhangsan', 15)
|
|
99
|
+
|
|
100
|
+
persons = dbx.sql('person.select_by_name').select(name='zhangsan')
|
|
101
|
+
# result:
|
|
102
|
+
# (3, 'zhangsan', 15)
|
|
103
|
+
|
|
104
|
+
# you can direct execute sql with db
|
|
105
|
+
effected_rowcount = db.insert(table='person', name='zhaoliu', age=66)
|
|
106
|
+
|
|
107
|
+
persons = db.select('select id, name, age from person')
|
|
108
|
+
# result:
|
|
109
|
+
# (3, 'zhangsan', 15)
|
|
110
|
+
# (4, 'lisi', 26)
|
|
111
|
+
# (5, 'wangwu', 38)
|
|
112
|
+
# (6, 'zhaoliu', 45)
|
|
113
|
+
|
|
114
|
+
persons = db.query('select id, name, age from person name = :name', name='zhangsan')
|
|
115
|
+
# result:
|
|
116
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
117
|
+
|
|
118
|
+
persons = db.sql('select id, name, age from person name = :name').query(name='zhangsan')
|
|
119
|
+
# result:
|
|
120
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
121
|
+
|
|
122
|
+
persons = db.select('select id, name, age from person where name = ?', 'zhangsan')
|
|
123
|
+
# result:
|
|
124
|
+
# [(3, 'zhangsan', 15)]
|
|
125
|
+
|
|
126
|
+
|
|
127
|
+
Transaction
|
|
128
|
+
'''''''''''
|
|
129
|
+
|
|
130
|
+
.. code:: python
|
|
131
|
+
|
|
132
|
+
from batisx import with_transaction, transaction
|
|
133
|
+
|
|
134
|
+
@with_transaction
|
|
135
|
+
def test_transaction():
|
|
136
|
+
insert_func(....)
|
|
137
|
+
update_func(....)
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
def test_transaction2():
|
|
141
|
+
with transaction():
|
|
142
|
+
insert_func(....)
|
|
143
|
+
update_func(....)
|
|
144
|
+
|
|
145
|
+
|
|
146
|
+
If you want to operate MySQL database, may be you need MySqlx: https://pypi.org/project/mysqlx
|
|
147
|
+
|
|
148
|
+
If you want to operate PostgreSQL database, may be you need MySqlx: https://pypi.org/project/pgsqlx
|
|
149
|
+
|
|
150
|
+
If you just wanted a simple sql executor, may be you need sqlx-exec: https://pypi.org/project/sqlx-exec
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
from mysqlx import sql_support
|
|
2
|
+
# Don't remove. Import for not repetitive implementation
|
|
3
|
+
from sqlexecx import save_select_key, do_save_sql_select_key
|
|
4
|
+
from mysqlx.db import insert, save, execute, batch_insert, batch_execute, get, query, query_one, select, select_one, \
|
|
5
|
+
do_execute, do_get, do_query, do_query_one, do_select, do_select_one, do_select_page, do_query_page, select_page, query_page,\
|
|
6
|
+
do_save_sql, drop_table, truncate_table, sql, table, page
|
|
7
|
+
|
|
8
|
+
|
|
9
|
+
def save_sql(sql: str, *args, **kwargs):
|
|
10
|
+
"""
|
|
11
|
+
Insert data into table, return primary key.
|
|
12
|
+
:param select_key: sql for select primary key
|
|
13
|
+
:param sql: SQL
|
|
14
|
+
:param args:
|
|
15
|
+
:return: Primary key
|
|
16
|
+
"""
|
|
17
|
+
sql, args = sql_support.try_dynamic_sql('batisx.db.save_sql', sql, *args, **kwargs)
|
|
18
|
+
return do_save_sql(sql, *args)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def save_sql_select_key(select_key: str, sql: str, *args, **kwargs):
|
|
22
|
+
"""
|
|
23
|
+
Insert data into table, return primary key.
|
|
24
|
+
:param select_key: sql for select primary key
|
|
25
|
+
:param sql: SQL
|
|
26
|
+
:param args:
|
|
27
|
+
:return: Primary key
|
|
28
|
+
"""
|
|
29
|
+
sql, args = sql_support.try_dynamic_sql('batisx.db.save_sql', sql, *args, **kwargs)
|
|
30
|
+
return do_save_sql_select_key(select_key, sql, *args)
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
from .sql_page_exec import sql, page
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
from mysqlx import sql_holder as holder
|
|
2
|
+
from mysqlx.dbx import batch_execute, execute, get, query, query_one, select, select_one, select_page, query_page, sql, page
|
|
3
|
+
|
|
4
|
+
from . import db
|
|
5
|
+
from .log_support import logger, sql_id_log, page_sql_id_log, sql_id_select_key_log
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def save(sql_id: str, *args, **kwargs):
|
|
9
|
+
"""
|
|
10
|
+
Execute insert SQL, return primary key.
|
|
11
|
+
:return: Primary key
|
|
12
|
+
"""
|
|
13
|
+
sql_id_log('save', sql_id, *args, **kwargs)
|
|
14
|
+
sql_model = holder.get_sql_model(sql_id)
|
|
15
|
+
select_key = sql_model.select_key
|
|
16
|
+
sql, args = holder.do_get_sql(sql_model, False, None, *args, **kwargs)
|
|
17
|
+
if select_key:
|
|
18
|
+
return db.do_save_sql_select_key(select_key, sql, *args)
|
|
19
|
+
return db.do_save_sql(sql, *args)
|
|
20
|
+
|
|
21
|
+
|
|
22
|
+
def save_select_key(select_key, sql_id: str, *args, **kwargs):
|
|
23
|
+
"""
|
|
24
|
+
Execute insert SQL, return primary key.
|
|
25
|
+
:return: Primary key
|
|
26
|
+
"""
|
|
27
|
+
sql_id_select_key_log('save_select_key', select_key, sql_id, *args, **kwargs)
|
|
28
|
+
sql, args = holder.get_sql(sql_id, *args, **kwargs)
|
|
29
|
+
return db.do_save_sql_select_key(select_key, sql, *args)
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
from .sql_id_exec import sql, page
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
from mysqlx.log_support import logger
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
def page_sql_id_log(function: str, sql_id: str, page_num, page_size, *args, **kwargs):
|
|
5
|
+
logger.debug("Exec func 'batisx.dbx.%s', page_num: %d, page_size: %d, sql_id: %s, args: %s, kwargs: %s" % (function, page_num, page_size, sql_id, args, kwargs))
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
def sql_id_log(function: str, sql_id: str, *args, **kwargs):
|
|
9
|
+
logger.debug("Exec func '%s', sql_id: %s, args: %s, kwargs: %s" % (function, sql_id.strip(), args, kwargs))
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def sql_id_select_key_log(function: str, select_key: str, sql_id: str, *args, **kwargs):
|
|
13
|
+
logger.debug("Exec func 'batisx.dbx.%s', select_key: %s, sql_id: %s, args: %s, kwargs: %s" % (function, select_key, sql_id.strip(), args, kwargs))
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
from . import dbx
|
|
2
|
+
from mysqlx.sql_id_exec import SqlExec as _SqlExec
|
|
3
|
+
from sqlexecx.page_exec import PageExec
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class SqlExec(_SqlExec):
|
|
7
|
+
|
|
8
|
+
def save_select_key(self, select_key: str, *args, **kwargs):
|
|
9
|
+
"""
|
|
10
|
+
Insert data into table, return primary key.
|
|
11
|
+
|
|
12
|
+
:param select_key: sql for select primary key
|
|
13
|
+
:param args:
|
|
14
|
+
:return: Primary key
|
|
15
|
+
"""
|
|
16
|
+
return self.exec.save_select_key(select_key, self.sql, *args, **kwargs)
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
def sql(sql: str) :
|
|
20
|
+
assert sql, "Parameter 'sql' must not be none"
|
|
21
|
+
return SqlExec(dbx, sql)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
def page(page_num: int, page_size: int) :
|
|
25
|
+
return PageExec(dbx, page_num, page_size)
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
import os
|
|
2
|
+
import sqlexecx
|
|
3
|
+
import functools
|
|
4
|
+
from .log_support import logger
|
|
5
|
+
from mysqlx.support import SqlAction, DBError
|
|
6
|
+
from mysqlx.sql_support import simple_sql, get_named_sql_args
|
|
7
|
+
from mysqlx.sql_holder import get_sql_model, do_get_sql, build_sql_id
|
|
8
|
+
from mysqlx.sql_mapper import get_exec_func, get_select_func, before
|
|
9
|
+
|
|
10
|
+
_UPDATE_ACTIONS = (SqlAction.INSERT.value, SqlAction.UPDATE.value, SqlAction.DELETE.value, SqlAction.CALL.value)
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
def mapper(namespace: str = None, sql_id: str = None, batch=False, return_key=False, select_key=None):
|
|
14
|
+
def _decorator(func):
|
|
15
|
+
@functools.wraps(func)
|
|
16
|
+
def _wrapper(*args, **kwargs):
|
|
17
|
+
param_names = func.__code__.co_varnames
|
|
18
|
+
full_sql_id, func_name = before(func, namespace, sql_id, *args, **kwargs)
|
|
19
|
+
sql_model = get_sql_model(full_sql_id)
|
|
20
|
+
exec_func = get_exec_func(func, sql_model.action, batch)
|
|
21
|
+
if return_key:
|
|
22
|
+
use_select_key = select_key
|
|
23
|
+
use_sql, args = do_get_sql(sql_model, batch, param_names, *args, **kwargs)
|
|
24
|
+
if use_select_key is None:
|
|
25
|
+
use_select_key = sql_model.select_key
|
|
26
|
+
if use_select_key is None:
|
|
27
|
+
try:
|
|
28
|
+
use_select_key = sqlexecx.Dialect.get_select_key(sql=use_sql)
|
|
29
|
+
except NotImplementedError:
|
|
30
|
+
return DBError(
|
|
31
|
+
f"Expect 'select_key' but not. you can set it in mapper file with 'selectKey', or @mapper with 'select_key'")
|
|
32
|
+
return sqlexecx.do_save_sql_select_key(use_select_key, use_sql, *args)
|
|
33
|
+
if batch:
|
|
34
|
+
if kwargs:
|
|
35
|
+
logger.warning("Batch exec sql better use like '{}(args)' or '{}(*args)' then '{}(args=args)'".format(func_name, func_name, func_name))
|
|
36
|
+
args = list(kwargs.values())[0]
|
|
37
|
+
use_sql, _ = do_get_sql(sql_model, batch, param_names, *args)
|
|
38
|
+
else:
|
|
39
|
+
use_sql, args = do_get_sql(sql_model, batch, param_names, *args, **kwargs)
|
|
40
|
+
return exec_func(use_sql, *args)
|
|
41
|
+
|
|
42
|
+
return _wrapper
|
|
43
|
+
|
|
44
|
+
return _decorator
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def sql(value: str, batch=False, return_key=False, select_key=None):
|
|
48
|
+
def _decorator(func):
|
|
49
|
+
@functools.wraps(func)
|
|
50
|
+
def _wrapper(*args, **kwargs):
|
|
51
|
+
use_sql = value
|
|
52
|
+
low_sql = value.lower()
|
|
53
|
+
if any([action in low_sql for action in _UPDATE_ACTIONS]):
|
|
54
|
+
if batch:
|
|
55
|
+
if kwargs:
|
|
56
|
+
args = list(kwargs.values())[0]
|
|
57
|
+
return sqlexecx.batch_execute(use_sql, *args)
|
|
58
|
+
if return_key:
|
|
59
|
+
use_select_key = select_key
|
|
60
|
+
if use_select_key is None:
|
|
61
|
+
try:
|
|
62
|
+
use_select_key = sqlexecx.Dialect.get_select_key(sql=use_sql)
|
|
63
|
+
except NotImplementedError:
|
|
64
|
+
return DBError(f"Expect 'select_key' but not in func '{func.__name__}' at file: '{func.__code__.co_filename}', line {func.__code__.co_firstlineno}. you can set it @sql with 'select_key'")
|
|
65
|
+
assert SqlAction.INSERT.value in low_sql, 'Only insert sql can return primary key.'
|
|
66
|
+
if kwargs:
|
|
67
|
+
use_sql, args = get_named_sql_args(use_sql, **kwargs)
|
|
68
|
+
return sqlexecx.do_save_sql_select_key(use_select_key, use_sql, *args)
|
|
69
|
+
|
|
70
|
+
if kwargs:
|
|
71
|
+
use_sql, args = get_named_sql_args(use_sql, **kwargs)
|
|
72
|
+
return sqlexecx.do_execute(use_sql, *args)
|
|
73
|
+
elif SqlAction.SELECT.value in low_sql:
|
|
74
|
+
select_func = get_select_func(func)
|
|
75
|
+
use_sql, args = simple_sql(use_sql, *args, **kwargs)
|
|
76
|
+
return select_func(use_sql, *args)
|
|
77
|
+
else:
|
|
78
|
+
return ValueError("Invalid sql: {}.".format(sql))
|
|
79
|
+
|
|
80
|
+
return _wrapper
|
|
81
|
+
|
|
82
|
+
return _decorator
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
from . import db
|
|
2
|
+
from sqlexecx.sql_exec import SqlExec
|
|
3
|
+
from sqlexecx.page_exec import PageExec
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
def sql(sql: str) :
|
|
7
|
+
assert sql, "Parameter 'sql' must not be none"
|
|
8
|
+
return SqlExec(db, sql)
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
def page(page_num: int, page_size: int) :
|
|
12
|
+
return PageExec(db, page_num, page_size)
|
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
Metadata-Version: 2.1
|
|
2
|
+
Name: batisx
|
|
3
|
+
Version: 2.2.0
|
|
4
|
+
Summary: A thread safe sql executor for Python 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/sqlx-batis
|
|
6
|
+
Author: summy
|
|
7
|
+
Author-email: xiazhongbiao@126.com
|
|
8
|
+
License: UNKNOWN
|
|
9
|
+
Keywords: sql,MySQL,PostgreSQL,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
|
+
'person_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/sqlx-batis/blob/master/dtd/mapper.dtd">
|
|
24
|
+
<mapper namespace="person">
|
|
25
|
+
<select id="select_all">
|
|
26
|
+
select id, name, age from person
|
|
27
|
+
</select>
|
|
28
|
+
|
|
29
|
+
<select id="select_by_name">
|
|
30
|
+
select id, name, age from person where name = ?
|
|
31
|
+
</select>
|
|
32
|
+
|
|
33
|
+
<select id="select_by_name2">
|
|
34
|
+
select id, name, age from person 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 typing import List, Tuple, Mapping
|
|
51
|
+
from batisx import mapper, sql, dbx, init_db
|
|
52
|
+
|
|
53
|
+
@mapper(namespace='person')
|
|
54
|
+
def select_all(): List
|
|
55
|
+
|
|
56
|
+
@mapper(namespace='person')
|
|
57
|
+
def select_by_name(name: str): List
|
|
58
|
+
|
|
59
|
+
@mapper(namespace='person')
|
|
60
|
+
def select_by_name2(name: str): List
|
|
61
|
+
|
|
62
|
+
@mapper(namespace='person')
|
|
63
|
+
def select_include(name: str): List
|
|
64
|
+
|
|
65
|
+
@sql('select id, name, age from person where name = ?')
|
|
66
|
+
def query_by_name(name: str): List(Mapping)
|
|
67
|
+
|
|
68
|
+
@sql('select id, name, age from person where name = :name')
|
|
69
|
+
def query_by_name2(name: str): List(Mapping)
|
|
70
|
+
|
|
71
|
+
if __name__ == '__main__':
|
|
72
|
+
# init_db('test.db', driver='sqlite3', show_sql=True, debug=True, mapper_path='./mapper')
|
|
73
|
+
# init_db("postgres://user:password@127.0.0.1:5432/testdb", driver='psycopg2', pool_size=5, mapper_path='./mapper')
|
|
74
|
+
init_db(host='127.0.0.1', port='3306', user='xxx', password='xxx', database='test', pool_size=5, show_sql=True, mapper_path='./mapper')
|
|
75
|
+
|
|
76
|
+
persons = select_all()
|
|
77
|
+
# result:
|
|
78
|
+
# (3, 'zhangsan', 15)
|
|
79
|
+
# (4, 'lisi', 26)
|
|
80
|
+
# (5, 'wangwu', 38)
|
|
81
|
+
|
|
82
|
+
persons = select_by_name('zhangsan')
|
|
83
|
+
# result:
|
|
84
|
+
# (3, 'zhangsan', 15)
|
|
85
|
+
|
|
86
|
+
persons = select_by_name2(name='zhangsan')
|
|
87
|
+
# result:
|
|
88
|
+
# (3, 'zhangsan', 15)
|
|
89
|
+
|
|
90
|
+
persons = select_include(name='zhangsan')
|
|
91
|
+
# result:
|
|
92
|
+
# (3, 'zhangsan', 15)
|
|
93
|
+
|
|
94
|
+
persons = query_by_name('zhangsan')
|
|
95
|
+
# result:
|
|
96
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
97
|
+
|
|
98
|
+
persons = query_by_name2(name='zhangsan')
|
|
99
|
+
# result:
|
|
100
|
+
# {'id': 3, 'name': 'zhangsan', 'age': 15}
|
|
101
|
+
|
|
102
|
+
# you can use dbx execute mapper sql with full sql id: namespace join sql id
|
|
103
|
+
persons = dbx.select('person.select_all') # 'person' is namespace, 'select_all' is sql id
|
|
104
|
+
# result:
|
|
105
|
+
# (3, 'zhangsan', 15)
|
|
106
|
+
# (4, 'lisi', 26)
|
|
107
|
+
# (5, 'wangwu', 38)
|
|
108
|
+
|
|
109
|
+
persons = dbx.select('person.select_by_name', name='zhangsan')
|
|
110
|
+
# result:
|
|
111
|
+
# (3, 'zhangsan', 15)
|
|
112
|
+
|
|
113
|
+
persons = dbx.sql('person.select_by_name').select(name='zhangsan')
|
|
114
|
+
# result:
|
|
115
|
+
# (3, 'zhangsan', 15)
|
|
116
|
+
|
|
117
|
+
# you can direct execute sql with db
|
|
118
|
+
effected_rowcount = db.insert(table='person', name='zhaoliu', age=66)
|
|
119
|
+
|
|
120
|
+
persons = db.select('select id, name, age from person')
|
|
121
|
+
# result:
|
|
122
|
+
# (3, 'zhangsan', 15)
|
|
123
|
+
# (4, 'lisi', 26)
|
|
124
|
+
# (5, 'wangwu', 38)
|
|
125
|
+
# (6, 'zhaoliu', 45)
|
|
126
|
+
|
|
127
|
+
persons = db.query('select id, name, age from person name = :name', name='zhangsan')
|
|
128
|
+
# result:
|
|
129
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
130
|
+
|
|
131
|
+
persons = db.sql('select id, name, age from person name = :name').query(name='zhangsan')
|
|
132
|
+
# result:
|
|
133
|
+
# [{'id': 3, 'name': 'zhangsan', 'age': 15}]
|
|
134
|
+
|
|
135
|
+
persons = db.select('select id, name, age from person where name = ?', 'zhangsan')
|
|
136
|
+
# result:
|
|
137
|
+
# [(3, 'zhangsan', 15)]
|
|
138
|
+
|
|
139
|
+
|
|
140
|
+
Transaction
|
|
141
|
+
'''''''''''
|
|
142
|
+
|
|
143
|
+
.. code:: python
|
|
144
|
+
|
|
145
|
+
from batisx import with_transaction, transaction
|
|
146
|
+
|
|
147
|
+
@with_transaction
|
|
148
|
+
def test_transaction():
|
|
149
|
+
insert_func(....)
|
|
150
|
+
update_func(....)
|
|
151
|
+
|
|
152
|
+
|
|
153
|
+
def test_transaction2():
|
|
154
|
+
with transaction():
|
|
155
|
+
insert_func(....)
|
|
156
|
+
update_func(....)
|
|
157
|
+
|
|
158
|
+
|
|
159
|
+
If you want to operate MySQL database, may be you need MySqlx: https://pypi.org/project/mysqlx
|
|
160
|
+
|
|
161
|
+
If you want to operate PostgreSQL database, may be you need MySqlx: https://pypi.org/project/pgsqlx
|
|
162
|
+
|
|
163
|
+
If you just wanted a simple sql executor, may be you need sqlx-exec: https://pypi.org/project/sqlx-exec
|
|
164
|
+
|
|
165
|
+
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
README.rst
|
|
2
|
+
setup.py
|
|
3
|
+
batisx/__init__.py
|
|
4
|
+
batisx/db.py
|
|
5
|
+
batisx/dbx.py
|
|
6
|
+
batisx/log_support.py
|
|
7
|
+
batisx/sql_id_exec.py
|
|
8
|
+
batisx/sql_mapper.py
|
|
9
|
+
batisx/sql_page_exec.py
|
|
10
|
+
batisx.egg-info/PKG-INFO
|
|
11
|
+
batisx.egg-info/SOURCES.txt
|
|
12
|
+
batisx.egg-info/dependency_links.txt
|
|
13
|
+
batisx.egg-info/not-zip-safe
|
|
14
|
+
batisx.egg-info/requires.txt
|
|
15
|
+
batisx.egg-info/top_level.txt
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
mysqlx>=2.2.0
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
batisx
|
batisx-2.2.0/setup.cfg
ADDED
batisx-2.2.0/setup.py
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
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='batisx',
|
|
16
|
+
packages=['batisx'],
|
|
17
|
+
description="A thread safe sql executor for Python 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
|
+
'mysqlx>=2.2.0',
|
|
22
|
+
],
|
|
23
|
+
version='2.2.0',
|
|
24
|
+
url='https://gitee.com/summry/sqlx-batis',
|
|
25
|
+
author='summy',
|
|
26
|
+
author_email='xiazhongbiao@126.com',
|
|
27
|
+
keywords=['sql', 'MySQL', 'PostgreSQL', 'MyBatis', 'python'],
|
|
28
|
+
package_data={
|
|
29
|
+
# include json and txt files
|
|
30
|
+
'': ['*.rst', '*.dtd', '*.tpl'],
|
|
31
|
+
},
|
|
32
|
+
include_package_data=True,
|
|
33
|
+
python_requires='>=3.5',
|
|
34
|
+
zip_safe=False
|
|
35
|
+
)
|
|
36
|
+
|