]>
Commit | Line | Data |
---|---|---|
1d09f67e TL |
1 | # Licensed to the Apache Software Foundation (ASF) under one |
2 | # or more contributor license agreements. See the NOTICE file | |
3 | # distributed with this work for additional information | |
4 | # regarding copyright ownership. The ASF licenses this file | |
5 | # to you under the Apache License, Version 2.0 (the | |
6 | # "License"); you may not use this file except in compliance | |
7 | # with the License. You may obtain a copy of the License at | |
8 | # | |
9 | # http://www.apache.org/licenses/LICENSE-2.0 | |
10 | # | |
11 | # Unless required by applicable law or agreed to in writing, | |
12 | # software distributed under the License is distributed on an | |
13 | # "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY | |
14 | # KIND, either express or implied. See the License for the | |
15 | # specific language governing permissions and limitations | |
16 | # under the License. | |
17 | ||
18 | module Arrow | |
19 | class Slicer | |
20 | def initialize(table) | |
21 | @table = table | |
22 | end | |
23 | ||
24 | def [](column_name) | |
25 | column = @table[column_name] | |
26 | return nil if column.nil? | |
27 | ColumnCondition.new(column) | |
28 | end | |
29 | ||
30 | def respond_to_missing?(name, include_private) | |
31 | return true if self[name] | |
32 | super | |
33 | end | |
34 | ||
35 | def method_missing(name, *args, &block) | |
36 | if args.empty? | |
37 | column_condition = self[name] | |
38 | return column_condition if column_condition | |
39 | end | |
40 | super | |
41 | end | |
42 | ||
43 | module Helper | |
44 | class << self | |
45 | def ensure_boolean(column) | |
46 | case column.data_type | |
47 | when Arrow::BooleanDataType | |
48 | column.data | |
49 | else | |
50 | options = CastOptions.new | |
51 | options.to_data_type = Arrow::BooleanDataType.new | |
52 | Function.find("cast").execute([column.data], options).value | |
53 | end | |
54 | end | |
55 | end | |
56 | end | |
57 | ||
58 | class Condition | |
59 | def evaluate | |
60 | message = "Slicer::Condition must define \#evaluate: #{inspect}" | |
61 | raise NotImplementedError.new(message) | |
62 | end | |
63 | ||
64 | def &(condition) | |
65 | AndCondition.new(self, condition) | |
66 | end | |
67 | ||
68 | def |(condition) | |
69 | OrCondition.new(self, condition) | |
70 | end | |
71 | ||
72 | def ^(condition) | |
73 | XorCondition.new(self, condition) | |
74 | end | |
75 | end | |
76 | ||
77 | class LogicalCondition < Condition | |
78 | def initialize(condition1, condition2) | |
79 | @condition1 = condition1 | |
80 | @condition2 = condition2 | |
81 | end | |
82 | ||
83 | def evaluate | |
84 | function.execute([@condition1.evaluate, @condition2.evaluate]).value | |
85 | end | |
86 | end | |
87 | ||
88 | class AndCondition < LogicalCondition | |
89 | private | |
90 | def function | |
91 | Function.find("and") | |
92 | end | |
93 | end | |
94 | ||
95 | class OrCondition < LogicalCondition | |
96 | private | |
97 | def function | |
98 | Function.find("or") | |
99 | end | |
100 | end | |
101 | ||
102 | class XorCondition < LogicalCondition | |
103 | private | |
104 | def function | |
105 | Function.find("xor") | |
106 | end | |
107 | end | |
108 | ||
109 | class ColumnCondition < Condition | |
110 | def initialize(column) | |
111 | @column = column | |
112 | end | |
113 | ||
114 | def evaluate | |
115 | Helper.ensure_boolean(@column) | |
116 | end | |
117 | ||
118 | def !@ | |
119 | NotColumnCondition.new(@column) | |
120 | end | |
121 | ||
122 | def null? | |
123 | self == nil | |
124 | end | |
125 | ||
126 | def valid? | |
127 | self != nil | |
128 | end | |
129 | ||
130 | def ==(value) | |
131 | EqualCondition.new(@column, value) | |
132 | end | |
133 | ||
134 | def !=(value) | |
135 | NotEqualCondition.new(@column, value) | |
136 | end | |
137 | ||
138 | def <(value) | |
139 | LessCondition.new(@column, value) | |
140 | end | |
141 | ||
142 | def <=(value) | |
143 | LessEqualCondition.new(@column, value) | |
144 | end | |
145 | ||
146 | def >(value) | |
147 | GreaterCondition.new(@column, value) | |
148 | end | |
149 | ||
150 | def >=(value) | |
151 | GreaterEqualCondition.new(@column, value) | |
152 | end | |
153 | ||
154 | def in?(values) | |
155 | InCondition.new(@column, values) | |
156 | end | |
157 | ||
158 | def select(&block) | |
159 | SelectCondition.new(@column, block) | |
160 | end | |
161 | ||
162 | def reject(&block) | |
163 | RejectCondition.new(@column, block) | |
164 | end | |
165 | end | |
166 | ||
167 | class NotColumnCondition < Condition | |
168 | def initialize(column) | |
169 | @column = column | |
170 | end | |
171 | ||
172 | def evaluate | |
173 | data = Helper.ensure_boolean(@column) | |
174 | Function.find("invert").execute([data]).value | |
175 | end | |
176 | ||
177 | def !@ | |
178 | ColumnCondition.new(@column) | |
179 | end | |
180 | end | |
181 | ||
182 | class EqualCondition < Condition | |
183 | def initialize(column, value) | |
184 | @column = column | |
185 | @value = value | |
186 | end | |
187 | ||
188 | def !@ | |
189 | NotEqualCondition.new(@column, @value) | |
190 | end | |
191 | ||
192 | def evaluate | |
193 | if @value.nil? | |
194 | Function.find("is_null").execute([@column.data]).value | |
195 | else | |
196 | Function.find("equal").execute([@column.data, @value]).value | |
197 | end | |
198 | end | |
199 | end | |
200 | ||
201 | class NotEqualCondition < Condition | |
202 | def initialize(column, value) | |
203 | @column = column | |
204 | @value = value | |
205 | end | |
206 | ||
207 | def !@ | |
208 | EqualCondition.new(@column, @value) | |
209 | end | |
210 | ||
211 | def evaluate | |
212 | if @value.nil? | |
213 | Function.find("is_valid").execute([@column.data]).value | |
214 | else | |
215 | Function.find("not_equal").execute([@column.data, @value]).value | |
216 | end | |
217 | end | |
218 | end | |
219 | ||
220 | class LessCondition < Condition | |
221 | def initialize(column, value) | |
222 | @column = column | |
223 | @value = value | |
224 | end | |
225 | ||
226 | def !@ | |
227 | GreaterEqualCondition.new(@column, @value) | |
228 | end | |
229 | ||
230 | def evaluate | |
231 | Function.find("less").execute([@column.data, @value]).value | |
232 | end | |
233 | end | |
234 | ||
235 | class LessEqualCondition < Condition | |
236 | def initialize(column, value) | |
237 | @column = column | |
238 | @value = value | |
239 | end | |
240 | ||
241 | def !@ | |
242 | GreaterCondition.new(@column, @value) | |
243 | end | |
244 | ||
245 | def evaluate | |
246 | Function.find("less_equal").execute([@column.data, @value]).value | |
247 | end | |
248 | end | |
249 | ||
250 | class GreaterCondition < Condition | |
251 | def initialize(column, value) | |
252 | @column = column | |
253 | @value = value | |
254 | end | |
255 | ||
256 | def !@ | |
257 | LessEqualCondition.new(@column, @value) | |
258 | end | |
259 | ||
260 | def evaluate | |
261 | Function.find("greater").execute([@column.data, @value]).value | |
262 | end | |
263 | end | |
264 | ||
265 | class GreaterEqualCondition < Condition | |
266 | def initialize(column, value) | |
267 | @column = column | |
268 | @value = value | |
269 | end | |
270 | ||
271 | def !@ | |
272 | LessCondition.new(@column, @value) | |
273 | end | |
274 | ||
275 | def evaluate | |
276 | Function.find("greater_equal").execute([@column.data, @value]).value | |
277 | end | |
278 | end | |
279 | ||
280 | class InCondition < Condition | |
281 | def initialize(column, values) | |
282 | @column = column | |
283 | @values = values | |
284 | end | |
285 | ||
286 | def !@ | |
287 | NotInCondition.new(@column, @values) | |
288 | end | |
289 | ||
290 | def evaluate | |
291 | values = @values | |
292 | values = Array.new(values) unless values.is_a?(Array) | |
293 | options = SetLookupOptions.new(values) | |
294 | Function.find("is_in").execute([@column.data], options).value | |
295 | end | |
296 | end | |
297 | ||
298 | class NotInCondition < Condition | |
299 | def initialize(column, values) | |
300 | @column = column | |
301 | @values = values | |
302 | end | |
303 | ||
304 | def !@ | |
305 | InCondition.new(@column, @values) | |
306 | end | |
307 | ||
308 | def evaluate | |
309 | values = @values | |
310 | values = Array.new(values) unless values.is_a?(Array) | |
311 | options = SetLookupOptions.new(values) | |
312 | booleans = Function.find("is_in").execute([@column.data], options).value | |
313 | Function.find("invert").execute([booleans]).value | |
314 | end | |
315 | end | |
316 | ||
317 | class SelectCondition < Condition | |
318 | def initialize(column, block) | |
319 | @column = column | |
320 | @block = block | |
321 | end | |
322 | ||
323 | def !@ | |
324 | RejectCondition.new(@column, @block) | |
325 | end | |
326 | ||
327 | def evaluate | |
328 | BooleanArray.new(@column.collect(&@block)) | |
329 | end | |
330 | end | |
331 | ||
332 | class RejectCondition < Condition | |
333 | def initialize(column, block) | |
334 | @column = column | |
335 | @block = block | |
336 | end | |
337 | ||
338 | def !@ | |
339 | SelectCondition.new(@column, @block) | |
340 | end | |
341 | ||
342 | def evaluate | |
343 | raw_array = @column.collect do |value| | |
344 | evaluated_value = @block.call(value) | |
345 | if evaluated_value.nil? | |
346 | nil | |
347 | else | |
348 | not evaluated_value | |
349 | end | |
350 | end | |
351 | BooleanArray.new(raw_array) | |
352 | end | |
353 | end | |
354 | end | |
355 | end |