Class: Factbase::IndexedFactbase

Inherits:
Object
  • Object
show all
Defined in:
lib/factbase/indexed/indexed_factbase.rb

Overview

A factbase with an index.

Author

Yegor Bugayenko ([email protected])

Copyright

Copyright © 2024-2026 Yegor Bugayenko

License

MIT

Instance Method Summary collapse

Constructor Details

#initialize(origin, idx = {}, fresh = Set.new) ⇒ IndexedFactbase

Constructor.

Parameters:

  • origin (Factbase)

    Original factbase to decorate

  • idx (Hash) (defaults to: {})

    Index to use

  • fresh (Set) (defaults to: Set.new)

    The set of IDs of newly inserted facts



25
26
27
28
29
30
31
# File 'lib/factbase/indexed/indexed_factbase.rb', line 25

def initialize(origin, idx = {}, fresh = Set.new)
  raise 'Wrong type of original' unless origin.respond_to?(:query)
  @origin = origin
  raise 'Wrong type of index' unless idx.is_a?(Hash)
  @idx = idx
  @fresh = fresh
end

Instance Method Details

#exportString

Export it into a chain of bytes, including both data and index.

Here is how you can export it to a file, for example:

fb = Factbase::IndexedFactbase.new(Factbase.new)
fb.insert.foo = 42
File.binwrite("foo.fb", fb.export)

The data is binary, it’s not a text!

Returns:

  • (String)

    Binary string containing serialized data and index



84
85
86
# File 'lib/factbase/indexed/indexed_factbase.rb', line 84

def export
  Marshal.dump({ maps: @origin.export, idx: @idx })
end

#import(bytes) ⇒ Object

Import from a chain of bytes, including both data and index.

Here is how you can read it from a file, for example:

fb = Factbase::IndexedFactbase.new(Factbase.new)
fb.import(File.binread("foo.fb"))

The facts that existed in the factbase before importing will remain there. The facts from the incoming byte stream will be added to them. If the byte stream doesn’t contain an index (for backward compatibility), the index will be empty and will be built on first use.

Parameters:

  • bytes (String)

    Binary string to import



101
102
103
104
105
106
107
108
109
110
111
112
# File 'lib/factbase/indexed/indexed_factbase.rb', line 101

def import(bytes)
  raise 'Empty input, cannot load a factbase' if bytes.empty?
  data = Marshal.load(bytes)
  if data.is_a?(Hash) && data.key?(:maps)
    @origin.import(data[:maps])
    @idx.merge!(data[:idx]) if data[:idx].is_a?(Hash)
  else
    @origin.import(bytes)
    @idx.clear
  end
  @fresh.clear
end

#insertFactbase::Fact

Insert a new fact and return it.

Returns:



35
36
37
38
39
# File 'lib/factbase/indexed/indexed_factbase.rb', line 35

def insert
  f = Factbase::IndexedFact.new(@origin.insert, @idx, @fresh)
  @fresh.add(f.object_id)
  f
end

#query(term, maps = nil) ⇒ Object

Create a query capable of iterating.

Parameters:

  • term (String)

    The term to use

  • maps (Array<Hash>) (defaults to: nil)

    Possible maps to use



53
54
55
56
57
58
59
# File 'lib/factbase/indexed/indexed_factbase.rb', line 53

def query(term, maps = nil)
  term = to_term(term) if term.is_a?(String)
  q = @origin.query(term, maps)
  q = Factbase::IndexedQuery.new(q, @idx, self, @fresh)
  @fresh.clear
  q
end

#sizeInteger

Size, the total number of facts in the factbase.

Returns:

  • (Integer)

    How many facts are in there



116
117
118
# File 'lib/factbase/indexed/indexed_factbase.rb', line 116

def size
  @origin.size
end

#to_term(query) ⇒ Factbase::Term

Convert a query to a term.

Parameters:

  • query (String)

    The query to convert

Returns:



44
45
46
47
48
# File 'lib/factbase/indexed/indexed_factbase.rb', line 44

def to_term(query)
  t = @origin.to_term(query)
  t.redress!(Factbase::IndexedTerm, idx: @idx)
  t
end

#txnFactbase::Churn

Run an ACID transaction.

Returns:

  • (Factbase::Churn)

    How many facts have been changed (zero if rolled back)



63
64
65
66
67
68
69
70
71
# File 'lib/factbase/indexed/indexed_factbase.rb', line 63

def txn
  result =
    @origin.txn do |fbt|
      yield Factbase::IndexedFactbase.new(fbt, @idx, @fresh)
    end
  @idx.clear
  @fresh.clear
  result
end