resource.go 4.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206
  1. package sqlite
  2. import (
  3. "context"
  4. "database/sql"
  5. "fmt"
  6. "strings"
  7. "github.com/usememos/memos/store"
  8. )
  9. func (d *DB) CreateResource(ctx context.Context, create *store.Resource) (*store.Resource, error) {
  10. stmt := `
  11. INSERT INTO resource (
  12. filename,
  13. blob,
  14. external_link,
  15. type,
  16. size,
  17. creator_id,
  18. internal_path
  19. )
  20. VALUES (?, ?, ?, ?, ?, ?, ?)
  21. RETURNING id, created_ts, updated_ts
  22. `
  23. if err := d.db.QueryRowContext(
  24. ctx,
  25. stmt,
  26. create.Filename,
  27. create.Blob,
  28. create.ExternalLink,
  29. create.Type,
  30. create.Size,
  31. create.CreatorID,
  32. create.InternalPath,
  33. ).Scan(&create.ID, &create.CreatedTs, &create.UpdatedTs); err != nil {
  34. return nil, err
  35. }
  36. return create, nil
  37. }
  38. func (d *DB) ListResources(ctx context.Context, find *store.FindResource) ([]*store.Resource, error) {
  39. where, args := []string{"1 = 1"}, []any{}
  40. if v := find.ID; v != nil {
  41. where, args = append(where, "id = ?"), append(args, *v)
  42. }
  43. if v := find.CreatorID; v != nil {
  44. where, args = append(where, "creator_id = ?"), append(args, *v)
  45. }
  46. if v := find.Filename; v != nil {
  47. where, args = append(where, "filename = ?"), append(args, *v)
  48. }
  49. if v := find.MemoID; v != nil {
  50. where, args = append(where, "memo_id = ?"), append(args, *v)
  51. }
  52. if find.HasRelatedMemo {
  53. where = append(where, "memo_id IS NOT NULL")
  54. }
  55. fields := []string{"id", "filename", "external_link", "type", "size", "creator_id", "created_ts", "updated_ts", "internal_path", "memo_id"}
  56. if find.GetBlob {
  57. fields = append(fields, "blob")
  58. }
  59. query := fmt.Sprintf(`
  60. SELECT
  61. %s
  62. FROM resource
  63. WHERE %s
  64. GROUP BY id
  65. ORDER BY created_ts DESC
  66. `, strings.Join(fields, ", "), strings.Join(where, " AND "))
  67. if find.Limit != nil {
  68. query = fmt.Sprintf("%s LIMIT %d", query, *find.Limit)
  69. if find.Offset != nil {
  70. query = fmt.Sprintf("%s OFFSET %d", query, *find.Offset)
  71. }
  72. }
  73. rows, err := d.db.QueryContext(ctx, query, args...)
  74. if err != nil {
  75. return nil, err
  76. }
  77. defer rows.Close()
  78. list := make([]*store.Resource, 0)
  79. for rows.Next() {
  80. resource := store.Resource{}
  81. var memoID sql.NullInt32
  82. dests := []any{
  83. &resource.ID,
  84. &resource.Filename,
  85. &resource.ExternalLink,
  86. &resource.Type,
  87. &resource.Size,
  88. &resource.CreatorID,
  89. &resource.CreatedTs,
  90. &resource.UpdatedTs,
  91. &resource.InternalPath,
  92. &memoID,
  93. }
  94. if find.GetBlob {
  95. dests = append(dests, &resource.Blob)
  96. }
  97. if err := rows.Scan(dests...); err != nil {
  98. return nil, err
  99. }
  100. if memoID.Valid {
  101. resource.MemoID = &memoID.Int32
  102. }
  103. list = append(list, &resource)
  104. }
  105. if err := rows.Err(); err != nil {
  106. return nil, err
  107. }
  108. return list, nil
  109. }
  110. func (d *DB) UpdateResource(ctx context.Context, update *store.UpdateResource) (*store.Resource, error) {
  111. set, args := []string{}, []any{}
  112. if v := update.UpdatedTs; v != nil {
  113. set, args = append(set, "updated_ts = ?"), append(args, *v)
  114. }
  115. if v := update.Filename; v != nil {
  116. set, args = append(set, "filename = ?"), append(args, *v)
  117. }
  118. if v := update.InternalPath; v != nil {
  119. set, args = append(set, "internal_path = ?"), append(args, *v)
  120. }
  121. if v := update.MemoID; v != nil {
  122. set, args = append(set, "memo_id = ?"), append(args, *v)
  123. }
  124. if v := update.Blob; v != nil {
  125. set, args = append(set, "blob = ?"), append(args, v)
  126. }
  127. args = append(args, update.ID)
  128. fields := []string{"id", "filename", "external_link", "type", "size", "creator_id", "created_ts", "updated_ts", "internal_path"}
  129. stmt := `
  130. UPDATE resource
  131. SET ` + strings.Join(set, ", ") + `
  132. WHERE id = ?
  133. RETURNING ` + strings.Join(fields, ", ")
  134. resource := store.Resource{}
  135. dests := []any{
  136. &resource.ID,
  137. &resource.Filename,
  138. &resource.ExternalLink,
  139. &resource.Type,
  140. &resource.Size,
  141. &resource.CreatorID,
  142. &resource.CreatedTs,
  143. &resource.UpdatedTs,
  144. &resource.InternalPath,
  145. }
  146. if err := d.db.QueryRowContext(ctx, stmt, args...).Scan(dests...); err != nil {
  147. return nil, err
  148. }
  149. return &resource, nil
  150. }
  151. func (d *DB) DeleteResource(ctx context.Context, delete *store.DeleteResource) error {
  152. stmt := `
  153. DELETE FROM resource
  154. WHERE id = ?
  155. `
  156. result, err := d.db.ExecContext(ctx, stmt, delete.ID)
  157. if err != nil {
  158. return err
  159. }
  160. if _, err := result.RowsAffected(); err != nil {
  161. return err
  162. }
  163. if err := d.Vacuum(ctx); err != nil {
  164. // Prevent linter warning.
  165. return err
  166. }
  167. return nil
  168. }
  169. func vacuumResource(ctx context.Context, tx *sql.Tx) error {
  170. stmt := `
  171. DELETE FROM
  172. resource
  173. WHERE
  174. creator_id NOT IN (
  175. SELECT
  176. id
  177. FROM
  178. user
  179. )`
  180. _, err := tx.ExecContext(ctx, stmt)
  181. if err != nil {
  182. return err
  183. }
  184. return nil
  185. }