首先这是一个很奇葩的需求,时间紧迫顺手胡写了一个,以后看看有没有好的思路
def and_(item_list):
return "%s:[%s]" % ("$and", ','.join(loop_func(item_list)))
def or_(item_list):
return "%s:[%s]" % ("$or", ','.join(loop_func(item_list)))
def lt(a, b):
return "%s<%s" % (a.name, b)
def le(a, b):
return "%s<=%s" % (a.name, b)
def ne(a, b):
return "%s!=%s" % (a.name, b)
def ge(a, b):
return "%s>=%s" % (a.name, b)
def eq(a, b):
return "%s=%s" % (a.name, b)
def gt(a, b):
return "%s>%s" % (a.name, b)
def in_op(a, b):
return '%s:{$in:%s}' % (a.name, b)
def notin_op(a, b):
return '%s:{$nin:%s}' % (a.name, b)
def desc_op(a):
return a
def asc_op(a):
return a.asc()
class ColumnOperators(object):
__slots__ = ['name']
def __init__(self, name):
self.name = name
def __and__(self, other):
return self.operate(and_, other)
def __or__(self, other):
return self.operate(or_, other)
def __lt__(self, other):
return self.operate(lt, other)
def __le__(self, other):
return self.operate(le, other)
def __eq__(self, other):
return self.operate(eq, other)
def __ne__(self, other):
return self.operate(ne, other)
def __gt__(self, other):
return self.operate(gt, other)
def __ge__(self, other):
return self.operate(ge, other)
def operate(self, op, other):
return op(self, other)
def in_(self, other):
return self.operate(in_op, other)
def notin_(self, other):
return self.operate(notin_op, other)
def desc(self):
return '{%s:1}' % self.name
def asc(self):
return '{%s:-1}' % self.name
dic = {'<': '$lt', '<=': '$lte', '=': '$eq', '>=': '$gte', '>': '$gt', '!=': '$ne'}
def split_func(item, op):
split_item_list = item.strip().split(op)
if len(split_item_list) != 2:
raise NotImplementedError("不支持同时两个及以上比较运算")
for split_item in split_item_list:
for key in dic:
if key in split_item:
raise NotImplementedError("不支持同时两个及以上比较运算")
return split_item_list, op
def loop_func(item_list):
and_or_list = []
for item in item_list:
if ">=" in item:
split_item_list, op = split_func(item, ">=")
and_or_list.append("{%s:{%s:%s}}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip()))
elif "<=" in item:
split_item_list, op = split_func(item, "<=")
and_or_list.append("{%s:{%s:%s}}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip()))
elif "!=" in item:
split_item_list, op = split_func(item, ">=")
and_or_list.append("{%s:{%s:%s}}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip()))
elif "<" in item:
split_item_list, op = split_func(item, "<")
and_or_list.append("{%s:{%s:%s}}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip()))
elif "=" in item:
split_item_list, op = split_func(item, "=")
and_or_list.append("{%s:{%s:%s}}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip()))
elif ">" in item:
split_item_list, op = split_func(item, ">")
and_or_list.append("{%s:{%s:%s}}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip()))
else:
and_or_list.append('{%s}' % item)
return and_or_list
def handle_op(item):
if ">=" in item:
split_item_list, op = split_func(item, ">=")
return "%s:{%s:%s}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip())
elif "<=" in item:
split_item_list, op = split_func(item, "<=")
return "%s:{%s:%s}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip())
elif "!=" in item:
split_item_list, op = split_func(item, "!=")
return "%s:{%s:%s}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip())
elif "<" in item:
split_item_list, op = split_func(item, "<")
return "%s:{%s:%s}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip())
elif "=" in item:
split_item_list, op = split_func(item, "=")
return "%s:{%s:%s}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip())
elif ">" in item:
split_item_list, op = split_func(item, ">")
return "%s:{%s:%s}" % (split_item_list[0].strip(), dic[op], split_item_list[1].strip())
else:
return item
class Query(object):
__slots__ = ['_projection_list', '_query_criteria_list', '_exec_order']
def __init__(self, *entities):
self._projection_list = []
self._query_criteria_list = []
self._set_entities(*entities)
self._exec_order = []
def _set_entities(self, *entities):
if entities is not ():
for ent in list(entities):
self._projection_list.append(ent.name)
def filter(self, *criterion):
if criterion is not ():
for cri in list(criterion):
self._query_criteria_list.append(handle_op(cri))
return self
def order_by(self, standard):
if 'sort' not in self._exec_order:
self._exec_order.append({'sort': standard})
else:
raise RuntimeError("sort方法只能调用一次")
return self
def limit(self, num):
if 'limit' not in self._exec_order:
self._exec_order.append({'limit': num})
else:
raise RuntimeError("limit方法只能调用一次")
return self
def skip(self, num):
if 'skip' not in self._exec_order:
self._exec_order.append({'skip': num})
else:
raise RuntimeError("skip方法只能调用一次")
return self
def query(*args):
return Query(*args)
class Users(object):
id = ColumnOperators('id')
name = ColumnOperators('name')
age = ColumnOperators('age')
def conditions(self): # 可以将这个方法写到类中,考虑到尽可能少的暴漏接口,就另外写了
dic = {}
if self._projection_list:
dic["columnStr"] = "{%s}" % (",".join(self._projection_list))
if self._query_criteria_list:
if len(self._query_criteria_list) == 1:
dic["condition"] = "{%s}" % (",".join(self._query_criteria_list))
else:
dic["condition"] = "{$and:[%s]}" % (",".join(['{%s}' % con for con in self._query_criteria_list]))
for i in self._exec_order:
dic.update(i)
return dic
if __name__ == '__main__':
Query.conditions = property(conditions)
query_obj = query(
Users.id,
Users.name
).filter(
and_([Users.id > 5, Users.age > 20]),
or_([Users.name == 'Tom', Users.name == 'Jade'])
).order_by(Users.age.desc()).limit(3)
print(query_obj.conditions)