Tests[SearchMessageFTSSimple]
This commit is contained in:
parent
3692b915f3
commit
26cd1533b4
@ -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)
|
||||||
|
@ -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,
|
||||||
|
@ -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
|
||||||
|
@ -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 (
|
||||||
|
@ -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=
|
||||||
|
@ -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
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
Loading…
Reference in New Issue
Block a user