shortcut.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268
  1. package store
  2. import (
  3. "context"
  4. "database/sql"
  5. "strings"
  6. )
  7. type Shortcut struct {
  8. ID int
  9. // Standard fields
  10. RowStatus RowStatus
  11. CreatorID int
  12. CreatedTs int64
  13. UpdatedTs int64
  14. // Domain specific fields
  15. Title string
  16. Payload string
  17. }
  18. type UpdateShortcut struct {
  19. ID int
  20. UpdatedTs *int64
  21. RowStatus *RowStatus
  22. Title *string
  23. Payload *string
  24. }
  25. type FindShortcut struct {
  26. ID *int
  27. CreatorID *int
  28. Title *string
  29. }
  30. type DeleteShortcut struct {
  31. ID *int
  32. CreatorID *int
  33. }
  34. func (s *Store) CreateShortcut(ctx context.Context, create *Shortcut) (*Shortcut, error) {
  35. tx, err := s.db.BeginTx(ctx, nil)
  36. if err != nil {
  37. return nil, err
  38. }
  39. defer tx.Rollback()
  40. query := `
  41. INSERT INTO shortcut (
  42. title,
  43. payload,
  44. creator_id
  45. )
  46. VALUES (?, ?, ?)
  47. RETURNING id, created_ts, updated_ts, row_status
  48. `
  49. if err := tx.QueryRowContext(ctx, query, create.Title, create.Payload, create.CreatorID).Scan(
  50. &create.ID,
  51. &create.CreatedTs,
  52. &create.UpdatedTs,
  53. &create.RowStatus,
  54. ); err != nil {
  55. return nil, err
  56. }
  57. if err := tx.Commit(); err != nil {
  58. return nil, err
  59. }
  60. shortcut := create
  61. return shortcut, nil
  62. }
  63. func (s *Store) ListShortcuts(ctx context.Context, find *FindShortcut) ([]*Shortcut, 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 := listShortcuts(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) GetShortcut(ctx context.Context, find *FindShortcut) (*Shortcut, 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 := listShortcuts(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. shortcut := list[0]
  95. return shortcut, nil
  96. }
  97. func (s *Store) UpdateShortcut(ctx context.Context, update *UpdateShortcut) (*Shortcut, error) {
  98. tx, err := s.db.BeginTx(ctx, nil)
  99. if err != nil {
  100. return nil, err
  101. }
  102. defer tx.Rollback()
  103. set, args := []string{}, []any{}
  104. if v := update.UpdatedTs; v != nil {
  105. set, args = append(set, "updated_ts = ?"), append(args, *v)
  106. }
  107. if v := update.Title; v != nil {
  108. set, args = append(set, "title = ?"), append(args, *v)
  109. }
  110. if v := update.Payload; v != nil {
  111. set, args = append(set, "payload = ?"), append(args, *v)
  112. }
  113. if v := update.RowStatus; v != nil {
  114. set, args = append(set, "row_status = ?"), append(args, *v)
  115. }
  116. args = append(args, update.ID)
  117. query := `
  118. UPDATE shortcut
  119. SET ` + strings.Join(set, ", ") + `
  120. WHERE id = ?
  121. RETURNING id, title, payload, creator_id, created_ts, updated_ts, row_status
  122. `
  123. shortcut := &Shortcut{}
  124. if err := tx.QueryRowContext(ctx, query, args...).Scan(
  125. &shortcut.ID,
  126. &shortcut.Title,
  127. &shortcut.Payload,
  128. &shortcut.CreatorID,
  129. &shortcut.CreatedTs,
  130. &shortcut.UpdatedTs,
  131. &shortcut.RowStatus,
  132. ); err != nil {
  133. return nil, err
  134. }
  135. if err := tx.Commit(); err != nil {
  136. return nil, err
  137. }
  138. return shortcut, nil
  139. }
  140. func (s *Store) DeleteShortcut(ctx context.Context, delete *DeleteShortcut) error {
  141. tx, err := s.db.BeginTx(ctx, nil)
  142. if err != nil {
  143. return err
  144. }
  145. defer tx.Rollback()
  146. where, args := []string{}, []any{}
  147. if v := delete.ID; v != nil {
  148. where, args = append(where, "id = ?"), append(args, *v)
  149. }
  150. if v := delete.CreatorID; v != nil {
  151. where, args = append(where, "creator_id = ?"), append(args, *v)
  152. }
  153. stmt := `DELETE FROM shortcut WHERE ` + strings.Join(where, " AND ")
  154. if _, err := tx.ExecContext(ctx, stmt, args...); err != nil {
  155. return err
  156. }
  157. if err := tx.Commit(); err != nil {
  158. return err
  159. }
  160. s.shortcutCache.Delete(*delete.ID)
  161. return nil
  162. }
  163. func listShortcuts(ctx context.Context, tx *sql.Tx, find *FindShortcut) ([]*Shortcut, error) {
  164. where, args := []string{"1 = 1"}, []any{}
  165. if v := find.ID; v != nil {
  166. where, args = append(where, "id = ?"), append(args, *v)
  167. }
  168. if v := find.CreatorID; v != nil {
  169. where, args = append(where, "creator_id = ?"), append(args, *v)
  170. }
  171. if v := find.Title; v != nil {
  172. where, args = append(where, "title = ?"), append(args, *v)
  173. }
  174. rows, err := tx.QueryContext(ctx, `
  175. SELECT
  176. id,
  177. title,
  178. payload,
  179. creator_id,
  180. created_ts,
  181. updated_ts,
  182. row_status
  183. FROM shortcut
  184. WHERE `+strings.Join(where, " AND ")+`
  185. ORDER BY created_ts DESC`,
  186. args...,
  187. )
  188. if err != nil {
  189. return nil, err
  190. }
  191. defer rows.Close()
  192. list := make([]*Shortcut, 0)
  193. for rows.Next() {
  194. var shortcut Shortcut
  195. if err := rows.Scan(
  196. &shortcut.ID,
  197. &shortcut.Title,
  198. &shortcut.Payload,
  199. &shortcut.CreatorID,
  200. &shortcut.CreatedTs,
  201. &shortcut.UpdatedTs,
  202. &shortcut.RowStatus,
  203. ); err != nil {
  204. return nil, err
  205. }
  206. list = append(list, &shortcut)
  207. }
  208. if err := rows.Err(); err != nil {
  209. return nil, err
  210. }
  211. return list, nil
  212. }
  213. func vacuumShortcut(ctx context.Context, tx *sql.Tx) error {
  214. stmt := `
  215. DELETE FROM
  216. shortcut
  217. WHERE
  218. creator_id NOT IN (
  219. SELECT
  220. id
  221. FROM
  222. user
  223. )`
  224. _, err := tx.ExecContext(ctx, stmt)
  225. if err != nil {
  226. return err
  227. }
  228. return nil
  229. }