Move to string-ids for all entities (compat translation for existing data)
This commit is contained in:
@@ -19,14 +19,14 @@ const (
|
||||
type CursorToken struct {
|
||||
Mode Mode
|
||||
Timestamp int64
|
||||
Id int64
|
||||
Id string
|
||||
Direction string
|
||||
FilterHash string
|
||||
}
|
||||
|
||||
type cursorTokenSerialize struct {
|
||||
Timestamp *int64 `json:"ts,omitempty"`
|
||||
Id *int64 `json:"id,omitempty"`
|
||||
Id *string `json:"id,omitempty"`
|
||||
Direction *string `json:"dir,omitempty"`
|
||||
FilterHash *string `json:"f,omitempty"`
|
||||
}
|
||||
@@ -35,7 +35,7 @@ func Start() CursorToken {
|
||||
return CursorToken{
|
||||
Mode: CTMStart,
|
||||
Timestamp: 0,
|
||||
Id: 0,
|
||||
Id: "",
|
||||
Direction: "",
|
||||
FilterHash: "",
|
||||
}
|
||||
@@ -45,13 +45,13 @@ func End() CursorToken {
|
||||
return CursorToken{
|
||||
Mode: CTMEnd,
|
||||
Timestamp: 0,
|
||||
Id: 0,
|
||||
Id: "",
|
||||
Direction: "",
|
||||
FilterHash: "",
|
||||
}
|
||||
}
|
||||
|
||||
func Normal(ts time.Time, id int64, dir string, filter string) CursorToken {
|
||||
func Normal(ts time.Time, id string, dir string, filter string) CursorToken {
|
||||
return CursorToken{
|
||||
Mode: CTMNormal,
|
||||
Timestamp: ts.UnixMilli(),
|
||||
@@ -76,7 +76,7 @@ func (c *CursorToken) Token() string {
|
||||
|
||||
sertok := cursorTokenSerialize{}
|
||||
|
||||
if c.Id != 0 {
|
||||
if c.Id != "" {
|
||||
sertok.Id = &c.Id
|
||||
}
|
||||
|
||||
|
@@ -24,7 +24,7 @@ type Database struct {
|
||||
func NewLogsDatabase(cfg server.Config) (*Database, error) {
|
||||
conf := cfg.DBLogs
|
||||
|
||||
url := fmt.Sprintf("file:%s?_journal=%s&_timeout=%d&_fk=%s", conf.File, conf.Journal, conf.Timeout.Milliseconds(), langext.FormatBool(conf.CheckForeignKeys, "true", "false"))
|
||||
url := fmt.Sprintf("file:%s?_journal=%s&_timeout=%d&_fk=%s&_busy_timeout=%d", conf.File, conf.Journal, conf.Timeout.Milliseconds(), langext.FormatBool(conf.CheckForeignKeys, "true", "false"), conf.BusyTimeout.Milliseconds())
|
||||
|
||||
xdb, err := sqlx.Open("sqlite3", url)
|
||||
if err != nil {
|
||||
|
@@ -1,9 +1,10 @@
|
||||
|
||||
CREATE TABLE `logs`
|
||||
(
|
||||
log_id INTEGER PRIMARY KEY,
|
||||
timestamp_created INTEGER NOT NULL
|
||||
log_id TEXT NOT NULL,
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (log_id)
|
||||
) STRICT;
|
||||
|
||||
|
||||
|
@@ -89,7 +89,10 @@ func (db *Database) CreateChannel(ctx TxContext, userid models.UserID, dispName
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
res, err := tx.Exec(ctx, "INSERT INTO channels (owner_user_id, display_name, internal_name, subscribe_key, send_key, timestamp_created) VALUES (:ouid, :dnam, :inam, :subkey, :sendkey, :ts)", sq.PP{
|
||||
channelid := models.NewChannelID()
|
||||
|
||||
_, err = tx.Exec(ctx, "INSERT INTO channels (channel_id, owner_user_id, display_name, internal_name, subscribe_key, send_key, timestamp_created) VALUES (:cid, :ouid, :dnam, :inam, :subkey, :sendkey, :ts)", sq.PP{
|
||||
"cid": channelid,
|
||||
"ouid": userid,
|
||||
"dnam": dispName,
|
||||
"inam": intName,
|
||||
@@ -101,13 +104,8 @@ func (db *Database) CreateChannel(ctx TxContext, userid models.UserID, dispName
|
||||
return models.Channel{}, err
|
||||
}
|
||||
|
||||
liid, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return models.Channel{}, err
|
||||
}
|
||||
|
||||
return models.Channel{
|
||||
ChannelID: models.ChannelID(liid),
|
||||
ChannelID: channelid,
|
||||
OwnerUserID: userid,
|
||||
DisplayName: dispName,
|
||||
InternalName: intName,
|
||||
@@ -125,7 +123,9 @@ func (db *Database) ListChannelsByOwner(ctx TxContext, userid models.UserID, sub
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT channels.*, sub.* FROM channels LEFT JOIN subscriptions AS sub ON channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid WHERE owner_user_id = :ouid", sq.PP{
|
||||
order := " ORDER BY channels.timestamp_created ASC, channels.channel_id ASC "
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT channels.*, sub.* FROM channels LEFT JOIN subscriptions AS sub ON channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid WHERE owner_user_id = :ouid"+order, sq.PP{
|
||||
"ouid": userid,
|
||||
"subuid": subUserID,
|
||||
})
|
||||
@@ -154,7 +154,9 @@ func (db *Database) ListChannelsBySubscriber(ctx TxContext, userid models.UserID
|
||||
confCond = " AND sub.confirmed = 0"
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT channels.*, sub.* FROM channels LEFT JOIN subscriptions AS sub on channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid WHERE sub.subscription_id IS NOT NULL "+confCond, sq.PP{
|
||||
order := " ORDER BY channels.timestamp_created ASC, channels.channel_id ASC "
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT channels.*, sub.* FROM channels LEFT JOIN subscriptions AS sub on channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid WHERE sub.subscription_id IS NOT NULL "+confCond+order, sq.PP{
|
||||
"subuid": userid,
|
||||
})
|
||||
if err != nil {
|
||||
@@ -182,7 +184,9 @@ func (db *Database) ListChannelsByAccess(ctx TxContext, userid models.UserID, co
|
||||
confCond = "OR (sub.subscription_id IS NOT NULL AND sub.confirmed = 0)"
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT channels.*, sub.* FROM channels LEFT JOIN subscriptions AS sub on channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid WHERE owner_user_id = :ouid "+confCond, sq.PP{
|
||||
order := " ORDER BY channels.timestamp_created ASC, channels.channel_id ASC "
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT channels.*, sub.* FROM channels LEFT JOIN subscriptions AS sub on channels.channel_id = sub.channel_id AND sub.subscriber_user_id = :subuid WHERE owner_user_id = :ouid "+confCond+order, sq.PP{
|
||||
"ouid": userid,
|
||||
"subuid": userid,
|
||||
})
|
||||
|
@@ -15,7 +15,10 @@ func (db *Database) CreateClient(ctx TxContext, userid models.UserID, ctype mode
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
res, err := tx.Exec(ctx, "INSERT INTO clients (user_id, type, fcm_token, timestamp_created, agent_model, agent_version) VALUES (:uid, :typ, :fcm, :ts, :am, :av)", sq.PP{
|
||||
clientid := models.NewClientID()
|
||||
|
||||
_, err = tx.Exec(ctx, "INSERT INTO clients (client_id, user_id, type, fcm_token, timestamp_created, agent_model, agent_version) VALUES (:cid, :uid, :typ, :fcm, :ts, :am, :av)", sq.PP{
|
||||
"cid": clientid,
|
||||
"uid": userid,
|
||||
"typ": string(ctype),
|
||||
"fcm": fcmToken,
|
||||
@@ -27,13 +30,8 @@ func (db *Database) CreateClient(ctx TxContext, userid models.UserID, ctype mode
|
||||
return models.Client{}, err
|
||||
}
|
||||
|
||||
liid, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return models.Client{}, err
|
||||
}
|
||||
|
||||
return models.Client{
|
||||
ClientID: models.ClientID(liid),
|
||||
ClientID: clientid,
|
||||
UserID: userid,
|
||||
Type: ctype,
|
||||
FCMToken: langext.Ptr(fcmToken),
|
||||
@@ -63,7 +61,7 @@ func (db *Database) ListClients(ctx TxContext, userid models.UserID) ([]models.C
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM clients WHERE user_id = :uid", sq.PP{"uid": userid})
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM clients WHERE user_id = :uid ORDER BY clients.timestamp_created DESC, clients.client_id ASC", sq.PP{"uid": userid})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
100
scnserver/db/impl/primary/compat.go
Normal file
100
scnserver/db/impl/primary/compat.go
Normal file
@@ -0,0 +1,100 @@
|
||||
package primary
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"errors"
|
||||
"gogs.mikescher.com/BlackForestBytes/goext/sq"
|
||||
)
|
||||
|
||||
func (db *Database) CreateCompatID(ctx TxContext, idtype string, newid string) (int64, error) {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT COALESCE(MAX(old), 0) FROM compat_ids", sq.PP{})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
if !rows.Next() {
|
||||
return 0, errors.New("failed to query MAX(old)")
|
||||
}
|
||||
|
||||
var oldid int64
|
||||
err = rows.Scan(&oldid)
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
oldid++
|
||||
|
||||
_, err = tx.Exec(ctx, "INSERT INTO compat_ids (old, new, type) VALUES (:old, :new, :typ)", sq.PP{
|
||||
"old": oldid,
|
||||
"new": newid,
|
||||
"typ": idtype,
|
||||
})
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
|
||||
return oldid, nil
|
||||
}
|
||||
|
||||
func (db *Database) ConvertCompatID(ctx TxContext, oldid int64, idtype string) (*string, error) {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT new FROM compat_ids WHERE old = :old AND type = :typ", sq.PP{
|
||||
"old": oldid,
|
||||
"typ": idtype,
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if !rows.Next() {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var newid string
|
||||
err = rows.Scan(&newid)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &newid, nil
|
||||
}
|
||||
|
||||
func (db *Database) ConvertToCompatID(ctx TxContext, newid string) (*int64, *string, error) {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT old, type FROM compat_ids WHERE new = :new", sq.PP{"new": newid})
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
if !rows.Next() {
|
||||
return nil, nil, nil
|
||||
}
|
||||
|
||||
var oldid int64
|
||||
var idtype string
|
||||
err = rows.Scan(&oldid, &idtype)
|
||||
if err == sql.ErrNoRows {
|
||||
return nil, nil, nil
|
||||
}
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return &oldid, &idtype, nil
|
||||
}
|
@@ -24,7 +24,7 @@ type Database struct {
|
||||
func NewPrimaryDatabase(cfg server.Config) (*Database, error) {
|
||||
conf := cfg.DBMain
|
||||
|
||||
url := fmt.Sprintf("file:%s?_journal=%s&_timeout=%d&_fk=%s", conf.File, conf.Journal, conf.Timeout.Milliseconds(), langext.FormatBool(conf.CheckForeignKeys, "true", "false"))
|
||||
url := fmt.Sprintf("file:%s?_journal=%s&_timeout=%d&_fk=%s&_busy_timeout=%d", conf.File, conf.Journal, conf.Timeout.Milliseconds(), langext.FormatBool(conf.CheckForeignKeys, "true", "false"), conf.BusyTimeout.Milliseconds())
|
||||
|
||||
xdb, err := sqlx.Open("sqlite3", url)
|
||||
if err != nil {
|
||||
|
@@ -17,8 +17,11 @@ func (db *Database) CreateRetryDelivery(ctx TxContext, client models.Client, msg
|
||||
now := time.Now().UTC()
|
||||
next := scn.NextDeliveryTimestamp(now)
|
||||
|
||||
res, err := tx.Exec(ctx, "INSERT INTO deliveries (scn_message_id, receiver_user_id, receiver_client_id, timestamp_created, timestamp_finalized, status, fcm_message_id, next_delivery) VALUES (:mid, :ruid, :rcid, :tsc, :tsf, :stat, :fcm, :next)", sq.PP{
|
||||
"mid": msg.SCNMessageID,
|
||||
deliveryid := models.NewDeliveryID()
|
||||
|
||||
_, err = tx.Exec(ctx, "INSERT INTO deliveries (delivery_id, message_id, receiver_user_id, receiver_client_id, timestamp_created, timestamp_finalized, status, fcm_message_id, next_delivery) VALUES (:did, :mid, :ruid, :rcid, :tsc, :tsf, :stat, :fcm, :next)", sq.PP{
|
||||
"did": deliveryid,
|
||||
"mid": msg.MessageID,
|
||||
"ruid": client.UserID,
|
||||
"rcid": client.ClientID,
|
||||
"tsc": time2DB(now),
|
||||
@@ -31,14 +34,9 @@ func (db *Database) CreateRetryDelivery(ctx TxContext, client models.Client, msg
|
||||
return models.Delivery{}, err
|
||||
}
|
||||
|
||||
liid, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return models.Delivery{}, err
|
||||
}
|
||||
|
||||
return models.Delivery{
|
||||
DeliveryID: models.DeliveryID(liid),
|
||||
SCNMessageID: msg.SCNMessageID,
|
||||
DeliveryID: deliveryid,
|
||||
MessageID: msg.MessageID,
|
||||
ReceiverUserID: client.UserID,
|
||||
ReceiverClientID: client.ClientID,
|
||||
TimestampCreated: now,
|
||||
@@ -58,8 +56,11 @@ func (db *Database) CreateSuccessDelivery(ctx TxContext, client models.Client, m
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
res, err := tx.Exec(ctx, "INSERT INTO deliveries (scn_message_id, receiver_user_id, receiver_client_id, timestamp_created, timestamp_finalized, status, fcm_message_id, next_delivery) VALUES (:mid, :ruid, :rcid, :tsc, :tsf, :stat, :fcm, :next)", sq.PP{
|
||||
"mid": msg.SCNMessageID,
|
||||
deliveryid := models.NewDeliveryID()
|
||||
|
||||
_, err = tx.Exec(ctx, "INSERT INTO deliveries (delivery_id, message_id, receiver_user_id, receiver_client_id, timestamp_created, timestamp_finalized, status, fcm_message_id, next_delivery) VALUES (:did, :mid, :ruid, :rcid, :tsc, :tsf, :stat, :fcm, :next)", sq.PP{
|
||||
"did": deliveryid,
|
||||
"mid": msg.MessageID,
|
||||
"ruid": client.UserID,
|
||||
"rcid": client.ClientID,
|
||||
"tsc": time2DB(now),
|
||||
@@ -72,14 +73,9 @@ func (db *Database) CreateSuccessDelivery(ctx TxContext, client models.Client, m
|
||||
return models.Delivery{}, err
|
||||
}
|
||||
|
||||
liid, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return models.Delivery{}, err
|
||||
}
|
||||
|
||||
return models.Delivery{
|
||||
DeliveryID: models.DeliveryID(liid),
|
||||
SCNMessageID: msg.SCNMessageID,
|
||||
DeliveryID: deliveryid,
|
||||
MessageID: msg.MessageID,
|
||||
ReceiverUserID: client.UserID,
|
||||
ReceiverClientID: client.ClientID,
|
||||
TimestampCreated: now,
|
||||
@@ -97,7 +93,7 @@ func (db *Database) ListRetrieableDeliveries(ctx TxContext, pageSize int) ([]mod
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM deliveries WHERE status = 'RETRY' AND next_delivery < :next LIMIT :lim", sq.PP{
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM deliveries WHERE status = 'RETRY' AND next_delivery < :next LIMIT :lim ORDER BY next_delivery ASC", sq.PP{
|
||||
"next": time2DB(time.Now()),
|
||||
"lim": pageSize,
|
||||
})
|
||||
@@ -169,15 +165,15 @@ func (db *Database) SetDeliveryRetry(ctx TxContext, delivery models.Delivery) er
|
||||
return nil
|
||||
}
|
||||
|
||||
func (db *Database) CancelPendingDeliveries(ctx TxContext, scnMessageID models.SCNMessageID) error {
|
||||
func (db *Database) CancelPendingDeliveries(ctx TxContext, messageID models.MessageID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET status = 'FAILED', next_delivery = NULL, timestamp_finalized = :ts WHERE scn_message_id = :mid AND status = 'RETRY'", sq.PP{
|
||||
_, err = tx.Exec(ctx, "UPDATE deliveries SET status = 'FAILED', next_delivery = NULL, timestamp_finalized = :ts WHERE message_id = :mid AND status = 'RETRY'", sq.PP{
|
||||
"ts": time.Now(),
|
||||
"mid": scnMessageID,
|
||||
"mid": messageID,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
|
@@ -30,7 +30,7 @@ func (db *Database) GetMessageByUserMessageID(ctx TxContext, usrMsgId string) (*
|
||||
return &msg, nil
|
||||
}
|
||||
|
||||
func (db *Database) GetMessage(ctx TxContext, scnMessageID models.SCNMessageID, allowDeleted bool) (models.Message, error) {
|
||||
func (db *Database) GetMessage(ctx TxContext, scnMessageID models.MessageID, allowDeleted bool) (models.Message, error) {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return models.Message{}, err
|
||||
@@ -38,9 +38,9 @@ func (db *Database) GetMessage(ctx TxContext, scnMessageID models.SCNMessageID,
|
||||
|
||||
var sqlcmd string
|
||||
if allowDeleted {
|
||||
sqlcmd = "SELECT * FROM messages WHERE scn_message_id = :mid LIMIT 1"
|
||||
sqlcmd = "SELECT * FROM messages WHERE message_id = :mid LIMIT 1"
|
||||
} else {
|
||||
sqlcmd = "SELECT * FROM messages WHERE scn_message_id = :mid AND deleted=0 LIMIT 1"
|
||||
sqlcmd = "SELECT * FROM messages WHERE message_id = :mid AND deleted=0 LIMIT 1"
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, sqlcmd, sq.PP{"mid": scnMessageID})
|
||||
@@ -64,7 +64,10 @@ func (db *Database) CreateMessage(ctx TxContext, senderUserID models.UserID, cha
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
res, err := tx.Exec(ctx, "INSERT INTO messages (sender_user_id, owner_user_id, channel_internal_name, channel_id, timestamp_real, timestamp_client, title, content, priority, usr_message_id, sender_ip, sender_name) VALUES (:suid, :ouid, :cnam, :cid, :tsr, :tsc, :tit, :cnt, :prio, :umid, :ip, :snam)", sq.PP{
|
||||
messageid := models.NewMessageID()
|
||||
|
||||
_, err = tx.Exec(ctx, "INSERT INTO messages (message_id, sender_user_id, owner_user_id, channel_internal_name, channel_id, timestamp_real, timestamp_client, title, content, priority, usr_message_id, sender_ip, sender_name) VALUES (:mid, :suid, :ouid, :cnam, :cid, :tsr, :tsc, :tit, :cnt, :prio, :umid, :ip, :snam)", sq.PP{
|
||||
"mid": messageid,
|
||||
"suid": senderUserID,
|
||||
"ouid": channel.OwnerUserID,
|
||||
"cnam": channel.InternalName,
|
||||
@@ -82,13 +85,8 @@ func (db *Database) CreateMessage(ctx TxContext, senderUserID models.UserID, cha
|
||||
return models.Message{}, err
|
||||
}
|
||||
|
||||
liid, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return models.Message{}, err
|
||||
}
|
||||
|
||||
return models.Message{
|
||||
SCNMessageID: models.SCNMessageID(liid),
|
||||
MessageID: messageid,
|
||||
SenderUserID: senderUserID,
|
||||
OwnerUserID: channel.OwnerUserID,
|
||||
ChannelInternalName: channel.InternalName,
|
||||
@@ -104,13 +102,13 @@ func (db *Database) CreateMessage(ctx TxContext, senderUserID models.UserID, cha
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (db *Database) DeleteMessage(ctx TxContext, scnMessageID models.SCNMessageID) error {
|
||||
func (db *Database) DeleteMessage(ctx TxContext, messageID models.MessageID) error {
|
||||
tx, err := ctx.GetOrCreateTransaction(db)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
_, err = tx.Exec(ctx, "UPDATE messages SET deleted=1 WHERE scn_message_id = :mid AND deleted=0", sq.PP{"mid": scnMessageID})
|
||||
_, err = tx.Exec(ctx, "UPDATE messages SET deleted=1 WHERE message_id = :mid AND deleted=0", sq.PP{"mid": messageID})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -130,12 +128,12 @@ func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pag
|
||||
|
||||
pageCond := "1=1"
|
||||
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 message_id < :tokid )"
|
||||
}
|
||||
|
||||
filterCond, filterJoin, prepParams, err := filter.SQL()
|
||||
|
||||
orderClause := "ORDER BY COALESCE(timestamp_client, timestamp_real) DESC LIMIT :lim"
|
||||
orderClause := "ORDER BY COALESCE(timestamp_client, timestamp_real) DESC, message_id DESC LIMIT :lim"
|
||||
|
||||
sqlQuery := "SELECT " + "messages.*" + " FROM messages " + filterJoin + " WHERE ( " + pageCond + " ) AND ( " + filterCond + " ) " + orderClause
|
||||
|
||||
@@ -156,7 +154,7 @@ func (db *Database) ListMessages(ctx TxContext, filter models.MessageFilter, pag
|
||||
if len(data) <= pageSize {
|
||||
return data, cursortoken.End(), nil
|
||||
} else {
|
||||
outToken := cursortoken.Normal(data[pageSize-1].Timestamp(), data[pageSize-1].SCNMessageID.IntID(), "DESC", filter.Hash())
|
||||
outToken := cursortoken.Normal(data[pageSize-1].Timestamp(), data[pageSize-1].MessageID.String(), "DESC", filter.Hash())
|
||||
return data[0:pageSize], outToken, nil
|
||||
}
|
||||
}
|
||||
|
@@ -20,7 +20,7 @@ CREATE TABLE `users`
|
||||
DROP TABLE IF EXISTS `messages`;
|
||||
CREATE TABLE `messages`
|
||||
(
|
||||
`scn_message_id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`message_id` INT(11) NOT NULL AUTO_INCREMENT,
|
||||
`sender_user_id` INT(11) NOT NULL,
|
||||
|
||||
`timestamp_real` DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
@@ -34,5 +34,5 @@ CREATE TABLE `messages`
|
||||
`fcm_message_id` VARCHAR(256) NULL,
|
||||
`usr_message_id` VARCHAR(256) NULL,
|
||||
|
||||
PRIMARY KEY (`scn_message_id`)
|
||||
PRIMARY KEY (`message_id`)
|
||||
);
|
@@ -18,7 +18,7 @@ CREATE TABLE `users`
|
||||
|
||||
CREATE TABLE `messages`
|
||||
(
|
||||
`scn_message_id` INTEGER AUTO_INCREMENT,
|
||||
`message_id` INTEGER AUTO_INCREMENT,
|
||||
`sender_user_id` INTEGER NOT NULL,
|
||||
|
||||
`timestamp_real` TEXT NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||
@@ -32,7 +32,7 @@ CREATE TABLE `messages`
|
||||
`fcm_message_id` TEXT NULL,
|
||||
`usr_message_id` TEXT NULL,
|
||||
|
||||
PRIMARY KEY (`scn_message_id`)
|
||||
PRIMARY KEY (`message_id`)
|
||||
);
|
||||
|
||||
CREATE TABLE `meta`
|
||||
|
@@ -1,6 +1,6 @@
|
||||
CREATE TABLE users
|
||||
(
|
||||
user_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
user_id TEXT NOT NULL,
|
||||
|
||||
username TEXT NULL DEFAULT NULL,
|
||||
|
||||
@@ -18,23 +18,27 @@ CREATE TABLE users
|
||||
quota_used_day TEXT NULL DEFAULT NULL,
|
||||
|
||||
is_pro INTEGER CHECK(is_pro IN (0, 1)) NOT NULL DEFAULT 0,
|
||||
pro_token TEXT NULL DEFAULT NULL
|
||||
pro_token TEXT NULL DEFAULT NULL,
|
||||
|
||||
PRIMARY KEY (user_id)
|
||||
) STRICT;
|
||||
CREATE UNIQUE INDEX "idx_users_protoken" ON users (pro_token) WHERE pro_token IS NOT NULL;
|
||||
|
||||
|
||||
CREATE TABLE clients
|
||||
(
|
||||
client_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
client_id TEXT NOT NULL,
|
||||
|
||||
user_id INTEGER NOT NULL,
|
||||
user_id TEXT NOT NULL,
|
||||
type TEXT CHECK(type IN ('ANDROID', 'IOS')) NOT NULL,
|
||||
fcm_token TEXT NULL,
|
||||
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
|
||||
agent_model TEXT NOT NULL,
|
||||
agent_version TEXT NOT NULL
|
||||
agent_version TEXT NOT NULL,
|
||||
|
||||
PRIMARY KEY (client_id)
|
||||
) STRICT;
|
||||
CREATE INDEX "idx_clients_userid" ON clients (user_id);
|
||||
CREATE UNIQUE INDEX "idx_clients_fcmtoken" ON clients (fcm_token);
|
||||
@@ -42,9 +46,9 @@ CREATE UNIQUE INDEX "idx_clients_fcmtoken" ON clients (fcm_token);
|
||||
|
||||
CREATE TABLE channels
|
||||
(
|
||||
channel_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
channel_id TEXT NOT NULL,
|
||||
|
||||
owner_user_id INTEGER NOT NULL,
|
||||
owner_user_id TEXT NOT NULL,
|
||||
|
||||
internal_name TEXT NOT NULL,
|
||||
display_name TEXT NOT NULL,
|
||||
@@ -56,22 +60,26 @@ CREATE TABLE channels
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
timestamp_lastsent INTEGER NULL DEFAULT NULL,
|
||||
|
||||
messages_sent INTEGER NOT NULL DEFAULT '0'
|
||||
messages_sent INTEGER NOT NULL DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (channel_id)
|
||||
) STRICT;
|
||||
CREATE UNIQUE INDEX "idx_channels_identity" ON channels (owner_user_id, internal_name);
|
||||
|
||||
CREATE TABLE subscriptions
|
||||
(
|
||||
subscription_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
subscription_id TEXT NOT NULL,
|
||||
|
||||
subscriber_user_id INTEGER NOT NULL,
|
||||
channel_owner_user_id INTEGER NOT NULL,
|
||||
subscriber_user_id TEXT NOT NULL,
|
||||
channel_owner_user_id TEXT NOT NULL,
|
||||
channel_internal_name TEXT NOT NULL,
|
||||
channel_id INTEGER NOT NULL,
|
||||
channel_id TEXT NOT NULL,
|
||||
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
|
||||
confirmed INTEGER CHECK(confirmed IN (0, 1)) NOT NULL
|
||||
confirmed INTEGER CHECK(confirmed IN (0, 1)) NOT NULL,
|
||||
|
||||
PRIMARY KEY (subscription_id)
|
||||
) STRICT;
|
||||
CREATE UNIQUE INDEX "idx_subscriptions_ref" ON subscriptions (subscriber_user_id, channel_owner_user_id, channel_internal_name);
|
||||
CREATE INDEX "idx_subscriptions_chan" ON subscriptions (channel_id);
|
||||
@@ -83,11 +91,11 @@ CREATE INDEX "idx_subscriptions_conf" ON subscriptions (confirmed);
|
||||
|
||||
CREATE TABLE messages
|
||||
(
|
||||
scn_message_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
sender_user_id INTEGER NOT NULL,
|
||||
owner_user_id INTEGER NOT NULL,
|
||||
message_id TEXT NOT NULL,
|
||||
sender_user_id TEXT NOT NULL,
|
||||
owner_user_id TEXT NOT NULL,
|
||||
channel_internal_name TEXT NOT NULL,
|
||||
channel_id INTEGER NOT NULL,
|
||||
channel_id TEXT NOT NULL,
|
||||
sender_ip TEXT NOT NULL,
|
||||
sender_name TEXT NULL,
|
||||
|
||||
@@ -99,7 +107,9 @@ CREATE TABLE messages
|
||||
priority INTEGER CHECK(priority IN (0, 1, 2)) NOT NULL,
|
||||
usr_message_id TEXT NULL,
|
||||
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0'
|
||||
deleted INTEGER CHECK(deleted IN (0, 1)) NOT NULL DEFAULT '0',
|
||||
|
||||
PRIMARY KEY (message_id)
|
||||
) STRICT;
|
||||
CREATE INDEX "idx_messages_owner_channel" ON messages (owner_user_id, channel_internal_name COLLATE BINARY);
|
||||
CREATE INDEX "idx_messages_owner_channel_nc" ON messages (owner_user_id, channel_internal_name COLLATE NOCASE);
|
||||
@@ -123,31 +133,30 @@ CREATE VIRTUAL TABLE messages_fts USING fts5
|
||||
|
||||
tokenize = unicode61,
|
||||
content = 'messages',
|
||||
content_rowid = 'scn_message_id'
|
||||
content_rowid = 'rowid'
|
||||
);
|
||||
|
||||
CREATE TRIGGER fts_insert AFTER INSERT ON messages BEGIN
|
||||
INSERT INTO messages_fts (rowid, channel_internal_name, sender_name, title, content) VALUES (new.scn_message_id, new.channel_internal_name, new.sender_name, new.title, new.content);
|
||||
INSERT INTO messages_fts (rowid, channel_internal_name, sender_name, title, content) VALUES (new.rowid, new.channel_internal_name, new.sender_name, new.title, new.content);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER fts_update AFTER UPDATE ON messages BEGIN
|
||||
INSERT INTO messages_fts (messages_fts, rowid, channel_internal_name, sender_name, title, content) VALUES ('delete', old.scn_message_id, old.channel_internal_name, old.sender_name, old.title, old.content);
|
||||
INSERT INTO messages_fts ( rowid, channel_internal_name, sender_name, title, content) VALUES ( new.scn_message_id, new.channel_internal_name, new.sender_name, new.title, new.content);
|
||||
INSERT INTO messages_fts (messages_fts, rowid, channel_internal_name, sender_name, title, content) VALUES ('delete', old.rowid, old.channel_internal_name, old.sender_name, old.title, old.content);
|
||||
INSERT INTO messages_fts ( rowid, channel_internal_name, sender_name, title, content) VALUES ( new.rowid, new.channel_internal_name, new.sender_name, new.title, new.content);
|
||||
END;
|
||||
|
||||
CREATE TRIGGER fts_delete AFTER DELETE ON messages BEGIN
|
||||
INSERT INTO messages_fts (messages_fts, rowid, channel_internal_name, sender_name, title, content) VALUES ('delete', old.scn_message_id, old.channel_internal_name, old.sender_name, old.title, old.content);
|
||||
INSERT INTO messages_fts (messages_fts, rowid, channel_internal_name, sender_name, title, content) VALUES ('delete', old.rowid, old.channel_internal_name, old.sender_name, old.title, old.content);
|
||||
END;
|
||||
|
||||
|
||||
|
||||
CREATE TABLE deliveries
|
||||
(
|
||||
delivery_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
delivery_id TEXT NOT NULL,
|
||||
|
||||
scn_message_id INTEGER NOT NULL,
|
||||
receiver_user_id INTEGER NOT NULL,
|
||||
receiver_client_id INTEGER NOT NULL,
|
||||
message_id TEXT NOT NULL,
|
||||
receiver_user_id TEXT NOT NULL,
|
||||
receiver_client_id TEXT NOT NULL,
|
||||
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
timestamp_finalized INTEGER NULL,
|
||||
@@ -157,9 +166,21 @@ CREATE TABLE deliveries
|
||||
retry_count INTEGER NOT NULL DEFAULT 0,
|
||||
next_delivery INTEGER NULL DEFAULT NULL,
|
||||
|
||||
fcm_message_id TEXT NULL
|
||||
fcm_message_id TEXT NULL,
|
||||
|
||||
PRIMARY KEY (delivery_id)
|
||||
) STRICT;
|
||||
CREATE INDEX "idx_deliveries_receiver" ON deliveries (scn_message_id, receiver_client_id);
|
||||
CREATE INDEX "idx_deliveries_receiver" ON deliveries (message_id, receiver_client_id);
|
||||
|
||||
|
||||
CREATE TABLE compat_ids
|
||||
(
|
||||
old INTEGER NOT NULL,
|
||||
new TEXT NOT NULL,
|
||||
type TEXT NOT NULL
|
||||
) STRICT;
|
||||
CREATE UNIQUE INDEX "idx_compatids_new" ON compat_ids (new);
|
||||
CREATE UNIQUE INDEX "idx_compatids_old" ON compat_ids (old, type);
|
||||
|
||||
|
||||
CREATE TABLE `meta`
|
||||
|
@@ -15,7 +15,10 @@ func (db *Database) CreateSubscription(ctx TxContext, subscriberUID models.UserI
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
res, err := tx.Exec(ctx, "INSERT INTO subscriptions (subscriber_user_id, channel_owner_user_id, channel_internal_name, channel_id, timestamp_created, confirmed) VALUES (:suid, :ouid, :cnam, :cid, :ts, :conf)", sq.PP{
|
||||
subscriptionid := models.NewSubscriptionID()
|
||||
|
||||
_, err = tx.Exec(ctx, "INSERT INTO subscriptions (subscription_id, subscriber_user_id, channel_owner_user_id, channel_internal_name, channel_id, timestamp_created, confirmed) VALUES (:sid, :suid, :ouid, :cnam, :cid, :ts, :conf)", sq.PP{
|
||||
"sid": subscriptionid,
|
||||
"suid": subscriberUID,
|
||||
"ouid": channel.OwnerUserID,
|
||||
"cnam": channel.InternalName,
|
||||
@@ -27,13 +30,8 @@ func (db *Database) CreateSubscription(ctx TxContext, subscriberUID models.UserI
|
||||
return models.Subscription{}, err
|
||||
}
|
||||
|
||||
liid, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return models.Subscription{}, err
|
||||
}
|
||||
|
||||
return models.Subscription{
|
||||
SubscriptionID: models.SubscriptionID(liid),
|
||||
SubscriptionID: subscriptionid,
|
||||
SubscriberUserID: subscriberUID,
|
||||
ChannelOwnerUserID: channel.OwnerUserID,
|
||||
ChannelID: channel.ChannelID,
|
||||
@@ -49,7 +47,9 @@ func (db *Database) ListSubscriptionsByChannel(ctx TxContext, channelID models.C
|
||||
return nil, err
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM subscriptions WHERE channel_id = :cid", sq.PP{"cid": channelID})
|
||||
order := " ORDER BY subscriptions.timestamp_created DESC, subscriptions.subscription_id DESC "
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM subscriptions WHERE channel_id = :cid"+order, sq.PP{"cid": channelID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -75,7 +75,9 @@ func (db *Database) ListSubscriptionsByChannelOwner(ctx TxContext, ownerUserID m
|
||||
cond = " AND confirmed = 0"
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM subscriptions WHERE channel_owner_user_id = :ouid"+cond, sq.PP{"ouid": ownerUserID})
|
||||
order := " ORDER BY subscriptions.timestamp_created DESC, subscriptions.subscription_id DESC "
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM subscriptions WHERE channel_owner_user_id = :ouid"+cond+order, sq.PP{"ouid": ownerUserID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
@@ -101,7 +103,9 @@ func (db *Database) ListSubscriptionsBySubscriber(ctx TxContext, subscriberUserI
|
||||
cond = " AND confirmed = 0"
|
||||
}
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM subscriptions WHERE subscriber_user_id = :suid"+cond, sq.PP{"suid": subscriberUserID})
|
||||
order := " ORDER BY subscriptions.timestamp_created DESC, subscriptions.subscription_id DESC "
|
||||
|
||||
rows, err := tx.Query(ctx, "SELECT * FROM subscriptions WHERE subscriber_user_id = :suid"+cond+order, sq.PP{"suid": subscriberUserID})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
@@ -16,7 +16,10 @@ func (db *Database) CreateUser(ctx TxContext, readKey string, sendKey string, ad
|
||||
|
||||
now := time.Now().UTC()
|
||||
|
||||
res, err := tx.Exec(ctx, "INSERT INTO users (username, read_key, send_key, admin_key, is_pro, pro_token, timestamp_created) VALUES (:un, :rk, :sk, :ak, :pro, :tok, :ts)", sq.PP{
|
||||
userid := models.NewUserID()
|
||||
|
||||
_, err = tx.Exec(ctx, "INSERT INTO users (user_id, username, read_key, send_key, admin_key, is_pro, pro_token, timestamp_created) VALUES (:uid, :un, :rk, :sk, :ak, :pro, :tok, :ts)", sq.PP{
|
||||
"uid": userid,
|
||||
"un": username,
|
||||
"rk": readKey,
|
||||
"sk": sendKey,
|
||||
@@ -29,13 +32,8 @@ func (db *Database) CreateUser(ctx TxContext, readKey string, sendKey string, ad
|
||||
return models.User{}, err
|
||||
}
|
||||
|
||||
liid, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return models.User{}, err
|
||||
}
|
||||
|
||||
return models.User{
|
||||
UserID: models.UserID(liid),
|
||||
UserID: userid,
|
||||
Username: username,
|
||||
ReadKey: readKey,
|
||||
SendKey: sendKey,
|
||||
|
@@ -24,7 +24,7 @@ type Database struct {
|
||||
func NewRequestsDatabase(cfg server.Config) (*Database, error) {
|
||||
conf := cfg.DBRequests
|
||||
|
||||
url := fmt.Sprintf("file:%s?_journal=%s&_timeout=%d&_fk=%s", conf.File, conf.Journal, conf.Timeout.Milliseconds(), langext.FormatBool(conf.CheckForeignKeys, "true", "false"))
|
||||
url := fmt.Sprintf("file:%s?_journal=%s&_timeout=%d&_fk=%s&_busy_timeout=%d", conf.File, conf.Journal, conf.Timeout.Milliseconds(), langext.FormatBool(conf.CheckForeignKeys, "true", "false"), conf.BusyTimeout.Milliseconds())
|
||||
|
||||
xdb, err := sqlx.Open("sqlite3", url)
|
||||
if err != nil {
|
||||
|
@@ -7,11 +7,12 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
func (db *Database) InsertRequestLog(ctx context.Context, data models.RequestLogDB) (models.RequestLogDB, error) {
|
||||
func (db *Database) InsertRequestLog(ctx context.Context, requestid models.RequestID, data models.RequestLogDB) (models.RequestLogDB, error) {
|
||||
|
||||
now := time.Now()
|
||||
|
||||
res, err := db.db.Exec(ctx, "INSERT INTO requests (method, uri, user_agent, authentication, request_body, request_body_size, request_content_type, remote_ip, userid, permissions, response_statuscode, response_body_size, response_body, response_content_type, retry_count, panicked, panic_str, processing_time, timestamp_created, timestamp_start, timestamp_finish) VALUES (:method, :uri, :user_agent, :authentication, :request_body, :request_body_size, :request_content_type, :remote_ip, :userid, :permissions, :response_statuscode, :response_body_size, :response_body, :response_content_type, :retry_count, :panicked, :panic_str, :processing_time, :timestamp_created, :timestamp_start, :timestamp_finish)", sq.PP{
|
||||
_, err := db.db.Exec(ctx, "INSERT INTO requests (request_id, method, uri, user_agent, authentication, request_body, request_body_size, request_content_type, remote_ip, userid, permissions, response_statuscode, response_body_size, response_body, response_content_type, retry_count, panicked, panic_str, processing_time, timestamp_created, timestamp_start, timestamp_finish) VALUES (:request_id, :method, :uri, :user_agent, :authentication, :request_body, :request_body_size, :request_content_type, :remote_ip, :userid, :permissions, :response_statuscode, :response_body_size, :response_body, :response_content_type, :retry_count, :panicked, :panic_str, :processing_time, :timestamp_created, :timestamp_start, :timestamp_finish)", sq.PP{
|
||||
"request_id": requestid,
|
||||
"method": data.Method,
|
||||
"uri": data.URI,
|
||||
"user_agent": data.UserAgent,
|
||||
@@ -38,13 +39,8 @@ func (db *Database) InsertRequestLog(ctx context.Context, data models.RequestLog
|
||||
return models.RequestLogDB{}, err
|
||||
}
|
||||
|
||||
liid, err := res.LastInsertId()
|
||||
if err != nil {
|
||||
return models.RequestLogDB{}, err
|
||||
}
|
||||
|
||||
return models.RequestLogDB{
|
||||
RequestID: models.RequestID(liid),
|
||||
RequestID: requestid,
|
||||
Method: data.Method,
|
||||
URI: data.URI,
|
||||
UserAgent: data.UserAgent,
|
||||
|
@@ -1,7 +1,7 @@
|
||||
|
||||
CREATE TABLE `requests`
|
||||
(
|
||||
request_id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
request_id TEXT NOT NULL,
|
||||
|
||||
method TEXT NOT NULL,
|
||||
uri TEXT NOT NULL,
|
||||
@@ -15,8 +15,8 @@ CREATE TABLE `requests`
|
||||
userid TEXT NULL,
|
||||
permissions TEXT NULL,
|
||||
|
||||
response_statuscode INTEGER NOT NULL,
|
||||
response_body_size INTEGER NOT NULL,
|
||||
response_statuscode INTEGER NULL,
|
||||
response_body_size INTEGER NULL,
|
||||
response_body TEXT NULL,
|
||||
response_content_type TEXT NOT NULL,
|
||||
processing_time INTEGER NOT NULL,
|
||||
@@ -26,8 +26,9 @@ CREATE TABLE `requests`
|
||||
|
||||
timestamp_created INTEGER NOT NULL,
|
||||
timestamp_start INTEGER NOT NULL,
|
||||
timestamp_finish INTEGER NOT NULL
|
||||
timestamp_finish INTEGER NOT NULL,
|
||||
|
||||
PRIMARY KEY (request_id)
|
||||
) STRICT;
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user