├── .gitignore
├── CHANGELOG.md
├── LICENSE.md
├── README.CH.md
├── README.md
├── __init__.py
├── lazy_mysql.py
└── sample.py
/.gitignore:
--------------------------------------------------------------------------------
1 | *.pyc
2 | *.idea/
3 | *.sublime-project
4 | *.sublime-workspace
5 |
--------------------------------------------------------------------------------
/CHANGELOG.md:
--------------------------------------------------------------------------------
1 | 2015-4-1 version 1.2.6
2 | --------------------------
3 |
4 | 1. 增加按多列进行 group by 操作。
5 | 2. Column 对象增加 sum, count, max, min 方法。
6 | 3. 修复 MySQL-python 1.2.3 环境下进行 in 操作时的字符转义问题。
7 |
8 | 1. Changed signature of _Select.group_by() to support group by multiple columns.
9 | 2. Added new methods sum, count, max, min to class Column.
10 | 3. Fixed bug over string escaping when using method Column.in_() in MySQL-python 1.2.3.
11 |
12 |
13 | 2015-3-12 version 1.2.1
14 | ----------------------------
15 |
16 | 1. 增加了 Pool 对象作为连接池。
17 |
18 | 1. Added class Pool to manage Engine objects.
19 |
20 |
21 | 2014-4-21 version 1.1.2
22 | ----------------------------
23 |
24 | 1. _Select类增加group_by()方法。
25 |
26 | 1. Added method group_by() in class _Select.
27 |
28 |
29 | 2014-2-26 version 1.1.1
30 | ----------------------------
31 |
32 | 1. 修改Session执行日志级别,SELECT, COUNT操作属于DEBUG级别,INSERT, UPDATE, DELETE属于INFO级别。
33 |
34 | 1. Reset logging level of SELECT, COUNT operations to DEBUG, logging level of INSERT, UPDATE, DELETE operations to INFO.
35 |
36 |
37 | 2014-2-22 version 1.1.0
38 | ----------------------------
39 |
40 | 1. Column对象增加is_null()方法,支持MYSQL的IS NULL语句。
41 |
42 | 1. Improved object Column by adding method is_null() in order to support MySql syntax IS NULL.
43 |
44 |
45 | 2014-1-16 version 1.0.3.0
46 | ------------------------------
47 |
48 | 1. 修改Table.add_column,Table.remove_column方法签名。
49 |
50 | 1. Change signature of Table.add_column, Table.remove_column.
51 |
52 |
53 | 2014-1-16 version 1.0.2.1
54 | ------------------------------
55 |
56 | 1. 使Table.binding_engine()方法具有返回值。
57 |
58 | 1. Making Table.binding_engine() method return itself.
59 |
60 |
61 | 2014-1-16 version 1.0.2.0
62 | ------------------------------
63 |
64 | 1. 增加SQL执行日志。
65 | 2. 增加Session的affected_rows, last_executed属性。
66 |
67 | 1. Added logger, all sql execution would be logged at debug level.
68 | 2. Added property affected_rows, last_executed to _BaseSession and Engine object.
69 |
70 |
71 | 2014-1-13 version 1.0.1.2
72 | ------------------------------
73 |
74 | 1. 修复Engine.connect()方法。
75 |
76 | 1. Fixed bug in Engine.connect().
77 |
78 |
79 | 2014-1-13 version 1.0.1.1
80 | ------------------------------
81 |
82 | 1. 修改Engine对象接收charset作为初始化参数。
83 |
84 | 1. Modified class Engine to accept charset as one of its __init__() arguments.
85 |
86 |
87 | 2014-1-12 version 1.0.1.0
88 | ------------------------------
89 |
90 | 1. Table.remove_column(self, column) 改进为column参数可以为Column对象。
91 | 2. Engine对象增加若干方法。
92 | 3. 增加clear()方法。
93 | 4. 更名为lazy_mysql。
94 |
95 | 1. Improve Table.remove_column to be able to accept Column object.
96 | 2. Add several instance methods to Engine object.
97 | 3. Add method clear() to _BaseSession object.
98 | 4. Renamed module to lazy_mysql.
--------------------------------------------------------------------------------
/LICENSE.md:
--------------------------------------------------------------------------------
1 | MIT License
2 | ========
3 |
4 | **Copyright (c) [2015] [Xavier Yin] [hendikoy@gmail.com] **
5 |
6 | Permission is hereby granted, free of charge, to any person obtaining a copy of
7 | this software and associated documentation files (the "Software"), to deal in
8 | the Software without restriction, including without limitation the rights to
9 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
10 | the Software, and to permit persons to whom the Software is furnished to do so,
11 | subject to the following conditions:
12 |
13 | The above copyright notice and this permission notice shall be included in all
14 | copies or substantial portions of the Software.
15 |
16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
18 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
19 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
20 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
21 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 |
23 | Developer's Certificate of Origin 1.1
24 |
25 | By making a contribution to this project, I certify that:
26 |
27 | (a) The contribution was created in whole or in part by me and I
28 | have the right to submit it under the open source license
29 | indicated in the file; or
30 |
31 | (b) The contribution is based upon previous work that, to the best
32 | of my knowledge, is covered under an appropriate open source
33 | license and I have the right under that license to submit that
34 | work with modifications, whether created in whole or in part
35 | by me, under the same open source license (unless I am
36 | permitted to submit under a different license), as indicated
37 | in the file; or
38 |
39 | (c) The contribution was provided directly to me by some other
40 | person who certified (a), (b) or (c) and I have not modified
41 | it.
42 |
43 | (d) I understand and agree that this project and the contribution
44 | are public and that a record of the contribution (including all
45 | personal information I submit with it, including my sign-off) is
46 | maintained indefinitely and may be redistributed consistent with
47 | this project or the open source license(s) involved.
--------------------------------------------------------------------------------
/README.CH.md:
--------------------------------------------------------------------------------
1 | lazy_mysql
2 | =======
3 |
4 | Click to see [English Version](./README.md)
5 |
6 |
7 |
8 | TOC
9 | -----
10 |
11 | 1. [Intro](#intro)
12 | 2. [Installation](#installation)
13 | 3. [Tutorial](#tutorial)
14 | 4. [API](#api)
15 | 1. [Engine](#1-engine)
16 | 2. [Pool](#2-pool)
17 | 3. [Column](#3-column)
18 | 4. [Table](#4-table)
19 |
20 |
21 |
22 | Intro
23 | ------
24 |
25 | 本模块基于 `MySQL-python` 之上提供了四个常用对象,分别是:
26 |
27 | * **Engine** : 负责连接数据库,执行 SQL 语句。
28 | * **Pool** : 数据库连接池,负责管理 Engine 对象。
29 | * **Table** : 该对象映射到数据表。
30 | * **Column** : 该对象映射到数据表字段。
31 |
32 | ### Dependencies
33 |
34 | * Python 2.6 - 2.7
35 | * MySQLdb-python 1.2.3+
36 |
37 |
38 | Installation
39 | --------------
40 |
41 | 从 [GitHub](https://github.com/hendiko/PyLazy.git) 下载。
42 |
43 | git clone https://github.com/hendiko/PyLazy.git
44 |
45 | 或者直接下载 `lazy_mysql.py` 文件,将 `lazy_mysql.py` 文件放到项目中任意可导入目录均可。
46 |
47 |
48 |
49 | Tutorial
50 | ---------
51 |
52 | ### 1. 建立数据库连接
53 |
54 | 使用 **Engine** 对象连接数据库。
55 |
56 | from lazy_mysql import Engine, Pool, Table, Column
57 |
58 | engine = Engine('localhost', 'test', 'root', 'root')
59 |
60 | 如果要应付多线程多并发连接,可使用 **Pool** 对象来管理数据库连接,**Pool** 的作用是提供一个连接池,用以管理多个 **Engine** 对象。
61 |
62 | pool = Pool('localhost', 'test', 'root', 'root', pool_size=4, extras=4)
63 |
64 | ### 2. 建立 Table 类
65 |
66 | 新建一个 **Table** 对象来映射数据表,只需要新建一个类继承自 **Table** 类。
67 |
68 | class Schedule(Table):
69 |
70 | def __init__(self, table_name='schedule', _engine=engine, *columns):
71 | super(Schedule, self).__init__(table_name, _engine, *columns)
72 |
73 | self.schedule_id = Column('scheduleId')
74 | self.task_id = Column('taskId')
75 | self.task_name = Column('taskName')
76 | self.status = Column('status')
77 |
78 | _engine 参数可以接收一个 *Engine* 或 *Pool* 实例对象。
79 |
80 | 在初始化中定义数据表字段,你可以只初始化部分字段而非全部字段,**Column** 对象代表一个字段对象,实例化一个 **Column** 字段仅需要传入一个字段名称,**Column** 对象不会检查字段类型及合法性。
81 |
82 | ### 3. Select 操作
83 |
84 | # 实例化一个数据表对象。
85 | s = Schedule()
86 |
87 | # SELECT * FROM schedule LIMIT 1;
88 | s.select().go()
89 |
90 | # SELECT * FROM schedule;
91 | s.select().limit().go()
92 |
93 | # SELECT taskName, status FROM schedule WHERE (taskId=1) LIMIT 1;
94 | s.select(s.task_name, s.status).where(schedule.task_id == 1).go()
95 |
96 | # SELECT DISTINCT taskName FROM schedule WHERE (scheduleId=1) GROUP BY taskName ORDER BY taskId DESC LIMIT 1, 4;
97 | s.select(s.task_name).where(s.schedule_id == 1).distinct().order(s.task_id, desc=True).group_by(s.task_name).limit(1, 4).go()
98 |
99 | # SELECT * FROM schedule WHERE (scheduleId=1 AND taskId=2) OR (taskId=2) AND (taskName='query') LIMIT 1;
100 | s.select().where(s.schedule_id == 1, s.task_id == 3).where(s.task_id == 2).where_and(s.task_name == "query").go()
101 |
102 | ### 4. Insert 操作
103 |
104 | # INSERT INTO schedule SET taskName='query';
105 | s.insert(**{s.task_name.name: 'query'}).go()
106 |
107 | # 或者
108 | s.insert(taskName="query").go()
109 |
110 | ### 5. Update 操作
111 |
112 | # UPDATE schedule SET taskName='query2' WHERE (scheduleId=5) LIMIT 1;
113 | s.update(**{s.task_name.name: "query2"}).where(s.schedule_id == 5).go()
114 |
115 | # 或者
116 | s.update(taskName="query2").where(s.schedule_id == 5).go()
117 |
118 | ### 6. Delete 操作
119 |
120 | # DELETE FROM schedule WHERE (scheduleId=5) LIMIT 1;
121 | s.delete().where(s.schedule_id == 5).go()
122 |
123 | ### 7. Count 操作
124 |
125 | # SELECT COUNT(DISTINCT scheduleId) AS X FROM schedule WHERE (scheduleId>2) LIMIT 1;
126 | s.count(s.schedule_id, distinct=True).where(s.schedule_id > 2).go()
127 |
128 |
129 |
130 | API
131 | ----
132 |
133 | ### 1. Engine
134 |
135 | **Engine** 对象负责数据库连接,执行 SQL 语句。
136 |
137 | #### 1.1. \__init\__(self, host, schema, user, pw, port=3306, charset='utf8', cursor_class='dict', autocommit=True, debug=True, \*args, \*\*kwargs):
138 |
139 | * host: 数据库主机
140 | * schema: 数据库名称。
141 | * user: 用户名。
142 | * pw: 密码。
143 | * port: 端口。
144 | * charset: 字符集。
145 | * cursor_class: 游标类型,默认值为 'dict',其他均返回 tuple 类型的结果集。
146 | * autocommit: 自动提交。
147 | * debug: 调试模式,若为真,则打印 SQL 语句。
148 | * args: 其他 MySQLdb.connect() 参数。
149 | * kwargs: 其他 MySQLdb.connect() 参数。
150 |
151 | #### 1.2. affected_rows
152 |
153 | 执行 SQL 语句影响的数据表行数。
154 |
155 | #### 1.3. last_executed
156 |
157 | 最后一次成功执行的 SQL 语句。
158 |
159 | #### 1.4. cursor_class
160 |
161 | 数据库连接游标类型。如果 `cursor_class='dict'`,则使用 DictCursor,否则使用 Cursor。
162 |
163 | #### 1.5. connect(self, cursor_class=None)
164 |
165 | 返回 **Connection** 对象,连接数据库,如果 cursor_class 为 None,则使用默认的 self.cursor_class 属性进行连接。
166 |
167 | #### 1.6. close(self)
168 |
169 | 关闭 **Connection** 对象。
170 |
171 |
172 | ### 2. Pool
173 |
174 | #### 2.1. \__init\__(self, host, schema, user, pw, port=3306, charset='utf8', cursor_class='dict', autocommit=True, debug=True, pool_size=2, extras=4, wait_time=5, \*args, \*\*kwargs):
175 |
176 | 初始化连接池,用以管理 **Engine** 对象。**Pool** 内部有一个保存 **Engine** 对象的队列 **self.pool**。Pool 允许在连接池外额外创建一些 Engine 对象用以应付超出预期的请求数量。
177 |
178 | **Pool** 初始化参数与 **Engine** 初始化参数大部分相同。
179 |
180 | * pool_size: 设置连接池大小。
181 | * extras: 当连接池满时,允许额外创建的 **Engine** 对象最大数量。
182 | * wait_time: 当连接池为空时,等待获取 **Engine** 的超时时间。
183 |
184 | #### 2.2. count
185 |
186 | 当前所有 **Engine** 对象数量。
187 |
188 | #### 2.3. put(self, engine=None)
189 |
190 | 回收 **Engine** 对象到连接池。
191 |
192 | #### 2.4. get(self)
193 |
194 | 从连接池申请 **Engine** 对象。
195 |
196 | #### 2.5. spawn_engine(self):
197 |
198 | 创建新的 **Engine** 对象。
199 |
200 | ### 3. Column
201 |
202 | 数据库字段对象。
203 |
204 | #### 3.1. \__init\__(self, name)
205 |
206 | 参数 *name* 为数据库字段名称。
207 |
208 | #### 3.2. like(self, other)
209 |
210 | 实现 SQL LIKE 语句。
211 |
212 | #### 3.3. in_(self, \*other)
213 |
214 | 实现 SQL IN 语句。
215 |
216 | #### 3.4. between(self, floor, ceil)
217 |
218 | 实现 SQL BETWEEN 语句。
219 |
220 | #### 3.5. is_null(self, boolean=True)
221 |
222 | 实现 SQL IS NULL 或 IS NOT NULL 语句。
223 |
224 | ### 4. Table
225 |
226 | #### 4.1. \__init\__(self, table_name, \_engine=None, \*columns)
227 |
228 | 实例化 **Table** 对象。
229 |
230 | * table_name: 数据表名称。
231 | * \_engine: 支持传入 **Engine** 或 **Pool** 对象。
232 |
233 | #### 4.2. add_column(self, \*columns)
234 |
235 | 向 Table 添加字段属性。
236 |
237 | #### 4.3. remove_column(self, \*columns)
238 |
239 | 从 Table 删除字段属性。
240 |
241 | #### 4.4. binding_engine(self, engine)
242 |
243 | 重新绑定数据表的 engine 属性,参数 *engine* 支持传入 **Engine** 或 **Pool** 对象。
244 |
245 | #### 4.5. select(self, \*columns)
246 |
247 | 执行 SELECT 语句。
248 |
249 | #### 4.6. insert(self, \**assignments)
250 |
251 | 执行 INSERT 语句。
252 |
253 | #### 4.7. update(self, \**assignments)
254 |
255 | 执行 UPDATE 语句。
256 |
257 | #### 4.8 delete(self)
258 |
259 | 执行 DELETE 语句。
260 |
261 | #### 4.9. count(self, column=None, distinct=None)
262 |
263 | 执行 COUNT 语句。
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | lazy_mysql
2 | =======
3 |
4 | 点击查看[中文版](./README.CH.md)
5 |
6 |
7 |
8 | TOC
9 | -----
10 |
11 | 1. [Intro](#intro)
12 | 2. [Installation](#installation)
13 | 3. [Tutorial](#tutorial)
14 | 4. [API](#api)
15 | 1. [Engine](#1-engine)
16 | 2. [Pool](#2-pool)
17 | 3. [Column](#3-column)
18 | 4. [Table](#4-table)
19 |
20 |
21 |
22 | Intro
23 | ------
24 |
25 | The module which is based on `MySQL-python` provides four main classes:
26 |
27 | * **Engine** : connect to MySQL server and execute SQL statements.
28 | * **Pool** : a pool that manages Engine objects.
29 | * **Table** : a python object mapping table in database.
30 | * **Column** : a python object mapping field in database.
31 |
32 | ### Dependencies
33 |
34 | * Python 2.6 - 2.7
35 | * MySQLdb-python 1.2.3+
36 |
37 |
38 |
39 | Installation
40 | --------------
41 |
42 | Download from [GitHub](https://github.com/hendiko/PyLazy.git).
43 |
44 | git clone https://github.com/hendiko/PyLazy.git
45 |
46 | Or you can simply download `lazy_mysql.py` then put it anywhere in your project.
47 |
48 |
49 |
50 | Tutorial
51 | ---------
52 |
53 | ### 1. Connect to server
54 |
55 | Use **Engine**.
56 |
57 | from lazy_mysql import Engine, Pool, Table, Column
58 |
59 | engine = Engine('localhost', 'test', 'root', 'root')
60 |
61 | It had better use **Pool** object to set up a pool to manage **Engine** objects to handle multi threads.
62 |
63 | pool = Pool('localhost', 'test', 'root', 'root', pool_size=4, extras=4)
64 |
65 | ### 2. Create **Table** object
66 |
67 | To create a **Table** object which maps a table in database, you need to define a class which inherits class **Table**.
68 |
69 | class Schedule(Table):
70 |
71 | def __init__(self, table_name='schedule', _engine=engine, *columns):
72 | super(Schedule, self).__init__(table_name, _engine, *columns)
73 |
74 | self.schedule_id = Column('scheduleId')
75 | self.task_id = Column('taskId')
76 | self.task_name = Column('taskName')
77 | self.status = Column('status')
78 |
79 | The argument of **_engine** could be either an **Engine** instance or a **Pool** instance.
80 |
81 | You could only define those fields you need to use instead of all of the fields that exsits in your database table. A **Column** object needs to be passed in field name to initialize itself, it won't check the field type nor validate the value to be written into database.
82 |
83 | ### 3. Select
84 |
85 | # Create a Table instance.
86 | s = Schedule()
87 |
88 | # SELECT * FROM schedule LIMIT 1;
89 | s.select().go()
90 |
91 | # SELECT * FROM schedule;
92 | s.select().limit().go()
93 |
94 | # SELECT taskName, status FROM schedule WHERE (taskId=1) LIMIT 1;
95 | s.select(s.task_name, s.status).where(schedule.task_id == 1).go()
96 |
97 | # SELECT DISTINCT taskName FROM schedule WHERE (scheduleId=1) GROUP BY taskName ORDER BY taskId DESC LIMIT 1, 4;
98 | s.select(s.task_name).where(s.schedule_id == 1).distinct().order(s.task_id, desc=True).group_by(s.task_name).limit(1, 4).go()
99 |
100 | # SELECT * FROM schedule WHERE (scheduleId=1 AND taskId=2) OR (taskId=2) AND (taskName='query') LIMIT 1;
101 | s.select().where(s.schedule_id == 1, s.task_id == 3).where(s.task_id == 2).where_and(s.task_name == "query").go()
102 |
103 | ### 4. Insert
104 |
105 | # INSERT INTO schedule SET taskName='query';
106 | s.insert(**{s.task_name.name: 'query'}).go()
107 |
108 | # or a deprecated way which is more convenient but less reliable.
109 | s.insert(taskName="query").go()
110 |
111 |
112 | ### 5. Update
113 |
114 | # UPDATE schedule SET taskName='query2' WHERE (scheduleId=5) LIMIT 1;
115 | s.update(**{s.task_name.name: "query2"}).where(s.schedule_id == 5).go()
116 |
117 | # or a deprecated way which is more convenient but less reliable.
118 | s.update(taskName="query2").where(s.schedule_id == 5).go()
119 |
120 |
121 | ### 6. Delete
122 |
123 | # DELETE FROM schedule WHERE (scheduleId=5) LIMIT 1;
124 | s.delete().where(s.schedule_id == 5).go()
125 |
126 |
127 | ### 7. Count
128 |
129 | # SELECT COUNT(DISTINCT scheduleId) AS X FROM schedule WHERE (scheduleId>2) LIMIT 1;
130 | s.count(s.schedule_id, distinct=True).where(s.schedule_id > 2).go()
131 |
132 |
133 | API
134 | ----
135 |
136 | ### 1. Engine
137 |
138 | **Engine** - connect to MySQL server and execute SQL statements.
139 |
140 | #### 1.1. \__init\__(self, host, schema, user, pw, port=3306, charset='utf8', cursor_class='dict', autocommit=True, debug=True, \*args, \*\*kwargs):
141 |
142 | * host: host address.
143 | * schema: database name.
144 | * user: user name.
145 | * pw: password.
146 | * port: port.
147 | * charset: charset.
148 | * cursor_class: use DictCursor if 'dict' given, or Cursor.
149 | * autocommit: automatically commit.
150 | * debug: if true, log the every SQL statement executed.
151 | * args: other arguments for MySQLdb.connect()
152 | * kwargs: other keyword arguments for MySQLdb.connect().
153 |
154 | #### 1.2. affected_rows
155 |
156 | The number of rows that have been affected by executing SQL statement.
157 |
158 | #### 1.3. last_executed
159 |
160 | The last SQL statement that is executed successfully.
161 |
162 | #### 1.4. cursor_class
163 |
164 | if a string 'dict' was given, use `DictCursor` instead of `Cursor`.
165 |
166 | #### 1.5. connect(self, cursor_class=None)
167 |
168 | Return a **Connection** object. If *cursor_class* is *None*, the `self.cursor_class` will be used.
169 |
170 | #### 1.6. close(self)
171 |
172 | Close connection.
173 |
174 | ### 2. Pool
175 |
176 | #### 2.1. \__init\__(self, host, schema, user, pw, port=3306, charset='utf8', cursor_class='dict', autocommit=True, debug=True, pool_size=2, extras=4, wait_time=5, \*args, \*\*kwargs):
177 |
178 | Initialize a **Pool** object to manage a number of **Engine** objects. A queue object that exsits inside the **Pool** object actually reserves all **Engine** objects. You could use the parameter **pool_size** to limit the number of **Engine** in pool. It also allows you to create a number of extra **Engine** objects outside the pool, the extra engines would cost more because they are created on the fly and be destroyed after use, you probably want to use them only in case there are many requests coming suddenly.
179 |
180 | The most of arguments of Pool is similar to those in Engine.
181 |
182 | * pool_size: the maximum number of engines reserved in pool.
183 | * extras: the maximun number of engines existing outside the pool.
184 | * wait_time: the timeout seconds waiting for Engine to be acquired from the pool.
185 |
186 | #### 2.2. count
187 |
188 | The current number of Engines both inside or outside the pool.
189 |
190 | #### 2.3. put(self, engine=None)
191 |
192 | Put the Engine object back to the pool.
193 |
194 | #### 2.4. get(self)
195 |
196 | Acquire Engine object from the pool.
197 |
198 | #### 2.5. spawn_engine(self):
199 |
200 | Create a new Engine object.
201 |
202 | ### 3. Column
203 |
204 | #### 3.1. \__init\__(self, name)
205 |
206 | The argument name is a string that is name of field in database.
207 |
208 | #### 3.2. like(self, other)
209 |
210 | The like statement in SQL.
211 |
212 | #### 3.3. in_(self, \*other)
213 |
214 | The in statement in SQL.
215 |
216 | #### 3.4. between(self, floor, ceil)
217 |
218 | The between statement in SQL.
219 |
220 | #### 3.5. is_null(self, boolean=True)
221 |
222 | The IS NULL or IS NOT NULL in SQL.
223 |
224 |
225 | ### 4. Table
226 |
227 | #### 4.1. \__init\__(self, table_name, \_engine=None, \*columns)
228 |
229 | Initialize a **Table** object.
230 |
231 | * table_name: a string that is the name of table.
232 | * \_engine: either an **Engine** object or a **Pool** object.
233 |
234 | #### 4.2. add_column(self, \*columns)
235 |
236 | Add a column into Table object.
237 |
238 | #### 4.3. remove_column(self, \*columns)
239 |
240 | Remove a column from Table object.
241 |
242 | #### 4.4. binding_engine(self, engine)
243 |
244 | Binding either an Engine or a Pool object to this Table object.
245 |
246 | #### 4.5. select(self, \*columns)
247 |
248 | Execute SELECT statement.
249 |
250 | #### 4.6. insert(self, \**assignments)
251 |
252 | Execute INSERT statement.
253 |
254 | #### 4.7. update(self, \**assignments)
255 |
256 | Execute UPDATE statement.
257 |
258 | #### 4.8 delete(self)
259 |
260 | Execute DELETE statement.
261 |
262 | #### 4.9. count(self, column=None, distinct=None)
263 |
264 | Execute COUNT statement.
--------------------------------------------------------------------------------
/__init__.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf8 -*-
3 | # Created by Xavier Yin on 2014-1-11
--------------------------------------------------------------------------------
/lazy_mysql.py:
--------------------------------------------------------------------------------
1 | # !/usr/bin/env python
2 | # -*- coding: utf-8 -*-
3 | # Author : Xavier Yin
4 | # Date : 2013-12-26
5 |
6 | """
7 | The lazy_mysql is a simple and light ORM framework based on MySQLdb.
8 |
9 | The module provides five main classes which are Engine, Pool, Session, Table, Column.
10 | It provides five SQL operations, they are SELECT, INSERT, DELETE, UPDATE, COUNT.
11 |
12 | 本模块包括 Engine, Pool, Session, Table, Column 五个对象。
13 | 目前支持 SELECT, INSERT, DELETE, UPDATE, COUNT 操作。
14 | 条件支持 WHERE, ORDER BY, GROUP BY, DISTINCT, LIMIT。
15 | """
16 | __author__ = 'Xavier Yin'
17 | __version__ = '1.2.6'
18 | __date__ = '2015-4-1'
19 |
20 |
21 | from datetime import datetime
22 | from MySQLdb import cursors
23 | from Queue import Queue, Full, Empty
24 | from threading import RLock
25 | import logging
26 | import MySQLdb
27 |
28 | MySQLdb.threadsafety = 1
29 | logger = logging.getLogger(__name__)
30 |
31 |
32 | class Engine(object):
33 | """The engine to connect database."""
34 | def __init__(self, host, schema, user, pw, port=3306, charset='utf8',
35 | cursor_class='dict', autocommit=True, debug=True, *args, **kwargs):
36 | """初始化数据库连接参数。
37 | :param host: 数据库主机。
38 | :param schema: 数据库名称。
39 | :param user: 用户名。
40 | :param pw: 密码。
41 | :param port: 端口。
42 | :param charset: 字符集。
43 | :param cursor_class: 游标类,默认值为 dict,其他为 tuple。
44 | :param autocommit: 自动提交。
45 | :param debug: 调试模式。
46 | :param args: 其他参数。
47 | :param kwargs: 其他参数。
48 | """
49 | self.host = host
50 | self.schema = schema
51 | self.user = user
52 | self.pw = pw
53 | self.port = port
54 | self.connection = None
55 | self.charset = charset
56 | self._cursor_class = cursor_class
57 | self.autocommit = autocommit
58 | self.debug = debug
59 | self.args = args
60 | self.kwargs = kwargs
61 | self.affected_rows = 0
62 | self.last_executed = ''
63 |
64 | @property
65 | def cursor_class(self):
66 | if self._cursor_class == 'dict':
67 | return cursors.DictCursor
68 | else:
69 | return cursors.Cursor
70 |
71 | @cursor_class.setter
72 | def cursor_class(self, _class):
73 | self._cursor_class = _class
74 |
75 | def connect(self, cursor_class=None):
76 | """建立数据库连接。"""
77 | if not self.connection:
78 | self.connection = MySQLdb.connect(
79 | self.host, self.user, self.pw, self.schema, port=self.port,
80 | charset=self.charset, cursorclass=cursor_class)
81 | self.connection.autocommit(self.autocommit)
82 | if cursor_class is None:
83 | self.connection.cursorclass = self.cursor_class
84 | elif cursor_class == "dict":
85 | self.connection.cursorclass = cursors.DictCursor
86 | else:
87 | self.connection.cursorclass = cursors.Cursor
88 | return self.connection
89 |
90 | def close(self):
91 | try:
92 | self.connection.close()
93 | except Exception as e:
94 | if self.debug:
95 | logger.exception(str(e))
96 | finally:
97 | self.connection = None
98 |
99 | def create_database(self, table_name, confirm=False):
100 | """创建新的数据库。
101 | :param table_name: 数据表名称。
102 | :param confirm: 如果为真,则新建数据表。
103 | """
104 | if confirm:
105 | sql = 'CREATE DATABASE `%(name)s`' % {'name': table_name}
106 | return self._transaction(sql)
107 |
108 | def drop_database(self, table_name, confirm=False):
109 | """
110 | 丢弃数据库
111 | :param table_name: 数据库名称。
112 | :param confirm: 安全确认。仅当confirm为True时才执行丢弃操作。
113 | """
114 | if confirm is True:
115 | sql = 'DROP DATABASE `%(name)s`' % {'name': table_name}
116 | return self._transaction(sql)
117 |
118 | def show_create_table(self, table_name):
119 | """显示数据库创建SQL语句。"""
120 | sql = 'SHOW CREATE TABLE `%(name)s`' % {'name': table_name}
121 | return self._transaction(sql, True)[0]['Create Table']
122 |
123 | def show_databases(self):
124 | """显示所有数据库名称。"""
125 | sql = 'SHOW DATABASES'
126 | return [d['Database'] for d in self._transaction(sql, True)]
127 |
128 | def show_tables(self):
129 | """显示所有数据表名称。"""
130 | sql = 'SHOW TABLES'
131 | return [d['Tables_in_%s' % self.schema] for d in self._transaction(sql, True)]
132 |
133 | def set_names(self, charset='utf8'):
134 | """设置输出字符集编码。"""
135 | sql = 'SET NAMES `%(name)s`' % {'name': charset.upper()}
136 | return self._transaction(sql)
137 |
138 | def _transaction(self, sql, fetch=False, cursor_class=None):
139 | """不要直接调用本方法,执行SQL语句并返回结果。"""
140 | self.affected_rows, self.last_executed, timestamp = 0, '', datetime.now().strftime('%Y-%m-%d %H:%M:%S')
141 | try:
142 | conn = self.connect(cursor_class)
143 | cursor = conn.cursor()
144 | self.affected_rows = cursor.execute(sql)
145 | except Exception as e:
146 | if self.debug:
147 | logger.exception(str(e))
148 | self.close()
149 | conn = self.connect(cursor_class)
150 | cursor = conn.cursor()
151 | self.affected_rows = cursor.execute(sql)
152 |
153 | self.last_executed = cursor._last_executed
154 | if self.debug:
155 | logger.debug('%s : %s ROW(S) AFFECTED WITH SQL: %s', timestamp, self.affected_rows, self.last_executed)
156 | result = cursor.fetchall() if fetch else self.affected_rows
157 | cursor.close()
158 | return result
159 |
160 |
161 | class Pool(object):
162 |
163 | def __init__(self, host, schema, user, pw, port=3306, charset='utf8',
164 | cursor_class='dict', autocommit=True, debug=True, pool_size=2,
165 | extras=4, wait_time=5, *args, **kwargs):
166 | """初始化数据库连接参数。
167 | :param host: 数据库主机。
168 | :param schema: 数据库。
169 | :param user: 用户名。
170 | :param pw: 密码。
171 | :param port: 端口。
172 | :param charset: 字符集。
173 | :param cursor_class: 游标类型。
174 | :param autocommit: 自动提交。
175 | :param debug: 调试模式。
176 | :param pool_size: 连接池大小。
177 | :param extras: 允许超出连接池大小。
178 | :param wait_time: 从连接池获取 Engine 对象超时时间。
179 | :param args: 其他参数。
180 | :param kwargs: 其他参数。
181 | """
182 | self.host = host
183 | self.schema = schema
184 | self.user = user
185 | self.pw = pw
186 | self.port = port
187 | self.connection = None
188 | self.charset = charset
189 | self.cursor_class = cursor_class
190 | self.autocommit = autocommit
191 | self.debug = debug
192 | self.args = args
193 | self.kwargs = kwargs
194 | self.affected_rows, self.last_executed = 0, ''
195 | self.wait_time = wait_time
196 | self.lock = RLock()
197 | self.pool_size = pool_size
198 | self.limits = extras + self.pool_size
199 | self._count = 0
200 | self.pool = Queue(self.pool_size)
201 |
202 | @property
203 | def count(self):
204 | return self._count
205 |
206 | def spawn_engine(self):
207 | self.lock.acquire()
208 | if self._count < self.limits:
209 | self._count += 1
210 | _engine = Engine(
211 | self.host, self.schema, self.user, self.pw, self.port, self.charset,
212 | self.cursor_class, self.autocommit, self.debug, *self.args, **self.kwargs)
213 | self.lock.release()
214 | else:
215 | self.lock.release()
216 | _engine = self.get()
217 |
218 | return _engine
219 |
220 | def put(self, engine=None):
221 | if not isinstance(engine, Engine):
222 | engine = self.spawn_engine()
223 | try:
224 | self.pool.put(engine, False)
225 | except Full:
226 | self.lock.acquire()
227 | self._count -= 1
228 | self.lock.release()
229 |
230 | def get(self):
231 | try:
232 | engine = self.pool.get(timeout=self.wait_time)
233 | self.pool.task_done()
234 | return engine
235 | except Empty:
236 | self.lock.acquire()
237 | if self._count < self.limits:
238 | self.lock.release()
239 | return self.spawn_engine()
240 | else:
241 | self.lock.release()
242 | engine = self.pool.get()
243 | self.pool.task_done()
244 | return engine
245 |
246 |
247 | class Column(object):
248 | def __init__(self, name):
249 | """数据库字段。"""
250 | self.name = name
251 |
252 | def __str__(self):
253 | return self.name
254 |
255 | def __eq__(self, other):
256 | name = '{0}_{1}'.format(self.name, 'eq')
257 | return '{0}=%({1})s'.format(self.name, name), {name: other}
258 |
259 | def __ne__(self, other):
260 | name = '{0}_{1}'.format(self.name, 'ne')
261 | return '{0}<>%({1})s'.format(self.name, name), {name: other}
262 |
263 | def __gt__(self, other):
264 | name = '{0}_{1}'.format(self.name, 'gt')
265 | return '{0}>%({1})s'.format(self.name, name), {name: other}
266 |
267 | def __ge__(self, other):
268 | name = '{0}_{1}'.format(self.name, 'ge')
269 | return '{0}>=%({1})s'.format(self.name, name), {name: other}
270 |
271 | def __lt__(self, other):
272 | name = '{0}_{1}'.format(self.name, 'lt')
273 | return '{0}<%({1})s'.format(self.name, name), {name: other}
274 |
275 | def __le__(self, other):
276 | name = '{0}_{1}'.format(self.name, 'le')
277 | return '{0}<=%({1})s'.format(self.name, name), {name: other}
278 |
279 | def like(self, other):
280 | name = '{0}_{1}'.format(self.name, 'like')
281 | return '{0} LIKE %({1})s'.format(self.name, name), {name: other}
282 |
283 | def in_(self, *other):
284 | names, maps = [], {}
285 | for index in range(len(other)):
286 | name = '{0}_{1}_{2}'.format(self.name, 'in', index)
287 | names.append("%({0})s".format(name))
288 | maps[name] = other[index]
289 | return '{0} IN ({1})'.format(self.name, ",".join(names)), maps
290 |
291 | def not_in(self, *other):
292 | names, maps = [], {}
293 | for index in range(len(other)):
294 | name = '{0}_{1}_{2}'.format(self.name, 'in', index)
295 | names.append("%({0})s".format(name))
296 | maps[name] = other[index]
297 | return '{0} NOT IN ({1})'.format(self.name, ",".join(names)), maps
298 |
299 | def between(self, floor, ceil):
300 | _floor = '{0}_{1}'.format(self.name, 'floor')
301 | _ceil = '{0}_{1}'.format(self.name, 'ceil')
302 | return '{0} BETWEEN %({1})s AND %({2})s'.format(self.name, _floor, _ceil), {_floor: floor, _ceil: ceil}
303 |
304 | def is_null(self, boolean=True):
305 | name = '{0}_{1}'.format(self.name, 'is_null')
306 | if boolean:
307 | return '{0} IS %({1})s'.format(self.name, name), {name: None}
308 | else:
309 | return '{0} IS NOT %({1})s'.format(self.name, name), {name: None}
310 |
311 | def sum(self):
312 | return 'SUM({0})'.format(self.name)
313 |
314 | def count(self):
315 | return "COUNT({0})".format(self.name)
316 |
317 | def max(self):
318 | return "MAX({0})".format(self.name)
319 |
320 | def min(self):
321 | return "MIN({0})".format(self.name)
322 |
323 |
324 | class Table(object):
325 | """数据表对象。"""
326 |
327 | def __init__(self, table_name, _engine=None, *columns):
328 | """初始化数据表,可以在columns参数中动态传入字段名称,或者覆写本方法并在新方法中直接定义字段。"""
329 | self.engine = _engine
330 | self.table_name = table_name
331 | self.add_column(*columns)
332 |
333 | def add_column(self, *columns):
334 | """增加字段。"""
335 | for column in columns:
336 | setattr(self, column.name, column) if isinstance(column, Column) else setattr(self, column, Column(column))
337 | return self
338 |
339 | def remove_column(self, *columns):
340 | """删除字段。"""
341 | for column in columns:
342 | self.__delattr__(column.name) if isinstance(column, Column) else self.__delattr__(column)
343 | return self
344 |
345 | def binding_engine(self, engine):
346 | """绑定用来建立数据库连接的Engine对象。"""
347 | self.engine = engine
348 | return self
349 |
350 | def select(self, *columns):
351 | """SELECT操作。"""
352 | return _Select(self.engine, self.table_name, 'SELECT', *columns)
353 |
354 | def insert(self, **assignments):
355 | """INSERT操作。"""
356 | return _Insert(self.engine, self.table_name, 'INSERT', **assignments)
357 |
358 | def update(self, **assignments):
359 | """UPDATE操作。"""
360 | return _Update(self.engine, self.table_name, 'UPDATE', **assignments)
361 |
362 | def delete(self):
363 | """DELETE操作。"""
364 | return _Delete(self.engine, self.table_name, 'DELETE')
365 |
366 | def count(self, column=None, distinct=None):
367 | """COUNT操作。"""
368 | return _Count(self.engine, self.table_name, 'COUNT', column, distinct)
369 |
370 |
371 | class _BaseSession(object):
372 | def __init__(self, engine, table_name, action, *columns, **assignments):
373 | self.engine, self.table_name, self.action = engine, table_name, action
374 | self._columns, self._assignments = columns, assignments
375 |
376 | self._where_clause, self._where_dict = '', {}
377 | self._distinct_clause = self._order_clause = self._limit_clause = ''
378 | self.affected_rows, self.last_executed = 0, ''
379 | self.limit(1) # for safety consideration
380 |
381 | def clear(self):
382 | self._where_clause, self._where_dict = '', {}
383 | self._distinct_clause = self._order_clause = self._limit_clause = ''
384 | self.limit(1) # for safety consideration
385 | return self
386 |
387 | def distinct(self, flag=True):
388 | """增加DISTINCT条件。"""
389 | self._distinct_clause = 'DISTINCT' if flag else ''
390 | return self
391 |
392 | def where(self, *columns):
393 | """
394 | 执行WHERE语句。
395 | :param columns: Column对象。
396 | """
397 | if columns:
398 | if self._where_clause:
399 | new_clause = '({0})'.format(' AND '.join([col[0] for col in columns]))
400 | self._where_clause = ' OR '.join([self._where_clause, new_clause])
401 | else:
402 | self._where_clause = 'WHERE ({0})'.format(' AND '.join([col[0] for col in columns]))
403 | self._where_dict.update(reduce(lambda x, y: x + y, [column[1].items() for column in columns]))
404 | else:
405 | self._where_clause, self._where_dict = '', {}
406 | return self
407 |
408 | def where_and(self, *columns):
409 | if columns:
410 | if self._where_clause:
411 | new_clause = '({0})'.format(' AND '.join([col[0] for col in columns]))
412 | self._where_clause = ' AND '.join([self._where_clause, new_clause])
413 | else:
414 | self._where_clause = 'WHERE ({0})'.format(' AND '.join([col[0] for col in columns]))
415 | self._where_dict.update(reduce(lambda x, y: x + y, [column[1].items() for column in columns]))
416 | else:
417 | self._where_clause, self._where_dict = '', {}
418 | return self
419 |
420 | def order(self, column=None, desc=False):
421 | """执行ORDER条件。"""
422 | self._order_clause = ('ORDER BY {0} {1}'.format(str(column), 'DESC' if desc else 'ASC')) if column else ''
423 | return self
424 |
425 | def limit(self, number=None, step=None):
426 | """执行LIMIT条件。"""
427 | self._limit_clause = '' if number is None else 'LIMIT %s' % number
428 | if None not in (number, step):
429 | self._limit_clause = '%s, %s' % (self._limit_clause, step)
430 | return self
431 |
432 | def _transaction(self, clauses, sql_dict, cursor_class):
433 | sql_clause = ' '.join([clause for clause in clauses if clause])
434 | self.affected_rows, self.last_executed, timestamp = 0, '', datetime.now().strftime('%Y-%m-%d %H:%M:%S')
435 |
436 | _engine = self.engine.get() if isinstance(self.engine, Pool) else self.engine
437 |
438 | try:
439 | conn = _engine.connect(cursor_class)
440 | cursor = conn.cursor()
441 | self.affected_rows = cursor.execute(sql_clause, sql_dict)
442 | except Exception as e:
443 | if _engine.debug:
444 | logger.exception(str(e))
445 | _engine.close()
446 | conn = _engine.connect(cursor_class)
447 | cursor = conn.cursor()
448 | self.affected_rows = cursor.execute(sql_clause, sql_dict)
449 | finally:
450 | if isinstance(self.engine, Pool):
451 | self.engine.put(_engine)
452 |
453 | self.last_executed = cursor._last_executed
454 | if _engine.debug:
455 | logger.debug('%s: %s ROW(S) AFFECTED WITH SQL: %s', timestamp, self.affected_rows, self.last_executed)
456 | result = None
457 | if self.action == 'SELECT':
458 | result = cursor.fetchall()
459 | elif self.action == 'INSERT':
460 | result = cursor.lastrowid
461 | elif self.action in ('UPDATE', 'DELETE'):
462 | result = self.affected_rows
463 | elif self.action == 'COUNT':
464 | result = cursor.fetchall()[0]['X']
465 | cursor.close()
466 | return result
467 |
468 |
469 | class _Select(_BaseSession):
470 | def __init__(self, engine, table_name, action, *columns, **assignments):
471 | super(_Select, self).__init__(engine, table_name, action, *columns, **assignments)
472 | self._action_clause = ', '.join([str(column) for column in self._columns]) or '*'
473 | self._group_by_clause = None
474 |
475 | def group_by(self, *columns):
476 | self._group_by_clause = 'GROUP BY %s' % (','.join([str(column) for column in columns]))
477 | return self
478 |
479 | def go(self, cursor_class=None):
480 | clauses = [self.action, self._distinct_clause, self._action_clause, 'FROM', self.table_name,
481 | self._where_clause, self._group_by_clause, self._order_clause, self._limit_clause]
482 | sql_dict = self._where_dict
483 | return self._transaction(clauses, sql_dict, cursor_class)
484 |
485 |
486 | class _Insert(_BaseSession):
487 | def __init__(self, engine, table_name, action, *columns, **assignments):
488 | super(_Insert, self).__init__(engine, table_name, action, *columns, **assignments)
489 | self._action_clause = ', '.join(['{0}=%(_insert_{0})s'.format(k) for k in self._assignments])
490 | self._action_dict = dict(('_insert_%s' % k, v) for k, v in self._assignments.items())
491 |
492 | def go(self, cursor_class=None):
493 | clauses = [self.action, 'INTO', self.table_name, 'SET', self._action_clause]
494 | sql_dict = self._action_dict
495 | return self._transaction(clauses, sql_dict, cursor_class)
496 |
497 |
498 | class _Update(_BaseSession):
499 | def __init__(self, engine, table_name, action, *columns, **assignments):
500 | super(_Update, self).__init__(engine, table_name, action, *columns, **assignments)
501 | self._action_clause = ', '.join(['{0}=%(_update_{0})s'.format(k) for k in self._assignments])
502 | self._action_dict = dict(('_update_%s' % k, v) for k, v in self._assignments.items())
503 |
504 | def go(self, cursor_class=None):
505 | clauses = [self.action, self.table_name, 'SET', self._action_clause, self._where_clause,
506 | self._order_clause, self._limit_clause]
507 | sql_dict = dict()
508 | sql_dict.update(self._action_dict, **self._where_dict)
509 | return self._transaction(clauses, sql_dict, cursor_class)
510 |
511 |
512 | class _Delete(_BaseSession):
513 | def __init__(self, engine, table_name, action, *columns, **assignments):
514 | super(_Delete, self).__init__(engine, table_name, action, *columns, **assignments)
515 |
516 | def go(self, cursor_class=None):
517 | clauses = [self.action, 'FROM', self.table_name, self._where_clause, self._order_clause, self._limit_clause]
518 | sql_dict = self._where_dict
519 | return self._transaction(clauses, sql_dict, cursor_class)
520 |
521 |
522 | class _Count(_BaseSession):
523 | def __init__(self, engine, table_name, action, *columns, **assignments):
524 | super(_Count, self).__init__(engine, table_name, action, *columns, **assignments)
525 | col, distinct = self._columns
526 | self._action_clause = ' '.join(['DISTINCT' if col and distinct else '', "'*'" if col is None else str(col)])
527 | self._action_clause = 'COUNT({0})'.format(self._action_clause)
528 |
529 | def go(self, cursor_class=None):
530 | clauses = ['SELECT', self._action_clause, 'AS X FROM', self.table_name, self._where_clause, self._limit_clause]
531 | sql_dict = self._where_dict
532 | return self._transaction(clauses, sql_dict, cursor_class)
533 |
534 |
535 | if __name__ == '__main__':
536 | pass
--------------------------------------------------------------------------------
/sample.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/env python
2 | # -*- coding: utf8 -*-
3 |
4 | from lazy_mysql import Engine, Table, Column, Pool
5 | import logging
6 |
7 | logging.basicConfig(level=logging.DEBUG)
8 |
9 | # create engine instance in order to connect local database
10 | engine = Engine('localhost', 'db_site_monitor', 'puppy', 'puppy')
11 |
12 | # Using Pool object which is a container to manage multiple Engine instances is a
13 | # better choice when you want to run multi threads with lazy_mysql.
14 | # The argument pool_size means the maximum Engine objects that are saved in pool.
15 | # The argument extras means it would create a number of extra Engine objects if
16 | # there is no one in pool.
17 | pool = Pool('localhost', 'db_site_monitor', 'puppy', 'puppy', pool_size=4, extras=10)
18 |
19 |
20 | # define Schedule object which is subclass of Table to map table 'tb_schedule_i' in database 'db_site_monitor'
21 | class Schedule(Table):
22 | def __init__(self, table_name='tb_schedule_i', _engine=engine, *columns):
23 | """
24 | This class maps itself to table tb_schedule_i in database db_site_monitor hosted in local machine.
25 | """
26 | super(Schedule, self).__init__(table_name, _engine, *columns)
27 |
28 | self.schedule_id = Column('scheduleId')
29 | self.task_id = Column('taskId')
30 | self.task_name = Column('taskName')
31 | self.status = Column('status')
32 | self.due_datetime = Column('dueDateTime')
33 | self.start_datetime = Column('startDateTime')
34 | self.end_datetime = Column('endDateTime')
35 | self.edit_datetime = Column('editDateTime')
36 |
37 |
38 | if __name__ == '__main__':
39 | # SHOW DATABASES
40 | engine.show_databases()
41 |
42 | # SHOW TABLES
43 | engine.show_tables()
44 |
45 | # SHOW CREATE TABLE `tb_schedule_i`
46 | engine.show_create_table('tb_schedule_i')
47 |
48 | # CREATE INSTANCE schedule
49 | schedule = Schedule()
50 |
51 | # SELECT * FROM tb_schedule_i LIMIT 1
52 | schedule.select().go()
53 |
54 | # SELECT taskName, status FROM tb_schedule_i WHERE (taskId=1) LIMIT 1
55 | schedule.select(schedule.task_name, schedule.status).where(schedule.task_id == 1).go()
56 |
57 | # SELECT DISTINCT * FROM tb_schedule_i ORDER BY dueDateTime DESC LIMIT 1, 2
58 | schedule.select().distinct().order(schedule.due_datetime, desc=True).limit(1, 2).go()
59 |
60 | # UPDATE tb_schedule_i SET status=0 WHERE (scheduleId=2 AND taskId=1) LIMIT 1
61 | schedule.update(**{schedule.status.name: 0}).where(schedule.schedule_id == 2, schedule.task_id == 1).go()
62 |
63 | # INSERT INTO tb_schedule_i SET status=1
64 | new_schedule_id = schedule.insert(**{schedule.status.name: 1}).go()
65 |
66 | # DELETE FROM tb_schedule_i WHERE (scheduleId=93) LIMIT 1
67 | schedule.delete().where(schedule.schedule_id == new_schedule_id).go()
68 |
69 | # SELECT COUNT(DISTINCT scheduleId) AS X FROM tb_schedule_i WHERE (scheduleId>50) LIMIT 1
70 | schedule.count(schedule.schedule_id, distinct=True).where(schedule.schedule_id > 50).go()
71 |
72 | pass
--------------------------------------------------------------------------------