ddl_parser 0.0.9 → 0.0.10
Sign up to get free protection for your applications and to get access to all the features.
- data/.gitignore +1 -0
- data/Vagrantfile +9 -0
- data/lib/ddl_parser/ddl/db2/parser.rb +112 -112
- data/lib/ddl_parser/translator/column.rb +132 -99
- data/lib/ddl_parser/version.rb +1 -1
- data/spec/ddl_parser/ddl/db2/create_table_spec.rb +518 -506
- data/spec/ddl_parser/translator/column_spec.rb +110 -99
- metadata +3 -2
data/.gitignore
CHANGED
data/Vagrantfile
ADDED
@@ -0,0 +1,9 @@
|
|
1
|
+
# -*- mode: ruby -*-
|
2
|
+
# vi: set ft=ruby :
|
3
|
+
|
4
|
+
# Vagrantfile API/syntax version. Don't touch unless you know what you're doing!
|
5
|
+
VAGRANTFILE_API_VERSION = "2"
|
6
|
+
|
7
|
+
Vagrant.configure(VAGRANTFILE_API_VERSION) do |config|
|
8
|
+
config.vm.box = 'thoughtbot/ubuntu-14-04-server-with-laptop'
|
9
|
+
end
|
@@ -1,112 +1,112 @@
|
|
1
|
-
module DDLParser
|
2
|
-
module DDL
|
3
|
-
module DB2
|
4
|
-
class Parser < Parslet::Parser
|
5
|
-
|
6
|
-
include DDLParser::SharedRules::Constants
|
7
|
-
include DDLParser::SharedRules::LogicalOperators
|
8
|
-
include DDLParser::SharedRules::DataTypes
|
9
|
-
|
10
|
-
# column options
|
11
|
-
rule(:option_not_null) { str('not null') }
|
12
|
-
rule(:column_option) { (option_not_null).as(:column_option) }
|
13
|
-
#rule(:lob_options)
|
14
|
-
rule(:primary_key) { (str('primary key') >> spaces >> references).as(:primary_key) }
|
15
|
-
rule(:constraint) { (str('constraint') >> spaces >> identifier.as(:column_name) >> spaces >> (str('unique') | str('foreign key')).as(:constraint_type) >>
|
16
|
-
spaces >> references.as(:constraint_arglist) >> spaces >> reference_clause.maybe).as(:constraint)}
|
17
|
-
#rule(:unique)
|
18
|
-
rule(:references) { lparen >> space? >> arglist >> space? >> rparen }
|
19
|
-
rule(:reference_clause) { str('references') >> spaces >> identifier >> spaces >> references.as(:reference_arglist) >> (identifier >> spaces).repeat }
|
20
|
-
#rule(:check)
|
21
|
-
#rule(:check_condition)
|
22
|
-
#rule(:constraint_attr)
|
23
|
-
rule(:gen_col_def) { str('generated always') | str('generated by default') }
|
24
|
-
rule(:default_value) { const | current_timestamp | function }
|
25
|
-
rule(:default_values) { (default_value >> space?).repeat }
|
26
|
-
rule(:default_clause) { ((str('with') >> space?).maybe >> str('default') >> space? >> default_values).as(:default_clause) }
|
27
|
-
rule(:identity_options) { (str('as identity') >> space? >> lparen >> str('start with') >> spaces >>
|
28
|
-
integer.as(:start_value) >> (comma|space) >> spaces.maybe >>str('increment by') >> spaces >> integer.as(:increment_value)>> (spaces >> str('cache')>>spaces>>integer.as(:cache_value)).maybe >> spaces.maybe >>rparen).as(:identity) }
|
29
|
-
|
30
|
-
rule(:column_options) { ((gen_col_def | column_option | default_clause | identity_options) >> spaces).repeat }
|
31
|
-
|
32
|
-
rule(:column_name) { identifier }
|
33
|
-
rule(:constraint_name) { identifier }
|
34
|
-
rule(:column_sort) { str('ascending') | str('descending')}
|
35
|
-
|
36
|
-
rule(:column_definition) { (column_name.as(:field) >> space.repeat >> data_type >> space.repeat >> (column_options.maybe).as(:options)).as(:column)}
|
37
|
-
|
38
|
-
rule(:index_column_definition) { column_name.as(:field) >> space.repeat >> (column_sort.as(:sort_id) >> space.repeat).maybe }
|
39
|
-
|
40
|
-
rule(:element_list) { (lparen >> space? >> (column_definition | constraint | primary_key) >> space? >>
|
41
|
-
(comma >> space? >> (column_definition | constraint | primary_key) >> space?).repeat >> rparen).as(:elements)
|
42
|
-
}
|
43
|
-
|
44
|
-
rule(:element_list_index) { space? >> index_column_definition >>
|
45
|
-
(comma >> space? >> index_column_definition).repeat
|
46
|
-
}
|
47
|
-
|
48
|
-
rule(:add_constraint_clause) { (str('add constraint') >> space? >>
|
49
|
-
constraint_name.as(:constraint_name) >> space? >>
|
50
|
-
foreign_key_clause.as(:foreign_key_clause)).as(:add_constraint)
|
51
|
-
}
|
52
|
-
rule(:foreign_key_clause) {str('foreign key') >> space? >> lparen >>
|
53
|
-
element_list_index.as(:member_fields) >> space? >> rparen >> space? >>
|
54
|
-
reference_clause.as(:reference_clause) >> space? >>
|
55
|
-
(on_delete_clause.as(:on_delete_clause) >> space?).maybe >>
|
56
|
-
(on_update_clause >> space?).maybe
|
57
|
-
}
|
58
|
-
rule(:on_delete_clause) {str('on delete') >> space? >>
|
59
|
-
(str('no action')|str('restrict')|str('cascade')|str('set null')).as(:on_delete_option) >> space?
|
60
|
-
}
|
61
|
-
rule(:on_update_clause) {str('on update') >> space? >>
|
62
|
-
(str('no action')|str('restrict')).as(:on_update_option) >> space?
|
63
|
-
}
|
64
|
-
|
65
|
-
rule(:alter_table_add_column) do
|
66
|
-
(str('add') >> space? >> (str('column') >> space? >> column_definition) | primary_key).as(:add)
|
67
|
-
end
|
68
|
-
|
69
|
-
rule(:alter_table_element) { (alter_table_add_column | add_constraint_clause) >> spaces.maybe }
|
70
|
-
|
71
|
-
#rule(:alter_table_alter) { }
|
72
|
-
#rule(:alter_table_drop) { }
|
73
|
-
|
74
|
-
rule(:term) { const | item }
|
75
|
-
|
76
|
-
rule(:function) {
|
77
|
-
(identifier.as(:name) >> space? >>
|
78
|
-
lparen >> arglist.as(:arguments) >> rparen).as(:function)
|
79
|
-
}
|
80
|
-
|
81
|
-
rule(:item) { function | identifier | string }
|
82
|
-
rule(:arglist) {
|
83
|
-
item.as(:item) >> (comma >> item.as(:item)).repeat
|
84
|
-
}
|
85
|
-
|
86
|
-
rule(:create_table_statement) {
|
87
|
-
str('create table').as(:operation) >> space? >> (identifier).as(:table_name)
|
88
|
-
}
|
89
|
-
rule(:alter_table_statement) {
|
90
|
-
str('alter table').as(:operation) >> space? >> (identifier).as(:table_name)
|
91
|
-
}
|
92
|
-
rule(:create_index_statement) {
|
93
|
-
str('create').as(:operation) >> (space? >> str('unique').as(:object_property)).maybe >> space? >> str('index').as(:object_type) >> space? >>
|
94
|
-
(identifier).as(:index_name) >> space? >> str('on') >> space? >> (identifier).as(:table_name)
|
95
|
-
}
|
96
|
-
rule(:create_table) {
|
97
|
-
spaces.maybe >> create_table_statement >> spaces >> element_list >> spaces.maybe >> (item >> spaces.maybe).repeat
|
98
|
-
}
|
99
|
-
rule(:alter_table) {
|
100
|
-
spaces.maybe >> alter_table_statement >> spaces >> (alter_table_element.repeat).as(:elements)
|
101
|
-
}
|
102
|
-
rule(:create_index) {
|
103
|
-
spaces.maybe >> create_index_statement >> spaces >> lparen >> element_list_index >> spaces.maybe >> rparen
|
104
|
-
}
|
105
|
-
|
106
|
-
rule(:expression) { create_table | alter_table | create_index}
|
107
|
-
root :expression
|
108
|
-
end
|
109
|
-
end
|
110
|
-
end
|
111
|
-
end
|
112
|
-
|
1
|
+
module DDLParser
|
2
|
+
module DDL
|
3
|
+
module DB2
|
4
|
+
class Parser < Parslet::Parser
|
5
|
+
|
6
|
+
include DDLParser::SharedRules::Constants
|
7
|
+
include DDLParser::SharedRules::LogicalOperators
|
8
|
+
include DDLParser::SharedRules::DataTypes
|
9
|
+
|
10
|
+
# column options
|
11
|
+
rule(:option_not_null) { str('not null') }
|
12
|
+
rule(:column_option) { (option_not_null).as(:column_option) }
|
13
|
+
#rule(:lob_options)
|
14
|
+
rule(:primary_key) { (str('primary key') >> spaces >> references).as(:primary_key) }
|
15
|
+
rule(:constraint) { (str('constraint') >> spaces >> identifier.as(:column_name) >> spaces >> (str('unique') | str('foreign key')).as(:constraint_type) >>
|
16
|
+
spaces >> references.as(:constraint_arglist) >> spaces >> reference_clause.maybe).as(:constraint)}
|
17
|
+
#rule(:unique)
|
18
|
+
rule(:references) { lparen >> space? >> arglist >> space? >> rparen }
|
19
|
+
rule(:reference_clause) { str('references') >> spaces >> identifier >> spaces >> references.as(:reference_arglist) >> (identifier >> spaces).repeat }
|
20
|
+
#rule(:check)
|
21
|
+
#rule(:check_condition)
|
22
|
+
#rule(:constraint_attr)
|
23
|
+
rule(:gen_col_def) { str('generated always') | str('generated by default') }
|
24
|
+
rule(:default_value) { const | current_timestamp | function }
|
25
|
+
rule(:default_values) { (default_value >> space?).repeat }
|
26
|
+
rule(:default_clause) { ((str('with') >> space?).maybe >> str('default') >> space? >> default_values).as(:default_clause) }
|
27
|
+
rule(:identity_options) { (str('as identity') >> space? >> lparen >> str('start with') >> spaces >>
|
28
|
+
integer.as(:start_value) >> (comma|space) >> spaces.maybe >>str('increment by') >> spaces >> integer.as(:increment_value)>> ((comma|space) >> spaces.maybe >> str('cache')>>spaces>>integer.as(:cache_value)).maybe >> spaces.maybe >>rparen).as(:identity) }
|
29
|
+
|
30
|
+
rule(:column_options) { ((gen_col_def | column_option | default_clause | identity_options) >> spaces).repeat }
|
31
|
+
|
32
|
+
rule(:column_name) { identifier }
|
33
|
+
rule(:constraint_name) { identifier }
|
34
|
+
rule(:column_sort) { str('ascending') | str('descending')}
|
35
|
+
|
36
|
+
rule(:column_definition) { (column_name.as(:field) >> space.repeat >> data_type >> space.repeat >> (column_options.maybe).as(:options)).as(:column)}
|
37
|
+
|
38
|
+
rule(:index_column_definition) { column_name.as(:field) >> space.repeat >> (column_sort.as(:sort_id) >> space.repeat).maybe }
|
39
|
+
|
40
|
+
rule(:element_list) { (lparen >> space? >> (column_definition | constraint | primary_key) >> space? >>
|
41
|
+
(comma >> space? >> (column_definition | constraint | primary_key) >> space?).repeat >> rparen).as(:elements)
|
42
|
+
}
|
43
|
+
|
44
|
+
rule(:element_list_index) { space? >> index_column_definition >>
|
45
|
+
(comma >> space? >> index_column_definition).repeat
|
46
|
+
}
|
47
|
+
|
48
|
+
rule(:add_constraint_clause) { (str('add constraint') >> space? >>
|
49
|
+
constraint_name.as(:constraint_name) >> space? >>
|
50
|
+
foreign_key_clause.as(:foreign_key_clause)).as(:add_constraint)
|
51
|
+
}
|
52
|
+
rule(:foreign_key_clause) {str('foreign key') >> space? >> lparen >>
|
53
|
+
element_list_index.as(:member_fields) >> space? >> rparen >> space? >>
|
54
|
+
reference_clause.as(:reference_clause) >> space? >>
|
55
|
+
(on_delete_clause.as(:on_delete_clause) >> space?).maybe >>
|
56
|
+
(on_update_clause >> space?).maybe
|
57
|
+
}
|
58
|
+
rule(:on_delete_clause) {str('on delete') >> space? >>
|
59
|
+
(str('no action')|str('restrict')|str('cascade')|str('set null')).as(:on_delete_option) >> space?
|
60
|
+
}
|
61
|
+
rule(:on_update_clause) {str('on update') >> space? >>
|
62
|
+
(str('no action')|str('restrict')).as(:on_update_option) >> space?
|
63
|
+
}
|
64
|
+
|
65
|
+
rule(:alter_table_add_column) do
|
66
|
+
(str('add') >> space? >> (str('column') >> space? >> column_definition) | primary_key).as(:add)
|
67
|
+
end
|
68
|
+
|
69
|
+
rule(:alter_table_element) { (alter_table_add_column | add_constraint_clause) >> spaces.maybe }
|
70
|
+
|
71
|
+
#rule(:alter_table_alter) { }
|
72
|
+
#rule(:alter_table_drop) { }
|
73
|
+
|
74
|
+
rule(:term) { const | item }
|
75
|
+
|
76
|
+
rule(:function) {
|
77
|
+
(identifier.as(:name) >> space? >>
|
78
|
+
lparen >> arglist.as(:arguments) >> rparen).as(:function)
|
79
|
+
}
|
80
|
+
|
81
|
+
rule(:item) { function | identifier | string }
|
82
|
+
rule(:arglist) {
|
83
|
+
item.as(:item) >> (comma >> item.as(:item)).repeat
|
84
|
+
}
|
85
|
+
|
86
|
+
rule(:create_table_statement) {
|
87
|
+
str('create table').as(:operation) >> space? >> (identifier).as(:table_name)
|
88
|
+
}
|
89
|
+
rule(:alter_table_statement) {
|
90
|
+
str('alter table').as(:operation) >> space? >> (identifier).as(:table_name)
|
91
|
+
}
|
92
|
+
rule(:create_index_statement) {
|
93
|
+
str('create').as(:operation) >> (space? >> str('unique').as(:object_property)).maybe >> space? >> str('index').as(:object_type) >> space? >>
|
94
|
+
(identifier).as(:index_name) >> space? >> str('on') >> space? >> (identifier).as(:table_name)
|
95
|
+
}
|
96
|
+
rule(:create_table) {
|
97
|
+
spaces.maybe >> create_table_statement >> spaces >> element_list >> spaces.maybe >> (item >> spaces.maybe).repeat
|
98
|
+
}
|
99
|
+
rule(:alter_table) {
|
100
|
+
spaces.maybe >> alter_table_statement >> spaces >> (alter_table_element.repeat).as(:elements)
|
101
|
+
}
|
102
|
+
rule(:create_index) {
|
103
|
+
spaces.maybe >> create_index_statement >> spaces >> lparen >> element_list_index >> spaces.maybe >> rparen
|
104
|
+
}
|
105
|
+
|
106
|
+
rule(:expression) { create_table | alter_table | create_index}
|
107
|
+
root :expression
|
108
|
+
end
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
@@ -1,99 +1,132 @@
|
|
1
|
-
class DDLParser::Translator::Column
|
2
|
-
|
3
|
-
def initialize(column_hash)
|
4
|
-
@column_hash = column_hash.is_a?(Hash) ? column_hash : {}
|
5
|
-
end
|
6
|
-
|
7
|
-
def to_hash
|
8
|
-
@column_hash
|
9
|
-
end
|
10
|
-
|
11
|
-
def name
|
12
|
-
@column_hash[:field]
|
13
|
-
end
|
14
|
-
|
15
|
-
def data_type
|
16
|
-
raise "DataType not specified #{@column_hash.inspect}" if @column_hash.nil? || @column_hash[:data_type].nil?
|
17
|
-
if @column_hash[:data_type].is_a?(Hash)
|
18
|
-
@column_hash[:data_type].keys.first
|
19
|
-
else
|
20
|
-
@column_hash[:data_type].to_sym
|
21
|
-
end
|
22
|
-
|
23
|
-
end
|
24
|
-
|
25
|
-
def length
|
26
|
-
case data_type
|
27
|
-
when :decimal
|
28
|
-
"#{precision}.#{scale}".to_f
|
29
|
-
when :char
|
30
|
-
begin
|
31
|
-
@column_hash[:data_type][:char][:length][:integer].to_i
|
32
|
-
rescue
|
33
|
-
raise "DataType CHAR length wrong format #{@column_hash[:data_type].inspect}"
|
34
|
-
end
|
35
|
-
else
|
36
|
-
nil
|
37
|
-
end
|
38
|
-
end
|
39
|
-
|
40
|
-
def precision
|
41
|
-
case data_type
|
42
|
-
when :decimal
|
43
|
-
begin
|
44
|
-
@column_hash[:data_type][:decimal][:precision][:total][:integer].to_i
|
45
|
-
rescue
|
46
|
-
5 # decimal default if no precision present
|
47
|
-
end
|
48
|
-
else
|
49
|
-
nil
|
50
|
-
end
|
51
|
-
end
|
52
|
-
|
53
|
-
def scale
|
54
|
-
case data_type
|
55
|
-
when :decimal
|
56
|
-
begin
|
57
|
-
@column_hash[:data_type][:decimal][:precision][:scale][:integer].to_i
|
58
|
-
rescue
|
59
|
-
0 # decimal default if no scale present
|
60
|
-
end
|
61
|
-
else
|
62
|
-
nil
|
63
|
-
end
|
64
|
-
end
|
65
|
-
|
66
|
-
def options
|
67
|
-
@column_hash[:options] if @column_hash[:options].length > 0
|
68
|
-
end
|
69
|
-
|
70
|
-
def
|
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
|
-
end
|
1
|
+
class DDLParser::Translator::Column
|
2
|
+
|
3
|
+
def initialize(column_hash)
|
4
|
+
@column_hash = column_hash.is_a?(Hash) ? column_hash : {}
|
5
|
+
end
|
6
|
+
|
7
|
+
def to_hash
|
8
|
+
@column_hash
|
9
|
+
end
|
10
|
+
|
11
|
+
def name
|
12
|
+
@column_hash[:field]
|
13
|
+
end
|
14
|
+
|
15
|
+
def data_type
|
16
|
+
raise "DataType not specified #{@column_hash.inspect}" if @column_hash.nil? || @column_hash[:data_type].nil?
|
17
|
+
if @column_hash[:data_type].is_a?(Hash)
|
18
|
+
@column_hash[:data_type].keys.first
|
19
|
+
else
|
20
|
+
@column_hash[:data_type].to_sym
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
24
|
+
|
25
|
+
def length
|
26
|
+
case data_type
|
27
|
+
when :decimal
|
28
|
+
"#{precision}.#{scale}".to_f
|
29
|
+
when :char
|
30
|
+
begin
|
31
|
+
@column_hash[:data_type][:char][:length][:integer].to_i
|
32
|
+
rescue
|
33
|
+
raise "DataType CHAR length wrong format #{@column_hash[:data_type].inspect}"
|
34
|
+
end
|
35
|
+
else
|
36
|
+
nil
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
def precision
|
41
|
+
case data_type
|
42
|
+
when :decimal
|
43
|
+
begin
|
44
|
+
@column_hash[:data_type][:decimal][:precision][:total][:integer].to_i
|
45
|
+
rescue
|
46
|
+
5 # decimal default if no precision present
|
47
|
+
end
|
48
|
+
else
|
49
|
+
nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def scale
|
54
|
+
case data_type
|
55
|
+
when :decimal
|
56
|
+
begin
|
57
|
+
@column_hash[:data_type][:decimal][:precision][:scale][:integer].to_i
|
58
|
+
rescue
|
59
|
+
0 # decimal default if no scale present
|
60
|
+
end
|
61
|
+
else
|
62
|
+
nil
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
def options
|
67
|
+
@column_hash[:options] if @column_hash[:options].length > 0
|
68
|
+
end
|
69
|
+
|
70
|
+
def option(key)
|
71
|
+
# return the right option
|
72
|
+
options.select{|o| o.is_a?(Hash) || o.has_key?(key)}.first
|
73
|
+
end
|
74
|
+
|
75
|
+
def not_null
|
76
|
+
if options.nil?
|
77
|
+
false
|
78
|
+
else
|
79
|
+
options.select{|h|h.has_key?(:column_option) && h.has_value?('not null')}.length > 0
|
80
|
+
end
|
81
|
+
end
|
82
|
+
|
83
|
+
def default_clause
|
84
|
+
unless options.nil?
|
85
|
+
default_value = options.select{|h|h.has_key?(:default_clause)}.first
|
86
|
+
if default_value
|
87
|
+
if default_value[:default_clause].is_a?(Array)
|
88
|
+
default_value[:default_clause].each do |c|
|
89
|
+
# TODO must handle other then integer
|
90
|
+
case c.keys.first
|
91
|
+
when :integer
|
92
|
+
return c[:integer].to_i
|
93
|
+
else
|
94
|
+
return c[c.keys.first].to_s
|
95
|
+
end
|
96
|
+
end
|
97
|
+
else
|
98
|
+
raise "Unknown default_clause #{default_value.inspect}"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
def identity?
|
105
|
+
if options.nil?
|
106
|
+
false
|
107
|
+
else
|
108
|
+
options.select{|h|h.has_key?(:column_option) && h.has_value?('identity')}.length > 0
|
109
|
+
end
|
110
|
+
end
|
111
|
+
|
112
|
+
def start_value?
|
113
|
+
unless option(:identity).nil?
|
114
|
+
option(:identity)[:start_value][:integer].to_i
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
118
|
+
def increment_value
|
119
|
+
if options.nil?
|
120
|
+
false
|
121
|
+
else
|
122
|
+
options.select{|h|h.has_key?(:column_option) && h.has_value?('identity')}.length > 0
|
123
|
+
end
|
124
|
+
end
|
125
|
+
def cache_value
|
126
|
+
if options.nil?
|
127
|
+
false
|
128
|
+
else
|
129
|
+
options.select{|h|h.has_key?(:column_option) && h.has_value?('identity')}.length > 0
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
data/lib/ddl_parser/version.rb
CHANGED