rails_graph 0.1.0 → 0.3.0

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: 49ba4bf9a585c25b02f0b15717a240503ed5edcf61fc751df0f782a5d5fb94c5
4
- data.tar.gz: 64610ec973417724321cc32dbfbc8dd7688474625b7c3df354dd9fd760220874
3
+ metadata.gz: 2aa9e5821416a34e7eca9ba18199bea6007190821c50cabb84147db6232b06e2
4
+ data.tar.gz: f54cb43940dba30d7ddc5915cb8669601d0e05b9b5eb4582c18a504859101ed0
5
5
  SHA512:
6
- metadata.gz: 753af0fc868143bdb6c6636fc9a51bb4254486851f65308ad8dea0ee83f60a97a6d699d5050c41b2c9750c654940a81603c9d740b0f624ff919edc851e70b037
7
- data.tar.gz: bc15a08314849217fa3e71c8ab9d9640c5b611b56c9ec9f98b22009487e6c6fce2b436b733a304cb7414bcb0081a98b393741c41007a7752bde4d391719a782e
6
+ metadata.gz: 714e4e3d097f8fda7958665d9f4f8ee0ca78978ecab77be2a59ad84fa1921c3204ae93d111072882068ce33ee3966786a3d7473d787e275077d61785f105815a
7
+ data.tar.gz: f3889f7437868743a38971f1808e2b3e9d6ac8445a8567f3e96ebb7722d35a24795830f220bdf7eeb1940bfefe472c1cc33f2539a4bd380358af006ad4c62035
data/Gemfile.lock CHANGED
@@ -1,7 +1,7 @@
1
1
  PATH
2
2
  remote: .
3
3
  specs:
4
- rails_graph (0.1.0)
4
+ rails_graph (0.3.0)
5
5
  activerecord (>= 6.0, < 7.1)
6
6
  neo4j-ruby-driver (>= 4.4.0.alpha.8)
7
7
  railties (>= 6.0, < 7.1)
@@ -9,83 +9,83 @@ PATH
9
9
  GEM
10
10
  remote: https://rubygems.org/
11
11
  specs:
12
- actionpack (7.0.4)
13
- actionview (= 7.0.4)
14
- activesupport (= 7.0.4)
15
- rack (~> 2.0, >= 2.2.0)
12
+ actionpack (7.0.5)
13
+ actionview (= 7.0.5)
14
+ activesupport (= 7.0.5)
15
+ rack (~> 2.0, >= 2.2.4)
16
16
  rack-test (>= 0.6.3)
17
17
  rails-dom-testing (~> 2.0)
18
18
  rails-html-sanitizer (~> 1.0, >= 1.2.0)
19
- actionview (7.0.4)
20
- activesupport (= 7.0.4)
19
+ actionview (7.0.5)
20
+ activesupport (= 7.0.5)
21
21
  builder (~> 3.1)
22
22
  erubi (~> 1.4)
23
23
  rails-dom-testing (~> 2.0)
24
24
  rails-html-sanitizer (~> 1.1, >= 1.2.0)
25
- activemodel (7.0.4)
26
- activesupport (= 7.0.4)
27
- activerecord (7.0.4)
28
- activemodel (= 7.0.4)
29
- activesupport (= 7.0.4)
30
- activesupport (7.0.4)
25
+ activemodel (7.0.5)
26
+ activesupport (= 7.0.5)
27
+ activerecord (7.0.5)
28
+ activemodel (= 7.0.5)
29
+ activesupport (= 7.0.5)
30
+ activesupport (7.0.5)
31
31
  concurrent-ruby (~> 1.0, >= 1.0.2)
32
32
  i18n (>= 1.6, < 2)
33
33
  minitest (>= 5.1)
34
34
  tzinfo (~> 2.0)
35
35
  ast (2.4.2)
36
- async (2.1.0)
36
+ async (2.5.1)
37
37
  console (~> 1.10)
38
- io-event (~> 1.0.0)
38
+ io-event (~> 1.1)
39
39
  timers (~> 4.1)
40
- async-io (1.34.0)
40
+ async-io (1.34.3)
41
41
  async
42
- async-pool (0.3.12)
43
- async (>= 1.25)
44
42
  builder (3.2.4)
45
- concurrent-ruby (1.1.10)
46
- console (1.15.3)
43
+ concurrent-ruby (1.2.2)
44
+ connection_pool (2.4.1)
45
+ console (1.16.2)
47
46
  fiber-local
48
47
  crass (1.0.6)
49
48
  diff-lcs (1.5.0)
50
- erubi (1.11.0)
49
+ erubi (1.12.0)
51
50
  fiber-local (1.0.0)
52
- i18n (1.12.0)
51
+ i18n (1.13.0)
53
52
  concurrent-ruby (~> 1.0)
54
- io-event (1.0.9)
53
+ io-event (1.2.2)
55
54
  json (2.6.2)
56
- loofah (2.19.0)
55
+ loofah (2.21.3)
57
56
  crass (~> 1.0.2)
58
- nokogiri (>= 1.5.9)
57
+ nokogiri (>= 1.12.0)
59
58
  method_source (1.0.0)
60
- mini_portile2 (2.8.0)
61
- minitest (5.16.3)
62
- neo4j-ruby-driver (4.4.0.alpha.8)
59
+ mini_portile2 (2.8.2)
60
+ minitest (5.18.0)
61
+ neo4j-ruby-driver (4.4.4)
63
62
  activesupport
64
63
  async-io
65
- async-pool
64
+ connection_pool
66
65
  zeitwerk (>= 2.1.10)
67
- nokogiri (1.13.8)
68
- mini_portile2 (~> 2.8.0)
66
+ nokogiri (1.15.2)
67
+ mini_portile2 (~> 2.8.2)
69
68
  racc (~> 1.4)
70
- nokogiri (1.13.8-arm64-darwin)
69
+ nokogiri (1.15.2-arm64-darwin)
71
70
  racc (~> 1.4)
72
- nokogiri (1.13.8-x86_64-linux)
71
+ nokogiri (1.15.2-x86_64-linux)
73
72
  racc (~> 1.4)
74
73
  parallel (1.22.1)
75
74
  parser (3.1.2.1)
76
75
  ast (~> 2.4.1)
77
- racc (1.6.0)
78
- rack (2.2.4)
79
- rack-test (2.0.2)
76
+ racc (1.6.2)
77
+ rack (2.2.7)
78
+ rack-test (2.1.0)
80
79
  rack (>= 1.3)
81
80
  rails-dom-testing (2.0.3)
82
81
  activesupport (>= 4.2.0)
83
82
  nokogiri (>= 1.6)
84
- rails-html-sanitizer (1.4.3)
85
- loofah (~> 2.3)
86
- railties (7.0.4)
87
- actionpack (= 7.0.4)
88
- activesupport (= 7.0.4)
83
+ rails-html-sanitizer (1.6.0)
84
+ loofah (~> 2.21)
85
+ nokogiri (~> 1.14)
86
+ railties (7.0.5)
87
+ actionpack (= 7.0.5)
88
+ activesupport (= 7.0.5)
89
89
  method_source
90
90
  rake (>= 12.2)
91
91
  thor (~> 1.0)
@@ -120,12 +120,12 @@ GEM
120
120
  rubocop-ast (1.21.0)
121
121
  parser (>= 3.1.1.0)
122
122
  ruby-progressbar (1.11.0)
123
- thor (1.2.1)
124
- timers (4.3.4)
125
- tzinfo (2.0.5)
123
+ thor (1.2.2)
124
+ timers (4.3.5)
125
+ tzinfo (2.0.6)
126
126
  concurrent-ruby (~> 1.0)
127
127
  unicode-display_width (2.3.0)
128
- zeitwerk (2.6.0)
128
+ zeitwerk (2.6.8)
129
129
 
130
130
  PLATFORMS
131
131
  arm64-darwin-21
data/README.md CHANGED
@@ -1,5 +1,7 @@
1
1
  # RailsGraph
2
2
 
3
+ [![Gem Version](https://badge.fury.io/rb/rails_graph.svg)](https://badge.fury.io/rb/rails_graph)
4
+
3
5
  Graph visualization for Rails applications using [Neo4j Browser](https://neo4j.com/docs/browser-manual/current/).
4
6
 
5
7
  Gain visibility on your Rails application data model and identify bottlenecks. It is an ERD, but interactive and queryable using [Cypher](https://neo4j.com/developer/cypher/).
@@ -8,6 +10,7 @@ Gain visibility on your Rails application data model and identify bottlenecks. I
8
10
 
9
11
  ## Features
10
12
 
13
+ - Application Databases and Tables
11
14
  - ActiveRecord Models
12
15
  - Metadata, e.g size, indexes
13
16
  - Columns (disabled by default)
@@ -20,6 +23,7 @@ Gain visibility on your Rails application data model and identify bottlenecks. I
20
23
  - Support for Polymorphic Associations
21
24
  - ActiveRecord Abstract models
22
25
  - Class Hierarchy
26
+ - [Packwerk](https://github.com/Shopify/packwerk) packages (disabled by default)
23
27
 
24
28
  ## Installation
25
29
 
@@ -59,10 +63,19 @@ RailsGraph.configure do |config|
59
63
  config.include_classes = [ActsAsTaggableOn::Tag, ActsAsTaggableOn::Tagging]
60
64
 
61
65
  # Configure Columns parsing
66
+ # default false
62
67
  config.columns = true
63
68
 
64
69
  # Configure Class Hierarchy parsing
65
70
  config.inheritance = true
71
+
72
+ # Configure Database entities
73
+ # default true
74
+ config.database = false
75
+
76
+ # Configure inclusion of Packwerk packages
77
+ # default false
78
+ config.include_packwerk = true
66
79
  end
67
80
  ```
68
81
 
@@ -6,16 +6,26 @@ require_relative "../graph/relationship"
6
6
 
7
7
  require_relative "../graph/nodes/abstract_model"
8
8
  require_relative "../graph/nodes/column"
9
+ require_relative "../graph/nodes/database"
9
10
  require_relative "../graph/nodes/model"
11
+ require_relative "../graph/nodes/pack"
12
+ require_relative "../graph/nodes/table"
10
13
  require_relative "../graph/nodes/virtual_model"
11
14
 
12
15
  require_relative "../graph/relationships/association"
13
16
  require_relative "../graph/relationships/attribute"
14
17
  require_relative "../graph/relationships/inheritance"
18
+ require_relative "../graph/relationships/pack_dependency"
19
+ require_relative "../graph/relationships/pack_model"
15
20
 
16
21
  require_relative "../helpers/associations"
17
22
  require_relative "../helpers/models"
18
23
 
24
+ require_relative "./builders/associations"
25
+ require_relative "./builders/models"
26
+ require_relative "./builders/packs"
27
+ require_relative "./builders/databases"
28
+
19
29
  module RailsGraph
20
30
  module Commands
21
31
  class BuildGraph
@@ -24,89 +34,33 @@ module RailsGraph
24
34
  end
25
35
 
26
36
  def call
27
- polymorphic_node = RailsGraph::Graph::Nodes::VirtualModel.new("PolymorphicModel")
28
- graph.add_node(polymorphic_node)
37
+ setup_generic_nodes
29
38
 
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?
39
+ RailsGraph::Commands::Builders::Databases.enrich(graph: graph) if configuration.databases?
40
+ RailsGraph::Commands::Builders::Models.enrich(inspector: inspector, graph: graph, classes: classes,
41
+ configuration: configuration)
42
+ RailsGraph::Commands::Builders::Packs.enrich(graph: graph) if configuration.include_packwerk?
37
43
 
38
44
  graph
39
45
  end
40
46
 
41
47
  private
42
48
 
43
- attr_reader :configuration, :classes, :graph
49
+ attr_reader :configuration, :classes, :graph, :inspector
44
50
 
45
51
  def initialize(configuration:)
46
52
  @configuration = configuration
47
53
  @classes = ActiveRecord::Base.descendants + configuration.include_classes
48
54
  @graph = RailsGraph::Graph::Graph.new
55
+ @inspector = RailsGraph::Inspector.new
49
56
  end
50
57
 
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)
58
+ def setup_generic_nodes
59
+ polymorphic_node = RailsGraph::Graph::Nodes::VirtualModel.new("PolymorphicModel")
60
+ graph.add_node(polymorphic_node)
105
61
 
106
- relationship = RailsGraph::Graph::Relationships::Association.new(association, source_node, target_node)
107
- graph.add_relationship(relationship)
108
- end
109
- end
62
+ active_record_base_node = RailsGraph::Graph::Nodes::AbstractModel.new(ActiveRecord::Base)
63
+ graph.add_node(active_record_base_node)
110
64
  end
111
65
  end
112
66
  end
@@ -0,0 +1,63 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsGraph
4
+ module Commands
5
+ module Builders
6
+ class Associations
7
+ attr_reader :graph, :inspector
8
+
9
+ def self.enrich(...)
10
+ new(...).enrich
11
+ end
12
+
13
+ def enrich
14
+ build_associations_relationships
15
+ end
16
+
17
+ private
18
+
19
+ attr_reader :classes
20
+
21
+ def initialize(inspector:, graph:, classes:)
22
+ @inspector = inspector
23
+ @graph = graph
24
+ @classes = classes
25
+ end
26
+
27
+ def build_associations_relationships
28
+ classes.each do |model|
29
+ model.reflect_on_all_associations.each do |association|
30
+ association.check_validity!
31
+
32
+ source_node, target_node = fetch_association_nodes(graph, association)
33
+ next report_invalid_class(model) if source_node.nil? || target_node.nil?
34
+
35
+ add_relationship(association, source_node, target_node)
36
+ rescue ActiveRecord::ActiveRecordError => _e
37
+ report_invalid_association(association)
38
+ end
39
+ end
40
+ end
41
+
42
+ def fetch_association_nodes(graph, association)
43
+ source_node = RailsGraph::Helpers::Associations.source_node(graph, association)
44
+ target_node = RailsGraph::Helpers::Associations.target_node(graph, association)
45
+ [source_node, target_node]
46
+ end
47
+
48
+ def add_relationship(association, source_node, target_node)
49
+ relationship = RailsGraph::Graph::Relationships::Association.new(association, source_node, target_node)
50
+ graph.add_relationship(relationship)
51
+ end
52
+
53
+ def report_invalid_association(association)
54
+ inspector.add_association(association)
55
+ end
56
+
57
+ def report_invalid_class(klass)
58
+ inspector.add_class(klass)
59
+ end
60
+ end
61
+ end
62
+ end
63
+ end
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsGraph
4
+ module Commands
5
+ module Builders
6
+ class Databases
7
+ def self.enrich(graph:)
8
+ new(graph: graph).enrich
9
+
10
+ graph
11
+ end
12
+
13
+ def enrich
14
+ build_databases_nodes
15
+ build_tables_nodes
16
+ end
17
+
18
+ private
19
+
20
+ attr_reader :graph
21
+
22
+ def initialize(graph:)
23
+ @graph = graph
24
+ end
25
+
26
+ def build_databases_nodes
27
+ databases.each do |config|
28
+ node = RailsGraph::Graph::Nodes::Database.new(config)
29
+ graph.add_node(node)
30
+ end
31
+ end
32
+
33
+ def build_tables_nodes
34
+ ActiveRecord::Base.connection_handler.connection_pools.each do |connection_pool|
35
+ database_name = connection_pool.db_config.name
36
+ database_node = graph.node("database_#{database_name}")
37
+
38
+ connection_pool.connection.tables.each do |table|
39
+ table_node = RailsGraph::Graph::Nodes::Table.new(table, database_name)
40
+ graph.add_node(table_node)
41
+
42
+ add_persisted_in_relationship(table_node, database_node)
43
+ end
44
+ end
45
+ end
46
+
47
+ def add_persisted_in_relationship(table_node, database_node)
48
+ relationship = RailsGraph::Graph::Relationship.new(
49
+ source: table_node,
50
+ target: database_node,
51
+ label: "PersistedIn",
52
+ name: "persisted_in",
53
+ properties: {}
54
+ )
55
+
56
+ graph.add_relationship(relationship)
57
+ end
58
+
59
+ def databases
60
+ @databases ||= ActiveRecord::Base.configurations.configs_for(env_name: Rails.env)
61
+ end
62
+ end
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,118 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsGraph
4
+ module Commands
5
+ module Builders
6
+ class Models
7
+ attr_reader :graph, :inspector
8
+
9
+ def self.enrich(...)
10
+ new(...).enrich
11
+ end
12
+
13
+ def enrich
14
+ build_model_nodes
15
+ build_associations
16
+ build_column_nodes if configuration.columns?
17
+ build_model_table_relationships if configuration.databases?
18
+ build_inheritance_relationships if configuration.inheritance?
19
+
20
+ inspector.log
21
+ graph
22
+ end
23
+
24
+ private
25
+
26
+ attr_reader :classes, :configuration
27
+
28
+ def initialize(inspector:, graph:, classes:, configuration:)
29
+ @inspector = inspector
30
+ @graph = graph
31
+ @configuration = configuration
32
+ @classes = classes
33
+ end
34
+
35
+ def build_model_nodes
36
+ classes.each do |model|
37
+ if model.abstract_class
38
+ node = RailsGraph::Graph::Nodes::AbstractModel.new(model)
39
+ graph.add_node(node)
40
+ next
41
+ end
42
+
43
+ node = RailsGraph::Graph::Nodes::Model.new(model)
44
+ graph.add_node(node)
45
+ end
46
+ end
47
+
48
+ def build_associations
49
+ Builders::Associations.enrich(inspector: inspector, graph: graph, classes: classes)
50
+ end
51
+
52
+ def build_column_nodes
53
+ processed = Hash.new(false)
54
+
55
+ classes.each do |model|
56
+ next if model.attribute_names.empty?
57
+
58
+ identifier = RailsGraph::Helpers::Models.identifier(model)
59
+ node = graph.node(identifier)
60
+
61
+ next if processed[node.id]
62
+
63
+ processed[node.id] = true
64
+ add_column_nodes(model: model, node: node)
65
+ end
66
+ end
67
+
68
+ def build_inheritance_relationships
69
+ classes.each do |model|
70
+ identifier = RailsGraph::Helpers::Models.identifier(model)
71
+ node = graph.node(identifier)
72
+
73
+ superclass_node_identifier = RailsGraph::Helpers::Models.identifier(model.superclass)
74
+ superclass_node = graph.node(superclass_node_identifier)
75
+
76
+ relationship = RailsGraph::Graph::Relationships::Inheritance.new(node, superclass_node)
77
+ graph.add_relationship(relationship)
78
+ end
79
+ end
80
+
81
+ def build_model_table_relationships
82
+ classes.each do |model|
83
+ database_name = model.connection_pool.db_config.name
84
+ table_node = graph.node("table_#{database_name}.#{model.table_name}")
85
+
86
+ next unless table_node
87
+
88
+ identifier = RailsGraph::Helpers::Models.identifier(model)
89
+ node = graph.node(identifier)
90
+
91
+ relationship = build_represents_table_relationship(node, table_node)
92
+ graph.add_relationship(relationship)
93
+ end
94
+ end
95
+
96
+ def build_represents_table_relationship(model, table)
97
+ RailsGraph::Graph::Relationship.new(
98
+ source: model,
99
+ target: table,
100
+ label: "RepresentsTable",
101
+ name: "represents_table",
102
+ properties: {}
103
+ )
104
+ end
105
+
106
+ def add_column_nodes(model:, node:)
107
+ model.columns.each do |column|
108
+ column_node = RailsGraph::Graph::Nodes::Column.new(column)
109
+ graph.add_node(column_node)
110
+
111
+ relationship = RailsGraph::Graph::Relationships::Attribute.new(node, column_node)
112
+ graph.add_relationship(relationship)
113
+ end
114
+ end
115
+ end
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,102 @@
1
+ # frozen_string_literal: true
2
+
3
+ module RailsGraph
4
+ module Commands
5
+ module Builders
6
+ class Packs
7
+ def self.enrich(graph:)
8
+ new(graph: graph).enrich
9
+
10
+ graph
11
+ end
12
+
13
+ def enrich
14
+ build_pack_nodes
15
+ build_pack_relationships
16
+ build_pack_model_relationships
17
+ end
18
+
19
+ private
20
+
21
+ attr_reader :graph
22
+
23
+ def initialize(graph:)
24
+ @graph = graph
25
+ end
26
+
27
+ def build_pack_nodes
28
+ packs.each do |pack|
29
+ name, owner = fetch_pack_attributes(pack)
30
+ node = RailsGraph::Graph::Nodes::Pack.new(name, owner)
31
+ graph.add_node(node)
32
+ end
33
+ end
34
+
35
+ def build_pack_relationships
36
+ packs.each do |pack|
37
+ source_identifier = pack.name
38
+ source_node = graph.node(source_identifier)
39
+
40
+ pack.dependencies.each do |dep|
41
+ target_identifier = dep.gsub("packs/", "")
42
+ target_node = graph.node(target_identifier)
43
+
44
+ relationship = RailsGraph::Graph::Relationships::PackDependency.new(source_node, target_node)
45
+ graph.add_relationship(relationship)
46
+ end
47
+ end
48
+ end
49
+
50
+ def build_pack_model_relationships
51
+ packs.each do |pack|
52
+ next if pack.name == "goals"
53
+
54
+ models = fetch_pack_models(pack: pack)
55
+ models.each do |model|
56
+ add_model_relationship(pack: pack, model: model)
57
+ end
58
+ end
59
+ end
60
+
61
+ def packs
62
+ @packs ||=
63
+ Packwerk::PackageSet.load_all_from("packs").reject do |pack|
64
+ pack.name == "."
65
+ end
66
+ end
67
+
68
+ def fetch_pack_attributes(pack)
69
+ [
70
+ pack.name,
71
+ pack.config["metadata"]["owner"] || pack.config["metadata"]["stewards"]
72
+ ]
73
+ end
74
+
75
+ def fetch_pack_models(pack:)
76
+ generic_path = "packs/#{pack.name}/app/models"
77
+ Dir["#{generic_path}/**/*.rb"].map do |path|
78
+ path
79
+ .gsub(generic_path, "")
80
+ .gsub(".rb", "")
81
+ .prepend(pack.name)
82
+ .camelize
83
+ .constantize
84
+ end
85
+ end
86
+
87
+ def add_model_relationship(pack:, model:)
88
+ return unless model.respond_to?(:descends_from_active_record?)
89
+
90
+ source_identifier = RailsGraph::Helpers::Models.identifier(model)
91
+ target_identifier = pack.name
92
+
93
+ source_node = graph.node(source_identifier)
94
+ target_node = graph.node(target_identifier)
95
+
96
+ relationship = RailsGraph::Graph::Relationships::PackModel.new(source_node, target_node)
97
+ graph.add_relationship(relationship)
98
+ end
99
+ end
100
+ end
101
+ end
102
+ end
@@ -3,10 +3,12 @@
3
3
  module RailsGraph
4
4
  class Configuration
5
5
  attr_reader :include_classes
6
- attr_writer :columns, :inheritance
6
+ attr_writer :columns, :inheritance, :include_packwerk, :databases
7
7
 
8
8
  def initialize
9
9
  @include_classes = []
10
+ @include_packwerk = false
11
+ @databases = true
10
12
  @columns = false
11
13
  @inheritance = true
12
14
  end
@@ -22,5 +24,13 @@ module RailsGraph
22
24
  def inheritance?
23
25
  @inheritance
24
26
  end
27
+
28
+ def include_packwerk?
29
+ @include_packwerk
30
+ end
31
+
32
+ def databases?
33
+ @databases
34
+ end
25
35
  end
26
36
  end
@@ -2,6 +2,6 @@
2
2
 
3
3
  module RailsGraph
4
4
  module Exporters
5
- class Base; end
5
+ class Base; end # rubocop:disable Lint/EmptyClass
6
6
  end
7
7
  end
@@ -11,9 +11,7 @@ module RailsGraph
11
11
 
12
12
  ::Neo4j::Driver::GraphDatabase.driver(host, auth) do |driver|
13
13
  driver.session do |session|
14
- queries = Cypher.build_queries(graph)
15
- queries.shift
16
- queries = queries.join("\n")
14
+ queries = build_query(graph)
17
15
 
18
16
  session.write_transaction do |tx|
19
17
  tx.run(queries, message: "Success!")
@@ -21,6 +19,12 @@ module RailsGraph
21
19
  end
22
20
  end
23
21
  end
22
+
23
+ def self.build_query(graph)
24
+ queries = Cypher.build_queries(graph)
25
+ queries.shift
26
+ queries.join("\n")
27
+ end
24
28
  end
25
29
  end
26
30
  end
@@ -0,0 +1,38 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../node"
4
+
5
+ module RailsGraph
6
+ module Graph
7
+ module Nodes
8
+ class Database < Node
9
+ attr_reader :configs
10
+
11
+ def initialize(configs)
12
+ @configs = configs
13
+
14
+ super(labels: "Database", name: configs.name, properties: build_properties)
15
+ end
16
+
17
+ def identifier
18
+ "database_#{name}"
19
+ end
20
+
21
+ private
22
+
23
+ def build_properties
24
+ {
25
+ pool_size: configs.pool,
26
+ adapter: configs.adapter,
27
+ schema_cache_path: configs.schema_cache_path,
28
+ replica: configs.replica? || false,
29
+ database_name: configs.database,
30
+ reaping_frequency: configs.reaping_frequency,
31
+ min_threads: configs.min_threads,
32
+ max_threads: configs.max_threads
33
+ }
34
+ end
35
+ end
36
+ end
37
+ end
38
+ end
@@ -0,0 +1,29 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../node"
4
+
5
+ module RailsGraph
6
+ module Graph
7
+ module Nodes
8
+ class Pack < Node
9
+ attr_reader :pack_owner
10
+
11
+ def initialize(name, owner)
12
+ @pack_owner = owner
13
+
14
+ super(labels: "Pack", name: name, properties: build_properties)
15
+ end
16
+
17
+ def identifier
18
+ name
19
+ end
20
+
21
+ private
22
+
23
+ def build_properties
24
+ { owner: pack_owner }
25
+ end
26
+ end
27
+ end
28
+ end
29
+ 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 Table < Node
9
+ attr_reader :name, :database_name
10
+
11
+ def initialize(name, database_name)
12
+ @database_name = database_name
13
+
14
+ super(labels: "Table", name: name, properties: build_properties)
15
+ end
16
+
17
+ def identifier
18
+ "table_#{database_name}.#{name}"
19
+ end
20
+
21
+ private
22
+
23
+ def build_properties
24
+ {
25
+ database_name: database_name
26
+ }
27
+ end
28
+ end
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../relationship"
4
+
5
+ module RailsGraph
6
+ module Graph
7
+ module Relationships
8
+ class PackDependency < Relationship
9
+ def initialize(source, target)
10
+ super(
11
+ source: source,
12
+ target: target,
13
+ label: "DependsOnPack",
14
+ name: target.name
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -0,0 +1,20 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative "../relationship"
4
+
5
+ module RailsGraph
6
+ module Graph
7
+ module Relationships
8
+ class PackModel < Relationship
9
+ def initialize(source, target)
10
+ super(
11
+ source: source,
12
+ target: target,
13
+ label: "PartOfPack",
14
+ name: target.name
15
+ )
16
+ end
17
+ end
18
+ end
19
+ end
20
+ end
@@ -6,6 +6,8 @@ module RailsGraph
6
6
  module_function
7
7
 
8
8
  def identifier(model)
9
+ return unless model
10
+
9
11
  model.to_s.delete_prefix("::")
10
12
  end
11
13
  end
@@ -0,0 +1,31 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "set"
4
+
5
+ module RailsGraph
6
+ class Inspector
7
+ def initialize
8
+ @classes = Set.new
9
+ @associations = Set.new
10
+ end
11
+
12
+ def add_class(klass)
13
+ @classes.add(klass)
14
+ end
15
+
16
+ def add_association(association)
17
+ @associations.add(association)
18
+ end
19
+
20
+ def log
21
+ @classes.each do |klass|
22
+ puts "[WARN][RailsGraph]: Invalid class configuration: #{klass}"
23
+ end
24
+
25
+ @associations.each do |association|
26
+ puts "[WARN][RailsGraph]: #{association.name} association defined " \
27
+ "under #{association.active_record.name} class has invalid configurations!"
28
+ end
29
+ end
30
+ end
31
+ end
@@ -1,5 +1,5 @@
1
1
  # frozen_string_literal: true
2
2
 
3
3
  module RailsGraph
4
- VERSION = "0.1.0"
4
+ VERSION = "0.3.0"
5
5
  end
data/lib/rails_graph.rb CHANGED
@@ -7,6 +7,7 @@ require "rails_graph/railtie"
7
7
 
8
8
  require "rails_graph/commands/build_graph"
9
9
  require "rails_graph/commands/export_graph"
10
+ require "rails_graph/inspector"
10
11
 
11
12
  module RailsGraph
12
13
  module_function
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: rails_graph
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.3.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ahmad Elassuty
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2022-10-01 00:00:00.000000000 Z
11
+ date: 2023-05-29 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: activerecord
@@ -85,6 +85,10 @@ files:
85
85
  - graph.svg
86
86
  - lib/rails_graph.rb
87
87
  - lib/rails_graph/commands/build_graph.rb
88
+ - lib/rails_graph/commands/builders/associations.rb
89
+ - lib/rails_graph/commands/builders/databases.rb
90
+ - lib/rails_graph/commands/builders/models.rb
91
+ - lib/rails_graph/commands/builders/packs.rb
88
92
  - lib/rails_graph/commands/export_graph.rb
89
93
  - lib/rails_graph/configuration.rb
90
94
  - lib/rails_graph/error.rb
@@ -97,15 +101,21 @@ files:
97
101
  - lib/rails_graph/graph/node.rb
98
102
  - lib/rails_graph/graph/nodes/abstract_model.rb
99
103
  - lib/rails_graph/graph/nodes/column.rb
104
+ - lib/rails_graph/graph/nodes/database.rb
100
105
  - lib/rails_graph/graph/nodes/model.rb
106
+ - lib/rails_graph/graph/nodes/pack.rb
107
+ - lib/rails_graph/graph/nodes/table.rb
101
108
  - lib/rails_graph/graph/nodes/virtual_model.rb
102
109
  - lib/rails_graph/graph/relationship.rb
103
110
  - lib/rails_graph/graph/relationships/association.rb
104
111
  - lib/rails_graph/graph/relationships/attribute.rb
105
112
  - lib/rails_graph/graph/relationships/inheritance.rb
113
+ - lib/rails_graph/graph/relationships/pack_dependency.rb
114
+ - lib/rails_graph/graph/relationships/pack_model.rb
106
115
  - lib/rails_graph/helpers/associations.rb
107
116
  - lib/rails_graph/helpers/models.rb
108
117
  - lib/rails_graph/helpers/options_parser.rb
118
+ - lib/rails_graph/inspector.rb
109
119
  - lib/rails_graph/railtie.rb
110
120
  - lib/rails_graph/tasks/rails_graph.rake
111
121
  - lib/rails_graph/version.rb