neo4j_bolt 0.1.7 → 0.1.8
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 +4 -4
- data/Gemfile +1 -0
- data/Gemfile.lock +3 -1
- data/bin/neo4j_bolt +213 -0
- data/lib/neo4j_bolt/version.rb +1 -1
- data/lib/neo4j_bolt.rb +6 -6
- data/neo4j_bolt.gemspec +2 -2
- metadata +8 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 1ac7e327b2ece44cd23a4408c81c0a9a41d52faf277c24b56280a15f1b79aeec
|
4
|
+
data.tar.gz: a24414f311a40ff6cb79d18a18497200f79ed7e2a58e070b5e321a4dc31cc757
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f716cd2380decb532dbe6954030e4ead5ea0a1edde1868922b81d2105801d7ed6bb9e5b35e3eb22f79ca9413408582bca6da44a9fa767ad6fa554b929df84436
|
7
|
+
data.tar.gz: 35f82570c1bcf2b56a61a17d9bbf189f2055386efd1c6f83cd3c60313069d26380ce050394665ede60ef9ea4eb27626bf7438b43a4070e361a2b9ed626c51893
|
data/Gemfile
CHANGED
data/Gemfile.lock
CHANGED
@@ -1,12 +1,13 @@
|
|
1
1
|
PATH
|
2
2
|
remote: .
|
3
3
|
specs:
|
4
|
-
neo4j_bolt (0.1.
|
4
|
+
neo4j_bolt (0.1.8)
|
5
5
|
|
6
6
|
GEM
|
7
7
|
remote: https://rubygems.org/
|
8
8
|
specs:
|
9
9
|
diff-lcs (1.5.0)
|
10
|
+
gli (2.21.0)
|
10
11
|
rake (12.3.3)
|
11
12
|
rspec (3.11.0)
|
12
13
|
rspec-core (~> 3.11.0)
|
@@ -26,6 +27,7 @@ PLATFORMS
|
|
26
27
|
ruby
|
27
28
|
|
28
29
|
DEPENDENCIES
|
30
|
+
gli
|
29
31
|
neo4j_bolt!
|
30
32
|
rake (~> 12.0)
|
31
33
|
rspec (~> 3.0)
|
data/bin/neo4j_bolt
ADDED
@@ -0,0 +1,213 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "neo4j_bolt"
|
5
|
+
require "gli"
|
6
|
+
|
7
|
+
include Neo4jBolt
|
8
|
+
|
9
|
+
class App
|
10
|
+
extend GLI::App
|
11
|
+
|
12
|
+
program_desc 'run various Neo4j housekeeping tasks'
|
13
|
+
version Neo4jBolt::VERSION
|
14
|
+
|
15
|
+
flag [:v, :verbosity], :default_value => 0
|
16
|
+
flag [:h, :host], :default_value => 'localhost:7687'
|
17
|
+
|
18
|
+
pre do |global_options, command, options, args|
|
19
|
+
host = global_options[:host]
|
20
|
+
Neo4jBolt.bolt_host = host.split(':').first
|
21
|
+
Neo4jBolt.bolt_port = host.split(':').last.to_i
|
22
|
+
Neo4jBolt.bolt_verbosity = global_options[:verbosity].to_i
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
# --------------------------------------------
|
27
|
+
|
28
|
+
desc 'Console'
|
29
|
+
command :console do |c|
|
30
|
+
c.action do
|
31
|
+
require "irb"
|
32
|
+
IRB.start(__FILE__)
|
33
|
+
end
|
34
|
+
end
|
35
|
+
|
36
|
+
# --------------------------------------------
|
37
|
+
|
38
|
+
desc 'Dump database'
|
39
|
+
long_desc 'Dump all nodes and relationships.'
|
40
|
+
command :dump do |c|
|
41
|
+
c.flag [:o, :out_file], :default_value => '/dev/stdout'
|
42
|
+
c.action do |global_options, options|
|
43
|
+
File.open(options[:out_file], 'w') do |f|
|
44
|
+
dump_database(f)
|
45
|
+
end
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
# --------------------------------------------
|
50
|
+
|
51
|
+
desc 'Load database dump'
|
52
|
+
long_desc 'Load nodes and relationships from a database dump.'
|
53
|
+
command :load do |c|
|
54
|
+
# c.flag [:i, :in_file], :desc => 'input path', :required => true
|
55
|
+
c.switch [:f, :force], :default_value => false, :desc => 'force appending nodes even if the database is not empty'
|
56
|
+
c.action do |global_options, options, args|
|
57
|
+
help_now!('input path is required') if args.empty?
|
58
|
+
path = args.shift
|
59
|
+
File.open(path, 'r') do |f|
|
60
|
+
load_database_dump(f, force_append: options[:force])
|
61
|
+
end
|
62
|
+
end
|
63
|
+
end
|
64
|
+
|
65
|
+
# --------------------------------------------
|
66
|
+
|
67
|
+
desc 'Clear database'
|
68
|
+
long_desc 'Clear all nodes and relationships'
|
69
|
+
command :clear do |c|
|
70
|
+
c.switch [:srsly], :required => true, :negatable => false, :desc => 'Specify --srsly to really clear the database'
|
71
|
+
c.action do |global_options, options, args|
|
72
|
+
if options[:srsly]
|
73
|
+
neo4j_query("MATCH (n) DETACH DELETE n;")
|
74
|
+
else
|
75
|
+
STDERR.puts "Doing nothing unless you specify --srsly."
|
76
|
+
end
|
77
|
+
end
|
78
|
+
end
|
79
|
+
|
80
|
+
# --------------------------------------------
|
81
|
+
|
82
|
+
desc 'Visualize database'
|
83
|
+
long_desc 'Generate a GraphViz-formatted visual representation of the database'
|
84
|
+
command :visualize do |c|
|
85
|
+
c.flag [:o, :out_file], :default_value => '/dev/stdout'
|
86
|
+
c.switch [:p, :properties], :default_value => false, :desc => 'include properties'
|
87
|
+
c.action do |global_options, options|
|
88
|
+
File.open(options[:out_file], 'w') do |f|
|
89
|
+
all_labels = Set.new()
|
90
|
+
|
91
|
+
TR = {'String' => 'string',
|
92
|
+
'Array' => 'list',
|
93
|
+
'Hash' => 'hash',
|
94
|
+
'TrueClass' => 'true',
|
95
|
+
'FalseClass' => 'false',
|
96
|
+
'NilClass' => 'null',
|
97
|
+
'Integer' => 'int',
|
98
|
+
'Float' => 'float'
|
99
|
+
}
|
100
|
+
|
101
|
+
neo4j_query("MATCH (n) RETURN DISTINCT labels(n) AS labels") do |entry|
|
102
|
+
labels = entry['labels']
|
103
|
+
if labels.size != 1
|
104
|
+
raise "multiple labels per node not supported yet: #{labels.join(' ')}"
|
105
|
+
end
|
106
|
+
all_labels << labels.first
|
107
|
+
end
|
108
|
+
|
109
|
+
all_relationships = Set.new()
|
110
|
+
|
111
|
+
neo4j_query("MATCH (a)-[r]->(b) RETURN DISTINCT labels(a) AS la, type(r) AS t, labels(b) AS lb;") do |entry|
|
112
|
+
la = entry['la'].first
|
113
|
+
t = entry['t']
|
114
|
+
lb = entry['lb'].first
|
115
|
+
all_relationships << "#{la}/#{t}/#{lb}"
|
116
|
+
end
|
117
|
+
|
118
|
+
properties_for_label = {}
|
119
|
+
counts_for_label = {}
|
120
|
+
|
121
|
+
all_labels.to_a.sort.each do |label|
|
122
|
+
properties_for_label[label] ||= {}
|
123
|
+
if options[:properties]
|
124
|
+
neo4j_query("MATCH (n:#{label}) RETURN n") do |entry|
|
125
|
+
counts_for_label[label] ||= 0
|
126
|
+
counts_for_label[label] += 1
|
127
|
+
node = entry['n']
|
128
|
+
node.each_pair do |key, value|
|
129
|
+
properties_for_label[label][key] ||= {:classes => Set.new()}
|
130
|
+
properties_for_label[label][key][:classes] << value.class
|
131
|
+
end
|
132
|
+
end
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
all_relationships.each do |s|
|
137
|
+
properties_for_label[s] ||= {}
|
138
|
+
parts = s.split('/')
|
139
|
+
la = parts[0]
|
140
|
+
type = parts[1]
|
141
|
+
lb = parts[2]
|
142
|
+
if options[:properties]
|
143
|
+
neo4j_query("MATCH (a:#{la})-[r:#{type}]->(b:#{lb}) RETURN r") do |entry|
|
144
|
+
counts_for_label[s] ||= 0
|
145
|
+
counts_for_label[s] += 1
|
146
|
+
rel = entry['r']
|
147
|
+
rel.each_pair do |key, value|
|
148
|
+
properties_for_label[s][key] ||= {:classes => Set.new()}
|
149
|
+
properties_for_label[s][key][:classes] << value.class
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
dot = StringIO.open do |io|
|
156
|
+
io.puts "digraph {"
|
157
|
+
io.puts "graph [fontname = Helvetica, fontsize = 10, nodesep = 0.2, ranksep = 0.3];"
|
158
|
+
io.puts "node [fontname = Helvetica, fontsize = 10, shape = none, margin = 0];"
|
159
|
+
io.puts "edge [fontname = Helvetica, fontsize = 10, arrowsize = 0.6, color = \"#000000\"];"
|
160
|
+
io.puts 'rankdir=LR;'
|
161
|
+
io.puts 'splines=true;'
|
162
|
+
properties_for_label.keys.sort.each do |lbl|
|
163
|
+
label = "<<table valign='top' align='left' border='0' cellborder='0' cellspacing='0' cellpadding='4'>"
|
164
|
+
label += "<tr><td border='1' bgcolor='#fce94f' valign='top' align='left' colspan='2'><b>#{lbl}</b>"
|
165
|
+
if options[:properties]
|
166
|
+
label += " <i>(#{counts_for_label[lbl]})</i>"
|
167
|
+
end
|
168
|
+
label += "</td></tr>"
|
169
|
+
properties_for_label[lbl].keys.sort.each do |key|
|
170
|
+
label += "<tr>"
|
171
|
+
label += "<td border='1' valign='top' align='left' colspan='1'>#{key}</td>"
|
172
|
+
label += "<td border='1' valign='top' align='left' colspan='1'>#{properties_for_label[lbl][key][:classes].to_a.map { |x| TR[x.to_s] || x.to_s }.sort.join(' / ')}</td>"
|
173
|
+
label += "</tr>"
|
174
|
+
end
|
175
|
+
label += "</table>>"
|
176
|
+
io.puts "\"#{lbl}\" [label = #{label}, pencolor = \"#000000\"];"
|
177
|
+
end
|
178
|
+
all_relationships.each do |s|
|
179
|
+
parts = s.split('/')
|
180
|
+
la = parts[0]
|
181
|
+
type = parts[1]
|
182
|
+
lb = parts[2]
|
183
|
+
|
184
|
+
label = "<<table valign='top' align='left' border='0' cellborder='0' cellspacing='0' cellpadding='4'>"
|
185
|
+
label += "<tr><td border='1' bgcolor='#d3d7cf' valign='top' align='left' colspan='2'><b>#{type}</b>"
|
186
|
+
if options[:properties]
|
187
|
+
label += " <i>(#{counts_for_label[s]})</i>"
|
188
|
+
end
|
189
|
+
label += "</td></tr>"
|
190
|
+
(properties_for_label[s] || {}).keys.sort.each do |key|
|
191
|
+
label += "<tr>"
|
192
|
+
label += "<td border='1' valign='top' align='left' colspan='1'>#{key}</td>"
|
193
|
+
label += "<td border='1' valign='top' align='left' colspan='1'>#{properties_for_label[s][key][:classes].to_a.map { |x| TR[x.to_s] || x.to_s }.sort.join(' / ')}</td>"
|
194
|
+
label += "</tr>"
|
195
|
+
end
|
196
|
+
label += "</table>>"
|
197
|
+
io.puts "\"#{s}\" [label = #{label}, pencolor = \"#000000\"];"
|
198
|
+
|
199
|
+
io.puts "\"#{la}\" -> \"#{s}\";"
|
200
|
+
io.puts "\"#{s}\" -> \"#{lb}\";"
|
201
|
+
end
|
202
|
+
|
203
|
+
io.puts "}"
|
204
|
+
io.string
|
205
|
+
end
|
206
|
+
f.puts dot
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
exit App.run(ARGV)
|
data/lib/neo4j_bolt/version.rb
CHANGED
data/lib/neo4j_bolt.rb
CHANGED
@@ -5,12 +5,12 @@ require 'yaml'
|
|
5
5
|
|
6
6
|
module Neo4jBolt
|
7
7
|
class << self
|
8
|
-
attr_accessor :bolt_host, :bolt_port
|
8
|
+
attr_accessor :bolt_host, :bolt_port, :bolt_verbosity
|
9
9
|
end
|
10
10
|
self.bolt_host = 'localhost'
|
11
11
|
self.bolt_port = 7687
|
12
|
+
self.bolt_verbosity = 0
|
12
13
|
|
13
|
-
NEO4J_DEBUG = 0
|
14
14
|
CONSTRAINT_INDEX_PREFIX = 'neo4j_bolt_'
|
15
15
|
|
16
16
|
module ServerState
|
@@ -115,7 +115,7 @@ module Neo4jBolt
|
|
115
115
|
end
|
116
116
|
chunk = @socket.read(length).unpack('C*')
|
117
117
|
@data += chunk
|
118
|
-
if
|
118
|
+
if Neo4jBolt.bolt_verbosity >= 3
|
119
119
|
dump()
|
120
120
|
end
|
121
121
|
end
|
@@ -753,7 +753,7 @@ module Neo4jBolt
|
|
753
753
|
end
|
754
754
|
|
755
755
|
def run_query(query, data = {}, &block)
|
756
|
-
if
|
756
|
+
if Neo4jBolt.bolt_verbosity >= 1
|
757
757
|
STDERR.puts query
|
758
758
|
STDERR.puts data.to_json
|
759
759
|
STDERR.puts '-' * 40
|
@@ -791,7 +791,7 @@ module Neo4jBolt
|
|
791
791
|
keys.each.with_index do |key, i|
|
792
792
|
entry[key] = fix_value(data[:data][i])
|
793
793
|
end
|
794
|
-
if
|
794
|
+
if Neo4jBolt.bolt_verbosity >= 1
|
795
795
|
STDERR.puts ">>> #{entry.to_json}"
|
796
796
|
STDERR.puts '-' * 40
|
797
797
|
end
|
@@ -938,7 +938,7 @@ module Neo4jBolt
|
|
938
938
|
transaction do
|
939
939
|
node_count = neo4j_query_expect_one('MATCH (n) RETURN COUNT(n) as count;')['count']
|
940
940
|
unless node_count == 0
|
941
|
-
raise "
|
941
|
+
raise "There are nodes in this database, exiting now."
|
942
942
|
end
|
943
943
|
end
|
944
944
|
end
|
data/neo4j_bolt.gemspec
CHANGED
@@ -22,8 +22,8 @@ Gem::Specification.new do |spec|
|
|
22
22
|
spec.files = Dir.chdir(File.expand_path('..', __FILE__)) do
|
23
23
|
`git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
|
24
24
|
end
|
25
|
-
spec.bindir = "
|
26
|
-
spec.executables = spec.files.grep(%r{^
|
25
|
+
spec.bindir = "bin"
|
26
|
+
spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
|
27
27
|
spec.require_paths = ["lib"]
|
28
28
|
|
29
29
|
spec.add_development_dependency "rspec", "~> 3.2"
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: neo4j_bolt
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.8
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Michael Specht
|
8
8
|
autorequire:
|
9
|
-
bindir:
|
9
|
+
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2022-10-
|
11
|
+
date: 2022-10-29 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rspec
|
@@ -27,7 +27,10 @@ dependencies:
|
|
27
27
|
description:
|
28
28
|
email:
|
29
29
|
- micha.specht@gmail.com
|
30
|
-
executables:
|
30
|
+
executables:
|
31
|
+
- console
|
32
|
+
- neo4j_bolt
|
33
|
+
- setup
|
31
34
|
extensions: []
|
32
35
|
extra_rdoc_files: []
|
33
36
|
files:
|
@@ -40,6 +43,7 @@ files:
|
|
40
43
|
- README.md
|
41
44
|
- Rakefile
|
42
45
|
- bin/console
|
46
|
+
- bin/neo4j_bolt
|
43
47
|
- bin/setup
|
44
48
|
- lib/neo4j_bolt.rb
|
45
49
|
- lib/neo4j_bolt/version.rb
|