factbase 0.7.3 → 0.7.5

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 (54) hide show
  1. checksums.yaml +4 -4
  2. data/.github/workflows/benchmark.yml +3 -1
  3. data/.gitignore +6 -5
  4. data/.rultor.yml +1 -1
  5. data/Gemfile +1 -1
  6. data/Gemfile.lock +9 -9
  7. data/README.md +37 -25
  8. data/REUSE.toml +4 -0
  9. data/Rakefile +10 -3
  10. data/benchmark/bench_factbase.rb +61 -0
  11. data/benchmark/bench_large_query.rb +128 -0
  12. data/benchmark/bench_query.rb +41 -0
  13. data/benchmark/bench_taped.rb +33 -0
  14. data/factbase.gemspec +5 -5
  15. data/lib/factbase/accum.rb +1 -1
  16. data/lib/factbase/{looged.rb → logged.rb} +8 -8
  17. data/lib/factbase/taped.rb +25 -25
  18. data/lib/factbase/term.rb +9 -1
  19. data/lib/factbase/terms/aggregates.rb +2 -2
  20. data/lib/factbase/terms/meta.rb +1 -1
  21. data/lib/factbase/terms/ordering.rb +1 -1
  22. data/lib/factbase.rb +3 -5
  23. data/test/factbase/terms/test_aggregates.rb +2 -2
  24. data/test/factbase/terms/test_aliases.rb +4 -4
  25. data/test/factbase/terms/test_casting.rb +1 -2
  26. data/test/factbase/terms/test_debug.rb +2 -2
  27. data/test/factbase/terms/test_defn.rb +2 -2
  28. data/test/factbase/terms/test_logical.rb +2 -2
  29. data/test/factbase/terms/test_math.rb +1 -2
  30. data/test/factbase/terms/test_meta.rb +2 -2
  31. data/test/factbase/terms/test_ordering.rb +2 -2
  32. data/test/factbase/terms/test_strings.rb +2 -2
  33. data/test/factbase/terms/test_system.rb +1 -2
  34. data/test/factbase/test_accum.rb +2 -2
  35. data/test/factbase/test_churn.rb +2 -2
  36. data/test/factbase/test_fact.rb +2 -2
  37. data/test/factbase/test_flatten.rb +2 -2
  38. data/test/factbase/test_inv.rb +2 -2
  39. data/test/factbase/{test_looged.rb → test_logged.rb} +13 -13
  40. data/test/factbase/test_pre.rb +2 -2
  41. data/test/factbase/test_query.rb +2 -2
  42. data/test/factbase/test_rules.rb +2 -2
  43. data/test/factbase/test_syntax.rb +2 -2
  44. data/test/factbase/test_tallied.rb +2 -2
  45. data/test/factbase/test_taped.rb +2 -2
  46. data/test/factbase/test_tee.rb +2 -2
  47. data/test/factbase/test_term.rb +2 -2
  48. data/test/factbase/test_to_json.rb +2 -2
  49. data/test/factbase/test_to_xml.rb +2 -2
  50. data/test/factbase/test_to_yaml.rb +2 -2
  51. data/test/test__helper.rb +3 -1
  52. data/test/test_factbase.rb +5 -5
  53. metadata +29 -29
  54. data/benchmarks/simple.rb +0 -127
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 1d14f3343341431bb4e9828abfc7f2c0bdda83d2c484cf6df1dbbc49b9b442ca
4
- data.tar.gz: 48e762c8d0c94102c8e757469c177698db655714128ae315d53696421fecce04
3
+ metadata.gz: 7a3adc3cc2aec38609bd1d98b4266e18db6d3fc9e0e9eb3714f9772bf6bfee60
4
+ data.tar.gz: 7eae0cf3bbd8b1d432971f051ad08be1f39df640245d2b0f565c14a95a436aa1
5
5
  SHA512:
6
- metadata.gz: 584de94a190d5a07693d788f9d36db7899b6535e353315d41a864184384f62825a0b6c0885a23a9f7332621bb96891362fdc090f2f6e11dac7663af9b5c35fef
7
- data.tar.gz: 78b784ccb6d2800dd3aa3711dd74cd43ec801a8343f87b695d47d6d9ae195d78e9350c57900dac388304da2a91f17b0b2bbf16ba8475fb794aea000e22a4c517
6
+ metadata.gz: ee55ea6c2b5c2bd780c5b241bc16c14a2151adcb44829ec15b71c6e6fa614f9c9776e11d7c0bf76e2693a9141c745a0a233946e7b09b9961dc042f2ab22d412a
7
+ data.tar.gz: 59c44e45b9a6f2bbfe70a7fe1e649fba6c3af8b9d04e9d225289cd32d7736db1e37a138f53ed300b5639fdadbe9cef448750c9033c08aad10f4d5e13c0587e91
@@ -23,11 +23,13 @@ jobs:
23
23
  bundler-cache: true
24
24
  - run: bundle config set --global path "$(pwd)/vendor/bundle"
25
25
  - run: bundle install --no-color
26
- - run: bundle exec ruby benchmarks/simple.rb > stdout.txt
26
+ - run: bundle exec rake benchmark > stdout.txt
27
27
  - run: |
28
28
  set -x
29
29
  sum=$(
30
+ echo '```text'
30
31
  cat stdout.txt
32
+ echo '```'
31
33
  echo
32
34
  echo "The results were calculated in [this GHA job][benchmark-gha]"
33
35
  echo "on $(date +'%Y-%m-%d') at $(date +'%H:%M'),"
data/.gitignore CHANGED
@@ -1,9 +1,10 @@
1
- coverage/
2
- .idea/
3
1
  *.gem
4
- .bundle/
5
2
  .DS_Store
6
- rdoc/
7
- doc/
3
+ .bundle/
4
+ .idea/
8
5
  .yardoc/
6
+ coverage/
7
+ doc/
8
+ node_modules/
9
+ rdoc/
9
10
  vendor/
data/.rultor.yml CHANGED
@@ -3,7 +3,7 @@
3
3
  ---
4
4
  # yamllint disable rule:line-length
5
5
  docker:
6
- image: yegor256/rultor-ruby
6
+ image: yegor256/ruby
7
7
  assets:
8
8
  rubygems.yml: yegor256/home#assets/rubygems.yml
9
9
  install: |
data/Gemfile CHANGED
@@ -10,7 +10,7 @@ gem 'minitest', '5.25.4', require: false
10
10
  gem 'minitest-reporters', '1.7.1', require: false
11
11
  gem 'rake', '13.2.1', require: false
12
12
  gem 'rspec-rails', '7.1.1', require: false
13
- gem 'rubocop', '1.72.2', require: false
13
+ gem 'rubocop', '1.73.1', require: false
14
14
  gem 'rubocop-minitest', '>0', require: false
15
15
  gem 'rubocop-performance', '>0', require: false
16
16
  gem 'rubocop-rake', '>0', require: false
data/Gemfile.lock CHANGED
@@ -2,13 +2,13 @@ PATH
2
2
  remote: .
3
3
  specs:
4
4
  factbase (0.0.0)
5
- backtrace (> 0)
6
- decoor (> 0)
5
+ backtrace (>= 0.4.0)
6
+ decoor (>= 0.0.1)
7
7
  json (~> 2.7)
8
- loog (> 0)
8
+ loog (>= 0.6.0)
9
9
  nokogiri (~> 1.10)
10
- others (> 0)
11
- tago (> 0)
10
+ others (>= 0.0.3)
11
+ tago (>= 0.0.2)
12
12
  yaml (~> 0.3)
13
13
 
14
14
  GEM
@@ -148,7 +148,7 @@ GEM
148
148
  rspec-mocks (~> 3.13)
149
149
  rspec-support (~> 3.13)
150
150
  rspec-support (3.13.2)
151
- rubocop (1.72.2)
151
+ rubocop (1.73.1)
152
152
  json (~> 2.3)
153
153
  language_server-protocol (~> 3.17.0.2)
154
154
  lint_roller (~> 1.1.0)
@@ -159,7 +159,7 @@ GEM
159
159
  rubocop-ast (>= 1.38.0, < 2.0)
160
160
  ruby-progressbar (~> 1.7)
161
161
  unicode-display_width (>= 2.4.0, < 4.0)
162
- rubocop-ast (1.38.0)
162
+ rubocop-ast (1.38.1)
163
163
  parser (>= 3.3.1.0)
164
164
  rubocop-minitest (0.37.1)
165
165
  lint_roller (~> 1.1)
@@ -197,7 +197,7 @@ GEM
197
197
  unicode-display_width (3.1.4)
198
198
  unicode-emoji (~> 4.0, >= 4.0.4)
199
199
  unicode-emoji (4.0.4)
200
- uri (1.0.2)
200
+ uri (1.0.3)
201
201
  useragent (0.16.11)
202
202
  yaml (0.4.0)
203
203
  yard (0.9.37)
@@ -218,7 +218,7 @@ DEPENDENCIES
218
218
  minitest-reporters (= 1.7.1)
219
219
  rake (= 13.2.1)
220
220
  rspec-rails (= 7.1.1)
221
- rubocop (= 1.72.2)
221
+ rubocop (= 1.73.1)
222
222
  rubocop-minitest (> 0)
223
223
  rubocop-performance (> 0)
224
224
  rubocop-rake (> 0)
data/README.md CHANGED
@@ -17,7 +17,7 @@ The values are either atomic literals or non-empty sets of literals.
17
17
  It is possible to delete a fact, but impossible to delete a property
18
18
  from a fact.
19
19
 
20
- **ATTENTION**: The current implemention is naive and,
20
+ **ATTENTION**: The current implementation is naive and,
21
21
  because of that, **very slow**. I will be very happy
22
22
  if you suggest a better implementation without the change of the interface.
23
23
  The `Factbase::query()` method is what mostly needs performance optimization:
@@ -68,9 +68,9 @@ You can make a factbase log all operations:
68
68
 
69
69
  ```ruby
70
70
  require 'loog'
71
- require 'factbase/looged'
71
+ require 'factbase/logged'
72
72
  log = Loog::VERBOSE
73
- fb = Factbase::Looged.new(Factbase.new, log)
73
+ fb = Factbase::Logged.new(Factbase.new, log)
74
74
  f = fb.insert
75
75
  ```
76
76
 
@@ -78,9 +78,9 @@ You can also count the amount of changes made to a factbase:
78
78
 
79
79
  ```ruby
80
80
  require 'loog'
81
- require 'factbase/tailled'
81
+ require 'factbase/tallied'
82
82
  log = Loog::VERBOSE
83
- fb = Factbase::Tailled.new(Factbase.new, log)
83
+ fb = Factbase::Tallied.new(Factbase.new, log)
84
84
  f = fb.insert
85
85
  churn = fb.churn
86
86
  assert churn.inserted == 1
@@ -137,7 +137,7 @@ Also, some simple arithmetic:
137
137
  * `(div v1 v2)` is a division of `∏v1` by `∏v2`
138
138
 
139
139
  It's possible to add and deduct string values to time values, like
140
- `(plus t '2 days')` or ``(minus t '14 hours')``.
140
+ `(plus t '2 days')` or `(minus t '14 hours')`.
141
141
 
142
142
  Types may be converted:
143
143
 
@@ -190,7 +190,7 @@ There are some system-level terms:
190
190
 
191
191
  Read
192
192
  [these guidelines](https://www.yegor256.com/2014/04/15/github-guidelines.html).
193
- Make sure you build is green before you contribute
193
+ Make sure your build is green before you contribute
194
194
  your pull request. You will need to have
195
195
  [Ruby](https://www.ruby-lang.org/en/) 3.2+ and
196
196
  [Bundler](https://bundler.io/) installed. Then:
@@ -207,26 +207,38 @@ If it's clean and you don't see any error messages, submit your pull request.
207
207
  This is the result of the benchmark:
208
208
 
209
209
  <!-- benchmark_begin -->
210
- | Action | Seconds | Details |
211
- | --- | --: | --- |
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) |
210
+ ```text
211
+
212
+
213
+ Benchmarking, please wait a few seconds...
214
+ user system total real
215
+ insert 500 facts 0.017487 0.000000 0.017487 ( 0.017560)
216
+ export 500 facts 0.000517 0.000024 0.000541 ( 0.000542)
217
+ import 10456 bytes (500 facts) 0.000404 0.000000 0.000404 ( 0.000404)
218
+ insert 10 facts 0.001825 0.000000 0.001825 ( 0.001826)
219
+ query 10 times w/txn 0.049619 0.003999 0.053618 ( 0.053621)
220
+ query 10 times w/o txn 0.043671 0.000000 0.043671 ( 0.043673)
221
+ modify 10 attrs w/txn 0.030897 0.000975 0.031872 ( 0.031875)
222
+ delete 10 facts w/txn 0.012024 0.000013 0.012037 ( 0.012038)
223
+ (and (eq what 'issue-was-closed') (exists... -> 200 7.836740 0.018246 7.854986 ( 7.855478)
224
+ (and (eq what 'issue-was-closed') (exists... -> 200/txn 8.817858 0.014003 8.831861 ( 8.832345)
225
+ (and (eq what 'issue-was-closed') (exists... -> zero 10.051354 0.017001 10.068355 ( 10.069083)
226
+ (and (eq what 'issue-was-closed') (exists... -> zero/txn 10.667497 0.016002 10.683499 ( 10.684435)
227
+ (gt time '2024-03-23T03:21:43Z') 0.008827 0.000000 0.008827 ( 0.008827)
228
+ (gt cost 50) 0.009784 0.000002 0.009786 ( 0.009789)
229
+ (eq title 'Object Thinking 5000') 0.008519 0.000000 0.008519 ( 0.008523)
230
+ (and (eq foo 42.998) (or (gt bar 200) (absent zzz))) 0.013591 0.000000 0.013591 ( 0.013595)
231
+ (eq id (agg (always) (max id))) 0.021419 0.000000 0.021419 ( 0.021423)
232
+ (join "c<=cost,b<=bar" (eq id (agg (always) (max id)))) 0.141201 0.000000 0.141201 ( 0.141216)
233
+ delete! 0.004025 0.000000 0.004025 ( 0.004027)
234
+ Taped.append() x50000 0.038128 0.001997 0.040125 ( 0.040130)
235
+ Taped.each() x125 1.510154 0.001001 1.511155 ( 1.511313)
236
+ Taped.delete_if() x375 0.883123 0.000000 0.883123 ( 0.883229)
237
+ ```
226
238
 
227
239
  The results were calculated in [this GHA job][benchmark-gha]
228
- on 2025-02-24 at 13:32,
240
+ on 2025-03-03 at 15:04,
229
241
  on Linux with 4 CPUs.
230
242
  <!-- benchmark_end -->
231
243
 
232
- [benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/13499241189
244
+ [benchmark-gha]: https://github.com/yegor256/factbase/actions/runs/13633891920
data/REUSE.toml CHANGED
@@ -4,13 +4,17 @@
4
4
  version = 1
5
5
  [[annotations]]
6
6
  path = [
7
+ "**/*.csv",
7
8
  "**/*.jpg",
8
9
  "**/*.json",
9
10
  "**/*.md",
10
11
  "**/*.pdf",
11
12
  "**/*.png",
12
13
  "**/*.svg",
14
+ "**/*.txt",
15
+ "**/*.vm",
13
16
  "**/.gitignore",
17
+ "**/CNAME",
14
18
  ".gitattributes",
15
19
  ".gitignore",
16
20
  ".gitleaksignore",
data/Rakefile CHANGED
@@ -15,7 +15,7 @@ def version
15
15
  Gem::Specification.load(Dir['*.gemspec'].first).version
16
16
  end
17
17
 
18
- task default: %i[clean test rubocop yard]
18
+ task default: %i[clean test rubocop yard benchmark]
19
19
 
20
20
  require 'rake/testtask'
21
21
  desc 'Run all unit tests'
@@ -40,7 +40,14 @@ RuboCop::RakeTask.new(:rubocop) do |task|
40
40
  task.requires << 'rubocop-rspec'
41
41
  end
42
42
 
43
- desc 'Run benchmark script'
43
+ desc 'Benchmark them all'
44
44
  task :benchmark do
45
- ruby 'benchmarks/simple.rb'
45
+ fb = Factbase.new
46
+ require 'benchmark'
47
+ Benchmark.bm(60) do |b|
48
+ Dir['benchmark/bench_*.rb'].each do |f|
49
+ require_relative f
50
+ Kernel.send(File.basename(f).gsub(/\.rb$/, '').to_sym, b, fb)
51
+ end
52
+ end
46
53
  end
@@ -0,0 +1,61 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require_relative '../lib/factbase'
7
+
8
+ def bench_factbase(bmk, fb)
9
+ total = 500
10
+ bmk.report("insert #{total} facts") do
11
+ total.times do
12
+ fact = fb.insert
13
+ fact.foo = rand(0.0..100.0).round(3)
14
+ fact.bar = rand(100..300)
15
+ end
16
+ end
17
+
18
+ bin = nil
19
+ bmk.report("export #{total} facts") do
20
+ bin = fb.export
21
+ end
22
+ bmk.report("import #{bin.size} bytes (#{total} facts)") do
23
+ fb2 = Factbase.new
24
+ fb2.import(bin)
25
+ end
26
+
27
+ actions = 10
28
+ bmk.report("insert #{actions} facts") do
29
+ fb.txn do |fbt|
30
+ actions.times do
31
+ fbt.insert.z = rand(0..100)
32
+ end
33
+ end
34
+ end
35
+ bmk.report("query #{actions} times w/txn") do
36
+ fb.txn do |fbt|
37
+ actions.times do |i|
38
+ fbt.query("(gt foo #{i})").each.to_a.each
39
+ end
40
+ end
41
+ end
42
+ bmk.report("query #{actions} times w/o txn") do
43
+ actions.times do |i|
44
+ fb.query("(gt foo #{i})").each.to_a.each
45
+ end
46
+ end
47
+ bmk.report("modify #{actions} attrs w/txn") do
48
+ fb.txn do |fbt|
49
+ actions.times do |i|
50
+ fbt.query("(gt foo #{i})").each.to_a.first.bar = 55
51
+ end
52
+ end
53
+ end
54
+ bmk.report("delete #{actions} facts w/txn") do
55
+ fb.txn do |fbt|
56
+ actions.times do |i|
57
+ fbt.query("(gt foo #{100 - i})").delete!
58
+ end
59
+ end
60
+ end
61
+ end
@@ -0,0 +1,128 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require_relative '../lib/factbase'
7
+ require_relative '../lib/factbase/logged'
8
+
9
+ def bench_large_query(bmk, fb)
10
+ total = 200
11
+ repo = 'foo'
12
+ total.times do |i|
13
+ f = fb.insert
14
+ f.id = i
15
+ f.where = 'github'
16
+ f.what = 'issue-was-closed'
17
+ f.who = 444
18
+ f.when = Time.now - (i * rand(1_000..100_000))
19
+ f.issue = i
20
+ f.repository = repo
21
+ end
22
+ total.times do |i|
23
+ f = fb.insert
24
+ f.id = i + total
25
+ f.where = 'github'
26
+ f.what = 'label-was-attached'
27
+ f.when = Time.now - (i * rand(1_000..100_000))
28
+ f.issue = i
29
+ f.repository = repo
30
+ f.label = 'bug'
31
+ end
32
+ total.times do |i|
33
+ f = fb.insert
34
+ f.id = i + (total * 2)
35
+ f.where = 'github'
36
+ f.what = 'issue-was-opened'
37
+ f.who = 555
38
+ f.when = Time.now - (i * rand(1_000..100_000))
39
+ f.issue = i
40
+ f.repository = repo
41
+ end
42
+ total.times do |i|
43
+ f = fb.insert
44
+ f.id = i + (total * 3)
45
+ f.where = 'github'
46
+ f.what = 'issue-was-assigned'
47
+ f.who = 666
48
+ f.when = Time.now - (i * rand(1_000..100_000))
49
+ f.issue = i
50
+ f.repository = repo
51
+ end
52
+
53
+ q = "(and
54
+ (eq what 'issue-was-closed')
55
+ (exists where)
56
+ (exists who)
57
+ (exists when)
58
+ (exists issue)
59
+ (exists repository)
60
+ (join 'label' (and
61
+ (eq what 'label-was-attached')
62
+ (eq issue $issue)
63
+ (eq where $where)
64
+ (eq repository $repository)
65
+ (or (eq label 'bug') (eq label 'enhancement') (eq label 'question'))))
66
+ (exists label)
67
+ (join 'opened_when<=when,opener<=who' (and
68
+ (eq what 'issue-was-opened')
69
+ (eq where $where)
70
+ (eq issue $issue)
71
+ (eq repository $repository)))
72
+ (exists opener)
73
+ (join 'assigned_when<=when,assigner<=who' (and
74
+ (eq what 'issue-was-assigned')
75
+ (eq where $where)
76
+ (eq issue $issue)
77
+ (eq repository $repository)))
78
+ (exists assigner)
79
+ (as seconds (to_integer (minus when assigned_when)))
80
+ (as closer who)
81
+ (as who assigner)
82
+ (empty (and
83
+ (eq what 'bug-was-resolved')
84
+ (eq where $where)
85
+ (eq issue $issue)
86
+ (eq repository $repository))))".gsub(/\s+/, ' ')
87
+
88
+ cycles = 1
89
+ bmk.report("#{q[0..40]}... -> #{total}") do
90
+ cycles.times do
91
+ t = fb.query(q).each.to_a.size
92
+ raise "Found #{t} facts, expected to find #{total}" unless t == total
93
+ end
94
+ end
95
+ bmk.report("#{q[0..40]}... -> #{total}/txn") do
96
+ cycles.times do
97
+ fb.txn do |fbt|
98
+ t = fbt.query(q).each.to_a.size
99
+ raise "Found #{t} facts, expected to find #{total}" unless t == total
100
+ end
101
+ end
102
+ end
103
+
104
+ total.times do |i|
105
+ f = fb.insert
106
+ f.id = i
107
+ f.where = 'github'
108
+ f.what = 'bug-was-resolved'
109
+ f.who = 444
110
+ f.when = Time.now - (i * rand(1_000..100_000))
111
+ f.issue = i
112
+ f.repository = repo
113
+ end
114
+ bmk.report("#{q[0..40]}... -> zero") do
115
+ cycles.times do
116
+ t = fb.query(q).each.to_a.size
117
+ raise "Found #{t} facts, expected to find nothing" unless t.zero?
118
+ end
119
+ end
120
+ bmk.report("#{q[0..40]}... -> zero/txn") do
121
+ cycles.times do
122
+ fb.txn do |fbt|
123
+ t = fbt.query(q).each.to_a.size
124
+ raise "Found #{t} facts, expected to find nothing" unless t.zero?
125
+ end
126
+ end
127
+ end
128
+ end
@@ -0,0 +1,41 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require_relative '../lib/factbase'
7
+
8
+ def bench_query(bmk, fb)
9
+ total = 500
10
+ total.times do |i|
11
+ f = fb.insert
12
+ f.id = i
13
+ f.title = "Object Thinking #{i}"
14
+ f.time = Time.now.iso8601
15
+ f.cost = rand(1..100)
16
+ f.foo = rand(0.0..100.0).round(3)
17
+ f.bar = rand(100..300)
18
+ f.seenBy = "User#{i}" if i.even?
19
+ f.zzz = "Extra#{i}" if (i % 10).zero?
20
+ end
21
+
22
+ runs = 10
23
+ [
24
+ '(gt time \'2024-03-23T03:21:43Z\')',
25
+ '(gt cost 50)',
26
+ '(eq title \'Object Thinking 5000\')',
27
+ '(and (eq foo 42.998) (or (gt bar 200) (absent zzz)))',
28
+ '(eq id (agg (always) (max id)))',
29
+ '(join "c<=cost,b<=bar" (eq id (agg (always) (max id))))'
30
+ ].each do |q|
31
+ bmk.report(q) do
32
+ runs.times do
33
+ fb.query(q).each.to_a
34
+ end
35
+ end
36
+ end
37
+
38
+ bmk.report('delete!') do
39
+ fb.query('(gt foo 50)').delete!
40
+ end
41
+ end
@@ -0,0 +1,33 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require_relative '../lib/factbase'
7
+ require_relative '../lib/factbase/taped'
8
+
9
+ def bench_taped(bmk, _fb)
10
+ maps = []
11
+ taped = Factbase::Taped.new(maps)
12
+
13
+ cycles = 50_000
14
+ bmk.report("Taped.append() x#{cycles}") do
15
+ cycles.times do
16
+ taped << { foo: rand(0..100) }
17
+ end
18
+ end
19
+
20
+ cycles /= 400
21
+ bmk.report("Taped.each() x#{cycles}") do
22
+ cycles.times do
23
+ taped.each.to_a
24
+ end
25
+ end
26
+
27
+ cycles *= 3
28
+ bmk.report("Taped.delete_if() x#{cycles}") do
29
+ cycles.times do
30
+ taped.delete_if { |m| m[:foo] < 50 }
31
+ end
32
+ end
33
+ end
data/factbase.gemspec CHANGED
@@ -25,13 +25,13 @@ Gem::Specification.new do |s|
25
25
  s.files = `git ls-files`.split($RS)
26
26
  s.rdoc_options = ['--charset=UTF-8']
27
27
  s.extra_rdoc_files = ['README.md', 'LICENSE.txt']
28
- s.add_dependency 'backtrace', '>0'
29
- s.add_dependency 'decoor', '>0'
28
+ s.add_dependency 'backtrace', '>=0.4.0'
29
+ s.add_dependency 'decoor', '>=0.0.1'
30
30
  s.add_dependency 'json', '~>2.7'
31
- s.add_dependency 'loog', '>0'
31
+ s.add_dependency 'loog', '>=0.6.0'
32
32
  s.add_dependency 'nokogiri', '~>1.10'
33
- s.add_dependency 'others', '>0'
34
- s.add_dependency 'tago', '>0'
33
+ s.add_dependency 'others', '>=0.0.3'
34
+ s.add_dependency 'tago', '>=0.0.2'
35
35
  s.add_dependency 'yaml', '~>0.3'
36
36
  s.metadata['rubygems_mfa_required'] = 'true'
37
37
  end
@@ -41,7 +41,7 @@ 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.respond_to?(:each)
44
+ vvv = [vvv] unless vvv.nil? || vvv.respond_to?(:to_a)
45
45
  vv += vvv.to_a unless vvv.nil?
46
46
  vv.uniq!
47
47
  vv.empty? ? nil : vv
@@ -14,7 +14,7 @@ require_relative 'syntax'
14
14
  # Author:: Yegor Bugayenko (yegor256@gmail.com)
15
15
  # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
16
16
  # License:: MIT
17
- class Factbase::Looged
17
+ class Factbase::Logged
18
18
  def initialize(fb, loog)
19
19
  raise 'The "fb" is nil' if fb.nil?
20
20
  @fb = fb
@@ -42,7 +42,7 @@ class Factbase::Looged
42
42
  r =
43
43
  @fb.txn do |fbt|
44
44
  id = fbt.object_id
45
- yield Factbase::Looged.new(fbt, @loog)
45
+ yield Factbase::Logged.new(fbt, @loog)
46
46
  rescue Factbase::Rollback => e
47
47
  rollback = true
48
48
  raise e
@@ -102,7 +102,7 @@ class Factbase::Looged
102
102
  q = Factbase::Syntax.new(@fb, @expr).to_term.to_s
103
103
  r = nil
104
104
  tail =
105
- Factbase::Looged.elapsed do
105
+ Factbase::Logged.elapsed do
106
106
  r = @fb.query(@expr).one(params)
107
107
  end
108
108
  if r.nil?
@@ -118,10 +118,10 @@ class Factbase::Looged
118
118
  if block_given?
119
119
  r = nil
120
120
  tail =
121
- Factbase::Looged.elapsed do
121
+ Factbase::Logged.elapsed do
122
122
  r = @fb.query(@expr).each(params, &)
123
123
  end
124
- raise ".each of #{@query.class} returned #{r.class}" unless r.is_a?(Integer)
124
+ raise ".each of #{@expr.class} returned #{r.class}" unless r.is_a?(Integer)
125
125
  if r.zero?
126
126
  @loog.debug("Nothing found by '#{q}' #{tail}")
127
127
  else
@@ -131,7 +131,7 @@ class Factbase::Looged
131
131
  else
132
132
  array = []
133
133
  tail =
134
- Factbase::Looged.elapsed do
134
+ Factbase::Logged.elapsed do
135
135
  @fb.query(@expr).each(params) do |f|
136
136
  array << f
137
137
  end
@@ -149,10 +149,10 @@ class Factbase::Looged
149
149
  r = nil
150
150
  before = @fb.size
151
151
  tail =
152
- Factbase::Looged.elapsed do
152
+ Factbase::Logged.elapsed do
153
153
  r = @fb.query(@expr).delete!
154
154
  end
155
- raise ".delete! of #{@query.class} returned #{r.class}" unless r.is_a?(Integer)
155
+ raise ".delete! of #{@expr.class} returned #{r.class}" unless r.is_a?(Integer)
156
156
  if before.zero?
157
157
  @loog.debug("There were no facts, nothing deleted by '#{@expr}' #{tail}")
158
158
  elsif r.zero?