neo4j_bolt 0.1.13 → 0.1.15

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: 0a19a8e8ffa10a25369a85dce34d09d3a3015a2a105ae52f43eb59fd9752badb
4
- data.tar.gz: 2ccb5d3d9d583e53afe638f4a21a328b94f9edadee9aa744baa9f019afa26007
3
+ metadata.gz: 04aa3226c239b35ccde7096230fd8421734dae517029af0501bf5381892b16e4
4
+ data.tar.gz: b267b7da10112ea640f326531c8db9260d9ea64fd722c9daa8f95a5473d8b740
5
5
  SHA512:
6
- metadata.gz: 1dadad65f242485126346c41db2c278f29a915ec075fb5775c0415c7b959cbc41efac7bfb3c29289b16a387de68f5a326be24b2bcd0614d5409e5a2503b39f0a
7
- data.tar.gz: 04d1a7cb369c42260bfd5ea6ce9a030a519e68fcf86aaa7bda14b9cd7ec696472eb01512d7390abcc5037ed452246a50780a05b564131c746c62e23bf5a59e0f
6
+ metadata.gz: 9c25238c42c83abdcab871eea6b2dadba8fe7c0ef3e40ce56ef1a161a7b2763f95b618f00d67aa24d766337ac20f0047263c0bca7921c532647c5c24fcf4f413
7
+ data.tar.gz: c6f653050a7928ca389aac06ad37b508e5b967745f557c5fcf920eeb0c0471ab83c37b085d2d6c5478de4f91fcbc1cf1fc1068b56bdea0000434f4425d11eba6
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- neo4j_bolt (0.1.12)
4
+ neo4j_bolt (0.1.15)
5
5
  gli
6
6
 
7
7
  GEM
data/bin/neo4j_bolt CHANGED
@@ -89,12 +89,10 @@ class App
89
89
  c.command :ls do |c2|
90
90
  c2.action do |global_options, options, args|
91
91
  neo4j_query("SHOW ALL CONSTRAINTS") do |row|
92
- # STDERR.puts row.to_yaml
93
- puts "#{row['type']} #{row['name']} #{(row['labelsOrTypes'] || []).join('/')}/#{row['properties'].join('/')}"
92
+ puts "#{row['type']} #{row['name']} #{(row['labelsOrTypes'] || []).join('/')}/#{(row['properties'] || []).join('/')}"
94
93
  end
95
94
  neo4j_query("SHOW ALL INDEXES") do |row|
96
- # STDERR.puts row.to_yaml
97
- puts "#{row['uniqueness']} #{row['entityType']} #{row['state']} #{row['populationPercent']}% #{row['name']} #{row['labelsOrTypes'].join('/')}/#{row['properties'].join('/')}"
95
+ puts "#{row['uniqueness']} #{row['entityType']} #{row['state']} #{row['populationPercent']}% #{row['name']} #{(row['labelsOrTypes'] || []).join('/')}/#{(row['properties'] || []).join('/')}"
98
96
  end
99
97
  end
100
98
  end
@@ -168,7 +166,7 @@ class App
168
166
  properties_for_label = {}
169
167
  counts_for_label = {}
170
168
 
171
- all_labels.to_a.sort.each do |label|
169
+ all_labels.to_a.each do |label|
172
170
  properties_for_label[label] ||= {}
173
171
  if options[:properties]
174
172
  neo4j_query("MATCH (n:#{label}) RETURN n") do |entry|
@@ -176,8 +174,26 @@ class App
176
174
  counts_for_label[label] += 1
177
175
  node = entry['n']
178
176
  node.each_pair do |key, value|
179
- properties_for_label[label][key] ||= {:classes => Set.new()}
180
- properties_for_label[label][key][:classes] << value.class
177
+ properties_for_label[label][key] ||= {:classes => Set.new(), :counts => {}, :min => {}, :max => {}, :sum => {}}
178
+ c = TR[value.class.to_s] || value.class.to_s
179
+ properties_for_label[label][key][:classes] << c
180
+ properties_for_label[label][key][:counts][c] ||= 0
181
+ properties_for_label[label][key][:counts][c] += 1
182
+ sz = if c == 'string' || c == 'list'
183
+ value.size
184
+ elsif c == 'int' || c == 'float'
185
+ value
186
+ else
187
+ nil
188
+ end
189
+ unless sz.nil?
190
+ properties_for_label[label][key][:min][c] ||= sz
191
+ properties_for_label[label][key][:min][c] = [properties_for_label[label][key][:min][c], sz].min
192
+ properties_for_label[label][key][:max][c] ||= sz
193
+ properties_for_label[label][key][:max][c] = [properties_for_label[label][key][:max][c], sz].max
194
+ properties_for_label[label][key][:sum][c] ||= 0
195
+ properties_for_label[label][key][:sum][c] += sz
196
+ end
181
197
  end
182
198
  end
183
199
  end
@@ -195,8 +211,26 @@ class App
195
211
  counts_for_label[s] += 1
196
212
  rel = entry['r']
197
213
  rel.each_pair do |key, value|
198
- properties_for_label[s][key] ||= {:classes => Set.new()}
199
- properties_for_label[s][key][:classes] << value.class
214
+ properties_for_label[s][key] ||= {:classes => Set.new(), :counts => {}, :min => {}, :max => {}, :sum => {}}
215
+ c = TR[value.class.to_s] || value.class.to_s
216
+ properties_for_label[s][key][:classes] << c
217
+ properties_for_label[s][key][:counts][c] ||= 0
218
+ properties_for_label[s][key][:counts][c] += 1
219
+ sz = if c == 'string' || c == 'list'
220
+ value.size
221
+ elsif c == 'int' || c == 'float'
222
+ value
223
+ else
224
+ nil
225
+ end
226
+ unless sz.nil?
227
+ properties_for_label[s][key][:min][c] ||= sz
228
+ properties_for_label[s][key][:min][c] = [properties_for_label[s][key][:min][c], sz].min
229
+ properties_for_label[s][key][:max][c] ||= sz
230
+ properties_for_label[s][key][:max][c] = [properties_for_label[s][key][:max][c], sz].max
231
+ properties_for_label[s][key][:sum][c] ||= 0
232
+ properties_for_label[s][key][:sum][c] += sz
233
+ end
200
234
  end
201
235
  end
202
236
  end
@@ -227,6 +261,47 @@ class App
227
261
  end
228
262
 
229
263
  dot = StringIO.open do |io|
264
+ print_properties = lambda do |props, lbl, rel|
265
+ label = ''
266
+ (props[lbl] || {}).keys.sort do |a, b|
267
+ partsa = Set.new()
268
+ ((((indexes[:node] || {})[lbl] || {})[a.to_s]) || Set.new()).each { |it| partsa << INDEX_TR[it] || it }
269
+ partsb = Set.new()
270
+ ((((indexes[:node] || {})[lbl] || {})[b.to_s]) || Set.new()).each { |it| partsb << INDEX_TR[it] || it }
271
+ (partsa.size == partsb.size) ? (a <=> b) : (partsb.size <=> partsa.size)
272
+ end.each do |key|
273
+ props[lbl][key][:classes].to_a.sort.each.with_index do |c, i|
274
+ label += "<tr>"
275
+ if i == 0
276
+ parts = Set.new()
277
+ ((((indexes[:node] || {})[lbl] || {})[key.to_s]) || Set.new()).each do |it|
278
+ parts << INDEX_TR[it] || it
279
+ end
280
+ index_s = parts.empty? ? '' : " <i>(#{parts.join(', ')})</i>"
281
+ label += "<td border='1' color='#{rel ? '#888888' : '#000000'}' valign='top' align='left' colspan='1' rowspan='#{props[lbl][key][:classes].size}'>#{key}#{index_s}</td>"
282
+ end
283
+ label += "<td border='1' color='#{rel ? '#888888' : '#000000'}' valign='top' align='left' colspan='1'>#{TR[c] || c}</td>"
284
+ label += "<td border='1' color='#{rel ? '#888888' : '#000000'}' valign='top' align='right' colspan='1'>#{sprintf('%d%%', props[lbl][key][:counts][c] * 100.0 / counts_for_label[lbl])}</td>"
285
+ if props[lbl][key][:sum][c]
286
+ mean_s = sprintf('%1.1f', props[lbl][key][:sum][c].to_f / props[lbl][key][:counts][c]).chomp('.0')
287
+ min_s = (c == 'float') ? sprintf('%1.1f', props[lbl][key][:min][c]) : props[lbl][key][:min][c]
288
+ max_s = (c == 'float') ? sprintf('%1.1f', props[lbl][key][:max][c]) : props[lbl][key][:max][c]
289
+ if props[lbl][key][:min][c] == props[lbl][key][:max][c]
290
+ label += "<td border='1' color='#{rel ? '#888888' : '#000000'}' valign='top' align='center' colspan='3'>#{min_s}</td>"
291
+ else
292
+ label += "<td border='1' color='#{rel ? '#888888' : '#000000'}' valign='top' align='right' colspan='1'>#{min_s}</td>"
293
+ label += "<td border='1' color='#{rel ? '#888888' : '#000000'}' valign='top' align='right' colspan='1'>#{mean_s}</td>"
294
+ label += "<td border='1' color='#{rel ? '#888888' : '#000000'}' valign='top' align='right' colspan='1'>#{max_s}</td>"
295
+ end
296
+ else
297
+ label += "<td border='1' color='#{rel ? '#888888' : '#000000'}' valign='top' align='left' colspan='3'></td>"
298
+ end
299
+ label += "</tr>"
300
+ end
301
+ end
302
+ label
303
+ end
304
+
230
305
  io.puts "digraph {"
231
306
  io.puts "graph [fontname = Helvetica, fontsize = 10, nodesep = 0.2, ranksep = 0.3];"
232
307
  io.puts "node [fontname = Helvetica, fontsize = 10, shape = none, margin = 0];"
@@ -235,22 +310,12 @@ class App
235
310
  io.puts 'splines=true;'
236
311
  properties_for_label.keys.sort.each do |lbl|
237
312
  label = "<<table valign='top' align='left' border='0' cellborder='0' cellspacing='0' cellpadding='4'>"
238
- label += "<tr><td border='1' bgcolor='#fce94f' valign='top' align='left' colspan='2'><b>#{lbl}</b>"
313
+ label += "<tr><td border='1' bgcolor='#fce94f' valign='top' align='left' colspan='6'><b>#{lbl}</b>"
239
314
  if options[:properties]
240
315
  label += " <i>(#{counts_for_label[lbl]})</i>"
241
316
  end
242
317
  label += "</td></tr>"
243
- properties_for_label[lbl].keys.sort.each do |key|
244
- label += "<tr>"
245
- parts = Set.new()
246
- ((((indexes[:node] || {})[lbl] || {})[key.to_s]) || Set.new()).each do |it|
247
- parts << INDEX_TR[it] || it
248
- end
249
- index_s = parts.empty? ? '' : " <i>(#{parts.join(', ')})</i>"
250
- label += "<td border='1' valign='top' align='left' colspan='1'>#{key}#{index_s}</td>"
251
- 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>"
252
- label += "</tr>"
253
- end
318
+ label += print_properties.call(properties_for_label, lbl, false)
254
319
  label += "</table>>"
255
320
  io.puts "\"#{lbl}\" [label = #{label}, pencolor = \"#000000\"];"
256
321
  end
@@ -261,27 +326,24 @@ class App
261
326
  lb = parts[2]
262
327
 
263
328
  label = "<<table valign='top' align='left' border='0' cellborder='0' cellspacing='0' cellpadding='4'>"
264
- label += "<tr><td border='1' color='#888888' bgcolor='#d3d7cf' valign='top' align='left' colspan='2'>#{type}"
329
+ label += "<tr><td border='1' color='#888888' bgcolor='#d3d7cf' valign='top' align='left' colspan='6'>#{type}"
265
330
  if options[:properties]
266
331
  label += " <i>(#{counts_for_label[s]})</i>"
267
332
  end
268
333
  label += "</td></tr>"
269
- (properties_for_label[s] || {}).keys.sort.each do |key|
270
- label += "<tr>"
271
- parts = Set.new()
272
- ((((indexes[:relationship] || {})[type] || {})[key.to_s]) || Set.new()).each do |it|
273
- parts << INDEX_TR[it] || it
274
- end
275
- index_s = parts.empty? ? '' : " <i>(#{parts.join(', ')})</i>"
276
- label += "<td border='1' color='#888888' valign='top' align='left' colspan='1'>#{key}#{index_s}</td>"
277
- label += "<td border='1' color='#888888' 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>"
278
- label += "</tr>"
279
- end
334
+ label += print_properties.call(properties_for_label, s, true)
335
+
280
336
  label += "</table>>"
281
337
  io.puts "\"#{s}\" [label = #{label}, pencolor = \"#000000\"];"
282
338
 
283
- io.puts "\"#{la}\" -> \"#{s}\";"
284
- io.puts "\"#{s}\" -> \"#{lb}\";"
339
+ cardinality = (counts_for_label[la] > counts_for_label[s]) ?
340
+ "#{sprintf('%1.1f', counts_for_label[la].to_f / counts_for_label[s]).chomp('.0')}:1" :
341
+ "1:#{sprintf('%1.1f', counts_for_label[s].to_f / counts_for_label[la]).chomp('.0')}"
342
+ io.puts "\"#{la}\" -> \"#{s}\" [label = \"#{cardinality}\", fontcolor=\"#888888\"];"
343
+ cardinality = (counts_for_label[lb] > counts_for_label[s]) ?
344
+ "1:#{sprintf('%1.1f', counts_for_label[lb].to_f / counts_for_label[s]).chomp('.0')}" :
345
+ "#{sprintf('%1.1f', counts_for_label[s].to_f / counts_for_label[lb]).chomp('.0')}:1"
346
+ io.puts "\"#{s}\" -> \"#{lb}\" [label = \"#{cardinality}\", fontcolor=\"#888888\"];"
285
347
  end
286
348
 
287
349
  io.puts "}"
@@ -1,3 +1,3 @@
1
1
  module Neo4jBolt
2
- VERSION = "0.1.13"
2
+ VERSION = "0.1.15"
3
3
  end
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.13
4
+ version: 0.1.15
5
5
  platform: ruby
6
6
  authors:
7
7
  - Michael Specht
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2022-10-29 00:00:00.000000000 Z
11
+ date: 2022-10-30 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rspec