factbase 0.5.2 → 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.
Files changed (88) hide show
  1. checksums.yaml +4 -4
  2. data/.0pdd.yml +2 -19
  3. data/.github/workflows/actionlint.yml +4 -20
  4. data/.github/workflows/benchmark.yml +10 -25
  5. data/.github/workflows/codecov.yml +6 -20
  6. data/.github/workflows/copyrights.yml +4 -19
  7. data/.github/workflows/markdown-lint.yml +4 -19
  8. data/.github/workflows/pdd.yml +4 -19
  9. data/.github/workflows/rake.yml +5 -21
  10. data/.github/workflows/reuse.yml +19 -0
  11. data/.github/workflows/xcop.yml +4 -19
  12. data/.github/workflows/yamllint.yml +4 -21
  13. data/.gitignore +1 -0
  14. data/.rubocop.yml +5 -21
  15. data/.rultor.yml +3 -19
  16. data/.simplecov +2 -19
  17. data/Gemfile +8 -24
  18. data/Gemfile.lock +40 -31
  19. data/LICENSES/MIT.txt +21 -0
  20. data/README.md +40 -10
  21. data/REUSE.toml +25 -0
  22. data/Rakefile +3 -28
  23. data/benchmarks/simple.rb +55 -24
  24. data/factbase.gemspec +2 -19
  25. data/lib/factbase/accum.rb +4 -21
  26. data/lib/factbase/churn.rb +44 -0
  27. data/lib/factbase/fact.rb +2 -19
  28. data/lib/factbase/flatten.rb +2 -19
  29. data/lib/factbase/inv.rb +6 -25
  30. data/lib/factbase/light.rb +32 -0
  31. data/lib/factbase/looged.rb +6 -27
  32. data/lib/factbase/pre.rb +6 -25
  33. data/lib/factbase/query.rb +4 -21
  34. data/lib/factbase/query_once.rb +2 -19
  35. data/lib/factbase/rules.rb +5 -26
  36. data/lib/factbase/syntax.rb +2 -19
  37. data/lib/factbase/tallied.rb +93 -0
  38. data/lib/factbase/taped.rb +113 -0
  39. data/lib/factbase/tee.rb +2 -19
  40. data/lib/factbase/term.rb +3 -20
  41. data/lib/factbase/term_once.rb +2 -19
  42. data/lib/factbase/terms/aggregates.rb +4 -21
  43. data/lib/factbase/terms/aliases.rb +2 -19
  44. data/lib/factbase/terms/casting.rb +2 -19
  45. data/lib/factbase/terms/debug.rb +2 -19
  46. data/lib/factbase/terms/defn.rb +2 -19
  47. data/lib/factbase/terms/logical.rb +3 -20
  48. data/lib/factbase/terms/math.rb +2 -19
  49. data/lib/factbase/terms/meta.rb +4 -21
  50. data/lib/factbase/terms/ordering.rb +3 -20
  51. data/lib/factbase/terms/strings.rb +2 -19
  52. data/lib/factbase/terms/system.rb +2 -19
  53. data/lib/factbase/to_json.rb +2 -19
  54. data/lib/factbase/to_xml.rb +2 -19
  55. data/lib/factbase/to_yaml.rb +2 -19
  56. data/lib/factbase.rb +48 -50
  57. data/test/factbase/terms/test_aggregates.rb +2 -19
  58. data/test/factbase/terms/test_aliases.rb +2 -19
  59. data/test/factbase/terms/test_casting.rb +2 -19
  60. data/test/factbase/terms/test_debug.rb +2 -19
  61. data/test/factbase/terms/test_defn.rb +2 -19
  62. data/test/factbase/terms/test_logical.rb +2 -19
  63. data/test/factbase/terms/test_math.rb +2 -19
  64. data/test/factbase/terms/test_meta.rb +2 -19
  65. data/test/factbase/terms/test_ordering.rb +2 -19
  66. data/test/factbase/terms/test_strings.rb +2 -19
  67. data/test/factbase/terms/test_system.rb +2 -19
  68. data/test/factbase/test_accum.rb +2 -19
  69. data/test/factbase/test_churn.rb +40 -0
  70. data/test/factbase/test_fact.rb +2 -19
  71. data/test/factbase/test_flatten.rb +2 -19
  72. data/test/factbase/test_inv.rb +2 -19
  73. data/test/factbase/test_looged.rb +6 -23
  74. data/test/factbase/test_pre.rb +2 -19
  75. data/test/factbase/test_query.rb +2 -19
  76. data/test/factbase/test_rules.rb +2 -19
  77. data/test/factbase/test_syntax.rb +2 -19
  78. data/test/factbase/test_tallied.rb +71 -0
  79. data/test/factbase/test_taped.rb +36 -0
  80. data/test/factbase/test_tee.rb +2 -19
  81. data/test/factbase/test_term.rb +2 -19
  82. data/test/factbase/test_to_json.rb +2 -19
  83. data/test/factbase/test_to_xml.rb +2 -19
  84. data/test/factbase/test_to_yaml.rb +2 -19
  85. data/test/test__helper.rb +3 -19
  86. data/test/test_factbase.rb +81 -50
  87. metadata +12 -3
  88. data/.yamllint.yml +0 -29
data/Gemfile.lock CHANGED
@@ -55,7 +55,7 @@ GEM
55
55
  crass (1.0.6)
56
56
  date (3.4.1)
57
57
  decoor (0.0.1)
58
- diff-lcs (1.5.1)
58
+ diff-lcs (1.6.0)
59
59
  docile (1.4.1)
60
60
  drb (2.2.1)
61
61
  erubi (1.13.1)
@@ -66,9 +66,10 @@ GEM
66
66
  pp (>= 0.6.0)
67
67
  rdoc (>= 4.0.0)
68
68
  reline (>= 0.4.2)
69
- json (2.9.1)
69
+ json (2.10.1)
70
70
  language_server-protocol (3.17.0.4)
71
- logger (1.6.5)
71
+ lint_roller (1.1.0)
72
+ logger (1.6.6)
72
73
  loofah (2.24.0)
73
74
  crass (~> 1.0.2)
74
75
  nokogiri (>= 1.12.0)
@@ -79,17 +80,17 @@ GEM
79
80
  builder
80
81
  minitest (>= 5.0)
81
82
  ruby-progressbar
82
- nokogiri (1.18.2-arm64-darwin)
83
+ nokogiri (1.18.3-arm64-darwin)
83
84
  racc (~> 1.4)
84
- nokogiri (1.18.2-x64-mingw-ucrt)
85
+ nokogiri (1.18.3-x64-mingw-ucrt)
85
86
  racc (~> 1.4)
86
- nokogiri (1.18.2-x86_64-darwin)
87
+ nokogiri (1.18.3-x86_64-darwin)
87
88
  racc (~> 1.4)
88
- nokogiri (1.18.2-x86_64-linux-gnu)
89
+ nokogiri (1.18.3-x86_64-linux-gnu)
89
90
  racc (~> 1.4)
90
91
  others (0.0.3)
91
92
  parallel (1.26.3)
92
- parser (3.3.7.0)
93
+ parser (3.3.7.1)
93
94
  ast (~> 2.4.1)
94
95
  racc
95
96
  pp (0.6.2)
@@ -99,7 +100,7 @@ GEM
99
100
  date
100
101
  stringio
101
102
  racc (1.8.1)
102
- rack (3.1.8)
103
+ rack (3.1.10)
103
104
  rack-session (2.1.0)
104
105
  base64 (>= 0.1.0)
105
106
  rack (>= 3.0.0)
@@ -124,13 +125,13 @@ GEM
124
125
  zeitwerk (~> 2.6)
125
126
  rainbow (3.1.1)
126
127
  rake (13.2.1)
127
- rdoc (6.11.0)
128
+ rdoc (6.12.0)
128
129
  psych (>= 4.0.0)
129
130
  regexp_parser (2.10.0)
130
131
  reline (0.6.0)
131
132
  io-console (~> 0.5)
132
- rexml (3.4.0)
133
- rspec-core (3.13.2)
133
+ rexml (3.4.1)
134
+ rspec-core (3.13.3)
134
135
  rspec-support (~> 3.13.0)
135
136
  rspec-expectations (3.13.3)
136
137
  diff-lcs (>= 1.2.0, < 2.0)
@@ -138,7 +139,7 @@ GEM
138
139
  rspec-mocks (3.13.2)
139
140
  diff-lcs (>= 1.2.0, < 2.0)
140
141
  rspec-support (~> 3.13.0)
141
- rspec-rails (7.1.0)
142
+ rspec-rails (7.1.1)
142
143
  actionpack (>= 7.0)
143
144
  activesupport (>= 7.0)
144
145
  railties (>= 7.0)
@@ -147,26 +148,33 @@ GEM
147
148
  rspec-mocks (~> 3.13)
148
149
  rspec-support (~> 3.13)
149
150
  rspec-support (3.13.2)
150
- rubocop (1.71.0)
151
+ rubocop (1.72.2)
151
152
  json (~> 2.3)
152
- language_server-protocol (>= 3.17.0)
153
+ language_server-protocol (~> 3.17.0.2)
154
+ lint_roller (~> 1.1.0)
153
155
  parallel (~> 1.10)
154
156
  parser (>= 3.3.0.2)
155
157
  rainbow (>= 2.2.2, < 4.0)
156
158
  regexp_parser (>= 2.9.3, < 3.0)
157
- rubocop-ast (>= 1.36.2, < 2.0)
159
+ rubocop-ast (>= 1.38.0, < 2.0)
158
160
  ruby-progressbar (~> 1.7)
159
161
  unicode-display_width (>= 2.4.0, < 4.0)
160
162
  rubocop-ast (1.38.0)
161
163
  parser (>= 3.3.1.0)
162
- rubocop-minitest (0.36.0)
163
- rubocop (>= 1.61, < 2.0)
164
- rubocop-ast (>= 1.31.1, < 2.0)
165
- rubocop-performance (1.23.1)
166
- rubocop (>= 1.48.1, < 2.0)
167
- rubocop-ast (>= 1.31.1, < 2.0)
168
- rubocop-rspec (3.4.0)
169
- rubocop (~> 1.61)
164
+ rubocop-minitest (0.37.1)
165
+ lint_roller (~> 1.1)
166
+ rubocop (>= 1.72.1, < 2.0)
167
+ rubocop-ast (>= 1.38.0, < 2.0)
168
+ rubocop-performance (1.24.0)
169
+ lint_roller (~> 1.1)
170
+ rubocop (>= 1.72.1, < 2.0)
171
+ rubocop-ast (>= 1.38.0, < 2.0)
172
+ rubocop-rake (0.7.1)
173
+ lint_roller (~> 1.1)
174
+ rubocop (>= 1.72.1)
175
+ rubocop-rspec (3.5.0)
176
+ lint_roller (~> 1.1)
177
+ rubocop (~> 1.72, >= 1.72.1)
170
178
  ruby-progressbar (1.13.0)
171
179
  securerandom (0.4.1)
172
180
  simplecov (0.22.0)
@@ -178,7 +186,7 @@ GEM
178
186
  simplecov (~> 0.19)
179
187
  simplecov-html (0.13.1)
180
188
  simplecov_json_formatter (0.1.4)
181
- stringio (3.1.2)
189
+ stringio (3.1.5)
182
190
  tago (0.0.2)
183
191
  thor (1.3.2)
184
192
  threads (0.4.1)
@@ -193,7 +201,7 @@ GEM
193
201
  useragent (0.16.11)
194
202
  yaml (0.4.0)
195
203
  yard (0.9.37)
196
- zeitwerk (2.7.1)
204
+ zeitwerk (2.7.2)
197
205
 
198
206
  PLATFORMS
199
207
  arm64-darwin-22
@@ -209,11 +217,12 @@ DEPENDENCIES
209
217
  minitest (= 5.25.4)
210
218
  minitest-reporters (= 1.7.1)
211
219
  rake (= 13.2.1)
212
- rspec-rails (= 7.1.0)
213
- rubocop (= 1.71.0)
214
- rubocop-minitest (= 0.36.0)
215
- rubocop-performance (= 1.23.1)
216
- rubocop-rspec (= 3.4.0)
220
+ rspec-rails (= 7.1.1)
221
+ rubocop (= 1.72.2)
222
+ rubocop-minitest (> 0)
223
+ rubocop-performance (> 0)
224
+ rubocop-rake (> 0)
225
+ rubocop-rspec (> 0)
217
226
  simplecov (= 0.22.0)
218
227
  simplecov-cobertura (= 2.1.0)
219
228
  threads (= 0.4.1)
data/LICENSES/MIT.txt ADDED
@@ -0,0 +1,21 @@
1
+ (The MIT License)
2
+
3
+ Copyright (c) 2024-2025 Yegor Bugayenko
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the 'Software'), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
data/README.md CHANGED
@@ -64,6 +64,30 @@ if f[n].nil?
64
64
  end
65
65
  ```
66
66
 
67
+ You can make a factbase log all operations:
68
+
69
+ ```ruby
70
+ require 'loog'
71
+ require 'factbase/looged'
72
+ log = Loog::VERBOSE
73
+ fb = Factbase::Looged.new(Factbase.new, log)
74
+ f = fb.insert
75
+ ```
76
+
77
+ You can also count the amount of changes made to a factbase:
78
+
79
+ ```ruby
80
+ require 'loog'
81
+ require 'factbase/tailled'
82
+ log = Loog::VERBOSE
83
+ fb = Factbase::Tailled.new(Factbase.new, log)
84
+ f = fb.insert
85
+ churn = fb.churn
86
+ assert churn.inserted == 1
87
+ ```
88
+
89
+ ## Terms
90
+
67
91
  There are some boolean terms available in a query
68
92
  (they return either `true` or `false`):
69
93
 
@@ -185,18 +209,24 @@ This is the result of the benchmark:
185
209
  <!-- benchmark_begin -->
186
210
  | Action | Seconds | Details |
187
211
  | --- | --: | --- |
188
- | `fb.insert()` | 7.874 | Inserted 100000 facts |
189
- | `(gt time '2024-03-23T03:21:43Z')` | 0.072 | Found 100000 fact(s) |
190
- | `(gt cost 50)` | 0.069 | Found 50030 fact(s) |
191
- | `(eq title 'Object Thinking 5000')` | 0.051 | Found 1 fact(s) |
192
- | `(and (eq foo 42.998) (or (gt bar 200) (absent zzz)))` | 0.059 | Found 2 fact(s) |
193
- | `(eq id (agg (always) (max id)))` | 0.131 | Found 1 fact(s) |
194
- | `(join "c<=cost,b<=bar" (eq id (agg (always) (max id))))` | 0.695 | Found 100000 fact(s) |
195
- | `.export()` + `.import()` | 1.931 | 11407636 bytes |
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) |
196
226
 
197
227
  The results were calculated in [this GHA job][benchmark-gha]
198
- on 2025-01-27 at 16:51,
228
+ on 2025-02-24 at 13:32,
199
229
  on Linux with 4 CPUs.
200
230
  <!-- benchmark_end -->
201
231
 
202
- [benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/12994018323
232
+ [benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/13499241189
data/REUSE.toml ADDED
@@ -0,0 +1,25 @@
1
+ # SPDX-FileCopyrightText: Copyright (c) 2025 Yegor Bugayenko
2
+ # SPDX-License-Identifier: MIT
3
+
4
+ version = 1
5
+ [[annotations]]
6
+ path = [
7
+ "**/*.jpg",
8
+ "**/*.json",
9
+ "**/*.md",
10
+ "**/*.pdf",
11
+ "**/*.png",
12
+ "**/*.svg",
13
+ "**/.gitignore",
14
+ ".gitattributes",
15
+ ".gitignore",
16
+ ".gitleaksignore",
17
+ ".pdd",
18
+ ".xcop",
19
+ "Gemfile.lock",
20
+ "README.md",
21
+ "renovate.json",
22
+ ]
23
+ precedence = "override"
24
+ SPDX-FileCopyrightText = "Copyright (c) 2025 Yegor Bugayenko"
25
+ SPDX-License-Identifier = "MIT"
data/Rakefile CHANGED
@@ -1,24 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2024-2025 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
22
5
 
23
6
  require 'rubygems'
24
7
  require 'rake'
@@ -32,7 +15,7 @@ def version
32
15
  Gem::Specification.load(Dir['*.gemspec'].first).version
33
16
  end
34
17
 
35
- task default: %i[clean test rubocop yard copyright]
18
+ task default: %i[clean test rubocop yard]
36
19
 
37
20
  require 'rake/testtask'
38
21
  desc 'Run all unit tests'
@@ -61,11 +44,3 @@ desc 'Run benchmark script'
61
44
  task :benchmark do
62
45
  ruby 'benchmarks/simple.rb'
63
46
  end
64
-
65
- task :copyright do
66
- sh "grep -q -r '#{Date.today.strftime('%Y')}' \
67
- --include '*.rb' \
68
- --include '*.txt' \
69
- --include 'Rakefile' \
70
- ."
71
- end
data/benchmarks/simple.rb CHANGED
@@ -1,25 +1,8 @@
1
1
  #!/usr/bin/env ruby
2
2
  # frozen_string_literal: true
3
3
 
4
- # Copyright (c) 2024-2025 Yegor Bugayenko
5
- #
6
- # Permission is hereby granted, free of charge, to any person obtaining a copy
7
- # of this software and associated documentation files (the 'Software'), to deal
8
- # in the Software without restriction, including without limitation the rights
9
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
- # copies of the Software, and to permit persons to whom the Software is
11
- # furnished to do so, subject to the following conditions:
12
- #
13
- # The above copyright notice and this permission notice shall be included in all
14
- # copies or substantial portions of the Software.
15
- #
16
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
19
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22
- # SOFTWARE.
4
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
5
+ # SPDX-License-Identifier: MIT
23
6
 
24
7
  require 'benchmark'
25
8
  require 'time'
@@ -49,7 +32,7 @@ end
49
32
 
50
33
  def query(fb, query)
51
34
  total = 0
52
- runs = 10
35
+ runs = 100
53
36
  time =
54
37
  Benchmark.measure do
55
38
  runs.times do
@@ -58,8 +41,21 @@ def query(fb, query)
58
41
  end
59
42
  {
60
43
  title: "`#{query}`",
61
- time: (time.real / runs).round(6),
62
- details: "Found #{total} fact(s)"
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)"
63
59
  }
64
60
  end
65
61
 
@@ -79,16 +75,51 @@ def impex(fb)
79
75
  }
80
76
  end
81
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
+
82
91
  fb = Factbase.new
83
92
  rows = [
84
- insert(fb, 100_000),
93
+ insert(fb, 25_000),
85
94
  query(fb, '(gt time \'2024-03-23T03:21:43Z\')'),
86
95
  query(fb, '(gt cost 50)'),
87
96
  query(fb, '(eq title \'Object Thinking 5000\')'),
88
97
  query(fb, '(and (eq foo 42.998) (or (gt bar 200) (absent zzz)))'),
89
98
  query(fb, '(eq id (agg (always) (max id)))'),
90
99
  query(fb, '(join "c<=cost,b<=bar" (eq id (agg (always) (max id))))'),
91
- impex(fb)
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)')
92
123
  ].map { |r| "| #{r[:title]} | #{format('%0.3f', r[:time])} | #{r[:details]} |" }
93
124
 
94
125
  puts '| Action | Seconds | Details |'
data/factbase.gemspec CHANGED
@@ -1,24 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2024-2025 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
22
5
 
23
6
  require 'English'
24
7
  require_relative 'lib/factbase'
@@ -1,24 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2024-2025 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
22
5
 
23
6
  require 'others'
24
7
  require_relative '../factbase'
@@ -58,8 +41,8 @@ class Factbase::Accum
58
41
  kk = args[1].to_s
59
42
  vv = @props[kk].nil? ? [] : @props[kk]
60
43
  vvv = @fact.method_missing(*args)
61
- vvv = [vvv] unless vvv.nil? || vvv.is_a?(Array)
62
- vv += vvv unless vvv.nil?
44
+ vvv = [vvv] unless vvv.nil? || vvv.respond_to?(:each)
45
+ vv += vvv.to_a unless vvv.nil?
63
46
  vv.uniq!
64
47
  vv.empty? ? nil : vv
65
48
  elsif @props[k].nil?
@@ -0,0 +1,44 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ # A churn.
7
+ #
8
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
9
+ # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
10
+ # License:: MIT
11
+ class Factbase::Churn
12
+ attr_reader :inserted, :deleted, :added
13
+
14
+ def initialize(ins = 0, del = 0, add = 0)
15
+ @mutex = Mutex.new
16
+ @inserted = ins
17
+ @deleted = del
18
+ @added = add
19
+ end
20
+
21
+ def to_s
22
+ "#{@inserted}i/#{@deleted}d/#{@added}a"
23
+ end
24
+
25
+ def zero?
26
+ @inserted.zero? && @deleted.zero? && @added.zero?
27
+ end
28
+
29
+ def append(ins, del, add)
30
+ @mutex.synchronize do
31
+ @inserted += ins
32
+ @deleted += del
33
+ @added += add
34
+ end
35
+ end
36
+
37
+ def +(other)
38
+ Factbase::Churn.new(
39
+ @inserted + other.inserted,
40
+ @deleted + other.deleted,
41
+ @added + other.added
42
+ )
43
+ end
44
+ end
data/lib/factbase/fact.rb CHANGED
@@ -1,24 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2024-2025 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
22
5
 
23
6
  require 'json'
24
7
  require 'time'
@@ -1,24 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2024-2025 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
22
5
 
23
6
  require_relative '../factbase'
24
7
 
data/lib/factbase/inv.rb CHANGED
@@ -1,24 +1,7 @@
1
1
  # frozen_string_literal: true
2
2
 
3
- # Copyright (c) 2024-2025 Yegor Bugayenko
4
- #
5
- # Permission is hereby granted, free of charge, to any person obtaining a copy
6
- # of this software and associated documentation files (the 'Software'), to deal
7
- # in the Software without restriction, including without limitation the rights
8
- # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
- # copies of the Software, and to permit persons to whom the Software is
10
- # furnished to do so, subject to the following conditions:
11
- #
12
- # The above copyright notice and this permission notice shall be included in all
13
- # copies or substantial portions of the Software.
14
- #
15
- # THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
- # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
- # FITNESS FOR A PARTICULAR PURPOSE AND NONINFINGEMENT. IN NO EVENT SHALL THE
18
- # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
- # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
- # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
- # SOFTWARE.
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
22
5
 
23
6
  require 'others'
24
7
  require 'decoor'
@@ -36,10 +19,6 @@ class Factbase::Inv
36
19
  @block = block
37
20
  end
38
21
 
39
- def dup
40
- Factbase::Inv.new(@fb.dup, &@block)
41
- end
42
-
43
22
  def insert
44
23
  Fact.new(@fb.insert, @block)
45
24
  end
@@ -48,8 +27,10 @@ class Factbase::Inv
48
27
  Query.new(@fb.query(query), @block)
49
28
  end
50
29
 
51
- def txn(this = self, &)
52
- @fb.txn(this, &)
30
+ def txn
31
+ @fb.txn do |fbt|
32
+ yield Factbase::Inv.new(fbt, &@block)
33
+ end
53
34
  end
54
35
 
55
36
  # Fact decorator.
@@ -0,0 +1,32 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require_relative '../factbase'
7
+
8
+ # A decorator of a Factbase, that forbids most of the operations.
9
+ #
10
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
11
+ # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
12
+ # License:: MIT
13
+ class Factbase::Light
14
+ attr_reader :cache
15
+
16
+ def initialize(fb, cache)
17
+ @fb = fb
18
+ @cache = cache
19
+ end
20
+
21
+ def size
22
+ @fb.size
23
+ end
24
+
25
+ def insert
26
+ @fb.insert
27
+ end
28
+
29
+ def query(query)
30
+ @fb.query(query)
31
+ end
32
+ end