graph2relational 0.0.1 → 0.0.2

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
  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: