rails_graph 0.1.0
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 +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +17 -0
- data/.ruby-version +1 -0
- data/.tool-versions +1 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +12 -0
- data/Gemfile.lock +142 -0
- data/LICENSE.txt +21 -0
- data/README.md +89 -0
- data/Rakefile +12 -0
- data/graph.svg +1 -0
- data/lib/rails_graph/commands/build_graph.rb +113 -0
- data/lib/rails_graph/commands/export_graph.rb +21 -0
- data/lib/rails_graph/configuration.rb +26 -0
- data/lib/rails_graph/error.rb +5 -0
- data/lib/rails_graph/exporters/base.rb +7 -0
- data/lib/rails_graph/exporters/cypher.rb +62 -0
- data/lib/rails_graph/exporters/json.rb +16 -0
- data/lib/rails_graph/exporters/neo4j.rb +26 -0
- data/lib/rails_graph/graph/entity.rb +21 -0
- data/lib/rails_graph/graph/graph.rb +43 -0
- data/lib/rails_graph/graph/node.rb +26 -0
- data/lib/rails_graph/graph/nodes/abstract_model.rb +27 -0
- data/lib/rails_graph/graph/nodes/column.rb +31 -0
- data/lib/rails_graph/graph/nodes/model.rb +44 -0
- data/lib/rails_graph/graph/nodes/virtual_model.rb +23 -0
- data/lib/rails_graph/graph/relationship.rb +34 -0
- data/lib/rails_graph/graph/relationships/association.rb +74 -0
- data/lib/rails_graph/graph/relationships/attribute.rb +23 -0
- data/lib/rails_graph/graph/relationships/inheritance.rb +21 -0
- data/lib/rails_graph/helpers/associations.rb +31 -0
- data/lib/rails_graph/helpers/models.rb +13 -0
- data/lib/rails_graph/helpers/options_parser.rb +21 -0
- data/lib/rails_graph/railtie.rb +14 -0
- data/lib/rails_graph/tasks/rails_graph.rake +27 -0
- data/lib/rails_graph/version.rb +5 -0
- data/lib/rails_graph.rb +33 -0
- data/sig/rails_graph.rbs +4 -0
- metadata +140 -0
@@ -0,0 +1,113 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../graph/graph"
|
4
|
+
require_relative "../graph/node"
|
5
|
+
require_relative "../graph/relationship"
|
6
|
+
|
7
|
+
require_relative "../graph/nodes/abstract_model"
|
8
|
+
require_relative "../graph/nodes/column"
|
9
|
+
require_relative "../graph/nodes/model"
|
10
|
+
require_relative "../graph/nodes/virtual_model"
|
11
|
+
|
12
|
+
require_relative "../graph/relationships/association"
|
13
|
+
require_relative "../graph/relationships/attribute"
|
14
|
+
require_relative "../graph/relationships/inheritance"
|
15
|
+
|
16
|
+
require_relative "../helpers/associations"
|
17
|
+
require_relative "../helpers/models"
|
18
|
+
|
19
|
+
module RailsGraph
|
20
|
+
module Commands
|
21
|
+
class BuildGraph
|
22
|
+
def self.call(configuration:)
|
23
|
+
new(configuration: configuration).call
|
24
|
+
end
|
25
|
+
|
26
|
+
def call
|
27
|
+
polymorphic_node = RailsGraph::Graph::Nodes::VirtualModel.new("PolymorphicModel")
|
28
|
+
graph.add_node(polymorphic_node)
|
29
|
+
|
30
|
+
active_record_base_node = RailsGraph::Graph::Nodes::AbstractModel.new(ActiveRecord::Base)
|
31
|
+
graph.add_node(active_record_base_node)
|
32
|
+
|
33
|
+
build_model_nodes
|
34
|
+
build_associations_relationships
|
35
|
+
build_column_nodes if configuration.columns?
|
36
|
+
build_inheritance_relationships if configuration.inheritance?
|
37
|
+
|
38
|
+
graph
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
|
43
|
+
attr_reader :configuration, :classes, :graph
|
44
|
+
|
45
|
+
def initialize(configuration:)
|
46
|
+
@configuration = configuration
|
47
|
+
@classes = ActiveRecord::Base.descendants + configuration.include_classes
|
48
|
+
@graph = RailsGraph::Graph::Graph.new
|
49
|
+
end
|
50
|
+
|
51
|
+
def build_model_nodes
|
52
|
+
classes.each do |model|
|
53
|
+
if model.abstract_class
|
54
|
+
node = RailsGraph::Graph::Nodes::AbstractModel.new(model)
|
55
|
+
graph.add_node(node)
|
56
|
+
next
|
57
|
+
end
|
58
|
+
|
59
|
+
node = RailsGraph::Graph::Nodes::Model.new(model)
|
60
|
+
graph.add_node(node)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
def build_column_nodes
|
65
|
+
processed = Hash.new(false)
|
66
|
+
|
67
|
+
classes.each do |model|
|
68
|
+
next if model.attribute_names.empty?
|
69
|
+
|
70
|
+
identifier = RailsGraph::Helpers::Models.identifier(model)
|
71
|
+
node = graph.node(identifier)
|
72
|
+
|
73
|
+
next if processed[node.id]
|
74
|
+
|
75
|
+
processed[node.id] = true
|
76
|
+
|
77
|
+
model.columns.each do |column|
|
78
|
+
column_node = RailsGraph::Graph::Nodes::Column.new(column)
|
79
|
+
graph.add_node(column_node)
|
80
|
+
|
81
|
+
relationship = RailsGraph::Graph::Relationships::Attribute.new(node, column_node)
|
82
|
+
graph.add_relationship(relationship)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
def build_inheritance_relationships
|
88
|
+
classes.each do |model|
|
89
|
+
identifier = RailsGraph::Helpers::Models.identifier(model)
|
90
|
+
node = graph.node(identifier)
|
91
|
+
|
92
|
+
superclass_node_identifier = RailsGraph::Helpers::Models.identifier(model.superclass)
|
93
|
+
superclass_node = graph.node(superclass_node_identifier)
|
94
|
+
|
95
|
+
relationship = RailsGraph::Graph::Relationships::Inheritance.new(node, superclass_node)
|
96
|
+
graph.add_relationship(relationship)
|
97
|
+
end
|
98
|
+
end
|
99
|
+
|
100
|
+
def build_associations_relationships
|
101
|
+
classes.each do |model|
|
102
|
+
model.reflect_on_all_associations.each do |association|
|
103
|
+
source_node = RailsGraph::Helpers::Associations.source_node(graph, association)
|
104
|
+
target_node = RailsGraph::Helpers::Associations.target_node(graph, association)
|
105
|
+
|
106
|
+
relationship = RailsGraph::Graph::Relationships::Association.new(association, source_node, target_node)
|
107
|
+
graph.add_relationship(relationship)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../exporters/cypher"
|
4
|
+
require_relative "../exporters/json"
|
5
|
+
require_relative "../exporters/neo4j"
|
6
|
+
|
7
|
+
module RailsGraph
|
8
|
+
module Commands
|
9
|
+
class ExportGraph
|
10
|
+
EXPORTERS = {
|
11
|
+
cypher: RailsGraph::Exporters::Cypher,
|
12
|
+
json: RailsGraph::Exporters::Json,
|
13
|
+
neo4j: RailsGraph::Exporters::Neo4j
|
14
|
+
}.freeze
|
15
|
+
|
16
|
+
def self.call(graph:, format: :cypher, **options)
|
17
|
+
EXPORTERS[format].export(graph: graph, **options)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsGraph
|
4
|
+
class Configuration
|
5
|
+
attr_reader :include_classes
|
6
|
+
attr_writer :columns, :inheritance
|
7
|
+
|
8
|
+
def initialize
|
9
|
+
@include_classes = []
|
10
|
+
@columns = false
|
11
|
+
@inheritance = true
|
12
|
+
end
|
13
|
+
|
14
|
+
def include_classes=(include_classes)
|
15
|
+
@include_classes = Array(include_classes)
|
16
|
+
end
|
17
|
+
|
18
|
+
def columns?
|
19
|
+
@columns
|
20
|
+
end
|
21
|
+
|
22
|
+
def inheritance?
|
23
|
+
@inheritance
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
|
5
|
+
module RailsGraph
|
6
|
+
module Exporters
|
7
|
+
class Cypher < Base
|
8
|
+
BASE_CYPHER = "MATCH (n) DETACH DELETE n;"
|
9
|
+
|
10
|
+
def self.export(graph:, filename:)
|
11
|
+
queries = build_queries(graph)
|
12
|
+
|
13
|
+
File.write(filename, queries.join("\n"), mode: "w")
|
14
|
+
end
|
15
|
+
|
16
|
+
def self.build_queries(graph)
|
17
|
+
queries = []
|
18
|
+
queries << BASE_CYPHER
|
19
|
+
|
20
|
+
graph.nodes.each { |node| queries << create_node_cypher(node) }
|
21
|
+
graph.relationships.each { |relationship| queries << create_relationship_cypher(relationship) }
|
22
|
+
|
23
|
+
queries
|
24
|
+
end
|
25
|
+
|
26
|
+
def self.node_ref(node)
|
27
|
+
"ref_#{node.id.gsub("-", "_")}"
|
28
|
+
end
|
29
|
+
|
30
|
+
def self.format_properties(item)
|
31
|
+
output = "name: '#{item.name}'"
|
32
|
+
|
33
|
+
item.properties.each do |k, v|
|
34
|
+
formatted_value = case v
|
35
|
+
when String, Symbol then "'#{v}'"
|
36
|
+
when nil then "null"
|
37
|
+
else v.to_s
|
38
|
+
end
|
39
|
+
|
40
|
+
output += ", #{k}: #{formatted_value}"
|
41
|
+
end
|
42
|
+
|
43
|
+
output
|
44
|
+
end
|
45
|
+
|
46
|
+
def self.create_node_cypher(node)
|
47
|
+
ref = node_ref(node)
|
48
|
+
labels = node.labels.join(":")
|
49
|
+
properties = format_properties(node)
|
50
|
+
|
51
|
+
"CREATE (#{ref}:#{labels} {#{properties}})"
|
52
|
+
end
|
53
|
+
|
54
|
+
def self.create_relationship_cypher(relationship)
|
55
|
+
source_ref = node_ref(relationship.source)
|
56
|
+
target_ref = node_ref(relationship.target)
|
57
|
+
|
58
|
+
"CREATE (#{source_ref})-[:#{relationship.label} {#{format_properties(relationship)}}]->(#{target_ref})"
|
59
|
+
end
|
60
|
+
end
|
61
|
+
end
|
62
|
+
end
|
@@ -0,0 +1,16 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
require "json"
|
5
|
+
|
6
|
+
module RailsGraph
|
7
|
+
module Exporters
|
8
|
+
class Json < Base
|
9
|
+
def self.export(graph:, filename:)
|
10
|
+
json = graph.to_json
|
11
|
+
|
12
|
+
File.write(filename, json, mode: "w")
|
13
|
+
end
|
14
|
+
end
|
15
|
+
end
|
16
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "base"
|
4
|
+
require "neo4j_ruby_driver"
|
5
|
+
|
6
|
+
module RailsGraph
|
7
|
+
module Exporters
|
8
|
+
class Neo4j < Base
|
9
|
+
def self.export(graph:, host:, username:, password:)
|
10
|
+
auth = ::Neo4j::Driver::AuthTokens.basic(username, password)
|
11
|
+
|
12
|
+
::Neo4j::Driver::GraphDatabase.driver(host, auth) do |driver|
|
13
|
+
driver.session do |session|
|
14
|
+
queries = Cypher.build_queries(graph)
|
15
|
+
queries.shift
|
16
|
+
queries = queries.join("\n")
|
17
|
+
|
18
|
+
session.write_transaction do |tx|
|
19
|
+
tx.run(queries, message: "Success!")
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require "securerandom"
|
4
|
+
|
5
|
+
module RailsGraph
|
6
|
+
module Graph
|
7
|
+
class Entity
|
8
|
+
attr_reader :id, :name, :properties
|
9
|
+
|
10
|
+
def initialize(name:, id: SecureRandom.uuid, properties: {})
|
11
|
+
@id = id
|
12
|
+
@name = name
|
13
|
+
@properties = properties
|
14
|
+
end
|
15
|
+
|
16
|
+
def identifier
|
17
|
+
id
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsGraph
|
4
|
+
module Graph
|
5
|
+
class Graph
|
6
|
+
def initialize(nodes: {}, relationships: {})
|
7
|
+
@nodes = nodes
|
8
|
+
@relationships = relationships
|
9
|
+
end
|
10
|
+
|
11
|
+
def add_node(node)
|
12
|
+
@nodes[node.identifier] = node
|
13
|
+
end
|
14
|
+
|
15
|
+
def nodes
|
16
|
+
@nodes.values
|
17
|
+
end
|
18
|
+
|
19
|
+
def node(identifier)
|
20
|
+
@nodes[identifier]
|
21
|
+
end
|
22
|
+
|
23
|
+
def add_relationship(relationship)
|
24
|
+
@relationships[relationship.identifier] = relationship
|
25
|
+
end
|
26
|
+
|
27
|
+
def relationships
|
28
|
+
@relationships.values.flatten
|
29
|
+
end
|
30
|
+
|
31
|
+
def relationship(identifier)
|
32
|
+
@relationships[identifier]
|
33
|
+
end
|
34
|
+
|
35
|
+
def as_json(_options = nil)
|
36
|
+
{
|
37
|
+
nodes: nodes,
|
38
|
+
relationships: relationships
|
39
|
+
}
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "entity"
|
4
|
+
|
5
|
+
module RailsGraph
|
6
|
+
module Graph
|
7
|
+
class Node < Entity
|
8
|
+
attr_reader :labels
|
9
|
+
|
10
|
+
def initialize(labels: [], **opts)
|
11
|
+
@labels = Array(labels)
|
12
|
+
|
13
|
+
super(**opts)
|
14
|
+
end
|
15
|
+
|
16
|
+
def as_json(_options = nil)
|
17
|
+
{
|
18
|
+
id: id,
|
19
|
+
labels: labels,
|
20
|
+
name: name,
|
21
|
+
properties: properties
|
22
|
+
}
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../node"
|
4
|
+
|
5
|
+
module RailsGraph
|
6
|
+
module Graph
|
7
|
+
module Nodes
|
8
|
+
class AbstractModel < Node
|
9
|
+
attr_reader :model
|
10
|
+
|
11
|
+
def initialize(model)
|
12
|
+
@model = model
|
13
|
+
|
14
|
+
super(
|
15
|
+
labels: "AbstractModel",
|
16
|
+
name: model.name,
|
17
|
+
properties: {}
|
18
|
+
)
|
19
|
+
end
|
20
|
+
|
21
|
+
def identifier
|
22
|
+
RailsGraph::Helpers::Models.identifier(model)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../node"
|
4
|
+
|
5
|
+
module RailsGraph
|
6
|
+
module Graph
|
7
|
+
module Nodes
|
8
|
+
class Column < Node
|
9
|
+
attr_reader :column
|
10
|
+
|
11
|
+
def initialize(column)
|
12
|
+
@column = column
|
13
|
+
|
14
|
+
super(labels: "Column", name: column.name, properties: build_properties)
|
15
|
+
end
|
16
|
+
|
17
|
+
private
|
18
|
+
|
19
|
+
def build_properties
|
20
|
+
{
|
21
|
+
nullable: column.null || false,
|
22
|
+
comment: column.comment,
|
23
|
+
default: column.default,
|
24
|
+
type: column.type,
|
25
|
+
sql_type: column.sql_type
|
26
|
+
}
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|
@@ -0,0 +1,44 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../node"
|
4
|
+
|
5
|
+
module RailsGraph
|
6
|
+
module Graph
|
7
|
+
module Nodes
|
8
|
+
class Model < Node
|
9
|
+
attr_reader :model
|
10
|
+
|
11
|
+
def initialize(model)
|
12
|
+
@model = model
|
13
|
+
|
14
|
+
super(labels: "Model", name: model.name, properties: build_properties)
|
15
|
+
end
|
16
|
+
|
17
|
+
def identifier
|
18
|
+
RailsGraph::Helpers::Models.identifier(model)
|
19
|
+
end
|
20
|
+
|
21
|
+
private
|
22
|
+
|
23
|
+
def build_properties
|
24
|
+
{
|
25
|
+
table_name: model.table_name,
|
26
|
+
table_exists: table_exists?,
|
27
|
+
columns_count: model.attribute_names.count,
|
28
|
+
db_indexes_count: db_indexes_count,
|
29
|
+
primary_key: model.primary_key,
|
30
|
+
full_name: model.to_s
|
31
|
+
}
|
32
|
+
end
|
33
|
+
|
34
|
+
def table_exists?
|
35
|
+
ActiveRecord::Base.connection.table_exists?(model.table_name)
|
36
|
+
end
|
37
|
+
|
38
|
+
def db_indexes_count
|
39
|
+
ActiveRecord::Base.connection.indexes(model.table_name).count
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../node"
|
4
|
+
|
5
|
+
module RailsGraph
|
6
|
+
module Graph
|
7
|
+
module Nodes
|
8
|
+
class VirtualModel < Node
|
9
|
+
def initialize(name)
|
10
|
+
super(
|
11
|
+
labels: "VirtualModel",
|
12
|
+
name: name,
|
13
|
+
properties: {}
|
14
|
+
)
|
15
|
+
end
|
16
|
+
|
17
|
+
def identifier
|
18
|
+
name
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,34 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "entity"
|
4
|
+
|
5
|
+
module RailsGraph
|
6
|
+
module Graph
|
7
|
+
class Relationship < Entity
|
8
|
+
attr_reader :source, :target, :label
|
9
|
+
|
10
|
+
def initialize(source:, target:, label:, **opts)
|
11
|
+
@source = source
|
12
|
+
@target = target
|
13
|
+
@label = label
|
14
|
+
|
15
|
+
super(**opts)
|
16
|
+
end
|
17
|
+
|
18
|
+
def identifier
|
19
|
+
"#{label}##{source.identifier}##{target.identifier}##{name}"
|
20
|
+
end
|
21
|
+
|
22
|
+
def as_json(_options = nil)
|
23
|
+
{
|
24
|
+
id: id,
|
25
|
+
label: label,
|
26
|
+
name: name,
|
27
|
+
source: source.id,
|
28
|
+
target: target.id,
|
29
|
+
properties: properties
|
30
|
+
}
|
31
|
+
end
|
32
|
+
end
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../relationship"
|
4
|
+
|
5
|
+
module RailsGraph
|
6
|
+
module Graph
|
7
|
+
module Relationships
|
8
|
+
class Association < Relationship
|
9
|
+
attr_reader :association
|
10
|
+
|
11
|
+
def initialize(association, source, target)
|
12
|
+
@association = association
|
13
|
+
|
14
|
+
super(
|
15
|
+
source: source,
|
16
|
+
target: target,
|
17
|
+
label: association.macro.to_s.camelize,
|
18
|
+
name: association.name.to_s,
|
19
|
+
properties: build_properties
|
20
|
+
)
|
21
|
+
end
|
22
|
+
|
23
|
+
private
|
24
|
+
|
25
|
+
def build_properties
|
26
|
+
{
|
27
|
+
polymorphic: polymorphic?,
|
28
|
+
through: through?,
|
29
|
+
foreign_key: foreign_key,
|
30
|
+
foreign_type: foreign_type,
|
31
|
+
type: type,
|
32
|
+
dependent: dependent,
|
33
|
+
class_name: class_name,
|
34
|
+
optional: optional?
|
35
|
+
}
|
36
|
+
end
|
37
|
+
|
38
|
+
def class_name
|
39
|
+
name = association.polymorphic? ? association.class_name : association.klass.name
|
40
|
+
|
41
|
+
name.delete_prefix("::")
|
42
|
+
end
|
43
|
+
|
44
|
+
def polymorphic?
|
45
|
+
association.polymorphic? || false
|
46
|
+
end
|
47
|
+
|
48
|
+
def through?
|
49
|
+
association.options[:through] || false
|
50
|
+
end
|
51
|
+
|
52
|
+
def foreign_key
|
53
|
+
association.foreign_key.to_s
|
54
|
+
end
|
55
|
+
|
56
|
+
def foreign_type
|
57
|
+
association.foreign_type.to_s
|
58
|
+
end
|
59
|
+
|
60
|
+
def type
|
61
|
+
association.type
|
62
|
+
end
|
63
|
+
|
64
|
+
def dependent
|
65
|
+
association.options[:dependent]
|
66
|
+
end
|
67
|
+
|
68
|
+
def optional?
|
69
|
+
association.options[:optional] || false
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../relationship"
|
4
|
+
|
5
|
+
module RailsGraph
|
6
|
+
module Graph
|
7
|
+
module Relationships
|
8
|
+
class Attribute < Relationship
|
9
|
+
def initialize(source, target)
|
10
|
+
super(
|
11
|
+
source: source,
|
12
|
+
target: target,
|
13
|
+
label: "HasAttribute",
|
14
|
+
name: target.name,
|
15
|
+
properties: {
|
16
|
+
primary_key: source.properties[:primary_key] == target.name
|
17
|
+
}
|
18
|
+
)
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
require_relative "../relationship"
|
4
|
+
|
5
|
+
module RailsGraph
|
6
|
+
module Graph
|
7
|
+
module Relationships
|
8
|
+
class Inheritance < Relationship
|
9
|
+
def initialize(source, target)
|
10
|
+
super(
|
11
|
+
source: source,
|
12
|
+
target: target,
|
13
|
+
label: "InheritsFrom",
|
14
|
+
name: target.name,
|
15
|
+
properties: {}
|
16
|
+
)
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
@@ -0,0 +1,31 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
module RailsGraph
|
4
|
+
module Helpers
|
5
|
+
module Associations
|
6
|
+
module_function
|
7
|
+
|
8
|
+
def source_identifier(association)
|
9
|
+
RailsGraph::Helpers::Models.identifier(association.active_record)
|
10
|
+
end
|
11
|
+
|
12
|
+
def source_node(graph, association)
|
13
|
+
identifier = source_identifier(association)
|
14
|
+
|
15
|
+
graph.node(identifier)
|
16
|
+
end
|
17
|
+
|
18
|
+
def target_identifier(association)
|
19
|
+
return "PolymorphicModel" if association.polymorphic?
|
20
|
+
|
21
|
+
RailsGraph::Helpers::Models.identifier(association.klass)
|
22
|
+
end
|
23
|
+
|
24
|
+
def target_node(graph, association)
|
25
|
+
identifier = target_identifier(association)
|
26
|
+
|
27
|
+
graph.node(identifier)
|
28
|
+
end
|
29
|
+
end
|
30
|
+
end
|
31
|
+
end
|