from pyparsing import * from sqlalchemy import and_, or_ from mods.user.mods.user.models import User # 定义词法规则 operand = Word(alphanums) | quotedString.setParseAction(removeQuotes) integer = Word(nums).setParseAction(lambda t: int(t[0])) floating = Combine(Word(nums) + '.' + Word(nums)).setParseAction(lambda t: float(t[0])) none = CaselessKeyword("None").setParseAction(lambda t: None) boolean = (CaselessKeyword("True") | CaselessKeyword("False")).setParseAction(lambda t: t[0] == "True") value = operand | integer | floating | none | boolean array = Group(Suppress('[') + delimitedList(value, delim=',') + Suppress(']')) operator = oneOf("< = > != like in") comparison = Group(operand + operator + (value | array)) # 定义解析动作 def convert_to_sqlalchemy_comparison(tokens): field, op, value = tokens[0] if op == '<': return ("condition", getattr(User, field).__lt__(value)) elif op == '>': return ("condition", getattr(User, field).__gt__(value)) elif op == '=': return ("condition", getattr(User, field).__eq__(value)) elif op == '!=': return ("condition", getattr(User, field).__ne__(value)) elif op == 'like': return ("condition", getattr(User, field).like(value)) elif op == 'in': return ("condition", getattr(User, field).in_(value)) else: raise Exception(f"Unknown operator: {op}") comparison.setParseAction(convert_to_sqlalchemy_comparison) # 定义解析动作 def combine_and(s, l, t): return ("and", t[0][::2]) def combine_or(s, l, t): return ("or", t[0][::2]) # 定义语法规则 and__ = CaselessKeyword("and") or__ = CaselessKeyword("or") condition = infixNotation(comparison, [(and__, 2, opAssoc.LEFT, combine_and), (or__, 2, opAssoc.LEFT, combine_or)]) from sqlalchemy import and_, or_ def build_query(parsed): if isinstance(parsed, tuple) and len(parsed) == 2: operator, conditions = parsed if operator == "and": return and_(*[build_query(condition) for condition in conditions]) elif operator == "or": return or_(*[build_query(condition) for condition in conditions]) else: raise Exception(f"Unknown operator: {operator}") elif isinstance(parsed, tuple) and parsed[0] == "condition": return parsed[1] else: raise Exception(f"Unknown condition: {parsed}") # 测试 # 测试解析 parsed = condition.parseString( "name like 'lili' or name like 'lina' or (phone < 50 and phone > 10) and email in ['london',1,1.2,None,False,True] and id = 1") print(parsed) query = build_query(parsed) print(query)