memo_resource.go 4.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218
  1. package store
  2. import (
  3. "context"
  4. "database/sql"
  5. "strings"
  6. )
  7. type MemoResource struct {
  8. MemoID int
  9. ResourceID int
  10. CreatedTs int64
  11. UpdatedTs int64
  12. }
  13. type UpsertMemoResource struct {
  14. MemoID int
  15. ResourceID int
  16. CreatedTs int64
  17. UpdatedTs *int64
  18. }
  19. type FindMemoResource struct {
  20. MemoID *int
  21. ResourceID *int
  22. }
  23. type DeleteMemoResource struct {
  24. MemoID *int
  25. ResourceID *int
  26. }
  27. func (s *Store) UpsertMemoResource(ctx context.Context, upsert *UpsertMemoResource) (*MemoResource, error) {
  28. tx, err := s.db.BeginTx(ctx, nil)
  29. if err != nil {
  30. return nil, err
  31. }
  32. defer tx.Rollback()
  33. set := []string{"memo_id", "resource_id"}
  34. args := []any{upsert.MemoID, upsert.ResourceID}
  35. placeholder := []string{"?", "?"}
  36. if v := upsert.UpdatedTs; v != nil {
  37. set, args, placeholder = append(set, "updated_ts"), append(args, v), append(placeholder, "?")
  38. }
  39. query := `
  40. INSERT INTO memo_resource (
  41. ` + strings.Join(set, ", ") + `
  42. )
  43. VALUES (` + strings.Join(placeholder, ",") + `)
  44. ON CONFLICT(memo_id, resource_id) DO UPDATE
  45. SET
  46. updated_ts = EXCLUDED.updated_ts
  47. RETURNING memo_id, resource_id, created_ts, updated_ts
  48. `
  49. memoResource := &MemoResource{}
  50. if err := tx.QueryRowContext(ctx, query, args...).Scan(
  51. &memoResource.MemoID,
  52. &memoResource.ResourceID,
  53. &memoResource.CreatedTs,
  54. &memoResource.UpdatedTs,
  55. ); err != nil {
  56. return nil, err
  57. }
  58. if err := tx.Commit(); err != nil {
  59. return nil, err
  60. }
  61. return memoResource, nil
  62. }
  63. func (s *Store) ListMemoResources(ctx context.Context, find *FindMemoResource) ([]*MemoResource, error) {
  64. tx, err := s.db.BeginTx(ctx, nil)
  65. if err != nil {
  66. return nil, err
  67. }
  68. defer tx.Rollback()
  69. list, err := listMemoResources(ctx, tx, find)
  70. if err != nil {
  71. return nil, err
  72. }
  73. if err := tx.Commit(); err != nil {
  74. return nil, err
  75. }
  76. return list, nil
  77. }
  78. func (s *Store) GetMemoResource(ctx context.Context, find *FindMemoResource) (*MemoResource, error) {
  79. tx, err := s.db.BeginTx(ctx, nil)
  80. if err != nil {
  81. return nil, err
  82. }
  83. defer tx.Rollback()
  84. list, err := listMemoResources(ctx, tx, find)
  85. if err != nil {
  86. return nil, err
  87. }
  88. if len(list) == 0 {
  89. return nil, nil
  90. }
  91. if err := tx.Commit(); err != nil {
  92. return nil, err
  93. }
  94. memoResource := list[0]
  95. return memoResource, nil
  96. }
  97. func (s *Store) DeleteMemoResource(ctx context.Context, delete *DeleteMemoResource) error {
  98. tx, err := s.db.BeginTx(ctx, nil)
  99. if err != nil {
  100. return err
  101. }
  102. defer tx.Rollback()
  103. where, args := []string{}, []any{}
  104. if v := delete.MemoID; v != nil {
  105. where, args = append(where, "memo_id = ?"), append(args, *v)
  106. }
  107. if v := delete.ResourceID; v != nil {
  108. where, args = append(where, "resource_id = ?"), append(args, *v)
  109. }
  110. stmt := `DELETE FROM memo_resource WHERE ` + strings.Join(where, " AND ")
  111. _, err = tx.ExecContext(ctx, stmt, args...)
  112. if err != nil {
  113. return err
  114. }
  115. if err := tx.Commit(); err != nil {
  116. // Prevent linter warning.
  117. return err
  118. }
  119. return nil
  120. }
  121. func listMemoResources(ctx context.Context, tx *sql.Tx, find *FindMemoResource) ([]*MemoResource, error) {
  122. where, args := []string{"1 = 1"}, []any{}
  123. if v := find.MemoID; v != nil {
  124. where, args = append(where, "memo_id = ?"), append(args, *v)
  125. }
  126. if v := find.ResourceID; v != nil {
  127. where, args = append(where, "resource_id = ?"), append(args, *v)
  128. }
  129. query := `
  130. SELECT
  131. memo_id,
  132. resource_id,
  133. created_ts,
  134. updated_ts
  135. FROM memo_resource
  136. WHERE ` + strings.Join(where, " AND ") + `
  137. ORDER BY updated_ts DESC
  138. `
  139. rows, err := tx.QueryContext(ctx, query, args...)
  140. if err != nil {
  141. return nil, err
  142. }
  143. defer rows.Close()
  144. list := make([]*MemoResource, 0)
  145. for rows.Next() {
  146. var memoResource MemoResource
  147. if err := rows.Scan(
  148. &memoResource.MemoID,
  149. &memoResource.ResourceID,
  150. &memoResource.CreatedTs,
  151. &memoResource.UpdatedTs,
  152. ); err != nil {
  153. return nil, err
  154. }
  155. list = append(list, &memoResource)
  156. }
  157. if err := rows.Err(); err != nil {
  158. return nil, err
  159. }
  160. return list, nil
  161. }
  162. func vacuumMemoResource(ctx context.Context, tx *sql.Tx) error {
  163. stmt := `
  164. DELETE FROM
  165. memo_resource
  166. WHERE
  167. memo_id NOT IN (
  168. SELECT
  169. id
  170. FROM
  171. memo
  172. )
  173. OR resource_id NOT IN (
  174. SELECT
  175. id
  176. FROM
  177. resource
  178. )`
  179. _, err := tx.ExecContext(ctx, stmt)
  180. if err != nil {
  181. return err
  182. }
  183. return nil
  184. }