factbase 0.9.9 → 0.10.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/Gemfile.lock +8 -8
- data/README.md +28 -28
- data/Rakefile +1 -1
- data/lib/factbase/accum.rb +1 -1
- data/lib/factbase/tee.rb +1 -1
- data/lib/factbase.rb +2 -2
- data/test/factbase/cached/test_cached_factbase.rb +2 -2
- data/test/factbase/indexed/test_indexed_query.rb +6 -0
- data/test/factbase/test_accum.rb +12 -0
- data/test/factbase/test_fact.rb +2 -2
- data/test/factbase/test_tee.rb +24 -0
- data/test/test__helper.rb +18 -5
- data/test/test_factbase.rb +11 -2
- metadata +2 -3
- data/.simplecov +0 -24
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: b91c02657bba3cc0c5d801a273b49c9fd18f0faeb94bf366f5e5f7f224dd703b
|
4
|
+
data.tar.gz: c6a77ef66e2a6b06d6e072c229b1b90f602adc8769f3434239d08b02f119b9c4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 50d3c7680612b0a02bec34b560581b3e1575e95d30511ec61bc7fa1504a42566116960532e2c9f9b0bb1ee6441d0c4eeed3a1b7e9076a7436af7a0a2c3e077ab
|
7
|
+
data.tar.gz: 69d6fb049f6631fbc9d17ee24d414cfa7c3acd6d3789f73f4613cb10230c0a697c2427eaf8a028db6f61ea1c2e08fb61cf51c34e79cd722c235c0a6127f3c06a
|
data/Gemfile.lock
CHANGED
@@ -48,7 +48,7 @@ GEM
|
|
48
48
|
os (1.1.4)
|
49
49
|
others (0.0.3)
|
50
50
|
parallel (1.26.3)
|
51
|
-
parser (3.3.7.
|
51
|
+
parser (3.3.7.4)
|
52
52
|
ast (~> 2.4.1)
|
53
53
|
racc
|
54
54
|
prism (1.4.0)
|
@@ -67,7 +67,7 @@ GEM
|
|
67
67
|
psych (>= 4.0.0)
|
68
68
|
regexp_parser (2.10.0)
|
69
69
|
rexml (3.4.1)
|
70
|
-
rubocop (1.75.
|
70
|
+
rubocop (1.75.2)
|
71
71
|
json (~> 2.3)
|
72
72
|
language_server-protocol (~> 3.17.0.2)
|
73
73
|
lint_roller (~> 1.1.0)
|
@@ -75,19 +75,19 @@ GEM
|
|
75
75
|
parser (>= 3.3.0.2)
|
76
76
|
rainbow (>= 2.2.2, < 4.0)
|
77
77
|
regexp_parser (>= 2.9.3, < 3.0)
|
78
|
-
rubocop-ast (>= 1.
|
78
|
+
rubocop-ast (>= 1.44.0, < 2.0)
|
79
79
|
ruby-progressbar (~> 1.7)
|
80
80
|
unicode-display_width (>= 2.4.0, < 4.0)
|
81
|
-
rubocop-ast (1.
|
81
|
+
rubocop-ast (1.44.0)
|
82
82
|
parser (>= 3.3.7.2)
|
83
83
|
prism (~> 1.4)
|
84
|
-
rubocop-minitest (0.
|
84
|
+
rubocop-minitest (0.38.0)
|
85
85
|
lint_roller (~> 1.1)
|
86
|
-
rubocop (>= 1.
|
86
|
+
rubocop (>= 1.75.0, < 2.0)
|
87
87
|
rubocop-ast (>= 1.38.0, < 2.0)
|
88
|
-
rubocop-performance (1.
|
88
|
+
rubocop-performance (1.25.0)
|
89
89
|
lint_roller (~> 1.1)
|
90
|
-
rubocop (>= 1.
|
90
|
+
rubocop (>= 1.75.0, < 2.0)
|
91
91
|
rubocop-ast (>= 1.38.0, < 2.0)
|
92
92
|
rubocop-rake (0.7.1)
|
93
93
|
lint_roller (~> 1.1)
|
data/README.md
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
# Single-Table NoSQL-ish In-Memory Database
|
2
2
|
|
3
|
-
[](https://www.rultor.com/p/yegor256/factbase)
|
4
4
|
[](https://www.jetbrains.com/ruby/)
|
5
5
|
|
6
6
|
[](https://github.com/yegor256/factbase/actions/workflows/rake.yml)
|
7
|
-
[](
|
7
|
+
[](https://www.0pdd.com/p?name=yegor256/factbase)
|
8
|
+
[](https://badge.fury.io/rb/factbase)
|
9
9
|
[](https://codecov.io/github/yegor256/factbase?branch=master)
|
10
|
-
[](https://rubydoc.info/github/yegor256/factbase/master/frames)
|
11
11
|
[](https://hitsofcode.com/view/github/yegor256/factbase)
|
12
12
|
[](https://github.com/yegor256/factbase/blob/master/LICENSE.txt)
|
13
13
|
[](https://app.fossa.com/projects/git%2Bgithub.com%2Fyegor256%2Ffactbase?ref=badge_shield&issueType=license)
|
@@ -210,33 +210,33 @@ This is the result of the benchmark:
|
|
210
210
|
<!-- benchmark_begin -->
|
211
211
|
```text
|
212
212
|
user system total real
|
213
|
-
insert 20000 facts 0.
|
214
|
-
export 20000 facts 0.
|
215
|
-
import
|
216
|
-
insert 10 facts 0.
|
217
|
-
query 10 times w/txn 1.
|
218
|
-
query 10 times w/o txn 0.
|
219
|
-
modify 10 attrs w/txn 1.
|
220
|
-
delete 10 facts w/txn
|
221
|
-
(and (eq what 'issue-was-closed') (exists... -> 200 2.
|
222
|
-
(and (eq what 'issue-was-closed') (exists... -> 200/txn 1.
|
223
|
-
(and (eq what 'issue-was-closed') (exists... -> zero 2.
|
224
|
-
(and (eq what 'issue-was-closed') (exists... -> zero/txn 1.
|
225
|
-
(gt time '2024-03-23T03:21:43Z') 0.
|
226
|
-
(gt cost 50) 0.
|
227
|
-
(eq title 'Object Thinking 5000') 0.
|
228
|
-
(and (eq foo 42.998) (or (gt bar 200) (absent zzz))) 0.
|
229
|
-
(eq id (agg (always) (max id))) 0.
|
230
|
-
(join "c<=cost,b<=bar" (eq id (agg (always) (max id)))) 0.
|
231
|
-
delete! 0.
|
232
|
-
Taped.append() x50000 0.
|
233
|
-
Taped.each() x125 1.
|
234
|
-
Taped.delete_if() x375 0.
|
213
|
+
insert 20000 facts 0.584619 0.003744 0.588363 ( 0.588372)
|
214
|
+
export 20000 facts 0.019872 0.004992 0.024864 ( 0.024870)
|
215
|
+
import 411135 bytes (20000 facts) 0.030978 0.004000 0.034978 ( 0.034983)
|
216
|
+
insert 10 facts 0.043662 0.002056 0.045718 ( 0.045738)
|
217
|
+
query 10 times w/txn 1.809973 0.034886 1.844859 ( 1.845456)
|
218
|
+
query 10 times w/o txn 0.039074 0.004004 0.043078 ( 0.043081)
|
219
|
+
modify 10 attrs w/txn 1.705921 0.015961 1.721882 ( 1.722316)
|
220
|
+
delete 10 facts w/txn 1.021624 0.007014 1.028638 ( 1.028692)
|
221
|
+
(and (eq what 'issue-was-closed') (exists... -> 200 2.110981 0.005000 2.115981 ( 2.116099)
|
222
|
+
(and (eq what 'issue-was-closed') (exists... -> 200/txn 1.125909 0.000000 1.125909 ( 1.125962)
|
223
|
+
(and (eq what 'issue-was-closed') (exists... -> zero 2.417743 0.000993 2.418736 ( 2.418869)
|
224
|
+
(and (eq what 'issue-was-closed') (exists... -> zero/txn 1.282409 0.003006 1.285415 ( 1.285498)
|
225
|
+
(gt time '2024-03-23T03:21:43Z') 0.092167 0.000000 0.092167 ( 0.092169)
|
226
|
+
(gt cost 50) 0.107435 0.000000 0.107435 ( 0.107438)
|
227
|
+
(eq title 'Object Thinking 5000') 0.002544 0.000000 0.002544 ( 0.002546)
|
228
|
+
(and (eq foo 42.998) (or (gt bar 200) (absent zzz))) 0.022142 0.000000 0.022142 ( 0.022143)
|
229
|
+
(eq id (agg (always) (max id))) 0.244818 0.000000 0.244818 ( 0.244835)
|
230
|
+
(join "c<=cost,b<=bar" (eq id (agg (always) (max id)))) 0.672133 0.001998 0.674131 ( 0.674186)
|
231
|
+
delete! 0.074661 0.000000 0.074661 ( 0.074663)
|
232
|
+
Taped.append() x50000 0.037757 0.004997 0.042754 ( 0.042759)
|
233
|
+
Taped.each() x125 1.283630 0.001995 1.285625 ( 1.285706)
|
234
|
+
Taped.delete_if() x375 0.819901 0.000000 0.819901 ( 0.819968)
|
235
235
|
```
|
236
236
|
|
237
237
|
The results were calculated in [this GHA job][benchmark-gha]
|
238
|
-
on 2025-
|
238
|
+
on 2025-04-07 at 10:33,
|
239
239
|
on Linux with 4 CPUs.
|
240
240
|
<!-- benchmark_end -->
|
241
241
|
|
242
|
-
[benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/
|
242
|
+
[benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/14306969571
|
data/Rakefile
CHANGED
@@ -35,7 +35,7 @@ task :picks do
|
|
35
35
|
next if OS.windows?
|
36
36
|
%w[test lib].each do |d|
|
37
37
|
Dir["#{d}/**/*.rb"].each do |f|
|
38
|
-
qbash("bundle exec ruby #{Shellwords.escape(f)}", log: $stdout)
|
38
|
+
qbash("bundle exec ruby #{Shellwords.escape(f)}", log: $stdout, env: { 'PICKS' => 'yes' })
|
39
39
|
end
|
40
40
|
end
|
41
41
|
end
|
data/lib/factbase/accum.rb
CHANGED
data/lib/factbase/tee.rb
CHANGED
data/lib/factbase.rb
CHANGED
@@ -82,7 +82,7 @@ require 'yaml'
|
|
82
82
|
# License:: MIT
|
83
83
|
class Factbase
|
84
84
|
# Current version of the gem (changed by .rultor.yml on every release)
|
85
|
-
VERSION = '0.
|
85
|
+
VERSION = '0.10.0' unless const_defined?(:VERSION)
|
86
86
|
|
87
87
|
# An exception that may be thrown in a transaction, to roll it back.
|
88
88
|
class Rollback < StandardError; end
|
@@ -176,7 +176,7 @@ class Factbase
|
|
176
176
|
end
|
177
177
|
require_relative 'factbase/taped'
|
178
178
|
taped = Factbase::Taped.new(before)
|
179
|
-
|
179
|
+
catch :commit do
|
180
180
|
require_relative 'factbase/light'
|
181
181
|
yield Factbase::Light.new(Factbase.new(taped))
|
182
182
|
rescue Factbase::Rollback
|
@@ -15,9 +15,9 @@ class TestCachedFactbase < Factbase::Test
|
|
15
15
|
def test_inserts_and_queries
|
16
16
|
fb = Factbase::CachedFactbase.new(Factbase.new)
|
17
17
|
f = fb.insert
|
18
|
-
f.
|
18
|
+
f.foo_bar = 1
|
19
19
|
f.bar = 'test'
|
20
|
-
assert_equal(1, fb.query('(and (eq
|
20
|
+
assert_equal(1, fb.query('(and (eq foo_bar 1) (eq bar "test"))').each.to_a.size)
|
21
21
|
end
|
22
22
|
|
23
23
|
def test_queries_after_update_in_txn
|
@@ -13,6 +13,12 @@ require_relative '../../../lib/factbase/indexed/indexed_factbase'
|
|
13
13
|
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
14
14
|
# License:: MIT
|
15
15
|
class TestIndexedQuery < Factbase::Test
|
16
|
+
def test_converts_to_string
|
17
|
+
fb = Factbase.new
|
18
|
+
fb.insert.foo = 42
|
19
|
+
refute_nil(Factbase::IndexedQuery.new(fb.query('(exists foo)'), {}, fb).to_s)
|
20
|
+
end
|
21
|
+
|
16
22
|
def test_queries_and_updates_origin
|
17
23
|
fb = Factbase.new
|
18
24
|
fb.insert.foo = 42
|
data/test/factbase/test_accum.rb
CHANGED
@@ -8,6 +8,10 @@ require_relative '../../lib/factbase'
|
|
8
8
|
require_relative '../../lib/factbase/accum'
|
9
9
|
require_relative '../../lib/factbase/fact'
|
10
10
|
|
11
|
+
def global_function_for_this_test_only(foo)
|
12
|
+
raise foo
|
13
|
+
end
|
14
|
+
|
11
15
|
# Accum test.
|
12
16
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
13
17
|
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
@@ -24,6 +28,14 @@ class TestAccum < Factbase::Test
|
|
24
28
|
assert_equal([42], props['foo'])
|
25
29
|
end
|
26
30
|
|
31
|
+
def test_fetches_without_conflict_with_global_name
|
32
|
+
t = Factbase::Accum.new(
|
33
|
+
Factbase::Fact.new({ 'global_function_for_this_test_only' => [2] }),
|
34
|
+
{}, true
|
35
|
+
)
|
36
|
+
assert_equal(2, t.global_function_for_this_test_only)
|
37
|
+
end
|
38
|
+
|
27
39
|
def test_passes_props
|
28
40
|
map = {}
|
29
41
|
f = Factbase::Fact.new(map)
|
data/test/factbase/test_fact.rb
CHANGED
@@ -15,11 +15,11 @@ class TestFact < Factbase::Test
|
|
15
15
|
def test_injects_data_correctly
|
16
16
|
map = {}
|
17
17
|
f = Factbase::Fact.new(map)
|
18
|
-
f.
|
18
|
+
f.foo_bar = 1
|
19
19
|
f.bar = 2
|
20
20
|
f.bar = 3
|
21
21
|
assert_equal(2, map.size)
|
22
|
-
assert_equal([1], map['
|
22
|
+
assert_equal([1], map['foo_bar'])
|
23
23
|
assert_equal([2, 3], map['bar'])
|
24
24
|
end
|
25
25
|
|
data/test/factbase/test_tee.rb
CHANGED
@@ -5,9 +5,14 @@
|
|
5
5
|
|
6
6
|
require_relative '../test__helper'
|
7
7
|
require_relative '../../lib/factbase'
|
8
|
+
require_relative '../../lib/factbase/accum'
|
8
9
|
require_relative '../../lib/factbase/tee'
|
9
10
|
require_relative '../../lib/factbase/fact'
|
10
11
|
|
12
|
+
def global_function_for_test_only(foo)
|
13
|
+
raise foo
|
14
|
+
end
|
15
|
+
|
11
16
|
# Tee test.
|
12
17
|
# Author:: Yegor Bugayenko (yegor256@gmail.com)
|
13
18
|
# Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
|
@@ -30,6 +35,25 @@ class TestTee < Factbase::Test
|
|
30
35
|
assert_nil(t['$foo'])
|
31
36
|
end
|
32
37
|
|
38
|
+
def test_fetches_simply
|
39
|
+
t = Factbase::Accum.new(
|
40
|
+
Factbase::Tee.new(
|
41
|
+
Factbase::Fact.new({ 'foo_bar' => [987] }),
|
42
|
+
Factbase::Fact.new({})
|
43
|
+
),
|
44
|
+
{}, true
|
45
|
+
)
|
46
|
+
assert_equal(987, t.foo_bar)
|
47
|
+
end
|
48
|
+
|
49
|
+
def test_fetches_without_conflict_with_global_name
|
50
|
+
t = Factbase::Tee.new(
|
51
|
+
Factbase::Fact.new({ 'global_function_for_test_only' => [2] }),
|
52
|
+
Factbase::Fact.new({})
|
53
|
+
)
|
54
|
+
assert_equal(2, t.global_function_for_test_only)
|
55
|
+
end
|
56
|
+
|
33
57
|
def test_all_properties
|
34
58
|
prim = Factbase::Fact.new({})
|
35
59
|
prim.foo = 42
|
data/test/test__helper.rb
CHANGED
@@ -6,14 +6,27 @@
|
|
6
6
|
$stdout.sync = true
|
7
7
|
|
8
8
|
require 'simplecov'
|
9
|
-
SimpleCov.external_at_exit = true
|
10
|
-
SimpleCov.start
|
11
|
-
|
12
9
|
require 'simplecov-cobertura'
|
13
|
-
SimpleCov.
|
10
|
+
unless SimpleCov.running || ENV['PICKS']
|
11
|
+
SimpleCov.command_name('test')
|
12
|
+
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
13
|
+
[
|
14
|
+
SimpleCov::Formatter::HTMLFormatter,
|
15
|
+
SimpleCov::Formatter::CoberturaFormatter
|
16
|
+
]
|
17
|
+
)
|
18
|
+
SimpleCov.minimum_coverage 95
|
19
|
+
SimpleCov.minimum_coverage_by_file 90
|
20
|
+
SimpleCov.start do
|
21
|
+
add_filter 'test/'
|
22
|
+
add_filter 'vendor/'
|
23
|
+
add_filter 'target/'
|
24
|
+
track_files 'lib/**/*.rb'
|
25
|
+
track_files '*.rb'
|
26
|
+
end
|
27
|
+
end
|
14
28
|
|
15
29
|
require 'minitest/autorun'
|
16
|
-
|
17
30
|
require 'minitest/reporters'
|
18
31
|
Minitest::Reporters.use! [Minitest::Reporters::SpecReporter.new]
|
19
32
|
|
data/test/test_factbase.rb
CHANGED
@@ -134,7 +134,7 @@ class TestFactbase < Factbase::Test
|
|
134
134
|
assert_raises(StandardError) do
|
135
135
|
fb.txn do |fbt|
|
136
136
|
fbt.insert.foo = 42
|
137
|
-
|
137
|
+
raise 'intentionally'
|
138
138
|
end
|
139
139
|
end.message, 'intentionally'
|
140
140
|
)
|
@@ -193,7 +193,7 @@ class TestFactbase < Factbase::Test
|
|
193
193
|
assert_raises(StandardError) do
|
194
194
|
d.txn do |fbt|
|
195
195
|
fbt.insert
|
196
|
-
|
196
|
+
raise 'oops'
|
197
197
|
end
|
198
198
|
end
|
199
199
|
d.import(d.export)
|
@@ -476,4 +476,13 @@ class TestFactbase < Factbase::Test
|
|
476
476
|
assert_equal(100, factbase.query('(eq foo 42)').each.to_a.size)
|
477
477
|
end
|
478
478
|
end
|
479
|
+
|
480
|
+
def test_commits_on_exit_by_throw
|
481
|
+
fb = Factbase.new
|
482
|
+
fb.txn do |fbt|
|
483
|
+
fbt.insert.foo = 1
|
484
|
+
throw :commit
|
485
|
+
end
|
486
|
+
assert_equal(1, fb.size)
|
487
|
+
end
|
479
488
|
end
|
metadata
CHANGED
@@ -1,13 +1,13 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: factbase
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.10.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Yegor Bugayenko
|
8
8
|
bindir: bin
|
9
9
|
cert_chain: []
|
10
|
-
date: 2025-
|
10
|
+
date: 2025-04-15 00:00:00.000000000 Z
|
11
11
|
dependencies:
|
12
12
|
- !ruby/object:Gem::Dependency
|
13
13
|
name: backtrace
|
@@ -163,7 +163,6 @@ files:
|
|
163
163
|
- ".pdd"
|
164
164
|
- ".rubocop.yml"
|
165
165
|
- ".rultor.yml"
|
166
|
-
- ".simplecov"
|
167
166
|
- Gemfile
|
168
167
|
- Gemfile.lock
|
169
168
|
- LICENSE.txt
|
data/.simplecov
DELETED
@@ -1,24 +0,0 @@
|
|
1
|
-
# frozen_string_literal: true
|
2
|
-
|
3
|
-
#
|
4
|
-
# SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
|
5
|
-
# SPDX-License-Identifier: MIT
|
6
|
-
|
7
|
-
if Gem.win_platform?
|
8
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter[
|
9
|
-
SimpleCov::Formatter::HTMLFormatter
|
10
|
-
]
|
11
|
-
SimpleCov.start do
|
12
|
-
add_filter '/test/'
|
13
|
-
add_filter '/features/'
|
14
|
-
end
|
15
|
-
else
|
16
|
-
SimpleCov.formatter = SimpleCov::Formatter::MultiFormatter.new(
|
17
|
-
[SimpleCov::Formatter::HTMLFormatter]
|
18
|
-
)
|
19
|
-
SimpleCov.start do
|
20
|
-
add_filter '/test/'
|
21
|
-
add_filter '/features/'
|
22
|
-
minimum_coverage 20
|
23
|
-
end
|
24
|
-
end
|