Line data Source code
1 : // Package valueobject は、ユースケース層で使用する補助的な値オブジェクトを提供します。
2 : package valueobject
3 :
4 : // 特に PATCH リクエストなどにおいて、フィールドの状態を3値で表現するための
5 : // PatchValue 型を定義します。
6 : //
7 : // PatchValue は以下の3つの状態を区別できます:
8 : //
9 : // - JSON にフィールドが **含まれていない** → Unset(更新対象外)
10 : // - JSON にフィールドが **null として含まれる** → Cleared(クリア/リセット)
11 : // - JSON にフィールドが **具体的な値で含まれる** → Set(更新対象)
12 : //
13 : // これにより、「未送信」「明示的に削除」「値を変更」の区別を
14 : // バックエンド側で安全に扱うことができます。
15 :
16 : import "encoding/json"
17 :
18 : // PatchValue は、PATCH リクエストなどで利用する「3値入力」を表すジェネリックな値オブジェクトです。
19 : // 型パラメータ T は、json.Unmarshal 可能な任意の型を指定できます。
20 : //
21 : // 例えば、次のようにユースケース入力構造体で使用します:
22 : //
23 : // type PatchUserProfileInput struct {
24 : // Initial valueobject.PatchValue[string] `json:"initial"`
25 : // BirthDate valueobject.PatchValue[string] `json:"birthDate"`
26 : // GenderID valueobject.PatchValue[uint8] `json:"genderId"`
27 : // }
28 : //
29 : // 各フィールドは次のように評価されます:
30 : //
31 : // - JSON にキーが存在しない場合 … Set=false, Value=nil (更新しない)
32 : // - JSON に null が指定された場合 … Set=true, Value=nil (値をクリアする)
33 : // - JSON に具体的な値が指定された場合 … Set=true, Value=&値 (値を更新する)
34 : //
35 : // これにより、Interactor 側で「未指定・クリア・更新」を安全に判定できます。
36 : type PatchValue[T any] struct {
37 : Set bool // JSON にフィールドが存在する場合 true
38 : Value *T // 値(null の場合は nil)
39 : }
40 :
41 : // UnmarshalJSON は json.Unmarshaler インタフェースを実装します。
42 : // JSON 解析時に「キーが存在したかどうか(Set)」と「値が null かどうか」を判定します。
43 0 : func (p *PatchValue[T]) UnmarshalJSON(data []byte) error {
44 0 : p.Set = true
45 0 :
46 0 : // "null" の場合は明示的にクリア指定
47 0 : if string(data) == "null" {
48 0 : p.Value = nil
49 0 : return nil
50 0 : }
51 :
52 : // それ以外は通常の値としてパース
53 0 : var v T
54 0 : if err := json.Unmarshal(data, &v); err != nil {
55 0 : return err
56 0 : }
57 0 : p.Value = &v
58 0 : return nil
59 : }
60 :
61 : // IsUnset は、このフィールドが JSON に含まれていなかった場合に true を返します。
62 : // この場合は更新対象外として扱うのが一般的です。
63 0 : func (p PatchValue[T]) IsUnset() bool {
64 0 : return !p.Set
65 0 : }
66 :
67 : // IsCleared は、このフィールドが JSON に含まれ、かつ値が null であった場合に true を返します。
68 : // この場合は、既存の値をクリア(NULL や空文字に更新)することを意図します。
69 0 : func (p PatchValue[T]) IsCleared() bool {
70 0 : return p.Set && p.Value == nil
71 0 : }
72 :
73 : // IsSet は、このフィールドが JSON に含まれ、かつ値が null ではない場合に true を返します。
74 : // この場合は、新しい値に更新することを意図します。
75 0 : func (p PatchValue[T]) IsSet() bool {
76 0 : return p.Set && p.Value != nil
77 0 : }
|