diff --git a/server/router/api/v1/memo_service.go b/server/router/api/v1/memo_service.go index 36d36db51..2b0d36f51 100644 --- a/server/router/api/v1/memo_service.go +++ b/server/router/api/v1/memo_service.go @@ -135,7 +135,7 @@ func (s *APIV1Service) ListMemos(ctx context.Context, request *v1pb.ListMemosReq if err := s.validateFilter(ctx, request.Filter); err != nil { return nil, status.Errorf(codes.InvalidArgument, "invalid filter: %v", err) } - memoFind.Filter = &request.Filter + memoFind.Filters = append(memoFind.Filters, request.Filter) } currentUser, err := s.GetCurrentUser(ctx) @@ -146,13 +146,8 @@ func (s *APIV1Service) ListMemos(ctx context.Context, request *v1pb.ListMemosReq memoFind.VisibilityList = []store.Visibility{store.Public} } else { if memoFind.CreatorID == nil { - internalFilter := fmt.Sprintf(`creator_id == %d || visibility in ["PUBLIC", "PROTECTED"]`, currentUser.ID) - if memoFind.Filter != nil { - filter := fmt.Sprintf("(%s) && (%s)", *memoFind.Filter, internalFilter) - memoFind.Filter = &filter - } else { - memoFind.Filter = &internalFilter - } + filter := fmt.Sprintf(`creator_id == %d || visibility in ["PUBLIC", "PROTECTED"]`, currentUser.ID) + memoFind.Filters = append(memoFind.Filters, filter) } else if *memoFind.CreatorID != currentUser.ID { memoFind.VisibilityList = []store.Visibility{store.Public, store.Protected} } diff --git a/server/router/api/v1/user_service_stats.go b/server/router/api/v1/user_service_stats.go index 552e61e29..775f6f189 100644 --- a/server/router/api/v1/user_service_stats.go +++ b/server/router/api/v1/user_service_stats.go @@ -36,13 +36,8 @@ func (s *APIV1Service) ListAllUserStats(ctx context.Context, _ *v1pb.ListAllUser memoFind.VisibilityList = []store.Visibility{store.Public} } else { if memoFind.CreatorID == nil { - internalFilter := fmt.Sprintf(`creator_id == %d || visibility in ["PUBLIC", "PROTECTED"]`, currentUser.ID) - if memoFind.Filter != nil { - filter := fmt.Sprintf("(%s) && (%s)", *memoFind.Filter, internalFilter) - memoFind.Filter = &filter - } else { - memoFind.Filter = &internalFilter - } + filter := fmt.Sprintf(`creator_id == %d || visibility in ["PUBLIC", "PROTECTED"]`, currentUser.ID) + memoFind.Filters = append(memoFind.Filters, filter) } else if *memoFind.CreatorID != currentUser.ID { memoFind.VisibilityList = []store.Visibility{store.Public, store.Protected} } diff --git a/store/db/mysql/memo.go b/store/db/mysql/memo.go index 6518df3a2..3c8684bdd 100644 --- a/store/db/mysql/memo.go +++ b/store/db/mysql/memo.go @@ -50,6 +50,24 @@ func (d *DB) CreateMemo(ctx context.Context, create *store.Memo) (*store.Memo, e func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo, error) { where, having, args := []string{"1 = 1"}, []string{"1 = 1"}, []any{} + for _, filterStr := range find.Filters { + // Parse filter string and return the parsed expression. + // The filter string should be a CEL expression. + parsedExpr, err := filter.Parse(filterStr, filter.MemoFilterCELAttributes...) + if err != nil { + return nil, err + } + convertCtx := filter.NewConvertContext() + // ConvertExprToSQL converts the parsed expression to a SQL condition string. + if err := d.ConvertExprToSQL(convertCtx, parsedExpr.GetExpr()); err != nil { + return nil, err + } + condition := convertCtx.Buffer.String() + if condition != "" { + where = append(where, fmt.Sprintf("(%s)", condition)) + args = append(args, convertCtx.Args...) + } + } if v := find.ID; v != nil { where, args = append(where, "`memo`.`id` = ?"), append(args, *v) } @@ -112,24 +130,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo where = append(where, "JSON_EXTRACT(`memo`.`payload`, '$.property.hasIncompleteTasks') IS TRUE") } } - if v := find.Filter; v != nil { - // Parse filter string and return the parsed expression. - // The filter string should be a CEL expression. - parsedExpr, err := filter.Parse(*v, filter.MemoFilterCELAttributes...) - if err != nil { - return nil, err - } - convertCtx := filter.NewConvertContext() - // ConvertExprToSQL converts the parsed expression to a SQL condition string. - if err := d.ConvertExprToSQL(convertCtx, parsedExpr.GetExpr()); err != nil { - return nil, err - } - condition := convertCtx.Buffer.String() - if condition != "" { - where = append(where, fmt.Sprintf("(%s)", condition)) - args = append(args, convertCtx.Args...) - } - } if find.ExcludeComments { having = append(having, "`parent_id` IS NULL") } diff --git a/store/db/postgres/memo.go b/store/db/postgres/memo.go index d9f57f7d7..19323505a 100644 --- a/store/db/postgres/memo.go +++ b/store/db/postgres/memo.go @@ -41,6 +41,25 @@ func (d *DB) CreateMemo(ctx context.Context, create *store.Memo) (*store.Memo, e func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo, error) { where, args := []string{"1 = 1"}, []any{} + for _, filterStr := range find.Filters { + // Parse filter string and return the parsed expression. + // The filter string should be a CEL expression. + parsedExpr, err := filter.Parse(filterStr, filter.MemoFilterCELAttributes...) + if err != nil { + return nil, err + } + convertCtx := filter.NewConvertContext() + convertCtx.ArgsOffset = len(args) + // ConvertExprToSQL converts the parsed expression to a SQL condition string. + if err := d.ConvertExprToSQL(convertCtx, parsedExpr.GetExpr()); err != nil { + return nil, err + } + condition := convertCtx.Buffer.String() + if condition != "" { + where = append(where, fmt.Sprintf("(%s)", condition)) + args = append(args, convertCtx.Args...) + } + } if v := find.ID; v != nil { where, args = append(where, "memo.id = "+placeholder(len(args)+1)), append(args, *v) } @@ -103,25 +122,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo where = append(where, "(memo.payload->'property'->>'hasIncompleteTasks')::BOOLEAN IS TRUE") } } - if v := find.Filter; v != nil { - // Parse filter string and return the parsed expression. - // The filter string should be a CEL expression. - parsedExpr, err := filter.Parse(*v, filter.MemoFilterCELAttributes...) - if err != nil { - return nil, err - } - convertCtx := filter.NewConvertContext() - convertCtx.ArgsOffset = len(args) - // ConvertExprToSQL converts the parsed expression to a SQL condition string. - if err := d.ConvertExprToSQL(convertCtx, parsedExpr.GetExpr()); err != nil { - return nil, err - } - condition := convertCtx.Buffer.String() - if condition != "" { - where = append(where, fmt.Sprintf("(%s)", condition)) - args = append(args, convertCtx.Args...) - } - } if find.ExcludeComments { where = append(where, "memo_relation.related_memo_id IS NULL") } diff --git a/store/db/sqlite/memo.go b/store/db/sqlite/memo.go index db8a9831c..3460282a4 100644 --- a/store/db/sqlite/memo.go +++ b/store/db/sqlite/memo.go @@ -42,6 +42,24 @@ func (d *DB) CreateMemo(ctx context.Context, create *store.Memo) (*store.Memo, e func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo, error) { where, args := []string{"1 = 1"}, []any{} + for _, filterStr := range find.Filters { + // Parse filter string and return the parsed expression. + // The filter string should be a CEL expression. + parsedExpr, err := filter.Parse(filterStr, filter.MemoFilterCELAttributes...) + if err != nil { + return nil, err + } + convertCtx := filter.NewConvertContext() + // ConvertExprToSQL converts the parsed expression to a SQL condition string. + if err := d.ConvertExprToSQL(convertCtx, parsedExpr.GetExpr()); err != nil { + return nil, err + } + condition := convertCtx.Buffer.String() + if condition != "" { + where = append(where, fmt.Sprintf("(%s)", condition)) + args = append(args, convertCtx.Args...) + } + } if v := find.ID; v != nil { where, args = append(where, "`memo`.`id` = ?"), append(args, *v) } @@ -104,24 +122,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo where = append(where, "JSON_EXTRACT(`memo`.`payload`, '$.property.hasIncompleteTasks') IS TRUE") } } - if v := find.Filter; v != nil { - // Parse filter string and return the parsed expression. - // The filter string should be a CEL expression. - parsedExpr, err := filter.Parse(*v, filter.MemoFilterCELAttributes...) - if err != nil { - return nil, err - } - convertCtx := filter.NewConvertContext() - // ConvertExprToSQL converts the parsed expression to a SQL condition string. - if err := d.ConvertExprToSQL(convertCtx, parsedExpr.GetExpr()); err != nil { - return nil, err - } - condition := convertCtx.Buffer.String() - if condition != "" { - where = append(where, fmt.Sprintf("(%s)", condition)) - args = append(args, convertCtx.Args...) - } - } if find.ExcludeComments { where = append(where, "`parent_id` IS NULL") } diff --git a/store/memo.go b/store/memo.go index e29bb0a4e..5192f881f 100644 --- a/store/memo.go +++ b/store/memo.go @@ -74,7 +74,7 @@ type FindMemo struct { PayloadFind *FindMemoPayload ExcludeContent bool ExcludeComments bool - Filter *string + Filters []string // Pagination Limit *int