graph2relational 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: ffd5eda800a15b74f1843d5e5e32c9063d8b2646
4
- data.tar.gz: a10dc8539499cb64bbcbd88355bfa2a064ce5970
3
+ metadata.gz: 4707cb31fae3fc71e5cfa92a2a98378c1637347d
4
+ data.tar.gz: 3ea233af867720ecc8a4e11a6213da93b8ec82e1
5
5
  SHA512:
6
- metadata.gz: aa6904f22f311b822dad0cfa1575b155cf1b3e03b58a1316eea3f026e4f69a7fc34984f242044c8ed2ebbf75dee188181a82c0f03d97dbb973a18d6cfb2bb6ea
7
- data.tar.gz: 656a7e830a82e14f0fece65483f6efe32b9c82ba8af15f225839c04037623784ba6e9a09b3455fdbd5a97ec98365116837aab9d1c63366c609ebed3acc1c2fb1
6
+ metadata.gz: 1451c83f93957bd2d5a14534cfdc3974f9c61ed4890688c6f653200cb2df5591fc9c0ef320193b57ca0453aed467cdaba0c8714d0c4a7d378fbd93b9df36b6c3
7
+ data.tar.gz: 101e107513aa533ff66bf4f130406883de8962016f106c054864ed5cb655fb660f24242bef7057bc4d9cf689d8d9a601402809c1f08d2b5ed202c597a0448c0c
@@ -15,8 +15,12 @@ require 'graph2relational/neo4j-database'
15
15
  require 'graph2relational/neo4j-connection'
16
16
 
17
17
  # RDBMS require
18
+ require 'graph2relational/rdbms'
18
19
  require 'graph2relational/rdbms-database'
19
20
  require 'graph2relational/rdbms-connection'
20
21
  require 'graph2relational/rdbms-table'
21
22
  require 'graph2relational/rdbms-join-table'
22
23
  require 'graph2relational/rdbms-column'
24
+
25
+ # Sequel extensions
26
+ Sequel.extension :inflector
@@ -5,10 +5,6 @@ module G2R
5
5
  @conn = Neography::Rest.new(options)
6
6
  end
7
7
 
8
- def query_data(cypher)
9
- query(cypher)['data']
10
- end
11
-
12
8
  def query_columns(cypher)
13
9
  columns = Set.new
14
10
  query(cypher)['data'].each do |row|
@@ -18,6 +14,15 @@ module G2R
18
14
  columns.to_a
19
15
  end
20
16
 
17
+ def query_data(cypher)
18
+ query(cypher)['data']
19
+ end
20
+
21
+ def query_hash(cypher)
22
+ results = query(cypher)
23
+ results["data"].map {|row| Hash[*results["columns"].zip(row).flatten] }
24
+ end
25
+
21
26
  def query(cypher)
22
27
  @conn.execute_query(cypher)
23
28
  end
@@ -46,8 +46,8 @@ module G2R
46
46
  end
47
47
 
48
48
  def label_data(label)
49
- return_clause = label_attributes(label).map {|column| "n.#{column}"}.join(", ")
50
- @conn.query_data("MATCH (n:#{label}) RETURN id(n), #{return_clause}")
49
+ return_clause = label_attributes(label).map {|column| "n.#{column} as #{column}"}.join(", ")
50
+ @conn.query_hash("MATCH (n:#{label}) RETURN id(n) as id, #{return_clause}")
51
51
  end
52
52
 
53
53
  # ==========================================================================
@@ -4,32 +4,48 @@ module G2R
4
4
  attr_accessor :name
5
5
 
6
6
  def initialize(name)
7
- @name = name.downcase.to_sym
7
+ @name = RDBMS.transform_name(name)
8
8
  @primary_key = false
9
9
  @foreign_key = false
10
10
  end
11
11
 
12
+ def ==(other_column)
13
+ @name == other_column.name
14
+ end
15
+
16
+ # ========================================================================
17
+ # PRIMARY KEY
18
+ # ========================================================================
12
19
  # Define the column as a primary key
13
20
  def primary_key
14
21
  @primary_key = true
15
22
  self
16
23
  end
17
24
 
18
- # Define the column as a foreign key
19
- def foreign_key
20
- @foreign_key = true
21
- self
22
- end
23
-
24
25
  # Checks if the column is a primary key
25
26
  def primary_key?
26
27
  @primary_key
27
28
  end
28
29
 
30
+ # ========================================================================
31
+ # FOREIGN KEY
32
+ # ========================================================================
33
+ # Define the column as a foreign key
34
+ def foreign_key(target_table)
35
+ @foreign_key = true
36
+ @target_table = RDBMS.transform_name(target_table)
37
+ self
38
+ end
39
+
29
40
  # Check if the column is a foreign key
30
41
  def foreign_key?
31
42
  @foreign_key
32
43
  end
44
+
45
+ # Table the foreign key is targeting
46
+ def target_table
47
+ @target_table
48
+ end
33
49
  end
34
50
  end
35
51
  end
@@ -8,18 +8,19 @@ module G2R
8
8
  end
9
9
 
10
10
  def create_table(table)
11
- @db.create_table! table.name do
11
+ @db.create_table! table.name.to_sym do
12
12
 
13
13
  table.columns.each do |column|
14
14
  # primary key
15
15
  if column.primary_key?
16
- primary_key column.name
16
+ primary_key column.name.to_sym
17
17
  # foreign key
18
18
  elsif column.foreign_key?
19
- Integer column.name
19
+ foreign_key column.name.to_sym, column.target_table.to_sym
20
+ index column.name.to_sym
20
21
  # common column
21
22
  else
22
- String column.name
23
+ String column.name.to_sym
23
24
  end
24
25
  end
25
26
  end
@@ -33,12 +33,12 @@ module G2R
33
33
  reset_data()
34
34
 
35
35
  # create tables
36
- puts "Creating base tables"
36
+ puts "Creating base tables schema"
37
37
  base_tables.each do |table|
38
38
  @conn.create_table(table)
39
39
  end
40
40
 
41
- puts "Creating relationship tables"
41
+ puts "Creating relationship tables schema"
42
42
  relationship_tables.each do |table|
43
43
  @conn.create_table(table)
44
44
  end
@@ -72,18 +72,24 @@ module G2R
72
72
  @base_tables = @source.labels.map do |label|
73
73
 
74
74
  # if excluding label, do not transform into base table
75
- next if exclude? label
75
+ next if exclude_label? label
76
76
 
77
77
  # generate table
78
78
  table = Table.new(label)
79
79
 
80
80
  # generate primary key
81
- table.add_columns(Column.new(:id).primary_key)
81
+ table.add_columns(Column.new('id').primary_key)
82
82
 
83
- # generate columns
83
+ # generate schema columns
84
84
  columns = @source.label_attributes(label).map {|attribute| Column.new(attribute)}
85
85
  table.add_columns(columns)
86
86
 
87
+ # add forced columns
88
+ if @options.has_key? :additional_base_columns
89
+ forced_columns = @options[:additional_base_columns].map {|name| Column.new(name)}
90
+ table.add_columns(forced_columns)
91
+ end
92
+
87
93
  # generate data
88
94
  label_data = @source.label_data(label)
89
95
  table.add_data(label_data)
@@ -104,26 +110,28 @@ module G2R
104
110
  @relationship_tables = @source.labels.flat_map do |label|
105
111
 
106
112
  # if excluding label, do not transform into relationship table
107
- next if exclude? label
113
+ next if exclude_label? label
108
114
 
109
115
  @source.label_relationships(label).map do |relationship|
110
116
  relationship, target_label = relationship
111
117
 
112
118
  # if excluding label, do not transform into relationship table
113
- next if exclude? target_label
119
+ next if exclude_relationship? relationship
120
+ next if exclude_label? target_label
114
121
 
115
122
  # gerarate table
116
- table_name = "#{label}_#{relationship}_#{target_label}"
117
- table = JoinTable.new(table_name)
118
-
119
- # generate keys
120
- table.source = label
121
- table.target = target_label
123
+ table = JoinTable.new(label, relationship, target_label)
122
124
 
123
125
  # generate columns
124
126
  columns = @source.relationship_attributes(label, relationship, target_label).map {|attribute| Column.new(attribute)}
125
127
  table.add_columns(columns)
126
128
 
129
+ # add forced columns
130
+ if @options.has_key? :additional_relationship_columns
131
+ forced_columns = @options[:additional_relationship_columns].map {|name| Column.new(name)}
132
+ table.add_columns(forced_columns)
133
+ end
134
+
127
135
  # generate data
128
136
  relationship_data = @source.relationship_data(label, relationship, target_label)
129
137
  table.add_data(relationship_data)
@@ -137,9 +145,18 @@ module G2R
137
145
  @relationship_tables
138
146
  end
139
147
 
148
+ # ========================================================================
149
+ # CHECKS
150
+ # ========================================================================
151
+
140
152
  # Check if a label should be excluded and not be transformed into a table
141
- def exclude?(label)
142
- @options.has_key? :exclude and @options[:exclude].include? label
153
+ def exclude_label?(label)
154
+ @options.has_key? :exclude_labels and @options[:exclude_labels].include? label
155
+ end
156
+
157
+ # Check if a relationship should be excluded and not be transformed into a relationship table
158
+ def exclude_relationship?(relationship)
159
+ @options.has_key? :exclude_relationships and @options[:exclude_relationships].include? relationship
143
160
  end
144
161
  end
145
162
  end
@@ -3,40 +3,44 @@ module G2R
3
3
 
4
4
  class JoinTable < Table
5
5
 
6
+ def initialize(source_table, relationship, target_table)
7
+ # parent initialization
8
+ super("")
9
+
10
+ # additiional initialization
11
+ table_name = "#{source_table}_#{relationship}_#{target_table}"
12
+ @name = RDBMS.transform_name(table_name)
13
+
14
+ @source_table = RDBMS.transform_name(source_table)
15
+ @target_table = RDBMS.transform_name(target_table)
16
+ end
17
+
6
18
  # Additionally return the source and target column ids plus all defined columns
7
19
  def columns
8
20
  [source_column, target_column] + super
9
21
  end
10
22
 
11
23
  def source_column
12
- Column.new(source + "_id").foreign_key
24
+ Column.new(source_table + "_id").foreign_key(source_table)
13
25
  end
14
26
 
15
27
  def target_column
16
- if source != target
17
- Column.new(target + "_id").foreign_key
28
+ if source_table != target_table
29
+ Column.new(target_table + "_id").foreign_key(target_table)
18
30
  else
19
- Column.new(target + "_id_2").foreign_key
31
+ Column.new(target_table + "_id_2").foreign_key(target_table)
20
32
  end
21
33
  end
22
34
 
23
35
  # ==========================================================================
24
36
  # ACESSORS
25
37
  # ==========================================================================
26
- def source=(source)
27
- @source = source
28
- end
29
-
30
- def source
31
- @source
32
- end
33
-
34
- def target=(target)
35
- @target = target
38
+ def source_table
39
+ @source_table
36
40
  end
37
41
 
38
- def target
39
- @target
42
+ def target_table
43
+ @target_table
40
44
  end
41
45
  end
42
46
  end
@@ -3,21 +3,36 @@ module G2R
3
3
  class Table
4
4
 
5
5
  def initialize(name)
6
- @name = name.downcase.to_sym
6
+ @name = RDBMS.transform_name(name)
7
7
  @columns = []
8
8
  @data = []
9
9
  end
10
10
 
11
+ def ==(other_table)
12
+ @name == other_table.name
13
+ end
14
+
11
15
  def name
12
16
  @name
13
17
  end
14
18
 
15
19
  def add_columns(columns)
16
- if columns.class == Array
17
- @columns += columns
18
- else
19
- @columns << columns
20
+ # transform string into array
21
+ if columns.class != Array
22
+ columns = [columns]
20
23
  end
24
+
25
+ # filter out columns that already exists
26
+ columns = columns.map do |column|
27
+ if @columns.include? column
28
+ nil
29
+ else
30
+ column
31
+ end
32
+ end.compact
33
+
34
+ # append columns
35
+ @columns += columns
21
36
  end
22
37
 
23
38
  def columns
@@ -0,0 +1,16 @@
1
+ module G2R
2
+ module RDBMS
3
+
4
+ def self.transform_name(name)
5
+ name = name.to_s if name.class == Symbol
6
+
7
+ # sequel underscore (handles CamelCase)
8
+ name = name.underscore
9
+
10
+ # space to underscore
11
+ name = name.gsub(/\s/, '_')
12
+
13
+ name
14
+ end
15
+ end
16
+ end
@@ -9,7 +9,11 @@ module G2R
9
9
 
10
10
  def parse()
11
11
  # default values
12
- options = {:input => nil, :output => nil, :exclude => []}
12
+ options = {
13
+ :input => nil, :output => nil,
14
+ :additional_base_columns => [], :additional_relationship_columns => [],
15
+ :exclude_labels => [], :exclude_relationships => []
16
+ }
13
17
 
14
18
  # display help if no args
15
19
  ARGV << '-h' if ARGV.empty?
@@ -28,9 +32,22 @@ module G2R
28
32
  options[:output] = output_connection
29
33
  end
30
34
 
35
+ # base columns to always be created
36
+ opts.on("--additional-base-columns COLUMNS", "Base table columns (separated by comma) that should always be created, even if they are not found in Neo4J schema") do |columns|
37
+ options[:additional_base_columns] = columns.split(",").map{|column| column.strip}
38
+ end
39
+
40
+ opts.on("--additional-relationships-columns COLUMNS", "Relationship table columns (separated by comma) that should always be created, even if they are not found in Neo4J schema") do |columns|
41
+ options[:additional_relationship_columns] = columns.split(",").map{|column| column.strip}
42
+ end
43
+
31
44
  # exclusion
32
- opts.on("-x EXCLUSION", "--exclude EXCLUSION", "Neo4J labels (separated by comma) to exclude from the conversion") do |exclude|
33
- options[:exclude] = exclude.split(",").map{|exclude| exclude.strip}
45
+ opts.on("--exclude-labels EXCLUSION", "Neo4J labels (separated by comma) to exclude from the conversion") do |exclude|
46
+ options[:exclude_labels] = exclude.split(",").map{|exclude| exclude.strip}
47
+ end
48
+
49
+ opts.on("--exclude-relationships EXCLUSION", "Neo4J relationships (separated by comma) to exclude from the conversion") do |exclude|
50
+ options[:exclude_relationships] = exclude.split(",").map{|exclude| exclude.strip}
34
51
  end
35
52
 
36
53
  # help
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: graph2relational
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Renato Dinhani Conceição
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2016-03-25 00:00:00.000000000 Z
11
+ date: 2016-03-28 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: neography
@@ -38,6 +38,34 @@ dependencies:
38
38
  - - "~>"
39
39
  - !ruby/object:Gem::Version
40
40
  version: '4.32'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rspec
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - ">="
46
+ - !ruby/object:Gem::Version
47
+ version: '0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - ">="
53
+ - !ruby/object:Gem::Version
54
+ version: '0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rake
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - ">="
60
+ - !ruby/object:Gem::Version
61
+ version: '0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - ">="
67
+ - !ruby/object:Gem::Version
68
+ version: '0'
41
69
  description: Converts a Neo4J graph database to a supported RDBMS database automatically
42
70
  generating tables from its labels, relationships and attributes
43
71
  email: renatodinhani@gmail.com
@@ -55,6 +83,7 @@ files:
55
83
  - lib/graph2relational/rdbms-database.rb
56
84
  - lib/graph2relational/rdbms-join-table.rb
57
85
  - lib/graph2relational/rdbms-table.rb
86
+ - lib/graph2relational/rdbms.rb
58
87
  - lib/graph2relational/util-commandline-parser.rb
59
88
  homepage: https://github.com/renatodinhani/graph2relational
60
89
  licenses: