Open1

CSVファイルをDB代わりにデータ保存用に使うための方法

nerusannerusan

モデル

package model

import (
	"errors"
	"fmt"
	"os"

	"github.com/jszwec/csvutil"
)

type User struct {
	UserID             string `csv:"user_id"`
	UserName           string `csv:"user_name"`
	LimitAt            string `csv:"limit_at"`
	SessionID          string `csv:"session_id"`
}

// Users はmodel.Userのスライスです.
type Users []*User

// NewUsers はユーザーデータを読み込みます.
func NewUsers() (Users, error) {
	var users Users
	fileName := "/app/data/users.csv"
	b, err := os.ReadFile(fileName)
	if err != nil {
		file, err := os.Create(fileName)
		if err != nil {
			fmt.Println("ファイルの作成に失敗しました:", err.Error())
			return nil, err
		}
		defer file.Close() // 関数が終了する前にファイルを閉じる
	}

	if err = csvutil.Unmarshal(b, &users); err != nil {
		return nil, err
	}
	return users, nil
}

// Filter はmodel.Users型に対する絞り込み処理を行います.
func (u Users) Filter(fn ...func(*User) bool) Users {
	newUsers := make(Users, 0, len(u))
	for _, v := range u {
		ok := true
		for _, f := range fn {
			if !f(v) {
				ok = false
				break
			}
		}
		if ok {
			newUsers = append(newUsers, v)
		}
	}
	return newUsers
}

// Usersの各要素に処理を適用します。
func (u Users) Apply(fn ...func(*User) *User) Users {
	newUsers := make(Users, 0, len(u))
	for _, v := range u {
		m := v
		for _, f := range fn {
			m = f(m)
		}
		newUsers = append(newUsers, m)
	}
	return newUsers
}

// ユーザーデータを追加
// 最後にSaveを呼び出すことで、CSVファイルに記録されます。
func (u Users) Add(user *User) (Users, error) {
	sameUser := u.Filter(func(v *User) bool {
		return v.UserID == user.UserID
	})
	if len(sameUser) > 0 {
		return nil, errors.New("user_idが重複しています")
	}
	v := append(u, user)
	return v, nil
}

// 指定したuserIDのユーザーデータを削除
// 最後にSaveを呼び出すことで、CSVファイルに記録されます。
func (u Users) Delete(userID string) (Users, error) {
	newUsers := u.Filter(func(v *User) bool {
		return v.UserID != userID
	})
	if len(u) == len(newUsers) {
		return nil, errors.New("ユーザーが存在しません")
	}
	return newUsers, nil
}

// ユーザーデータをCSVファイルに記録
func (u Users) Save() error {
	b, err := csvutil.Marshal(u)
	if err != nil {
		return err
	}
	return os.WriteFile("/app/data/users.csv", b, 0666)
}

使う側

	// ユーザーを取得する
	users, err := model.NewUsers()

	// 該当のユーザー情報を取得する
	searchedUser := users.Filter(func(v *model.User) bool {
		return input.UserID == v.UserID
	})
	// ユーザーが存在しない場合
	if len(searchedUser) == 0 {
            // ・・・
	}

	// セッションIDを更新し、保存する
	sessionID := uuid.New()
	err = users.Apply(func(v *model.User) *model.User {
		if input.UserID == v.UserID {
			v.SessionID = sessionID.String()
		}
		return v
	}).Save()