kwatable 0.0.1
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.
- data/COPYING +340 -0
- data/ChangeLog.txt +27 -0
- data/README.txt +81 -0
- data/bin/kwatable +20 -0
- data/examples/ex1/Makefile +34 -0
- data/examples/ex1/example1.yaml +85 -0
- data/examples/ex2/Makefile +34 -0
- data/examples/ex2/example2.yaml +94 -0
- data/kwatable.gemspec +48 -0
- data/lib/kwatable.rb +31 -0
- data/lib/kwatable/error-msg.rb +37 -0
- data/lib/kwatable/kwatable.schema.yaml +133 -0
- data/lib/kwatable/main-program.rb +197 -0
- data/lib/kwatable/manufactory.rb +213 -0
- data/lib/kwatable/templates/ddl-mysql.eruby +169 -0
- data/lib/kwatable/templates/ddl-postgresql.eruby +153 -0
- data/lib/kwatable/templates/defaults.yaml +87 -0
- data/lib/kwatable/templates/dto-java.eruby +204 -0
- data/lib/kwatable/templates/dto-ruby.eruby +180 -0
- data/setup.rb +1331 -0
- data/test/assert-diff.rb +44 -0
- data/test/test.rb +202 -0
- data/test/test1/test1.ddl-mysql.expected +22 -0
- data/test/test1/test1.ddl-postgresql.expected +22 -0
- data/test/test1/test1.dto-java.Group.expected +32 -0
- data/test/test1/test1.dto-java.User.expected +59 -0
- data/test/test1/test1.dto-ruby.Group.expected +21 -0
- data/test/test1/test1.dto-ruby.User.expected +36 -0
- data/test/test1/test1.yaml +85 -0
- data/test/test2/test2.ddl-mysql.expected +49 -0
- data/test/test2/test2.ddl-postgresql.expected +49 -0
- data/test/test2/test2.dto-java.Address.expected +42 -0
- data/test/test2/test2.dto-java.Customer.expected +49 -0
- data/test/test2/test2.dto-java.Item.expected +37 -0
- data/test/test2/test2.dto-java.SalesOrder.expected +50 -0
- data/test/test2/test2.dto-java.SalesOrderLine.expected +56 -0
- data/test/test2/test2.dto-ruby.Address.expected +25 -0
- data/test/test2/test2.dto-ruby.Customer.expected +32 -0
- data/test/test2/test2.dto-ruby.Item.expected +23 -0
- data/test/test2/test2.dto-ruby.SalesOrder.expected +32 -0
- data/test/test2/test2.dto-ruby.SalesOrderLine.expected +39 -0
- data/test/test2/test2.yaml +94 -0
- metadata +91 -0
@@ -0,0 +1,197 @@
|
|
1
|
+
###
|
2
|
+
### copyright(c) 2005 kuwata-lab.com all rights reserved.
|
3
|
+
### $Release: 0.0.1 $
|
4
|
+
### $Rev: 12 $
|
5
|
+
###
|
6
|
+
|
7
|
+
require 'erb'
|
8
|
+
|
9
|
+
module Kwatable
|
10
|
+
|
11
|
+
class CommandOptionError < KwatableError
|
12
|
+
end
|
13
|
+
|
14
|
+
class MainProgram
|
15
|
+
def initialize(argv=ARGV)
|
16
|
+
@argv = argv
|
17
|
+
end
|
18
|
+
|
19
|
+
def execute()
|
20
|
+
options, properties = parse_options(@argv)
|
21
|
+
|
22
|
+
## help or version
|
23
|
+
if options[?h] || options[?v]
|
24
|
+
puts version() if options[?v]
|
25
|
+
puts usage() if options[?h]
|
26
|
+
return
|
27
|
+
end
|
28
|
+
|
29
|
+
## load data file
|
30
|
+
s = ''
|
31
|
+
filenames = @argv
|
32
|
+
filenames.each do |filename|
|
33
|
+
File.open(filename) do |f|
|
34
|
+
f.each_line do |line|
|
35
|
+
s << line.gsub(/([^\t]{8})|([^\t]*)\t/n){[$+].pack("A8")} ## expand tab
|
36
|
+
end
|
37
|
+
end
|
38
|
+
end
|
39
|
+
yaml = YAML.load(s)
|
40
|
+
|
41
|
+
## manufacture
|
42
|
+
manufactory = Manufactory.new()
|
43
|
+
manufactory.manufacture(yaml)
|
44
|
+
$stderr.print yaml.to_yaml if options[?D]
|
45
|
+
|
46
|
+
## template filename
|
47
|
+
template = options[?f]
|
48
|
+
unless template
|
49
|
+
return nil if options[?D]
|
50
|
+
#* key=:template_required msg="template is not specified."
|
51
|
+
raise CommandOptionError.new(Kwatable.msg(:template_required))
|
52
|
+
end
|
53
|
+
|
54
|
+
## template filepath
|
55
|
+
template_filepath = nil
|
56
|
+
if test(?f, template)
|
57
|
+
template_filepath = template
|
58
|
+
elsif options[?I] && t = find_template(template, options[?I])
|
59
|
+
template_filepath = t
|
60
|
+
else
|
61
|
+
template_filepath = find_template(template, Kwatable.template_path)
|
62
|
+
end
|
63
|
+
unless template_filepath
|
64
|
+
#* key=:template_notfound msg="`%s': template file not found."
|
65
|
+
raise CommandOptionError.new(Kwatable.msg(:template_notfound) % template)
|
66
|
+
end
|
67
|
+
|
68
|
+
## apply template
|
69
|
+
if !options[?m]
|
70
|
+
context = { 'tables' => yaml['tables'], 'properties' => properties, }
|
71
|
+
output = apply_template(template_filepath, context)
|
72
|
+
return output
|
73
|
+
else
|
74
|
+
yaml['tables'].each do |table|
|
75
|
+
context = { 'table' => table, 'properties' => properties, }
|
76
|
+
output = apply_template(template_filepath, context)
|
77
|
+
output_filename = context[:output_filename]
|
78
|
+
output_filename = "#{options[?d]}/#{output_filename}" if options[?d]
|
79
|
+
File.open(output_filename, 'w') { |f| f.write(output) }
|
80
|
+
unless options[?s]
|
81
|
+
#* key=:file_generated msg="generated: %s"
|
82
|
+
$stderr.puts(Kwatable.msg(:file_generated) % output_filename)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
return nil
|
86
|
+
end
|
87
|
+
end
|
88
|
+
|
89
|
+
private
|
90
|
+
|
91
|
+
def parse_options(argv)
|
92
|
+
options = {}
|
93
|
+
properties = {}
|
94
|
+
while argv[0] && argv[0][0] == ?-
|
95
|
+
optstr = argv.shift
|
96
|
+
if optstr =~ /\A--([-\w]+)(=.*)?/ ## properties
|
97
|
+
key, value = $1, $2
|
98
|
+
key = key.gsub(/-/, '_')
|
99
|
+
if value
|
100
|
+
value.sub!(/\A=/, '')
|
101
|
+
else
|
102
|
+
value = true
|
103
|
+
end
|
104
|
+
case value
|
105
|
+
when "true", "yes" ; value = true
|
106
|
+
when "false", "no" ; value = false
|
107
|
+
when "null", "nil" ; value = nil
|
108
|
+
when /\A\d+\z/ ; value = value.to_i
|
109
|
+
when /\A\d+\.\d+\z/ ; value = value.to_f
|
110
|
+
when /\A'.*'\z/ ; value = eval(value)
|
111
|
+
when /\A".*"\z/ ; value = eval(value)
|
112
|
+
end
|
113
|
+
properties[key.intern] = value
|
114
|
+
else
|
115
|
+
optstr = optstr[1, optstr.length-1]
|
116
|
+
while optstr && !optstr.empty?
|
117
|
+
optchar = optstr[0]
|
118
|
+
optstr = optstr[1, optstr.length-1]
|
119
|
+
case optchar
|
120
|
+
when ?h, ?v, ?m, ?s, ?D
|
121
|
+
options[optchar] = true
|
122
|
+
when ?f, ?t
|
123
|
+
arg = optstr.empty? ? argv.shift : optstr
|
124
|
+
optstr = nil
|
125
|
+
unless arg
|
126
|
+
#* key=:template_required msg="-%s: template filename required."
|
127
|
+
raise CommandOptionError.new(Kwatable.msg(:template_required) % optchar.chr)
|
128
|
+
end
|
129
|
+
options[?f] = arg
|
130
|
+
#options[optchar] = arg
|
131
|
+
when ?d
|
132
|
+
arg = optstr.empty? ? argv.shift : optstr
|
133
|
+
optstr = nil
|
134
|
+
unless arg
|
135
|
+
#* key=:outdir_required msg="-%s: output directory required."
|
136
|
+
raise CommandOptionError.new(Kwatable.msg(:outdir_required) % optchar.chr)
|
137
|
+
end
|
138
|
+
options[optchar] = arg
|
139
|
+
when ?I
|
140
|
+
arg = optstr.empty? ? argv.shift : optstr
|
141
|
+
optstr = nil
|
142
|
+
unless arg
|
143
|
+
#* key=:directory_required msg="-%s: directory required."
|
144
|
+
raise CommandOptionError.new(Kwatable.msg(:directory_required) % optchar.chr)
|
145
|
+
end
|
146
|
+
(options[optchar] ||= []).concat(arg.split(/,/))
|
147
|
+
else
|
148
|
+
#* key=:option_invalid msg="-%s: invalid option."
|
149
|
+
raise CommandOptionError.new(Kwatable.msg(:option_invalid) % optchar.chr)
|
150
|
+
end
|
151
|
+
end # end while
|
152
|
+
end # end if
|
153
|
+
end # end while
|
154
|
+
return options, properties
|
155
|
+
end
|
156
|
+
|
157
|
+
def find_template(template, path_list)
|
158
|
+
path_list.each do |path|
|
159
|
+
t = "#{path}/#{template}"
|
160
|
+
return t if test(?f, t)
|
161
|
+
end
|
162
|
+
return nil
|
163
|
+
end
|
164
|
+
|
165
|
+
def apply_template(filename, context)
|
166
|
+
str = File.open(filename) { |f| f.read() }
|
167
|
+
trim_mode = '>' # or '%'
|
168
|
+
erb = ERB.new(str, $SAFE, trim_mode)
|
169
|
+
result = eval_erb(erb, context)
|
170
|
+
return result
|
171
|
+
end
|
172
|
+
|
173
|
+
def eval_erb(__erb, context)
|
174
|
+
return __erb.result(binding())
|
175
|
+
end
|
176
|
+
|
177
|
+
def usage()
|
178
|
+
command = File::basename($0)
|
179
|
+
s = ""
|
180
|
+
s << "Usage: #{command} [-hvm] [-I path] [-d dir] -f template datafile [datafile2 ...]\n"
|
181
|
+
s << " -h : help\n"
|
182
|
+
s << " -v : version\n"
|
183
|
+
s << " -I path : template directory path\n"
|
184
|
+
s << " -f template : template filename\n"
|
185
|
+
s << " -m : multiple output file\n"
|
186
|
+
s << " -d dir : output file directory (with '-m')\n"
|
187
|
+
s << " -s : silent mode\n"
|
188
|
+
return s
|
189
|
+
end
|
190
|
+
|
191
|
+
def version()
|
192
|
+
return ("$Release: 0.0.1 $" =~ /[\.\d]+/ && $&)
|
193
|
+
end
|
194
|
+
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
@@ -0,0 +1,213 @@
|
|
1
|
+
###
|
2
|
+
### copyright(c) 2005 kuwata-lab.com all rights reserved.
|
3
|
+
### $Release: 0.0.1 $
|
4
|
+
### $Rev: 11 $
|
5
|
+
###
|
6
|
+
|
7
|
+
require 'yaml'
|
8
|
+
|
9
|
+
module Kwatable
|
10
|
+
|
11
|
+
class ManufactureError < KwatableError
|
12
|
+
end
|
13
|
+
|
14
|
+
|
15
|
+
##
|
16
|
+
## ex.
|
17
|
+
## manufactory = Kwatable::Manufactory.new
|
18
|
+
## tabledef = manufactory.parse(input) # input is String or File
|
19
|
+
## p tabledef[:columns]
|
20
|
+
## p tabledef[:tables]
|
21
|
+
##
|
22
|
+
class Manufactory
|
23
|
+
|
24
|
+
def parse(input)
|
25
|
+
str = ''
|
26
|
+
input.each_line do |line|
|
27
|
+
str << line.gsub(/([^\t]{8})|([^\t]*)\t/n){[$+].pack("A8")} ## expand tab
|
28
|
+
end
|
29
|
+
ingredient = YAML.load(str)
|
30
|
+
manufacture(ingredient)
|
31
|
+
return ingredient
|
32
|
+
end
|
33
|
+
|
34
|
+
def manufacture(ingredient)
|
35
|
+
#assert unless ingredient.is_a?(Hash)
|
36
|
+
|
37
|
+
column_map, patterned_columns = manufacture_columns(ingredient['columns'])
|
38
|
+
#assert unless column_map.is_a?(Hash)
|
39
|
+
#assert unless patterned_columns.is_a?(Array)
|
40
|
+
|
41
|
+
table_map = manufacture_tables(ingredient['tables'], column_map, patterned_columns)
|
42
|
+
#assert unless table_map.is_a?(Hash)
|
43
|
+
|
44
|
+
ingredient['column_map'] = column_map # Hash
|
45
|
+
ingredient['table_map'] = table_map # Hash
|
46
|
+
return ingredient
|
47
|
+
end
|
48
|
+
|
49
|
+
private
|
50
|
+
|
51
|
+
def manufacture_columns(columns)
|
52
|
+
column_map = {}
|
53
|
+
patterned_columns = []
|
54
|
+
columns.each do |column|
|
55
|
+
name = column['name']
|
56
|
+
unless name
|
57
|
+
#* key=:colname_required msg="column definition doesn't have a name."
|
58
|
+
raise ManufactureError.new(Kwatable.msg(:colname_required))
|
59
|
+
end
|
60
|
+
if name =~ /\A\/(.*)\/\z/
|
61
|
+
pattern = $1
|
62
|
+
begin
|
63
|
+
name = Regexp.compile(pattern)
|
64
|
+
rescue RegexpError => ex
|
65
|
+
#* key=:regexp_invalid msg="column %s: %s"
|
66
|
+
raise ManufactureError.new(Kwatable.msg(:regexp_invalid) % [name, ex.message])
|
67
|
+
end
|
68
|
+
column['namepattern'] = name
|
69
|
+
#column.delete('name')
|
70
|
+
patterned_columns << column
|
71
|
+
else
|
72
|
+
if column_map.key?(name)
|
73
|
+
#* key=:coldef_duplicated msg="column definition `%s' is duplicated."
|
74
|
+
raise ManufactureError.new(Kwatable.msg(:coldef_duplicated) % name)
|
75
|
+
end
|
76
|
+
column_map[name] = column
|
77
|
+
end
|
78
|
+
#name = column['name'].strip
|
79
|
+
#namepattern = column['namepattern']
|
80
|
+
#unless name || namepattern
|
81
|
+
# #* key=:colname_required msg="column definition doesn't have a name nor namepattern."
|
82
|
+
# raise ManufactureError.new(Kwatable.msg(:colname_required))
|
83
|
+
#end
|
84
|
+
#if name
|
85
|
+
# if column_map.key?(name)
|
86
|
+
# #* key=:coldef_duplicated msg="column definition `%s' is duplicated."
|
87
|
+
# raise ManufactureError.new(Kwatable.msg(:coldef_duplicated) % [name])
|
88
|
+
# end
|
89
|
+
# column_map[name] = column
|
90
|
+
#end
|
91
|
+
#if namepattern
|
92
|
+
# pattern = namepattern.strip
|
93
|
+
# pattern = $1 if pattern =~ /^\/(.*)\/$/
|
94
|
+
# column['namepattern'] = Regexp.compile(pattern)
|
95
|
+
# patterned_columns << column
|
96
|
+
#end
|
97
|
+
end if columns
|
98
|
+
return column_map, patterned_columns
|
99
|
+
end
|
100
|
+
|
101
|
+
def manufacture_tables(tables, column_map, patterned_columns)
|
102
|
+
#assert unless tables.is_a?(Array)
|
103
|
+
#assert unless column_map.is_a?(Hash)
|
104
|
+
#assert unless patterned_columns.is_a?(Array)
|
105
|
+
|
106
|
+
## create table_map
|
107
|
+
table_map = {}
|
108
|
+
tables.each do |table|
|
109
|
+
name = table['name']
|
110
|
+
unless name
|
111
|
+
#* key=:tablename_required msg="table definition doesn't have a name."
|
112
|
+
raise ManufactureError.new(Kwatable.msg(:tablename_required))
|
113
|
+
end
|
114
|
+
if table_map.key?(name)
|
115
|
+
#* key=:tabledef_duplicated msg="table definition `%s' is duplicated."
|
116
|
+
raise ManufactureError.new(Kwatable.msg(:tabledef_duplicated) % [name])
|
117
|
+
end
|
118
|
+
table_map[name] = table
|
119
|
+
end
|
120
|
+
|
121
|
+
## manufacture table columns
|
122
|
+
tables.each do |table|
|
123
|
+
name_map = {}
|
124
|
+
table['columns'].each do |column|
|
125
|
+
name = column['name']
|
126
|
+
unless name
|
127
|
+
#* key=:tablecolumn_required msg="table '%s': column name requried."
|
128
|
+
raise ManufactureError.new(Kwatable.msg(:tablecolumn_required % [table['name']]))
|
129
|
+
end
|
130
|
+
if name_map[name]
|
131
|
+
#* key=:tablecolumn_duplicated msg="table '%s': column '%s' is duplicated."
|
132
|
+
raise ManufactureError.new(Kwatable.msg(:tablecolumn_duplicated % [table['name'], name]))
|
133
|
+
end
|
134
|
+
name_map[name] = true
|
135
|
+
set_defaults(column, column_map, patterned_columns)
|
136
|
+
#alias_keys(column, "primary-key", "primarykey", "identifier")
|
137
|
+
#alias_keys(column, "not-null", "notnull", "required")
|
138
|
+
alias_key(column, "primary-key", "identifier")
|
139
|
+
alias_key(column, "not-null", "required")
|
140
|
+
handle_ref(column, table_map) if column['ref']
|
141
|
+
handle_values(column) if column['values']
|
142
|
+
unless column['type']
|
143
|
+
#* key=:tabletype_required msg="table `%s': type of column `%s' is not determined."
|
144
|
+
raise ManufactureError.new(Kwatable.msg(:tabletype_required) % [table['name'], column['name']])
|
145
|
+
end
|
146
|
+
end if table['columns']
|
147
|
+
end if tables
|
148
|
+
|
149
|
+
return table_map
|
150
|
+
end
|
151
|
+
|
152
|
+
def set_defaults(column, column_map, patterned_columns)
|
153
|
+
colname = column['name']
|
154
|
+
defaults = column_map[colname]
|
155
|
+
defaults ||= patterned_columns.find { |col| colname =~ col['namepattern'] }
|
156
|
+
defaults.each do |key, val|
|
157
|
+
column[key] = val if !column.key?(key) && key != 'namepattern'
|
158
|
+
end if defaults
|
159
|
+
end
|
160
|
+
|
161
|
+
def alias_keys(column, key, *old_keys) # not used
|
162
|
+
old_keys.each do |old_key|
|
163
|
+
column[key] = column[old_key] if !column.key?(key) && column.key?(old_key)
|
164
|
+
end if old_keys
|
165
|
+
end
|
166
|
+
|
167
|
+
def alias_key(column, key1, key2)
|
168
|
+
if column[key1] && !column.key?(key2)
|
169
|
+
column[key2] = column[key1]
|
170
|
+
elsif column[key2] && !column.key?(key1)
|
171
|
+
column[key1] = column[key2]
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def handle_values(column)
|
176
|
+
return unless column['values']
|
177
|
+
width = 0
|
178
|
+
column['values'].each do |value|
|
179
|
+
len = value.to_s.length
|
180
|
+
width = len if len > width
|
181
|
+
end
|
182
|
+
column['type'] ||= 'string'
|
183
|
+
column['width'] ||= width
|
184
|
+
end
|
185
|
+
|
186
|
+
def handle_ref(column, table_map)
|
187
|
+
ref = column['ref']
|
188
|
+
return unless ref
|
189
|
+
ref = ref.strip
|
190
|
+
return unless ref =~ /\A(\w+)\.(\w+)\z/ || ref =~ /\A(\w+)\((\w+)\)\z/
|
191
|
+
ref_table_name = $1
|
192
|
+
ref_column_name = $2
|
193
|
+
ref_table = table_map[ref_table_name]
|
194
|
+
unless ref_table
|
195
|
+
#* key=:reftable_notfound msg="`ref: %s': table not found."
|
196
|
+
raise ManufactureError.new(Kwatable.msg(:reftable_notfound) % column['ref'])
|
197
|
+
end
|
198
|
+
cols = ref_table['columns']
|
199
|
+
ref_column = cols ? cols.find { |col| col['name'] == ref_column_name } : nil
|
200
|
+
unless ref_column
|
201
|
+
#* key=:refcolumn_notfound msg="`ref: %s': column not found in the table."
|
202
|
+
raise ManufactureError.new(Kwatable.msg(:refcolumn_notfound) % column['ref'])
|
203
|
+
end
|
204
|
+
column['ref-table'] = ref_table
|
205
|
+
column['ref-column'] = ref_column
|
206
|
+
column['ref-name'] ||= column['name'].sub(/_#{ref_column_name}$/, '')
|
207
|
+
column['type'] = ref_column['type']
|
208
|
+
column['width'] ||= ref_column['width'] if ref_column.key?('width')
|
209
|
+
end
|
210
|
+
|
211
|
+
end
|
212
|
+
|
213
|
+
end
|
@@ -0,0 +1,169 @@
|
|
1
|
+
<%
|
2
|
+
|
3
|
+
##
|
4
|
+
## kwatable template file for MySQL
|
5
|
+
##
|
6
|
+
## copyright(c) 2005 kuwata-lab.com all rights reserved.
|
7
|
+
## $Release: 0.0.1 $
|
8
|
+
## $Rev: 12 $
|
9
|
+
##
|
10
|
+
## template properties:
|
11
|
+
## (none)
|
12
|
+
|
13
|
+
|
14
|
+
#
|
15
|
+
# context variables
|
16
|
+
#
|
17
|
+
tables = context['tables']
|
18
|
+
properties = context['properties']
|
19
|
+
raise "don't use '-m' option with 'ddl-mysql.eruby'." unless tables
|
20
|
+
|
21
|
+
|
22
|
+
#
|
23
|
+
# MySQL keywords
|
24
|
+
#
|
25
|
+
keywords = <<-END
|
26
|
+
add all alter analyze and as asc asensitive
|
27
|
+
before between bigint binary blob both by
|
28
|
+
call cascade case change char character check collate column
|
29
|
+
condition connection constraint continue convert create cross
|
30
|
+
current_date current_time current_timestamp current_user cursor
|
31
|
+
database databases day_hour day_microsecond day_minute day_second
|
32
|
+
dec decimal declare default delayed delete desc describe
|
33
|
+
deterministic distinct distinctrow div double drop dual
|
34
|
+
each else elseif enclosed escaped exists exit explain
|
35
|
+
false fetch float for force foreign from fulltext
|
36
|
+
goto grant group
|
37
|
+
having high_priority hour_microsecond hour_minute hour_second
|
38
|
+
if ignore in index infile inner inout insensitive insert
|
39
|
+
int integer interval into is iterate
|
40
|
+
join
|
41
|
+
key keys kill
|
42
|
+
leading leave left like limit lines load localtime
|
43
|
+
localtimestamp lock long longblob longtext loop low_priority
|
44
|
+
match mediumblob mediumint mediumtext middleint
|
45
|
+
minute_microsecond minute_second mod modifies
|
46
|
+
natural not no_write_to_binlog null numeric
|
47
|
+
on optimize option optionally or order out outer outfile
|
48
|
+
precision primary procedure purge
|
49
|
+
read reads real references regexp release rename repeat
|
50
|
+
replace require restrict return revoke right rlike
|
51
|
+
schema schemas second_microsecond select sensitive
|
52
|
+
separator set show smallint soname spatial specific sql
|
53
|
+
sqlexception sqlstate sqlwarning sql_big_result
|
54
|
+
sql_calc_found_rows sql_small_result ssl starting straight_join
|
55
|
+
table terminated then tinyblob tinyint tinytext to
|
56
|
+
trailing trigger true
|
57
|
+
undo union unique unlock unsigned update usage use using
|
58
|
+
utc_date utc_time utc_timestamp
|
59
|
+
values varbinary varchar varcharacter varying
|
60
|
+
when where while with write
|
61
|
+
xor
|
62
|
+
year_month
|
63
|
+
zerofill
|
64
|
+
END
|
65
|
+
KEYWORDS = {}
|
66
|
+
keywords.split(/\s+/).each { |word| KEYWORDS[word] = true }
|
67
|
+
|
68
|
+
|
69
|
+
#
|
70
|
+
# escape keyword
|
71
|
+
#
|
72
|
+
def _(word)
|
73
|
+
return KEYWORDS[word.downcase] ? "`#{word}`" : word
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
#
|
78
|
+
# start output
|
79
|
+
#
|
80
|
+
%>
|
81
|
+
----------------------------------------------------------------------
|
82
|
+
-- DDL for MySQL
|
83
|
+
-- generated by kwatable with template 'ddl-mysql.eruby'
|
84
|
+
-- at <%= Time.now.to_s %>
|
85
|
+
|
86
|
+
----------------------------------------------------------------------
|
87
|
+
<%
|
88
|
+
#
|
89
|
+
# create table statement
|
90
|
+
#
|
91
|
+
%>
|
92
|
+
<% for table in tables %>
|
93
|
+
|
94
|
+
-- <%= table['desc'] %>
|
95
|
+
|
96
|
+
create table <%= _(table['name']) %> (
|
97
|
+
<%
|
98
|
+
n = table['columns'].length
|
99
|
+
i = 0
|
100
|
+
for column in table['columns']
|
101
|
+
i += 1
|
102
|
+
flag_last_loop = (i == n)
|
103
|
+
|
104
|
+
name = column['name']
|
105
|
+
type = column['type']
|
106
|
+
width = column['width']
|
107
|
+
|
108
|
+
#
|
109
|
+
# column type
|
110
|
+
#
|
111
|
+
case type
|
112
|
+
when 'char' ; type = 'tinyint'
|
113
|
+
when 'short' ; type = 'mediumint'
|
114
|
+
when 'int' ; type = 'integer'
|
115
|
+
when 'inteter' ;
|
116
|
+
when 'str' ; type = 'varchar' ; width ||= 255
|
117
|
+
when 'string' ; type = 'varchar' ; width ||= 255
|
118
|
+
when 'text' ;
|
119
|
+
when 'float' ;
|
120
|
+
when 'double' ;
|
121
|
+
when 'bool' ; type = 'boolean'
|
122
|
+
when 'boolean' ;
|
123
|
+
when 'date' ;
|
124
|
+
when 'timestamp' ;
|
125
|
+
when 'money' ; type = 'decimal'
|
126
|
+
end
|
127
|
+
type += "(#{width})" if width
|
128
|
+
|
129
|
+
#
|
130
|
+
# set type with 'enum(...)' if column has values
|
131
|
+
#
|
132
|
+
if column['values']
|
133
|
+
type = "enum(" + column['values'].collect{|v| "'#{v}'"}.join(", ") + ")"
|
134
|
+
width = nil
|
135
|
+
end
|
136
|
+
|
137
|
+
#
|
138
|
+
# constraints
|
139
|
+
#
|
140
|
+
constraints = []
|
141
|
+
constraints << 'auto_increment' if column['serial']
|
142
|
+
constraints << 'not null' if column['not-null'] && !column['serial'] && !column['primary-key']
|
143
|
+
constraints << 'primary key' if column['primary-key']
|
144
|
+
constraints << 'unique' if column['unique']
|
145
|
+
|
146
|
+
#
|
147
|
+
# column definition
|
148
|
+
#
|
149
|
+
name_part = '%-20s' % _(name)
|
150
|
+
type_part = '%-20s' % type
|
151
|
+
const_part = constraints.join(' ')
|
152
|
+
comma = flag_last_loop ? '' : ','
|
153
|
+
comment = column['ref'] ? " -- references #{column['ref']}" : ""
|
154
|
+
%>
|
155
|
+
<%= name_part %> <%= type_part %> <%= const_part %><%= comma %><%= comment %>
|
156
|
+
|
157
|
+
<%
|
158
|
+
end
|
159
|
+
|
160
|
+
#
|
161
|
+
# composite primary key
|
162
|
+
#
|
163
|
+
%>
|
164
|
+
<% if table['primary-keys'] %>
|
165
|
+
<% pkeystr = table['primary-keys'].collect { |pkey| _(pkey) }.join(', ') %>
|
166
|
+
, primary key (<%= pkeystr %>)
|
167
|
+
<% end %>
|
168
|
+
);
|
169
|
+
<% end %>
|