predicate 2.3.3 → 2.7.0

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.
Files changed (88) hide show
  1. checksums.yaml +5 -5
  2. data/Gemfile +4 -0
  3. data/LICENSE.md +17 -19
  4. data/README.md +467 -0
  5. data/bin/g +2 -0
  6. data/lib/predicate/dsl.rb +138 -0
  7. data/lib/predicate/factory.rb +149 -40
  8. data/lib/predicate/grammar.rb +11 -2
  9. data/lib/predicate/grammar.sexp.yml +31 -0
  10. data/lib/predicate/nodes/${op_name}.rb.jeny +12 -0
  11. data/lib/predicate/nodes/and.rb +9 -0
  12. data/lib/predicate/nodes/binary_func.rb +20 -0
  13. data/lib/predicate/nodes/contradiction.rb +2 -7
  14. data/lib/predicate/nodes/dyadic_comp.rb +1 -3
  15. data/lib/predicate/nodes/empty.rb +14 -0
  16. data/lib/predicate/nodes/eq.rb +11 -3
  17. data/lib/predicate/nodes/expr.rb +5 -3
  18. data/lib/predicate/nodes/has_size.rb +14 -0
  19. data/lib/predicate/nodes/identifier.rb +1 -3
  20. data/lib/predicate/nodes/in.rb +7 -6
  21. data/lib/predicate/nodes/intersect.rb +3 -23
  22. data/lib/predicate/nodes/literal.rb +1 -3
  23. data/lib/predicate/nodes/match.rb +1 -21
  24. data/lib/predicate/nodes/nadic_bool.rb +1 -3
  25. data/lib/predicate/nodes/native.rb +1 -3
  26. data/lib/predicate/nodes/not.rb +1 -3
  27. data/lib/predicate/nodes/opaque.rb +1 -3
  28. data/lib/predicate/nodes/qualified_identifier.rb +1 -3
  29. data/lib/predicate/nodes/set_op.rb +26 -0
  30. data/lib/predicate/nodes/subset.rb +11 -0
  31. data/lib/predicate/nodes/superset.rb +11 -0
  32. data/lib/predicate/nodes/tautology.rb +6 -7
  33. data/lib/predicate/nodes/unary_func.rb +16 -0
  34. data/lib/predicate/nodes/var.rb +46 -0
  35. data/lib/predicate/postgres/ext/factory.rb +28 -0
  36. data/lib/predicate/postgres/ext/to_sequel.rb +26 -0
  37. data/lib/predicate/postgres/ext.rb +2 -0
  38. data/lib/predicate/postgres/pg_array/empty.rb +10 -0
  39. data/lib/predicate/postgres/pg_array/literal.rb +10 -0
  40. data/lib/predicate/postgres/pg_array/overlaps.rb +10 -0
  41. data/lib/predicate/postgres/pg_array.rb +25 -0
  42. data/lib/predicate/postgres/rewriter.rb +49 -0
  43. data/lib/predicate/postgres.rb +4 -0
  44. data/lib/predicate/processors/qualifier.rb +4 -0
  45. data/lib/predicate/processors/renamer.rb +4 -0
  46. data/lib/predicate/processors/to_s.rb +28 -0
  47. data/lib/predicate/processors/unqualifier.rb +4 -0
  48. data/lib/predicate/sequel/to_sequel.rb +5 -1
  49. data/lib/predicate/sugar.rb +47 -0
  50. data/lib/predicate/version.rb +2 -2
  51. data/lib/predicate.rb +28 -4
  52. data/spec/dsl/test_dsl.rb +204 -0
  53. data/spec/dsl/test_evaluate.rb +65 -0
  54. data/spec/dsl/test_respond_to_missing.rb +35 -0
  55. data/spec/dsl/test_to_skake_case.rb +38 -0
  56. data/spec/factory/shared/a_comparison_factory_method.rb +1 -0
  57. data/spec/factory/test_${op_name}.rb.jeny +12 -0
  58. data/spec/factory/test_comp.rb +28 -5
  59. data/spec/factory/test_empty.rb +11 -0
  60. data/spec/factory/test_has_size.rb +11 -0
  61. data/spec/factory/test_match.rb +1 -0
  62. data/spec/factory/test_set_ops.rb +18 -0
  63. data/spec/factory/test_var.rb +22 -0
  64. data/spec/factory/test_vars.rb +27 -0
  65. data/spec/nodes/${op_name}.jeny/test_evaluate.rb.jeny +19 -0
  66. data/spec/nodes/empty/test_evaluate.rb +42 -0
  67. data/spec/nodes/has_size/test_evaluate.rb +44 -0
  68. data/spec/postgres/test_factory.rb +48 -0
  69. data/spec/postgres/test_to_postgres.rb +41 -0
  70. data/spec/postgres/test_to_sequel.rb +44 -0
  71. data/spec/predicate/test_and_split.rb +18 -0
  72. data/spec/predicate/test_attr_split.rb +18 -0
  73. data/spec/predicate/test_constant_variables.rb +24 -2
  74. data/spec/predicate/test_constants.rb +24 -0
  75. data/spec/predicate/test_evaluate.rb +205 -3
  76. data/spec/predicate/test_free_variables.rb +1 -1
  77. data/spec/predicate/test_to_hash.rb +40 -0
  78. data/spec/predicate/test_to_s.rb +37 -0
  79. data/spec/sequel/test_to_sequel.rb +26 -10
  80. data/spec/shared/a_predicate.rb +34 -0
  81. data/spec/spec_helper.rb +18 -1
  82. data/spec/test_predicate.rb +78 -33
  83. data/spec/test_readme.rb +80 -0
  84. data/spec/test_sugar.rb +48 -0
  85. data/tasks/test.rake +3 -3
  86. metadata +67 -11
  87. data/spec/factory/test_between.rb +0 -12
  88. data/spec/factory/test_intersect.rb +0 -12
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ class Predicate
4
+ describe 'to_postgres' do
5
+ subject {
6
+ predicate.to_postgres
7
+ }
8
+
9
+ context 'on an intersect' do
10
+ let(:predicate){
11
+ Predicate.intersect(:x, [1, 2, 3])
12
+ }
13
+
14
+ it 'returns another predicate' do
15
+ expect(subject).to be_a(Predicate)
16
+ end
17
+
18
+ it 'replaces intersect by pg_array_overlaps' do
19
+ expect(subject.sexpr).to eql([
20
+ :pg_array_overlaps,
21
+ [ :identifier, :x ],
22
+ [ :pg_array_literal, [1, 2, 3], :varchar ]
23
+ ])
24
+ end
25
+ end
26
+
27
+ context 'on an intersect' do
28
+ let(:predicate){
29
+ Predicate.empty(:x)
30
+ }
31
+
32
+ it 'replaces empty by pg_array_empty' do
33
+ expect(subject.sexpr).to eql([
34
+ :pg_array_empty,
35
+ [ :identifier, :x ],
36
+ :varchar
37
+ ])
38
+ end
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,44 @@
1
+ require 'spec_helper'
2
+ class Predicate
3
+ describe ToSequel do
4
+ PG_DB = Sequel.connect(ENV['PREDICATE_PG_URL'])
5
+
6
+ before(:all) do
7
+ create_items_database(PG_DB)
8
+ items = PG_DB[:items]
9
+ end
10
+
11
+ subject do
12
+ dataset = PG_DB[:items].where(predicate.to_postgres.to_sequel)
13
+ dataset
14
+ end
15
+
16
+ # after do
17
+ # subject.to_a
18
+ # end
19
+
20
+ context 'tautology' do
21
+ let(:predicate) { Predicate.tautology }
22
+
23
+ it 'works as expected' do
24
+ expect(subject.sql).to eql(%Q{SELECT * FROM "items" WHERE true})
25
+ end
26
+ end
27
+
28
+ context 'intersect' do
29
+ let(:predicate) { Predicate.intersect(:x, [1, 2, 3]) }
30
+
31
+ it 'works as expected' do
32
+ expect(subject.sql).to eql(%Q{SELECT * FROM "items" WHERE ("x" && ARRAY[1,2,3])})
33
+ end
34
+ end
35
+
36
+ context 'empty' do
37
+ let(:predicate) { Predicate.empty(:x) }
38
+
39
+ it 'works as expected' do
40
+ expect(subject.sql).to eql(%Q{SELECT * FROM "items" WHERE ("x" = '{}'::varchar[])})
41
+ end
42
+ end
43
+ end if ENV['PREDICATE_PG_URL']
44
+ end
@@ -83,5 +83,23 @@ class Predicate
83
83
  it{ should eq([ pred, p.tautology ]) }
84
84
  end
85
85
 
86
+ context "on intersect" do
87
+ let(:pred){ p.intersect(:x, [1, 2]) }
88
+
89
+ it{ should eq([ pred, p.tautology ]) }
90
+ end
91
+
92
+ context "on subset" do
93
+ let(:pred){ p.subset(:x, [1, 2]) }
94
+
95
+ it{ should eq([ pred, p.tautology ]) }
96
+ end
97
+
98
+ context "on superset" do
99
+ let(:pred){ p.superset(:x, [1, 2]) }
100
+
101
+ it{ should eq([ pred, p.tautology ]) }
102
+ end
103
+
86
104
  end
87
105
  end
@@ -47,6 +47,24 @@ class Predicate
47
47
  it{ should eq({ x: pred }) }
48
48
  end
49
49
 
50
+ context "on intersect" do
51
+ let(:pred){ p.intersect(:x, [2]) }
52
+
53
+ it{ should eq({ x: pred }) }
54
+ end
55
+
56
+ context "on subset" do
57
+ let(:pred){ p.subset(:x, [2]) }
58
+
59
+ it{ should eq({ x: pred }) }
60
+ end
61
+
62
+ context "on superset" do
63
+ let(:pred){ p.superset(:x, [2]) }
64
+
65
+ it{ should eq({ x: pred }) }
66
+ end
67
+
50
68
  context "on match" do
51
69
  let(:pred){ p.match(:x, "London") }
52
70
 
@@ -37,14 +37,36 @@ class Predicate
37
37
  describe "on an intersect with one value" do
38
38
  let(:p){ Predicate.intersect(:x, [2]) }
39
39
 
40
- # TODO: is that correct?
41
40
  it{ expect(subject).to eql([]) }
42
41
  end
43
42
 
44
43
  describe "on an intersect with a placeholder" do
45
44
  let(:p){ Predicate.intersect(:x, Predicate.placeholder) }
46
45
 
47
- # TODO: is that correct?
46
+ it{ expect(subject).to eql([]) }
47
+ end
48
+
49
+ describe "on an subset with one value" do
50
+ let(:p){ Predicate.subset(:x, [2]) }
51
+
52
+ it{ expect(subject).to eql([]) }
53
+ end
54
+
55
+ describe "on an subset with a placeholder" do
56
+ let(:p){ Predicate.subset(:x, Predicate.placeholder) }
57
+
58
+ it{ expect(subject).to eql([]) }
59
+ end
60
+
61
+ describe "on an superset with one value" do
62
+ let(:p){ Predicate.superset(:x, [2]) }
63
+
64
+ it{ expect(subject).to eql([]) }
65
+ end
66
+
67
+ describe "on an superset with a placeholder" do
68
+ let(:p){ Predicate.superset(:x, Predicate.placeholder) }
69
+
48
70
  it{ expect(subject).to eql([]) }
49
71
  end
50
72
 
@@ -119,6 +119,30 @@ class Predicate
119
119
  it{ should eq({}) }
120
120
  end
121
121
 
122
+ context "on subset" do
123
+ let(:pred){ p.subset(:x, [4,8]) }
124
+
125
+ it{ should eq({}) }
126
+ end
127
+
128
+ context "on subset with placeholder" do
129
+ let(:pred){ p.subset(:x, p.placeholder) }
130
+
131
+ it{ should eq({}) }
132
+ end
133
+
134
+ context "on superset" do
135
+ let(:pred){ p.superset(:x, [4,8]) }
136
+
137
+ it{ should eq({}) }
138
+ end
139
+
140
+ context "on superset with placeholder" do
141
+ let(:pred){ p.superset(:x, p.placeholder) }
142
+
143
+ it{ should eq({}) }
144
+ end
145
+
122
146
  context "on or (two eqs)" do
123
147
  let(:pred){ p.eq(:x, 2) | p.eq(:y, 4) }
124
148
 
@@ -40,7 +40,7 @@ class Predicate
40
40
 
41
41
  context 'on a factored predicate' do
42
42
  let(:predicate){
43
- Predicate.new(Factory.lte(:x => 2))
43
+ Predicate.lte(:x => 2)
44
44
  }
45
45
 
46
46
  describe "on x == 2" do
@@ -80,7 +80,7 @@ class Predicate
80
80
  end
81
81
  end
82
82
 
83
- context 'on an intersect predicate' do
83
+ context 'on an intersect predicate, with array literal' do
84
84
  let(:predicate){
85
85
  Predicate.intersect(:x, [8,9])
86
86
  }
@@ -98,6 +98,168 @@ class Predicate
98
98
  end
99
99
  end
100
100
 
101
+ context 'on an intersect predicate, with two variables' do
102
+ let(:predicate){
103
+ Predicate.intersect(:x, :y)
104
+ }
105
+
106
+ describe "on x == [2]" do
107
+ let(:scope){ { :x => [2], :y => [8,9] } }
108
+
109
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
110
+ end
111
+
112
+ describe "on x == [9,12]" do
113
+ let(:scope){ { :x => [9,12], :y => [8,9] } }
114
+
115
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
116
+ end
117
+ end
118
+
119
+ context 'on an subset predicate, with an array literal' do
120
+ let(:predicate){
121
+ Predicate.subset(:x, [8,9])
122
+ }
123
+
124
+ describe "on x == [2]" do
125
+ let(:scope){ { :x => [2] } }
126
+
127
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
128
+ end
129
+
130
+ describe "on x == []" do
131
+ let(:scope){ { :x => [] } }
132
+
133
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
134
+ end
135
+
136
+ describe "on x == [9]" do
137
+ let(:scope){ { :x => [9] } }
138
+
139
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
140
+ end
141
+
142
+ describe "on x == [8, 9]" do
143
+ let(:scope){ { :x => [8, 9] } }
144
+
145
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
146
+ end
147
+
148
+ describe "on x == [8, 9, 10]" do
149
+ let(:scope){ { :x => [8, 9, 19] } }
150
+
151
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
152
+ end
153
+ end
154
+
155
+ context 'on an subset predicate, with two variables' do
156
+ let(:predicate){
157
+ Predicate.subset(:x, :y)
158
+ }
159
+
160
+ describe "on x == [2]" do
161
+ let(:scope){ { :x => [2], :y => [8,9] } }
162
+
163
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
164
+ end
165
+
166
+ describe "on x == []" do
167
+ let(:scope){ { :x => [], :y => [8,9] } }
168
+
169
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
170
+ end
171
+
172
+ describe "on x == [9]" do
173
+ let(:scope){ { :x => [9], :y => [8,9] } }
174
+
175
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
176
+ end
177
+
178
+ describe "on x == [8, 9]" do
179
+ let(:scope){ { :x => [8, 9], :y => [8,9] } }
180
+
181
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
182
+ end
183
+
184
+ describe "on x == [8, 9, 10]" do
185
+ let(:scope){ { :x => [8, 9, 19], :y => [8,9] } }
186
+
187
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
188
+ end
189
+ end
190
+
191
+ context 'on an superset predicate, with an array literal' do
192
+ let(:predicate){
193
+ Predicate.superset(:x, [8,9])
194
+ }
195
+
196
+ describe "on x == [2]" do
197
+ let(:scope){ { :x => [2] } }
198
+
199
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
200
+ end
201
+
202
+ describe "on x == []" do
203
+ let(:scope){ { :x => [] } }
204
+
205
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
206
+ end
207
+
208
+ describe "on x == [9]" do
209
+ let(:scope){ { :x => [9] } }
210
+
211
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
212
+ end
213
+
214
+ describe "on x == [8, 9]" do
215
+ let(:scope){ { :x => [8, 9] } }
216
+
217
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
218
+ end
219
+
220
+ describe "on x == [8, 9, 10]" do
221
+ let(:scope){ { :x => [8, 9, 19] } }
222
+
223
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
224
+ end
225
+ end
226
+
227
+ context 'on an superset predicate, with two variables' do
228
+ let(:predicate){
229
+ Predicate.superset(:x, :y)
230
+ }
231
+
232
+ describe "on x == [2]" do
233
+ let(:scope){ { :x => [2], :y => [8,9] } }
234
+
235
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
236
+ end
237
+
238
+ describe "on x == []" do
239
+ let(:scope){ { :x => [], :y => [8,9] } }
240
+
241
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
242
+ end
243
+
244
+ describe "on x == [9]" do
245
+ let(:scope){ { :x => [9], :y => [8,9] } }
246
+
247
+ it{ expect(predicate.evaluate(scope)).to be_falsy }
248
+ end
249
+
250
+ describe "on x == [8, 9]" do
251
+ let(:scope){ { :x => [8, 9], :y => [8,9] } }
252
+
253
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
254
+ end
255
+
256
+ describe "on x == [8, 9, 10]" do
257
+ let(:scope){ { :x => [8, 9, 19], :y => [8,9] } }
258
+
259
+ it{ expect(predicate.evaluate(scope)).to be_truthy }
260
+ end
261
+ end
262
+
101
263
  context 'on a match against a string' do
102
264
  let(:predicate){
103
265
  Predicate.match(:x, "12")
@@ -228,12 +390,52 @@ class Predicate
228
390
 
229
391
  context 'has a call alias' do
230
392
  let(:predicate){
231
- Predicate.new(Factory.gte(:x => 0))
393
+ Predicate.gte(:x => 0)
232
394
  }
233
395
 
234
396
  let(:scope){ { x: 2 } }
235
397
 
236
398
  it{ expect(predicate.call(scope)).to be(true) }
237
399
  end
400
+
401
+ context "on a var, build with a dotted string" do
402
+ let(:predicate){
403
+ Predicate.var("x.0.y")
404
+ }
405
+
406
+ let(:scope){ { x: [{ y: 2 }] } }
407
+
408
+ it{ expect(predicate.call(scope)).to eql(2) }
409
+ end
410
+
411
+ context "on a var, build with a . string" do
412
+ let(:predicate){
413
+ Predicate.var(".")
414
+ }
415
+
416
+ let(:scope){ { x: [{ y: 2 }] } }
417
+
418
+ it{ expect(predicate.call(scope)).to be(scope) }
419
+ end
420
+
421
+ context "on a var, build with an array for terms" do
422
+ let(:predicate){
423
+ Predicate.var([:x, 0, :y])
424
+ }
425
+
426
+ let(:scope){ { x: [{ y: 2 }] } }
427
+
428
+ it{ expect(predicate.call(scope)).to eql(2) }
429
+ end
430
+
431
+ context "on a var, build with an empty array" do
432
+ let(:predicate){
433
+ Predicate.var([])
434
+ }
435
+
436
+ let(:scope){ { x: [{ y: 2 }] } }
437
+
438
+ it{ expect(predicate.call(scope)).to be(scope) }
439
+ end
238
440
  end
239
441
  end
@@ -9,6 +9,6 @@ class Predicate
9
9
 
10
10
  it{ should eq([:x]) }
11
11
  end
12
-
12
+
13
13
  end
14
14
  end
@@ -0,0 +1,40 @@
1
+ require 'spec_helper'
2
+ class Predicate
3
+ describe Predicate, "to_hash" do
4
+
5
+ let(:p){ Predicate }
6
+
7
+ subject{ predicate.to_hash }
8
+
9
+ context "tautology" do
10
+ let(:predicate){ Predicate.tautology }
11
+
12
+ it{ expect(subject).to eql({}) }
13
+ end
14
+
15
+ context "contradiction" do
16
+ let(:predicate){ Predicate.contradiction }
17
+
18
+ it{ expect{ subject }.to raise_error(ArgumentError) }
19
+ end
20
+
21
+ context "eq" do
22
+ let(:predicate){ Predicate.eq(:x, 2) }
23
+
24
+ it{ expect(subject).to eql(x: 2) }
25
+ end
26
+
27
+ context "in" do
28
+ let(:predicate){ Predicate.in(:x, [2,3]) }
29
+
30
+ it{ expect(subject).to eql(x: [2,3]) }
31
+ end
32
+
33
+ context "and" do
34
+ let(:predicate){ Predicate.eq(:x, 3) & Predicate.in(:y, [2,3]) }
35
+
36
+ it{ expect(subject).to eql(x: 3, y: [2,3]) }
37
+ end
38
+
39
+ end
40
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+ class Predicate
3
+ describe Predicate, "to_s" do
4
+
5
+ let(:p){ Predicate }
6
+
7
+ subject{ predicate.to_s }
8
+
9
+ context "tautology" do
10
+ let(:predicate){ Predicate.tautology }
11
+
12
+ it{ expect(subject).to eql("true") }
13
+ end
14
+
15
+ context "contradiction" do
16
+ let(:predicate){ Predicate.contradiction }
17
+
18
+ it{ expect(subject).to eql("false") }
19
+ end
20
+
21
+ context "var" do
22
+ let(:predicate){ Predicate.var("x.y") }
23
+
24
+ it{ expect(subject).to eql("dig(x.y)") }
25
+ end
26
+
27
+ context "var when used in another predicate" do
28
+ let(:predicate){
29
+ v = Predicate.var("x.y")
30
+ Predicate.eq(v, 6)
31
+ }
32
+
33
+ it{ expect(subject).to eql("dig(x.y) == 6") }
34
+ end
35
+
36
+ end
37
+ end
@@ -1,19 +1,11 @@
1
1
  require 'spec_helper'
2
- require 'sequel'
3
- require 'sqlite3'
4
- require 'predicate/sequel'
5
2
  class Predicate
6
3
  describe ToSequel do
7
4
 
8
5
  DB = Sequel.sqlite
9
6
 
10
7
  before(:all) do
11
- DB.create_table :items do
12
- primary_key :id
13
- String :name
14
- String :address
15
- Float :price
16
- end
8
+ create_items_database(DB)
17
9
  items = DB[:items]
18
10
  end
19
11
 
@@ -140,6 +132,15 @@ class Predicate
140
132
  end
141
133
  end
142
134
 
135
+ context 'nary and' do
136
+ let(:predicate) { Predicate.eq(:name, "Bob") & Predicate.eq(:price, 10.0) & Predicate.eq(:city, "London") }
137
+
138
+ it 'works as expected' do
139
+ puts predicate.sexpr.inspect
140
+ expect(subject).to eql("SELECT * FROM `items` WHERE ((`name` = 'Bob') AND (`price` = 10.0) AND (`city` = 'London'))")
141
+ end
142
+ end
143
+
143
144
  context 'or' do
144
145
  let(:predicate) { Predicate.eq(:name, "Bob") | Predicate.lt(:price, 10.0) }
145
146
 
@@ -164,6 +165,22 @@ class Predicate
164
165
  end
165
166
  end
166
167
 
168
+ context 'subset' do
169
+ let(:predicate) { Predicate.subset(:x, [8, 9]) }
170
+
171
+ it 'raises an error' do
172
+ expect { subject }.to raise_error(NotSupportedError)
173
+ end
174
+ end
175
+
176
+ context 'superset' do
177
+ let(:predicate) { Predicate.superset(:x, [8, 9]) }
178
+
179
+ it 'raises an error' do
180
+ expect { subject }.to raise_error(NotSupportedError)
181
+ end
182
+ end
183
+
167
184
  context 'match' do
168
185
  let(:predicate) { Predicate.match(left, right, options) }
169
186
  let(:options){ nil }
@@ -204,6 +221,5 @@ class Predicate
204
221
  expect { subject }.to raise_error(NotSupportedError)
205
222
  end
206
223
  end
207
-
208
224
  end
209
225
  end
@@ -0,0 +1,34 @@
1
+ shared_examples_for "a predicate" do
2
+
3
+ let(:w){ [8, 9] }
4
+ let(:x){ 12 }
5
+ let(:y){ 13 }
6
+
7
+ it 'is a Predicate' do
8
+ subject.should be_a(Predicate)
9
+ end
10
+
11
+ it 'can be negated easily' do
12
+ (!subject).should be_a(Predicate)
13
+ end
14
+
15
+ it 'detects stupid AND' do
16
+ (subject & Predicate.tautology).should be(subject)
17
+ end
18
+
19
+ it 'detects stupid OR' do
20
+ (subject | Predicate.contradiction).should be(subject)
21
+ end
22
+
23
+ it 'has free variables' do
24
+ (fv = subject.free_variables).should be_a(Array)
25
+ (fv - [ :w, :x, :y ]).should be_empty
26
+ end
27
+
28
+ it 'always splits around and trivially when no free variables are touched' do
29
+ top, down = subject.and_split([:z])
30
+ top.should be_tautology
31
+ down.should eq(subject)
32
+ end
33
+
34
+ end
data/spec/spec_helper.rb CHANGED
@@ -1,9 +1,26 @@
1
1
  $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
2
- require "rspec"
2
+ require 'rspec'
3
+ require 'sequel'
4
+ require 'sqlite3'
5
+ require 'pg'
3
6
  require 'predicate'
7
+ require 'predicate/sequel'
8
+ require 'predicate/postgres'
9
+ require_relative 'shared/a_predicate'
4
10
 
11
+ Sequel.extension :pg_array, :pg_array_ops
5
12
  module Helpers
6
13
 
14
+ def create_items_database(db)
15
+ db.drop_table? :items
16
+ db.create_table :items do
17
+ primary_key :id
18
+ String :name
19
+ String :address
20
+ Float :price
21
+ end
22
+ end
23
+
7
24
  end
8
25
 
9
26
  RSpec.configure do |c|