2023-09-28 17:09:52 +03:00
package mysql
import (
"context"
"database/sql"
"fmt"
"strings"
"github.com/pkg/errors"
"github.com/usememos/memos/store"
)
2023-10-05 18:11:29 +03:00
func ( d * DB ) CreateResource ( ctx context . Context , create * store . Resource ) ( * store . Resource , error ) {
2023-10-08 13:29:03 +03:00
fields := [ ] string { "`filename`" , "`blob`" , "`external_link`" , "`type`" , "`size`" , "`creator_id`" , "`internal_path`" }
placeholder := [ ] string { "?" , "?" , "?" , "?" , "?" , "?" , "?" }
args := [ ] any { create . Filename , create . Blob , create . ExternalLink , create . Type , create . Size , create . CreatorID , create . InternalPath }
if create . ID != 0 {
fields = append ( fields , "`id`" )
placeholder = append ( placeholder , "?" )
args = append ( args , create . ID )
}
if create . CreatedTs != 0 {
fields = append ( fields , "`created_ts`" )
placeholder = append ( placeholder , "FROM_UNIXTIME(?)" )
args = append ( args , create . CreatedTs )
}
if create . UpdatedTs != 0 {
fields = append ( fields , "`updated_ts`" )
placeholder = append ( placeholder , "FROM_UNIXTIME(?)" )
args = append ( args , create . UpdatedTs )
}
if create . MemoID != nil {
fields = append ( fields , "`memo_id`" )
placeholder = append ( placeholder , "?" )
args = append ( args , * create . MemoID )
}
stmt := "INSERT INTO `resource` (" + strings . Join ( fields , ", " ) + ") VALUES (" + strings . Join ( placeholder , ", " ) + ")"
result , err := d . db . ExecContext ( ctx , stmt , args ... )
2023-09-28 17:09:52 +03:00
if err != nil {
return nil , err
}
id , err := result . LastInsertId ( )
if err != nil {
return nil , err
}
id32 := int32 ( id )
list , err := d . ListResources ( ctx , & store . FindResource { ID : & id32 } )
if err != nil {
return nil , err
}
if len ( list ) != 1 {
return nil , errors . Wrapf ( nil , "unexpected resource count: %d" , len ( list ) )
}
return list [ 0 ] , nil
}
2023-10-05 18:11:29 +03:00
func ( d * DB ) ListResources ( ctx context . Context , find * store . FindResource ) ( [ ] * store . Resource , error ) {
2023-09-28 17:09:52 +03:00
where , args := [ ] string { "1 = 1" } , [ ] any { }
if v := find . ID ; v != nil {
2023-10-07 17:56:12 +03:00
where , args = append ( where , "`id` = ?" ) , append ( args , * v )
2023-09-28 17:09:52 +03:00
}
if v := find . CreatorID ; v != nil {
2023-10-07 17:56:12 +03:00
where , args = append ( where , "`creator_id` = ?" ) , append ( args , * v )
2023-09-28 17:09:52 +03:00
}
if v := find . Filename ; v != nil {
2023-10-07 17:56:12 +03:00
where , args = append ( where , "`filename` = ?" ) , append ( args , * v )
2023-09-28 17:09:52 +03:00
}
if v := find . MemoID ; v != nil {
2023-10-07 17:56:12 +03:00
where , args = append ( where , "`memo_id` = ?" ) , append ( args , * v )
2023-09-28 17:09:52 +03:00
}
if find . HasRelatedMemo {
2023-10-07 17:56:12 +03:00
where = append ( where , "`memo_id` IS NOT NULL" )
2023-09-28 17:09:52 +03:00
}
2023-10-07 17:56:12 +03:00
fields := [ ] string { "`id`" , "`filename`" , "`external_link`" , "`type`" , "`size`" , "`creator_id`" , "UNIX_TIMESTAMP(`created_ts`)" , "UNIX_TIMESTAMP(`updated_ts`)" , "`internal_path`" , "`memo_id`" }
2023-09-28 17:09:52 +03:00
if find . GetBlob {
2023-10-07 17:56:12 +03:00
fields = append ( fields , "`blob`" )
2023-09-28 17:09:52 +03:00
}
2023-10-07 17:56:12 +03:00
query := fmt . Sprintf ( "SELECT %s FROM `resource` WHERE %s GROUP BY `id` ORDER BY `created_ts` DESC" , strings . Join ( fields , ", " ) , strings . Join ( where , " AND " ) )
2023-09-28 17:09:52 +03:00
if find . Limit != nil {
query = fmt . Sprintf ( "%s LIMIT %d" , query , * find . Limit )
if find . Offset != nil {
query = fmt . Sprintf ( "%s OFFSET %d" , query , * find . Offset )
}
}
rows , err := d . db . QueryContext ( ctx , query , args ... )
if err != nil {
return nil , err
}
defer rows . Close ( )
list := make ( [ ] * store . Resource , 0 )
for rows . Next ( ) {
resource := store . Resource { }
var memoID sql . NullInt32
dests := [ ] any {
& resource . ID ,
& resource . Filename ,
& resource . ExternalLink ,
& resource . Type ,
& resource . Size ,
& resource . CreatorID ,
& resource . CreatedTs ,
& resource . UpdatedTs ,
& resource . InternalPath ,
& memoID ,
}
if find . GetBlob {
dests = append ( dests , & resource . Blob )
}
if err := rows . Scan ( dests ... ) ; err != nil {
return nil , err
}
if memoID . Valid {
resource . MemoID = & memoID . Int32
}
list = append ( list , & resource )
}
if err := rows . Err ( ) ; err != nil {
return nil , err
}
return list , nil
}
2023-10-05 18:11:29 +03:00
func ( d * DB ) UpdateResource ( ctx context . Context , update * store . UpdateResource ) ( * store . Resource , error ) {
2023-09-28 17:09:52 +03:00
set , args := [ ] string { } , [ ] any { }
if v := update . UpdatedTs ; v != nil {
2023-10-07 17:56:12 +03:00
set , args = append ( set , "`updated_ts` = ?" ) , append ( args , * v )
2023-09-28 17:09:52 +03:00
}
if v := update . Filename ; v != nil {
2023-10-07 17:56:12 +03:00
set , args = append ( set , "`filename` = ?" ) , append ( args , * v )
2023-09-28 17:09:52 +03:00
}
if v := update . InternalPath ; v != nil {
2023-10-07 17:56:12 +03:00
set , args = append ( set , "`internal_path` = ?" ) , append ( args , * v )
2023-09-28 17:09:52 +03:00
}
if v := update . MemoID ; v != nil {
2023-10-07 17:56:12 +03:00
set , args = append ( set , "`memo_id` = ?" ) , append ( args , * v )
2023-09-28 17:09:52 +03:00
}
if v := update . Blob ; v != nil {
2023-10-07 17:56:12 +03:00
set , args = append ( set , "`blob` = ?" ) , append ( args , v )
2023-09-28 17:09:52 +03:00
}
args = append ( args , update . ID )
2023-10-07 17:56:12 +03:00
stmt := "UPDATE `resource` SET " + strings . Join ( set , ", " ) + " WHERE `id` = ?"
2023-09-28 17:09:52 +03:00
if _ , err := d . db . ExecContext ( ctx , stmt , args ... ) ; err != nil {
return nil , err
}
list , err := d . ListResources ( ctx , & store . FindResource { ID : & update . ID } )
if err != nil {
return nil , err
}
if len ( list ) != 1 {
return nil , errors . Wrapf ( nil , "unexpected resource count: %d" , len ( list ) )
}
return list [ 0 ] , nil
}
2023-10-05 18:11:29 +03:00
func ( d * DB ) DeleteResource ( ctx context . Context , delete * store . DeleteResource ) error {
2023-10-07 17:56:12 +03:00
stmt := "DELETE FROM `resource` WHERE `id` = ?"
2023-09-28 17:09:52 +03:00
result , err := d . db . ExecContext ( ctx , stmt , delete . ID )
if err != nil {
return err
}
if _ , err := result . RowsAffected ( ) ; err != nil {
return err
}
if err := d . Vacuum ( ctx ) ; err != nil {
// Prevent linter warning.
return err
}
return nil
}
func vacuumResource ( ctx context . Context , tx * sql . Tx ) error {
2023-10-07 17:56:12 +03:00
stmt := "DELETE FROM `resource` WHERE `creator_id` NOT IN (SELECT `id` FROM `user`)"
2023-09-28 17:09:52 +03:00
_ , err := tx . ExecContext ( ctx , stmt )
if err != nil {
return err
}
return nil
}