Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158

159

160

161

162

163

164

165

166

167

168

169

170

171

172

173

174

175

176

177

178

179

180

181

182

183

184

185

186

187

188

189

190

191

192

193

194

195

196

197

198

199

200

201

202

203

204

205

206

207

208

209

210

211

212

213

214

215

216

# 

# BSD licence 

# 

# Author : Bro <bro.development@gmail.com> 

# 

 

 

def enum(*sequential, **named): 

    enums = dict(zip(sequential, range(len(sequential))), **named) 

    return type('Enum', (), enums) 

 

try: 

    strinstance = basestring 

except: 

    strinstance = str 

 

 

def is_iterable_but_not_str(x): 

    return hasattr(x, '__iter__') and not isinstance(x, strinstance) 

 

 

class Expression(object): 

    def __init__(self, **kwargs): 

        self.key = kwargs.get("key", None) 

        self.value = kwargs.get("value", None) 

        self.filter_value = self.value 

        self.operator = kwargs.get("operator", None) 

 

exit        if kwargs: 

            if self.operator == Filter.operations.LIKE: 

                self.filter_value = "'%%%s%%'" % self.value 

            elif self.operator == Filter.operations.ILIKE: 

                self.filter_value = "'*%s*'" % self.value 

            elif self.operator == Filter.operations.IN: 

                self.filter_value = "('%s')" % "','".join(self.value) 

            else: 

                if type(self.value) is bool: 

                    self.filter_value = 1 if self.value else 0 

                else: 

                    self.filter_value = "'%s'" % self.value 

 

    def filter_string(self): 

        filter_str = "%s %s %s" % (self.key, self.operator, self.filter_value) 

        return filter_str 

 

    def filter(self): 

        filter_str = "? %s ?" % (self.operator) 

        filter_values = (self.key, self.operator, self.filter_value) 

        return filter_str, filter_values 

 

    def __str__(self): 

        return self.filter_string() 

 

 

class ExpressionGroup(object): 

 

    def __init__(self): 

        self.expression = None 

        self.exp_group1 = None 

        self.exp_group2 = None 

        self.exp_operator = None 

 

    def is_dummy(self): 

        return self.expression is None and self.exp_operator is None 

 

    def is_filtered(self): 

        return not self.is_dummy() 

 

    def __or__(self, exp_group): 

        if exp_group.is_dummy() or self.is_dummy(): 

            return exp_group if self.is_dummy() else self 

        new_exp_group = type(self)() 

        new_exp_group.exp_group1 = exp_group 

        new_exp_group.exp_group2 = self 

        new_exp_group.exp_operator = Filter.operations.OR 

        return new_exp_group 

 

    def __and__(self, exp_group): 

        if exp_group.is_dummy() or self.is_dummy(): 

            return exp_group if self.is_dummy() else self 

        new_exp_group = type(self)() 

        new_exp_group.exp_group1 = exp_group 

        new_exp_group.exp_group2 = self 

        new_exp_group.exp_operator = Filter.operations.AND 

        return new_exp_group 

 

    def __str__(self): 

89        if self.is_dummy(): 

            return "" 

        if self.expression: 

            return self.expression.filter_string() 

        else: 

            return "((%s) %s (%s))" % (self.exp_group1.filter_string(), self.exp_operator, 

                                       self.exp_group2.filter_string()) 

 

    def filter(self): 

        if self.is_dummy(): 

            return "", [] 

        if self.expression: 

            return self.expression.filter() 

        else: 

            group1_str, group1_values = self.exp_group1.filter() 

            group2_str, group2_values = self.exp_group2.filter() 

            filter_str = "((%s) %s (%s))" % (group1_str, self.exp_operator, group2_str) 

            return filter_str, group1_values + group2_values 

 

    def filter_string(self): 

        return str(self) 

 

 

class Filter(object): 

    """A filter to be used to filter the results from a database query. 

    Users should not have to use this class.""" 

    operations = enum(**{'AND': 'AND', 'OR': 'OR', 'LIKE': 'LIKE', 'ILIKE': "GLOB", 

                         "IN": "IN", 'EQ': "=", 'NE': "!=", 'LT': "<", 'LE': "<=", 

                         'GT': ">", 'GE': ">="}) 

 

    def __init__(self, db, key): 

        self.db = db 

        self.key = key 

        self.expression_group = ExpressionGroup() 

        self.expression_t = Expression 

 

    def is_filtered(self): 

        """If the filter contains any filters""" 

        return not self.expression_group.is_dummy() 

 

    def _comparison(self, value, operation): 

        self.expression_group.expression = self.expression_t(key=self.key, 

                                                             value=value, operator=operation) 

        return self 

 

    def like(self, value): 

        """Perform LIKE operation""" 

        return self._comparison(value, self.operations.LIKE) 

 

    def ilike(self, value): 

        """Perform ILIKE operation""" 

        return self._comparison(value, self.operations.ILIKE) 

 

    def __eq__(self, value): 

        """Perform EQUALS operation 

        When input value is an iterable, but not a string, it will match for 

        any of the values on the iterable 

        """ 

        # Iterable, so we use IN (X, X...) instead of = 

        if is_iterable_but_not_str(value): 

            return self._comparison(value, self.operations.IN) 

        else: 

            return self._comparison(value, self.operations.EQ) 

 

    def __ne__(self, value): 

        """Perform NOT EQUALS operation""" 

        return self._comparison(value, self.operations.NE) 

 

    def __lt__(self, value): 

        """Perform LESS THAN operation""" 

        return self._comparison(value, self.operations.LT) 

 

    def __le__(self, value): 

        """Perform LESS THAN OR EQUALS operation""" 

        return self._comparison(value, self.operations.LE) 

 

    def __gt__(self, value): 

        """Perform GREATER THAN operation""" 

        return self._comparison(value, self.operations.GT) 

 

    def __ge__(self, value): 

        """Perform GREATER THAN OR EQUALS operation""" 

        return self._comparison(value, self.operations.GE) 

 

    def __and__(self, other_filter): 

        """ 

        Returns a new filter that combines this filter with other_filter using AND. 

        """ 

        new_filter = type(self)(self.db, None) 

        new_filter.expression_group = self.expression_group & other_filter.expression_group 

        return new_filter 

 

    def __or__(self, other_filter): 

        """ 

        Returns a new filter that combines this filter with other_filter using OR. 

        """ 

        new_filter = type(self)(self.db, None) 

        new_filter.expression_group = self.expression_group | other_filter.expression_group 

        return new_filter 

 

    def __len__(self): 

        """Returns the number of records that matches this filter""" 

        if self.expression_group.is_dummy(): 

            count = len(self.db) 

        else: 

            count = self.db._len(db_filter=self.expression_group) 

        return count 

 

    def __iter__(self): 

        """Returns in iterator over the records for this filter""" 

201        if self.expression_group.is_dummy(): 

            res = self.db() 

        else: 

            res = self.db(self.expression_group) 

        return iter(res) 

 

    def __str__(self): 

        """Returns a string representation of the filter""" 

209        if self.expression_group: 

            return self.expression_group.filter_string() 

        else: 

            return "" 

 

    def filter(self): 

        """Returns the filter""" 

        if self.expression_group: 

            return self.expression_group.filter() 

        else: 

            return "", []