From d605faeffa74d20cc15fe461f770f8809fdc265f Mon Sep 17 00:00:00 2001 From: johnnyjoy Date: Fri, 31 Jan 2025 20:58:18 +0800 Subject: [PATCH] refactor: move pinned to memo --- proto/gen/store/memo.pb.go | 69 +++++++++----------- proto/store/memo.proto | 2 - server/router/api/v1/memo_service.go | 10 +-- store/db/mysql/memo.go | 8 ++- store/db/mysql/memo_organizer.go | 70 --------------------- store/db/postgres/memo.go | 8 ++- store/db/postgres/memo_organizer.go | 91 --------------------------- store/db/sqlite/memo.go | 8 ++- store/db/sqlite/memo_organizer.go | 89 -------------------------- store/driver.go | 5 -- store/memo.go | 3 +- store/memo_organizer.go | 47 -------------- store/migration/sqlite/dev/LATEST.sql | 11 +--- test/store/memo_organizer_test.go | 64 ------------------- 14 files changed, 50 insertions(+), 435 deletions(-) delete mode 100644 store/db/mysql/memo_organizer.go delete mode 100644 store/db/postgres/memo_organizer.go delete mode 100644 store/db/sqlite/memo_organizer.go delete mode 100644 store/memo_organizer.go delete mode 100644 test/store/memo_organizer_test.go diff --git a/proto/gen/store/memo.pb.go b/proto/gen/store/memo.pb.go index 80b76737..5136e90a 100644 --- a/proto/gen/store/memo.pb.go +++ b/proto/gen/store/memo.pb.go @@ -26,7 +26,6 @@ type MemoPayload struct { Property *MemoPayload_Property `protobuf:"bytes,1,opt,name=property,proto3" json:"property,omitempty"` Location *MemoPayload_Location `protobuf:"bytes,2,opt,name=location,proto3" json:"location,omitempty"` Tags []string `protobuf:"bytes,3,rep,name=tags,proto3" json:"tags,omitempty"` - Pinned bool `protobuf:"varint,4,opt,name=pinned,proto3" json:"pinned,omitempty"` unknownFields protoimpl.UnknownFields sizeCache protoimpl.SizeCache } @@ -82,13 +81,6 @@ func (x *MemoPayload) GetTags() []string { return nil } -func (x *MemoPayload) GetPinned() bool { - if x != nil { - return x.Pinned - } - return false -} - // The calculated properties from the memo content. type MemoPayload_Property struct { state protoimpl.MessageState `protogen:"open.v1"` @@ -232,7 +224,7 @@ var File_store_memo_proto protoreflect.FileDescriptor var file_store_memo_proto_rawDesc = string([]byte{ 0x0a, 0x10, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x2e, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x12, 0x0b, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x22, - 0xd8, 0x03, 0x0a, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, + 0xc0, 0x03, 0x0a, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x12, 0x3d, 0x0a, 0x08, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x21, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x2e, 0x4d, 0x65, 0x6d, 0x6f, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x50, 0x72, 0x6f, 0x70, @@ -242,36 +234,35 @@ var file_store_memo_proto_rawDesc = string([]byte{ 0x65, 0x6d, 0x6f, 0x50, 0x61, 0x79, 0x6c, 0x6f, 0x61, 0x64, 0x2e, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x52, 0x08, 0x6c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x12, 0x0a, 0x04, 0x74, 0x61, 0x67, 0x73, 0x18, 0x03, 0x20, 0x03, 0x28, 0x09, 0x52, 0x04, 0x74, 0x61, 0x67, - 0x73, 0x12, 0x16, 0x0a, 0x06, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x18, 0x04, 0x20, 0x01, 0x28, - 0x08, 0x52, 0x06, 0x70, 0x69, 0x6e, 0x6e, 0x65, 0x64, 0x1a, 0xb6, 0x01, 0x0a, 0x08, 0x50, 0x72, - 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x61, 0x73, 0x5f, 0x6c, 0x69, - 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x68, 0x61, 0x73, 0x4c, 0x69, 0x6e, - 0x6b, 0x12, 0x22, 0x0a, 0x0d, 0x68, 0x61, 0x73, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x6c, 0x69, - 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, 0x52, 0x0b, 0x68, 0x61, 0x73, 0x54, 0x61, 0x73, - 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x19, 0x0a, 0x08, 0x68, 0x61, 0x73, 0x5f, 0x63, 0x6f, 0x64, - 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, 0x07, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x64, 0x65, - 0x12, 0x30, 0x0a, 0x14, 0x68, 0x61, 0x73, 0x5f, 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, - 0x74, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, - 0x68, 0x61, 0x73, 0x49, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x61, 0x73, - 0x6b, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, - 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, - 0x65, 0x73, 0x1a, 0x66, 0x0a, 0x08, 0x4c, 0x6f, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, - 0x0a, 0x0b, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, - 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65, 0x72, - 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, - 0x28, 0x01, 0x52, 0x08, 0x6c, 0x61, 0x74, 0x69, 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, - 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, - 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, 0x65, 0x42, 0x94, 0x01, 0x0a, 0x0f, 0x63, - 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x09, - 0x4d, 0x65, 0x6d, 0x6f, 0x50, 0x72, 0x6f, 0x74, 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, - 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, - 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, - 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0xa2, 0x02, 0x03, 0x4d, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x4d, - 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xca, 0x02, 0x0b, 0x4d, 0x65, 0x6d, - 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0xe2, 0x02, 0x17, 0x4d, 0x65, 0x6d, 0x6f, 0x73, - 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x5c, 0x47, 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, - 0x74, 0x61, 0xea, 0x02, 0x0c, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, - 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, + 0x73, 0x1a, 0xb6, 0x01, 0x0a, 0x08, 0x50, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x12, 0x19, + 0x0a, 0x08, 0x68, 0x61, 0x73, 0x5f, 0x6c, 0x69, 0x6e, 0x6b, 0x18, 0x01, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x07, 0x68, 0x61, 0x73, 0x4c, 0x69, 0x6e, 0x6b, 0x12, 0x22, 0x0a, 0x0d, 0x68, 0x61, 0x73, + 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x5f, 0x6c, 0x69, 0x73, 0x74, 0x18, 0x02, 0x20, 0x01, 0x28, 0x08, + 0x52, 0x0b, 0x68, 0x61, 0x73, 0x54, 0x61, 0x73, 0x6b, 0x4c, 0x69, 0x73, 0x74, 0x12, 0x19, 0x0a, + 0x08, 0x68, 0x61, 0x73, 0x5f, 0x63, 0x6f, 0x64, 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x08, 0x52, + 0x07, 0x68, 0x61, 0x73, 0x43, 0x6f, 0x64, 0x65, 0x12, 0x30, 0x0a, 0x14, 0x68, 0x61, 0x73, 0x5f, + 0x69, 0x6e, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x5f, 0x74, 0x61, 0x73, 0x6b, 0x73, + 0x18, 0x04, 0x20, 0x01, 0x28, 0x08, 0x52, 0x12, 0x68, 0x61, 0x73, 0x49, 0x6e, 0x63, 0x6f, 0x6d, + 0x70, 0x6c, 0x65, 0x74, 0x65, 0x54, 0x61, 0x73, 0x6b, 0x73, 0x12, 0x1e, 0x0a, 0x0a, 0x72, 0x65, + 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x18, 0x05, 0x20, 0x03, 0x28, 0x09, 0x52, 0x0a, + 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x73, 0x1a, 0x66, 0x0a, 0x08, 0x4c, 0x6f, + 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x12, 0x20, 0x0a, 0x0b, 0x70, 0x6c, 0x61, 0x63, 0x65, 0x68, + 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x70, 0x6c, 0x61, + 0x63, 0x65, 0x68, 0x6f, 0x6c, 0x64, 0x65, 0x72, 0x12, 0x1a, 0x0a, 0x08, 0x6c, 0x61, 0x74, 0x69, + 0x74, 0x75, 0x64, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x01, 0x52, 0x08, 0x6c, 0x61, 0x74, 0x69, + 0x74, 0x75, 0x64, 0x65, 0x12, 0x1c, 0x0a, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, 0x64, + 0x65, 0x18, 0x03, 0x20, 0x01, 0x28, 0x01, 0x52, 0x09, 0x6c, 0x6f, 0x6e, 0x67, 0x69, 0x74, 0x75, + 0x64, 0x65, 0x42, 0x94, 0x01, 0x0a, 0x0f, 0x63, 0x6f, 0x6d, 0x2e, 0x6d, 0x65, 0x6d, 0x6f, 0x73, + 0x2e, 0x73, 0x74, 0x6f, 0x72, 0x65, 0x42, 0x09, 0x4d, 0x65, 0x6d, 0x6f, 0x50, 0x72, 0x6f, 0x74, + 0x6f, 0x50, 0x01, 0x5a, 0x29, 0x67, 0x69, 0x74, 0x68, 0x75, 0x62, 0x2e, 0x63, 0x6f, 0x6d, 0x2f, + 0x75, 0x73, 0x65, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x6d, 0x65, 0x6d, 0x6f, 0x73, 0x2f, 0x70, + 0x72, 0x6f, 0x74, 0x6f, 0x2f, 0x67, 0x65, 0x6e, 0x2f, 0x73, 0x74, 0x6f, 0x72, 0x65, 0xa2, 0x02, + 0x03, 0x4d, 0x53, 0x58, 0xaa, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x2e, 0x53, 0x74, 0x6f, + 0x72, 0x65, 0xca, 0x02, 0x0b, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, + 0xe2, 0x02, 0x17, 0x4d, 0x65, 0x6d, 0x6f, 0x73, 0x5c, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x5c, 0x47, + 0x50, 0x42, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0xea, 0x02, 0x0c, 0x4d, 0x65, 0x6d, + 0x6f, 0x73, 0x3a, 0x3a, 0x53, 0x74, 0x6f, 0x72, 0x65, 0x62, 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, + 0x33, }) var ( diff --git a/proto/store/memo.proto b/proto/store/memo.proto index 5ee09a8a..56e74889 100644 --- a/proto/store/memo.proto +++ b/proto/store/memo.proto @@ -11,8 +11,6 @@ message MemoPayload { repeated string tags = 3; - bool pinned = 4; - // The calculated properties from the memo content. message Property { bool has_link = 1; diff --git a/server/router/api/v1/memo_service.go b/server/router/api/v1/memo_service.go index a09b0e37..be9981d0 100644 --- a/server/router/api/v1/memo_service.go +++ b/server/router/api/v1/memo_service.go @@ -268,6 +268,8 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR return nil, status.Errorf(codes.PermissionDenied, "disable public memos system setting is enabled") } update.Visibility = &visibility + } else if path == "pinned" { + update.Pinned = &request.Memo.Pinned } else if path == "state" { rowStatus := convertStateToStore(request.Memo.State) update.RowStatus = &rowStatus @@ -291,14 +293,6 @@ func (s *APIV1Service) UpdateMemo(ctx context.Context, request *v1pb.UpdateMemoR } else { update.CreatedTs = &displayTs } - } else if path == "pinned" { - if _, err := s.Store.UpsertMemoOrganizer(ctx, &store.MemoOrganizer{ - MemoID: id, - UserID: user.ID, - Pinned: request.Memo.Pinned, - }); err != nil { - return nil, status.Errorf(codes.Internal, "failed to upsert memo organizer") - } } else if path == "resources" { _, err := s.SetMemoResources(ctx, &v1pb.SetMemoResourcesRequest{ Name: request.Memo.Name, diff --git a/store/db/mysql/memo.go b/store/db/mysql/memo.go index a1c20d63..af17a493 100644 --- a/store/db/mysql/memo.go +++ b/store/db/mysql/memo.go @@ -138,8 +138,8 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo "UNIX_TIMESTAMP(`memo`.`updated_ts`) AS `updated_ts`", "`memo`.`row_status` AS `row_status`", "`memo`.`visibility` AS `visibility`", + "`memo`.`pinned` AS `pinned`", "`memo`.`payload` AS `payload`", - "IFNULL(`memo_organizer`.`pinned`, 0) AS `pinned`", "`memo_relation`.`related_memo_id` AS `parent_id`", } if !find.ExcludeContent { @@ -147,7 +147,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo } query := "SELECT " + strings.Join(fields, ", ") + " FROM `memo`" + " " + - "LEFT JOIN `memo_organizer` ON `memo`.`id` = `memo_organizer`.`memo_id` AND `memo`.`creator_id` = `memo_organizer`.`user_id`" + " " + "LEFT JOIN `memo_relation` ON `memo`.`id` = `memo_relation`.`memo_id` AND `memo_relation`.`type` = 'COMMENT'" + " " + "WHERE " + strings.Join(where, " AND ") + " " + "HAVING " + strings.Join(having, " AND ") + " " + @@ -177,8 +176,8 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo &memo.UpdatedTs, &memo.RowStatus, &memo.Visibility, - &payloadBytes, &memo.Pinned, + &payloadBytes, &memo.ParentID, } if !find.ExcludeContent { @@ -235,6 +234,9 @@ func (d *DB) UpdateMemo(ctx context.Context, update *store.UpdateMemo) error { if v := update.Visibility; v != nil { set, args = append(set, "`visibility` = ?"), append(args, *v) } + if v := update.Pinned; v != nil { + set, args = append(set, "`pinned` = ?"), append(args, *v) + } if v := update.Payload; v != nil { payloadBytes, err := protojson.Marshal(v) if err != nil { diff --git a/store/db/mysql/memo_organizer.go b/store/db/mysql/memo_organizer.go deleted file mode 100644 index 8893bfcc..00000000 --- a/store/db/mysql/memo_organizer.go +++ /dev/null @@ -1,70 +0,0 @@ -package mysql - -import ( - "context" - "strings" - - "github.com/usememos/memos/store" -) - -func (d *DB) UpsertMemoOrganizer(ctx context.Context, upsert *store.MemoOrganizer) (*store.MemoOrganizer, error) { - stmt := "INSERT INTO `memo_organizer` (`memo_id`, `user_id`, `pinned`) VALUES (?, ?, ?) ON DUPLICATE KEY UPDATE `pinned` = ?" - if _, err := d.db.ExecContext(ctx, stmt, upsert.MemoID, upsert.UserID, upsert.Pinned, upsert.Pinned); err != nil { - return nil, err - } - return upsert, nil -} - -func (d *DB) ListMemoOrganizer(ctx context.Context, find *store.FindMemoOrganizer) ([]*store.MemoOrganizer, error) { - where, args := []string{"1 = 1"}, []any{} - if find.MemoID != 0 { - where = append(where, "`memo_id` = ?") - args = append(args, find.MemoID) - } - if find.UserID != 0 { - where = append(where, "`user_id` = ?") - args = append(args, find.UserID) - } - - query := "SELECT `memo_id`, `user_id`, `pinned` FROM `memo_organizer` WHERE " + strings.Join(where, " AND ") - rows, err := d.db.QueryContext(ctx, query, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - list := []*store.MemoOrganizer{} - for rows.Next() { - memoOrganizer := &store.MemoOrganizer{} - if err := rows.Scan( - &memoOrganizer.MemoID, - &memoOrganizer.UserID, - &memoOrganizer.Pinned, - ); err != nil { - return nil, err - } - - list = append(list, memoOrganizer) - } - - if err := rows.Err(); err != nil { - return nil, err - } - - return list, nil -} - -func (d *DB) DeleteMemoOrganizer(ctx context.Context, delete *store.DeleteMemoOrganizer) error { - where, args := []string{}, []any{} - if v := delete.MemoID; v != nil { - where, args = append(where, "`memo_id` = ?"), append(args, *v) - } - if v := delete.UserID; v != nil { - where, args = append(where, "`user_id` = ?"), append(args, *v) - } - stmt := "DELETE FROM `memo_organizer` WHERE " + strings.Join(where, " AND ") - if _, err := d.db.ExecContext(ctx, stmt, args...); err != nil { - return err - } - return nil -} diff --git a/store/db/postgres/memo.go b/store/db/postgres/memo.go index fb85f788..8f605bc2 100644 --- a/store/db/postgres/memo.go +++ b/store/db/postgres/memo.go @@ -129,8 +129,8 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo `memo.updated_ts AS updated_ts`, `memo.row_status AS row_status`, `memo.visibility AS visibility`, + `memo.pinned AS pinned`, `memo.payload AS payload`, - `COALESCE(memo_organizer.pinned, 0) AS pinned`, `memo_relation.related_memo_id AS parent_id`, } if !find.ExcludeContent { @@ -139,7 +139,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo query := `SELECT ` + strings.Join(fields, ", ") + ` FROM memo - LEFT JOIN memo_organizer ON memo.id = memo_organizer.memo_id AND memo.creator_id = memo_organizer.user_id LEFT JOIN memo_relation ON memo.id = memo_relation.memo_id AND memo_relation.type = 'COMMENT' WHERE ` + strings.Join(where, " AND ") + ` ORDER BY ` + strings.Join(orders, ", ") @@ -168,8 +167,8 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo &memo.UpdatedTs, &memo.RowStatus, &memo.Visibility, - &payloadBytes, &memo.Pinned, + &payloadBytes, &memo.ParentID, } if !find.ExcludeContent { @@ -226,6 +225,9 @@ func (d *DB) UpdateMemo(ctx context.Context, update *store.UpdateMemo) error { if v := update.Visibility; v != nil { set, args = append(set, "visibility = "+placeholder(len(args)+1)), append(args, *v) } + if v := update.Pinned; v != nil { + set, args = append(set, "pinned = "+placeholder(len(args)+1)), append(args, *v) + } if v := update.Payload; v != nil { payloadBytes, err := protojson.Marshal(v) if err != nil { diff --git a/store/db/postgres/memo_organizer.go b/store/db/postgres/memo_organizer.go deleted file mode 100644 index b6abd287..00000000 --- a/store/db/postgres/memo_organizer.go +++ /dev/null @@ -1,91 +0,0 @@ -package postgres - -import ( - "context" - "fmt" - "strings" - - "github.com/usememos/memos/store" -) - -func (d *DB) UpsertMemoOrganizer(ctx context.Context, upsert *store.MemoOrganizer) (*store.MemoOrganizer, error) { - pinned := 0 - if upsert.Pinned { - pinned = 1 - } - stmt := ` - INSERT INTO memo_organizer ( - memo_id, - user_id, - pinned - ) - VALUES (` + placeholders(3) + `) - ON CONFLICT(memo_id, user_id) DO UPDATE - SET pinned = EXCLUDED.pinned` - if _, err := d.db.ExecContext(ctx, stmt, upsert.MemoID, upsert.UserID, pinned); err != nil { - return nil, err - } - - return upsert, nil -} - -func (d *DB) ListMemoOrganizer(ctx context.Context, find *store.FindMemoOrganizer) ([]*store.MemoOrganizer, error) { - where, args := []string{"1 = 1"}, []any{} - if find.MemoID != 0 { - where, args = append(where, "memo_id = "+placeholder(len(args)+1)), append(args, find.MemoID) - } - if find.UserID != 0 { - where, args = append(where, "user_id = "+placeholder(len(args)+1)), append(args, find.UserID) - } - - query := fmt.Sprintf(` - SELECT - memo_id, - user_id, - pinned - FROM memo_organizer - WHERE %s - `, strings.Join(where, " AND ")) - rows, err := d.db.QueryContext(ctx, query, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - list := []*store.MemoOrganizer{} - for rows.Next() { - memoOrganizer := &store.MemoOrganizer{} - pinned := 0 - if err := rows.Scan( - &memoOrganizer.MemoID, - &memoOrganizer.UserID, - &pinned, - ); err != nil { - return nil, err - } - - memoOrganizer.Pinned = pinned == 1 - list = append(list, memoOrganizer) - } - - if err := rows.Err(); err != nil { - return nil, err - } - - return list, nil -} - -func (d *DB) DeleteMemoOrganizer(ctx context.Context, delete *store.DeleteMemoOrganizer) error { - where, args := []string{}, []any{} - if v := delete.MemoID; v != nil { - where, args = append(where, "memo_id = "+placeholder(len(args)+1)), append(args, *v) - } - if v := delete.UserID; v != nil { - where, args = append(where, "user_id = "+placeholder(len(args)+1)), append(args, *v) - } - stmt := `DELETE FROM memo_organizer WHERE ` + strings.Join(where, " AND ") - if _, err := d.db.ExecContext(ctx, stmt, args...); err != nil { - return err - } - return nil -} diff --git a/store/db/sqlite/memo.go b/store/db/sqlite/memo.go index 38f9dca5..c0bdc9bf 100644 --- a/store/db/sqlite/memo.go +++ b/store/db/sqlite/memo.go @@ -130,8 +130,8 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo "`memo`.`updated_ts` AS `updated_ts`", "`memo`.`row_status` AS `row_status`", "`memo`.`visibility` AS `visibility`", + "`memo`.`pinned` AS `pinned`", "`memo`.`payload` AS `payload`", - "IFNULL(`memo_organizer`.`pinned`, 0) AS `pinned`", "`memo_relation`.`related_memo_id` AS `parent_id`", } if !find.ExcludeContent { @@ -139,7 +139,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo } query := "SELECT " + strings.Join(fields, ", ") + "FROM `memo` " + - "LEFT JOIN `memo_organizer` ON `memo`.`id` = `memo_organizer`.`memo_id` AND `memo`.`creator_id` = `memo_organizer`.`user_id` " + "LEFT JOIN `memo_relation` ON `memo`.`id` = `memo_relation`.`memo_id` AND `memo_relation`.`type` = \"COMMENT\" " + "WHERE " + strings.Join(where, " AND ") + " " + "ORDER BY " + strings.Join(orderBy, ", ") @@ -168,8 +167,8 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo &memo.UpdatedTs, &memo.RowStatus, &memo.Visibility, - &payloadBytes, &memo.Pinned, + &payloadBytes, &memo.ParentID, } if !find.ExcludeContent { @@ -213,6 +212,9 @@ func (d *DB) UpdateMemo(ctx context.Context, update *store.UpdateMemo) error { if v := update.Visibility; v != nil { set, args = append(set, "`visibility` = ?"), append(args, *v) } + if v := update.Pinned; v != nil { + set, args = append(set, "`pinned` = ?"), append(args, *v) + } if v := update.Payload; v != nil { payloadBytes, err := protojson.Marshal(v) if err != nil { diff --git a/store/db/sqlite/memo_organizer.go b/store/db/sqlite/memo_organizer.go deleted file mode 100644 index 20f73251..00000000 --- a/store/db/sqlite/memo_organizer.go +++ /dev/null @@ -1,89 +0,0 @@ -package sqlite - -import ( - "context" - "fmt" - "strings" - - "github.com/usememos/memos/store" -) - -func (d *DB) UpsertMemoOrganizer(ctx context.Context, upsert *store.MemoOrganizer) (*store.MemoOrganizer, error) { - stmt := ` - INSERT INTO memo_organizer ( - memo_id, - user_id, - pinned - ) - VALUES (?, ?, ?) - ON CONFLICT(memo_id, user_id) DO UPDATE - SET - pinned = EXCLUDED.pinned - ` - if _, err := d.db.ExecContext(ctx, stmt, upsert.MemoID, upsert.UserID, upsert.Pinned); err != nil { - return nil, err - } - - return upsert, nil -} - -func (d *DB) ListMemoOrganizer(ctx context.Context, find *store.FindMemoOrganizer) ([]*store.MemoOrganizer, error) { - where, args := []string{"1 = 1"}, []any{} - if find.MemoID != 0 { - where = append(where, "memo_id = ?") - args = append(args, find.MemoID) - } - if find.UserID != 0 { - where = append(where, "user_id = ?") - args = append(args, find.UserID) - } - - query := fmt.Sprintf(` - SELECT - memo_id, - user_id, - pinned - FROM memo_organizer - WHERE %s - `, strings.Join(where, " AND ")) - rows, err := d.db.QueryContext(ctx, query, args...) - if err != nil { - return nil, err - } - defer rows.Close() - - list := []*store.MemoOrganizer{} - for rows.Next() { - memoOrganizer := &store.MemoOrganizer{} - if err := rows.Scan( - &memoOrganizer.MemoID, - &memoOrganizer.UserID, - &memoOrganizer.Pinned, - ); err != nil { - return nil, err - } - - list = append(list, memoOrganizer) - } - - if err := rows.Err(); err != nil { - return nil, err - } - - return list, nil -} - -func (d *DB) DeleteMemoOrganizer(ctx context.Context, delete *store.DeleteMemoOrganizer) error { - where, args := []string{}, []any{} - if v := delete.MemoID; v != nil { - where, args = append(where, "memo_id = ?"), append(args, *v) - } - if v := delete.UserID; v != nil { - where, args = append(where, "user_id = ?"), append(args, *v) - } - stmt := `DELETE FROM memo_organizer WHERE ` + strings.Join(where, " AND ") - if _, err := d.db.ExecContext(ctx, stmt, args...); err != nil { - return err - } - return nil -} diff --git a/store/driver.go b/store/driver.go index c152a937..94bd5113 100644 --- a/store/driver.go +++ b/store/driver.go @@ -36,11 +36,6 @@ type Driver interface { ListMemoRelations(ctx context.Context, find *FindMemoRelation) ([]*MemoRelation, error) DeleteMemoRelation(ctx context.Context, delete *DeleteMemoRelation) error - // MemoOrganizer model related methods. - UpsertMemoOrganizer(ctx context.Context, upsert *MemoOrganizer) (*MemoOrganizer, error) - ListMemoOrganizer(ctx context.Context, find *FindMemoOrganizer) ([]*MemoOrganizer, error) - DeleteMemoOrganizer(ctx context.Context, delete *DeleteMemoOrganizer) error - // WorkspaceSetting model related methods. UpsertWorkspaceSetting(ctx context.Context, upsert *WorkspaceSetting) (*WorkspaceSetting, error) ListWorkspaceSettings(ctx context.Context, find *FindWorkspaceSetting) ([]*WorkspaceSetting, error) diff --git a/store/memo.go b/store/memo.go index e8513fa4..3388695c 100644 --- a/store/memo.go +++ b/store/memo.go @@ -48,10 +48,10 @@ type Memo struct { // Domain specific fields Content string Visibility Visibility + Pinned bool Payload *storepb.MemoPayload // Composed fields - Pinned bool ParentID *int32 } @@ -102,6 +102,7 @@ type UpdateMemo struct { RowStatus *RowStatus Content *string Visibility *Visibility + Pinned *bool Payload *storepb.MemoPayload } diff --git a/store/memo_organizer.go b/store/memo_organizer.go deleted file mode 100644 index dbf2618e..00000000 --- a/store/memo_organizer.go +++ /dev/null @@ -1,47 +0,0 @@ -package store - -import ( - "context" - "errors" -) - -type MemoOrganizer struct { - MemoID int32 - UserID int32 - Pinned bool -} - -type FindMemoOrganizer struct { - MemoID int32 - UserID int32 -} - -type DeleteMemoOrganizer struct { - MemoID *int32 - UserID *int32 -} - -func (s *Store) UpsertMemoOrganizer(ctx context.Context, upsert *MemoOrganizer) (*MemoOrganizer, error) { - return s.driver.UpsertMemoOrganizer(ctx, upsert) -} - -func (s *Store) GetMemoOrganizer(ctx context.Context, find *FindMemoOrganizer) (*MemoOrganizer, error) { - list, err := s.ListMemoOrganizer(ctx, find) - if err != nil { - return nil, err - } - - if len(list) == 0 { - return nil, errors.New("not found") - } - - return list[0], nil -} - -func (s *Store) ListMemoOrganizer(ctx context.Context, find *FindMemoOrganizer) ([]*MemoOrganizer, error) { - return s.driver.ListMemoOrganizer(ctx, find) -} - -func (s *Store) DeleteMemoOrganizer(ctx context.Context, delete *DeleteMemoOrganizer) error { - return s.driver.DeleteMemoOrganizer(ctx, delete) -} diff --git a/store/migration/sqlite/dev/LATEST.sql b/store/migration/sqlite/dev/LATEST.sql index 3e1c8810..42932b88 100644 --- a/store/migration/sqlite/dev/LATEST.sql +++ b/store/migration/sqlite/dev/LATEST.sql @@ -47,20 +47,11 @@ CREATE TABLE memo ( row_status TEXT NOT NULL CHECK (row_status IN ('NORMAL', 'ARCHIVED')) DEFAULT 'NORMAL', content TEXT NOT NULL DEFAULT '', visibility TEXT NOT NULL CHECK (visibility IN ('PUBLIC', 'PROTECTED', 'PRIVATE')) DEFAULT 'PRIVATE', + pinned INTEGER NOT NULL CHECK (pinned IN (0, 1)) DEFAULT 0, payload TEXT NOT NULL DEFAULT '{}' ); CREATE INDEX idx_memo_creator_id ON memo (creator_id); -CREATE INDEX idx_memo_content ON memo (content); -CREATE INDEX idx_memo_visibility ON memo (visibility); - --- memo_organizer -CREATE TABLE memo_organizer ( - memo_id INTEGER NOT NULL, - user_id INTEGER NOT NULL, - pinned INTEGER NOT NULL CHECK (pinned IN (0, 1)) DEFAULT 0, - UNIQUE(memo_id, user_id) -); -- memo_relation CREATE TABLE memo_relation ( diff --git a/test/store/memo_organizer_test.go b/test/store/memo_organizer_test.go deleted file mode 100644 index 8d942c78..00000000 --- a/test/store/memo_organizer_test.go +++ /dev/null @@ -1,64 +0,0 @@ -package teststore - -import ( - "context" - "testing" - - "github.com/stretchr/testify/require" - - "github.com/usememos/memos/store" -) - -func TestMemoOrganizerStore(t *testing.T) { - ctx := context.Background() - ts := NewTestingStore(ctx, t) - user, err := createTestingHostUser(ctx, ts) - require.NoError(t, err) - memoCreate := &store.Memo{ - UID: "main-memo", - CreatorID: user.ID, - Content: "main memo content", - Visibility: store.Public, - } - memo, err := ts.CreateMemo(ctx, memoCreate) - require.NoError(t, err) - require.Equal(t, memoCreate.Content, memo.Content) - - memoOrganizer, err := ts.UpsertMemoOrganizer(ctx, &store.MemoOrganizer{ - MemoID: memo.ID, - UserID: user.ID, - Pinned: true, - }) - require.NoError(t, err) - require.NotNil(t, memoOrganizer) - require.Equal(t, memo.ID, memoOrganizer.MemoID) - require.Equal(t, user.ID, memoOrganizer.UserID) - require.Equal(t, true, memoOrganizer.Pinned) - - memoOrganizerTemp, err := ts.GetMemoOrganizer(ctx, &store.FindMemoOrganizer{ - MemoID: memo.ID, - }) - require.NoError(t, err) - require.Equal(t, memoOrganizer, memoOrganizerTemp) - memoOrganizerTemp, err = ts.UpsertMemoOrganizer(ctx, &store.MemoOrganizer{ - MemoID: memo.ID, - UserID: user.ID, - Pinned: false, - }) - require.NoError(t, err) - require.NotNil(t, memoOrganizerTemp) - require.Equal(t, memo.ID, memoOrganizerTemp.MemoID) - require.Equal(t, user.ID, memoOrganizerTemp.UserID) - require.Equal(t, false, memoOrganizerTemp.Pinned) - err = ts.DeleteMemoOrganizer(ctx, &store.DeleteMemoOrganizer{ - MemoID: &memo.ID, - UserID: &user.ID, - }) - require.NoError(t, err) - memoOrganizers, err := ts.ListMemoOrganizer(ctx, &store.FindMemoOrganizer{ - UserID: user.ID, - }) - require.NoError(t, err) - require.Equal(t, 0, len(memoOrganizers)) - ts.Close() -}