factbase 0.7.1 → 0.7.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 +4 -4
- data/benchmarks/simple.rb +1 -1
- data/lib/factbase/churn.rb +4 -0
- data/lib/factbase/looged.rb +1 -1
- data/lib/factbase/taped.rb +12 -9
- data/lib/factbase.rb +8 -7
- data/test/factbase/test_churn.rb +1 -0
- data/test/factbase/test_looged.rb +6 -6
- data/test/factbase/test_query.rb +30 -23
- data/test/factbase/test_taped.rb +10 -0
- data/test/test_factbase.rb +50 -12
- metadata +1 -1
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1d14f3343341431bb4e9828abfc7f2c0bdda83d2c484cf6df1dbbc49b9b442ca
|
4
|
+
data.tar.gz: 48e762c8d0c94102c8e757469c177698db655714128ae315d53696421fecce04
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 584de94a190d5a07693d788f9d36db7899b6535e353315d41a864184384f62825a0b6c0885a23a9f7332621bb96891362fdc090f2f6e11dac7663af9b5c35fef
|
7
|
+
data.tar.gz: 78b784ccb6d2800dd3aa3711dd74cd43ec801a8343f87b695d47d6d9ae195d78e9350c57900dac388304da2a91f17b0b2bbf16ba8475fb794aea000e22a4c517
|
data/benchmarks/simple.rb
CHANGED
data/lib/factbase/churn.rb
CHANGED
data/lib/factbase/looged.rb
CHANGED
@@ -50,7 +50,7 @@ class Factbase::Looged
|
|
50
50
|
if rollback
|
51
51
|
@loog.debug("Txn ##{id} rolled back in #{start.ago}")
|
52
52
|
else
|
53
|
-
@loog.debug("Txn ##{id} #{r
|
53
|
+
@loog.debug("Txn ##{id} touched #{r} in #{start.ago}")
|
54
54
|
end
|
55
55
|
r
|
56
56
|
end
|
data/lib/factbase/taped.rb
CHANGED
@@ -16,9 +16,9 @@ class Factbase::Taped
|
|
16
16
|
|
17
17
|
def initialize(origin, lookup: {})
|
18
18
|
@origin = origin
|
19
|
-
@inserted =
|
20
|
-
@deleted =
|
21
|
-
@added =
|
19
|
+
@inserted = Set.new
|
20
|
+
@deleted = Set.new
|
21
|
+
@added = Set.new
|
22
22
|
@lookup = lookup
|
23
23
|
end
|
24
24
|
|
@@ -37,7 +37,7 @@ class Factbase::Taped
|
|
37
37
|
# rubocop:disable Lint/HashCompareByIdentity
|
38
38
|
@lookup[map.object_id] = map
|
39
39
|
# rubocop:enable Lint/HashCompareByIdentity
|
40
|
-
@inserted.
|
40
|
+
@inserted.add(map.object_id)
|
41
41
|
end
|
42
42
|
|
43
43
|
def each
|
@@ -54,7 +54,7 @@ class Factbase::Taped
|
|
54
54
|
r = yield m
|
55
55
|
if r
|
56
56
|
@lookup.delete(m.object_id)
|
57
|
-
@deleted.
|
57
|
+
@deleted.add(m.object_id)
|
58
58
|
end
|
59
59
|
r
|
60
60
|
end
|
@@ -75,7 +75,7 @@ class Factbase::Taped
|
|
75
75
|
|
76
76
|
def []=(key, value)
|
77
77
|
@origin[key] = value
|
78
|
-
@added.
|
78
|
+
@added.add(@origin.object_id)
|
79
79
|
end
|
80
80
|
end
|
81
81
|
|
@@ -91,22 +91,25 @@ class Factbase::Taped
|
|
91
91
|
@origin.each(&)
|
92
92
|
end
|
93
93
|
|
94
|
+
def [](key)
|
95
|
+
@origin[key]
|
96
|
+
end
|
97
|
+
|
94
98
|
def to_a
|
95
99
|
@origin.to_a
|
96
100
|
end
|
97
101
|
|
98
102
|
def any?(&)
|
99
|
-
p 1
|
100
103
|
@origin.any?(&)
|
101
104
|
end
|
102
105
|
|
103
106
|
def <<(item)
|
104
|
-
@added.
|
107
|
+
@added.add(@oid)
|
105
108
|
@origin << (item)
|
106
109
|
end
|
107
110
|
|
108
111
|
def uniq!
|
109
|
-
@added.
|
112
|
+
@added.add(@oid)
|
110
113
|
@origin.uniq!
|
111
114
|
end
|
112
115
|
end
|
data/lib/factbase.rb
CHANGED
@@ -64,7 +64,7 @@ require 'yaml'
|
|
64
64
|
# License:: MIT
|
65
65
|
class Factbase
|
66
66
|
# Current version of the gem (changed by .rultor.yml on every release)
|
67
|
-
VERSION = '0.7.
|
67
|
+
VERSION = '0.7.3'
|
68
68
|
|
69
69
|
# An exception that may be thrown in a transaction, to roll it back.
|
70
70
|
class Rollback < StandardError; end
|
@@ -147,7 +147,7 @@ class Factbase
|
|
147
147
|
# A the end of this script, the factbase will be empty. No facts will
|
148
148
|
# inserted and all changes that happened in the block will be rolled back.
|
149
149
|
#
|
150
|
-
# @return [
|
150
|
+
# @return [Factbase::Churn] How many facts have been changed (zero if rolled back)
|
151
151
|
def txn
|
152
152
|
pairs = {}
|
153
153
|
lookup = {}
|
@@ -170,13 +170,14 @@ class Factbase
|
|
170
170
|
rescue Factbase::Rollback
|
171
171
|
return 0
|
172
172
|
end
|
173
|
-
|
173
|
+
require_relative 'factbase/churn'
|
174
|
+
churn = Factbase::Churn.new
|
174
175
|
@mutex.synchronize do
|
175
176
|
taped.inserted.each do |oid|
|
176
177
|
b = taped.find_by_object_id(oid)
|
177
178
|
next if b.nil?
|
178
179
|
@maps << b
|
179
|
-
|
180
|
+
churn.append(1, 0, 0)
|
180
181
|
end
|
181
182
|
garbage = []
|
182
183
|
taped.added.each do |oid|
|
@@ -184,15 +185,15 @@ class Factbase
|
|
184
185
|
next if b.nil?
|
185
186
|
garbage << pairs[oid]
|
186
187
|
@maps << b
|
187
|
-
|
188
|
+
churn.append(0, 0, 1)
|
188
189
|
end
|
189
190
|
taped.deleted.each do |oid|
|
190
191
|
garbage << pairs[oid]
|
191
|
-
|
192
|
+
churn.append(0, 1, 0)
|
192
193
|
end
|
193
194
|
@maps.delete_if { |m| garbage.include?(m.object_id) }
|
194
195
|
end
|
195
|
-
|
196
|
+
churn
|
196
197
|
end
|
197
198
|
|
198
199
|
# Export it into a chain of bytes.
|
data/test/factbase/test_churn.rb
CHANGED
@@ -45,7 +45,7 @@ class TestLooged < Minitest::Test
|
|
45
45
|
end
|
46
46
|
)
|
47
47
|
assert_equal(1, fb.size)
|
48
|
-
assert_includes(log.to_s, '
|
48
|
+
assert_includes(log.to_s, 'touched', log)
|
49
49
|
end
|
50
50
|
|
51
51
|
def test_with_txn_rollback
|
@@ -61,16 +61,16 @@ class TestLooged < Minitest::Test
|
|
61
61
|
log = Loog::Buffer.new
|
62
62
|
fb = Factbase::Looged.new(Factbase.new, log)
|
63
63
|
fb.insert.foo = 1
|
64
|
-
assert_equal(0, fb.txn { |fbt| fbt.query('(always)').each.to_a }, log)
|
65
|
-
assert_equal(1, fb.txn { |fbt| fbt.query('(always)').each.to_a[0].foo = 42 })
|
66
|
-
assert_includes(log.to_s, '
|
64
|
+
assert_equal(0, fb.txn { |fbt| fbt.query('(always)').each.to_a }.to_i, log)
|
65
|
+
assert_equal(1, fb.txn { |fbt| fbt.query('(always)').each.to_a[0].foo = 42 }.to_i)
|
66
|
+
assert_includes(log.to_s, 'touched', log)
|
67
67
|
end
|
68
68
|
|
69
69
|
def test_with_empty_txn
|
70
70
|
log = Loog::Buffer.new
|
71
71
|
fb = Factbase::Looged.new(Factbase.new, log)
|
72
|
-
assert_equal(0, fb.txn { |fbt| fbt.query('(always)').each.to_a })
|
73
|
-
assert_includes(log.to_s, '
|
72
|
+
assert_equal(0, fb.txn { |fbt| fbt.query('(always)').each.to_a }.to_i)
|
73
|
+
assert_includes(log.to_s, 'touched', log)
|
74
74
|
end
|
75
75
|
|
76
76
|
def test_returns_int
|
data/test/factbase/test_query.rb
CHANGED
@@ -26,10 +26,11 @@ class TestQuery < Minitest::Test
|
|
26
26
|
end
|
27
27
|
|
28
28
|
def test_complex_parsing
|
29
|
-
maps = [
|
30
|
-
|
31
|
-
|
32
|
-
|
29
|
+
maps = [
|
30
|
+
{ 'num' => [42], 'name' => ['Jeff'] },
|
31
|
+
{ 'pi' => [3.14], 'num' => [42, 66, 0], 'name' => ['peter'] },
|
32
|
+
{ 'time' => [Time.now - 100], 'num' => [0], 'hi' => [4], 'nome' => ['Walter'] }
|
33
|
+
]
|
33
34
|
{
|
34
35
|
'(eq num 444)' => 0,
|
35
36
|
'(eq hi 4)' => 1,
|
@@ -71,7 +72,11 @@ class TestQuery < Minitest::Test
|
|
71
72
|
"(or (eq num +66) (lt time #{(Time.now - 200).utc.iso8601}))" => 1,
|
72
73
|
'(eq 3 (agg (eq num $num) (count)))' => 1
|
73
74
|
}.each do |q, r|
|
74
|
-
|
75
|
+
fb = Factbase.new(maps)
|
76
|
+
assert_equal(r, fb.query(q).each.to_a.size, q)
|
77
|
+
fb.txn do |fbt|
|
78
|
+
assert_equal(r, fbt.query(q).each.to_a.size, q)
|
79
|
+
end
|
75
80
|
end
|
76
81
|
end
|
77
82
|
|
@@ -84,19 +89,21 @@ class TestQuery < Minitest::Test
|
|
84
89
|
end
|
85
90
|
|
86
91
|
def test_simple_deleting
|
87
|
-
maps = [
|
88
|
-
|
89
|
-
|
90
|
-
|
92
|
+
maps = [
|
93
|
+
{ 'foo' => [42] },
|
94
|
+
{ 'bar' => [4, 5] },
|
95
|
+
{ 'bar' => [5] }
|
96
|
+
]
|
91
97
|
q = Factbase::Query.new(Factbase.new, maps, Mutex.new, '(eq bar 5)')
|
92
98
|
assert_equal(2, q.delete!)
|
93
99
|
assert_equal(1, maps.size)
|
94
100
|
end
|
95
101
|
|
96
102
|
def test_reading_one
|
97
|
-
maps = [
|
98
|
-
|
99
|
-
|
103
|
+
maps = [
|
104
|
+
{ 'foo' => [42] },
|
105
|
+
{ 'bar' => [4, 5] }
|
106
|
+
]
|
100
107
|
{
|
101
108
|
'(agg (exists foo) (first foo))' => [42],
|
102
109
|
'(agg (exists z) (first z))' => nil,
|
@@ -114,10 +121,11 @@ class TestQuery < Minitest::Test
|
|
114
121
|
end
|
115
122
|
|
116
123
|
def test_deleting_nothing
|
117
|
-
maps = [
|
118
|
-
|
119
|
-
|
120
|
-
|
124
|
+
maps = [
|
125
|
+
{ 'foo' => [42] },
|
126
|
+
{ 'bar' => [4, 5] },
|
127
|
+
{ 'bar' => [5] }
|
128
|
+
]
|
121
129
|
q = Factbase::Query.new(Factbase.new, maps, Mutex.new, '(never)')
|
122
130
|
assert_equal(0, q.delete!)
|
123
131
|
assert_equal(3, maps.size)
|
@@ -144,9 +152,10 @@ class TestQuery < Minitest::Test
|
|
144
152
|
end
|
145
153
|
|
146
154
|
def test_with_params
|
147
|
-
maps = [
|
148
|
-
|
149
|
-
|
155
|
+
maps = [
|
156
|
+
{ 'foo' => [42] },
|
157
|
+
{ 'foo' => [17] }
|
158
|
+
]
|
150
159
|
found = 0
|
151
160
|
Factbase::Query.new(Factbase.new, maps, Mutex.new, '(eq foo $bar)').each(bar: [42]) do
|
152
161
|
found += 1
|
@@ -157,14 +166,12 @@ class TestQuery < Minitest::Test
|
|
157
166
|
end
|
158
167
|
|
159
168
|
def test_with_nil_alias
|
160
|
-
maps = []
|
161
|
-
maps << { 'foo' => [42] }
|
169
|
+
maps = [{ 'foo' => [42] }]
|
162
170
|
assert_nil(Factbase::Query.new(Factbase.new, maps, Mutex.new, '(as bar (plus xxx 3))').each.to_a[0]['bar'])
|
163
171
|
end
|
164
172
|
|
165
173
|
def test_get_all_properties
|
166
|
-
maps = []
|
167
|
-
maps << { 'foo' => [42] }
|
174
|
+
maps = [{ 'foo' => [42] }]
|
168
175
|
f = Factbase::Query.new(Factbase.new, maps, Mutex.new, '(always)').each.to_a[0]
|
169
176
|
assert_includes(f.all_properties, 'foo')
|
170
177
|
end
|
data/test/factbase/test_taped.rb
CHANGED
@@ -33,4 +33,14 @@ class TestTaped < Minitest::Test
|
|
33
33
|
assert_equal(1, t.added.size)
|
34
34
|
assert_equal(h.object_id, t.added.first)
|
35
35
|
end
|
36
|
+
|
37
|
+
def test_tracks_addition_uniquely
|
38
|
+
h = { f: 5 }
|
39
|
+
t = Factbase::Taped.new([h])
|
40
|
+
t.each do |m|
|
41
|
+
m[:bar] = 66
|
42
|
+
m[:foo] = 77
|
43
|
+
end
|
44
|
+
assert_equal(1, t.added.size)
|
45
|
+
end
|
36
46
|
end
|
data/test/test_factbase.rb
CHANGED
@@ -104,11 +104,11 @@ class TestFactbase < Minitest::Test
|
|
104
104
|
|
105
105
|
def test_txn_returns_boolean
|
106
106
|
fb = Factbase.new
|
107
|
-
assert_equal(1, fb.txn(&:insert))
|
108
|
-
assert_equal(1, fb.txn { |fbt| fbt.insert.bar = 42 })
|
109
|
-
assert_equal(0, fb.txn { |fbt| fbt.query('(always)').each.to_a })
|
110
|
-
assert_equal(2, fb.txn { |fbt| fbt.query('(always)').each { |f| f.hello = 33 } })
|
111
|
-
assert_equal(1, fb.txn { |fbt| fbt.query('(always)').each.to_a[0].zzz = 33 })
|
107
|
+
assert_equal(1, fb.txn(&:insert).to_i)
|
108
|
+
assert_equal(1, fb.txn { |fbt| fbt.insert.bar = 42 }.to_i)
|
109
|
+
assert_equal(0, fb.txn { |fbt| fbt.query('(always)').each.to_a }.to_i)
|
110
|
+
assert_equal(2, fb.txn { |fbt| fbt.query('(always)').each { |f| f.hello = 33 } }.to_i)
|
111
|
+
assert_equal(1, fb.txn { |fbt| fbt.query('(always)').each.to_a[0].zzz = 33 }.to_i)
|
112
112
|
end
|
113
113
|
|
114
114
|
def test_appends_in_txn
|
@@ -137,11 +137,12 @@ class TestFactbase < Minitest::Test
|
|
137
137
|
|
138
138
|
def test_deals_with_arrays_in_txn
|
139
139
|
fb = Factbase.new
|
140
|
-
|
141
|
-
|
142
|
-
|
140
|
+
n = fb.insert
|
141
|
+
n.foo = 1
|
142
|
+
n.foo = 2
|
143
143
|
fb.txn do |fbt|
|
144
|
-
|
144
|
+
f = fbt.query('(gt foo 0)').each.to_a.first
|
145
|
+
assert_equal(1, f.foo)
|
145
146
|
end
|
146
147
|
end
|
147
148
|
|
@@ -197,9 +198,13 @@ class TestFactbase < Minitest::Test
|
|
197
198
|
|
198
199
|
def test_txn_inside_query
|
199
200
|
fb = Factbase.new
|
200
|
-
fb.insert
|
201
|
+
fact = fb.insert
|
202
|
+
fact.foo = 42
|
203
|
+
fact.foo = 555
|
201
204
|
fb.query('(exists foo)').each do |f|
|
202
205
|
fb.txn do |fbt|
|
206
|
+
assert_equal(42, fb.query('(always)').each.to_a.first.foo)
|
207
|
+
assert_equal(42, fb.query('(always)').each.to_a.first['foo'].first)
|
203
208
|
fbt.insert.bar = 33
|
204
209
|
end
|
205
210
|
f.xyz = 1
|
@@ -207,15 +212,48 @@ class TestFactbase < Minitest::Test
|
|
207
212
|
assert_equal(1, fb.query('(exists xyz)').each.to_a.size)
|
208
213
|
end
|
209
214
|
|
215
|
+
def test_evals_complex_txn
|
216
|
+
fb = Factbase.new
|
217
|
+
n = fb.insert
|
218
|
+
n.foo = 42
|
219
|
+
n.bar = 555
|
220
|
+
fb.txn do |fbt|
|
221
|
+
fbt.insert.foo = 333
|
222
|
+
fbt.insert.bar = 333
|
223
|
+
fbt.query('(eq bar 555)').delete!
|
224
|
+
fbt.insert.bar = 555
|
225
|
+
fbt.query('(eq bar 777)').delete! # nothing to be deleted
|
226
|
+
n1 = fbt.insert
|
227
|
+
n1.bar = 9
|
228
|
+
n1.bar = 99
|
229
|
+
end
|
230
|
+
assert_equal(4, fb.query('(always)').each.to_a.size)
|
231
|
+
end
|
232
|
+
|
210
233
|
def test_txn_with_rollback
|
211
234
|
fb = Factbase.new
|
235
|
+
n = fb.insert
|
236
|
+
n.bar = 55
|
212
237
|
modified =
|
213
238
|
fb.txn do |fbt|
|
214
239
|
fbt.insert.bar = 33
|
240
|
+
fbt.query('(eq bar 55)').each.to_a.first.boom = 44
|
215
241
|
raise Factbase::Rollback
|
216
242
|
end
|
217
|
-
assert_equal(0, modified)
|
218
|
-
assert_equal(
|
243
|
+
assert_equal(0, modified.to_i)
|
244
|
+
assert_equal(1, fb.query('(always)').each.to_a.size)
|
245
|
+
assert_equal(0, fb.query('(exists boom)').each.to_a.size)
|
246
|
+
end
|
247
|
+
|
248
|
+
def test_modifies_existing_fact_in_txn
|
249
|
+
fb = Factbase.new
|
250
|
+
n = fb.insert
|
251
|
+
n.foo = 1
|
252
|
+
fb.txn do |fbt|
|
253
|
+
f = fbt.query('(always)').each.to_a.first
|
254
|
+
f.bar = 2
|
255
|
+
end
|
256
|
+
assert_equal(1, fb.query('(eq foo 1)').each.to_a.size)
|
219
257
|
end
|
220
258
|
|
221
259
|
def test_simple_concurrent_inserts
|