sparkql 1.3.1 → 1.3.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 0f8f460c07a1a833cd0a80040f686b12a9579db3bc0ae60d1cc7aa1c73fe644d
4
- data.tar.gz: 66a6701ad74dc5454d9e4dd2a14c0ea133715e10ba5babb676c90aed62e917bd
3
+ metadata.gz: 1fb6060ec97e59958c12e0ed3338540afa180bf28eab0224af3ffef568dbf469
4
+ data.tar.gz: 982d3956830686faeb210e6abf52125d18d4d68fa0d231b00a251a4876e1bd14
5
5
  SHA512:
6
- metadata.gz: 661e847ae1aa0f336706d94129c0afdc7d0ba040c0c8f62b7a6e9248dcc990d8f0179ef153355e050bae2b8a2f676c7e358081280418986c6c0bbf27393ac572
7
- data.tar.gz: 4b64da6af2453236ec0b9c0e240238241609c79e0d4b8cca2c126ecc9b5e3b7e9c585836cc0dceb9a5136cb9decb993bffdef0145720de8dd734b2b2f291f340
6
+ metadata.gz: 6754d10ca449bbd3467127a8470bb4233dd00b5162984ca636bcd93aff41743b25ace78fdd30ba77cbb6a79bef55d36118f67f2102b676ca9184db04c2437c01
7
+ data.tar.gz: d337d7169ceb202c6f4d8a066196c472404cccf5e1b6f0fc13bf07a4fba62fa6d135c04bfc017544c73fb84ca1834f5d06c78bbf5ee2848ac16b06372b09b711
data/CHANGELOG.md CHANGED
@@ -1,3 +1,13 @@
1
+
2
+ v1.3.3, 2025-08-12
3
+ -------------------
4
+ * [BUGFIX] Evaluator fix for Not regression
5
+
6
+ v1.3.2, 2025-08-06
7
+ -------------------
8
+ * [BUGFIX] More Evaluator fixes
9
+ * [BUGFIX] fixed the build.
10
+
1
11
  v1.3.1, 2025-08-06
2
12
  -------------------
3
13
  * [BUGFIX] Evaluator fix for Not expressions
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.1
1
+ 1.3.3
@@ -1,9 +1,12 @@
1
+
1
2
  # Using an instance of ExpressionResolver to resolve the individual expressions,
2
3
  # this class will evaluate the rest of a parsed sparkql string to true or false.
3
4
  # Namely, this class will handle all the nesting, boolean algebra, and dropped
4
5
  # fields. Plus, it has some optimizations built in to skip the processing for
5
6
  # any expressions that don't contribute to the net result of the filter.
6
7
  class Sparkql::Evaluator
8
+ include Sparkql::Token
9
+
7
10
  attr_reader :processed_count
8
11
 
9
12
  def initialize(expression_resolver)
@@ -40,6 +43,11 @@ class Sparkql::Evaluator
40
43
  block = expression[:block_group]
41
44
  block_group = block_groups[block]
42
45
 
46
+ if expression[:conjunction] == NOT && expression[:conjunction_level] == level
47
+ expression[:conjunction] = AND
48
+ expression[:unary] = NOT
49
+ end
50
+
43
51
  unless block_group
44
52
  block_groups[block] ||= block_builder(expression, level)
45
53
  block_group = block_groups[block]
@@ -48,9 +56,9 @@ class Sparkql::Evaluator
48
56
 
49
57
  # When dealing with Not expression conjunctions at the block level,
50
58
  # it's far simpler to convert it into the equivalent "And Not"
51
- if block_group[:conjunction] == "Not"
52
- block_group[:unary] = "Not"
53
- block_group[:conjunction] = "And"
59
+ if block_group[:conjunction] == NOT
60
+ block_group[:unary] = NOT
61
+ block_group[:conjunction] = AND
54
62
  end
55
63
 
56
64
  # Every block group _must_ be seen as an expression in another block
@@ -60,20 +68,22 @@ class Sparkql::Evaluator
60
68
  # with a level -1 here to turn the top level expressions into a block
61
69
  # group for processing.
62
70
  current_level = level
71
+ last_block_group = block_group
63
72
  while current_level >= 0
64
73
  current_level -= 1
65
74
  levels[current_level] ||= []
66
75
  last_block_group_id = levels[current_level].last
67
76
  if last_block_group_id
68
- block_groups[last_block_group_id][:expressions] << block_group
77
+ block_groups[last_block_group_id][:expressions] << last_block_group
69
78
  break
70
79
  else
71
80
  block_id = "placeholder_for_#{block}_#{current_level}"
72
- placeholder_block = block_builder(block_group, current_level)
73
- placeholder_block[:expressions] << block_group
81
+ placeholder_block = block_builder(last_block_group, current_level)
82
+ placeholder_block[:expressions] << last_block_group
74
83
 
75
84
  levels[current_level] << block_id
76
85
  block_groups[block_id] = placeholder_block
86
+ last_block_group = placeholder_block
77
87
  end
78
88
  end
79
89
  end
@@ -98,7 +108,7 @@ class Sparkql::Evaluator
98
108
  block_group[:expressions].each do |expression|
99
109
  # If we encounter any or's in the same block group, we can cheat at
100
110
  # resolving the rest, if we are at a true
101
- if block_result && expression[:conjunction] == 'Or'
111
+ if block_result && expression[:conjunction] == OR
102
112
  break
103
113
  end
104
114
 
@@ -112,7 +122,7 @@ class Sparkql::Evaluator
112
122
  end
113
123
  next if expression_result == :drop
114
124
 
115
- if expression[:unary] == "Not"
125
+ if expression[:unary] == NOT
116
126
  expression_result = !expression_result
117
127
  end
118
128
 
@@ -122,11 +132,11 @@ class Sparkql::Evaluator
122
132
  end
123
133
 
124
134
  case expression[:conjunction]
125
- when 'Not'
135
+ when NOT
126
136
  block_result &= !expression_result
127
- when 'And'
137
+ when AND
128
138
  block_result &= expression_result
129
- when 'Or'
139
+ when OR
130
140
  block_result |= expression_result
131
141
  else
132
142
  # Not a supported conjunction. We skip over this for backwards
@@ -134,7 +144,7 @@ class Sparkql::Evaluator
134
144
  end
135
145
  end
136
146
 
137
- # block_group.delete(:expressions)
147
+ block_group.delete(:expressions)
138
148
  block_group[:result] = block_result
139
149
  final_result = block_result
140
150
  end
data/lib/sparkql/token.rb CHANGED
@@ -24,8 +24,15 @@ module Sparkql::Token
24
24
  NULL = /NULL|null|Null/.freeze
25
25
  # Reserved words
26
26
  RANGE_OPERATOR = 'Bt'.freeze
27
- EQUALITY_OPERATORS = %w[Eq Ne].freeze
27
+ EQUAL = 'Eq'.freeze
28
+ NOT_EQUAL = 'Ne'.freeze
29
+ EQUALITY_OPERATORS = [EQUAL, NOT_EQUAL].freeze
30
+
28
31
  OPERATORS = %w[Gt Ge Lt Le] + EQUALITY_OPERATORS
29
- UNARY_CONJUNCTIONS = ['Not'].freeze
30
- CONJUNCTIONS = %w[And Or].freeze
32
+
33
+ NOT = 'Not'.freeze
34
+ AND = 'And'.freeze
35
+ OR = 'Or'.freeze
36
+ UNARY_CONJUNCTIONS = [NOT].freeze
37
+ CONJUNCTIONS = [AND, OR].freeze
31
38
  end
@@ -64,35 +64,93 @@ class EvaluatorTest < Test::Unit::TestCase
64
64
  def test_dropped_field_handling
65
65
  assert sample("Test Eq 'Drop' And Test Eq true")
66
66
  assert !sample("Test Eq 'Drop' And Test Eq false")
67
- assert !sample("Test Eq 'Drop' Or Test Eq false")
67
+
68
68
  assert sample("Test Eq 'Drop' Or Test Eq true")
69
+ assert !sample("Test Eq 'Drop' Or Test Eq false")
70
+
69
71
  assert sample("Test Eq false And Test Eq 'Drop' Or Test Eq true")
72
+ assert !sample("Test Eq false And Test Eq 'Drop' Or Test Eq false")
73
+
70
74
  assert sample("Test Eq false Or (Test Eq 'Drop' And Test Eq true)")
75
+ assert !sample("Test Eq false Or (Test Eq 'Drop' And Test Eq false)")
76
+
77
+ assert sample("Test Eq false Or (Not Test Eq 'Drop' And Test Eq true)")
78
+ assert !sample("Test Eq false Or (Not Test Eq 'Drop' And Test Eq false)")
79
+
80
+ assert sample("Test Eq true Not Test Eq 'Drop' And Test Eq true")
81
+ assert !sample("Test Eq true Not Test Eq 'Drop' And Test Eq false")
82
+ assert !sample("Test Eq false Not Test Eq 'Drop' And Test Eq false")
83
+
84
+ assert sample("Test Eq true And Test Eq 'Drop' Not Test Eq false")
85
+ assert !sample("Test Eq true And Test Eq 'Drop' Not Test Eq true")
86
+ assert !sample("Test Eq true And Test Eq 'Drop' Not Test Eq true")
87
+
88
+ assert sample("Test Eq true Not (Test Eq 'Drop' And Test Eq false)")
89
+ assert !sample("Test Eq true Not (Test Eq 'Drop' And Test Eq true)")
90
+ assert !sample("Test Eq true Not (Test Eq 'Drop' And Test Eq true)")
71
91
  end
72
92
 
73
93
  def test_nesting
74
94
  assert sample("Test Eq true Or (Test Eq true) And Test Eq false And (Test Eq true)")
95
+ assert sample("Test Eq true Or (Test Eq false) And Test Eq false And (Test Eq false)")
96
+ assert sample("Test Eq false Or (Test Eq true) And Test Eq true And (Test Eq true)")
97
+ assert !sample("Test Eq false Or (Test Eq false) And Test Eq false And (Test Eq false)")
98
+ assert !sample("Test Eq false Or (Test Eq true) And Test Eq false And (Test Eq false)")
99
+ assert !sample("Test Eq false Or (Test Eq false) And Test Eq true And (Test Eq false)")
100
+ assert !sample("Test Eq false Or (Test Eq false) And Test Eq false And (Test Eq true)")
101
+
75
102
  assert sample("Test Eq true Or ((Test Eq false) And Test Eq false) And (Test Eq false)")
76
103
  assert sample("(Test Eq false Or Test Eq true) Or (Test Eq false Or Test Eq false)")
77
104
  assert sample("(Test Eq true And Test Eq true) Or (Test Eq false)")
78
105
  assert sample("(Test Eq true And Test Eq true) Or (Test Eq false And Test Eq true)")
79
106
  assert !sample("(Test Eq false And Test Eq true) Or (Test Eq false)")
107
+
80
108
  assert sample("Test Eq true And ((Test Eq true And Test Eq false) Or Test Eq true)")
81
109
  assert !sample("Test Eq true And ((Test Eq true And Test Eq false) Or Test Eq false) And Test Eq true")
82
110
  assert !sample("Test Eq true And ((Test Eq true And Test Eq false) Or Test Eq false) Or Test Eq false")
83
111
  assert sample("Test Eq true And ((Test Eq true And Test Eq false) Or Test Eq false) Or Test Eq true")
112
+ assert !sample("(Test Eq true Or Test Eq true) And Test Eq false")
113
+ assert !sample("(Test Eq true Or Test Eq true) And (Test Eq false)")
114
+
115
+ assert sample("(Test Eq true Or Test Eq true) And (Test Eq false Or Test Eq true)")
116
+ assert !sample("(Test Eq true Or Test Eq true) And (Test Eq false Or Test Eq false)")
117
+
118
+ assert sample("(Test Eq true) Not Test Eq false And (Test Eq true)")
119
+ assert !sample("(Test Eq true) Not Test Eq true And (Test Eq true)")
120
+ assert !sample("(Test Eq false) Not Test Eq false And (Test Eq true)")
121
+ assert !sample("(Test1 Eq true) Not Test2 Eq false And (Test3 Eq false)")
84
122
  end
85
123
 
86
124
  def test_nots
87
125
  assert sample("Test Eq true Not Test Eq false")
88
126
  assert !sample("Test Eq true Not Test Eq true")
127
+ assert !sample("Test Eq false Not Test Eq true")
128
+ assert !sample("Test Eq false Not Test Eq false")
129
+
130
+ assert sample("Test Eq true And Test Eq true Not Test Eq false")
131
+ assert !sample("Test Eq false And Test Eq true Not Test Eq false")
132
+ assert !sample("Test Eq true And Test Eq true Not Test Eq true")
133
+ assert !sample("Test Eq true And Test Eq false Not Test Eq false")
134
+
89
135
  assert sample("Test Eq true Not (Test Eq false Or Test Eq false)")
90
- assert sample("Test Eq true Not (Test Eq false And Test Eq false)")
91
136
  assert !sample("Test Eq true Not (Test Eq false Or Test Eq true)")
92
137
  assert !sample("Test Eq true Not (Test Eq true Or Test Eq false)")
93
- assert !sample("Test Eq true Not (Not Test Eq false)")
94
- assert !sample("Test Eq false And Test Eq true Not Test Eq false")
138
+ assert !sample("Test Eq true Not (Test Eq true Or Test Eq true)")
139
+ assert !sample("Test Eq false Not (Test Eq false Or Test Eq false)")
140
+
141
+ assert sample("Test Eq true Not (Test Eq false And Test Eq false)")
142
+ assert sample("Test Eq true Not (Test Eq true And Test Eq false)")
143
+ assert sample("Test Eq true Not (Test Eq false And Test Eq true)")
144
+ assert !sample("Test Eq true Not (Test Eq true And Test Eq true)")
145
+ assert !sample("Test Eq false Not (Test Eq false And Test Eq false)")
146
+
147
+ assert sample("Test Eq true Not (Test Eq false Or Test Eq false) And (Test Eq true Or Test Eq false)")
148
+ assert sample("Test Eq true Not (Test Eq false Or Test Eq false) And (Test Eq false Or Test Eq true)")
149
+ assert sample("Test Eq true Not (Test Eq false Or Test Eq false) And (Test Eq true Or Test Eq true)")
95
150
  assert !sample("Test Eq true Not (Test Eq false Or Test Eq false) And (Test Eq false Or Test Eq false)")
151
+ assert !sample("Test Eq true Not (Test Eq false Or Test Eq true) And (Test Eq true Or Test Eq false)")
152
+ assert !sample("Test Eq true Not (Test Eq true Or Test Eq false) And (Test Eq true Or Test Eq false)")
153
+ assert !sample("Test Eq false Not (Test Eq false Or Test Eq false) And (Test Eq true Or Test Eq false)")
96
154
  end
97
155
 
98
156
  def test_unary_nots
@@ -105,17 +163,14 @@ class EvaluatorTest < Test::Unit::TestCase
105
163
 
106
164
  def test_unary_double_nots
107
165
  assert sample("Not (Not(Not Test Eq true))")
166
+ assert !sample("Not (Not(Not Test Eq false))")
167
+
168
+ assert sample("Test Eq true Not (Not Test Eq true)")
169
+ assert !sample("Test Eq true Not (Not Test Eq false)")
170
+ assert !sample("Test Eq false Not (Not Test Eq true)")
108
171
  end
109
172
 
110
173
  def test_examples
111
- # This one is based on a real life example that had problems.
112
- #
113
- # CurrentPrice Bt 130000.00,180000.00 And PropertySubType Eq 'Single Family Residence' And
114
- # SchoolDistrict Eq 'Byron Center','Grandville','Jenison' And MlsStatus Eq 'Active' And
115
- # BathsTotal Bt 1.50,9999.00 And BedsTotal Bt 3,99 And PropertyType Eq 'A'
116
- # Not "Garage"."Garage2" Eq 'No' And "Pool"."OutdoorAbove" Eq true
117
- # And "Pool"."OutdoorInground" Eq true Not "Substructure"."Michigan Basement" Eq true
118
-
119
174
  assert !sample("Test Eq false And Test Eq true And " \
120
175
  "Test Eq false And Test Eq true And " \
121
176
  "Test Eq true And Test Eq true And Test Eq true " \
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: sparkql
3
3
  version: !ruby/object:Gem::Version
4
- version: 1.3.1
4
+ version: 1.3.3
5
5
  platform: ruby
6
6
  authors:
7
7
  - Wade McEwen
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2025-08-07 00:00:00.000000000 Z
11
+ date: 2025-08-19 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: georuby