neo4j_bolt 0.1.6 → 0.1.7

Sign up to get free protection for your applications and to get access to all the features.
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