forked from cloudfoundry/cloud_controller_ng
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathvisualize_models
executable file
·118 lines (105 loc) · 3.74 KB
/
visualize_models
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
#!/usr/bin/env ruby
# Copyright (c) 2009-2012 VMware, Inc.
#
# Note, I didn't try to make this a particularly clean implementation. It is
# somewhat of a hack just to printout the CC schema.
#
# It might be nice to factor this out into a common tool.
#
require "rubygems"
require "bundler/setup"
require "graphviz"
require "sequel"
ENV["BUNDLE_GEMFILE"] ||= File.expand_path("../../Gemfile", __FILE__)
$:.unshift(File.expand_path("../../lib", __FILE__))
db = Sequel.connect("sqlite:///")
Sequel::Model.plugin :timestamps
Sequel::Model.plugin :validation_helpers
Sequel::Model.plugin :subclasses
Sequel.extension :migration
migrations_dir ||= File.expand_path("../../db/migrations", __FILE__)
Sequel::Migrator.apply(db, migrations_dir)
require "cloud_controller"
require "cloud_controller/models"
g = GraphViz.new(:G, :type => :digraph, :rankdir => "LR",
:label => "*** REVIEW HIERARCHY ONLY. ATTRIBUTES ARE NOT COMPLETE ***")
def short_name(str)
name = str.split("::").last
end
Sequel::Model.descendents.each do |c|
name = short_name(c.name)
field_str = nil
c.columns.each do |col|
if field_str.nil?
field_str = ""
else
field_str += "|"
end
field_str += "<#{col}>- #{col}\\l"
end
label = "<entity_name>#{name}|" + field_str
g.add_nodes(name, "label" => label, "shape" => "record")
end
associations = {}
Sequel::Model.descendents.each do |c|
c.associations.each do |a|
ar = c.association_reflection(a)
ac = ar.associated_class
c_name = short_name(c.name)
ac_name = short_name(ac.name)
if associations[ac_name].nil? || associations[ac_name][c_name].nil?
case ar[:type]
when :many_to_many
if ar[:join_table]
join_table = ar[:join_table].to_s
left_key = ar[:left_key]
right_key = ar[:right_key]
label = "#{join_table}|<#{left_key}> -#{left_key}\\l|<#{right_key}> -#{right_key}\\l"
g.add_nodes(join_table, "label" => label, "shape" => "record")
arrowhead = "crow"
arrowtail = "crowodot"
g.add_edges({join_table => left_key },
{short_name(c.name) => :id },
"dir" => "both",
"arrowhead" => "dot",
"arrowtail" => "crowodot",
"minlen" => 2)
g.add_edges({join_table => right_key },
{short_name(ac.name) => :id },
"dir" => "both",
"arrowhead" => "dot",
"arrowtail" => "crowodot",
"minlen" => 2)
else
# NOTE: this may not be correct, the current schema
# does not have such an example
g.add_edges({short_name(ac.name) => ar[:key] },
{short_name(c.name) => :id },
"dir" => "both",
"arrowhead" => "crowodot",
"arrowtail" => "crowodot",
"minlen" => 2)
end
when :one_to_many
g.add_edges({short_name(ac.name) => ar[:key] },
{short_name(c.name) => :id },
"dir" => "both",
"arrowhead" => "dot",
"arrowtail" => "crowodot",
"minlen" => 2)
when :many_to_one
g.add_edges({short_name(ac.name) => :id},
{short_name(c.name) => ar[:key]},
"dir" => "both",
"arrowhead" => "crowodot",
"arrowtail" => "dot",
"minlen" => 2)
end
associations[c_name] ||= {}
associations[c_name][ac_name] = true
end
end
end
file_name = File.expand_path("../../docs/model.png", __FILE__)
g.output(:png => file_name)
puts "Model output to #{file_name}"