filter.py 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293
  1. #!/usr/bin/env python
  2. # -*- coding: utf-8 -*-
  3. from enum import Enum
  4. from initialize import regex_sql_str, regex_dsl_str
  5. __author__ = 'James Iter'
  6. __date__ = '2016/10/3'
  7. __contact__ = 'james.iter.cn@gmail.com'
  8. __copyright__ = '(c) 2016 by James Iter.'
  9. class FilterFieldType(Enum):
  10. INT = 'int'
  11. STR = 'str'
  12. BOOL = 'bool'
  13. class Filter(object):
  14. operator = {'eq': '=',
  15. 'gt': '>',
  16. 'lt': '<',
  17. 'ne': '!=',
  18. 'in': 'in',
  19. 'notin': 'in',
  20. 'like': 'like'}
  21. def __init__(self):
  22. pass
  23. @staticmethod
  24. def get_fit_statement(field_type=None, value=''):
  25. if field_type == FilterFieldType.INT.value:
  26. if not value.lstrip('-').isdigit():
  27. raise TypeError(''.join(['Value: ', str(value), ' should be digit']))
  28. return value
  29. elif field_type == FilterFieldType.STR.value:
  30. _s = regex_sql_str.sub('"', str(value)).strip('"')
  31. return ''.join(['"', _s.replace('"', '\\"'), '"'])
  32. elif field_type == FilterFieldType.BOOL.value:
  33. return str(False) if value.lower() == 'false' else str(True)
  34. else:
  35. raise TypeError(''.join(['unknown type ', str(field_type)]))
  36. @classmethod
  37. def dsl_to_sql(cls, allow_keywords=None, dsl=''):
  38. sql_stmt = ''
  39. if regex_dsl_str.match(dsl) is None:
  40. return sql_stmt
  41. keyword, operator, value = dsl.split(':', 2)
  42. operator = operator.lower()
  43. if keyword not in allow_keywords.keys():
  44. return sql_stmt
  45. field_type = allow_keywords[keyword]
  46. if operator in ['eq', 'gt', 'lt', 'ne']:
  47. sql_stmt = keyword + cls.operator[operator] + cls.get_fit_statement(field_type=field_type, value=value)
  48. elif operator == 'in':
  49. # from itertools import repeat
  50. # _sql_stmt = map(cls.get_fit_statement, repeat(field_type, len(value.split(','))), value.split(','))
  51. # 上面为通过map实现的方式
  52. _sql_stmt = [cls.get_fit_statement(field_type=field_type, value=v) for v in value.split(',')]
  53. sql_stmt = keyword + ' in (' + ','.join(_sql_stmt) + ')'
  54. elif operator == 'notin':
  55. _sql_stmt = [cls.get_fit_statement(field_type=field_type, value=v) for v in value.split(',')]
  56. sql_stmt = keyword + ' not in (' + ','.join(_sql_stmt) + ')'
  57. elif operator == 'like':
  58. sql_stmt = keyword + ' like "%' + cls.get_fit_statement(
  59. field_type=field_type, value=value).strip('"') + '%"'
  60. return sql_stmt
  61. @classmethod
  62. def filter_str_to_sql(cls, allow_keywords=None, filter_str=''):
  63. sql_stmts = []
  64. for dsl in filter_str.split(';'):
  65. sql_stmt = cls.dsl_to_sql(allow_keywords=allow_keywords, dsl=dsl)
  66. if sql_stmt == '':
  67. continue
  68. sql_stmts.append(sql_stmt)
  69. return ' AND '.join(sql_stmts)