factbase 0.17.0 → 0.17.1

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 8e2593945542e79d93c93e662467bb704ad98d9a481887b5447341c700e4abf8
4
- data.tar.gz: 5e13613617c829b0669235a275a1796c6556ca8cdced3ef9ee3502cbb2c300db
3
+ metadata.gz: 91ef3ed499ea15abb77bc39cfed30eb9af704921e86c3c03c7bdd9b13cb44270
4
+ data.tar.gz: 3c2e80d00620e0de14ec4be35ff08b28393793c69742dda9bda55c4a5ae01c8f
5
5
  SHA512:
6
- metadata.gz: 22d7965bd3b3f60070ca8293e3c054ea5b2553913ccb091328f3d51f2aab3a42c3be56b5197536014c550eecceb708186a826cb1fe67b6e31deb636819ceb866
7
- data.tar.gz: 5e5fef55d3e316d19d5d96c2de10b23d1788541c09a2331c8762cd73c1c4b15b468c7cb4c0ff4b4f33f3b296f0a875673568f7a1eca92744fbf54c2e0c042233
6
+ metadata.gz: 9c6e18a32a5ae773e78672e449cce031a2c7641b1291b9f637ccb28afb6afddc87091955ce06e75c0e35326f4db37b04fac5b827b1cdc203a8b0262c105ca2c3
7
+ data.tar.gz: 923207d8494313e1af4fae0ecf3068372a5dde28924840edbe1b6d625127afb7e4eb2cf44c9f86a28d9d7fc650336abce9c9b99cd492b3ff29bcbb4cf214c83e
data/Gemfile CHANGED
@@ -12,12 +12,13 @@ gem 'minitest-reporters', '~>1.7', require: false
12
12
  gem 'os', '~>1.1', require: false
13
13
  gem 'qbash', '~>0.4', require: false
14
14
  gem 'rake', '~>13.2', require: false
15
- gem 'rdoc', '6.15.1', require: false # GPL
15
+ gem 'rdoc', '6.16.1', require: false # GPL
16
16
  gem 'rubocop', '~>1.74', require: false
17
17
  gem 'rubocop-minitest', '~>0.38', require: false
18
18
  gem 'rubocop-performance', '~>1.25', require: false
19
19
  gem 'rubocop-rake', '~>0.7', require: false
20
20
  gem 'simplecov', '~>0.22', require: false
21
21
  gem 'simplecov-cobertura', '~>3.0', require: false
22
+ gem 'stackprof', '~>0.2', require: false, platforms: [:ruby]
22
23
  gem 'threads', '~>0.4', require: false
23
24
  gem 'yard', '~>0.9', require: false
data/Gemfile.lock CHANGED
@@ -30,7 +30,7 @@ GEM
30
30
  tago (~> 0.1)
31
31
  ellipsized (0.3.0)
32
32
  erb (6.0.0)
33
- json (2.16.0)
33
+ json (2.17.1)
34
34
  language_server-protocol (3.17.0.5)
35
35
  lint_roller (1.1.0)
36
36
  logger (1.7.0)
@@ -68,7 +68,7 @@ GEM
68
68
  racc (1.8.1)
69
69
  rainbow (3.1.1)
70
70
  rake (13.3.1)
71
- rdoc (6.15.1)
71
+ rdoc (6.16.1)
72
72
  erb
73
73
  psych (>= 4.0.0)
74
74
  tsort
@@ -109,7 +109,8 @@ GEM
109
109
  simplecov (~> 0.19)
110
110
  simplecov-html (0.13.2)
111
111
  simplecov_json_formatter (0.1.4)
112
- stringio (3.1.8)
112
+ stackprof (0.2.27)
113
+ stringio (3.1.9)
113
114
  tago (0.4.0)
114
115
  threads (0.5.0)
115
116
  backtrace (~> 0)
@@ -119,7 +120,7 @@ GEM
119
120
  unicode-emoji (~> 4.1)
120
121
  unicode-emoji (4.1.0)
121
122
  yaml (0.4.0)
122
- yard (0.9.37)
123
+ yard (0.9.38)
123
124
 
124
125
  PLATFORMS
125
126
  arm64-darwin-22
@@ -139,13 +140,14 @@ DEPENDENCIES
139
140
  os (~> 1.1)
140
141
  qbash (~> 0.4)
141
142
  rake (~> 13.2)
142
- rdoc (= 6.15.1)
143
+ rdoc (= 6.16.1)
143
144
  rubocop (~> 1.74)
144
145
  rubocop-minitest (~> 0.38)
145
146
  rubocop-performance (~> 1.25)
146
147
  rubocop-rake (~> 0.7)
147
148
  simplecov (~> 0.22)
148
149
  simplecov-cobertura (~> 3.0)
150
+ stackprof (~> 0.2)
149
151
  threads (~> 0.4)
150
152
  yard (~> 0.9)
151
153
 
data/Rakefile CHANGED
@@ -78,3 +78,19 @@ task :benchmark, [:name] do |_t, args|
78
78
  end
79
79
  end
80
80
  end
81
+
82
+ # Run profiling on a benchmark and generate a flamegraph.
83
+ # To run this task, you need to have stackprof installed.
84
+ # https://github.com/tmm1/stackprof
85
+ # To run profiling for a specific benchmark you can run:
86
+ # bundle exec rake flamegraph\[bench_slow_query\]
87
+ desc 'Profile a benchmark (e.g., flamegraph[bench_slow_query])'
88
+ task :flamegraph, [:name] do |_t, args|
89
+ require 'stackprof'
90
+ bname = args[:name] || 'all'
91
+ puts "Starting profiling for '#{bname}'..."
92
+ StackProf.run(mode: :cpu, out: 'stackprof-cpu-myapp.dump', raw: true) do
93
+ Rake::Task['benchmark'].invoke(bname)
94
+ end
95
+ `stackprof --d3-flamegraph stackprof-cpu-myapp.dump > flamegraph.html`
96
+ end
@@ -57,9 +57,12 @@ class Factbase::IndexedFactbase
57
57
  # Run an ACID transaction.
58
58
  # @return [Factbase::Churn] How many facts have been changed (zero if rolled back)
59
59
  def txn
60
- @origin.txn do |fbt|
61
- yield Factbase::IndexedFactbase.new(fbt, @idx)
62
- end
60
+ result =
61
+ @origin.txn do |fbt|
62
+ yield Factbase::IndexedFactbase.new(fbt, @idx)
63
+ end
64
+ @idx.clear
65
+ result
63
66
  end
64
67
 
65
68
  # Export it into a chain of bytes, including both data and index.
data/lib/factbase/term.rb CHANGED
@@ -52,6 +52,12 @@ require_relative 'terms/when'
52
52
  require_relative 'terms/either'
53
53
  require_relative 'terms/count'
54
54
  require_relative 'terms/first'
55
+ require_relative 'terms/nth'
56
+ require_relative 'terms/sum'
57
+ require_relative 'terms/agg'
58
+ require_relative 'terms/empty'
59
+ require_relative 'terms/min'
60
+ require_relative 'terms/max'
55
61
 
56
62
  # Term.
57
63
  #
@@ -89,12 +95,6 @@ class Factbase::Term
89
95
  # @return [Array] The operands
90
96
  attr_reader :operands
91
97
 
92
- require_relative 'terms/logical'
93
- include Factbase::Logical
94
-
95
- require_relative 'terms/aggregates'
96
- include Factbase::Aggregates
97
-
98
98
  require_relative 'terms/shared'
99
99
  include Factbase::TermShared
100
100
 
@@ -149,7 +149,13 @@ class Factbase::Term
149
149
  when: Factbase::When.new(operands),
150
150
  either: Factbase::Either.new(operands),
151
151
  count: Factbase::Count.new(operands),
152
- first: Factbase::First.new(operands)
152
+ first: Factbase::First.new(operands),
153
+ nth: Factbase::Nth.new(operands),
154
+ sum: Factbase::Sum.new(operands),
155
+ agg: Factbase::Agg.new(operands),
156
+ empty: Factbase::Empty.new(operands),
157
+ min: Factbase::Min.new(operands),
158
+ max: Factbase::Max.new(operands)
153
159
  }
154
160
  end
155
161
 
@@ -211,11 +217,15 @@ class Factbase::Term
211
217
  # Simplify it if possible.
212
218
  # @return [Factbase::Term] New term or itself
213
219
  def simplify
214
- m = "#{@op}_simplify"
215
- if respond_to?(m, true)
216
- send(m)
220
+ if @terms.key?(@op) && @terms[@op].respond_to?(:simplify)
221
+ @terms[@op].simplify
217
222
  else
218
- self
223
+ m = "#{@op}_simplify"
224
+ if respond_to?(m, true)
225
+ send(m)
226
+ else
227
+ self
228
+ end
219
229
  end
220
230
  end
221
231
 
@@ -0,0 +1,35 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require_relative 'base'
7
+ # The term 'agg' that aggregates.
8
+ class Factbase::Agg < Factbase::TermBase
9
+ # Constructor.
10
+ # @param [Array] operands Operands
11
+ def initialize(operands = [])
12
+ super()
13
+ @operands = operands
14
+ @op = :agg
15
+ end
16
+
17
+ # Evaluate term on a fact.
18
+ # @param [Factbase::Fact] fact The fact
19
+ # @param [Array<Factbase::Fact>] maps All maps available
20
+ # @param [Factbase] fb Factbase to use for sub-queries
21
+ # @return [Object] The result of evaluation
22
+ def evaluate(fact, maps, fb)
23
+ assert_args(2)
24
+ selector = @operands[0]
25
+ unless selector.is_a?(Factbase::Term) || selector.is_a?(Factbase::TermBase)
26
+ raise "A term is expected, but '#{selector}' provided"
27
+ end
28
+ term = @operands[1]
29
+ unless term.is_a?(Factbase::Term) || selector.is_a?(Factbase::TermBase)
30
+ raise "A term is expected, but '#{term}' provided"
31
+ end
32
+ subset = fb.query(selector, maps).each(fb, fact).to_a
33
+ term.evaluate(nil, subset, fb)
34
+ end
35
+ end
@@ -5,6 +5,7 @@
5
5
 
6
6
  require_relative 'base'
7
7
  require_relative 'boolean'
8
+ require_relative 'simplified'
8
9
  # The 'and' term that represents a logical AND operation between multiple operands.
9
10
  class Factbase::And < Factbase::TermBase
10
11
  # Constructor.
@@ -25,4 +26,10 @@ class Factbase::And < Factbase::TermBase
25
26
  end
26
27
  true
27
28
  end
29
+
30
+ def simplify
31
+ unique = Factbase::Simplified.new(@operands).unique
32
+ return unique[0] if unique.size == 1
33
+ Factbase::Term.new(@op, unique)
34
+ end
28
35
  end
@@ -0,0 +1,25 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ # The 'best' term evaluates the best value for a given key.
7
+ class Factbase::Best
8
+ def initialize(&block)
9
+ @criteria = block
10
+ end
11
+
12
+ def evaluate(key, maps)
13
+ raise "A symbol is expected, but #{key} provided" unless key.is_a?(Symbol)
14
+ best = nil
15
+ maps.each do |m|
16
+ vv = m[key.to_s]
17
+ next if vv.nil?
18
+ vv = [vv] unless vv.respond_to?(:to_a)
19
+ vv.each do |v|
20
+ best = v if best.nil? || @criteria.call(v, best)
21
+ end
22
+ end
23
+ best
24
+ end
25
+ end
@@ -0,0 +1,36 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require_relative 'base'
7
+
8
+ # The 'empty' term checks for emptiness in the results of a query evaluation.
9
+ class Factbase::Empty < Factbase::TermBase
10
+ # Constructor.
11
+ # @param [Array] operands Operands
12
+ def initialize(operands)
13
+ super()
14
+ @operands = operands
15
+ @op = :empty
16
+ end
17
+
18
+ # Evaluate term on a fact.
19
+ # @param [Factbase::Fact] fact The fact
20
+ # @param [Array<Factbase::Fact>] maps All maps available
21
+ # @param [Factbase] fb Factbase to use for sub-queries
22
+ # @return [Boolean] The result of the emptiness check
23
+ def evaluate(fact, maps, fb)
24
+ assert_args(1)
25
+ term = @operands[0]
26
+ unless term.is_a?(Factbase::Term) || term.is_a?(Factbase::TermBase)
27
+ raise "A term is expected, but '#{term}' provided"
28
+ end
29
+ # rubocop:disable Lint/UnreachableLoop
30
+ fb.query(term, maps).each(fb, fact) do
31
+ return false
32
+ end
33
+ # rubocop:enable Lint/UnreachableLoop
34
+ true
35
+ end
36
+ end
@@ -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
+ require_relative 'best'
8
+ require_relative 'base'
9
+
10
+ # The 'max' term.
11
+ # This term calculates the max value among the evaluated operands.
12
+ class Factbase::Max < Factbase::TermBase
13
+ MAX = Factbase::Best.new { |v, b| v > b }
14
+
15
+ # Constructor.
16
+ # @param [Array] operands Operands
17
+ def initialize(operands)
18
+ super()
19
+ @operands = operands
20
+ @op = :max
21
+ end
22
+
23
+ # Evaluate term on a fact.
24
+ # @param [Factbase::Fact] _fact The fact
25
+ # @param [Array<Factbase::Fact>] maps All maps available
26
+ # @param [Factbase] _fb Factbase to use for sub-queries
27
+ # @return [Object] The max value among the evaluated operands
28
+ def evaluate(_fact, maps, _fb)
29
+ assert_args(1)
30
+ MAX.evaluate(@operands[0], maps)
31
+ end
32
+ end
@@ -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
+ require_relative 'best'
8
+ require_relative 'base'
9
+
10
+ # The 'min' term.
11
+ # This term calculates the minimum value among the evaluated operands.
12
+ class Factbase::Min < Factbase::TermBase
13
+ MIN = Factbase::Best.new { |v, b| v < b }
14
+
15
+ # Constructor.
16
+ # @param [Array] operands Operands
17
+ def initialize(operands)
18
+ super()
19
+ @operands = operands
20
+ @op = :min
21
+ end
22
+
23
+ # Evaluate term on a fact.
24
+ # @param [Factbase::Fact] _fact The fact
25
+ # @param [Array<Factbase::Fact>] maps All maps available
26
+ # @param [Factbase] _fb Factbase to use for sub-queries
27
+ # @return [Object] The minimum value among the evaluated operands
28
+ def evaluate(_fact, maps, _fb)
29
+ assert_args(1)
30
+ MIN.evaluate(@operands[0], maps)
31
+ end
32
+ 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 'base'
7
+ # Represents an 'nth' term in the Factbase.
8
+ # Retrieves the value of a specified key from the nth map.
9
+ class Factbase::Nth < Factbase::TermBase
10
+ # Constructor.
11
+ # @param [Array] operands Operands
12
+ def initialize(operands)
13
+ super()
14
+ @operands = operands
15
+ @op = :nth
16
+ end
17
+
18
+ # Evaluate term on a fact.
19
+ # @param [Factbase::Fact] _fact The fact
20
+ # @param [Array<Factbase::Fact>] maps All maps available
21
+ # @param [Factbase] _fb Factbase to use for sub-queries
22
+ # @return [Object] The value of the specified key from the nth map
23
+ def evaluate(_fact, maps, _fb)
24
+ assert_args(2)
25
+ pos = @operands[0]
26
+ raise "An integer is expected, but #{pos} provided" unless pos.is_a?(Integer)
27
+ k = @operands[1]
28
+ raise "A symbol is expected, but #{k} provided" unless k.is_a?(Symbol)
29
+ m = maps[pos]
30
+ return nil if m.nil?
31
+ m[k.to_s]
32
+ end
33
+ end
@@ -5,6 +5,7 @@
5
5
 
6
6
  require_relative 'base'
7
7
  require_relative 'boolean'
8
+ require_relative 'simplified'
8
9
  # The 'or' term that represents a logical OR operation between multiple operands.
9
10
  class Factbase::Or < Factbase::TermBase
10
11
  # Constructor.
@@ -25,4 +26,10 @@ class Factbase::Or < Factbase::TermBase
25
26
  end
26
27
  false
27
28
  end
29
+
30
+ def simplify
31
+ unique = Factbase::Simplified.new(@operands).unique
32
+ return unique[0] if unique.size == 1
33
+ Factbase::Term.new(@op, unique)
34
+ end
28
35
  end
@@ -0,0 +1,31 @@
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
+ # Simplified operands.
9
+ #
10
+ # Author:: Yegor Bugayenko (yegor256@gmail.com)
11
+ # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
12
+ # License:: MIT
13
+ class Factbase::Simplified
14
+ def initialize(operands)
15
+ @operands = operands
16
+ end
17
+
18
+ # Removes duplicate operands
19
+ def unique
20
+ strs = []
21
+ ops = []
22
+ @operands.each do |o|
23
+ o = o.simplify
24
+ s = o.to_s
25
+ next if strs.include?(s)
26
+ strs << s
27
+ ops << o
28
+ end
29
+ ops
30
+ end
31
+ end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ # SPDX-FileCopyrightText: Copyright (c) 2024-2025 Yegor Bugayenko
4
+ # SPDX-License-Identifier: MIT
5
+
6
+ require_relative 'base'
7
+
8
+ # This class represents a specialized 'sum' term.
9
+ # This term calculates the sum of values for a specified key.
10
+ class Factbase::Sum < Factbase::TermBase
11
+ # Constructor.
12
+ # @param [Array] operands Operands
13
+ def initialize(operands)
14
+ super()
15
+ @operands = operands
16
+ @op = :sum
17
+ end
18
+
19
+ # Evaluate term on a fact.
20
+ # @param [Factbase::Fact] _fact The fact
21
+ # @param [Array<Factbase::Fact>] maps All maps available
22
+ # @param [Factbase] _fb Factbase to use for sub-queries
23
+ # @return [Integer] The sum of values for the specified key across all maps
24
+ def evaluate(_fact, maps, _fb)
25
+ k = @operands[0]
26
+ raise "A symbol is expected, but '#{k}' provided" unless k.is_a?(Symbol)
27
+ sum = 0
28
+ maps.each do |m|
29
+ vv = m[k.to_s]
30
+ next if vv.nil?
31
+ vv = [vv] unless vv.respond_to?(:to_a)
32
+ vv.each do |v|
33
+ sum += v
34
+ end
35
+ end
36
+ sum
37
+ end
38
+ end
@@ -9,5 +9,5 @@
9
9
  # License:: MIT
10
10
  class Factbase
11
11
  # Current version of the gem (changed by .rultor.yml on every release)
12
- VERSION = '0.17.0' unless const_defined?(:VERSION)
12
+ VERSION = '0.17.1' unless const_defined?(:VERSION)
13
13
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: factbase
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.17.0
4
+ version: 0.17.1
5
5
  platform: ruby
6
6
  authors:
7
7
  - Yegor Bugayenko
@@ -208,13 +208,14 @@ files:
208
208
  - lib/factbase/tee.rb
209
209
  - lib/factbase/term.rb
210
210
  - lib/factbase/terms/absent.rb
211
- - lib/factbase/terms/aggregates.rb
211
+ - lib/factbase/terms/agg.rb
212
212
  - lib/factbase/terms/always.rb
213
213
  - lib/factbase/terms/and.rb
214
214
  - lib/factbase/terms/arithmetic.rb
215
215
  - lib/factbase/terms/as.rb
216
216
  - lib/factbase/terms/assert.rb
217
217
  - lib/factbase/terms/base.rb
218
+ - lib/factbase/terms/best.rb
218
219
  - lib/factbase/terms/boolean.rb
219
220
  - lib/factbase/terms/compare.rb
220
221
  - lib/factbase/terms/concat.rb
@@ -222,6 +223,7 @@ files:
222
223
  - lib/factbase/terms/defn.rb
223
224
  - lib/factbase/terms/div.rb
224
225
  - lib/factbase/terms/either.rb
226
+ - lib/factbase/terms/empty.rb
225
227
  - lib/factbase/terms/env.rb
226
228
  - lib/factbase/terms/eq.rb
227
229
  - lib/factbase/terms/exists.rb
@@ -231,23 +233,27 @@ files:
231
233
  - lib/factbase/terms/head.rb
232
234
  - lib/factbase/terms/inverted.rb
233
235
  - lib/factbase/terms/join.rb
234
- - lib/factbase/terms/logical.rb
235
236
  - lib/factbase/terms/lt.rb
236
237
  - lib/factbase/terms/lte.rb
237
238
  - lib/factbase/terms/many.rb
238
239
  - lib/factbase/terms/matches.rb
240
+ - lib/factbase/terms/max.rb
241
+ - lib/factbase/terms/min.rb
239
242
  - lib/factbase/terms/minus.rb
240
243
  - lib/factbase/terms/never.rb
241
244
  - lib/factbase/terms/nil.rb
242
245
  - lib/factbase/terms/not.rb
246
+ - lib/factbase/terms/nth.rb
243
247
  - lib/factbase/terms/one.rb
244
248
  - lib/factbase/terms/or.rb
245
249
  - lib/factbase/terms/plus.rb
246
250
  - lib/factbase/terms/prev.rb
247
251
  - lib/factbase/terms/shared.rb
252
+ - lib/factbase/terms/simplified.rb
248
253
  - lib/factbase/terms/size.rb
249
254
  - lib/factbase/terms/sorted.rb
250
255
  - lib/factbase/terms/sprintf.rb
256
+ - lib/factbase/terms/sum.rb
251
257
  - lib/factbase/terms/times.rb
252
258
  - lib/factbase/terms/to_float.rb
253
259
  - lib/factbase/terms/to_integer.rb
@@ -1,86 +0,0 @@
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
- # Aggregating terms.
9
- #
10
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
11
- # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
12
- # License:: MIT
13
- module Factbase::Aggregates
14
- def min(_fact, maps, _fb)
15
- assert_args(1)
16
- _best(maps) { |v, b| v < b }
17
- end
18
-
19
- def max(_fact, maps, _fb)
20
- assert_args(1)
21
- _best(maps) { |v, b| v > b }
22
- end
23
-
24
- def nth(_fact, maps, _fb)
25
- assert_args(2)
26
- pos = @operands[0]
27
- raise "An integer is expected, but #{pos} provided" unless pos.is_a?(Integer)
28
- k = @operands[1]
29
- raise "A symbol is expected, but #{k} provided" unless k.is_a?(Symbol)
30
- m = maps[pos]
31
- return nil if m.nil?
32
- m[k.to_s]
33
- end
34
-
35
- def sum(_fact, maps, _fb)
36
- k = @operands[0]
37
- raise "A symbol is expected, but '#{k}' provided" unless k.is_a?(Symbol)
38
- sum = 0
39
- maps.each do |m|
40
- vv = m[k.to_s]
41
- next if vv.nil?
42
- vv = [vv] unless vv.respond_to?(:to_a)
43
- vv.each do |v|
44
- sum += v
45
- end
46
- end
47
- sum
48
- end
49
-
50
- def agg(fact, maps, fb)
51
- assert_args(2)
52
- selector = @operands[0]
53
- raise "A term is expected, but '#{selector}' provided" unless selector.is_a?(Factbase::Term)
54
- term = @operands[1]
55
- raise "A term is expected, but '#{term}' provided" unless term.is_a?(Factbase::Term)
56
- subset = fb.query(selector, maps).each(fb, fact).to_a
57
- term.evaluate(nil, subset, fb)
58
- end
59
-
60
- def empty(fact, maps, fb)
61
- assert_args(1)
62
- term = @operands[0]
63
- raise "A term is expected, but '#{term}' provided" unless term.is_a?(Factbase::Term)
64
- # rubocop:disable Lint/UnreachableLoop
65
- fb.query(term, maps).each(fb, fact) do
66
- return false
67
- end
68
- # rubocop:enable Lint/UnreachableLoop
69
- true
70
- end
71
-
72
- def _best(maps)
73
- k = @operands[0]
74
- raise "A symbol is expected, but #{k} provided" unless k.is_a?(Symbol)
75
- best = nil
76
- maps.each do |m|
77
- vv = m[k.to_s]
78
- next if vv.nil?
79
- vv = [vv] unless vv.respond_to?(:to_a)
80
- vv.each do |v|
81
- best = v if best.nil? || yield(v, best)
82
- end
83
- end
84
- best
85
- end
86
- end
@@ -1,41 +0,0 @@
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
- # Logical terms.
9
- #
10
- # Author:: Yegor Bugayenko (yegor256@gmail.com)
11
- # Copyright:: Copyright (c) 2024-2025 Yegor Bugayenko
12
- # License:: MIT
13
- module Factbase::Logical
14
- # Simplifies AND or OR expressions by removing duplicates
15
- # @return [Factbase::Term] Simplified term
16
- def and_or_simplify
17
- strs = []
18
- ops = []
19
- @operands.each do |o|
20
- o = o.simplify
21
- s = o.to_s
22
- next if strs.include?(s)
23
- strs << s
24
- ops << o
25
- end
26
- return ops[0] if ops.size == 1
27
- self.class.new(@op, ops)
28
- end
29
-
30
- # Simplifies AND expressions by removing duplicates
31
- # @return [Factbase::Term] Simplified term
32
- def and_simplify
33
- and_or_simplify
34
- end
35
-
36
- # Simplifies OR expressions by removing duplicates
37
- # @return [Factbase::Term] Simplified term
38
- def or_simplify
39
- and_or_simplify
40
- end
41
- end