neo4j_bolt 0.1.6 → 0.1.7

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: e754e8e69d3794520280d568a879834a6ceb91bad419385fb68318959f8168c2
4
- data.tar.gz: 48ac0bab0ae453aa6d41ce6832271db2798b99f49baaa0307c0795a7d932264d
3
+ metadata.gz: 86471d4b049b4054a378f5084ae13dda181bd818a205ee4a67e6aa4bc5d0607f
4
+ data.tar.gz: b1e855e4689946026eaa7971acb730577a57973b02605c893916d15e2438b1f3
5
5
  SHA512:
6
- metadata.gz: dfabf88d8ec3a58298c87ab3a1662bcf43abe83a5bc6d2d948992389704a34c70f2fb5f21877adf7d2e826f39e1da5936764369de3ee1942e4466e6d54ea1acc
7
- data.tar.gz: f21d0f51b0a90083a79d5df951b76d8acf5c3bd55386fa3a10039f0ae107115927eea9bbe56ee3d0763b9e42e04f86181b4806f43d8f72f392b82f3538c01e29
6
+ metadata.gz: e4e414cb24861f58ae67f2a5c92da46f720c861fd49131befa16a9c046ea557d1e31fb40130fe892aa91b38d0ec3de881d4da94de4fde4a5288ab0add379c33f
7
+ data.tar.gz: be8ed37b6ea0a7e358c25257eea3be90f78c2fd1342a4666bc244a5a379e241780a6df01d4005c4b26a4986a2fd24cd0a65f7569f4de19bcbf4a65517a33aa8a
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- neo4j_bolt (0.1.5)
4
+ neo4j_bolt (0.1.6)
5
5
 
6
6
  GEM
7
7
  remote: https://rubygems.org/
data/README.md CHANGED
@@ -1,6 +1,6 @@
1
1
  # Neo4jBolt
2
2
 
3
- A Neo4j/Bolt driver written in pure Ruby. Currently only supporting Neo4j 4.4.
3
+ A Neo4j/Bolt driver written in pure Ruby. Currently only supporting Neo4j 4.4. Caution: This gem is not feature complete, and also the documention is not complete yet.
4
4
 
5
5
  ## Installation
6
6
 
@@ -1,3 +1,3 @@
1
1
  module Neo4jBolt
2
- VERSION = "0.1.6"
2
+ VERSION = "0.1.7"
3
3
  end
data/lib/neo4j_bolt.rb CHANGED
@@ -11,6 +11,7 @@ module Neo4jBolt
11
11
  self.bolt_port = 7687
12
12
 
13
13
  NEO4J_DEBUG = 0
14
+ CONSTRAINT_INDEX_PREFIX = 'neo4j_bolt_'
14
15
 
15
16
  module ServerState
16
17
  DISCONNECTED = 0
@@ -830,6 +831,50 @@ module Neo4jBolt
830
831
  end
831
832
  rows.first
832
833
  end
834
+
835
+ def setup_constraints_and_indexes(constraints, indexes)
836
+ wanted_constraints = Set.new()
837
+ wanted_indexes = Set.new()
838
+ # STDERR.puts "Setting up constraints and indexes..."
839
+ constraints.each do |constraint|
840
+ unless constraint =~ /\w+\/\w+/
841
+ raise "Unexpected constraint format: #{constraint}"
842
+ end
843
+ constraint_name = "#{CONSTRAINT_INDEX_PREFIX}#{constraint.gsub('/', '_')}"
844
+ wanted_constraints << constraint_name
845
+ label = constraint.split('/').first
846
+ property = constraint.split('/').last
847
+ query = "CREATE CONSTRAINT #{constraint_name} IF NOT EXISTS FOR (n:#{label}) REQUIRE n.#{property} IS UNIQUE"
848
+ # STDERR.puts query
849
+ neo4j_query(query)
850
+ end
851
+ indexes.each do |index|
852
+ unless index =~ /\w+\/\w+/
853
+ raise "Unexpected index format: #{index}"
854
+ end
855
+ index_name = "#{CONSTRAINT_INDEX_PREFIX}#{index.gsub('/', '_')}"
856
+ wanted_indexes << index_name
857
+ label = index.split('/').first
858
+ property = index.split('/').last
859
+ query = "CREATE INDEX #{index_name} IF NOT EXISTS FOR (n:#{label}) ON (n.#{property})"
860
+ # STDERR.puts query
861
+ neo4j_query(query)
862
+ end
863
+ neo4j_query("SHOW ALL CONSTRAINTS").each do |row|
864
+ next unless row['name'].index(CONSTRAINT_INDEX_PREFIX) == 0
865
+ next if wanted_constraints.include?(row['name'])
866
+ query = "DROP CONSTRAINT #{row['name']}"
867
+ # STDERR.puts query
868
+ neo4j_query(query)
869
+ end
870
+ neo4j_query("SHOW ALL INDEXES").each do |row|
871
+ next unless row['name'].index(CONSTRAINT_INDEX_PREFIX) == 0
872
+ next if wanted_indexes.include?(row['name']) || wanted_constraints.include?(row['name'])
873
+ query = "DROP INDEX #{row['name']}"
874
+ # STDERR.puts query
875
+ neo4j_query(query)
876
+ end
877
+ end
833
878
  end
834
879
 
835
880
  def transaction(&block)
@@ -864,7 +909,7 @@ module Neo4jBolt
864
909
  end
865
910
  end
866
911
 
867
- def dump_database(&block)
912
+ def dump_database(io)
868
913
  tr_id = {}
869
914
  id = 0
870
915
  neo4j_query("MATCH (n) RETURN n ORDER BY ID(n);") do |row|
@@ -874,7 +919,7 @@ module Neo4jBolt
874
919
  :labels => row['n'].labels,
875
920
  :properties => row['n']
876
921
  }
877
- yield "n #{node.to_json}"
922
+ io.puts "n #{node.to_json}"
878
923
  id += 1
879
924
  end
880
925
  neo4j_query("MATCH ()-[r]->() RETURN r;") do |row|
@@ -884,14 +929,99 @@ module Neo4jBolt
884
929
  :type => row['r'].type,
885
930
  :properties => row['r']
886
931
  }
887
- yield "r #{rel.to_json}"
932
+ io.puts "r #{rel.to_json}"
888
933
  end
889
934
  end
890
935
 
936
+ def load_database_dump(io, force_append: false)
937
+ unless force_append
938
+ transaction do
939
+ node_count = neo4j_query_expect_one('MATCH (n) RETURN COUNT(n) as count;')['count']
940
+ unless node_count == 0
941
+ raise "Error: There are nodes in this database, exiting now."
942
+ end
943
+ end
944
+ end
945
+ n_count = 0
946
+ r_count = 0
947
+ node_tr = {}
948
+ node_batch_by_label = {}
949
+ relationship_batch_by_type = {}
950
+ io.each_line do |line|
951
+ line.strip!
952
+ next if line.empty?
953
+ if line[0] == 'n'
954
+ line = line[2, line.size - 2]
955
+ node = JSON.parse(line)
956
+ label_key = node['labels'].sort.join('/')
957
+ node_batch_by_label[label_key] ||= []
958
+ node_batch_by_label[label_key] << node
959
+ elsif line[0] == 'r'
960
+ line = line[2, line.size - 2]
961
+ relationship = JSON.parse(line)
962
+ relationship_batch_by_type[relationship['type']] ||= []
963
+ relationship_batch_by_type[relationship['type']] << relationship
964
+ else
965
+ STDERR.puts "Invalid entry: #{line}"
966
+ exit(1)
967
+ end
968
+ end
969
+ node_batch_by_label.each_pair do |label_key, batch|
970
+ while !batch.empty? do
971
+ slice = []
972
+ json_size = 0
973
+ while (!batch.empty?) && json_size < 0x20000 && slice.size < 256
974
+ x = batch.shift
975
+ slice << x
976
+ json_size += x.to_json.size
977
+ end
978
+ ids = neo4j_query(<<~END_OF_QUERY, {:properties => slice.map { |x| x['properties']}})
979
+ UNWIND $properties AS props
980
+ CREATE (n:#{slice.first['labels'].join(':')})
981
+ SET n = props
982
+ RETURN ID(n) AS id;
983
+ END_OF_QUERY
984
+ slice.each.with_index do |node, i|
985
+ node_tr[node['id']] = ids[i]['id']
986
+ end
987
+ n_count += slice.size
988
+ STDERR.print "\rLoaded #{n_count} nodes, #{r_count} relationships..."
989
+ end
990
+ end
991
+ relationship_batch_by_type.each_pair do |rel_type, batch|
992
+ batch.each_slice(256) do |slice|
993
+ slice.map! do |rel|
994
+ rel['from'] = node_tr[rel['from']]
995
+ rel['to'] = node_tr[rel['to']]
996
+ rel
997
+ end
998
+ count = neo4j_query_expect_one(<<~END_OF_QUERY, {:slice => slice})['count_r']
999
+ UNWIND $slice AS props
1000
+ MATCH (from), (to) WHERE ID(from) = props.from AND ID(to) = props.to
1001
+ CREATE (from)-[r:#{rel_type}]->(to)
1002
+ SET r = props.properties
1003
+ RETURN COUNT(r) AS count_r, COUNT(from) AS count_from, COUNT(to) AS count_to;
1004
+ END_OF_QUERY
1005
+ if count != slice.size
1006
+ raise "Ooops... expected #{slice.size} relationships, got #{count}."
1007
+ end
1008
+ r_count += slice.size
1009
+ STDERR.print "\rLoaded #{n_count} nodes, #{r_count} relationships..."
1010
+ end
1011
+ end
1012
+
1013
+ STDERR.puts
1014
+ end
1015
+
891
1016
  def cleanup_neo4j
892
1017
  if @bolt_socket
893
1018
  @bolt_socket.disconnect()
894
1019
  @bolt_socket = nil
895
1020
  end
896
1021
  end
1022
+
1023
+ def setup_constraints_and_indexes(constraints, indexes)
1024
+ @bolt_socket ||= BoltSocket.new()
1025
+ @bolt_socket.setup_constraints_and_indexes(constraints, indexes)
1026
+ end
897
1027
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: neo4j_bolt
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.6
4
+ version: 0.1.7
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Specht