arxutils_sqlite3 0.1.37
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.rspec +3 -0
- data/.rubocop.yml +20 -0
- data/.rubocop_todo.yml +387 -0
- data/CHANGELOG.md +5 -0
- data/CODE_OF_CONDUCT.md +84 -0
- data/Gemfile +41 -0
- data/LICENSE +21 -0
- data/LICENSE.txt +21 -0
- data/README.md +43 -0
- data/Rakefile +12 -0
- data/arxutils_sqlite3.gemspec +52 -0
- data/bin/arxutils-cli +134 -0
- data/bin/console +15 -0
- data/bin/makemigrate +55 -0
- data/bin/setup +8 -0
- data/bin/setupx.bat +7 -0
- data/bin/setupx.rb +4 -0
- data/config/.gitignore +3 -0
- data/lib/arxutils_sqlite3/arx.rb +41 -0
- data/lib/arxutils_sqlite3/dbutil/dbconnect.rb +95 -0
- data/lib/arxutils_sqlite3/dbutil/dbmgr.rb +28 -0
- data/lib/arxutils_sqlite3/dbutil.rb +22 -0
- data/lib/arxutils_sqlite3/hier.rb +218 -0
- data/lib/arxutils_sqlite3/migrate.rb +225 -0
- data/lib/arxutils_sqlite3/transactstate.rb +76 -0
- data/lib/arxutils_sqlite3/version.rb +4 -0
- data/lib/arxutils_sqlite3.rb +40 -0
- data/lib/template/config/mysql.tmpl +29 -0
- data/lib/template/config/sqlite3.tmpl +26 -0
- data/lib/template/relation/base.tmpl +14 -0
- data/lib/template/relation/current.tmpl +15 -0
- data/lib/template/relation/db_scheme/db_scheme.yml +48 -0
- data/lib/template/relation/db_scheme/dbsetup.rb +51 -0
- data/lib/template/relation/db_scheme/opts.rb +8 -0
- data/lib/template/relation/invalid.tmpl +12 -0
- data/lib/template/relation/noitem.tmpl +13 -0
- data/lib/template/relation/relation.tmpl +3 -0
- data/lib/template/relation/relation_count.tmpl +3 -0
- data/lib/template/relation/relation_current.tmpl +3 -0
- data/lib/template/relation/relation_invalid.tmpl +4 -0
- metadata +85 -0
@@ -0,0 +1,218 @@
|
|
1
|
+
module Arxutils_Sqlite3
|
2
|
+
# 階層処理
|
3
|
+
class HierOp
|
4
|
+
# 階層処理を付加したいフィールド名(未使用か?)
|
5
|
+
attr_reader :field_name
|
6
|
+
# '/'が区切り文字の文字列で階層処理を実現するクラスの階層構造を表す文字列を持つメソッド/アトリビュートを表すシンボル
|
7
|
+
attr_reader :hier_symbol
|
8
|
+
# '/'が区切り文字の文字列で階層処理を実現するクラスのクラス名(DB中のテーブルに対応するActiveRecordの子クラス)
|
9
|
+
# シンボルhier_symbolで指定できるメソッド/アトリビュート(string)を持つ。
|
10
|
+
# nameというメソッド/アトリビュート(string)を持つ。"'/'を区切り文字として持つ階層を表す文字列
|
11
|
+
# registerメソッドを呼び出す時は、hier_symbolのみを指定してcreate出来なければならない(そうでなければSQLの制約違反発生)
|
12
|
+
attr_reader :base_klass
|
13
|
+
# '/'が区切り文字の文字列で階層処理を実現するクラスのカレントに対応するクラス名(DB中のテーブルに対応するActiveRecordの子クラス)
|
14
|
+
attr_reader :current_klass
|
15
|
+
# '/'が区切り文字の文字列で階層処理を実現するクラスのインバリッドに対応するクラス名(DB中のテーブルに対応するActiveRecordの子クラス)
|
16
|
+
attr_reader :invalid_klass
|
17
|
+
# IDの親子関係で階層処理を実現するクラス名(DB中のテーブルに対応するActiveRecordの子クラス)
|
18
|
+
# parent_id(integer) , child_id(integer) , leve(integer)というメソッド/アトリビュートを持つ
|
19
|
+
attr_reader :hier_klass
|
20
|
+
|
21
|
+
# 初期化
|
22
|
+
def initialize(field_name, hier_symbol, _hier_name, base_klass, hier_klass, current_klass, invalid_klass)
|
23
|
+
# 階層処理を付加したいフィールド名
|
24
|
+
@field_name = field_name
|
25
|
+
# '/'が区切り文字の文字列で階層処理を実現するクラスの階層構造を表す文字列を持つメソッド/アトリビュートを表すシンボ
|
26
|
+
@hier_symbol = hier_symbol
|
27
|
+
# '/'が区切り文字の文字列で階層処理を実現するクラスのクラス名(DB中のテーブルに対応するActiveRecordの子クラス)
|
28
|
+
@base_klass = base_klass
|
29
|
+
# '/'が区切り文字の文字列で階層処理を実現するクラスのカレントに対応するクラス名(DB中のテーブルに対応するActiveRecordの子クラス)
|
30
|
+
@current_klass = current_klass
|
31
|
+
# '/'が区切り文字の文字列で階層処理を実現するクラスのインバリッドに対応するクラス名(DB中のテーブルに対応するActiveRecordの子クラス)
|
32
|
+
@invalid_klass = invalid_klass
|
33
|
+
# IDの親子関係で階層処理を実現するクラス名(DB中のテーブルに対応するActiveRecordの子クラス)
|
34
|
+
# print_id(integer), child_id(integer), level(integer)
|
35
|
+
@hier_klass = hier_klass
|
36
|
+
end
|
37
|
+
|
38
|
+
# 指定した階層(階層を/で区切って表現)のアイテムをbase_klassから削除
|
39
|
+
def delete(hier)
|
40
|
+
# 子として探す
|
41
|
+
id = nil
|
42
|
+
base = @base_klass.find_by({ @hier_symbol => hier })
|
43
|
+
if base
|
44
|
+
delete_at(base.org_id)
|
45
|
+
@base_klass.delete_at(base.id)
|
46
|
+
end
|
47
|
+
id
|
48
|
+
end
|
49
|
+
|
50
|
+
def delete_by_id(id)
|
51
|
+
base = @base_klass.find_by(org_id: id)
|
52
|
+
delete_at(id)
|
53
|
+
@base_klass.delete_at(base.id)
|
54
|
+
end
|
55
|
+
|
56
|
+
# 文字列で指定した階層を移動
|
57
|
+
def move(src_hier, dest_parent_hier)
|
58
|
+
# dest_parent_hierがsrc_hierの子であれば(=src_hierがdest_parent_hierの先頭からの部分文字列である)何もせずエラーを返す
|
59
|
+
escaped = Regexp.escape(src_hier)
|
60
|
+
src_re = Regexp.new(%(^#{escaped}))
|
61
|
+
ret = (src_re =~ dest_parent_hier)
|
62
|
+
# 自身の子への移動はエラーとする
|
63
|
+
return false if ret
|
64
|
+
|
65
|
+
src_row_item = @base_klass.where(name: src_hier)
|
66
|
+
src_num = src_row_item.id
|
67
|
+
# srcが子である(tblでは項目を一意に指定できる)tblでの項目を得る
|
68
|
+
src_row = @hire_klass.find_by(child_id: src_num)
|
69
|
+
|
70
|
+
dest_parent_row_item = @base_klass.find_by(name: dest_parent_hier)
|
71
|
+
dest_parent_num = if dest_parent_row_item
|
72
|
+
dest_parent_row_item.id
|
73
|
+
else
|
74
|
+
register(dest_parent_hier)
|
75
|
+
end
|
76
|
+
dest_parent_level = get_level_by_child(dest_parent_num)
|
77
|
+
|
78
|
+
# srcの親をdest_parentにする
|
79
|
+
src_row.parent_id = dest_parent_num
|
80
|
+
src_row.save
|
81
|
+
# destに移動後のsrcの子のレベルを調整する
|
82
|
+
level_adjust(src_row, dest_parent_level)
|
83
|
+
# destに移動後のsrcのhierを再設定
|
84
|
+
set_hier(src_row_item, make_hier(dest_parent_row_item.name, get_name(src_row_item)))
|
85
|
+
src_row_item.save
|
86
|
+
# destに移動後のsrcの子のhierを調整する
|
87
|
+
hier_adjust(src_row_item)
|
88
|
+
|
89
|
+
true
|
90
|
+
end
|
91
|
+
|
92
|
+
# 配列で指定した階層を親の階層としてhier_klassに登録
|
93
|
+
def register_parent(hier_ary, child_num, level)
|
94
|
+
hier_ary.pop
|
95
|
+
parent_hier_ary = hier_ary
|
96
|
+
parent_hier = parent_hier_ary.join("/")
|
97
|
+
parent_num = register(parent_hier)
|
98
|
+
hs = { parent_id: parent_num, child_id: child_num, level: level }
|
99
|
+
@hier_klass.create(hs)
|
100
|
+
end
|
101
|
+
|
102
|
+
# 文字列で指定した階層(/を区切り文字として持つ)をhier_klassに登録
|
103
|
+
def register(hier)
|
104
|
+
hier_ary = hier.split("/")
|
105
|
+
level = get_level_by_array(hier_ary)
|
106
|
+
|
107
|
+
# もしhier_aryがnilだけを1個持つ配列、または空文字列だけを1個もつ配列であれば、hier_nameは空文字列になる
|
108
|
+
item_row = @current_klass.find_by({ @hier_symbol => hier })
|
109
|
+
if item_row
|
110
|
+
new_num = item_row.org_id
|
111
|
+
if level.zero?
|
112
|
+
unless @hier_klass.find_by(child_id: new_num)
|
113
|
+
hs = { parent_id: new_num, child_id: new_num, level: level }
|
114
|
+
@hier_klass.create(hs)
|
115
|
+
end
|
116
|
+
else
|
117
|
+
register_parent(hier_ary, new_num, level) unless @hier_klass.find_by(child_id: new_num)
|
118
|
+
end
|
119
|
+
else
|
120
|
+
# @base_klassがhierだけでcreateできる場合は(他にフィールドがnot_nullでないか)、ここに来てもよい。
|
121
|
+
# そうでなければ、SQLの制約違反が発生するため、ここに来ることを避けなければならない。
|
122
|
+
# (あらかじめここが呼ばれないようにdatabaseに登録済みにしておかなければならない。)
|
123
|
+
new_category = @base_klass.create({ @hier_symbol => hier })
|
124
|
+
new_num = new_category.id
|
125
|
+
if level.zero?
|
126
|
+
unless @hier_klass.find_by(child_id: new_num)
|
127
|
+
hs = { parent_id: new_num, child_id: new_num, level: level }
|
128
|
+
@hier_klass.create(hs)
|
129
|
+
end
|
130
|
+
else
|
131
|
+
register_parent(hier_ary, new_num, level)
|
132
|
+
end
|
133
|
+
end
|
134
|
+
new_num
|
135
|
+
end
|
136
|
+
|
137
|
+
private
|
138
|
+
|
139
|
+
# IDで指定した階層を削除
|
140
|
+
def delete_at(num)
|
141
|
+
# 子として探す
|
142
|
+
hier = @hier_klass.find_by(child_id: num)
|
143
|
+
level = hier.level
|
144
|
+
parent_id = hier.parent_id
|
145
|
+
base = @base_klass.find_by(ord_id: num)
|
146
|
+
|
147
|
+
parent_base = @base_klass.find_by(ord_id: parent_id)
|
148
|
+
parent_hier_string = parent_base.__send__ @hier_symbol
|
149
|
+
|
150
|
+
# 属する子を探す
|
151
|
+
children_hier = @hier_klass.where(parent_id: num)
|
152
|
+
# 属する子の階層レベルを調整する(削除するのでlevel - 1になる)
|
153
|
+
children_hier.map { |x| level_adjust(x, level - 1) }
|
154
|
+
# 属する子の親を、親の親にする
|
155
|
+
children_hier.map do |x|
|
156
|
+
x.parent_id = parent_id
|
157
|
+
x.save
|
158
|
+
end
|
159
|
+
# 属する子のhierを調整する
|
160
|
+
children_hier.map do |x|
|
161
|
+
child_base = @base_klass.find_by(org_id: x.child_id)
|
162
|
+
name = get_name(child_base)
|
163
|
+
child_base.hier = make_hier(parent_hier, name)
|
164
|
+
child_base.save
|
165
|
+
hier_adjust(child_base)
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
# 配列で指定した階層のレベルを得る
|
170
|
+
def get_level_by_array(hier_ary)
|
171
|
+
level = hier_ary.size - 1
|
172
|
+
level = 0 if level.negative?
|
173
|
+
level
|
174
|
+
end
|
175
|
+
|
176
|
+
# 階層を表すデータ構造から階層の名前を得る
|
177
|
+
def get_name(items_row)
|
178
|
+
items_row ? items_row.name.split("/").pop : ""
|
179
|
+
end
|
180
|
+
|
181
|
+
# 階層を表すデータ構造で指定された階層の下部階層の名前を調整する
|
182
|
+
def hier_adjust(base)
|
183
|
+
parent_hier_string = base.__send__ @hier_symbol
|
184
|
+
parent_num = base.org_id
|
185
|
+
|
186
|
+
tbl_rows = @hier_klass.where(parent_id: parent_num)
|
187
|
+
return if tbl_rows.size.zero?
|
188
|
+
|
189
|
+
tbl_rows.map do |x|
|
190
|
+
child_num = x.child_id
|
191
|
+
item_row = @base_klass.find_by(org_id: child_num)
|
192
|
+
item_row.hier = make_hier(parent_hier_string, get_name(item_row))
|
193
|
+
item_row.save
|
194
|
+
hier_adjust(item_row)
|
195
|
+
end
|
196
|
+
end
|
197
|
+
|
198
|
+
# 指定項目と、その子のlevelを調整
|
199
|
+
def level_adjust(row, parent_level)
|
200
|
+
row.level = parent_level + 1
|
201
|
+
row.save
|
202
|
+
child_rows = @hier_klass.where(parent_id: row.id)
|
203
|
+
return if child_rows.size.zero?
|
204
|
+
|
205
|
+
child_rows.map { |x| level_adjust(x, row.level) }
|
206
|
+
end
|
207
|
+
|
208
|
+
# IDで指定された階層のレベルを得る
|
209
|
+
def get_level_by_child(num)
|
210
|
+
@hier_klass.find_by(child_id: num).level
|
211
|
+
end
|
212
|
+
|
213
|
+
# 文字列で指定された親の階層の下の子の名前から、子の名前を作成
|
214
|
+
def make_hier(parent_hier, name)
|
215
|
+
[parent_hier, name].join("/")
|
216
|
+
end
|
217
|
+
end
|
218
|
+
end
|
@@ -0,0 +1,225 @@
|
|
1
|
+
#require "arxutils_sqlite3"
|
2
|
+
require "ykutils"
|
3
|
+
require "fileutils"
|
4
|
+
#require "active_support"
|
5
|
+
require "active_record"
|
6
|
+
require "active_record/migration"
|
7
|
+
require "pp"
|
8
|
+
|
9
|
+
# ActiveRecord用ユーティリティモジュール
|
10
|
+
module Arxutils_Sqlite3
|
11
|
+
##
|
12
|
+
# migrateに必要なファイルをテンプレートから作成し、migarteを実行する
|
13
|
+
class Migrate
|
14
|
+
# migrate用スクリプトファイル名の先頭の番号の間隔
|
15
|
+
FILENAME_COUNTER_STEP = 10
|
16
|
+
|
17
|
+
# migrateに必要なファイルをテンプレートから作成し、migarteを実行する
|
18
|
+
def self.migrate(dbconnect, db_scheme_ary, migrate_cmd, relation, opts)
|
19
|
+
mig = Migratex.new(dbconnect, db_scheme_ary, relation, opts)
|
20
|
+
# DB構成情報の生成
|
21
|
+
# dbconfigのテンプレートは内容が固定である。
|
22
|
+
if migrate_cmd == "makeconfig"
|
23
|
+
mig.make_dbconfig(opts)
|
24
|
+
return
|
25
|
+
end
|
26
|
+
# remigrateが指定されれば、migrate用スクリプトとDB構成ファイルとDBファイルを削除する
|
27
|
+
if migrate_cmd == "delete"
|
28
|
+
mig.delete_migrate_config_and_db
|
29
|
+
return
|
30
|
+
end
|
31
|
+
# マイグレーション用スクリプトの生成、relationのクラス定義ファイルの生成、migrate実行
|
32
|
+
mig.process
|
33
|
+
end
|
34
|
+
|
35
|
+
# migrationのスクリプトをファイル出力する
|
36
|
+
def output_all_script(mig, db_scheme_ary)
|
37
|
+
# スキーマ設定配列から、migrate用のスクリプトを作成する
|
38
|
+
db_scheme_ary.map { |x| mig.make_script_group(x) }.flatten(1).each_with_index do |data, index|
|
39
|
+
idy = (index + 1) * FILENAME_COUNTER_STEP
|
40
|
+
mig.output_script(idy, *data)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
# migrate用のスクリプトの内容をテンプレートから作成し、ファイルに出力し、migrateを実行する
|
45
|
+
class Migratex
|
46
|
+
# DB接続までの初期化を行うDbinitクラスのインスタンス
|
47
|
+
#attr_reader :dbinit
|
48
|
+
|
49
|
+
# migrate用のスクリプトの生成、migrateの実行を行うmigratexの生成
|
50
|
+
def initialize(dbconnect, db_scheme_ary, relation, opts)
|
51
|
+
# DB接続までの初期化を行うDbinitクラスのインスタンス
|
52
|
+
@dbconnect = dbconnect
|
53
|
+
# 生成するDB構成情報ファイルパス
|
54
|
+
@dbconfig_dest_path = @dbconnect.dbconfig_dest_path
|
55
|
+
# 参照用DB構成情報ファイル名
|
56
|
+
@dbconfig_src_fname = @dbconnect.dbconfig_src_fname
|
57
|
+
|
58
|
+
# migrate用スクリプトの出力先ディレクトリ名
|
59
|
+
@migrate_dir = @dbconnect.migrate_dir
|
60
|
+
# テンプレートファイル格納ディレクトリ名
|
61
|
+
@src_path = Arxutils_Sqlite3::TEMPLATE_RELATION_DIR
|
62
|
+
# 構成ファイル格納ディレクトリ
|
63
|
+
@src_config_path = Arxutils_Sqlite3::TEMPLATE_CONFIG_DIR
|
64
|
+
# データベーススキーマ定義配列
|
65
|
+
@db_scheme_ary = db_scheme_ary
|
66
|
+
# リレーション指定
|
67
|
+
@relation = relation
|
68
|
+
# オプション指定
|
69
|
+
@opts = opts
|
70
|
+
end
|
71
|
+
|
72
|
+
# マイグレート用スクリプト、DB構成情報ファイル、DBファイルの削除
|
73
|
+
def delete_migrate_config_and_db
|
74
|
+
migrate_dir = @dbconnect.migrate_dir
|
75
|
+
dest_config_dir = @dbconnect.dest_config_dir
|
76
|
+
db_dir = @dbconnect.db_dir
|
77
|
+
|
78
|
+
FileUtils.rm(Dir.glob(File.join(migrate_dir, "*"))) if migrate_dir
|
79
|
+
FileUtils.rm(Dir.glob(File.join(dest_config_dir, "*")))
|
80
|
+
Dir.glob(File.join(db_dir, "*")).each do |x|
|
81
|
+
# puts x
|
82
|
+
FileUtils.rm(x) if File.file?(x)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
|
86
|
+
# マイグレーション用スクリプトの生成、relationのクラス定義ファイルの生成、migrate実行
|
87
|
+
def process
|
88
|
+
# migrationのスクリプトをファイル出力する
|
89
|
+
output_all_script
|
90
|
+
|
91
|
+
# relationを表すクラス定義のファイルの内容を生成
|
92
|
+
content_array = make_content_array
|
93
|
+
# p "content_array=#{content_array}"
|
94
|
+
# 複数形のクラス名を集める
|
95
|
+
count_class_plurals = content_array.reject do |x|
|
96
|
+
x[:need_count_class_plural].nil?
|
97
|
+
end
|
98
|
+
need_count_class_plural = count_class_plurals.map { |x| x[:need_count_class_plural] }
|
99
|
+
# relationのmigrateが必要であれば、それをテンプレートファイルから作成して、スクリプトの内容として追加する
|
100
|
+
if content_array.find { |x| !x.nil? }
|
101
|
+
# p "####### 1"
|
102
|
+
data_count = {
|
103
|
+
count_classname: "Count",
|
104
|
+
need_count_class_plural: need_count_class_plural
|
105
|
+
}
|
106
|
+
# p "data_count=#{data_count}"
|
107
|
+
ary = content_array.collect { |x| x[:content] }.flatten
|
108
|
+
count_content = convert_count_class_relation(data_count, "relation_count.tmpl")
|
109
|
+
ary.unshift(count_content)
|
110
|
+
content_array = ary
|
111
|
+
end
|
112
|
+
# relationのスクリプトを作成
|
113
|
+
output_relation_script(content_array, @relation)
|
114
|
+
end
|
115
|
+
|
116
|
+
# migrationのスクリプトをファイル出力する
|
117
|
+
def output_all_script
|
118
|
+
# スキーマ設定配列から、migrate用のスクリプトを作成する
|
119
|
+
@db_scheme_ary.map { |x| make_script_group(x) }.flatten(1).each_with_index do |data, index|
|
120
|
+
idy = (index + 1) * FILENAME_COUNTER_STEP
|
121
|
+
output_script(idy, *data)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# relationを表すクラス定義のファイルの内容を生成
|
126
|
+
def make_content_array
|
127
|
+
# スキーマ設定配列から、relationのmigrate用のスクリプトの内容(ハッシュ形式)の配列を作成する
|
128
|
+
relations = @db_scheme_ary.map do |x|
|
129
|
+
make_relation(x, "count")
|
130
|
+
end
|
131
|
+
relations.select { |x| x.size.positive? }
|
132
|
+
end
|
133
|
+
|
134
|
+
# Countクラス用のrelationのスクリプトの内容に変換
|
135
|
+
def convert_count_class_relation(data, src_fname)
|
136
|
+
convert(data, @src_path, src_fname)
|
137
|
+
end
|
138
|
+
|
139
|
+
# テンプレートファイルからスクリプトの内容に変換
|
140
|
+
def convert(data, src_dir, src_fname)
|
141
|
+
arx = Arx.new(data, File.join(src_dir, src_fname))
|
142
|
+
# 指定テンプレートファイルからスクリプトの内容に作成
|
143
|
+
arx.create
|
144
|
+
end
|
145
|
+
|
146
|
+
# データベース構成ファイルをテンプレートから生成する
|
147
|
+
def make_dbconfig(data)
|
148
|
+
content = convert(data, @src_config_path, @dbconfig_src_fname)
|
149
|
+
File.open(
|
150
|
+
@dbconfig_dest_path, "w:utf-8") do |f|
|
151
|
+
f.puts(content)
|
152
|
+
end
|
153
|
+
end
|
154
|
+
|
155
|
+
# 英子文字で表現したクラス名が、countを表していなければ、relationを
|
156
|
+
# 英子文字で表現したクラス名が、countを表していれが、空のハッシュを返す
|
157
|
+
# スキーマでbase, noitem以外のフィールドが指定されていれば、そのフィールドに対するrelationの設定の内容を返す
|
158
|
+
def make_relation(data, count_classname_downcase)
|
159
|
+
if data[:classname_downcase] == count_classname_downcase
|
160
|
+
{}
|
161
|
+
else
|
162
|
+
# 指定フィールドのフィールド名に対応したテンプレートファイルを用いて、relation設定を作成
|
163
|
+
data[:flist].each_with_object({ content: [], need_count_class: nil }) do |field_name, s|
|
164
|
+
case field_name
|
165
|
+
when "base", "noitem"
|
166
|
+
name_base = "relation"
|
167
|
+
# data[:relation]がnilに設定されていたら改めて空の配列を設定
|
168
|
+
data[:relation] = [] unless data[:relation]
|
169
|
+
else
|
170
|
+
data[:count_classname_downcase] = count_classname_downcase
|
171
|
+
name_base = "relation_#{field_name}"
|
172
|
+
s[:need_count_class_plural] ||= data[:plural]
|
173
|
+
end
|
174
|
+
# テンプレートファイルからスクリプトの内容を作成
|
175
|
+
content = convert(data, @src_path, "#{name_base}.tmpl")
|
176
|
+
s[:content] << content
|
177
|
+
end
|
178
|
+
end
|
179
|
+
end
|
180
|
+
|
181
|
+
# スキーマ設定からmigarte用スクリプトの内容を生成
|
182
|
+
def make_script_group(data)
|
183
|
+
#p data
|
184
|
+
data[:flist].map {
|
185
|
+
|kind|
|
186
|
+
[kind,
|
187
|
+
convert(data, @src_path, "#{kind}.tmpl"),
|
188
|
+
data[:classname_downcase]
|
189
|
+
] }
|
190
|
+
end
|
191
|
+
|
192
|
+
# migrationのスクリプトをファイル出力する
|
193
|
+
def output_script(idy, kind, content, classname_downcase)
|
194
|
+
additional = case kind
|
195
|
+
when "base", "noitem"
|
196
|
+
""
|
197
|
+
else
|
198
|
+
kind
|
199
|
+
end
|
200
|
+
fname = File.join(@migrate_dir, format("%03d_create_%s%s.rb", idy, additional, classname_downcase))
|
201
|
+
File.open(fname, "w", **{ encoding: Encoding::UTF_8 }) do |f|
|
202
|
+
f.puts(content)
|
203
|
+
end
|
204
|
+
end
|
205
|
+
|
206
|
+
# relationのスクリプトをファイル出力する
|
207
|
+
def output_relation_script(content_array, opts)
|
208
|
+
# pp "=="
|
209
|
+
# pp opts
|
210
|
+
dir = opts[:dir]
|
211
|
+
fname = opts[:filename]
|
212
|
+
fpath = File.join(dir, fname)
|
213
|
+
File.open(fpath, "w") do |file|
|
214
|
+
opts[:module].map { |mod| file.puts("module #{mod}") }
|
215
|
+
content_array.map do |x|
|
216
|
+
file.puts x
|
217
|
+
file.puts ""
|
218
|
+
end
|
219
|
+
opts[:module].map { |_mod| file.puts("end") }
|
220
|
+
end
|
221
|
+
end
|
222
|
+
|
223
|
+
end
|
224
|
+
end
|
225
|
+
end
|
@@ -0,0 +1,76 @@
|
|
1
|
+
module Arxutils_Sqlite3
|
2
|
+
# 簡易的なトランザクション処理
|
3
|
+
class TransactState
|
4
|
+
# 対象ID群
|
5
|
+
attr_reader :ids
|
6
|
+
# 状態
|
7
|
+
attr_accessor :state
|
8
|
+
|
9
|
+
# 初期化
|
10
|
+
def initialize
|
11
|
+
# 対象ID群
|
12
|
+
@ids = []
|
13
|
+
# 状態
|
14
|
+
@state = :NONE
|
15
|
+
end
|
16
|
+
|
17
|
+
# :TRACE状態の時のみ対象IDとして追加
|
18
|
+
def add(xid)
|
19
|
+
@ids << xid if @state == :TRACE
|
20
|
+
end
|
21
|
+
|
22
|
+
# 対象ID群をクリア
|
23
|
+
def clear
|
24
|
+
@ids = []
|
25
|
+
end
|
26
|
+
|
27
|
+
# 処理の必要性の確認
|
28
|
+
def need?
|
29
|
+
@ids.size.positive?
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# 複数の簡易的なトランザクション処理
|
34
|
+
class TransactStateGroup
|
35
|
+
# 初期化
|
36
|
+
def initialize(*names)
|
37
|
+
@names = names
|
38
|
+
@state = :NONE
|
39
|
+
@inst = {}
|
40
|
+
names.map { |x| @inst[x] = TransactState.new }
|
41
|
+
end
|
42
|
+
|
43
|
+
# 処理の必要性の確認
|
44
|
+
def need?
|
45
|
+
@state != :NONE
|
46
|
+
end
|
47
|
+
|
48
|
+
# 状態の一括設定
|
49
|
+
def set_all_inst_state
|
50
|
+
@inst.map { |x| x[1].state = @state }
|
51
|
+
end
|
52
|
+
|
53
|
+
# 状態を:TRACEに一括設定
|
54
|
+
def trace
|
55
|
+
@state = :TRACE
|
56
|
+
set_all_inst_state
|
57
|
+
end
|
58
|
+
|
59
|
+
# 状態を:NONEに一括設定
|
60
|
+
def reset
|
61
|
+
@state = :NONE
|
62
|
+
set_all_inst_state
|
63
|
+
end
|
64
|
+
|
65
|
+
# 指定名の状態を返す
|
66
|
+
def method_missing(name, _lang = nil)
|
67
|
+
@inst[name]
|
68
|
+
end
|
69
|
+
|
70
|
+
# 指定名に対応するかを返す
|
71
|
+
def respond_to_missing?(symbol)
|
72
|
+
name = symbol.to_s
|
73
|
+
@names.include?(name)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
@@ -0,0 +1,40 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
require "ykutils"
|
3
|
+
require "ykxutils"
|
4
|
+
|
5
|
+
require "bigdecimal"
|
6
|
+
require "active_support"
|
7
|
+
require "active_support/core_ext"
|
8
|
+
require "active_record"
|
9
|
+
require "pathname"
|
10
|
+
|
11
|
+
require_relative "arxutils_sqlite3/version"
|
12
|
+
require_relative "arxutils_sqlite3/arx"
|
13
|
+
require_relative "arxutils_sqlite3/transactstate"
|
14
|
+
require_relative "arxutils_sqlite3/hier"
|
15
|
+
require_relative "arxutils_sqlite3/migrate"
|
16
|
+
require_relative "arxutils_sqlite3/dbutil"
|
17
|
+
|
18
|
+
module Arxutils_Sqlite3
|
19
|
+
TOP_DIR = Pathname(__FILE__).parent
|
20
|
+
TEMPLATE_DIR = TOP_DIR.join("template")
|
21
|
+
TEMPLATE_RELATION_DIR = TEMPLATE_DIR.join("relation")
|
22
|
+
TEMPLATE_CONFIG_DIR = TEMPLATE_DIR.join("config")
|
23
|
+
CONFIG_DIR = "config".freeze
|
24
|
+
DEST_CONFIG_DIR = Pathname.new("config")
|
25
|
+
DB_SCHEME_DIR = TEMPLATE_RELATION_DIR.join("db_scheme")
|
26
|
+
DB_SCHEME_FILE = DB_SCHEME_DIR.join("db_scheme.yml")
|
27
|
+
OPTS_FILE_NAME = "opts.rb"
|
28
|
+
OPTS_FILE_NAME_2 = "opts"
|
29
|
+
DBSETUP_FILE_NAME = "dbsetup.rb"
|
30
|
+
DBSETUP_FILE_NAME_2 = "dbsetup"
|
31
|
+
OPTS_FILE = DB_SCHEME_DIR.join(OPTS_FILE_NAME)
|
32
|
+
DBSETUP_FILE = DB_SCHEME_DIR.join(DBSETUP_FILE_NAME)
|
33
|
+
DEST_OPTS_FILE = DEST_CONFIG_DIR.join(OPTS_FILE_NAME)
|
34
|
+
DEST_OPTS_FILE_2 = DEST_CONFIG_DIR.join(OPTS_FILE_NAME_2)
|
35
|
+
DEST_DBSETUP_FILE = DEST_CONFIG_DIR.join(DBSETUP_FILE_NAME)
|
36
|
+
DEST_DBSETUP_FILE_2 = DEST_CONFIG_DIR.join(DBSETUP_FILE_NAME_2)
|
37
|
+
|
38
|
+
class Error < StandardError; end
|
39
|
+
# Your code goes here...
|
40
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
# MySQL
|
2
|
+
# gem install mysql2
|
3
|
+
#
|
4
|
+
# Ensure the SQLite 3 gem is defined in your Gemfile
|
5
|
+
# gem 'sqlite3'
|
6
|
+
#
|
7
|
+
default_env: &default
|
8
|
+
adapter: mysql2
|
9
|
+
host: localhost
|
10
|
+
username:
|
11
|
+
password:
|
12
|
+
database: <%= @data[:dbname] %>
|
13
|
+
pool: 5
|
14
|
+
timeout: 5000
|
15
|
+
|
16
|
+
development:
|
17
|
+
<<: *default
|
18
|
+
database: <%= @data[:dbname] %>_developement
|
19
|
+
|
20
|
+
# Warning: The database defined as "test" will be erased and
|
21
|
+
# re-generated from your development database when you run "rake".
|
22
|
+
# Do not set this db to the same as development or production.
|
23
|
+
test:
|
24
|
+
<<: *default
|
25
|
+
database: <%= @data[:dbname] %>_test
|
26
|
+
|
27
|
+
production:
|
28
|
+
<<: *default
|
29
|
+
database: <%= @data[:dbname] %>_production
|
@@ -0,0 +1,26 @@
|
|
1
|
+
# SQLite version 3.x
|
2
|
+
# gem install sqlite3
|
3
|
+
#
|
4
|
+
# Ensure the SQLite 3 gem is defined in your Gemfile
|
5
|
+
# gem 'sqlite3'
|
6
|
+
#
|
7
|
+
default_env: &default
|
8
|
+
adapter: sqlite3
|
9
|
+
pool: 5
|
10
|
+
timeout: 5000
|
11
|
+
database: <%= @data[:db_dir] %>/production.sqlite3
|
12
|
+
|
13
|
+
development:
|
14
|
+
<<: *default
|
15
|
+
database: <%= @data[:db_dir] %>/development.sqlite3
|
16
|
+
|
17
|
+
# Warning: The database defined as "test" will be erased and
|
18
|
+
# re-generated from your development database when you run "rake".
|
19
|
+
# Do not set this db to the same as development or production.
|
20
|
+
test:
|
21
|
+
<<: *default
|
22
|
+
database: <%= @data[:db_dir] %>/test.sqlite3
|
23
|
+
|
24
|
+
production:
|
25
|
+
<<: *default
|
26
|
+
database: <%= @data[:db_dir] %>/production.sqlite3
|
@@ -0,0 +1,14 @@
|
|
1
|
+
class Create<%= @data[:classname] %> < ActiveRecord::Migration[<%= @data[:ar_version] %>]
|
2
|
+
def self.up
|
3
|
+
create_table :<%= @data[:plural] %> do |t|
|
4
|
+
<% @data[:ary].each do |x| %>
|
5
|
+
t.column :<%= x.name %>, :<%= x.type %>, :null => <%= x.null %>
|
6
|
+
<% end %>
|
7
|
+
t.timestamps null: false
|
8
|
+
end
|
9
|
+
end
|
10
|
+
|
11
|
+
def self.down
|
12
|
+
drop_table :<%= @data[:plural] %>
|
13
|
+
end
|
14
|
+
end
|
@@ -0,0 +1,15 @@
|
|
1
|
+
class CreateCurrent<%= @data[:classname_downcase] %> < ActiveRecord::Migration[<%= @data[:ar_version] %>]
|
2
|
+
def self.up
|
3
|
+
execute <<-SQL
|
4
|
+
CREATE VIEW current<%= @data[:plural] %> AS SELECT id as org_id,
|
5
|
+
<%= @data[:ary].map{|x| x.name }.join(" , ") %>
|
6
|
+
FROM <%= @data[:plural] %> where not exists (select * from invalid<%= @data[:plural] %> where invalid<%= @data[:plural] %>.org_id = <%= @data[:plural] %>.id )
|
7
|
+
SQL
|
8
|
+
end
|
9
|
+
|
10
|
+
def self.down
|
11
|
+
execute <<-SQL
|
12
|
+
DROP VIEW current<%= @data[:plural] %>
|
13
|
+
SQL
|
14
|
+
end
|
15
|
+
end
|