memo_relation.go 5.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210
  1. package store
  2. import (
  3. "context"
  4. "database/sql"
  5. "fmt"
  6. "strings"
  7. "github.com/usememos/memos/api"
  8. "github.com/usememos/memos/common"
  9. )
  10. func (s *Store) ComposeMemoRelationList(ctx context.Context, memo *api.Memo) error {
  11. memoRelationList, err := s.ListMemoRelations(ctx, &FindMemoRelationMessage{
  12. MemoID: &memo.ID,
  13. })
  14. if err != nil {
  15. return err
  16. }
  17. memo.RelationList = []*api.MemoRelation{}
  18. for _, memoRelation := range memoRelationList {
  19. memo.RelationList = append(memo.RelationList, &api.MemoRelation{
  20. MemoID: memoRelation.MemoID,
  21. RelatedMemoID: memoRelation.RelatedMemoID,
  22. Type: api.MemoRelationType(memoRelation.Type),
  23. })
  24. }
  25. return nil
  26. }
  27. type MemoRelationType string
  28. const (
  29. MemoRelationReference MemoRelationType = "REFERENCE"
  30. MemoRelationAdditional MemoRelationType = "ADDITIONAL"
  31. )
  32. type MemoRelationMessage struct {
  33. MemoID int
  34. RelatedMemoID int
  35. Type MemoRelationType
  36. }
  37. type FindMemoRelationMessage struct {
  38. MemoID *int
  39. RelatedMemoID *int
  40. Type *MemoRelationType
  41. }
  42. type DeleteMemoRelationMessage struct {
  43. MemoID *int
  44. RelatedMemoID *int
  45. Type *MemoRelationType
  46. }
  47. func (s *Store) UpsertMemoRelation(ctx context.Context, create *MemoRelationMessage) (*MemoRelationMessage, error) {
  48. tx, err := s.db.BeginTx(ctx, nil)
  49. if err != nil {
  50. return nil, FormatError(err)
  51. }
  52. defer tx.Rollback()
  53. query := `
  54. INSERT INTO memo_relation (
  55. memo_id,
  56. related_memo_id,
  57. type
  58. )
  59. VALUES (?, ?, ?)
  60. ON CONFLICT (memo_id, related_memo_id, type) DO UPDATE SET
  61. type = EXCLUDED.type
  62. RETURNING memo_id, related_memo_id, type
  63. `
  64. memoRelationMessage := &MemoRelationMessage{}
  65. if err := tx.QueryRowContext(
  66. ctx,
  67. query,
  68. create.MemoID,
  69. create.RelatedMemoID,
  70. create.Type,
  71. ).Scan(
  72. &memoRelationMessage.MemoID,
  73. &memoRelationMessage.RelatedMemoID,
  74. &memoRelationMessage.Type,
  75. ); err != nil {
  76. return nil, FormatError(err)
  77. }
  78. if err := tx.Commit(); err != nil {
  79. return nil, FormatError(err)
  80. }
  81. return memoRelationMessage, nil
  82. }
  83. func (s *Store) ListMemoRelations(ctx context.Context, find *FindMemoRelationMessage) ([]*MemoRelationMessage, error) {
  84. tx, err := s.db.BeginTx(ctx, nil)
  85. if err != nil {
  86. return nil, FormatError(err)
  87. }
  88. defer tx.Rollback()
  89. list, err := listMemoRelations(ctx, tx, find)
  90. if err != nil {
  91. return nil, err
  92. }
  93. return list, nil
  94. }
  95. func (s *Store) GetMemoRelation(ctx context.Context, find *FindMemoRelationMessage) (*MemoRelationMessage, error) {
  96. tx, err := s.db.BeginTx(ctx, nil)
  97. if err != nil {
  98. return nil, FormatError(err)
  99. }
  100. defer tx.Rollback()
  101. list, err := listMemoRelations(ctx, tx, find)
  102. if err != nil {
  103. return nil, err
  104. }
  105. if len(list) == 0 {
  106. return nil, &common.Error{Code: common.NotFound, Err: fmt.Errorf("not found")}
  107. }
  108. return list[0], nil
  109. }
  110. func (s *Store) DeleteMemoRelation(ctx context.Context, delete *DeleteMemoRelationMessage) error {
  111. tx, err := s.db.BeginTx(ctx, nil)
  112. if err != nil {
  113. return FormatError(err)
  114. }
  115. defer tx.Rollback()
  116. where, args := []string{"TRUE"}, []any{}
  117. if delete.MemoID != nil {
  118. where, args = append(where, "memo_id = ?"), append(args, delete.MemoID)
  119. }
  120. if delete.RelatedMemoID != nil {
  121. where, args = append(where, "related_memo_id = ?"), append(args, delete.RelatedMemoID)
  122. }
  123. if delete.Type != nil {
  124. where, args = append(where, "type = ?"), append(args, delete.Type)
  125. }
  126. query := `
  127. DELETE FROM memo_relation
  128. WHERE ` + strings.Join(where, " AND ")
  129. if _, err := tx.ExecContext(ctx, query, args...); err != nil {
  130. return FormatError(err)
  131. }
  132. if err := tx.Commit(); err != nil {
  133. return FormatError(err)
  134. }
  135. return nil
  136. }
  137. func listMemoRelations(ctx context.Context, tx *sql.Tx, find *FindMemoRelationMessage) ([]*MemoRelationMessage, error) {
  138. where, args := []string{"TRUE"}, []any{}
  139. if find.MemoID != nil {
  140. where, args = append(where, "memo_id = ?"), append(args, find.MemoID)
  141. }
  142. if find.RelatedMemoID != nil {
  143. where, args = append(where, "related_memo_id = ?"), append(args, find.RelatedMemoID)
  144. }
  145. if find.Type != nil {
  146. where, args = append(where, "type = ?"), append(args, find.Type)
  147. }
  148. rows, err := tx.QueryContext(ctx, `
  149. SELECT
  150. memo_id,
  151. related_memo_id,
  152. type
  153. FROM memo_relation
  154. WHERE `+strings.Join(where, " AND "), args...)
  155. if err != nil {
  156. return nil, FormatError(err)
  157. }
  158. defer rows.Close()
  159. memoRelationMessages := []*MemoRelationMessage{}
  160. for rows.Next() {
  161. memoRelationMessage := &MemoRelationMessage{}
  162. if err := rows.Scan(
  163. &memoRelationMessage.MemoID,
  164. &memoRelationMessage.RelatedMemoID,
  165. &memoRelationMessage.Type,
  166. ); err != nil {
  167. return nil, FormatError(err)
  168. }
  169. memoRelationMessages = append(memoRelationMessages, memoRelationMessage)
  170. }
  171. if err := rows.Err(); err != nil {
  172. return nil, FormatError(err)
  173. }
  174. return memoRelationMessages, nil
  175. }
  176. func vacuumMemoRelations(ctx context.Context, tx *sql.Tx) error {
  177. if _, err := tx.ExecContext(ctx, `
  178. DELETE FROM memo_relation
  179. WHERE memo_id NOT IN (SELECT id FROM memo) OR related_memo_id NOT IN (SELECT id FROM memo)
  180. `); err != nil {
  181. return FormatError(err)
  182. }
  183. return nil
  184. }