Line data Source code
1 : // Package profile は、ユーザープロフィールに関するユースケースロジックを提供します。
2 : //
3 : // このパッケージはアプリケーション層に属し、
4 : // エンティティやリポジトリを利用してドメイン操作を実現します。
5 : // 特に、ユーザープロフィールの参照・更新(PATCH)・登録(Upsert)などの
6 : // ビジネスロジックを実装します。
7 : package profile
8 :
9 : import (
10 : "context"
11 : "fmt"
12 : "time"
13 :
14 : "resume/internal/domain/entity"
15 : )
16 :
17 : // PatchUserProfile は、ユーザープロフィール情報の登録または更新(Upsert)を行うユースケースです。
18 : //
19 : // 呼び出し元(controller)は、ユーザーIDと部分的なプロフィール情報を
20 : // PatchUserProfileInput 構造体として渡します。
21 : //
22 : // 本メソッドの主な責務は以下の通りです:
23 : // 1. 入力値の検証と正規化(例:BirthDate の日付パース)
24 : // 2. 既存レコードの取得(存在しない場合は新規作成として扱う)
25 : // 3. GenderID(性別ID)の決定:
26 : // - 入力で指定されていればそれを使用
27 : // - 既存レコードがあれば既存値を維持
28 : // - どちらも無ければ「未回答(4)」をセット
29 : // 4. エンティティを構築して Upsert(INSERT ... ON DUPLICATE KEY UPDATE)を実行
30 : //
31 : // 成功時は nil を返し、更新結果は返却しません。
32 : // (参照API側で最新状態を取得する設計としています)
33 0 : func (uc *Interactor) PatchUserProfile(ctx context.Context, in PatchUserProfileInput) error {
34 0 : if in.UserID == 0 {
35 0 : return fmt.Errorf("user_id is required")
36 0 : }
37 :
38 : // Entity 生成
39 0 : up := &entity.UserProfile{
40 0 : UserID: in.UserID,
41 0 : FamilyName: in.FamilyName,
42 0 : GivenName: in.GivenName,
43 0 : FamilyNameKana: in.FamilyNameKana,
44 0 : GivenNameKana: in.GivenNameKana,
45 0 : }
46 0 :
47 0 : // ==========
48 0 : // BirthDate(任意)
49 0 : // ==========
50 0 : if in.BirthDate.IsCleared() {
51 0 : // null 指定 → 「NULL にクリア」したいのでゼロ値ポインタを立てる
52 0 : var z time.Time
53 0 : up.BirthDate = &z
54 0 : } else if in.BirthDate.IsSet() {
55 0 : v := *in.BirthDate.Value
56 0 : if v == "" {
57 0 : // 空文字もクリア扱いにするなら同様
58 0 : var z time.Time
59 0 : up.BirthDate = &z
60 0 : } else {
61 0 : t, err := time.Parse("2006-01-02", v)
62 0 : if err != nil {
63 0 : return fmt.Errorf("invalid birth_date format: must be YYYY-MM-DD")
64 0 : }
65 0 : up.BirthDate = &t
66 : }
67 : }
68 : // IsUnset のときは up.BirthDate は nil のまま(=触らない)
69 :
70 : // ==========
71 : // GenderID(任意・NULL 可)
72 : // ==========
73 0 : if in.GenderID.IsCleared() {
74 0 : // null → クリア(NULL)を表すため 0 をセンチネルに
75 0 : var z uint8 = 0
76 0 : up.GenderID = &z
77 0 : } else if in.GenderID.IsSet() {
78 0 : up.GenderID = in.GenderID.Value // 1,2,... の実値
79 0 : }
80 : // IsUnset のときは up.GenderID は nil のまま
81 :
82 : // ==========
83 : // Initial(任意)
84 : // ==========
85 0 : if in.Initial.IsCleared() {
86 0 : // null → クリア(NULL)を表すため空文字をセンチネルに
87 0 : empty := ""
88 0 : up.Initial = &empty
89 0 : } else if in.Initial.IsSet() {
90 0 : v := *in.Initial.Value
91 0 : if v == "" {
92 0 : // 空文字はクリア扱いで NULL にしたいなら同様
93 0 : empty := ""
94 0 : up.Initial = &empty
95 0 : } else {
96 0 : up.Initial = &v
97 0 : }
98 : }
99 :
100 : // Upsert 実行
101 0 : if err := uc.upRepo.Upsert(ctx, up); err != nil {
102 0 : return fmt.Errorf("failed to upsert user_profile: %w", err)
103 0 : }
104 :
105 0 : return nil
106 : }
|