Class: RDF::LMDB::Repository

Inherits:
Repository
  • Object
show all
Defined in:
lib/rdf/lmdb.rb

Overview

RDF::LMDB::Repository implements a lightweight, transactional, locally-attached data store using Symas LMDB.

Instance Method Summary collapse

Constructor Details

#initialize(dir = nil, uri: nil, title: nil, **options, &block) ⇒ Repository

Returns a new instance of Repository.

Raises:

  • (ArgumentError)


640
641
642
643
644
645
646
647
648
649
650
# File 'lib/rdf/lmdb.rb', line 640

def initialize dir = nil, uri: nil, title: nil, **options, &block
  dir ||= options.delete(:dir) if options[:dir]

  # wtf no idea why this won't inherit
  @tx_class ||= options.delete(:transaction_class) { DEFAULT_TX_CLASS }
  raise ArgumentError, "Invalid transaction class #{@tx_class}" unless
    @tx_class.is_a? Class and @tx_class <= DEFAULT_TX_CLASS

  init_lmdb dir, **options
  super uri: uri, title: title, **options, &block
end

Instance Method Details

#clearObject



666
667
668
669
670
671
672
# File 'lib/rdf/lmdb.rb', line 666

def clear
  @lmdb.transaction do
    @dbs.each_value { |db| db.clear }
  end
  # we do not clear the main database; that nukes the sub-databases
  # @lmdb.database.clear
end

#closeObject



678
679
680
# File 'lib/rdf/lmdb.rb', line 678

def close
  @lmdb.close
end

#countObject



822
823
824
# File 'lib/rdf/lmdb.rb', line 822

def count
  @dbs[:stmt2g].size
end

#delete_insert(deletes, inserts) ⇒ Object

def apply_changeset changeset

@lmdb.transaction do |t|
  delete_insert(changeset.deletes, changeset.inserts)
end

end



836
837
838
839
840
841
# File 'lib/rdf/lmdb.rb', line 836

def delete_insert deletes, inserts
  ret = nil
  @lmdb.transaction { ret = super(deletes, inserts) }
  commit_transaction # this is to satiate the test suite
  ret
end

#delete_statement(statement) ⇒ Object



690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
# File 'lib/rdf/lmdb.rb', line 690

def delete_statement statement
  # note that this does not get called by `delete_statements`,
  # because we want the transaction on the outside.
  complete! statement
  # warn "WTF LOL #{statement.inspect}"
  @lmdb.transaction do |t|
    if statement.variable?
      query(statement).each { |stmt| rm_one stmt }
    else
      rm_one statement
    end
    t.commit
  end
  nil
end

#delete_statements(statements) ⇒ Object



717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
# File 'lib/rdf/lmdb.rb', line 717

def delete_statements statements
  @lmdb.transaction do |t|
    hashes = []

    # we don't know what's in here but it may contain statements
    # with variables, in which case we have to handle them
    enums = [statements]
    # also note that RDF::Util::Coercions#coerce_statements
    # which is called in advance of this is supposed to take
    # care of this situation but doesn't for some reason.
    until enums.empty?
      statements = enums.shift
      statements.each do |statement|
        if statement.variable?
          enums << query(statement)
        else
          hashes += rm_one statement, scan: false
        end
      end
    end

    clean_terms hashes.uniq
    t.commit
  end

  nil
end

#each(&block) ⇒ Object

data retrieval



747
748
749
750
751
# File 'lib/rdf/lmdb.rb', line 747

def each &block
  return enum_for :each unless block_given?

  each_maybe_with_graph(&block)
end

#each_graph(&block) ⇒ Object



780
781
782
783
784
785
786
787
# File 'lib/rdf/lmdb.rb', line 780

def each_graph &block
  return enum_for :each_graph unless block_given?
  @dbs[:g2stmt].cursor do |c|
    while (k, _ = c.next true)
      yield RDF::Graph.new(graph_name: resolve_term(k), data: self)
    end
  end
end

#each_object(&block) ⇒ Object



771
772
773
774
775
776
777
778
# File 'lib/rdf/lmdb.rb', line 771

def each_object &block
  return enum_for :each_object unless block_given?
  @dbs[:o2stmt].cursor do |c|
    while (k, _ = c.next true)
      yield resolve_term k
    end
  end
end

#each_predicate(&block) ⇒ Object



762
763
764
765
766
767
768
769
# File 'lib/rdf/lmdb.rb', line 762

def each_predicate &block
  return enum_for :each_predicate unless block_given?
  @dbs[:p2stmt].cursor do |c|
    while (k, _ = c.next true)
      yield resolve_term k
    end
  end
end

#each_subject(&block) ⇒ Object



753
754
755
756
757
758
759
760
# File 'lib/rdf/lmdb.rb', line 753

def each_subject &block
  return enum_for :each_subject unless block_given?
  @dbs[:s2stmt].cursor do |c|
    while (k, _ = c.next true)
      yield resolve_term k
    end
  end
end

#each_term(&block) ⇒ Object



789
790
791
792
793
794
795
796
797
798
# File 'lib/rdf/lmdb.rb', line 789

def each_term &block
  return enum_for :each_term unless block_given?
  @dbs[:int2term].cursor do |c|
    while (_, v = c.next)
      # yield RDF::NTriples::Reader.unserialize v
      v.force_encoding 'utf-8'
      yield RDF::NTriples::Reader.parse_object(v, intern: true)
    end
  end
end

#empty?Boolean

Returns:

  • (Boolean)


826
827
828
# File 'lib/rdf/lmdb.rb', line 826

def empty?
  count == 0
end

#envObject



843
844
845
# File 'lib/rdf/lmdb.rb', line 843

def env
  @lmdb
end

#has_graph?(graph_name) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


866
867
868
869
870
871
872
# File 'lib/rdf/lmdb.rb', line 866

def has_graph? graph_name
  raise ArgumentError, 'graph_name must be an RDF::Term' unless
    graph_name.is_a? RDF::Term
  int  = int_for(graph_name) or return
  pack = [int].pack ?J
  @dbs[:g2stmt].has? pack
end

#has_object?(object) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


890
891
892
893
894
895
896
# File 'lib/rdf/lmdb.rb', line 890

def has_object? object
  raise ArgumentError, 'object must be an RDF::Term' unless
    object.is_a? RDF::Term
  int  = int_for(object) or return
  pack = [int].pack ?J
  @dbs[:o2stmt].has? pack
end

#has_predicate?(predicate) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


882
883
884
885
886
887
888
# File 'lib/rdf/lmdb.rb', line 882

def has_predicate? predicate
  raise ArgumentError, 'predicate must be an RDF::Term' unless
    predicate.is_a? RDF::Term
  int  = int_for(predicate) or return
  pack = [int].pack ?J
  @dbs[:p2stmt].has? pack
end

#has_quad?(quad) ⇒ Boolean

Returns:

  • (Boolean)


908
909
910
# File 'lib/rdf/lmdb.rb', line 908

def has_quad? quad
  has_statement? check_triple_quad quad, quad: true
end

#has_statement?(statement) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


860
861
862
863
864
# File 'lib/rdf/lmdb.rb', line 860

def has_statement? statement
  raise ArgumentError, 'Argument must be an RDF::Statement' unless
    statement.is_a? RDF::Statement
  !query_pattern(statement.to_h).to_a.empty?
end

#has_subject?(subject) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


874
875
876
877
878
879
880
# File 'lib/rdf/lmdb.rb', line 874

def has_subject? subject
  raise ArgumentError, 'subject must be an RDF::Term' unless
    subject.is_a? RDF::Term
  int  = int_for(subject) or return
  pack = [int].pack ?J
  @dbs[:s2stmt].has? pack
end

#has_term?(term) ⇒ Boolean

Returns:

  • (Boolean)

Raises:

  • (ArgumentError)


898
899
900
901
902
# File 'lib/rdf/lmdb.rb', line 898

def has_term? term
  raise ArgumentError, 'term must be an RDF::Term' unless
    term.is_a? RDF::Term
  @dbs[:hash2term].has? hash_term(term)
end

#has_triple?(triple) ⇒ Boolean

Returns:

  • (Boolean)


904
905
906
# File 'lib/rdf/lmdb.rb', line 904

def has_triple? triple
  has_statement? check_triple_quad triple
end

#insert_statement(statement) ⇒ Object

data manipulation



684
685
686
687
688
# File 'lib/rdf/lmdb.rb', line 684

def insert_statement statement
  complete! statement
  @lmdb.transaction { |t| add_one statement; t.commit }
  nil
end

#insert_statements(statements) ⇒ Object



706
707
708
709
710
711
712
713
714
715
# File 'lib/rdf/lmdb.rb', line 706

def insert_statements statements
  @lmdb.transaction do
    statements.each do |statement|
      complete! statement
      add_one statement
    end
  end

  nil
end

#isolation_levelObject



658
659
660
# File 'lib/rdf/lmdb.rb', line 658

def isolation_level
  :serializable
end

#open(dir, **options) ⇒ Object



674
675
676
# File 'lib/rdf/lmdb.rb', line 674

def open dir, **options
  init_lmdb dir, **options
end

#pathObject



662
663
664
# File 'lib/rdf/lmdb.rb', line 662

def path
  Pathname(@lmdb.path)
end

#project_graph(graph_name, &block) ⇒ Object



800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
# File 'lib/rdf/lmdb.rb', line 800

def project_graph graph_name, &block
  return enum_for :project_graph, graph_name unless block_given?
  body = -> do
    gint  = graph_name ? int_for(graph_name) : 0
    return unless gint
    gpack = [gint].pack ?J
    cache = {}
    @dbs[:statement].each do |spack, spo|
      next unless @dbs[:stmt2g].has? spack, gpack
      spo = resolve_terms spo, cache: cache, write: true

      block.call RDF::Statement(*spo, graph_name: graph_name)
    end
  end

  @lmdb.transaction do
    body.call
  end

  #@lmdb.active_txn ? body.call : @lmdb.transaction(true, &body)
end

#supports?(feature) ⇒ Boolean

housekeeping

Returns:

  • (Boolean)


654
655
656
# File 'lib/rdf/lmdb.rb', line 654

def supports? feature
  !!SUPPORTS[feature.to_s.to_sym]
end

#transaction(mutable: false, &block) ⇒ Object



847
848
849
850
851
852
853
854
855
856
857
858
# File 'lib/rdf/lmdb.rb', line 847

def transaction mutable: false, &block
  return begin_transaction mutable: mutable unless block_given?

  begin
    begin_transaction mutable: mutable, &block
  rescue => error
    rollback_transaction # to sate the test suite
    raise error
  end
  #commit_transaction # to sate the test suite
  self
end