This commit is contained in:
shufeng2012 committed 2026-07-24 06:35:46 +08:00
1 parent 0603c473fa
commit 03d7b07bf6
5 files changed
+334 -231

No files matched your search

+135 -41
View File
@@ -1,57 +1,151 @@
import sqlite3
import os
from flask import Flask, request, jsonify, g
from sqlalchemy import (
create_engine, MetaData, Table, select, insert, update, delete, text
)
from sqlalchemy.exc import SQLAlchemyError
from waitress import serve
app = Flask(__name__)
app.config['DATABASE'] = 'database.db'
def get_db():
if 'db' not in g:
conn = sqlite3.connect(app.config['DATABASE'])
conn.row_factory = sqlite3.Row
g.db = conn
return g.db
# 数据库配置
DATABASE_URL = os.environ.get('DATABASE_URL', 'sqlite:///database.db')
engine = create_engine(DATABASE_URL)
@app.teardown_appcontext
def close_db(exception):
db = g.pop('db', None)
if db is not None:
db.close()
# 缓存反射的元数据(避免每次请求都反射)
metadata = MetaData()
def get_table(table_name):
"""反射表对象(若已缓存则直接返回)"""
if table_name not in metadata.tables:
Table(table_name, metadata, autoload_with=engine)
return metadata.tables[table_name]
def build_where(table, conditions):
"""将条件字典转换为 SQLAlchemy 条件表达式"""
if not conditions:
return None
clauses = []
for col, val in conditions.items():
column = table.columns[col]
if isinstance(val, dict):
# 支持多种比较操作
if 'eq' in val:
clauses.append(column == val['eq'])
if 'ne' in val:
clauses.append(column != val['ne'])
if 'gt' in val:
clauses.append(column > val['gt'])
if 'lt' in val:
clauses.append(column < val['lt'])
if 'ge' in val:
clauses.append(column >= val['ge'])
if 'le' in val:
clauses.append(column <= val['le'])
if 'like' in val:
clauses.append(column.like(val['like']))
if 'in' in val:
clauses.append(column.in_(val['in']))
else:
# 直接等值比较
clauses.append(column == val)
from sqlalchemy import and_
return and_(*clauses)
@app.route('/execute', methods=['POST'])
def execute_sql():
def execute_structured():
data = request.get_json()
if not data or 'sql' not in data:
return jsonify({'success': False, 'error': '缺少 sql 字段'}), 400
if not data:
return jsonify({'success': False, 'error': '请求体不能为空'}), 400
sql = data['sql'].strip()
params = data.get('params', [])
# 参数必须是列表、元组或字典
if not isinstance(params, (list, tuple, dict)):
params = []
action = data.get('action', 'select')
table_name = data.get('table')
if not table_name:
return jsonify({'success': False, 'error': '缺少 table 字段'}), 400
try:
db = get_db()
cur = db.execute(sql, params)
db.commit()
try:
rows = cur.fetchall()
result = [dict(row) for row in rows]
except Exception:
result = []
return jsonify({
'success': True,
'data': result
})
table = get_table(table_name)
except Exception as e:
db = g.get('db')
if db:
db.rollback()
return jsonify({'success': False, 'error': f'表加载失败: {str(e)}'}), 400
conn = None
try:
conn = engine.connect()
result = []
if action == 'select':
columns = data.get('columns', None)
if columns:
cols = [table.columns[c] for c in columns]
else:
cols = [table] # select *
stmt = select(*cols)
where_cond = build_where(table, data.get('where'))
if where_cond is not None:
stmt = stmt.where(where_cond)
# 排序
order_by = data.get('order_by')
if order_by:
for item in order_by:
col = table.columns[item['column']]
stmt = stmt.order_by(col.desc() if item.get('desc') else col.asc())
# 分页
limit = data.get('limit')
if limit is not None:
stmt = stmt.limit(limit)
offset = data.get('offset')
if offset is not None:
stmt = stmt.offset(offset)
res = conn.execute(stmt)
rows = res.fetchall()
result = [dict(row._mapping) for row in rows]
elif action == 'insert':
values = data.get('values', {})
stmt = insert(table).values(**values)
res = conn.execute(stmt)
conn.commit()
result = [{'lastrowid': res.lastrowid}] if hasattr(res, 'lastrowid') else []
elif action == 'update':
values = data.get('values', {})
where_cond = build_where(table, data.get('where'))
stmt = update(table).values(**values)
if where_cond is not None:
stmt = stmt.where(where_cond)
res = conn.execute(stmt)
conn.commit()
result = [{'rowcount': res.rowcount}]
elif action == 'delete':
where_cond = build_where(table, data.get('where'))
stmt = delete(table)
if where_cond is not None:
stmt = stmt.where(where_cond)
res = conn.execute(stmt)
conn.commit()
result = [{'rowcount': res.rowcount}]
else:
return jsonify({'success': False, 'error': f'不支持的操作: {action}'}), 400
return jsonify({'success': True, 'data': result})
except SQLAlchemyError as e:
if conn:
conn.rollback()
return jsonify({'success': False, 'error': str(e)}), 400
except Exception as e:
if conn:
conn.rollback()
return jsonify({'success': False, 'error': str(e)}), 400
finally:
if conn:
conn.close()
if __name__ == '__main__':
# 单线程单进程,绑定 127.0.0.1:8005
serve(app, host='127.0.0.1', port=8005, threads=1)
# 单线程单进程,绑定 127.0.0.1
serve(app, host='127.0.0.1', port=8005, threads=1)