factbase 0.6.0 → 0.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.
- checksums.yaml +4 -4
- data/.github/workflows/reuse.yml +0 -2
- data/.gitignore +1 -0
- data/.rubocop.yml +1 -0
- data/README.md +16 -10
- data/REUSE.toml +9 -1
- data/benchmarks/simple.rb +53 -5
- data/lib/factbase/accum.rb +2 -2
- data/lib/factbase/churn.rb +8 -0
- data/lib/factbase/looged.rb +1 -1
- data/lib/factbase/taped.rb +30 -5
- data/lib/factbase/term.rb +1 -1
- data/lib/factbase/terms/aggregates.rb +2 -2
- data/lib/factbase/terms/logical.rb +1 -1
- data/lib/factbase/terms/meta.rb +2 -2
- data/lib/factbase/terms/ordering.rb +1 -1
- data/lib/factbase.rb +17 -9
- data/test/factbase/test_churn.rb +9 -0
- data/test/factbase/test_looged.rb +4 -4
- data/test/factbase/test_tallied.rb +1 -1
- data/test/factbase/test_taped.rb +0 -1
- data/test/test_factbase.rb +16 -7
- metadata +2 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 61e944b02d2b8110a72ad61a25766dfc85a6fd9996af11d3fff8548a2b7dc8d0
|
4
|
+
data.tar.gz: 900e17bafd0abf7cd1a4cc87a003c2315bd22e865166454dd9712afd4d5c822f
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f8eb4bf66d83e08c7527a492e224673874071655ecada4fdb163e872cc018d35bd24c445b267ed65a9ac6f3275a40826df9e745279af00f473ed9edde76fed76
|
7
|
+
data.tar.gz: 4911055570df61091d8beeb36a7a02d74985c64edbf6246fb5dcd429fc07d4f32e694a42ad856a941c5963a3c30009ca9ea0d1c42c13e5017d6a946aa038a798
|
data/.github/workflows/reuse.yml
CHANGED
data/.gitignore
CHANGED
data/.rubocop.yml
CHANGED
data/README.md
CHANGED
@@ -209,18 +209,24 @@ This is the result of the benchmark:
|
|
209
209
|
<!-- benchmark_begin -->
|
210
210
|
| Action | Seconds | Details |
|
211
211
|
| --- | --: | --- |
|
212
|
-
| `fb.insert()` |
|
213
|
-
| `(gt time '2024-03-23T03:21:43Z')` | 0.
|
214
|
-
| `(gt cost 50)` | 0.
|
215
|
-
| `(eq title 'Object Thinking 5000')` | 0.
|
216
|
-
| `(and (eq foo 42.998) (or (gt bar 200) (absent zzz)))` | 0.
|
217
|
-
| `(eq id (agg (always) (max id)))` | 0.
|
218
|
-
| `(join "c<=cost,b<=bar" (eq id (agg (always) (max id))))` |
|
219
|
-
|
|
212
|
+
| `fb.insert()` | 1.883 | Inserted 25000 facts |
|
213
|
+
| `(gt time '2024-03-23T03:21:43Z')` | 0.201 | 25000 facts x100 |
|
214
|
+
| `(gt cost 50)` | 0.175 | 12430 facts x100 |
|
215
|
+
| `(eq title 'Object Thinking 5000')` | 0.129 | 1 facts x100 |
|
216
|
+
| `(and (eq foo 42.998) (or (gt bar 200) (absent zzz)))` | 0.157 | 0 facts x100 |
|
217
|
+
| `(eq id (agg (always) (max id)))` | 0.268 | 1 facts x100 |
|
218
|
+
| `(join "c<=cost,b<=bar" (eq id (agg (always) (max id))))` | 1.844 | 25000 facts x100 |
|
219
|
+
| txn: `query()` | 19.358 | modified 0 facts |
|
220
|
+
| txn: `insert()` | 0.059 | modified 100 facts |
|
221
|
+
| txn: `add()` | 16.223 | modified 3 facts |
|
222
|
+
| txn: `delete!()` | 3.573 | modified 12439 facts |
|
223
|
+
| `.export()` + `.import()` | 0.369 | 1451040 bytes |
|
224
|
+
| `(gt cost 3)` | 0.030 | Deleted 12395 fact(s) |
|
225
|
+
| `(gt bar 1)` | 0.001 | Deleted 363 fact(s) |
|
220
226
|
|
221
227
|
The results were calculated in [this GHA job][benchmark-gha]
|
222
|
-
on 2025-
|
228
|
+
on 2025-02-24 at 13:32,
|
223
229
|
on Linux with 4 CPUs.
|
224
230
|
<!-- benchmark_end -->
|
225
231
|
|
226
|
-
[benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/
|
232
|
+
[benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/13499241189
|
data/REUSE.toml
CHANGED
@@ -4,13 +4,21 @@
|
|
4
4
|
version = 1
|
5
5
|
[[annotations]]
|
6
6
|
path = [
|
7
|
+
"**/*.jpg",
|
8
|
+
"**/*.json",
|
9
|
+
"**/*.md",
|
10
|
+
"**/*.pdf",
|
11
|
+
"**/*.png",
|
12
|
+
"**/*.svg",
|
13
|
+
"**/.gitignore",
|
7
14
|
".gitattributes",
|
8
15
|
".gitignore",
|
9
16
|
".gitleaksignore",
|
10
17
|
".pdd",
|
18
|
+
".xcop",
|
11
19
|
"Gemfile.lock",
|
12
20
|
"README.md",
|
13
|
-
"renovate.json"
|
21
|
+
"renovate.json",
|
14
22
|
]
|
15
23
|
precedence = "override"
|
16
24
|
SPDX-FileCopyrightText = "Copyright (c) 2025 Yegor Bugayenko"
|
data/benchmarks/simple.rb
CHANGED
@@ -32,7 +32,7 @@ end
|
|
32
32
|
|
33
33
|
def query(fb, query)
|
34
34
|
total = 0
|
35
|
-
runs =
|
35
|
+
runs = 100
|
36
36
|
time =
|
37
37
|
Benchmark.measure do
|
38
38
|
runs.times do
|
@@ -41,8 +41,21 @@ def query(fb, query)
|
|
41
41
|
end
|
42
42
|
{
|
43
43
|
title: "`#{query}`",
|
44
|
-
time:
|
45
|
-
details: "
|
44
|
+
time: time.real.round(6),
|
45
|
+
details: "#{total} facts x#{runs}"
|
46
|
+
}
|
47
|
+
end
|
48
|
+
|
49
|
+
def delete(fb, query)
|
50
|
+
total = 0
|
51
|
+
time =
|
52
|
+
Benchmark.measure do
|
53
|
+
total = fb.query(query).delete!
|
54
|
+
end
|
55
|
+
{
|
56
|
+
title: "`#{query}`",
|
57
|
+
time: time.real.round(6),
|
58
|
+
details: "Deleted #{total} fact(s)"
|
46
59
|
}
|
47
60
|
end
|
48
61
|
|
@@ -62,16 +75,51 @@ def impex(fb)
|
|
62
75
|
}
|
63
76
|
end
|
64
77
|
|
78
|
+
def txn(fb, scenario, &block)
|
79
|
+
modified = 0
|
80
|
+
time =
|
81
|
+
Benchmark.measure do
|
82
|
+
modified = fb.txn(&block)
|
83
|
+
end
|
84
|
+
{
|
85
|
+
title: "txn: `#{scenario}`",
|
86
|
+
time: time.real,
|
87
|
+
details: "modified #{modified} facts"
|
88
|
+
}
|
89
|
+
end
|
90
|
+
|
65
91
|
fb = Factbase.new
|
66
92
|
rows = [
|
67
|
-
insert(fb,
|
93
|
+
insert(fb, 25_000),
|
68
94
|
query(fb, '(gt time \'2024-03-23T03:21:43Z\')'),
|
69
95
|
query(fb, '(gt cost 50)'),
|
70
96
|
query(fb, '(eq title \'Object Thinking 5000\')'),
|
71
97
|
query(fb, '(and (eq foo 42.998) (or (gt bar 200) (absent zzz)))'),
|
72
98
|
query(fb, '(eq id (agg (always) (max id)))'),
|
73
99
|
query(fb, '(join "c<=cost,b<=bar" (eq id (agg (always) (max id))))'),
|
74
|
-
|
100
|
+
txn(fb, 'query()') do |fbt|
|
101
|
+
100.times do |i|
|
102
|
+
fbt.query("(gt foo #{i})").each.to_a
|
103
|
+
end
|
104
|
+
end,
|
105
|
+
txn(fb, 'insert()') do |fbt|
|
106
|
+
100.times do
|
107
|
+
fbt.insert
|
108
|
+
end
|
109
|
+
end,
|
110
|
+
txn(fb, 'add()') do |fbt|
|
111
|
+
100.times do |i|
|
112
|
+
fbt.query("(gt foo #{i})").each.to_a.first.bar = 55
|
113
|
+
end
|
114
|
+
end,
|
115
|
+
txn(fb, 'delete!()') do |fbt|
|
116
|
+
50.times do |i|
|
117
|
+
fbt.query("(gt foo #{100 - i})").delete!
|
118
|
+
end
|
119
|
+
end,
|
120
|
+
impex(fb),
|
121
|
+
delete(fb, '(gt cost 3)'),
|
122
|
+
delete(fb, '(gt bar 1)')
|
75
123
|
].map { |r| "| #{r[:title]} | #{format('%0.3f', r[:time])} | #{r[:details]} |" }
|
76
124
|
|
77
125
|
puts '| Action | Seconds | Details |'
|
data/lib/factbase/accum.rb
CHANGED
@@ -41,8 +41,8 @@ class Factbase::Accum
|
|
41
41
|
kk = args[1].to_s
|
42
42
|
vv = @props[kk].nil? ? [] : @props[kk]
|
43
43
|
vvv = @fact.method_missing(*args)
|
44
|
-
vvv = [vvv] unless vvv.nil? || vvv.
|
45
|
-
vv += vvv unless vvv.nil?
|
44
|
+
vvv = [vvv] unless vvv.nil? || vvv.respond_to?(:each)
|
45
|
+
vv += vvv.to_a unless vvv.nil?
|
46
46
|
vv.uniq!
|
47
47
|
vv.empty? ? nil : vv
|
48
48
|
elsif @props[k].nil?
|
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 ? 'modified' : 'didn\'t touch'} the factbase in #{start.ago}")
|
53
|
+
@loog.debug("Txn ##{id} #{r.positive? ? 'modified' : 'didn\'t touch'} the factbase in #{start.ago}")
|
54
54
|
end
|
55
55
|
r
|
56
56
|
end
|
data/lib/factbase/taped.rb
CHANGED
@@ -14,15 +14,18 @@ require_relative '../factbase'
|
|
14
14
|
class Factbase::Taped
|
15
15
|
attr_reader :inserted, :deleted, :added
|
16
16
|
|
17
|
-
def initialize(origin)
|
17
|
+
def initialize(origin, lookup: {})
|
18
18
|
@origin = origin
|
19
19
|
@inserted = []
|
20
20
|
@deleted = []
|
21
21
|
@added = []
|
22
|
+
@lookup = lookup
|
22
23
|
end
|
23
24
|
|
24
|
-
def
|
25
|
-
|
25
|
+
def find_by_object_id(oid)
|
26
|
+
o = @lookup[oid]
|
27
|
+
o = @origin.find { |m| m.object_id == oid } if o.nil?
|
28
|
+
o
|
26
29
|
end
|
27
30
|
|
28
31
|
def size
|
@@ -31,11 +34,17 @@ class Factbase::Taped
|
|
31
34
|
|
32
35
|
def <<(map)
|
33
36
|
@origin << (map)
|
37
|
+
# rubocop:disable Lint/HashCompareByIdentity
|
38
|
+
@lookup[map.object_id] = map
|
39
|
+
# rubocop:enable Lint/HashCompareByIdentity
|
34
40
|
@inserted.append(map.object_id)
|
35
41
|
end
|
36
42
|
|
37
43
|
def each
|
38
44
|
@origin.each do |m|
|
45
|
+
# rubocop:disable Lint/HashCompareByIdentity
|
46
|
+
@lookup[m.object_id] = m
|
47
|
+
# rubocop:enable Lint/HashCompareByIdentity
|
39
48
|
yield TapedHash.new(m, @added)
|
40
49
|
end
|
41
50
|
end
|
@@ -43,7 +52,10 @@ class Factbase::Taped
|
|
43
52
|
def delete_if
|
44
53
|
@origin.delete_if do |m|
|
45
54
|
r = yield m
|
46
|
-
|
55
|
+
if r
|
56
|
+
@lookup.delete(m.object_id)
|
57
|
+
@deleted.append(m.object_id)
|
58
|
+
end
|
47
59
|
r
|
48
60
|
end
|
49
61
|
end
|
@@ -57,7 +69,7 @@ class Factbase::Taped
|
|
57
69
|
|
58
70
|
def [](key)
|
59
71
|
v = @origin[key]
|
60
|
-
v = TapedArray.new(v, @origin.object_id, @added) if v.
|
72
|
+
v = TapedArray.new(v, @origin.object_id, @added) if v.respond_to?(:each)
|
61
73
|
v
|
62
74
|
end
|
63
75
|
|
@@ -75,6 +87,19 @@ class Factbase::Taped
|
|
75
87
|
@added = added
|
76
88
|
end
|
77
89
|
|
90
|
+
def each(&)
|
91
|
+
@origin.each(&)
|
92
|
+
end
|
93
|
+
|
94
|
+
def to_a
|
95
|
+
@origin.to_a
|
96
|
+
end
|
97
|
+
|
98
|
+
def any?(&)
|
99
|
+
p 1
|
100
|
+
@origin.any?(&)
|
101
|
+
end
|
102
|
+
|
78
103
|
def <<(item)
|
79
104
|
@added.append(@oid)
|
80
105
|
@origin << (item)
|
data/lib/factbase/term.rb
CHANGED
@@ -50,7 +50,7 @@ module Factbase::Term::Aggregates
|
|
50
50
|
maps.each do |m|
|
51
51
|
vv = m[k.to_s]
|
52
52
|
next if vv.nil?
|
53
|
-
vv = [vv] unless vv.
|
53
|
+
vv = [vv] unless vv.respond_to?(:each)
|
54
54
|
vv.each do |v|
|
55
55
|
sum += v
|
56
56
|
end
|
@@ -82,7 +82,7 @@ module Factbase::Term::Aggregates
|
|
82
82
|
maps.each do |m|
|
83
83
|
vv = m[k.to_s]
|
84
84
|
next if vv.nil?
|
85
|
-
vv = [vv] unless vv.
|
85
|
+
vv = [vv] unless vv.respond_to?(:each)
|
86
86
|
vv.each do |v|
|
87
87
|
best = v if best.nil? || yield(v, best)
|
88
88
|
end
|
@@ -77,7 +77,7 @@ module Factbase::Term::Logical
|
|
77
77
|
end
|
78
78
|
|
79
79
|
def _only_bool(val, pos)
|
80
|
-
val = val[0] if val.
|
80
|
+
val = val[0] if val.respond_to?(:each)
|
81
81
|
return false if val.nil?
|
82
82
|
return val if val.is_a?(TrueClass) || val.is_a?(FalseClass)
|
83
83
|
raise "Boolean expected, while #{val.class} received from #{@operands[pos]}"
|
data/lib/factbase/terms/meta.rb
CHANGED
@@ -25,7 +25,7 @@ module Factbase::Term::Meta
|
|
25
25
|
assert_args(1)
|
26
26
|
v = by_symbol(0, fact)
|
27
27
|
return 0 if v.nil?
|
28
|
-
return 1 unless v.
|
28
|
+
return 1 unless v.respond_to?(:each)
|
29
29
|
v.size
|
30
30
|
end
|
31
31
|
|
@@ -33,7 +33,7 @@ module Factbase::Term::Meta
|
|
33
33
|
assert_args(1)
|
34
34
|
v = by_symbol(0, fact)
|
35
35
|
return 'nil' if v.nil?
|
36
|
-
v = v[0] if v.
|
36
|
+
v = v[0] if v.respond_to?(:each) && v.size == 1
|
37
37
|
v.class.to_s
|
38
38
|
end
|
39
39
|
|
@@ -24,7 +24,7 @@ module Factbase::Term::Ordering
|
|
24
24
|
assert_args(1)
|
25
25
|
vv = the_values(0, fact, maps)
|
26
26
|
return false if vv.nil?
|
27
|
-
vv = [vv] unless vv.
|
27
|
+
vv = [vv] unless vv.respond_to?(:each)
|
28
28
|
vv.each do |v|
|
29
29
|
return false if @uniques.include?(v)
|
30
30
|
@uniques << v
|
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.
|
67
|
+
VERSION = '0.7.0'
|
68
68
|
|
69
69
|
# An exception that may be thrown in a transaction, to roll it back.
|
70
70
|
class Rollback < StandardError; end
|
@@ -147,44 +147,52 @@ 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 [Integer] How many facts have been changed (zero if rolled back)
|
151
151
|
def txn
|
152
152
|
pairs = {}
|
153
|
+
lookup = {}
|
153
154
|
before =
|
154
155
|
@mutex.synchronize do
|
155
156
|
@maps.map do |m|
|
156
157
|
n = m.transform_values(&:dup)
|
157
158
|
# rubocop:disable Lint/HashCompareByIdentity
|
158
159
|
pairs[n.object_id] = m.object_id
|
160
|
+
lookup[n.object_id] = n
|
159
161
|
# rubocop:enable Lint/HashCompareByIdentity
|
160
162
|
n
|
161
163
|
end
|
162
164
|
end
|
163
165
|
require_relative 'factbase/taped'
|
164
|
-
taped = Factbase::Taped.new(before)
|
166
|
+
taped = Factbase::Taped.new(before, lookup:)
|
165
167
|
begin
|
166
168
|
require_relative 'factbase/light'
|
167
169
|
yield Factbase::Light.new(Factbase.new(taped, cache: @cache), @cache)
|
168
170
|
rescue Factbase::Rollback
|
169
|
-
return
|
171
|
+
return 0
|
170
172
|
end
|
173
|
+
modified = []
|
171
174
|
@mutex.synchronize do
|
172
175
|
taped.inserted.each do |oid|
|
173
|
-
b =
|
176
|
+
b = taped.find_by_object_id(oid)
|
174
177
|
next if b.nil?
|
175
178
|
@maps << b
|
179
|
+
modified << oid
|
176
180
|
end
|
181
|
+
garbage = []
|
177
182
|
taped.added.each do |oid|
|
178
|
-
b =
|
183
|
+
b = taped.find_by_object_id(oid)
|
179
184
|
next if b.nil?
|
180
|
-
|
185
|
+
garbage << pairs[oid]
|
181
186
|
@maps << b
|
187
|
+
modified << oid
|
182
188
|
end
|
183
189
|
taped.deleted.each do |oid|
|
184
|
-
|
190
|
+
garbage << pairs[oid]
|
191
|
+
modified << oid
|
185
192
|
end
|
186
|
-
|
193
|
+
@maps.delete_if { |m| garbage.include?(m.object_id) }
|
187
194
|
end
|
195
|
+
modified.uniq.count
|
188
196
|
end
|
189
197
|
|
190
198
|
# Export it into a chain of bytes.
|
data/test/factbase/test_churn.rb
CHANGED
@@ -28,4 +28,13 @@ class TestChurn < Minitest::Test
|
|
28
28
|
c = Factbase::Churn.new
|
29
29
|
assert_predicate(c.dup, :zero?)
|
30
30
|
end
|
31
|
+
|
32
|
+
def test_concatenates_with_other
|
33
|
+
c1 = Factbase::Churn.new
|
34
|
+
c1.append(1, 6, 3)
|
35
|
+
c2 = Factbase::Churn.new
|
36
|
+
c2.append(3, 2, 46)
|
37
|
+
c3 = c1 + c2
|
38
|
+
assert_equal('4i/8d/49a', c3.to_s)
|
39
|
+
end
|
31
40
|
end
|
@@ -51,7 +51,7 @@ class TestLooged < Minitest::Test
|
|
51
51
|
def test_with_txn_rollback
|
52
52
|
log = Loog::Buffer.new
|
53
53
|
fb = Factbase::Looged.new(Factbase.new, log)
|
54
|
-
|
54
|
+
assert_equal(0, fb.txn { raise Factbase::Rollback })
|
55
55
|
assert_equal(0, fb.size)
|
56
56
|
assert_includes(log.to_s, 'rolled back', log)
|
57
57
|
refute_includes(log.to_s, 'didn\'t touch', log)
|
@@ -61,15 +61,15 @@ 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
|
-
|
65
|
-
|
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
66
|
assert_includes(log.to_s, 'modified', 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
|
-
|
72
|
+
assert_equal(0, fb.txn { |fbt| fbt.query('(always)').each.to_a })
|
73
73
|
assert_includes(log.to_s, 'didn\'t touch', log)
|
74
74
|
end
|
75
75
|
|
data/test/factbase/test_taped.rb
CHANGED
data/test/test_factbase.rb
CHANGED
@@ -104,12 +104,11 @@ class TestFactbase < Minitest::Test
|
|
104
104
|
|
105
105
|
def test_txn_returns_boolean
|
106
106
|
fb = Factbase.new
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
assert(fb.txn { |fbt| fbt.query('(always)').each.to_a[0].zzz = 33 })
|
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 })
|
113
112
|
end
|
114
113
|
|
115
114
|
def test_appends_in_txn
|
@@ -136,6 +135,16 @@ class TestFactbase < Minitest::Test
|
|
136
135
|
assert_equal(2, fb.size)
|
137
136
|
end
|
138
137
|
|
138
|
+
def test_deals_with_arrays_in_txn
|
139
|
+
fb = Factbase.new
|
140
|
+
f = fb.insert
|
141
|
+
f.foo = 1
|
142
|
+
f.foo = 2
|
143
|
+
fb.txn do |fbt|
|
144
|
+
assert_equal(1, fbt.query('(gt foo 0)').each.to_a.size)
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
139
148
|
def test_run_txn_via_query
|
140
149
|
fb = Factbase.new
|
141
150
|
fb.insert.foo = 1
|
@@ -205,7 +214,7 @@ class TestFactbase < Minitest::Test
|
|
205
214
|
fbt.insert.bar = 33
|
206
215
|
raise Factbase::Rollback
|
207
216
|
end
|
208
|
-
|
217
|
+
assert_equal(0, modified)
|
209
218
|
assert_equal(0, fb.query('(always)').each.to_a.size)
|
210
219
|
end
|
211
220
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factbase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.7.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2025-02-
|
11
|
+
date: 2025-02-24 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: backtrace
|