ezframe 0.1.1 → 0.2.0

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.
@@ -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