kwatable 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (67) hide show
  1. data/ChangeLog +46 -0
  2. data/MIT-LICENSE +20 -0
  3. data/README.txt +4 -2
  4. data/bin/kwatable +4 -4
  5. data/examples/ex1/Makefile +40 -14
  6. data/examples/ex1/{example1.yaml → tabledef.yaml} +42 -11
  7. data/examples/ex2/Makefile +41 -14
  8. data/examples/ex2/{example2.yaml → tabledef.yaml} +45 -30
  9. data/examples/ex3/Makefile +52 -0
  10. data/examples/ex3/tabledef.yaml +136 -0
  11. data/kwatable.gemspec +11 -10
  12. data/lib/kwatable.rb +24 -18
  13. data/lib/kwatable/kwatable.schema.yaml +95 -5
  14. data/lib/kwatable/main.rb +331 -0
  15. data/lib/kwatable/manipulator.rb +320 -192
  16. data/lib/kwatable/messages.rb +59 -0
  17. data/lib/kwatable/template/ddl-mysql.eruby +202 -0
  18. data/lib/kwatable/{templates → template}/ddl-postgresql.eruby +71 -45
  19. data/lib/kwatable/{templates → template}/defaults.yaml +2 -2
  20. data/lib/kwatable/template/dictionary.en.yaml +70 -0
  21. data/lib/kwatable/template/dictionary.ja.yaml +165 -0
  22. data/lib/kwatable/template/dto-java.eruby +77 -0
  23. data/lib/kwatable/template/dto-java.sub.eruby +259 -0
  24. data/lib/kwatable/template/dto-ruby.eruby +63 -0
  25. data/lib/kwatable/template/dto-ruby.sub.eruby +213 -0
  26. data/lib/kwatable/template/helper/column.rb +70 -0
  27. data/lib/kwatable/template/helper/common.rb +151 -0
  28. data/lib/kwatable/template/helper/java.rb +83 -0
  29. data/lib/kwatable/template/helper/label.rb +90 -0
  30. data/lib/kwatable/template/helper/ruby.rb +36 -0
  31. data/lib/kwatable/template/helper/table.rb +62 -0
  32. data/lib/kwatable/template/hibernate.eruby +139 -0
  33. data/lib/kwatable/template/rails-controller.eruby +66 -0
  34. data/lib/kwatable/template/rails-controller.sub.eruby +114 -0
  35. data/lib/kwatable/template/rails-kwartz.eruby +164 -0
  36. data/lib/kwatable/template/rails-kwartz/_attr.plogic.eruby +56 -0
  37. data/lib/kwatable/template/rails-kwartz/_form.plogic.eruby +81 -0
  38. data/lib/kwatable/template/rails-kwartz/_link.plogic.eruby +36 -0
  39. data/lib/kwatable/template/rails-kwartz/edit.cfg.yaml.eruby +16 -0
  40. data/lib/kwatable/template/rails-kwartz/edit.html.eruby +46 -0
  41. data/lib/kwatable/template/rails-kwartz/edit.plogic.eruby +20 -0
  42. data/lib/kwatable/template/rails-kwartz/layout.html.eruby +39 -0
  43. data/lib/kwatable/template/rails-kwartz/layout.plogic.eruby +32 -0
  44. data/lib/kwatable/template/rails-kwartz/list.html.eruby +94 -0
  45. data/lib/kwatable/template/rails-kwartz/list.plogic.eruby +41 -0
  46. data/lib/kwatable/template/rails-kwartz/new.html.eruby +100 -0
  47. data/lib/kwatable/template/rails-kwartz/new.plogic.eruby +26 -0
  48. data/lib/kwatable/template/rails-kwartz/show.html.eruby +51 -0
  49. data/lib/kwatable/template/rails-kwartz/show.plogic.eruby +9 -0
  50. data/lib/kwatable/template/rails-model.eruby +35 -0
  51. data/lib/kwatable/template/rails-model.sub.eruby +136 -0
  52. data/lib/kwatable/{templates → template}/validator-ruby.eruby +18 -11
  53. data/lib/kwatable/util.rb +133 -0
  54. data/lib/kwatable/util/assert-text-equal.rb +47 -0
  55. data/lib/kwatable/util/assertion.rb +115 -0
  56. data/lib/kwatable/validator.rb +50 -0
  57. data/test/assert-diff.rb +1 -1
  58. data/test/test-ex.rb +306 -0
  59. data/test/test.rb +37 -127
  60. metadata +66 -17
  61. data/COPYING +0 -340
  62. data/ChangeLog.txt +0 -65
  63. data/lib/kwatable/error-msg.rb +0 -38
  64. data/lib/kwatable/main-program.rb +0 -216
  65. data/lib/kwatable/templates/ddl-mysql.eruby +0 -172
  66. data/lib/kwatable/templates/dto-java.eruby +0 -260
  67. data/lib/kwatable/templates/dto-ruby.eruby +0 -185
@@ -0,0 +1,331 @@
1
+ ###
2
+ ### copyright(c) 2005 kuwata-lab.com all rights reserved.
3
+ ### $Release: 0.3.0 $
4
+ ### $Rev: 43 $
5
+ ###
6
+
7
+ require 'yaml'
8
+ require 'erb'
9
+ require 'fileutils'
10
+
11
+ begin
12
+ require 'rubygems'
13
+ require_gem 'activesupport'
14
+ rescue LoadError => ex
15
+ # ignore
16
+ end
17
+
18
+ require 'kwatable'
19
+ require 'kwatable/util'
20
+ require 'kwatable/util/assertion'
21
+ require 'kwatable/validator'
22
+
23
+
24
+ module Kwatable
25
+
26
+ class CommandOptionError < KwatableError
27
+ end
28
+
29
+ class Main
30
+ include Assertion
31
+
32
+ def initialize(argv=ARGV)
33
+ @argv = argv
34
+ end
35
+
36
+ def execute()
37
+ options, properties, filenames = _parse_options(@argv)
38
+
39
+ ## help or version
40
+ if options[?h] || options[?v]
41
+ puts _version() if options[?v]
42
+ return unless options[?h]
43
+ puts _template_info(options) if options[?t]
44
+ puts _usage() if !options[?t]
45
+ puts _available_template(options) if !options[?t]
46
+ return
47
+ end
48
+
49
+ ## option check
50
+ if dir = options[?d]
51
+ #* key=:dir_notfound msg="-d %s: directory not found."
52
+ _option_error(:dir_notfound, dir) unless test(?e, dir)
53
+ #* key=:dir_notadir msg="-d %s: not a directory."
54
+ _option_error(:dir_notadir, dir) unless test(?d, dir)
55
+ end
56
+
57
+ ## load and validate datafile
58
+ tabledefs = []
59
+ check_only = options[?c]
60
+ s = '' if check_only
61
+ filenames.each do |filename|
62
+ tabledef, content = _load_yaml(filename, options[?T])
63
+ tabledefs << tabledef
64
+ unless options[?u]
65
+ errors = Kwatable.validate(tabledef, content)
66
+ if !errors || errors.empty?
67
+ s << "#{filename}: valid.\n" if check_only
68
+ else
69
+ s << "#{filename}: INVALID!\n" if check_only
70
+ s2 = errors.sort.collect { |err|
71
+ "%s:%d: %s: %s" % [filename, err.linenum, err.path, err.message]
72
+ }.join("\n")
73
+ if check_only
74
+ s << s2 << "\n"
75
+ else
76
+ #* key=:tabledef_validation_error msg="schema validation error.\n%s"
77
+ _option_error(:tabledef_validation_error, s2)
78
+ end
79
+ end
80
+ end
81
+ end
82
+ return s if check_only
83
+
84
+ ## merge tabledefs
85
+ tabledef = tabledefs.shift
86
+ tabledefs.each do |tdef|
87
+ tabledef = _merge_tabledefs(tabledef, tdef)
88
+ end
89
+
90
+ ## manipulation
91
+ manipulator = Manipulator.new()
92
+ manipulator.manipulate(tabledef)
93
+ $stderr.puts tabledef.to_yaml if options[?D]
94
+
95
+ ## template filename
96
+ filename = options[?t]
97
+ unless filename
98
+ return nil if options[?D]
99
+ #* key=:template_notspecified msg="template is not specified."
100
+ _option_error(:template_notspecified)
101
+ end
102
+ template_pathlist = _template_pathlist(options[?I])
103
+ template_filename = _find_template(filename, template_pathlist)
104
+
105
+ ## apply template
106
+ hash = { :options=>options, :properties=>properties,
107
+ :template_filename=>template_filename,
108
+ :template_pathlist=>template_pathlist,
109
+ }
110
+ hash[:tables] = tabledef['tables']
111
+ context = _create_context(hash)
112
+ output = Util.eval_template(template_filename, context)
113
+ output_files = context.instance_variable_get("@output_files")
114
+ if output_files
115
+ output_files.each do |filename, content, message_key|
116
+ _write_file(filename, content, message_key, options)
117
+ end
118
+ output = nil
119
+ end
120
+ return output
121
+ end
122
+
123
+ def self.main(argv=ARGV)
124
+ begin
125
+ main = Main.new(ARGV)
126
+ output = main.execute()
127
+ print output if output
128
+ rescue KwatableError => ex
129
+ $stderr.puts "[ERROR] #{ex.message()}"
130
+ end
131
+ end
132
+
133
+ private
134
+
135
+ def _write_file(filepath, content, message_key, options)
136
+ flag_quiet = options[?q]
137
+ #dir = options[?d]
138
+ #filepath = "#{dir}/#{filepath}" if dir
139
+ unless message_key == :identical
140
+ path = File.dirname(filepath)
141
+ FileUtils.mkdir_p(path) unless test(?d, path)
142
+ File.open(filepath, 'w') { |f| f.write(content) }
143
+ end
144
+ unless flag_quiet
145
+ message = _output_message(message_key)
146
+ $stderr.puts(message % filepath)
147
+ end
148
+ end
149
+
150
+ def _output_message(message_key)
151
+ unless @msg_table
152
+ table = {}
153
+ #* key=:file_create msg="create: %s"
154
+ table[:create] = Kwatable.msg(:file_create)
155
+ #* key=:file_update msg="update: %s"
156
+ table[:update] = Kwatable.msg(:file_update)
157
+ #* key=:file_delete msg="delete: %s"
158
+ table[:delete] = Kwatable.msg(:file_delete)
159
+ #* key=:file_identical msg="identical: %s"
160
+ table[:identical] = Kwatable.msg(:file_identical)
161
+ table[nil] = table[:create]
162
+ @msg_table = table
163
+ end
164
+ message = @msg_table[message_key]
165
+ assert! "message_key=#{message_key.inspect}"unless message
166
+ return message
167
+ end
168
+
169
+ def _load_yaml(filename, not_untabify)
170
+ #* key=:datafile_notfound msg="%s: datafile notfound."
171
+ _option_error(:datafile_notfound, filename) unless test(?e, filename)
172
+ #* key=:datafile_notafile msg="%s: not a file."
173
+ _option_error(:datafile_notafile, filename) unless test(?f, filename)
174
+ content = File.read(filename)
175
+ content = Util.untabify(content) unless not_untabify
176
+ ydoc = YAML.load(content)
177
+ #* key=:tabledef_empty msg="table definition file is empty."
178
+ _option_error(:tabledef_empty) unless ydoc
179
+ #* key=:tabledef_notmap msg="table definition is not a mapping."
180
+ _option_error(:tabledef_notmap) unless ydoc.is_a?(Hash)
181
+ return ydoc, content
182
+ end
183
+
184
+ def _merge_tabledefs(base_tabledef, other_tabledef)
185
+ base, other = base_tabledef, other_tabledef
186
+ return other unless base
187
+ other.each do |key, value|
188
+ if base.key?(key)
189
+ case v = base[key]
190
+ when Array ; v.concat(value)
191
+ when Hash ; v.update(value)
192
+ else ; base[key] = v
193
+ end
194
+ else
195
+ base[key] = value
196
+ end
197
+ end
198
+ return base
199
+ end
200
+
201
+ def _create_context(vars={})
202
+ context = Object.new
203
+ vars.each do |key, val|
204
+ context.instance_variable_set("@#{key.to_s}", val)
205
+ end
206
+ context.extend Assertion
207
+ return context
208
+ end
209
+
210
+ def _find_template(filename, pathlist)
211
+ filename += '.eruby' unless filename =~ /\.eruby$/
212
+ filepath = Util.find_file(filename, pathlist)
213
+ unless filepath
214
+ #* key=:template_notfound msg="`%s': template file not found."
215
+ _option_error(:template_notfound, filename)
216
+ end
217
+ return filepath
218
+ end
219
+
220
+ def _template_info(options)
221
+ filename = options[?t]
222
+ template_pathlist = _template_pathlist(options[?I])
223
+ template_filename = _find_template(filename, template_pathlist)
224
+ s = ''
225
+ s << "Filename: #{template_filename}\n"
226
+ content = File.read(template_filename)
227
+ if content =~ /<template-desc>(.*?)<\/template-desc>/m
228
+ s << "Description: #{$1}\n"
229
+ end
230
+ if content =~ /<template-properties>(.*?)<\/template-properties>/m
231
+ lines = $1.to_a
232
+ lines.shift; lines.pop
233
+ s << "Properties:\n"
234
+ s << lines.collect { |line| line.sub(/^[ \t]*\#+/, '') }.join
235
+ end
236
+ if content =~ /<template-details>(.*?)<\/template-details>/m
237
+ lines = $1.to_a
238
+ lines.shift; lines.pop
239
+ s << "Details:\n"
240
+ s << lines.collect { |line| line.sub(/^[ \t]*\#+/, '') }.join
241
+ end
242
+ return s
243
+ end
244
+
245
+ def _available_template(options)
246
+ path_list = _template_pathlist(options[?I])
247
+ filenames = path_list.collect { |path| Dir.glob("#{path}/*.eruby") }.flatten
248
+ filenames.delete_if { |filename| filename =~ /\.sub\.eruby$/ }
249
+ s = "Templates:\n"
250
+ filenames.each do |filename|
251
+ content = File.read(filename)
252
+ desc = (content =~ /<template-desc>(.*?)<\/template-desc>/) ? $1 : ''
253
+ name = File.basename(filename).sub(/\.eruby$/, '')
254
+ s << " %-18s: %s\n" % [name, desc]
255
+ end
256
+ return s
257
+ end
258
+
259
+ def _template_pathlist(option_I)
260
+ path_list = []
261
+ path_list.concat(option_I.split(/,/)) if option_I
262
+ path_list.concat(Kwatable.template_path)
263
+ return path_list
264
+ end
265
+
266
+ def _option_error(message_key, *args)
267
+ msg = Kwatable.msg(message_key)
268
+ assert! "massage not found. (message_key=#{message_key.inspect})" unless msg
269
+ err = CommandOptionError.new(msg % args)
270
+ err.set_backtrace(caller())
271
+ raise err
272
+ end
273
+
274
+ def _parse_options(argv)
275
+ begin
276
+ options, properties, filenames = Util.parse_argv(argv, "hvqcuD", "Iftd")
277
+ options[?h] = true if properties[:help]
278
+ options[?t] ||= options[?f] if options[?f]
279
+ return options, properties, filenames
280
+ rescue => ex
281
+ msg = ex.message
282
+ if msg =~ /\A-(.+?): unknown option.\z/
283
+ optchar = $1
284
+ #* key=:option_unknown msg="-%s: unknown option."
285
+ _option_error(:option_unknown, optchar)
286
+ elsif msg =~ /\A-(.+?): argument required.\z/
287
+ case optchar = $1
288
+ when 'f', 't'
289
+ #* key=:template_required msg="-%s: template filename required."
290
+ _option_error(:template_required, optchar)
291
+ when 'd'
292
+ #* key=:outdir_required msg="-%s: output directory required."
293
+ _option_error(:outdir_required, optchar)
294
+ when 'I'
295
+ #* key=:directory_required msg="-%s: directory required."
296
+ _option_error(:directory_required, optchar)
297
+ else
298
+ raise "*** internal error: optchar=#{optchar.inspect}"
299
+ end
300
+ else
301
+ raise "*** internal error: msg=#{msg.inspect}"
302
+ end
303
+ end
304
+ end
305
+
306
+ def _usage(command=nil)
307
+ command ||= File::basename($0)
308
+ s = ""
309
+ s << "Usage: #{command} [-hvmqcuT] [-I path] [-d dir] -t template datafile [datafile2 ...]\n"
310
+ s << " -h, --help : show help\n"
311
+ s << " -v : show version\n"
312
+ s << " -I path : template directory path\n"
313
+ s << " -t template : template filename\n"
314
+ #s << " -f template : template filename\n"
315
+ s << " -ht template : show template info(filename, desc, and properties)\n"
316
+ s << " -d dir : output file directory\n"
317
+ #s << " -m : multiple output file mode\n"
318
+ s << " -q : quiet mode\n"
319
+ s << " -c : validation only\n"
320
+ s << " -u : skip validation of datafile\n"
321
+ s << " -T : not expand tab characters in datafile\n"
322
+ return s
323
+ end
324
+
325
+ def _version()
326
+ return RELEASE
327
+ end
328
+
329
+ end
330
+
331
+ end
@@ -1,222 +1,350 @@
1
1
  ###
2
2
  ### copyright(c) 2005 kuwata-lab.com all rights reserved.
3
- ### $Release: 0.2.0 $
4
- ### $Rev: 18 $
3
+ ### $Release: 0.3.0 $
4
+ ### $Rev: 44 $
5
5
  ###
6
6
 
7
7
  require 'yaml'
8
+ require 'kwatable/util/assertion'
8
9
 
9
10
  module Kwatable
10
11
 
11
- class ManipulationError < KwatableError
12
- end
13
-
14
-
15
- ##
16
- ## ex.
17
- ## tabledef = YAML.load_file('tabledef.yaml')
18
- ## manipulator = Kwatable::Manipulator.new
19
- ## tabledef = manipulator.manipulate(tabledef)
20
- ## p tabledef[:columns]
21
- ## p tabledef[:tables]
22
- ##
23
- class Manipulator
24
-
25
- #def parse(input)
26
- # str = ''
27
- # input.each_line do |line|
28
- # str << line.gsub(/([^\t]{8})|([^\t]*)\t/n){[$+].pack("A8")} ## expand tab
29
- # end
30
- # tabledef = YAML.load(str)
31
- # manipulate(tabledef)
32
- # return tabledef
33
- #end
34
-
35
- def manipulate(tabledef)
36
- #assert unless tabledef.is_a?(Hash)
37
- return tabledef unless tabledef.is_a?(Hash)
38
-
39
- column_map, patterned_columns = _manipulate_columns(tabledef['columns'])
40
- #assert unless column_map.is_a?(Hash)
41
- #assert unless patterned_columns.is_a?(Array)
42
-
43
- table_map = _manipulate_tables(tabledef['tables'], column_map, patterned_columns)
44
- #assert unless table_map.is_a?(Hash)
45
-
46
- tabledef['column_map'] = column_map # Hash
47
- tabledef['table_map'] = table_map # Hash
48
- return tabledef
12
+ class ManipulationError < KwatableError
13
+ end
14
+
15
+
16
+ ##
17
+ ## ex.
18
+ ## tabledef = YAML.load_file('tabledef.yaml')
19
+ ## manipulator = Kwatable::Manipulator.new
20
+ ## tabledef = manipulator.manipulate(tabledef)
21
+ ## p tabledef[:columns]
22
+ ## p tabledef[:tables]
23
+ ##
24
+ class Manipulator
25
+ include Assertion
26
+
27
+ def initialize(options={})
28
+ @overridable = options[:overridable]
29
+ end
30
+
31
+ #def parse(input)
32
+ # str = ''
33
+ # input.each_line do |line|
34
+ # str << line.gsub(/([^\t]{8})|([^\t]*)\t/n){[$+].pack("A8")} ## expand tab
35
+ # end
36
+ # tabledef = YAML.load(str)
37
+ # manipulate(tabledef)
38
+ # return tabledef
39
+ #end
40
+
41
+ def manipulate(tabledef)
42
+ #assert unless tabledef.is_a?(Hash)
43
+ return tabledef unless tabledef.is_a?(Hash)
44
+
45
+ column_map, patterned_columns = _manipulate_columns(tabledef['columns'])
46
+ #assert unless column_map.is_a?(Hash)
47
+ #assert unless patterned_columns.is_a?(Array)
48
+
49
+ table_map = _manipulate_tables(tabledef['tables'], column_map, patterned_columns)
50
+ #assert unless table_map.is_a?(Hash)
51
+
52
+ tabledef['column_map'] = column_map # Hash
53
+ tabledef['table_map'] = table_map # Hash
54
+ return tabledef
55
+ end
56
+
57
+ private
58
+
59
+ def _error(message_key, *args)
60
+ msg = Kwatable.msg(message_key)
61
+ assert! "message_key=#{message_key}" unless msg
62
+ return ManipulationError.new(msg % args)
63
+ end
64
+
65
+ def _manipulate_columns(columns)
66
+ column_map = {}
67
+ patterned_columns = []
68
+ columns.each_with_index do |column, i|
69
+ name = column['name']
70
+ unless name
71
+ #* key=:colname_required msg="column name required (index=%d)."
72
+ raise _error(:colname_required, i)
73
+ end
74
+ if name =~ /\A\/(.*)\/\z/
75
+ pattern = $1
76
+ begin
77
+ #namepatetrn = eval(name)
78
+ namepattern = Regexp.compile(pattern)
79
+ rescue RegexpError => ex
80
+ #* key=:regexp_invalid msg="column '%s': pattern %s: %s"
81
+ raise _error(:regexp_invalid, column['name'], column['pattern'], ex.message)
82
+ end
83
+ column['namepattern'] = namepatntern
84
+ patterned_columns << column
85
+ else
86
+ if column_map.key?(name)
87
+ #* key=:coldef_duplicated msg="column '%s': column name is duplicated."
88
+ raise _error(:coldef_duplicated, column['name']) unless @overridable
89
+ end
90
+ column_map[name] = column
91
+ end
92
+ #name = column['name'].strip
93
+ #namepattern = column['namepattern']
94
+ #unless name || namepattern
95
+ # #* key=:colname_required msg="column definition doesn't have a name nor namepattern."
96
+ # raise ManipulationError.new(Kwatable.msg(:colname_required))
97
+ #end
98
+ #if name
99
+ # if column_map.key?(name)
100
+ # #* key=:coldef_duplicated msg="column definition `%s' is duplicated."
101
+ # raise ManipulationError.new(Kwatable.msg(:coldef_duplicated) % [name]) unless @overridable
102
+ # end
103
+ # column_map[name] = column
104
+ #end
105
+ #if namepattern
106
+ # pattern = namepattern.strip
107
+ # pattern = $1 if pattern =~ /^\/(.*)\/$/
108
+ # column['namepattern'] = Regexp.compile(pattern)
109
+ # patterned_columns << column
110
+ #end
111
+ end if columns
112
+ return column_map, patterned_columns
113
+ end
114
+
115
+ def _manipulate_tables(tables, column_map, patterned_columns)
116
+ #assert unless tables.is_a?(Array)
117
+ #assert unless column_map.is_a?(Hash)
118
+ #assert unless patterned_columns.is_a?(Array)
119
+
120
+ ## create table_map
121
+ table_map = {}
122
+ tables.each_with_index do |table, i|
123
+ name = table['name']
124
+ unless name
125
+ #* key=:tablename_required msg="table definition doesn't have a name (index=%d)."
126
+ raise _error(:tablename_required, i)
127
+ end
128
+ if table_map.key?(name)
129
+ #* key=:tabledef_duplicated msg="table '%s': table name is duplicated."
130
+ raise _error(:tabledef_duplicated, name) unless @overridable
131
+ end
132
+ unless table['columns']
133
+ #* key=:tablecolumns_required msg="table '%s': columns requried."
134
+ raise _error(:tablecolumns_required, table['name'])
135
+ end
136
+ table_map[name] = table
49
137
  end
50
138
 
51
- private
139
+ ## manipulate table columns
140
+ tables.each do |table|
141
+ _alias_table_key(table, 'ident-columns', 'primary-keys')
142
+ _manipulate_table_columns(table, table_map, column_map, patterned_columns)
143
+ end
52
144
 
53
- def _error(message_key, *args)
54
- msg = Kwatable.msg(message_key) % args
55
- return ManipulationError.new(msg)
145
+ ## manipulate table column ref
146
+ tables.each do |table|
147
+ _manipulate_table_column_ref(table, table_map)
56
148
  end
57
149
 
58
- def _manipulate_columns(columns)
59
- column_map = {}
60
- patterned_columns = []
61
- columns.each_with_index do |column, i|
62
- name = column['name']
63
- unless name
64
- #* key=:colname_required msg="table '%s': column name required (index=%d)."
65
- raise _error(:colname_required, table['name'], i)
66
- end
67
- if name =~ /\A\/(.*)\/\z/
68
- pattern = $1
69
- begin
70
- namepattern = Regexp.compile(pattern)
71
- rescue RegexpError => ex
72
- #* key=:regexp_invalid msg="table '%s': column '%s': pattern %s: %s"
73
- raise _error(:regexp_invalid, table['name'], column['name'], column['pattern'], ex.message)
74
- end
75
- column['namepattern'] = namepattern
76
- patterned_columns << column
77
- else
78
- if column_map.key?(name)
79
- #* key=:coldef_duplicated msg="table '%s': column '%s': column name is duplicated."
80
- raise _error(:coldef_duplicated, table['name'], column['name'])
81
- end
82
- column_map[name] = column
150
+ ## ident-columns (primary-keys)
151
+ tables.each do |table|
152
+ if table['ident-columns']
153
+ ident_columns = table['ident-columns'].collect do |colname|
154
+ column = table['columns'].find { |col| col['name'] == colname }
155
+ unless column
156
+ #* key=:table_identcol_missing msg="table '%s': ident-column '%s': no such column."
157
+ raise _error(:table_identcol_missing, table['name'], colname)
83
158
  end
84
- #name = column['name'].strip
85
- #namepattern = column['namepattern']
86
- #unless name || namepattern
87
- # #* key=:colname_required msg="column definition doesn't have a name nor namepattern."
88
- # raise ManipulationError.new(Kwatable.msg(:colname_required))
89
- #end
90
- #if name
91
- # if column_map.key?(name)
92
- # #* key=:coldef_duplicated msg="column definition `%s' is duplicated."
93
- # raise ManipulationError.new(Kwatable.msg(:coldef_duplicated) % [name])
94
- # end
95
- # column_map[name] = column
96
- #end
97
- #if namepattern
98
- # pattern = namepattern.strip
99
- # pattern = $1 if pattern =~ /^\/(.*)\/$/
100
- # column['namepattern'] = Regexp.compile(pattern)
101
- # patterned_columns << column
102
- #end
103
- end if columns
104
- return column_map, patterned_columns
159
+ column
160
+ end
161
+ table['ident-columns'] = table['primary-keys'] = ident_columns
162
+ end
163
+ ## detect ident-column, and column type checking
164
+ ident_columns = []
165
+ table['columns'].each do |column|
166
+ ident_columns << column if column['ident']
167
+ unless column['type']
168
+ #* key=:tabletype_required msg="table '%s': column '%s': type is not determined.."
169
+ raise _error(:tabletype_required, table['name'], column['name'])
170
+ end
171
+ end
172
+ table['ident-columns'] ||= ident_columns
173
+ table['primary-keys'] ||= ident_columns
174
+ ## check modeling
175
+ #if table['ident-columns'].length != 1 && table['modeling'] != false
176
+ # warn("table `%s': may be `modeling: no' ? " % [table['name']])
177
+ #end
105
178
  end
106
179
 
107
- def _manipulate_tables(tables, column_map, patterned_columns)
108
- #assert unless tables.is_a?(Array)
109
- #assert unless column_map.is_a?(Hash)
110
- #assert unless patterned_columns.is_a?(Array)
111
-
112
- ## create table_map
113
- table_map = {}
114
- tables.each_with_index do |table, i|
115
- name = table['name']
116
- unless name
117
- #* key=:tablename_required msg="table definition doesn't have a name (index=%d)."
118
- raise _error(:tablename_required, i)
119
- end
120
- if table_map.key?(name)
121
- #* key=:tabledef_duplicated msg="table '%s': table name is duplicated."
122
- raise _error(:tabledef_duplicated, name)
123
- end
124
- table_map[name] = table
125
- end
126
-
127
- ## manipulate table columns
128
- tables.each do |table|
129
- colname_map = {}
130
- table['columns'].each_with_index do |column, i|
131
- column['table'] = table
132
- colname = column['name']
133
- unless colname
134
- #* key=:tablecolumn_required msg="table '%s': column name requried (index=%d)."
135
- raise _error(:tablecolumn_required, table['name'], i)
136
- end
137
- if colname_map[colname]
138
- #* key=:tablecolumn_duplicated msg="table '%s': column '%s': column name is duplicated."
139
- raise _error(:tablecolumn_duplicated, table['name'], colname)
140
- end
141
- colname_map[colname] = true
142
- _set_defaults(column, column_map, patterned_columns)
143
- #_alias_keys(column, "primary-key", "primarykey", "identifier")
144
- #_alias_keys(column, "not-null", "notnull", "required")
145
- _alias_key(column, table, "ident", "primary-key")
146
- _alias_key(column, table, "required", "not-null")
147
- _handle_ref(column, table, table_map) if column['ref']
148
- _handle_enum(column) if column['enum']
149
- unless column['type']
150
- #* key=:tabletype_required msg="table `%s': column `%s': type is not determined."
151
- raise _error(:tabletype_required, table['name'], column['name'])
152
- end
153
- end if table['columns']
154
- end if tables
155
-
156
- return table_map
180
+ ## manipulate table relations
181
+ tables.each do |table|
182
+ _manipulate_table_relations(table, table_map) if table['relations']
157
183
  end
158
184
 
159
- def _set_defaults(column, column_map, patterned_columns)
160
- colname = column['name']
161
- defaults = column_map[colname]
162
- defaults ||= patterned_columns.find { |col| colname =~ col['namepattern'] }
163
- defaults.each do |key, val|
164
- column[key] = val if !column.key?(key) && key != 'namepattern'
165
- end if defaults
185
+ return table_map
186
+ end
187
+
188
+ def _manipulate_table_columns(table, table_map, column_map, patterned_columns)
189
+ colname_map = {}
190
+ table['columns'].each_with_index do |column, i|
191
+ column['table'] = table
192
+ colname = column['name']
193
+ unless colname
194
+ #* key=:tablecolumn_required msg="table '%s': column name requried (index=%d)."
195
+ raise _error(:tablecolumn_required, table['name'], i)
196
+ end
197
+ if colname_map[colname]
198
+ #* key=:tablecolumn_duplicated msg="table '%s': column '%s': column name is duplicated."
199
+ raise _error(:tablecolumn_duplicated, table['name'], colname)
200
+ end
201
+ colname_map[colname] = true
202
+ _set_defaults(column, column_map, patterned_columns)
203
+ _alias_column_key(column, table, "ident", "primary-key")
204
+ _alias_column_key(column, table, "required", "not-null")
205
+ _manipulate_column_enum(column) if column['enum']
166
206
  end
207
+ end
167
208
 
168
- def _alias_keys(column, key, *old_keys) # not used
169
- old_keys.each do |old_key|
170
- column[key] = column[old_key] if !column.key?(key) && column.key?(old_key)
171
- end if old_keys
209
+ def _manipulate_table_column_ref(table, table_map)
210
+ table['columns'].each do |column|
211
+ _manipulate_column_ref(column, table, table_map) if column['ref']
172
212
  end
213
+ end
214
+
215
+ def _set_defaults(column, column_map, patterned_columns)
216
+ colname = column['name']
217
+ defaults = column_map[colname]
218
+ defaults ||= patterned_columns.find { |col| colname =~ col['namepattern'] }
219
+ defaults.each do |key, val|
220
+ column[key] = val if !column.key?(key) && key != 'namepattern'
221
+ end if defaults
222
+ end
173
223
 
174
- def _alias_key(column, table, key1, key2)
175
- if column.key?(key1) && column.key?(key2)
176
- #* key=:alias_conflict msg="table '%s', column '%s': alias key '%1:' and '%2:' are not allowed to use in the same time."
177
- raise _error(:alias_conflict, table['name'], column['name'], key1, key2)
178
- end
179
- column[key2] = column[key1] if column.key?(key1)
180
- column[key1] = column[key2] if column.key?(key2)
224
+ def _alias_table_key(table, key1, key2)
225
+ if table.key?(key1) && table.key?(key2)
226
+ #* key=:alias_tablekey_conflict msg="table '%s': alias key '%1:' and '%2:' are not allowed to use in the same time."
227
+ raise _error(:alias_tablekey_conflict, table['name'], nil, key1, key2)
181
228
  end
229
+ table[key2] = table[key1] if table.key?(key1)
230
+ table[key1] = table[key2] if table.key?(key2)
231
+ end
182
232
 
183
- def _handle_enum(column)
184
- return unless column['enum']
185
- width = 0
186
- column['enum'].each do |value|
187
- len = value.to_s.length
188
- width = len if len > width
189
- end
190
- column['type'] ||= 'str'
191
- column['width'] ||= width
233
+ def _alias_column_key(column, table, key1, key2)
234
+ if column.key?(key1) && column.key?(key2)
235
+ #* key=:alias_columnkey_conflict msg="table '%s', column '%s': alias key '%1:' and '%2:' are not allowed to use in the same time."
236
+ raise _error(:alias_columnkey_conflict, table['name'], column['name'], key1, key2)
192
237
  end
238
+ column[key2] = column[key1] if column.key?(key1)
239
+ column[key1] = column[key2] if column.key?(key2)
240
+ end
193
241
 
194
- def _handle_ref(column, table, table_map)
195
- ref = column['ref']
196
- return unless ref
197
- ref = ref.strip
198
- return unless ref =~ /\A(\w+)\.(\w+)\z/ || ref =~ /\A(\w+)\((\w+)\)\z/
199
- ref_table_name = $1
200
- ref_column_name = $2
201
- ref_table = table_map[ref_table_name]
202
- unless ref_table
203
- #* key=:reftable_notfound msg="`table '%s': column '%s': 'ref: %s': reference table not found."
204
- raise _error(:reftable_notfound, table['name'], column['name'], column['ref'])
205
- end
206
- cols = ref_table['columns']
207
- ref_column = cols ? cols.find { |col| col['name'] == ref_column_name } : nil
208
- unless ref_column
209
- #* key=:refcolumn_notfound msg="`table '%s': column '%s': ref: %s': reference column not found in the table."
210
- raise _error(:refcolumn_notfound, table['name'], column['name'], column['ref'])
211
- end
212
- #column['ref-table'] = ref_table
213
- #column['ref-column'] = ref_column
214
- column['ref'] = ref_column
215
- column['ref-name'] ||= column['name'].sub(/_#{ref_column['name']}$/, '')
216
- column['type'] = ref_column['type']
217
- column['width'] ||= ref_column['width'] if ref_column.key?('width')
242
+ def _manipulate_column_enum(column)
243
+ return unless column['enum']
244
+ width = 0
245
+ column['enum'].each do |value|
246
+ len = value.to_s.length
247
+ width = len if len > width
218
248
  end
249
+ column['type'] ||= 'str'
250
+ column['width'] ||= width
251
+ end
252
+
253
+ def _manipulate_column_ref(column, table, table_map)
254
+ ref = column['ref']
255
+ return unless ref
256
+ ref = ref.strip
257
+ return unless ref =~ /\A(\w+)\.(\w+)\z/ || ref =~ /\A(\w+)\((\w+)\)\z/
258
+ ref_table_name = $1
259
+ ref_column_name = $2
260
+ ref_table = table_map[ref_table_name]
261
+ unless ref_table
262
+ #* key=:reftable_notfound msg="`table '%s': column '%s': 'ref: %s': reference table not found."
263
+ raise _error(:reftable_notfound, table['name'], column['name'], column['ref'])
264
+ end
265
+ cols = ref_table['columns']
266
+ ref_column = cols ? cols.find { |col| col['name'] == ref_column_name } : nil
267
+ unless ref_column
268
+ #* key=:refcolumn_notfound msg="`table '%s': column '%s': ref: %s': reference column not found in the table."
269
+ raise _error(:refcolumn_notfound, table['name'], column['name'], column['ref'])
270
+ end
271
+ #column['ref-table'] = ref_table
272
+ #column['ref-column'] = ref_column
273
+ column['_ref'] = column['ref']
274
+ column['ref'] = ref_column
275
+ #column['ref-name'] ||= column['name'].sub(/_#{ref_column['name']}$/, '')
276
+ column['type'] = ref_column['type']
277
+ column['width'] ||= ref_column['width'] if ref_column.key?('width')
278
+ end
279
+
280
+ def _manipulate_table_relations(table, table_map)
281
+ return unless table['relations']
282
+ table['relations'].each do |relation|
283
+ unless relation['kind']
284
+ #* key=:relation_kind_required msg="table `%s': relation kind required."
285
+ raise _error(:relation_kind_required, table['name'])
286
+ end
287
+ unless relation['referrer']
288
+ #* key=:relation_referrer_required msg="table `%s': relation referrer required."
289
+ raise _error(:relation_referrer_required, table['name'])
290
+ end
291
+ referrer = relation['referrer']
292
+ unless referrer =~ /\A(\w+)\.(\w+)\z/ || referrer =~ /\A(\w+)\((\w+(?:,\s*\w+)*)\)\z/
293
+ #* key=:referrer_invalid msg="table `%s': referrer `%s': invalid pattern."
294
+ raise _error(:referrer_invalid, table['name'], referrer)
295
+ end
296
+ reftable_name, refcolumn_names = $1, $2
297
+ unless table_map[reftable_name]
298
+ #* key=:referrer_table_notfound msg="table `%s': referrer `%s': table not found."
299
+ raise _error(:referrer_table_notfound, table['name'], referrer)
300
+ end
301
+ reftable = table_map[reftable_name]
302
+ refcolumns = refcolumn_names.split(/,\s*/).collect do |refcolumn_name|
303
+ refcolumn = reftable['columns'].find { |col| col['name'] == refcolumn_name }
304
+ unless refcolumn
305
+ #* key=:referrer_column_notfound msg="table `%s': referrer `%s': column not found."
306
+ raise _error(:referrer_column_notfound, table['name'], referrer)
307
+ end
308
+ refcolumn
309
+ end
310
+ relation['table'] = reftable
311
+ relation['columns'] = refcolumns
312
+ #
313
+ if relation['kind'] == 'n:n'
314
+ unless relation['join-table']
315
+ #* key=:referrer_jointable_required msg="table `%s': referrer `%s': `join-table:' is required when n:n relationship."
316
+ raise _error(:referrer_jointable_required, table['name'], referrer)
317
+ end
318
+ join_table_name = relation['join-table']
319
+ join_table = table_map[join_table_name]
320
+ unless join_table
321
+ #* key=:referrer_jointable_notfound msg="table `%s': referrer `%s': join-table '%s' not found."
322
+ raise _error(:referrer_jointable_notfound, table['name'], referrer, join_table_name)
323
+ end
324
+ relation['join-table'] = join_table
325
+ ident_column = table['columns'].find { |col| col['ident'] }
326
+ unless ident_column
327
+ #* key=:referrer_identcolumn_notfound msg="table `%s': referrer `%s': table `%s' does not have ident column (it is required for have n:n relationship)."
328
+ raise _error(:referrer_identcolumn_notfound, table['name'], referrer, table['name'])
329
+ end
330
+ unless _find_ref_column(join_table, ident_column)
331
+ #* key=:referrer_joincolumn_notfound msg="table `%s': referrer `%s': join-table '%s' does not have column to link to %s table."
332
+ raise _error(:referrer_joincolumn_notfound, table['name'], referrer, join_table['name'], table['name'])
333
+ end
334
+ refcolumns.each do |refcolumn|
335
+ unless _find_ref_column(join_table, refcolumn)
336
+ #* key=:referrer_joincolumn2_notfound msg="table `%s': referrer `%s': join-table '%s' does not have column to link to table '%s'."
337
+ raise _error(:referrer_joincolumn2_notfound, table['name'], referrer, join_table['name'], reftable['name'])
338
+ end
339
+ end
340
+ end
341
+ end
342
+ end
343
+
344
+ def _find_ref_column(table, refcolumn)
345
+ return table['columns'].find { |col| col['ref'] && col['ref'].__id__ == refcolumn.__id__ }
346
+ end
219
347
 
220
- end
348
+ end
221
349
 
222
350
  end