Tests[SearchMessageFTSSimple]

This commit is contained in:
Mike Schwörer 2022-12-11 02:47:23 +01:00
parent 3692b915f3
commit 26cd1533b4
Signed by: Mikescher
GPG Key ID: D3C7172E0A70F8CF
9 changed files with 59 additions and 20 deletions

View File

@ -1184,6 +1184,10 @@ func (h APIHandler) ListMessages(g *gin.Context) ginresp.HTTPResponse {
ConfirmedSubscriptionBy: langext.Ptr(userid), ConfirmedSubscriptionBy: langext.Ptr(userid),
} }
if q.Filter != nil && strings.TrimSpace(*q.Filter) != "" {
filter.SearchString = langext.Ptr([]string{strings.TrimSpace(*q.Filter)})
}
messages, npt, err := h.database.ListMessages(ctx, filter, pageSize, tok) messages, npt, err := h.database.ListMessages(ctx, filter, pageSize, tok)
if err != nil { if err != nil {
return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query messages", err) return ginresp.APIError(g, 500, apierr.DATABASE_ERROR, "Failed to query messages", err)

View File

@ -201,7 +201,7 @@ func (h CompatHandler) Info(g *gin.Context) ginresp.HTTPResponse {
return ginresp.CompatAPIError(0, "Failed to query clients") return ginresp.CompatAPIError(0, "Failed to query clients")
} }
fcmSet := langext.ArrAny(clients, func(i int) bool { return clients[i].FCMToken != nil }) fcmSet := langext.ArrAny(clients, func(c models.Client) bool { return c.FCMToken != nil })
return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{ return ctx.FinishSuccess(ginresp.JSON(http.StatusOK, response{
Success: true, Success: true,

View File

@ -121,7 +121,7 @@ func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pag
return make([]models.Message, 0), cursortoken.End(), nil return make([]models.Message, 0), cursortoken.End(), nil
} }
pageCond := "" pageCond := "1=1"
if inTok.Mode == cursortoken.CTMNormal { if inTok.Mode == cursortoken.CTMNormal {
pageCond = "timestamp_real < :tokts OR (timestamp_real = :tokts AND scn_message_id < :tokid )" pageCond = "timestamp_real < :tokts OR (timestamp_real = :tokts AND scn_message_id < :tokid )"
} }
@ -130,7 +130,7 @@ func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pag
orderClause := "ORDER BY COALESCE(timestamp_client, timestamp_real) DESC LIMIT :lim" orderClause := "ORDER BY COALESCE(timestamp_client, timestamp_real) DESC LIMIT :lim"
sqlQuery := "SELECT " + "messages.*" + " FROM messages " + filterJoin + " WHERE ( " + filterCond + " ) AND ( " + pageCond + " ) " + orderClause sqlQuery := "SELECT " + "messages.*" + " FROM messages " + filterJoin + " WHERE ( " + pageCond + " ) AND ( " + filterCond + " ) " + orderClause
prepParams["lim"] = pageSize + 1 prepParams["lim"] = pageSize + 1
prepParams["tokts"] = inTok.Timestamp prepParams["tokts"] = inTok.Timestamp

View File

@ -8,7 +8,7 @@ require (
github.com/mattn/go-sqlite3 v1.14.16 github.com/mattn/go-sqlite3 v1.14.16
github.com/rs/zerolog v1.28.0 github.com/rs/zerolog v1.28.0
github.com/swaggo/swag v1.8.7 github.com/swaggo/swag v1.8.7
gogs.mikescher.com/BlackForestBytes/goext v0.0.32 gogs.mikescher.com/BlackForestBytes/goext v0.0.33
) )
require ( require (

View File

@ -102,6 +102,8 @@ gogs.mikescher.com/BlackForestBytes/goext v0.0.31 h1:DC2RZe7/tSDDbPRbjDcYa+BLRlY
gogs.mikescher.com/BlackForestBytes/goext v0.0.31/go.mod h1:/u9JtMwCP68ix4R9BJ/MT0Lm+QScmqIoyYZFKBGzv9g= gogs.mikescher.com/BlackForestBytes/goext v0.0.31/go.mod h1:/u9JtMwCP68ix4R9BJ/MT0Lm+QScmqIoyYZFKBGzv9g=
gogs.mikescher.com/BlackForestBytes/goext v0.0.32 h1:DJoRBNhq4rrOBXA/nD6WEm7L3vylLkMifU9/sWEiF7M= gogs.mikescher.com/BlackForestBytes/goext v0.0.32 h1:DJoRBNhq4rrOBXA/nD6WEm7L3vylLkMifU9/sWEiF7M=
gogs.mikescher.com/BlackForestBytes/goext v0.0.32/go.mod h1:/u9JtMwCP68ix4R9BJ/MT0Lm+QScmqIoyYZFKBGzv9g= gogs.mikescher.com/BlackForestBytes/goext v0.0.32/go.mod h1:/u9JtMwCP68ix4R9BJ/MT0Lm+QScmqIoyYZFKBGzv9g=
gogs.mikescher.com/BlackForestBytes/goext v0.0.33 h1:NQRgsEs2j8eY9V45Ynq84+F0FgBfvapOGv4JZMh0eaI=
gogs.mikescher.com/BlackForestBytes/goext v0.0.33/go.mod h1:/u9JtMwCP68ix4R9BJ/MT0Lm+QScmqIoyYZFKBGzv9g=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97 h1:/UOmuWzQfxxo9UtlXMwuQU8CMgg1eZXqTRwkSQJWKOI=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s= golang.org/x/mod v0.6.0-dev.0.20220419223038-86c51ed26bb4 h1:6zppjxzCulZykYSLyVDYbneBfbaBIQPYMevg0bEwv2s=

View File

@ -46,7 +46,7 @@ func (f MessageFilter) SQL() (string, string, sq.PP, error) {
joinClause += " LEFT JOIN subscriptions subs on messages.channel_id = subs.channel_id " joinClause += " LEFT JOIN subscriptions subs on messages.channel_id = subs.channel_id "
} }
if f.SearchString != nil { if f.SearchString != nil {
joinClause += " JOIN messages_fts mfts on (mfts.rowid = a.scn_message_id) " joinClause += " JOIN messages_fts mfts on (mfts.rowid = messages.scn_message_id) "
} }
sqlClauses := make([]string, 0) sqlClauses := make([]string, 0)
@ -58,15 +58,6 @@ func (f MessageFilter) SQL() (string, string, sq.PP, error) {
params["sub_uid"] = *f.ConfirmedSubscriptionBy params["sub_uid"] = *f.ConfirmedSubscriptionBy
} }
if f.SearchString != nil {
filter := make([]string, 0)
for i, v := range *f.SearchString {
filter = append(filter, fmt.Sprintf("(messages_fts match :searchstring_%d)", i))
params[fmt.Sprintf("searchstring_%d", i)] = v
}
sqlClauses = append(sqlClauses, "("+strings.Join(filter, " OR ")+")")
}
if f.Sender != nil { if f.Sender != nil {
filter := make([]string, 0) filter := make([]string, 0)
for i, v := range *f.Sender { for i, v := range *f.Sender {
@ -208,9 +199,20 @@ func (f MessageFilter) SQL() (string, string, sq.PP, error) {
sqlClauses = append(sqlClauses, "(usr_message_id IS NOT NULL AND ("+strings.Join(filter, " OR ")+"))") sqlClauses = append(sqlClauses, "(usr_message_id IS NOT NULL AND ("+strings.Join(filter, " OR ")+"))")
} }
if f.SearchString != nil {
filter := make([]string, 0)
for i, v := range *f.SearchString {
filter = append(filter, fmt.Sprintf("(messages_fts match :searchstring_%d)", i))
params[fmt.Sprintf("searchstring_%d", i)] = v
}
sqlClauses = append(sqlClauses, "("+strings.Join(filter, " OR ")+")")
}
sqlClause := "" sqlClause := ""
if len(sqlClauses) > 0 { if len(sqlClauses) > 0 {
sqlClause = strings.Join(sqlClauses, " AND ") sqlClause = strings.Join(sqlClauses, " AND ")
} else {
sqlClause = "1=1"
} }
return sqlClause, joinClause, params, nil return sqlClause, joinClause, params, nil

View File

@ -2,15 +2,32 @@ package test
import ( import (
tt "blackforestbytes.com/simplecloudnotifier/test/util" tt "blackforestbytes.com/simplecloudnotifier/test/util"
"fmt"
"github.com/gin-gonic/gin"
"gogs.mikescher.com/BlackForestBytes/goext/langext"
"net/url"
"testing" "testing"
) )
func TestSearchMessageFTS(t *testing.T) { func TestSearchMessageFTSSimple(t *testing.T) {
ws, stop := tt.StartSimpleWebserver(t) ws, stop := tt.StartSimpleWebserver(t)
defer stop() defer stop()
tt.InitDefaultData(t, ws) baseUrl := "http://127.0.0.1:" + ws.Port
data := tt.InitDefaultData(t, ws)
type mglist struct {
Messages []gin.H `json:"messages"`
}
msgList := tt.RequestAuthGet[mglist](t, data.User[0].AdminKey, baseUrl, fmt.Sprintf("/api/messages?filter=%s", url.QueryEscape("Friday")))
tt.AssertEqual(t, "msgList.len", 2, len(msgList.Messages))
tt.AssertTrue(t, "msgList.any<1>", langext.ArrAny(msgList.Messages, func(msg gin.H) bool { return msg["title"].(string) == "Invitation" }))
tt.AssertTrue(t, "msgList.any<2>", langext.ArrAny(msgList.Messages, func(msg gin.H) bool { return msg["title"].(string) == "Important notice" }))
}
func TestSearchMessageFTSMulti(t *testing.T) {
//TODO search for messages by FTS //TODO search for messages by FTS
} }

View File

@ -56,6 +56,14 @@ func AssertEqual(t *testing.T, key string, expected any, actual any) {
} }
} }
func AssertTrue(t *testing.T, key string, v bool) {
if !v {
t.Errorf("AssertTrue(%s) failed", key)
t.Error(string(debug.Stack()))
t.FailNow()
}
}
func AssertNotEqual(t *testing.T, key string, expected any, actual any) { func AssertNotEqual(t *testing.T, key string, expected any, actual any) {
if expected == actual { if expected == actual {
t.Errorf("Value [%s] does not differ (%T <-> %T):\n", key, expected, actual) t.Errorf("Value [%s] does not differ (%T <-> %T):\n", key, expected, actual)

View File

@ -58,7 +58,7 @@ type clientex struct {
FCMTok string FCMTok string
} }
type userdat struct { type Userdat struct {
UID int64 UID int64
SendKey string SendKey string
AdminKey string AdminKey string
@ -266,7 +266,11 @@ var messageExamples = []msgex{
{11, "Promotions", "", P2, SKEY, "Summer Clearance: Save Up to 75% on Your Favorite Products", "It's time for our annual summer clearance sale! Save up to 75% on your favorite products, from clothing and accessories to home decor and more.", timeext.FromHours(1.87)}, {11, "Promotions", "", P2, SKEY, "Summer Clearance: Save Up to 75% on Your Favorite Products", "It's time for our annual summer clearance sale! Save up to 75% on your favorite products, from clothing and accessories to home decor and more.", timeext.FromHours(1.87)},
} }
func InitDefaultData(t *testing.T, ws *logic.Application) { type DefData struct {
User []Userdat
}
func InitDefaultData(t *testing.T, ws *logic.Application) DefData {
// set logger to buffer, only output if error occured // set logger to buffer, only output if error occured
success := false success := false
@ -280,7 +284,7 @@ func InitDefaultData(t *testing.T, ws *logic.Application) {
baseUrl := "http://127.0.0.1:" + ws.Port baseUrl := "http://127.0.0.1:" + ws.Port
users := make([]userdat, 0, len(userExamples)) users := make([]Userdat, 0, len(userExamples))
for _, uex := range userExamples { for _, uex := range userExamples {
body := gin.H{} body := gin.H{}
@ -306,7 +310,7 @@ func InitDefaultData(t *testing.T, ws *logic.Application) {
admintok0 := user0["admin_key"].(string) admintok0 := user0["admin_key"].(string)
AssertMultiNonEmpty(t, "user0", uid0, readtok0, sendtok0, admintok0) AssertMultiNonEmpty(t, "user0", uid0, readtok0, sendtok0, admintok0)
users = append(users, userdat{ users = append(users, Userdat{
UID: uid0, UID: uid0,
SendKey: sendtok0, SendKey: sendtok0,
AdminKey: admintok0, AdminKey: admintok0,
@ -361,6 +365,8 @@ func InitDefaultData(t *testing.T, ws *logic.Application) {
} }
success = true success = true
return DefData{User: users}
} }
func lipsum(seed int64, paracount int) string { func lipsum(seed int64, paracount int) string {