ezframe 0.1.1 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -2,54 +2,191 @@
2
2
 
3
3
  module Ezframe
4
4
  class ColumnSets
5
- attr_accessor :tables, :model
6
-
7
- def initialize
8
- @tables = {}
9
- end
5
+ class << self
6
+ def init(dir = nil)
7
+ dir ||= "./column"
8
+ unless @colset_h
9
+ @colset_h = {}
10
+ load_files(dir)
11
+ end
12
+ end
10
13
 
11
- def load_files(dir)
12
- Dir["#{dir}/*.yml"].each do |filename|
13
- load_one_file(filename)
14
+ def load_files(dir)
15
+ Dir["#{dir}/*.yml"].each do |filename|
16
+ load_one_file(filename)
17
+ end
14
18
  end
15
- end
16
19
 
17
- def load_one_file(filename)
18
- table_name = $1 if filename =~ /(\w+).ya?ml$/
19
- #begin
20
+ def load_one_file(filename)
21
+ colset_name = $1 if filename =~ /(\w+).ya?ml$/
20
22
  yaml = YAML.load_file(filename)
21
- #rescue
22
- # raise "YAML load error: #{filename}"
23
- #end
24
- if yaml.length == 0
25
- mylog("[ERROR] columns file is empty: #{filename}")
26
- return
23
+ if yaml.length == 0
24
+ Logger.error("[ERROR] columns file is empty: #{filename}")
25
+ return
26
+ end
27
+ column_info = yaml.recursively_symbolize_keys
28
+ # puts "load_one_file: filename=#{filename} column_info=#{column_info.inspect}"
29
+ add(colset_name, column_info)
30
+ end
31
+
32
+ def add(colset_name, columns)
33
+ @colset_h[colset_name.to_sym] = cs = ColumnSet.new(parent: self, name: colset_name, columns: columns)
34
+ cs.set(columns)
35
+ return cs
36
+ end
37
+
38
+ def clone
39
+ @colset_h.deep_dup
40
+ end
41
+
42
+ def has_key?(key)
43
+ return nil unless key
44
+ return @colset_h[key.to_sym]
45
+ end
46
+
47
+ def get(colset_name)
48
+ return nil unless colset_name
49
+ return @colset_h[colset_name.to_sym].deep_dup
50
+ end
51
+
52
+ def refer(colset_name)
53
+ return nil unless colset_name
54
+ return @colset_h[colset_name.to_sym]
55
+ end
56
+
57
+ def [](colset_name)
58
+ return get(colset_name)
59
+ end
60
+
61
+ def each
62
+ @colset_h.each { |k, v| yield(k, v) }
63
+ end
64
+
65
+ def inspect
66
+ @colset_h.each do |name, colset|
67
+ "[#{name}]:#{colset.inspect}"
68
+ end
69
+ end
70
+
71
+ def create_tables
72
+ self.each do |table_name, column_set|
73
+ begin
74
+ create_one_table(table_name, column_set)
75
+ rescue => e
76
+ Logger.error("create_tables: #{e.inspect}\n#{$@.inspect}")
77
+ end
78
+ end
79
+ end
80
+
81
+ def create_one_table(table_name, column_set)
82
+ col_h = column_set.get_hash(:db_type)
83
+ Logger.info "create_one_table: col_h=#{col_h.inspect}"
84
+ DB.create_table(table_name, col_h)
85
+ end
86
+
87
+ # foreignから生成したテーブル連結情報を返す
88
+ def full_join_structure(colset_id)
89
+ struct = { tables: [colset_id] }
90
+ colset = @colset_h[colset_id.to_sym]
91
+ colset_keys = colset.keys
92
+ struct[:column_list] = colset_keys.map { |k| "#{colset_id}.#{k}" }
93
+ join_cond_h = {}
94
+ colset_keys.each do |key|
95
+ column = colset[key]
96
+ if column.type.to_s == "foreign"
97
+ # 連結するテーブル名をtable: で指定する。
98
+ foreign_table = column.attribute[:table]
99
+ # 指定されてなければ、キーの名称をテーブル名とする
100
+ # そのテーブルが定義されてなければ、エラーとしてログに残す。
101
+ unless foreign_table
102
+ if @colset_h[key]
103
+ foreign_table = key
104
+ else
105
+ Logger.error "There is no related table: #{key}"
106
+ next
107
+ end
108
+ end
109
+ raise "no table: key=#{key}" unless foreign_table
110
+ foreign_column = column.attribute[:column]&.to_sym || :id
111
+ foreign_table = foreign_table.to_sym
112
+ next if struct[:tables].include?(foreign_table)
113
+ # join_cond_h["#{colset_id}.#{key}"] = "#{colset_id}.#{key} = #{foreign_table}.#{foreign_column}"
114
+ join_cond_h[foreign_table] = "#{colset_id}.#{key} = #{foreign_table}.#{foreign_column}"
115
+ struct[:tables].push(foreign_table)
116
+ struct[:column_list] += ColumnSets.refer(foreign_table).keys.map {|k| "#{foreign_table}.#{k}" }
117
+ end
118
+ end
119
+ struct[:join_condition] = join_cond_h
120
+ return struct
121
+ end
122
+
123
+ def join_complex_column
124
+
27
125
  end
28
- column_info = yaml.recursively_symbolize_keys
29
- # puts "load_one_file: filename=#{filename} column_info=#{column_info.inspect}"
30
- add(table_name, column_info)
31
126
  end
127
+ end
128
+
129
+ # ColumnSetを複数組み合わせて扱う
130
+ class ColumnSetCollection
131
+ attr_accessor :colset_list
32
132
 
33
- def add(table_name, columns)
34
- @tables[table_name.to_sym] = tb = ColumnSet.new(parent: self, name: table_name, columns: columns)
35
- tb.set(columns)
133
+ def initialize(default_table=nil)
134
+ @colset_h = {}
135
+ @default_table = default_table
36
136
  end
37
137
 
38
- def [](table_name)
39
- return @tables[table_name]
138
+ def values=(data)
139
+ @colset_h.each {|key, colset| colset.clear }
140
+ set_values(data)
40
141
  end
41
142
 
42
- def each
43
- @tables.each {|k, v| yield(k, v) }
143
+ def set_values(data)
144
+ data.each do |key, value|
145
+ if key.to_s.index(".")
146
+ table_key, col_key = key.to_s.split(".")
147
+ colset = @colset_h[table_key.to_sym]
148
+ unless colset
149
+ @colset_h[table_key.to_sym] = colset = ColumnSets[table_key]
150
+ end
151
+ elsif @default_table
152
+ col_key = key
153
+ colset = @colset_h[@default_table.to_sym]
154
+ unless colset
155
+ @colset_h[table_key.to_sym] = colset = ColumnSets[@default_table]
156
+ end
157
+ end
158
+ colset[col_key].value = value
159
+ end
160
+ end
161
+
162
+ def get(colset_key, col_key=nil)
163
+ if col_key.nil?
164
+ if colset_key.to_s.index(".")
165
+ colset_key, col_key = colset_key.to_s.split(".")
166
+ elsif @default_table
167
+ colset_key, col_key = @default_table, colset_key
168
+ else
169
+ Logger.error "ColumnSetCollection.get: illegal arguments: #{colset_key}, #{col_key}"
170
+ return nil
171
+ end
172
+ end
173
+ colset = @colset_h[colset_key.to_sym]
174
+ return nil unless colset
175
+ # Logger.debug("Collection.get: colset_key=#{colset_key}, col_key=#{col_key}, value=#{colset[col_key].value}")
176
+ return colset[col_key]
177
+ end
178
+
179
+ def [](k)
180
+ return get(k)
44
181
  end
45
182
  end
46
183
 
47
184
  class ColumnSet
48
185
  attr_accessor :name, :parent, :edit_keys, :view_keys
49
186
 
50
- def initialize(parent:, name: nil, columns: nil)
187
+ def initialize(parent: nil, name: nil, columns: nil)
51
188
  @parent = parent
52
- @name = name
189
+ @name = name
53
190
  @columns ||= {}
54
191
  set(columns) if columns
55
192
  end
@@ -66,9 +203,9 @@ module Ezframe
66
203
 
67
204
  # 配列を初期化する
68
205
  def set(attr_a)
69
- @columns[:id] = IdType.new(key: "id", label: "ID", no_edit: true)
70
- attr_a.each do |attributes|
71
- attr = attributes.clone
206
+ @columns[:id] = IdType.new(key: "id", label: "ID", hidden: true)
207
+ attr_a.each do |attribute|
208
+ attr = attribute.clone
72
209
  col_key = attr[:key]
73
210
  raise "no column key: #{attr.inspect}" unless col_key
74
211
  klass = TypeBase.get_class(attr[:type])
@@ -78,16 +215,14 @@ module Ezframe
78
215
  @columns[col_key.to_sym] = klass.new(attr)
79
216
  end
80
217
  end
81
- @columns[:created_at] = DatetimeType.new(type: "datetime", key: "created_at", label: "生成日時", no_edit: true)
82
- @columns[:updated_at] = DatetimeType.new(type: "datetime", key: "updated_at", label: "更新日時", no_edit: true)
83
- # mylog "set: #{@columns.inspect}"
84
- @columns.values.each {|col| col.parent = self }
218
+ @columns[:created_at] = DatetimeType.new(type: "datetime", key: "created_at", label: "生成日時", hidden: true)
219
+ @columns[:updated_at] = DatetimeType.new(type: "datetime", key: "updated_at", label: "更新日時", hidden: true)
220
+ @columns.values.each { |col| col.parent = self }
85
221
  return @columns
86
222
  end
87
223
 
88
224
  def dataset
89
- # puts "dataset: #{@model.inspect}"
90
- return @parent.model.db.dataset(@name)
225
+ return DB.dataset(@name)
91
226
  end
92
227
 
93
228
  def set_from_db(id)
@@ -97,19 +232,15 @@ module Ezframe
97
232
  return data
98
233
  end
99
234
 
100
- # 新規に値を登録する
101
- def create
102
- col_h = get_hash(:value)
103
- col_h.delete(:id)
104
- col_h.delete(:created_at)
105
- col_h[:updated_at] = Time.now
106
- mylog "create: #{col_h.inspect}"
107
- id = @columns[:id]
108
- if id.value.to_i > 0
109
- dataset.where(id: id.value).update(col_h)
110
- else
111
- return dataset.insert(col_h)
112
- end
235
+ # データベースに新規に値を登録する
236
+ def create(value_h)
237
+ self.set_values(value_h)
238
+ db_value_h = self.get_hash(:db_value)
239
+ Logger.debug("column_set.create: #{db_value_h}")
240
+ db_value_h.delete(:id)
241
+ db_value_h[:updated_at] = Time.now
242
+ db_value_h[:created_at] = Time.now
243
+ return dataset.insert(db_value_h)
113
244
  end
114
245
 
115
246
  # データベース上の値の更新
@@ -125,15 +256,18 @@ module Ezframe
125
256
  end
126
257
  prev_value = column.value
127
258
  column.value = new_value
128
- if prev_value != column.value
259
+ if column.respond_to?("value_equal?")
260
+ unless column.value_equal?(prev_value, column.value)
261
+ updated_values[colkey] = column.set_for_db(value)
262
+ end
263
+ elsif prev_value != column.value
129
264
  updated_values[colkey] = column.value
130
265
  end
131
266
  end
132
- mylog "column_set.updated_values = #{updated_values.inspect}"
133
267
  if updated_values.length > 0
134
268
  updated_values[:updated_at] = Time.now
135
- puts dataset.where(id: id).update_sql(updated_values)
136
- dataset.where(id: id).update(updated_values)
269
+ # puts dataset.where(id: id).update_sql(updated_values)
270
+ dataset.where(id: id).update(updated_values)
137
271
  end
138
272
  end
139
273
 
@@ -142,50 +276,69 @@ module Ezframe
142
276
  set_values(value_h)
143
277
  end
144
278
 
279
+ # 各カラムに値を格納する
145
280
  def set_values(value_h)
146
281
  return unless value_h
147
- value_h.each do |k, v|
148
- next if k.nil? || k.to_s.empty?
149
- col = @columns[k.to_sym]
150
- next unless col
151
- col.value = v
282
+ @columns.keys.each do |key|
283
+ next if key.nil? || key.to_s.empty?
284
+ column = @columns[key.to_sym]
285
+ next unless column
286
+ if column.respond_to?(:form_to_value) && !value_h.has_key?(key)
287
+ val = column.form_to_value(value_h)
288
+ else
289
+ val = value_h[key]
290
+ end
291
+ column.value = val
152
292
  end
293
+ return self
153
294
  end
154
295
 
155
- def validate
296
+ # 各カラムのバリデーション
297
+ # 戻り値は[ 正規化した値, エラーシンボル(Messageのキーと紐づく) ]を値として、
298
+ # カラムキーをキーとするハッシュ
299
+ def validate(value_h)
300
+ return {} unless value_h
156
301
  clear_error
157
- errors = []
158
- @columns.values.each do |col|
159
- err = col.validate
160
- errors.push([ col.key, err ]) if err
302
+ result_h = {}
303
+ @columns.values.each do |col|
304
+ res = []
305
+ if col.respond_to?(:form_to_value) && !value_h.has_key?(col.key)
306
+ orig_val = col.form_to_value(value_h)
307
+ else
308
+ orig_val = value_h[col.key]
309
+ end
310
+ new_val = col.normalize(orig_val)
311
+ res[0] = new_val if orig_val != new_val
312
+ res[1] = col.validate(new_val)
313
+ result_h[col.key] = res if res[0] || res[1]
161
314
  end
162
- return errors
315
+ return result_h
163
316
  end
164
317
 
165
318
  def clear_error
166
- @columns.values.each {|col| col.error = nil }
319
+ @columns.values.each { |col| col.error = nil }
167
320
  end
168
321
 
169
322
  def values
170
- @columns.map {|key, col| col.value}
171
- end
323
+ @columns.map { |key, col| col.value }
324
+ end
172
325
 
173
326
  def each
174
- @columns.values.each {|column| yield(column) }
327
+ @columns.values.each { |column| yield(column) }
175
328
  end
176
329
 
177
330
  def map
178
- @columns.values.map {|column| yield(column) }
331
+ @columns.values.map { |column| yield(column) }
179
332
  end
180
333
 
181
334
  def get_matrix(method_a)
182
335
  return @columns.map do |_key, col|
183
- method_a.map { |method| col.send(method) }
184
- end
336
+ method_a.map { |method| col.send(method) }
337
+ end
185
338
  end
186
339
 
187
340
  def get_hash(method)
188
- res_h = {}
341
+ res_h = {}
189
342
  @columns.map do |key, col|
190
343
  res_h[key.to_sym] = col.send(method)
191
344
  end
@@ -195,41 +348,52 @@ module Ezframe
195
348
  def [](col_key)
196
349
  return @columns[col_key.to_sym]
197
350
  end
198
-
351
+
199
352
  def form
200
353
  if @edit_keys
201
- return @edit_keys.map do |key|
202
- col = @columns[key.to_sym]
203
- unless col
204
- mylog "[ERROR] @edit_keys has unknown column:name=#{@name}:key=#{key}"
205
- next
206
- end
207
- col.form
208
- end
354
+ return @edit_keys.map do |key|
355
+ col = @columns[key.to_sym]
356
+ unless col
357
+ Logger.info "[ERROR] @edit_keys has unknown column:name=#{@name}:key=#{key}"
358
+ next
359
+ end
360
+ col.form
361
+ end
209
362
  else
210
- return @columns.values.map {|coltype| coltype.form }
211
- end
363
+ return @columns.values.map { |coltype| coltype.form }
364
+ end
212
365
  end
213
366
 
214
367
  def view
215
368
  if @view_keys
216
- return @view_keys.map do |key|
217
- col = @columns[key.to_sym]
218
- unless col
219
- mylog "[ERROR] @view_keys has unknown column:name=#{@name}:key=#{key}"
220
- next
221
- end
222
- col.view
223
- end
369
+ return @view_keys.map do |key|
370
+ col = @columns[key.to_sym]
371
+ unless col
372
+ Logger.info "[ERROR] @view_keys has unknown column:name=#{@name}:key=#{key}"
373
+ next
374
+ end
375
+ col.view
376
+ end
224
377
  else
225
- return @columns.values.map {|coltype| coltype.view }
378
+ return @columns.values.map { |coltype| coltype.view }
226
379
  end
227
380
  end
228
381
 
382
+ def get_full_join(opts = {})
383
+ struct = ColumnSets.full_join_structure(self.name)
384
+ return DB.get_join_table(struct, opts)
385
+ end
386
+
229
387
  def hidden_form
230
388
  return @columns.map do |colkey, coltype|
231
- { tag: 'input', id: colkey, name: colkey, type: 'hidden', value: coltype.value }
232
- end
389
+ { tag: "input", id: colkey, name: colkey, type: "hidden", value: coltype.value }
390
+ end
391
+ end
392
+
393
+ def inpsect
394
+ @columns.map do |colkey, coltype|
395
+ "#{colkey}=#{coltype.value}"
396
+ end.join(" ")
233
397
  end
234
398
  end
235
399
  end