2026-02-18 20:22:44 -05:00
package message
import (
"time"
2026-03-10 22:17:40 -04:00
"heckel.io/ntfy/v2/db"
2026-02-18 20:22:44 -05:00
)
// PostgreSQL runtime query constants
const (
2026-02-21 21:29:29 -05:00
postgresInsertMessageQuery = `
2026-02-18 20:22:44 -05:00
INSERT INTO message ( mid , sequence_id , time , event , expires , topic , message , title , priority , tags , click , icon , actions , attachment_name , attachment_type , attachment_size , attachment_expires , attachment_url , attachment_deleted , sender , user_id , content_type , encoding , published )
VALUES ( $ 1 , $ 2 , $ 3 , $ 4 , $ 5 , $ 6 , $ 7 , $ 8 , $ 9 , $ 10 , $ 11 , $ 12 , $ 13 , $ 14 , $ 15 , $ 16 , $ 17 , $ 18 , $ 19 , $ 20 , $ 21 , $ 22 , $ 23 , $ 24 )
`
2026-02-21 21:29:29 -05:00
postgresSelectScheduledMessageIDsBySeqIDQuery = ` SELECT mid FROM message WHERE topic = $1 AND sequence_id = $2 AND published = FALSE `
postgresDeleteScheduledBySequenceIDQuery = ` DELETE FROM message WHERE topic = $1 AND sequence_id = $2 AND published = FALSE `
postgresUpdateMessagesForTopicExpiryQuery = ` UPDATE message SET expires = $1 WHERE topic = $2 `
postgresSelectMessagesByIDQuery = `
2026-02-18 20:22:44 -05:00
SELECT mid , sequence_id , time , event , expires , topic , message , title , priority , tags , click , icon , actions , attachment_name , attachment_type , attachment_size , attachment_expires , attachment_url , sender , user_id , content_type , encoding
FROM message
WHERE mid = $ 1
`
2026-02-21 21:29:29 -05:00
postgresSelectMessagesSinceTimeQuery = `
2026-02-18 20:22:44 -05:00
SELECT mid , sequence_id , time , event , expires , topic , message , title , priority , tags , click , icon , actions , attachment_name , attachment_type , attachment_size , attachment_expires , attachment_url , sender , user_id , content_type , encoding
FROM message
WHERE topic = $ 1 AND time >= $ 2 AND published = TRUE
ORDER BY time , id
`
2026-02-21 21:29:29 -05:00
postgresSelectMessagesSinceTimeIncludeScheduledQuery = `
2026-02-18 20:22:44 -05:00
SELECT mid , sequence_id , time , event , expires , topic , message , title , priority , tags , click , icon , actions , attachment_name , attachment_type , attachment_size , attachment_expires , attachment_url , sender , user_id , content_type , encoding
FROM message
WHERE topic = $ 1 AND time >= $ 2
ORDER BY time , id
`
2026-02-21 21:29:29 -05:00
postgresSelectMessagesSinceIDQuery = `
2026-02-18 20:22:44 -05:00
SELECT mid , sequence_id , time , event , expires , topic , message , title , priority , tags , click , icon , actions , attachment_name , attachment_type , attachment_size , attachment_expires , attachment_url , sender , user_id , content_type , encoding
FROM message
2026-02-22 16:21:27 -05:00
WHERE topic = $ 1
AND id > COALESCE ( ( SELECT id FROM message WHERE mid = $ 2 ) , 0 )
AND published = TRUE
2026-02-18 20:22:44 -05:00
ORDER BY time , id
`
2026-02-21 21:29:29 -05:00
postgresSelectMessagesSinceIDIncludeScheduledQuery = `
2026-02-18 20:22:44 -05:00
SELECT mid , sequence_id , time , event , expires , topic , message , title , priority , tags , click , icon , actions , attachment_name , attachment_type , attachment_size , attachment_expires , attachment_url , sender , user_id , content_type , encoding
FROM message
2026-02-22 16:21:27 -05:00
WHERE topic = $ 1
AND ( id > COALESCE ( ( SELECT id FROM message WHERE mid = $ 2 ) , 0 ) OR published = FALSE )
2026-02-18 20:22:44 -05:00
ORDER BY time , id
`
2026-02-21 21:29:29 -05:00
postgresSelectMessagesLatestQuery = `
2026-02-18 20:22:44 -05:00
SELECT mid , sequence_id , time , event , expires , topic , message , title , priority , tags , click , icon , actions , attachment_name , attachment_type , attachment_size , attachment_expires , attachment_url , sender , user_id , content_type , encoding
FROM message
WHERE topic = $ 1 AND published = TRUE
ORDER BY time DESC , id DESC
LIMIT 1
`
2026-02-21 21:29:29 -05:00
postgresSelectMessagesDueQuery = `
2026-02-18 20:22:44 -05:00
SELECT mid , sequence_id , time , event , expires , topic , message , title , priority , tags , click , icon , actions , attachment_name , attachment_type , attachment_size , attachment_expires , attachment_url , sender , user_id , content_type , encoding
FROM message
WHERE time <= $ 1 AND published = FALSE
ORDER BY time , id
`
2026-02-22 16:21:27 -05:00
postgresUpdateMessagePublishedQuery = ` UPDATE message SET published = TRUE WHERE mid = $1 `
postgresSelectMessagesCountQuery = ` SELECT COUNT(*) FROM message `
postgresSelectTopicsQuery = ` SELECT topic FROM message GROUP BY topic `
2026-02-18 20:22:44 -05:00
2026-03-25 15:28:23 -04:00
postgresDeleteExpiredMessagesQuery = ` DELETE FROM message WHERE mid IN (SELECT mid FROM message WHERE expires <= $1 AND published = TRUE LIMIT $2) `
postgresMarkExpiredAttachmentsDeletedQuery = ` UPDATE message SET attachment_deleted = TRUE WHERE mid IN (SELECT mid FROM message WHERE attachment_expires > 0 AND attachment_expires <= $1 AND attachment_deleted = FALSE LIMIT $2) `
2026-02-21 21:29:29 -05:00
postgresSelectAttachmentsSizeBySenderQuery = ` SELECT COALESCE(SUM(attachment_size), 0) FROM message WHERE user_id = '' AND sender = $1 AND attachment_expires >= $2 `
postgresSelectAttachmentsSizeByUserIDQuery = ` SELECT COALESCE(SUM(attachment_size), 0) FROM message WHERE user_id = $1 AND attachment_expires >= $2 `
2026-03-23 12:44:40 -04:00
postgresSelectAttachmentsWithSizesQuery = ` SELECT mid, attachment_size FROM message WHERE attachment_expires > $1 AND attachment_deleted = FALSE `
2026-02-18 20:22:44 -05:00
2026-03-01 13:47:42 -05:00
postgresSelectStatsQuery = ` SELECT value FROM message_stats WHERE key = 'messages' `
postgresUpdateStatsQuery = ` UPDATE message_stats SET value = $1 WHERE key = 'messages' `
postgresUpdateMessageTimeQuery = ` UPDATE message SET time = $1 WHERE mid = $2 `
2026-02-18 20:22:44 -05:00
)
2026-03-02 12:58:01 -05:00
var postgresQueries = queries {
2026-02-21 21:29:29 -05:00
insertMessage : postgresInsertMessageQuery ,
selectScheduledMessageIDsBySeqID : postgresSelectScheduledMessageIDsBySeqIDQuery ,
deleteScheduledBySequenceID : postgresDeleteScheduledBySequenceIDQuery ,
updateMessagesForTopicExpiry : postgresUpdateMessagesForTopicExpiryQuery ,
selectMessagesByID : postgresSelectMessagesByIDQuery ,
selectMessagesSinceTime : postgresSelectMessagesSinceTimeQuery ,
selectMessagesSinceTimeScheduled : postgresSelectMessagesSinceTimeIncludeScheduledQuery ,
selectMessagesSinceID : postgresSelectMessagesSinceIDQuery ,
selectMessagesSinceIDScheduled : postgresSelectMessagesSinceIDIncludeScheduledQuery ,
selectMessagesLatest : postgresSelectMessagesLatestQuery ,
selectMessagesDue : postgresSelectMessagesDueQuery ,
2026-03-25 15:28:23 -04:00
deleteExpiredMessages : postgresDeleteExpiredMessagesQuery ,
2026-02-21 21:29:29 -05:00
updateMessagePublished : postgresUpdateMessagePublishedQuery ,
selectMessagesCount : postgresSelectMessagesCountQuery ,
selectTopics : postgresSelectTopicsQuery ,
2026-03-25 15:28:23 -04:00
markExpiredAttachmentsDeleted : postgresMarkExpiredAttachmentsDeletedQuery ,
2026-02-21 21:29:29 -05:00
selectAttachmentsSizeBySender : postgresSelectAttachmentsSizeBySenderQuery ,
selectAttachmentsSizeByUserID : postgresSelectAttachmentsSizeByUserIDQuery ,
2026-03-23 12:44:40 -04:00
selectAttachmentsWithSizes : postgresSelectAttachmentsWithSizesQuery ,
2026-02-21 21:29:29 -05:00
selectStats : postgresSelectStatsQuery ,
updateStats : postgresUpdateStatsQuery ,
2026-03-01 13:47:42 -05:00
updateMessageTime : postgresUpdateMessageTimeQuery ,
2026-02-18 20:22:44 -05:00
}
2026-02-19 22:34:53 -05:00
// NewPostgresStore creates a new PostgreSQL-backed message cache store using an existing database connection pool.
2026-03-10 22:17:40 -04:00
func NewPostgresStore ( d * db . DB , batchSize int , batchTimeout time . Duration ) ( * Cache , error ) {
2026-03-11 11:58:40 -04:00
if err := setupPostgres ( d . Primary ( ) ) ; err != nil {
2026-02-18 20:22:44 -05:00
return nil , err
}
2026-03-10 22:17:40 -04:00
return newCache ( d , postgresQueries , nil , batchSize , batchTimeout , false ) , nil
2026-02-18 20:22:44 -05:00
}