user.go 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269
  1. package store
  2. import (
  3. "context"
  4. "strings"
  5. )
  6. // Role is the type of a role.
  7. type Role string
  8. const (
  9. // RoleHost is the HOST role.
  10. RoleHost Role = "HOST"
  11. // RoleAdmin is the ADMIN role.
  12. RoleAdmin Role = "ADMIN"
  13. // RoleUser is the USER role.
  14. RoleUser Role = "USER"
  15. )
  16. func (e Role) String() string {
  17. switch e {
  18. case RoleHost:
  19. return "HOST"
  20. case RoleAdmin:
  21. return "ADMIN"
  22. case RoleUser:
  23. return "USER"
  24. }
  25. return "USER"
  26. }
  27. type User struct {
  28. ID int32
  29. // Standard fields
  30. RowStatus RowStatus
  31. CreatedTs int64
  32. UpdatedTs int64
  33. // Domain specific fields
  34. Username string
  35. Role Role
  36. Email string
  37. Nickname string
  38. PasswordHash string
  39. AvatarURL string
  40. }
  41. type UpdateUser struct {
  42. ID int32
  43. UpdatedTs *int64
  44. RowStatus *RowStatus
  45. Username *string
  46. Role *Role
  47. Email *string
  48. Nickname *string
  49. Password *string
  50. AvatarURL *string
  51. PasswordHash *string
  52. }
  53. type FindUser struct {
  54. ID *int32
  55. RowStatus *RowStatus
  56. Username *string
  57. Role *Role
  58. Email *string
  59. Nickname *string
  60. }
  61. type DeleteUser struct {
  62. ID int32
  63. }
  64. func (s *Store) CreateUser(ctx context.Context, create *User) (*User, error) {
  65. stmt := `
  66. INSERT INTO user (
  67. username,
  68. role,
  69. email,
  70. nickname,
  71. password_hash
  72. )
  73. VALUES (?, ?, ?, ?, ?)
  74. RETURNING id, avatar_url, created_ts, updated_ts, row_status
  75. `
  76. if err := s.db.QueryRowContext(
  77. ctx,
  78. stmt,
  79. create.Username,
  80. create.Role,
  81. create.Email,
  82. create.Nickname,
  83. create.PasswordHash,
  84. ).Scan(
  85. &create.ID,
  86. &create.AvatarURL,
  87. &create.CreatedTs,
  88. &create.UpdatedTs,
  89. &create.RowStatus,
  90. ); err != nil {
  91. return nil, err
  92. }
  93. user := create
  94. s.userCache.Store(user.ID, user)
  95. return user, nil
  96. }
  97. func (s *Store) UpdateUser(ctx context.Context, update *UpdateUser) (*User, error) {
  98. set, args := []string{}, []any{}
  99. if v := update.UpdatedTs; v != nil {
  100. set, args = append(set, "updated_ts = ?"), append(args, *v)
  101. }
  102. if v := update.RowStatus; v != nil {
  103. set, args = append(set, "row_status = ?"), append(args, *v)
  104. }
  105. if v := update.Username; v != nil {
  106. set, args = append(set, "username = ?"), append(args, *v)
  107. }
  108. if v := update.Email; v != nil {
  109. set, args = append(set, "email = ?"), append(args, *v)
  110. }
  111. if v := update.Nickname; v != nil {
  112. set, args = append(set, "nickname = ?"), append(args, *v)
  113. }
  114. if v := update.AvatarURL; v != nil {
  115. set, args = append(set, "avatar_url = ?"), append(args, *v)
  116. }
  117. if v := update.PasswordHash; v != nil {
  118. set, args = append(set, "password_hash = ?"), append(args, *v)
  119. }
  120. args = append(args, update.ID)
  121. query := `
  122. UPDATE user
  123. SET ` + strings.Join(set, ", ") + `
  124. WHERE id = ?
  125. RETURNING id, username, role, email, nickname, password_hash, avatar_url, created_ts, updated_ts, row_status
  126. `
  127. user := &User{}
  128. if err := s.db.QueryRowContext(ctx, query, args...).Scan(
  129. &user.ID,
  130. &user.Username,
  131. &user.Role,
  132. &user.Email,
  133. &user.Nickname,
  134. &user.PasswordHash,
  135. &user.AvatarURL,
  136. &user.CreatedTs,
  137. &user.UpdatedTs,
  138. &user.RowStatus,
  139. ); err != nil {
  140. return nil, err
  141. }
  142. s.userCache.Store(user.ID, user)
  143. return user, nil
  144. }
  145. func (s *Store) ListUsers(ctx context.Context, find *FindUser) ([]*User, error) {
  146. where, args := []string{"1 = 1"}, []any{}
  147. if v := find.ID; v != nil {
  148. where, args = append(where, "id = ?"), append(args, *v)
  149. }
  150. if v := find.Username; v != nil {
  151. where, args = append(where, "username = ?"), append(args, *v)
  152. }
  153. if v := find.Role; v != nil {
  154. where, args = append(where, "role = ?"), append(args, *v)
  155. }
  156. if v := find.Email; v != nil {
  157. where, args = append(where, "email = ?"), append(args, *v)
  158. }
  159. if v := find.Nickname; v != nil {
  160. where, args = append(where, "nickname = ?"), append(args, *v)
  161. }
  162. query := `
  163. SELECT
  164. id,
  165. username,
  166. role,
  167. email,
  168. nickname,
  169. password_hash,
  170. avatar_url,
  171. created_ts,
  172. updated_ts,
  173. row_status
  174. FROM user
  175. WHERE ` + strings.Join(where, " AND ") + `
  176. ORDER BY created_ts DESC, row_status DESC
  177. `
  178. rows, err := s.db.QueryContext(ctx, query, args...)
  179. if err != nil {
  180. return nil, err
  181. }
  182. defer rows.Close()
  183. list := make([]*User, 0)
  184. for rows.Next() {
  185. var user User
  186. if err := rows.Scan(
  187. &user.ID,
  188. &user.Username,
  189. &user.Role,
  190. &user.Email,
  191. &user.Nickname,
  192. &user.PasswordHash,
  193. &user.AvatarURL,
  194. &user.CreatedTs,
  195. &user.UpdatedTs,
  196. &user.RowStatus,
  197. ); err != nil {
  198. return nil, err
  199. }
  200. list = append(list, &user)
  201. }
  202. if err := rows.Err(); err != nil {
  203. return nil, err
  204. }
  205. for _, user := range list {
  206. s.userCache.Store(user.ID, user)
  207. }
  208. return list, nil
  209. }
  210. func (s *Store) GetUser(ctx context.Context, find *FindUser) (*User, error) {
  211. if find.ID != nil {
  212. if cache, ok := s.userCache.Load(*find.ID); ok {
  213. return cache.(*User), nil
  214. }
  215. }
  216. list, err := s.ListUsers(ctx, find)
  217. if err != nil {
  218. return nil, err
  219. }
  220. if len(list) == 0 {
  221. return nil, nil
  222. }
  223. user := list[0]
  224. s.userCache.Store(user.ID, user)
  225. return user, nil
  226. }
  227. func (s *Store) DeleteUser(ctx context.Context, delete *DeleteUser) error {
  228. result, err := s.db.ExecContext(ctx, `
  229. DELETE FROM user WHERE id = ?
  230. `, delete.ID)
  231. if err != nil {
  232. return err
  233. }
  234. if _, err := result.RowsAffected(); err != nil {
  235. return err
  236. }
  237. if err := s.Vacuum(ctx); err != nil {
  238. // Prevent linter warning.
  239. return err
  240. }
  241. s.userCache.Delete(delete.ID)
  242. return nil
  243. }