mirror of
https://github.com/usememos/memos.git
synced 2025-09-13 09:17:24 +08:00
fix: memo filter for sqlite
This commit is contained in:
parent
ac386c218d
commit
1a75d19a89
8 changed files with 23 additions and 153 deletions
|
@ -559,7 +559,7 @@ func (s *APIV1Service) RenameMemoTag(ctx context.Context, request *v1pb.RenameMe
|
|||
|
||||
memoFind := &store.FindMemo{
|
||||
CreatorID: &user.ID,
|
||||
PayloadFind: &store.FindMemoPayload{TagSearch: []string{request.OldTag}},
|
||||
Filters: []string{fmt.Sprintf("tag in [\"%s\"]", request.OldTag)},
|
||||
ExcludeComments: true,
|
||||
}
|
||||
if (request.Parent) != "memos/-" {
|
||||
|
@ -609,7 +609,7 @@ func (s *APIV1Service) DeleteMemoTag(ctx context.Context, request *v1pb.DeleteMe
|
|||
|
||||
memoFind := &store.FindMemo{
|
||||
CreatorID: &user.ID,
|
||||
PayloadFind: &store.FindMemoPayload{TagSearch: []string{request.Tag}},
|
||||
Filters: []string{fmt.Sprintf("tag in [\"%s\"]", request.Tag)},
|
||||
ExcludeContent: true,
|
||||
ExcludeComments: true,
|
||||
}
|
||||
|
|
|
@ -80,23 +80,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
|
|||
if v := find.RowStatus; v != nil {
|
||||
where, args = append(where, "`memo`.`row_status` = ?"), append(args, *v)
|
||||
}
|
||||
if v := find.CreatedTsBefore; v != nil {
|
||||
where, args = append(where, "UNIX_TIMESTAMP(`memo`.`created_ts`) < ?"), append(args, *v)
|
||||
}
|
||||
if v := find.CreatedTsAfter; v != nil {
|
||||
where, args = append(where, "UNIX_TIMESTAMP(`memo`.`created_ts`) > ?"), append(args, *v)
|
||||
}
|
||||
if v := find.UpdatedTsBefore; v != nil {
|
||||
where, args = append(where, "UNIX_TIMESTAMP(`memo`.`updated_ts`) < ?"), append(args, *v)
|
||||
}
|
||||
if v := find.UpdatedTsAfter; v != nil {
|
||||
where, args = append(where, "UNIX_TIMESTAMP(`memo`.`updated_ts`) > ?"), append(args, *v)
|
||||
}
|
||||
if v := find.ContentSearch; len(v) != 0 {
|
||||
for _, s := range v {
|
||||
where, args = append(where, "`memo`.`content` LIKE ?"), append(args, "%"+s+"%")
|
||||
}
|
||||
}
|
||||
if v := find.VisibilityList; len(v) != 0 {
|
||||
placeholder := []string{}
|
||||
for _, visibility := range v {
|
||||
|
@ -105,31 +88,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
|
|||
}
|
||||
where = append(where, fmt.Sprintf("`memo`.`visibility` in (%s)", strings.Join(placeholder, ",")))
|
||||
}
|
||||
if v := find.Pinned; v != nil {
|
||||
where, args = append(where, "`memo`.`pinned` = ?"), append(args, *v)
|
||||
}
|
||||
if v := find.PayloadFind; v != nil {
|
||||
if v.Raw != nil {
|
||||
where, args = append(where, "`memo`.`payload` = ?"), append(args, *v.Raw)
|
||||
}
|
||||
if len(v.TagSearch) != 0 {
|
||||
for _, tag := range v.TagSearch {
|
||||
where, args = append(where, "(JSON_CONTAINS(JSON_EXTRACT(`memo`.`payload`, '$.tags'), ?) OR JSON_CONTAINS(JSON_EXTRACT(`memo`.`payload`, '$.tags'), ?))"), append(args, fmt.Sprintf(`"%s"`, tag), fmt.Sprintf(`"%s/"`, tag))
|
||||
}
|
||||
}
|
||||
if v.HasLink {
|
||||
where = append(where, "JSON_EXTRACT(`memo`.`payload`, '$.property.hasLink') IS TRUE")
|
||||
}
|
||||
if v.HasTaskList {
|
||||
where = append(where, "JSON_EXTRACT(`memo`.`payload`, '$.property.hasTaskList') IS TRUE")
|
||||
}
|
||||
if v.HasCode {
|
||||
where = append(where, "JSON_EXTRACT(`memo`.`payload`, '$.property.hasCode') IS TRUE")
|
||||
}
|
||||
if v.HasIncompleteTasks {
|
||||
where = append(where, "JSON_EXTRACT(`memo`.`payload`, '$.property.hasIncompleteTasks') IS TRUE")
|
||||
}
|
||||
}
|
||||
if find.ExcludeComments {
|
||||
having = append(having, "`parent_id` IS NULL")
|
||||
}
|
||||
|
|
|
@ -72,23 +72,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
|
|||
if v := find.RowStatus; v != nil {
|
||||
where, args = append(where, "memo.row_status = "+placeholder(len(args)+1)), append(args, *v)
|
||||
}
|
||||
if v := find.CreatedTsBefore; v != nil {
|
||||
where, args = append(where, "memo.created_ts < "+placeholder(len(args)+1)), append(args, *v)
|
||||
}
|
||||
if v := find.CreatedTsAfter; v != nil {
|
||||
where, args = append(where, "memo.created_ts > "+placeholder(len(args)+1)), append(args, *v)
|
||||
}
|
||||
if v := find.UpdatedTsBefore; v != nil {
|
||||
where, args = append(where, "memo.updated_ts < "+placeholder(len(args)+1)), append(args, *v)
|
||||
}
|
||||
if v := find.UpdatedTsAfter; v != nil {
|
||||
where, args = append(where, "memo.updated_ts > "+placeholder(len(args)+1)), append(args, *v)
|
||||
}
|
||||
if v := find.ContentSearch; len(v) != 0 {
|
||||
for _, s := range v {
|
||||
where, args = append(where, "memo.content ILIKE "+placeholder(len(args)+1)), append(args, fmt.Sprintf("%%%s%%", s))
|
||||
}
|
||||
}
|
||||
if v := find.VisibilityList; len(v) != 0 {
|
||||
holders := []string{}
|
||||
for _, visibility := range v {
|
||||
|
@ -97,31 +80,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
|
|||
}
|
||||
where = append(where, fmt.Sprintf("memo.visibility in (%s)", strings.Join(holders, ", ")))
|
||||
}
|
||||
if v := find.Pinned; v != nil {
|
||||
where, args = append(where, "memo.pinned = "+placeholder(len(args)+1)), append(args, *v)
|
||||
}
|
||||
if v := find.PayloadFind; v != nil {
|
||||
if v.Raw != nil {
|
||||
where, args = append(where, "memo.payload = "+placeholder(len(args)+1)), append(args, *v.Raw)
|
||||
}
|
||||
if len(v.TagSearch) != 0 {
|
||||
for _, tag := range v.TagSearch {
|
||||
where, args = append(where, "EXISTS (SELECT 1 FROM jsonb_array_elements(memo.payload->'tags') AS tag WHERE tag::text = "+placeholder(len(args)+1)+" OR tag::text LIKE "+placeholder(len(args)+2)+")"), append(args, fmt.Sprintf(`"%s"`, tag), fmt.Sprintf(`"%s/%%"`, tag))
|
||||
}
|
||||
}
|
||||
if v.HasLink {
|
||||
where = append(where, "(memo.payload->'property'->>'hasLink')::BOOLEAN IS TRUE")
|
||||
}
|
||||
if v.HasTaskList {
|
||||
where = append(where, "(memo.payload->'property'->>'hasTaskList')::BOOLEAN IS TRUE")
|
||||
}
|
||||
if v.HasCode {
|
||||
where = append(where, "(memo.payload->'property'->>'hasCode')::BOOLEAN IS TRUE")
|
||||
}
|
||||
if v.HasIncompleteTasks {
|
||||
where = append(where, "(memo.payload->'property'->>'hasIncompleteTasks')::BOOLEAN IS TRUE")
|
||||
}
|
||||
}
|
||||
if find.ExcludeComments {
|
||||
where = append(where, "memo_relation.related_memo_id IS NULL")
|
||||
}
|
||||
|
|
|
@ -72,23 +72,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
|
|||
if v := find.RowStatus; v != nil {
|
||||
where, args = append(where, "`memo`.`row_status` = ?"), append(args, *v)
|
||||
}
|
||||
if v := find.CreatedTsBefore; v != nil {
|
||||
where, args = append(where, "`memo`.`created_ts` < ?"), append(args, *v)
|
||||
}
|
||||
if v := find.CreatedTsAfter; v != nil {
|
||||
where, args = append(where, "`memo`.`created_ts` > ?"), append(args, *v)
|
||||
}
|
||||
if v := find.UpdatedTsBefore; v != nil {
|
||||
where, args = append(where, "`memo`.`updated_ts` < ?"), append(args, *v)
|
||||
}
|
||||
if v := find.UpdatedTsAfter; v != nil {
|
||||
where, args = append(where, "`memo`.`updated_ts` > ?"), append(args, *v)
|
||||
}
|
||||
if v := find.ContentSearch; len(v) != 0 {
|
||||
for _, s := range v {
|
||||
where, args = append(where, "`memo`.`content` LIKE ?"), append(args, fmt.Sprintf("%%%s%%", s))
|
||||
}
|
||||
}
|
||||
if v := find.VisibilityList; len(v) != 0 {
|
||||
placeholder := []string{}
|
||||
for _, visibility := range v {
|
||||
|
@ -97,31 +80,6 @@ func (d *DB) ListMemos(ctx context.Context, find *store.FindMemo) ([]*store.Memo
|
|||
}
|
||||
where = append(where, fmt.Sprintf("`memo`.`visibility` IN (%s)", strings.Join(placeholder, ",")))
|
||||
}
|
||||
if v := find.Pinned; v != nil {
|
||||
where, args = append(where, "`memo`.`pinned` = ?"), append(args, *v)
|
||||
}
|
||||
if v := find.PayloadFind; v != nil {
|
||||
if v.Raw != nil {
|
||||
where, args = append(where, "`memo`.`payload` = ?"), append(args, *v.Raw)
|
||||
}
|
||||
if len(v.TagSearch) != 0 {
|
||||
for _, tag := range v.TagSearch {
|
||||
where, args = append(where, "(JSON_EXTRACT(`memo`.`payload`, '$.tags') LIKE ? OR JSON_EXTRACT(`memo`.`payload`, '$.tags') LIKE ?)"), append(args, fmt.Sprintf(`%%"%s"%%`, tag), fmt.Sprintf(`%%"%s/%%`, tag))
|
||||
}
|
||||
}
|
||||
if v.HasLink {
|
||||
where = append(where, "JSON_EXTRACT(`memo`.`payload`, '$.property.hasLink') IS TRUE")
|
||||
}
|
||||
if v.HasTaskList {
|
||||
where = append(where, "JSON_EXTRACT(`memo`.`payload`, '$.property.hasTaskList') IS TRUE")
|
||||
}
|
||||
if v.HasCode {
|
||||
where = append(where, "JSON_EXTRACT(`memo`.`payload`, '$.property.hasCode') IS TRUE")
|
||||
}
|
||||
if v.HasIncompleteTasks {
|
||||
where = append(where, "JSON_EXTRACT(`memo`.`payload`, '$.property.hasIncompleteTasks') IS TRUE")
|
||||
}
|
||||
}
|
||||
if find.ExcludeComments {
|
||||
where = append(where, "`parent_id` IS NULL")
|
||||
}
|
||||
|
|
|
@ -200,15 +200,15 @@ func (d *DB) convertWithTemplates(ctx *filter.ConvertContext, expr *exprv1.Expr)
|
|||
var sqlTemplate string
|
||||
if operator == "=" {
|
||||
if valueBool {
|
||||
sqlTemplate = fmt.Sprintf("JSON_EXTRACT(`memo`.`payload`, '%s') = JSON('true')", jsonPath)
|
||||
sqlTemplate = fmt.Sprintf("JSON_EXTRACT(`memo`.`payload`, '%s') IS TRUE", jsonPath)
|
||||
} else {
|
||||
sqlTemplate = fmt.Sprintf("JSON_EXTRACT(`memo`.`payload`, '%s') = JSON('false')", jsonPath)
|
||||
sqlTemplate = fmt.Sprintf("NOT(JSON_EXTRACT(`memo`.`payload`, '%s') IS TRUE)", jsonPath)
|
||||
}
|
||||
} else { // operator == "!="
|
||||
if valueBool {
|
||||
sqlTemplate = fmt.Sprintf("JSON_EXTRACT(`memo`.`payload`, '%s') != JSON('true')", jsonPath)
|
||||
sqlTemplate = fmt.Sprintf("NOT(JSON_EXTRACT(`memo`.`payload`, '%s') IS TRUE)", jsonPath)
|
||||
} else {
|
||||
sqlTemplate = fmt.Sprintf("JSON_EXTRACT(`memo`.`payload`, '%s') != JSON('false')", jsonPath)
|
||||
sqlTemplate = fmt.Sprintf("JSON_EXTRACT(`memo`.`payload`, '%s') IS TRUE", jsonPath)
|
||||
}
|
||||
}
|
||||
if _, err := ctx.Buffer.WriteString(sqlTemplate); err != nil {
|
||||
|
@ -319,17 +319,17 @@ func (d *DB) convertWithTemplates(ctx *filter.ConvertContext, expr *exprv1.Expr)
|
|||
}
|
||||
} else if identifier == "has_link" {
|
||||
// Handle has_link as a standalone boolean identifier
|
||||
if _, err := ctx.Buffer.WriteString("JSON_EXTRACT(`memo`.`payload`, '$.property.hasLink') = JSON('true')"); err != nil {
|
||||
if _, err := ctx.Buffer.WriteString("JSON_EXTRACT(`memo`.`payload`, '$.property.hasLink') IS TRUE"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if identifier == "has_code" {
|
||||
// Handle has_code as a standalone boolean identifier
|
||||
if _, err := ctx.Buffer.WriteString("JSON_EXTRACT(`memo`.`payload`, '$.property.hasCode') = JSON('true')"); err != nil {
|
||||
if _, err := ctx.Buffer.WriteString("JSON_EXTRACT(`memo`.`payload`, '$.property.hasCode') IS TRUE"); err != nil {
|
||||
return err
|
||||
}
|
||||
} else if identifier == "has_incomplete_tasks" {
|
||||
// Handle has_incomplete_tasks as a standalone boolean identifier
|
||||
if _, err := ctx.Buffer.WriteString("JSON_EXTRACT(`memo`.`payload`, '$.property.hasIncompleteTasks') = JSON('true')"); err != nil {
|
||||
if _, err := ctx.Buffer.WriteString("JSON_EXTRACT(`memo`.`payload`, '$.property.hasIncompleteTasks') IS TRUE"); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
|
|
@ -60,6 +60,11 @@ func TestConvertExprToSQL(t *testing.T) {
|
|||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasTaskList') IS TRUE",
|
||||
args: []any{},
|
||||
},
|
||||
{
|
||||
filter: `has_code`,
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasCode') IS TRUE",
|
||||
args: []any{},
|
||||
},
|
||||
{
|
||||
filter: `has_task_list == true`,
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasTaskList') = 1",
|
||||
|
@ -117,32 +122,32 @@ func TestConvertExprToSQL(t *testing.T) {
|
|||
},
|
||||
{
|
||||
filter: `has_link == true`,
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasLink') = JSON('true')",
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasLink') IS TRUE",
|
||||
args: []any{},
|
||||
},
|
||||
{
|
||||
filter: `has_code == false`,
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasCode') = JSON('false')",
|
||||
want: "NOT(JSON_EXTRACT(`memo`.`payload`, '$.property.hasCode') IS TRUE)",
|
||||
args: []any{},
|
||||
},
|
||||
{
|
||||
filter: `has_incomplete_tasks != false`,
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasIncompleteTasks') != JSON('false')",
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasIncompleteTasks') IS TRUE",
|
||||
args: []any{},
|
||||
},
|
||||
{
|
||||
filter: `has_link`,
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasLink') = JSON('true')",
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasLink') IS TRUE",
|
||||
args: []any{},
|
||||
},
|
||||
{
|
||||
filter: `has_code`,
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasCode') = JSON('true')",
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasCode') IS TRUE",
|
||||
args: []any{},
|
||||
},
|
||||
{
|
||||
filter: `has_incomplete_tasks`,
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasIncompleteTasks') = JSON('true')",
|
||||
want: "JSON_EXTRACT(`memo`.`payload`, '$.property.hasIncompleteTasks') IS TRUE",
|
||||
args: []any{},
|
||||
},
|
||||
}
|
||||
|
|
|
@ -60,18 +60,11 @@ type FindMemo struct {
|
|||
UID *string
|
||||
|
||||
// Standard fields
|
||||
RowStatus *RowStatus
|
||||
CreatorID *int32
|
||||
CreatedTsAfter *int64
|
||||
CreatedTsBefore *int64
|
||||
UpdatedTsAfter *int64
|
||||
UpdatedTsBefore *int64
|
||||
RowStatus *RowStatus
|
||||
CreatorID *int32
|
||||
|
||||
// Domain specific fields
|
||||
ContentSearch []string
|
||||
VisibilityList []Visibility
|
||||
Pinned *bool
|
||||
PayloadFind *FindMemoPayload
|
||||
ExcludeContent bool
|
||||
ExcludeComments bool
|
||||
Filters []string
|
||||
|
|
|
@ -86,9 +86,7 @@ func TestMemoListByTags(t *testing.T) {
|
|||
require.NotNil(t, memo)
|
||||
|
||||
memoList, err := ts.ListMemos(ctx, &store.FindMemo{
|
||||
PayloadFind: &store.FindMemoPayload{
|
||||
TagSearch: []string{"test_tag"},
|
||||
},
|
||||
Filters: []string{"tag in [\"test_tag\"]"},
|
||||
})
|
||||
require.NoError(t, err)
|
||||
require.Equal(t, 1, len(memoList))
|
||||
|
|
Loading…
Add table
Reference in a new issue