Skip to content

Commit 3aa27a1

Browse files
committed
Added documents for Columns / Associations / Datasets
1 parent 7a82ce5 commit 3aa27a1

3 files changed

Lines changed: 365 additions & 0 deletions

File tree

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
# SimpleMaster Association 仕様 (日本語)
2+
3+
## 全体説明
4+
SimpleMaster の Association は `belongs_to` / `has_one` / `has_many` / `has_many :through` を提供します。
5+
6+
## 定義方法
7+
```ruby
8+
class Player < ApplicationRecord
9+
belongs_to :level, foreign_key: :lv, primary_key: :lv
10+
has_many :player_items
11+
end
12+
```
13+
14+
```ruby
15+
class Reward < ApplicationMaster
16+
belongs_to :enemy
17+
belongs_to :reward, polymorphic: true
18+
end
19+
```
20+
21+
対象が `SimpleMaster::Master``ActiveRecord::Base` かで参照方法が変わります。
22+
23+
- Master 同士: `all_by` / `find_by` を使った参照
24+
- 取得が高速なため、都度引き直しとなります。利用時に呼ぶ回数多いなら、変数に格納してください。
25+
- ActiveRecord: `simple_master_connection` で DB 参照
26+
- `belongs_to_store` / `has_many_store` (RequestStore) に保持されるため、リクエストごとにキャッシュが効きます。
27+
28+
## 共通オプション
29+
### `class_name:`
30+
- 例: `belongs_to :reward, class_name: "Weapon"`
31+
- 明示的に参照先クラスを指定します。
32+
33+
### `foreign_key:`
34+
- 例: `has_many :players, foreign_key: :lv`
35+
- 外部キー名を指定します。
36+
37+
### `primary_key:`
38+
- 例: `belongs_to :level, primary_key: :lv`
39+
- 参照先のキーを指定します(デフォルトは `:id`)。
40+
41+
## Association 種別
42+
- `belongs_to` : `belongs_to :enemy`
43+
- `belongs_to (polymorphic)` : `belongs_to :reward, polymorphic: true`
44+
- 前提: `def_column :reward_type, polymorphic_type: true`
45+
- `has_one` : `has_one :profile`
46+
- `has_many` : `has_many :players, foreign_key: :lv`
47+
- `has_many :through` : `has_many :items, through: :player_items`
48+
- `source:` を指定すると参照先の名前を変更できます。

docs/simple_master_columns_ja.md

Lines changed: 197 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,197 @@
1+
# SimpleMaster カラム仕様 (日本語)
2+
3+
## 全体説明
4+
SimpleMaster のカラムは `def_column` で定義し、ロード時に型変換・キャッシュ・補助メソッドを自動生成します。
5+
`type` や各種 DSL によって、変換ルールや追加メソッドが決まります。
6+
7+
```ruby
8+
class Weapon < ApplicationMaster
9+
def_column :id
10+
def_column :name, type: :string
11+
def_column :attack, type: :float
12+
def_column :rarity
13+
14+
enum :rarity, { common: 0, rare: 1, epic: 2 }
15+
end
16+
```
17+
18+
## 共通オプション
19+
### `type:`
20+
- 例: `def_column :attack, type: :float`
21+
- 対応タイプは「カラムタイプ別一覧」を参照してください。
22+
23+
### `group_key:`
24+
- 例: `def_column :lv, type: :integer, group_key: true`
25+
- もしくは `group_key :lv` でも指定できます。
26+
27+
### `db_column_name:`
28+
- DB 側のカラム名が異なる場合に使います。
29+
- 例: `def_column :start_at, type: :time, db_column_name: :start_time`
30+
31+
### `globalize:`
32+
- 言語による差分が定義でき、`I18n.locale` に応じた値を返すようになります。
33+
- 例: `def_column :name, globalize: true`
34+
- もしくは `globalize :name` でも指定できます。
35+
- `@_globalized_name` に翻訳文が `{ en: "Storm Edge", ja: "ストームエッジ" }` のように入ります。
36+
- `id` / `enum` / `bitmask` / `sti` / `polymorphic_type` では利用できません。
37+
- `group_key` とは併用できません。
38+
39+
## カラムタイプ別一覧
40+
41+
### id (IdColumn)
42+
**指定方法**
43+
```ruby
44+
def_column :id
45+
```
46+
**挙動**
47+
- 代入時に `to_i` で変換。
48+
- テスト用の更新時に `id_hash` を再構築するための処理が入ります。
49+
50+
### integer
51+
**指定方法**
52+
```ruby
53+
def_column :lv, type: :integer
54+
```
55+
**挙動**
56+
- 代入時に nil 以外は `to_i` で変換されます(空文字は `nil` に)。
57+
58+
### float
59+
**指定方法**
60+
```ruby
61+
def_column :attack, type: :float
62+
```
63+
**挙動**
64+
- 代入時に nil 以外は `to_f` で変換されます(空文字は `nil` に)。
65+
66+
### string
67+
**指定方法**
68+
```ruby
69+
def_column :name, type: :string
70+
```
71+
**挙動**
72+
- 代入時に nil 以外は `to_s` で変換されます。
73+
- メモリ節約のために、オブジェクトはキャッシュされ、同じ値ならオブジェクトは流用されます。(object_cache)
74+
75+
### symbol
76+
**指定方法**
77+
```ruby
78+
def_column :kind, type: :symbol
79+
```
80+
**挙動**
81+
- 代入時に nil 以外は `to_s` + `to_sym` で変換されます。
82+
- SQL/CSV 用には文字列として出力されます。
83+
84+
### boolean
85+
**指定方法**
86+
```ruby
87+
def_column :is_boss, type: :boolean
88+
```
89+
**挙動**
90+
- `Integer` は 0/1、`String` は "true" / "1" で判定。
91+
- `name?` のメソッドが追加されます。
92+
- SQL/CSV 出力時は 0/1 に変換されます。
93+
94+
### json
95+
**指定方法**
96+
```ruby
97+
def_column :info, type: :json
98+
```
99+
**オプション**
100+
- `symbolize_names: true` を指定すると JSON 文字列をシンボルキーに変換します。
101+
102+
**挙動**
103+
- 文字列の場合は `JSON.parse`
104+
- SQL/CSV 出力時は `JSON.generate` で文字列化されます。
105+
- 注意点: 文字列以外の代入は、`symbolize_names` によるキー変換は行われません。
106+
107+
### time
108+
**指定方法**
109+
```ruby
110+
def_column :start_at, type: :time
111+
```
112+
**オプション**
113+
- `db_type: :time` を指定すると時刻だけの形式 (`HH:MM:SS`) で出力します。
114+
115+
**挙動**
116+
- 文字列を `Date._parse` で解析して `Time` に変換します。
117+
- 小数秒は切り捨てられます。
118+
119+
### enum
120+
**指定方法**
121+
```ruby
122+
def_column :rarity, enum: { common: 0, rare: 1, epic: 2 }
123+
# or
124+
def_column :rarity
125+
enum :rarity, { common: 0, rare: 1, epic: 2 }
126+
```
127+
**オプション**
128+
- `prefix`, `suffix`: 述語メソッドに prefix / suffix を付けられます。
129+
- `prefix: true``rarity_common?` のようになります。
130+
- `suffix: :rarity``common_rarity?` のようになります。
131+
132+
**挙動**
133+
- 値は `Symbol` として扱われます。
134+
- `rarities` クラスメソッドと `rarity_before_type_cast` が追加されます。
135+
- 述語メソッド (例: `common?`) が自動生成されます。
136+
137+
### bitmask
138+
**指定方法**
139+
```ruby
140+
def_column :flags, type: :integer
141+
bitmask :flags, as: [:tradeable, :soulbound, :limited]
142+
```
143+
**挙動**
144+
- 配列/シンボル/整数を受け取り、内部では整数ビットに変換します。
145+
- `flags` はシンボル配列として返ります。
146+
- `flags_value` / `flags_value=` が追加されます。ビット列の数値が返ります。
147+
148+
### sti (STIタイプカラム)
149+
**指定方法**
150+
```ruby
151+
def_column :type, sti: true
152+
```
153+
**挙動**
154+
- `type` を文字列に変換します。
155+
- Loader 側で `type` を見てクラス分岐する運用になります。
156+
- `sti_base_class``sti_column` が定義されます。
157+
158+
### polymorphic_type
159+
**指定方法**
160+
```ruby
161+
def_column :reward_type, polymorphic_type: true
162+
```
163+
**挙動**
164+
- `belongs_to polymorphic` のタイプカラムとして使います。
165+
- `reward_type` を文字列として保持し、`reward_type_class` を自動で設定します。
166+
- 空文字は `nil` に変換されます。
167+
168+
## カラムのカスタム定義
169+
独自のカラム型を追加する場合は `SimpleMaster::Master::Column` を継承します。
170+
クラス名の末尾が `Column` であれば、自動で `type` が登録されます。
171+
172+
```ruby
173+
class MoneyColumn < SimpleMaster::Master::Column
174+
private
175+
176+
def code_for_conversion
177+
<<-RUBY
178+
value = value&.to_i
179+
RUBY
180+
end
181+
182+
def code_for_sql_value
183+
<<-RUBY
184+
#{name}
185+
RUBY
186+
end
187+
end
188+
189+
# 利用側
190+
class Product < ApplicationMaster
191+
def_column :price, type: :money
192+
end
193+
```
194+
195+
- カスタムカラムのファイルはロード対象に含めてください。
196+
- `init` をオーバーライドすると、独自メソッドの生成も可能です。
197+
- 詳しくは [lib/simple_master/master/column.rb](lib/simple_master/master/column.rb) 定義ファイルを直接ご覧ください

docs/simple_master_dataset_ja.md

Lines changed: 120 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,120 @@
1+
# SimpleMaster Dataset / Table 仕様 (日本語)
2+
3+
## 全体説明
4+
SimpleMaster ではデータの実体を `Dataset` が持ち、各 Master クラスごとに `Table` が対応します。
5+
`Loader` が外部データを読み込み、`Table` がレコードと各種キャッシュを保持します。
6+
7+
```
8+
Dataset
9+
├─ Table (Weapon)
10+
├─ Table (Armor)
11+
└─ Table (Level)
12+
```
13+
14+
## Dataset
15+
### 役割
16+
- `loader` を使って各 `Table` をロードする
17+
- `cache` を保持し、クラス/インスタンスのキャッシュに利用する
18+
- `diff` による差分上書きを提供する
19+
20+
### 基本の使い方
21+
```ruby
22+
loader = SimpleMaster::Loader::QueryLoader.new
23+
dataset = SimpleMaster::Storage::Dataset.new(loader: loader)
24+
dataset.load
25+
26+
SimpleMaster.use_dataset(dataset) do
27+
# dataset を使った処理
28+
end
29+
```
30+
31+
### 主なAPI
32+
- `load` : 全対象テーブルをロードし、キャッシュを更新
33+
- `reload` : `Table` の種類に応じて再ロード/アンロードを実行
34+
- `unload` : テーブルとキャッシュをクリア
35+
- `duplicate(diff: nil)` : dataset を複製 (diff も継承)
36+
- `table(klass)` : 対象クラスの `Table` を取得
37+
38+
### 差分 (diff)
39+
Loader から取得するデータの上にさらに変更を自動的に加えられる仕組みです。
40+
`dataset.diff` に JSON/Hash を設定するとロード後に差分が適用されます。
41+
`Table.apply_diff``id_hash` を更新し、差分レコードを上書きします。
42+
43+
```ruby
44+
dataset = SimpleMaster::Storage::Dataset.new
45+
46+
dataset.diff = {
47+
"weapons" => {
48+
"1" => { "name" => "Updated Name" },
49+
"2" => nil
50+
}
51+
}
52+
53+
dataset.load
54+
```
55+
56+
### Dataset キャッシュ
57+
`cache_read` / `cache_fetch` / `cache_write` / `cache_delete` を用意しています。
58+
外部参照用の軽量キャッシュに使えます。ただし、メモリに保存されるので、容量にご注意ください。
59+
60+
## Table
61+
### 役割
62+
- 対象クラスのレコード配列 (`all`) を保持
63+
- `id_hash` / `grouped_hash` を構築
64+
- クラス/インスタンスキャッシュを更新
65+
- STI サブクラスのサブテーブルを保持
66+
67+
### 主なデータ
68+
- `all` : レコードの配列
69+
- `id_hash` : `id` => record
70+
- `grouped_hash` : `group_key` => grouped records
71+
- `class_method_cache` : `cache_class_method` の結果
72+
- `method_cache` : `cache_method` の結果
73+
74+
### STI とサブテーブル
75+
STI を使うクラスでは、`sub_table` がサブクラスごとの `Table` を返します。
76+
`update_sub_tables``all` からサブクラスを抽出して登録します。
77+
78+
## Table の種類
79+
### Table (デフォルト)
80+
- `Dataset` 読み込み時に全件をロードする
81+
- `load` のタイミングで `all` / `id_hash` / `grouped_hash` を構築
82+
- 基本的に中身は freeze されるので、Copy-on-Write が効きやすい
83+
84+
### OndemandTable
85+
- `all` / `id_hash` / `grouped_hash` を初回アクセス時に構築
86+
- 大規模データやオンデマンド参照で有効
87+
88+
```ruby
89+
dataset = SimpleMaster::Storage::Dataset.new(
90+
table_class: SimpleMaster::Storage::OndemandTable
91+
)
92+
```
93+
94+
### TestTable
95+
- テスト向けの軽量テーブル
96+
- `update` / `record_updated` による差分更新を前提とする
97+
98+
```ruby
99+
dataset = SimpleMaster::Storage::Dataset.new(
100+
table_class: SimpleMaster::Storage::TestTable
101+
)
102+
```
103+
104+
## Loader
105+
`Loader``read_raw``build_records` を実装して使います。
106+
既存の `QueryLoader` / `MarshalLoader` のほか、アプリケーションの要件に応じて Loader を作れます。
107+
108+
```ruby
109+
class JsonLoader < SimpleMaster::Loader
110+
FIXTURE_DIR = Rails.root.join("fixtures/masters")
111+
112+
def read_raw(table)
113+
File.read(FIXTURE_DIR.join("#{table.klass.table_name}.json"))
114+
end
115+
116+
def build_records(klass, raw)
117+
JSON.parse(raw).map { |attrs| klass.new(attrs) }
118+
end
119+
end
120+
```

0 commit comments

Comments
 (0)