chore: refresh gramsrv public release
This commit is contained in:
parent
75cebe8dbf
commit
70b6820474
1274 changed files with 378751 additions and 59919 deletions
97
internal/store/postgres/queries/bot.sql
Normal file
97
internal/store/postgres/queries/bot.sql
Normal file
|
|
@ -0,0 +1,97 @@
|
|||
-- name: InsertBotUser :one
|
||||
INSERT INTO users (access_hash, phone, first_name, last_name, username, country_code, is_bot, bot_info_version)
|
||||
VALUES ($1, '', $2, '', $3, '', TRUE, 1)
|
||||
RETURNING *;
|
||||
|
||||
-- name: InsertBot :exec
|
||||
INSERT INTO bots (bot_user_id, owner_user_id, token_secret)
|
||||
VALUES ($1, $2, $3);
|
||||
|
||||
-- name: GetBot :one
|
||||
SELECT * FROM bots WHERE bot_user_id = $1;
|
||||
|
||||
-- name: ListBotsByOwner :many
|
||||
-- 排除 self-owner 种子行(内置 BotFather 自有),与 memory 实现一致:/mybots 与
|
||||
-- 创建上限只统计用户经 /newbot 创建的 bot。
|
||||
SELECT * FROM bots WHERE owner_user_id = $1 AND bot_user_id <> owner_user_id ORDER BY bot_user_id;
|
||||
|
||||
-- name: CountBotsByOwner :one
|
||||
SELECT COUNT(*) FROM bots WHERE owner_user_id = $1 AND bot_user_id <> owner_user_id;
|
||||
|
||||
-- name: UpdateBotTokenSecret :execrows
|
||||
UPDATE bots SET token_secret = $2, updated_at = now() WHERE bot_user_id = $1;
|
||||
|
||||
-- name: UpdateBotCommandsRow :execrows
|
||||
UPDATE bots SET commands = $2, updated_at = now() WHERE bot_user_id = $1;
|
||||
|
||||
-- name: UpdateBotDescriptionRow :execrows
|
||||
UPDATE bots SET description = $2, updated_at = now() WHERE bot_user_id = $1;
|
||||
|
||||
-- name: UpdateBotMenuButtonRow :execrows
|
||||
UPDATE bots
|
||||
SET menu_button_type = $2, menu_button_text = $3, menu_button_url = $4, updated_at = now()
|
||||
WHERE bot_user_id = $1;
|
||||
|
||||
-- name: SetBotInlinePlaceholderRow :execrows
|
||||
UPDATE bots SET inline_placeholder = $2, updated_at = now() WHERE bot_user_id = $1;
|
||||
|
||||
-- name: SetBotInlineGeoRow :execrows
|
||||
UPDATE bots SET bot_inline_geo = $2, updated_at = now() WHERE bot_user_id = $1;
|
||||
|
||||
-- name: SetBotNochatsRow :execrows
|
||||
UPDATE bots SET bot_nochats = $2, updated_at = now() WHERE bot_user_id = $1;
|
||||
|
||||
-- name: SetBotChatHistoryRow :execrows
|
||||
UPDATE bots SET bot_chat_history = $2, updated_at = now() WHERE bot_user_id = $1;
|
||||
|
||||
-- name: CanBotSendMessage :one
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM bot_user_permissions
|
||||
WHERE bot_user_id = $1 AND user_id = $2
|
||||
);
|
||||
|
||||
-- name: AllowBotSendMessage :one
|
||||
WITH inserted AS (
|
||||
INSERT INTO bot_user_permissions (bot_user_id, user_id, from_request)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (bot_user_id, user_id) DO NOTHING
|
||||
RETURNING 1
|
||||
),
|
||||
updated AS (
|
||||
UPDATE bot_user_permissions
|
||||
SET from_request = bot_user_permissions.from_request OR $3,
|
||||
updated_at = now()
|
||||
WHERE bot_user_id = $1 AND user_id = $2
|
||||
AND NOT EXISTS (SELECT 1 FROM inserted)
|
||||
AND $3
|
||||
AND NOT from_request
|
||||
RETURNING 1
|
||||
)
|
||||
SELECT EXISTS (SELECT 1 FROM inserted) AS created;
|
||||
|
||||
-- name: BumpBotInfoVersion :one
|
||||
UPDATE users
|
||||
SET bot_info_version = bot_info_version + 1, updated_at = now()
|
||||
WHERE id = $1 AND is_bot
|
||||
RETURNING bot_info_version;
|
||||
|
||||
-- name: UpdateBotProfileFields :one
|
||||
-- 部分更新 bot 的 users 行(setBotInfo 的 name/about);NULL 参数表示不动该字段。
|
||||
UPDATE users
|
||||
SET first_name = COALESCE(sqlc.narg(first_name), first_name),
|
||||
about = COALESCE(sqlc.narg(about), about),
|
||||
updated_at = now()
|
||||
WHERE id = $1 AND is_bot
|
||||
RETURNING bot_info_version;
|
||||
|
||||
-- name: GetBotChatState :one
|
||||
SELECT * FROM bot_chat_states WHERE bot_user_id = $1 AND user_id = $2;
|
||||
|
||||
-- name: UpsertBotChatState :exec
|
||||
INSERT INTO bot_chat_states (bot_user_id, user_id, state, updated_at)
|
||||
VALUES ($1, $2, $3, now())
|
||||
ON CONFLICT (bot_user_id, user_id) DO UPDATE SET state = EXCLUDED.state, updated_at = now();
|
||||
|
||||
-- name: DeleteBotChatState :exec
|
||||
DELETE FROM bot_chat_states WHERE bot_user_id = $1 AND user_id = $2;
|
||||
|
|
@ -2,6 +2,7 @@
|
|||
SELECT
|
||||
c.contact_user_id,
|
||||
c.mutual,
|
||||
c.close_friend,
|
||||
c.contact_phone,
|
||||
c.contact_first_name,
|
||||
c.contact_last_name,
|
||||
|
|
@ -16,6 +17,11 @@ SELECT
|
|||
u.country_code,
|
||||
u.verified,
|
||||
u.support,
|
||||
u.is_bot,
|
||||
u.bot_info_version,
|
||||
u.premium_expires_at,
|
||||
u.emoji_status_document_id,
|
||||
u.emoji_status_until,
|
||||
u.last_seen_at
|
||||
FROM contacts c
|
||||
JOIN users u ON u.id = c.contact_user_id
|
||||
|
|
@ -26,6 +32,7 @@ ORDER BY c.contact_first_name, c.contact_last_name, u.first_name, u.last_name, u
|
|||
SELECT
|
||||
c.contact_user_id,
|
||||
c.mutual,
|
||||
c.close_friend,
|
||||
c.contact_phone,
|
||||
c.contact_first_name,
|
||||
c.contact_last_name,
|
||||
|
|
@ -40,6 +47,11 @@ SELECT
|
|||
u.country_code,
|
||||
u.verified,
|
||||
u.support,
|
||||
u.is_bot,
|
||||
u.bot_info_version,
|
||||
u.premium_expires_at,
|
||||
u.emoji_status_document_id,
|
||||
u.emoji_status_until,
|
||||
u.last_seen_at
|
||||
FROM contacts c
|
||||
JOIN users u ON u.id = c.contact_user_id
|
||||
|
|
@ -98,6 +110,7 @@ reverse_updated AS (
|
|||
SELECT
|
||||
c.contact_user_id,
|
||||
c.mutual,
|
||||
c.close_friend,
|
||||
c.contact_phone,
|
||||
c.contact_first_name,
|
||||
c.contact_last_name,
|
||||
|
|
@ -112,6 +125,11 @@ SELECT
|
|||
u.country_code,
|
||||
u.verified,
|
||||
u.support,
|
||||
u.is_bot,
|
||||
u.bot_info_version,
|
||||
u.premium_expires_at,
|
||||
u.emoji_status_document_id,
|
||||
u.emoji_status_until,
|
||||
u.last_seen_at,
|
||||
EXISTS (SELECT 1 FROM reverse_updated)::boolean AS reverse_mutual_changed
|
||||
FROM upserted c
|
||||
|
|
@ -130,6 +148,7 @@ WITH updated AS (
|
|||
SELECT
|
||||
c.contact_user_id,
|
||||
c.mutual,
|
||||
c.close_friend,
|
||||
c.contact_phone,
|
||||
c.contact_first_name,
|
||||
c.contact_last_name,
|
||||
|
|
@ -144,6 +163,11 @@ SELECT
|
|||
u.country_code,
|
||||
u.verified,
|
||||
u.support,
|
||||
u.is_bot,
|
||||
u.bot_info_version,
|
||||
u.premium_expires_at,
|
||||
u.emoji_status_document_id,
|
||||
u.emoji_status_until,
|
||||
u.last_seen_at
|
||||
FROM updated c
|
||||
JOIN users u ON u.id = c.contact_user_id;
|
||||
|
|
|
|||
|
|
@ -12,6 +12,9 @@ WITH base AS (
|
|||
d.unread_count,
|
||||
d.unread_mentions_count,
|
||||
d.unread_reactions_count,
|
||||
d.ttl_period,
|
||||
d.theme_emoticon,
|
||||
d.has_scheduled,
|
||||
d.pinned,
|
||||
d.pinned_order,
|
||||
d.unread_mark,
|
||||
|
|
@ -25,25 +28,64 @@ WITH base AS (
|
|||
COALESCE(u.country_code, '')::text AS peer_country_code,
|
||||
COALESCE(u.verified, false)::boolean AS peer_verified,
|
||||
COALESCE(u.support, false)::boolean AS peer_support,
|
||||
COALESCE(u.is_bot, false)::boolean AS peer_is_bot,
|
||||
COALESCE(u.bot_info_version, 0)::int AS peer_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM u.premium_expires_at), 0)::bigint AS peer_premium_until,
|
||||
COALESCE(u.emoji_status_document_id, 0)::bigint AS peer_emoji_status_document_id,
|
||||
COALESCE(u.emoji_status_until, 0)::bigint AS peer_emoji_status_until,
|
||||
COALESCE(u.last_seen_at, 0)::bigint AS peer_last_seen_at,
|
||||
(c.contact_user_id IS NOT NULL)::boolean AS peer_contact,
|
||||
COALESCE(c.mutual, false)::boolean AS peer_mutual,
|
||||
COALESCE(m.box_id, 0)::int AS message_id,
|
||||
COALESCE(m.private_message_id, 0)::bigint AS message_private_message_id,
|
||||
COALESCE(m.from_user_id, 0)::bigint AS message_from_user_id,
|
||||
COALESCE(m.message_date, 0)::int AS message_date,
|
||||
COALESCE(m.outgoing, false)::boolean AS message_outgoing,
|
||||
COALESCE(m.body, '')::text AS message_body,
|
||||
COALESCE(m.entities::text, '[]')::text AS message_entities_json,
|
||||
COALESCE(m.media::text, '{}')::text AS message_media_json
|
||||
COALESCE(m.media::text, '{}')::text AS message_media_json,
|
||||
COALESCE(m.ttl_period, 0)::int AS message_ttl_period,
|
||||
COALESCE(m.expires_at, 0)::int AS message_expires_at,
|
||||
COALESCE(m.edit_date, 0)::int AS message_edit_date,
|
||||
COALESCE(m.silent, false)::boolean AS message_silent,
|
||||
COALESCE(m.noforwards, false)::boolean AS message_noforwards,
|
||||
COALESCE(m.reply_to_msg_id, 0)::int AS message_reply_to_msg_id,
|
||||
COALESCE(m.reply_to_peer_type, '')::text AS message_reply_to_peer_type,
|
||||
COALESCE(m.reply_to_peer_id, 0)::bigint AS message_reply_to_peer_id,
|
||||
COALESCE(m.reply_to_top_id, 0)::int AS message_reply_to_top_id,
|
||||
COALESCE(m.reply_to_story_id, 0)::int AS message_reply_to_story_id,
|
||||
COALESCE(m.quote_text, '')::text AS message_quote_text,
|
||||
COALESCE(m.quote_entities::text, '[]')::text AS message_quote_entities_json,
|
||||
COALESCE(m.quote_offset, 0)::int AS message_quote_offset,
|
||||
COALESCE(m.fwd_from_peer_type, '')::text AS message_fwd_from_peer_type,
|
||||
COALESCE(m.fwd_from_peer_id, 0)::bigint AS message_fwd_from_peer_id,
|
||||
COALESCE(m.fwd_from_name, '')::text AS message_fwd_from_name,
|
||||
COALESCE(m.fwd_date, 0)::int AS message_fwd_date,
|
||||
COALESCE(m.fwd_saved_from_peer_type, '')::text AS message_fwd_saved_from_peer_type,
|
||||
COALESCE(m.fwd_saved_from_peer_id, 0)::bigint AS message_fwd_saved_from_peer_id,
|
||||
COALESCE(m.fwd_saved_from_msg_id, 0)::int AS message_fwd_saved_from_msg_id,
|
||||
COALESCE(m.saved_peer_type, '')::text AS message_saved_peer_type,
|
||||
COALESCE(m.saved_peer_id, 0)::bigint AS message_saved_peer_id,
|
||||
COALESCE(m.media_unread, false)::boolean AS message_media_unread,
|
||||
COALESCE(m.reaction_unread, false)::boolean AS message_reaction_unread,
|
||||
COALESCE(m.via_bot_id, 0)::bigint AS message_via_bot_id,
|
||||
COALESCE(m.grouped_id, 0)::bigint AS message_grouped_id,
|
||||
COALESCE(m.effect, 0)::bigint AS message_effect,
|
||||
COALESCE(m.reply_markup::text, '{}')::text AS message_reply_markup_json,
|
||||
COALESCE(m.rich_message::text, '{}')::text AS message_rich_message_json,
|
||||
COALESCE(m.pinned, false)::boolean AS message_pinned
|
||||
FROM dialogs d
|
||||
LEFT JOIN users u ON d.peer_type = 'user' AND u.id = d.peer_id
|
||||
LEFT JOIN contacts c ON d.peer_type = 'user' AND c.user_id = d.user_id AND c.contact_user_id = d.peer_id
|
||||
LEFT JOIN message_boxes m ON m.owner_user_id = d.user_id AND m.box_id = d.top_message_id AND NOT m.deleted
|
||||
WHERE d.user_id = $1
|
||||
AND (
|
||||
NOT sqlc.arg(has_folder_id)::boolean
|
||||
-- 不带 folder_id flag 视为主列表(folder 0):官方语义下归档对话只以
|
||||
-- dialogFolder 聚合条目出现在主列表,DrKLO Android 主列表请求不设 flag。
|
||||
(NOT sqlc.arg(has_folder_id)::boolean AND d.folder_id = 0)
|
||||
OR (
|
||||
sqlc.arg(folder_id)::int < 2
|
||||
sqlc.arg(has_folder_id)::boolean
|
||||
AND sqlc.arg(folder_id)::int < 2
|
||||
AND d.folder_id = sqlc.arg(folder_id)::int
|
||||
)
|
||||
OR (
|
||||
|
|
@ -135,6 +177,9 @@ SELECT
|
|||
unread_count,
|
||||
unread_mentions_count,
|
||||
unread_reactions_count,
|
||||
ttl_period,
|
||||
theme_emoticon,
|
||||
has_scheduled,
|
||||
pinned,
|
||||
pinned_order,
|
||||
unread_mark,
|
||||
|
|
@ -148,20 +193,56 @@ SELECT
|
|||
peer_country_code,
|
||||
peer_verified,
|
||||
peer_support,
|
||||
peer_is_bot,
|
||||
peer_bot_info_version,
|
||||
peer_premium_until,
|
||||
peer_emoji_status_document_id,
|
||||
peer_emoji_status_until,
|
||||
peer_last_seen_at,
|
||||
peer_contact,
|
||||
peer_mutual,
|
||||
message_id,
|
||||
message_private_message_id,
|
||||
message_from_user_id,
|
||||
message_date,
|
||||
message_outgoing,
|
||||
message_body,
|
||||
message_entities_json,
|
||||
message_media_json
|
||||
message_media_json,
|
||||
message_ttl_period,
|
||||
message_expires_at,
|
||||
message_edit_date,
|
||||
message_silent,
|
||||
message_noforwards,
|
||||
message_reply_to_msg_id,
|
||||
message_reply_to_peer_type,
|
||||
message_reply_to_peer_id,
|
||||
message_reply_to_top_id,
|
||||
message_reply_to_story_id,
|
||||
message_quote_text,
|
||||
message_quote_entities_json,
|
||||
message_quote_offset,
|
||||
message_fwd_from_peer_type,
|
||||
message_fwd_from_peer_id,
|
||||
message_fwd_from_name,
|
||||
message_fwd_date,
|
||||
message_fwd_saved_from_peer_type,
|
||||
message_fwd_saved_from_peer_id,
|
||||
message_fwd_saved_from_msg_id,
|
||||
message_saved_peer_type,
|
||||
message_saved_peer_id,
|
||||
message_media_unread,
|
||||
message_reaction_unread,
|
||||
message_via_bot_id,
|
||||
message_grouped_id,
|
||||
message_effect,
|
||||
message_reply_markup_json,
|
||||
message_rich_message_json,
|
||||
message_pinned
|
||||
FROM paged
|
||||
ORDER BY
|
||||
pinned DESC,
|
||||
CASE WHEN pinned THEN COALESCE(NULLIF(pinned_order, 0), 2147483647) ELSE 2147483647 END ASC,
|
||||
CASE WHEN pinned THEN COALESCE(pinned_order, 0) ELSE 0 END DESC,
|
||||
top_message_date DESC,
|
||||
top_message_id DESC,
|
||||
peer_id DESC
|
||||
|
|
@ -179,6 +260,9 @@ SELECT
|
|||
d.unread_count,
|
||||
d.unread_mentions_count,
|
||||
d.unread_reactions_count,
|
||||
d.ttl_period,
|
||||
d.theme_emoticon,
|
||||
d.has_scheduled,
|
||||
d.pinned,
|
||||
d.pinned_order,
|
||||
d.unread_mark,
|
||||
|
|
@ -187,9 +271,10 @@ FROM dialogs d
|
|||
LEFT JOIN contacts c ON d.peer_type = 'user' AND c.user_id = d.user_id AND c.contact_user_id = d.peer_id
|
||||
WHERE d.user_id = $1
|
||||
AND (
|
||||
NOT sqlc.arg(has_folder_id)::boolean
|
||||
(NOT sqlc.arg(has_folder_id)::boolean AND d.folder_id = 0)
|
||||
OR (
|
||||
sqlc.arg(folder_id)::int < 2
|
||||
sqlc.arg(has_folder_id)::boolean
|
||||
AND sqlc.arg(folder_id)::int < 2
|
||||
AND d.folder_id = sqlc.arg(folder_id)::int
|
||||
)
|
||||
OR (
|
||||
|
|
@ -233,7 +318,7 @@ WHERE d.user_id = $1
|
|||
AND (NOT sqlc.arg(exclude_pinned)::boolean OR NOT d.pinned)
|
||||
ORDER BY
|
||||
d.pinned DESC,
|
||||
CASE WHEN d.pinned THEN COALESCE(NULLIF(d.pinned_order, 0), 2147483647) ELSE 2147483647 END ASC,
|
||||
CASE WHEN d.pinned THEN COALESCE(d.pinned_order, 0) ELSE 0 END DESC,
|
||||
d.top_message_date DESC,
|
||||
d.top_message_id DESC,
|
||||
d.peer_id DESC;
|
||||
|
|
@ -268,6 +353,9 @@ base AS (
|
|||
COALESCE(d.unread_count, 0)::int AS unread_count,
|
||||
COALESCE(d.unread_mentions_count, 0)::int AS unread_mentions_count,
|
||||
COALESCE(d.unread_reactions_count, 0)::int AS unread_reactions_count,
|
||||
COALESCE(d.ttl_period, 0)::int AS ttl_period,
|
||||
COALESCE(d.theme_emoticon, '')::text AS theme_emoticon,
|
||||
COALESCE(d.has_scheduled, false)::boolean AS has_scheduled,
|
||||
COALESCE(d.pinned, false)::boolean AS pinned,
|
||||
COALESCE(d.pinned_order, 0)::int AS pinned_order,
|
||||
COALESCE(d.unread_mark, false)::boolean AS unread_mark,
|
||||
|
|
@ -281,16 +369,52 @@ base AS (
|
|||
COALESCE(u.country_code, '')::text AS peer_country_code,
|
||||
COALESCE(u.verified, false)::boolean AS peer_verified,
|
||||
COALESCE(u.support, false)::boolean AS peer_support,
|
||||
COALESCE(u.is_bot, false)::boolean AS peer_is_bot,
|
||||
COALESCE(u.bot_info_version, 0)::int AS peer_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM u.premium_expires_at), 0)::bigint AS peer_premium_until,
|
||||
COALESCE(u.emoji_status_document_id, 0)::bigint AS peer_emoji_status_document_id,
|
||||
COALESCE(u.emoji_status_until, 0)::bigint AS peer_emoji_status_until,
|
||||
COALESCE(u.last_seen_at, 0)::bigint AS peer_last_seen_at,
|
||||
(c.contact_user_id IS NOT NULL)::boolean AS peer_contact,
|
||||
COALESCE(c.mutual, false)::boolean AS peer_mutual,
|
||||
COALESCE(m.box_id, 0)::int AS message_id,
|
||||
COALESCE(m.private_message_id, 0)::bigint AS message_private_message_id,
|
||||
COALESCE(m.from_user_id, 0)::bigint AS message_from_user_id,
|
||||
COALESCE(m.message_date, 0)::int AS message_date,
|
||||
COALESCE(m.outgoing, false)::boolean AS message_outgoing,
|
||||
COALESCE(m.body, '')::text AS message_body,
|
||||
COALESCE(m.entities::text, '[]')::text AS message_entities_json,
|
||||
COALESCE(m.media::text, '{}')::text AS message_media_json,
|
||||
COALESCE(m.ttl_period, 0)::int AS message_ttl_period,
|
||||
COALESCE(m.expires_at, 0)::int AS message_expires_at,
|
||||
COALESCE(m.edit_date, 0)::int AS message_edit_date,
|
||||
COALESCE(m.silent, false)::boolean AS message_silent,
|
||||
COALESCE(m.noforwards, false)::boolean AS message_noforwards,
|
||||
COALESCE(m.reply_to_msg_id, 0)::int AS message_reply_to_msg_id,
|
||||
COALESCE(m.reply_to_peer_type, '')::text AS message_reply_to_peer_type,
|
||||
COALESCE(m.reply_to_peer_id, 0)::bigint AS message_reply_to_peer_id,
|
||||
COALESCE(m.reply_to_top_id, 0)::int AS message_reply_to_top_id,
|
||||
COALESCE(m.reply_to_story_id, 0)::int AS message_reply_to_story_id,
|
||||
COALESCE(m.quote_text, '')::text AS message_quote_text,
|
||||
COALESCE(m.quote_entities::text, '[]')::text AS message_quote_entities_json,
|
||||
COALESCE(m.quote_offset, 0)::int AS message_quote_offset,
|
||||
COALESCE(m.fwd_from_peer_type, '')::text AS message_fwd_from_peer_type,
|
||||
COALESCE(m.fwd_from_peer_id, 0)::bigint AS message_fwd_from_peer_id,
|
||||
COALESCE(m.fwd_from_name, '')::text AS message_fwd_from_name,
|
||||
COALESCE(m.fwd_date, 0)::int AS message_fwd_date,
|
||||
COALESCE(m.fwd_saved_from_peer_type, '')::text AS message_fwd_saved_from_peer_type,
|
||||
COALESCE(m.fwd_saved_from_peer_id, 0)::bigint AS message_fwd_saved_from_peer_id,
|
||||
COALESCE(m.fwd_saved_from_msg_id, 0)::int AS message_fwd_saved_from_msg_id,
|
||||
COALESCE(m.saved_peer_type, '')::text AS message_saved_peer_type,
|
||||
COALESCE(m.saved_peer_id, 0)::bigint AS message_saved_peer_id,
|
||||
COALESCE(m.media_unread, false)::boolean AS message_media_unread,
|
||||
COALESCE(m.reaction_unread, false)::boolean AS message_reaction_unread,
|
||||
COALESCE(m.via_bot_id, 0)::bigint AS message_via_bot_id,
|
||||
COALESCE(m.grouped_id, 0)::bigint AS message_grouped_id,
|
||||
COALESCE(m.effect, 0)::bigint AS message_effect,
|
||||
COALESCE(m.reply_markup::text, '{}')::text AS message_reply_markup_json,
|
||||
COALESCE(m.rich_message::text, '{}')::text AS message_rich_message_json,
|
||||
COALESCE(m.pinned, false)::boolean AS message_pinned,
|
||||
r.ord
|
||||
FROM deduped r
|
||||
LEFT JOIN dialogs d
|
||||
|
|
@ -313,6 +437,9 @@ SELECT
|
|||
unread_count,
|
||||
unread_mentions_count,
|
||||
unread_reactions_count,
|
||||
ttl_period,
|
||||
theme_emoticon,
|
||||
has_scheduled,
|
||||
pinned,
|
||||
pinned_order,
|
||||
unread_mark,
|
||||
|
|
@ -326,16 +453,52 @@ SELECT
|
|||
peer_country_code,
|
||||
peer_verified,
|
||||
peer_support,
|
||||
peer_is_bot,
|
||||
peer_bot_info_version,
|
||||
peer_premium_until,
|
||||
peer_emoji_status_document_id,
|
||||
peer_emoji_status_until,
|
||||
peer_last_seen_at,
|
||||
peer_contact,
|
||||
peer_mutual,
|
||||
message_id,
|
||||
message_private_message_id,
|
||||
message_from_user_id,
|
||||
message_date,
|
||||
message_outgoing,
|
||||
message_body,
|
||||
message_entities_json,
|
||||
message_media_json
|
||||
message_media_json,
|
||||
message_ttl_period,
|
||||
message_expires_at,
|
||||
message_edit_date,
|
||||
message_silent,
|
||||
message_noforwards,
|
||||
message_reply_to_msg_id,
|
||||
message_reply_to_peer_type,
|
||||
message_reply_to_peer_id,
|
||||
message_reply_to_top_id,
|
||||
message_reply_to_story_id,
|
||||
message_quote_text,
|
||||
message_quote_entities_json,
|
||||
message_quote_offset,
|
||||
message_fwd_from_peer_type,
|
||||
message_fwd_from_peer_id,
|
||||
message_fwd_from_name,
|
||||
message_fwd_date,
|
||||
message_fwd_saved_from_peer_type,
|
||||
message_fwd_saved_from_peer_id,
|
||||
message_fwd_saved_from_msg_id,
|
||||
message_saved_peer_type,
|
||||
message_saved_peer_id,
|
||||
message_media_unread,
|
||||
message_reaction_unread,
|
||||
message_via_bot_id,
|
||||
message_grouped_id,
|
||||
message_effect,
|
||||
message_reply_markup_json,
|
||||
message_rich_message_json,
|
||||
message_pinned
|
||||
FROM base
|
||||
ORDER BY ord;
|
||||
|
||||
|
|
@ -369,6 +532,8 @@ ON CONFLICT (user_id, peer_type, peer_id) DO UPDATE SET
|
|||
updated_at = now();
|
||||
|
||||
-- name: UpsertOutboxDialog :exec
|
||||
-- 发送方向该会话发出消息即视为已知晓内容:清除手动未读标记,
|
||||
-- 与 channel 发送路径、readHistory 清除语义对齐。
|
||||
INSERT INTO dialogs (
|
||||
user_id,
|
||||
peer_type,
|
||||
|
|
@ -382,6 +547,7 @@ INSERT INTO dialogs (
|
|||
ON CONFLICT (user_id, peer_type, peer_id) DO UPDATE SET
|
||||
top_message_id = EXCLUDED.top_message_id,
|
||||
top_message_date = EXCLUDED.top_message_date,
|
||||
unread_mark = false,
|
||||
updated_at = now();
|
||||
|
||||
-- name: UpsertInboxDialog :exec
|
||||
|
|
@ -396,9 +562,22 @@ INSERT INTO dialogs (
|
|||
$1, $2, $3, $4, $5, 1
|
||||
)
|
||||
ON CONFLICT (user_id, peer_type, peer_id) DO UPDATE SET
|
||||
top_message_id = EXCLUDED.top_message_id,
|
||||
top_message_date = EXCLUDED.top_message_date,
|
||||
unread_count = dialogs.unread_count + 1,
|
||||
top_message_id = GREATEST(dialogs.top_message_id, EXCLUDED.top_message_id),
|
||||
top_message_date = CASE
|
||||
WHEN EXCLUDED.top_message_id >= dialogs.top_message_id THEN EXCLUDED.top_message_date
|
||||
ELSE dialogs.top_message_date
|
||||
END,
|
||||
unread_count = (
|
||||
SELECT COUNT(*)::int
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = dialogs.user_id
|
||||
AND m.peer_type = dialogs.peer_type
|
||||
AND m.peer_id = dialogs.peer_id
|
||||
AND NOT m.deleted
|
||||
AND NOT m.outgoing
|
||||
AND m.box_id > dialogs.read_inbox_max_id
|
||||
AND m.box_id <= GREATEST(dialogs.top_message_id, EXCLUDED.top_message_id)
|
||||
),
|
||||
updated_at = now();
|
||||
|
||||
-- name: MarkDialogRead :one
|
||||
|
|
@ -409,7 +588,11 @@ WITH target AS (
|
|||
d.peer_id,
|
||||
d.top_message_id,
|
||||
d.read_inbox_max_id,
|
||||
d.unread_count
|
||||
d.unread_count,
|
||||
LEAST(
|
||||
d.top_message_id,
|
||||
CASE WHEN sqlc.arg(max_id)::int > 0 THEN sqlc.arg(max_id)::int ELSE d.top_message_id END
|
||||
)::int AS requested_read_max_id
|
||||
FROM dialogs d
|
||||
WHERE d.user_id = $1
|
||||
AND d.peer_type = $2
|
||||
|
|
@ -418,14 +601,19 @@ WITH target AS (
|
|||
updated AS (
|
||||
UPDATE dialogs d
|
||||
SET
|
||||
read_inbox_max_id = GREATEST(
|
||||
d.read_inbox_max_id,
|
||||
CASE WHEN sqlc.arg(max_id)::int > 0 THEN sqlc.arg(max_id)::int ELSE d.top_message_id END
|
||||
read_inbox_max_id = GREATEST(d.read_inbox_max_id, target.requested_read_max_id),
|
||||
unread_count = (
|
||||
SELECT count(*)::int
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = d.user_id
|
||||
AND m.peer_type = d.peer_type
|
||||
AND m.peer_id = d.peer_id
|
||||
AND NOT m.deleted
|
||||
AND NOT m.outgoing
|
||||
AND m.box_id > GREATEST(d.read_inbox_max_id, target.requested_read_max_id)
|
||||
),
|
||||
unread_count = 0,
|
||||
unread_mark = false,
|
||||
unread_mentions_count = 0,
|
||||
unread_reactions_count = 0,
|
||||
updated_at = now()
|
||||
FROM target
|
||||
WHERE d.user_id = target.user_id
|
||||
|
|
@ -439,9 +627,7 @@ RETURNING
|
|||
d.unread_count,
|
||||
(
|
||||
target.unread_count > 0
|
||||
OR (
|
||||
CASE WHEN sqlc.arg(max_id)::int > 0 THEN sqlc.arg(max_id)::int ELSE target.top_message_id END
|
||||
) > target.read_inbox_max_id
|
||||
OR target.requested_read_max_id > target.read_inbox_max_id
|
||||
)::boolean AS changed
|
||||
)
|
||||
SELECT
|
||||
|
|
@ -454,11 +640,34 @@ SELECT
|
|||
FROM updated;
|
||||
|
||||
-- name: SetDialogPinned :one
|
||||
WITH next_order AS (
|
||||
SELECT COALESCE(MAX(pinned_order), 0)::int + 1 AS value
|
||||
FROM dialogs
|
||||
WHERE user_id = sqlc.arg(user_id)::bigint
|
||||
AND pinned
|
||||
-- 置顶顺序在 dialog 当前 folder(0 主列表/1 归档)内独立分配,
|
||||
-- 返回 folder_id 供 updateDialogPinned.folder_id 使用。
|
||||
WITH target AS (
|
||||
SELECT d.folder_id
|
||||
FROM dialogs d
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
AND d.peer_id = sqlc.arg(peer_id)::bigint
|
||||
),
|
||||
next_order AS (
|
||||
-- order 空间跨 dialogs/channel_dialogs 两表统一(合并层按 pinned_order
|
||||
-- 全局排序),但仅在目标会话所在 folder 内取最大值。
|
||||
SELECT GREATEST(
|
||||
COALESCE((
|
||||
SELECT MAX(d.pinned_order)
|
||||
FROM dialogs d, target t
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.pinned
|
||||
AND d.folder_id = t.folder_id
|
||||
), 0),
|
||||
COALESCE((
|
||||
SELECT MAX(cd.pinned_order)
|
||||
FROM channel_dialogs cd, target t
|
||||
WHERE cd.user_id = sqlc.arg(user_id)::bigint
|
||||
AND cd.pinned
|
||||
AND COALESCE(cd.folder_id, 0) = t.folder_id
|
||||
), 0)
|
||||
)::int + 1 AS value
|
||||
),
|
||||
updated AS (
|
||||
UPDATE dialogs d
|
||||
|
|
@ -473,11 +682,15 @@ updated AS (
|
|||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
AND d.peer_id = sqlc.arg(peer_id)::bigint
|
||||
RETURNING d.user_id
|
||||
RETURNING d.folder_id
|
||||
)
|
||||
SELECT EXISTS (SELECT 1 FROM updated)::boolean AS changed;
|
||||
SELECT
|
||||
EXISTS (SELECT 1 FROM updated)::boolean AS changed,
|
||||
COALESCE((SELECT folder_id FROM updated), 0)::int AS folder_id;
|
||||
|
||||
-- name: SetDialogUnreadMark :one
|
||||
-- 值守卫 IS DISTINCT FROM:重复标记同一值不应算 changed,否则上层会记一条
|
||||
-- 幽灵 durable 未读标事件并多推一次 update(对齐频道侧 SetChannelDialogUnreadMark)。
|
||||
WITH updated AS (
|
||||
UPDATE dialogs d
|
||||
SET unread_mark = sqlc.arg(unread)::boolean,
|
||||
|
|
@ -485,6 +698,7 @@ WITH updated AS (
|
|||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
AND d.peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND d.unread_mark IS DISTINCT FROM sqlc.arg(unread)::boolean
|
||||
RETURNING d.user_id
|
||||
)
|
||||
SELECT EXISTS (SELECT 1 FROM updated)::boolean AS changed;
|
||||
|
|
@ -527,10 +741,12 @@ WITH requested AS (
|
|||
WHERE i <= cardinality(sqlc.arg(peer_types)::text[])
|
||||
),
|
||||
deduped AS (
|
||||
-- 请求数组首位是置顶区最顶部;统一编码为"值越大越靠前",与频道
|
||||
-- reorder、toggle 的 MAX+1 分配以及合并层排序方向一致。
|
||||
SELECT DISTINCT ON (peer_type, peer_id)
|
||||
peer_type,
|
||||
peer_id,
|
||||
pos::int AS ord
|
||||
(cardinality(sqlc.arg(peer_ids)::bigint[]) - pos + 1)::int AS ord
|
||||
FROM requested
|
||||
ORDER BY peer_type, peer_id, pos
|
||||
)
|
||||
|
|
@ -541,7 +757,8 @@ SET pinned = true,
|
|||
FROM deduped
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = deduped.peer_type
|
||||
AND d.peer_id = deduped.peer_id;
|
||||
AND d.peer_id = deduped.peer_id
|
||||
AND d.folder_id = sqlc.arg(folder_id)::int;
|
||||
|
||||
-- name: EditDialogPeerFolders :exec
|
||||
WITH requested AS (
|
||||
|
|
@ -563,13 +780,50 @@ deduped AS (
|
|||
ORDER BY peer_type, peer_id
|
||||
)
|
||||
UPDATE dialogs d
|
||||
-- 换 folder 时清 pinned:TDesktop History::setFolderPointer 在归档/还原时
|
||||
-- 本地无条件 unpin,服务端保留旧 pin 会在下次 getDialogs 时把状态漂移回来。
|
||||
SET folder_id = deduped.folder_id,
|
||||
pinned = CASE WHEN d.folder_id <> deduped.folder_id THEN false ELSE d.pinned END,
|
||||
pinned_order = CASE WHEN d.folder_id <> deduped.folder_id THEN 0 ELSE d.pinned_order END,
|
||||
updated_at = now()
|
||||
FROM deduped
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = deduped.peer_type
|
||||
AND d.peer_id = deduped.peer_id;
|
||||
|
||||
-- name: SetDialogArchivePinned :one
|
||||
-- archive folder 行本身的置顶状态(toggleDialogPin(inputDialogPeerFolder))。
|
||||
-- 无行时官方默认视为 pinned=true,所以这里总是落一行显式值。
|
||||
WITH current AS (
|
||||
SELECT archive_pinned
|
||||
FROM dialog_filter_settings
|
||||
WHERE user_id = sqlc.arg(user_id)::bigint
|
||||
),
|
||||
upserted AS (
|
||||
INSERT INTO dialog_filter_settings (user_id, archive_pinned)
|
||||
VALUES (sqlc.arg(user_id)::bigint, sqlc.arg(pinned)::boolean)
|
||||
ON CONFLICT (user_id) DO UPDATE SET
|
||||
archive_pinned = EXCLUDED.archive_pinned,
|
||||
updated_at = now()
|
||||
RETURNING archive_pinned
|
||||
)
|
||||
SELECT (COALESCE((SELECT archive_pinned FROM current), true) IS DISTINCT FROM sqlc.arg(pinned)::boolean)::boolean AS changed
|
||||
FROM upserted;
|
||||
|
||||
-- name: GetDialogArchivePinned :one
|
||||
SELECT archive_pinned
|
||||
FROM dialog_filter_settings
|
||||
WHERE user_id = $1;
|
||||
|
||||
-- name: CountArchiveUnreadDialogs :one
|
||||
-- 归档(folder_id=1)未读聚合:有未读或手动标记未读的会话数 + 未读消息总数。
|
||||
SELECT
|
||||
COUNT(*) FILTER (WHERE unread_count > 0 OR unread_mark)::int AS unread_peers,
|
||||
COALESCE(SUM(unread_count), 0)::int AS unread_messages
|
||||
FROM dialogs
|
||||
WHERE user_id = $1
|
||||
AND folder_id = 1;
|
||||
|
||||
-- name: ClearPinnedDialogsNotInOrder :exec
|
||||
WITH requested AS (
|
||||
SELECT
|
||||
|
|
@ -584,6 +838,7 @@ SET pinned = false,
|
|||
updated_at = now()
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.pinned
|
||||
AND d.folder_id = sqlc.arg(folder_id)::int
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM requested r
|
||||
|
|
@ -607,7 +862,15 @@ SET
|
|||
AND m.box_id > d.read_inbox_max_id
|
||||
),
|
||||
unread_mentions_count = 0,
|
||||
unread_reactions_count = 0,
|
||||
unread_reactions_count = (
|
||||
SELECT COUNT(*)::int
|
||||
FROM message_boxes m2
|
||||
WHERE m2.owner_user_id = d.user_id
|
||||
AND m2.peer_type = d.peer_type
|
||||
AND m2.peer_id = d.peer_id
|
||||
AND NOT m2.deleted
|
||||
AND m2.reaction_unread
|
||||
),
|
||||
updated_at = now()
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
|
|
@ -623,17 +886,32 @@ SET
|
|||
unread_count = 0,
|
||||
unread_mark = false,
|
||||
unread_mentions_count = 0,
|
||||
unread_reactions_count = 0,
|
||||
unread_reactions_count = (
|
||||
SELECT COUNT(*)::int
|
||||
FROM message_boxes m2
|
||||
WHERE m2.owner_user_id = d.user_id
|
||||
AND m2.peer_type = d.peer_type
|
||||
AND m2.peer_id = d.peer_id
|
||||
AND NOT m2.deleted
|
||||
AND m2.reaction_unread
|
||||
),
|
||||
updated_at = now()
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
AND d.peer_id = sqlc.arg(peer_id)::bigint;
|
||||
|
||||
-- name: DeleteDialogByPeer :exec
|
||||
DELETE FROM dialogs
|
||||
WHERE user_id = $1
|
||||
AND peer_type = $2
|
||||
AND peer_id = $3;
|
||||
WITH dropped_drafts AS (
|
||||
-- 删除会话同时丢弃该 peer 的云草稿,避免对端重建会话后旧草稿复活。
|
||||
DELETE FROM dialog_drafts dd
|
||||
WHERE dd.user_id = sqlc.arg(user_id)::bigint
|
||||
AND dd.peer_type = sqlc.arg(peer_type)::text
|
||||
AND dd.peer_id = sqlc.arg(peer_id)::bigint
|
||||
)
|
||||
DELETE FROM dialogs d
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
AND d.peer_id = sqlc.arg(peer_id)::bigint;
|
||||
|
||||
-- name: ListDialogFolders :many
|
||||
SELECT
|
||||
|
|
@ -775,3 +1053,11 @@ deleted AS (
|
|||
)
|
||||
SELECT draft_json
|
||||
FROM deleted;
|
||||
|
||||
-- name: AdvanceDialogReadInboxFloor :exec
|
||||
UPDATE dialogs
|
||||
SET read_inbox_max_id = GREATEST(read_inbox_max_id, @read_inbox_max_id::int),
|
||||
updated_at = now()
|
||||
WHERE user_id = @user_id
|
||||
AND peer_type = @peer_type
|
||||
AND peer_id = @peer_id;
|
||||
|
|
|
|||
|
|
@ -1,31 +1,85 @@
|
|||
-- upload_parts ----------------------------------------------------------------
|
||||
|
||||
-- name: SaveUploadPart :exec
|
||||
INSERT INTO upload_parts (owner_user_id, file_id, part, total_parts, is_big, bytes)
|
||||
INSERT INTO upload_parts (owner_user_id, file_id, part, total_parts, is_big, backend, object_key, size, sha256)
|
||||
VALUES (
|
||||
sqlc.arg(owner_user_id)::bigint,
|
||||
sqlc.arg(file_id)::bigint,
|
||||
sqlc.arg(part)::int,
|
||||
sqlc.arg(total_parts)::int,
|
||||
sqlc.arg(is_big)::boolean,
|
||||
sqlc.arg(bytes)::bytea
|
||||
sqlc.arg(backend)::text,
|
||||
sqlc.arg(object_key)::text,
|
||||
sqlc.arg(size)::bigint,
|
||||
sqlc.arg(sha256)::bytea
|
||||
)
|
||||
ON CONFLICT (owner_user_id, file_id, part) DO UPDATE SET
|
||||
total_parts = EXCLUDED.total_parts,
|
||||
is_big = EXCLUDED.is_big,
|
||||
bytes = EXCLUDED.bytes;
|
||||
backend = EXCLUDED.backend,
|
||||
object_key = EXCLUDED.object_key,
|
||||
size = EXCLUDED.size,
|
||||
sha256 = EXCLUDED.sha256,
|
||||
created_at = now();
|
||||
|
||||
-- name: GetUploadPartUsage :one
|
||||
SELECT
|
||||
COALESCE(SUM(size), 0)::bigint AS bytes,
|
||||
COUNT(*)::int AS parts,
|
||||
COUNT(DISTINCT file_id)::int AS files
|
||||
FROM upload_parts
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint;
|
||||
|
||||
-- name: GetUploadPartSlot :one
|
||||
SELECT
|
||||
COALESCE((
|
||||
SELECT size
|
||||
FROM upload_parts
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND file_id = sqlc.arg(file_id)::bigint
|
||||
AND part = sqlc.arg(part)::int
|
||||
), -1)::bigint AS existing_bytes,
|
||||
COALESCE((
|
||||
SELECT object_key
|
||||
FROM upload_parts
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND file_id = sqlc.arg(file_id)::bigint
|
||||
AND part = sqlc.arg(part)::int
|
||||
), '')::text AS object_key,
|
||||
(
|
||||
SELECT COUNT(*)::int
|
||||
FROM upload_parts
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND file_id = sqlc.arg(file_id)::bigint
|
||||
)::int AS file_parts;
|
||||
|
||||
-- name: ListUploadParts :many
|
||||
SELECT part, total_parts, is_big, bytes
|
||||
SELECT part, total_parts, is_big, backend, object_key, size, sha256
|
||||
FROM upload_parts
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND file_id = sqlc.arg(file_id)::bigint
|
||||
ORDER BY part ASC;
|
||||
|
||||
-- name: DeleteUploadParts :exec
|
||||
-- name: DeleteUploadParts :many
|
||||
DELETE FROM upload_parts
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND file_id = sqlc.arg(file_id)::bigint;
|
||||
AND file_id = sqlc.arg(file_id)::bigint
|
||||
RETURNING object_key;
|
||||
|
||||
-- name: DeleteExpiredUploadParts :many
|
||||
WITH doomed AS (
|
||||
SELECT owner_user_id, file_id, part
|
||||
FROM upload_parts
|
||||
WHERE created_at < sqlc.arg(before)::timestamptz
|
||||
ORDER BY created_at ASC
|
||||
LIMIT sqlc.arg(batch_limit)::int
|
||||
)
|
||||
DELETE FROM upload_parts p
|
||||
USING doomed d
|
||||
WHERE p.owner_user_id = d.owner_user_id
|
||||
AND p.file_id = d.file_id
|
||||
AND p.part = d.part
|
||||
RETURNING p.object_key;
|
||||
|
||||
-- file_blobs ------------------------------------------------------------------
|
||||
|
||||
|
|
|
|||
|
|
@ -81,6 +81,8 @@ INSERT INTO private_messages (
|
|||
recipient_user_id,
|
||||
random_id,
|
||||
message_date,
|
||||
ttl_period,
|
||||
expires_at,
|
||||
body,
|
||||
entities,
|
||||
silent,
|
||||
|
|
@ -89,6 +91,7 @@ INSERT INTO private_messages (
|
|||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
reply_to_story_id,
|
||||
quote_text,
|
||||
quote_entities,
|
||||
quote_offset,
|
||||
|
|
@ -96,15 +99,21 @@ INSERT INTO private_messages (
|
|||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
media
|
||||
media,
|
||||
reply_markup,
|
||||
rich_message,
|
||||
via_bot_id,
|
||||
grouped_id,
|
||||
effect
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, sqlc.arg(entities_json)::jsonb,
|
||||
$1, $2, $3, $4, sqlc.arg(ttl_period)::int, sqlc.arg(expires_at)::int, $5, sqlc.arg(entities_json)::jsonb,
|
||||
sqlc.arg(silent)::boolean,
|
||||
sqlc.arg(noforwards)::boolean,
|
||||
sqlc.arg(reply_to_msg_id)::int,
|
||||
sqlc.arg(reply_to_peer_type)::text,
|
||||
sqlc.arg(reply_to_peer_id)::bigint,
|
||||
sqlc.arg(reply_to_top_id)::int,
|
||||
sqlc.arg(reply_to_story_id)::int,
|
||||
sqlc.arg(quote_text)::text,
|
||||
sqlc.arg(quote_entities_json)::jsonb,
|
||||
sqlc.arg(quote_offset)::int,
|
||||
|
|
@ -112,7 +121,12 @@ INSERT INTO private_messages (
|
|||
sqlc.arg(fwd_from_peer_id)::bigint,
|
||||
sqlc.arg(fwd_from_name)::text,
|
||||
sqlc.arg(fwd_date)::int,
|
||||
sqlc.arg(media_json)::jsonb
|
||||
sqlc.arg(media_json)::jsonb,
|
||||
sqlc.arg(reply_markup_json)::jsonb,
|
||||
sqlc.arg(rich_message_json)::jsonb,
|
||||
sqlc.arg(via_bot_id)::bigint,
|
||||
sqlc.arg(grouped_id)::bigint,
|
||||
sqlc.arg(effect)::bigint
|
||||
)
|
||||
ON CONFLICT (sender_user_id, random_id) WHERE random_id <> 0 DO NOTHING
|
||||
RETURNING
|
||||
|
|
@ -121,6 +135,8 @@ RETURNING
|
|||
recipient_user_id,
|
||||
random_id,
|
||||
message_date,
|
||||
ttl_period,
|
||||
expires_at,
|
||||
edit_date,
|
||||
body,
|
||||
entities::text AS entities_json;
|
||||
|
|
@ -132,6 +148,8 @@ SELECT
|
|||
recipient_user_id,
|
||||
random_id,
|
||||
message_date,
|
||||
ttl_period,
|
||||
expires_at,
|
||||
edit_date,
|
||||
body,
|
||||
entities::text AS entities_json
|
||||
|
|
@ -150,6 +168,8 @@ INSERT INTO message_boxes (
|
|||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
ttl_period,
|
||||
expires_at,
|
||||
outgoing,
|
||||
body,
|
||||
entities,
|
||||
|
|
@ -159,6 +179,7 @@ INSERT INTO message_boxes (
|
|||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
reply_to_story_id,
|
||||
quote_text,
|
||||
quote_entities,
|
||||
quote_offset,
|
||||
|
|
@ -166,18 +187,32 @@ INSERT INTO message_boxes (
|
|||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
fwd_saved_from_peer_type,
|
||||
fwd_saved_from_peer_id,
|
||||
fwd_saved_from_msg_id,
|
||||
saved_peer_type,
|
||||
saved_peer_id,
|
||||
pts,
|
||||
media,
|
||||
media_unread,
|
||||
reaction_unread
|
||||
reaction_unread,
|
||||
reply_markup,
|
||||
rich_message,
|
||||
via_bot_id,
|
||||
grouped_id,
|
||||
effect
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, sqlc.arg(entities_json)::jsonb,
|
||||
$1, $2, $3, $4, $5, $6, $7, $8,
|
||||
sqlc.arg(ttl_period)::int,
|
||||
sqlc.arg(expires_at)::int,
|
||||
$9, $10, sqlc.arg(entities_json)::jsonb,
|
||||
sqlc.arg(silent)::boolean,
|
||||
sqlc.arg(noforwards)::boolean,
|
||||
sqlc.arg(reply_to_msg_id)::int,
|
||||
sqlc.arg(reply_to_peer_type)::text,
|
||||
sqlc.arg(reply_to_peer_id)::bigint,
|
||||
sqlc.arg(reply_to_top_id)::int,
|
||||
sqlc.arg(reply_to_story_id)::int,
|
||||
sqlc.arg(quote_text)::text,
|
||||
sqlc.arg(quote_entities_json)::jsonb,
|
||||
sqlc.arg(quote_offset)::int,
|
||||
|
|
@ -185,10 +220,20 @@ INSERT INTO message_boxes (
|
|||
sqlc.arg(fwd_from_peer_id)::bigint,
|
||||
sqlc.arg(fwd_from_name)::text,
|
||||
sqlc.arg(fwd_date)::int,
|
||||
sqlc.arg(fwd_saved_from_peer_type)::text,
|
||||
sqlc.arg(fwd_saved_from_peer_id)::bigint,
|
||||
sqlc.arg(fwd_saved_from_msg_id)::int,
|
||||
sqlc.arg(saved_peer_type)::text,
|
||||
sqlc.arg(saved_peer_id)::bigint,
|
||||
sqlc.arg(pts)::int,
|
||||
sqlc.arg(media_json)::jsonb,
|
||||
sqlc.arg(media_unread)::boolean,
|
||||
sqlc.arg(reaction_unread)::boolean
|
||||
sqlc.arg(reaction_unread)::boolean,
|
||||
sqlc.arg(reply_markup_json)::jsonb,
|
||||
sqlc.arg(rich_message_json)::jsonb,
|
||||
sqlc.arg(via_bot_id)::bigint,
|
||||
sqlc.arg(grouped_id)::bigint,
|
||||
sqlc.arg(effect)::bigint
|
||||
)
|
||||
RETURNING
|
||||
box_id,
|
||||
|
|
@ -198,6 +243,8 @@ RETURNING
|
|||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
ttl_period,
|
||||
expires_at,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
|
|
@ -208,6 +255,7 @@ RETURNING
|
|||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
reply_to_story_id,
|
||||
quote_text,
|
||||
quote_entities::text AS quote_entities_json,
|
||||
quote_offset,
|
||||
|
|
@ -215,10 +263,21 @@ RETURNING
|
|||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
fwd_saved_from_peer_type,
|
||||
fwd_saved_from_peer_id,
|
||||
fwd_saved_from_msg_id,
|
||||
saved_peer_type,
|
||||
saved_peer_id,
|
||||
pts,
|
||||
media::text AS media_json,
|
||||
media_unread,
|
||||
reaction_unread;
|
||||
reaction_unread,
|
||||
pinned,
|
||||
via_bot_id,
|
||||
grouped_id,
|
||||
effect,
|
||||
reply_markup::text AS reply_markup_json,
|
||||
rich_message::text AS rich_message_json;
|
||||
|
||||
-- name: GetMessageBoxByPrivateMessage :one
|
||||
SELECT
|
||||
|
|
@ -229,6 +288,8 @@ SELECT
|
|||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
ttl_period,
|
||||
expires_at,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
|
|
@ -239,6 +300,7 @@ SELECT
|
|||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
reply_to_story_id,
|
||||
quote_text,
|
||||
quote_entities::text AS quote_entities_json,
|
||||
quote_offset,
|
||||
|
|
@ -246,10 +308,21 @@ SELECT
|
|||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
fwd_saved_from_peer_type,
|
||||
fwd_saved_from_peer_id,
|
||||
fwd_saved_from_msg_id,
|
||||
saved_peer_type,
|
||||
saved_peer_id,
|
||||
pts,
|
||||
media::text AS media_json,
|
||||
media_unread,
|
||||
reaction_unread
|
||||
reaction_unread,
|
||||
pinned,
|
||||
via_bot_id,
|
||||
grouped_id,
|
||||
effect,
|
||||
reply_markup::text AS reply_markup_json,
|
||||
rich_message::text AS rich_message_json
|
||||
FROM message_boxes
|
||||
WHERE owner_user_id = $1
|
||||
AND private_message_id = $2
|
||||
|
|
@ -285,6 +358,8 @@ SELECT
|
|||
m.peer_id,
|
||||
m.from_user_id,
|
||||
m.message_date,
|
||||
m.ttl_period,
|
||||
m.expires_at,
|
||||
m.edit_date,
|
||||
m.outgoing,
|
||||
m.body,
|
||||
|
|
@ -295,6 +370,7 @@ SELECT
|
|||
m.reply_to_peer_type,
|
||||
m.reply_to_peer_id,
|
||||
m.reply_to_top_id,
|
||||
m.reply_to_story_id,
|
||||
m.quote_text,
|
||||
m.quote_entities::text AS quote_entities_json,
|
||||
m.quote_offset,
|
||||
|
|
@ -302,10 +378,18 @@ SELECT
|
|||
m.fwd_from_peer_id,
|
||||
m.fwd_from_name,
|
||||
m.fwd_date,
|
||||
m.fwd_saved_from_peer_type,
|
||||
m.fwd_saved_from_peer_id,
|
||||
m.fwd_saved_from_msg_id,
|
||||
m.saved_peer_type,
|
||||
m.saved_peer_id,
|
||||
m.pts,
|
||||
m.media::text AS media_json,
|
||||
m.media_unread,
|
||||
m.reaction_unread
|
||||
m.reaction_unread,
|
||||
m.pinned,
|
||||
m.via_bot_id,
|
||||
m.grouped_id
|
||||
FROM requested r
|
||||
JOIN message_boxes m
|
||||
ON m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
|
|
@ -342,6 +426,8 @@ base AS NOT MATERIALIZED (
|
|||
m.peer_id,
|
||||
m.from_user_id,
|
||||
m.message_date,
|
||||
m.ttl_period,
|
||||
m.expires_at,
|
||||
m.edit_date,
|
||||
m.outgoing,
|
||||
m.body,
|
||||
|
|
@ -352,6 +438,7 @@ base AS NOT MATERIALIZED (
|
|||
m.reply_to_peer_type,
|
||||
m.reply_to_peer_id,
|
||||
m.reply_to_top_id,
|
||||
m.reply_to_story_id,
|
||||
m.quote_text,
|
||||
m.quote_entities::text AS quote_entities_json,
|
||||
m.quote_offset,
|
||||
|
|
@ -359,10 +446,21 @@ base AS NOT MATERIALIZED (
|
|||
m.fwd_from_peer_id,
|
||||
m.fwd_from_name,
|
||||
m.fwd_date,
|
||||
m.fwd_saved_from_peer_type,
|
||||
m.fwd_saved_from_peer_id,
|
||||
m.fwd_saved_from_msg_id,
|
||||
m.saved_peer_type,
|
||||
m.saved_peer_id,
|
||||
m.pts,
|
||||
m.media::text AS media_json,
|
||||
m.media_unread,
|
||||
m.reaction_unread,
|
||||
m.pinned,
|
||||
m.via_bot_id,
|
||||
m.grouped_id,
|
||||
m.effect,
|
||||
m.reply_markup::text AS reply_markup_json,
|
||||
m.rich_message::text AS rich_message_json,
|
||||
COALESCE(peer_u.id, 0)::bigint AS peer_user_id,
|
||||
COALESCE(peer_u.access_hash, 0)::bigint AS peer_access_hash,
|
||||
COALESCE(peer_u.phone, '')::text AS peer_phone,
|
||||
|
|
@ -372,6 +470,11 @@ base AS NOT MATERIALIZED (
|
|||
COALESCE(peer_u.country_code, '')::text AS peer_country_code,
|
||||
COALESCE(peer_u.verified, false)::boolean AS peer_verified,
|
||||
COALESCE(peer_u.support, false)::boolean AS peer_support,
|
||||
COALESCE(peer_u.is_bot, false)::boolean AS peer_is_bot,
|
||||
COALESCE(peer_u.bot_info_version, 0)::int AS peer_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM peer_u.premium_expires_at), 0)::bigint AS peer_premium_until,
|
||||
COALESCE(peer_u.emoji_status_document_id, 0)::bigint AS peer_emoji_status_document_id,
|
||||
COALESCE(peer_u.emoji_status_until, 0)::bigint AS peer_emoji_status_until,
|
||||
COALESCE(peer_u.last_seen_at, 0)::bigint AS peer_last_seen_at,
|
||||
COALESCE(from_u.id, 0)::bigint AS from_user_user_id,
|
||||
COALESCE(from_u.access_hash, 0)::bigint AS from_user_access_hash,
|
||||
|
|
@ -382,6 +485,11 @@ base AS NOT MATERIALIZED (
|
|||
COALESCE(from_u.country_code, '')::text AS from_user_country_code,
|
||||
COALESCE(from_u.verified, false)::boolean AS from_user_verified,
|
||||
COALESCE(from_u.support, false)::boolean AS from_user_support,
|
||||
COALESCE(from_u.is_bot, false)::boolean AS from_user_is_bot,
|
||||
COALESCE(from_u.bot_info_version, 0)::int AS from_user_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM from_u.premium_expires_at), 0)::bigint AS from_user_premium_until,
|
||||
COALESCE(from_u.emoji_status_document_id, 0)::bigint AS from_user_emoji_status_document_id,
|
||||
COALESCE(from_u.emoji_status_until, 0)::bigint AS from_user_emoji_status_until,
|
||||
COALESCE(from_u.last_seen_at, 0)::bigint AS from_user_last_seen_at
|
||||
FROM message_boxes m
|
||||
LEFT JOIN users peer_u ON m.peer_type = 'user' AND peer_u.id = m.peer_id
|
||||
|
|
@ -398,6 +506,23 @@ base AS NOT MATERIALIZED (
|
|||
)
|
||||
AND (sqlc.arg(max_id)::int <= 0 OR m.box_id < sqlc.arg(max_id)::int)
|
||||
AND (sqlc.arg(min_id)::int <= 0 OR m.box_id > sqlc.arg(min_id)::int)
|
||||
AND (NOT sqlc.arg(pinned_only)::boolean OR m.pinned)
|
||||
AND (
|
||||
NOT sqlc.arg(music_only)::boolean
|
||||
OR (
|
||||
m.media->>'kind' = 'document'
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM jsonb_array_elements(COALESCE(m.media #> '{document,attributes}', '[]'::jsonb)) AS attr
|
||||
WHERE attr->>'kind' = 'audio'
|
||||
AND COALESCE((attr->>'voice')::boolean, false) = false
|
||||
)
|
||||
)
|
||||
)
|
||||
AND (
|
||||
sqlc.arg(saved_peer_type)::text = ''
|
||||
OR (m.saved_peer_type = sqlc.arg(saved_peer_type)::text AND m.saved_peer_id = sqlc.arg(saved_peer_id)::bigint)
|
||||
)
|
||||
),
|
||||
total AS (
|
||||
SELECT count(*)::int AS total_count
|
||||
|
|
@ -476,6 +601,8 @@ SELECT
|
|||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
ttl_period,
|
||||
expires_at,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
|
|
@ -486,6 +613,7 @@ SELECT
|
|||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
reply_to_story_id,
|
||||
quote_text,
|
||||
quote_entities_json,
|
||||
quote_offset,
|
||||
|
|
@ -493,10 +621,21 @@ SELECT
|
|||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
fwd_saved_from_peer_type,
|
||||
fwd_saved_from_peer_id,
|
||||
fwd_saved_from_msg_id,
|
||||
saved_peer_type,
|
||||
saved_peer_id,
|
||||
pts,
|
||||
media_json,
|
||||
media_unread,
|
||||
reaction_unread,
|
||||
pinned,
|
||||
via_bot_id,
|
||||
grouped_id,
|
||||
effect,
|
||||
reply_markup_json,
|
||||
rich_message_json,
|
||||
peer_user_id,
|
||||
peer_access_hash,
|
||||
peer_phone,
|
||||
|
|
@ -506,6 +645,11 @@ SELECT
|
|||
peer_country_code,
|
||||
peer_verified,
|
||||
peer_support,
|
||||
peer_is_bot,
|
||||
peer_bot_info_version,
|
||||
peer_premium_until,
|
||||
peer_emoji_status_document_id,
|
||||
peer_emoji_status_until,
|
||||
peer_last_seen_at,
|
||||
from_user_user_id,
|
||||
from_user_access_hash,
|
||||
|
|
@ -516,12 +660,171 @@ SELECT
|
|||
from_user_country_code,
|
||||
from_user_verified,
|
||||
from_user_support,
|
||||
from_user_is_bot,
|
||||
from_user_bot_info_version,
|
||||
from_user_premium_until,
|
||||
from_user_emoji_status_document_id,
|
||||
from_user_emoji_status_until,
|
||||
from_user_last_seen_at,
|
||||
COALESCE(total.total_count, 0)::int AS total_count
|
||||
FROM paged
|
||||
CROSS JOIN total
|
||||
ORDER BY box_id DESC;
|
||||
|
||||
-- name: ListMessagesBackward :many
|
||||
-- backward 热路径(add_offset>=0:初始加载/上滑翻页)的扁平静态查询。
|
||||
-- 与 ListMessagesByUser 的 backward 分支逐位等价(相同 base 过滤 + 相同 anchor +
|
||||
-- ORDER BY box_id DESC + OFFSET GREATEST(add_offset,0) + LIMIT),但只规划单次
|
||||
-- index scan + 2 LEFT JOIN,避免大 CTE 把 4 个分支+total 全树规划。total 走
|
||||
-- 独立 CountMessagesByUser,仅 NeedTotalCount 时发。
|
||||
SELECT
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.owner_user_id,
|
||||
m.peer_type,
|
||||
m.peer_id,
|
||||
m.from_user_id,
|
||||
m.message_date,
|
||||
m.ttl_period,
|
||||
m.expires_at,
|
||||
m.edit_date,
|
||||
m.outgoing,
|
||||
m.body,
|
||||
m.entities::text AS entities_json,
|
||||
m.silent,
|
||||
m.noforwards,
|
||||
m.reply_to_msg_id,
|
||||
m.reply_to_peer_type,
|
||||
m.reply_to_peer_id,
|
||||
m.reply_to_top_id,
|
||||
m.reply_to_story_id,
|
||||
m.quote_text,
|
||||
m.quote_entities::text AS quote_entities_json,
|
||||
m.quote_offset,
|
||||
m.fwd_from_peer_type,
|
||||
m.fwd_from_peer_id,
|
||||
m.fwd_from_name,
|
||||
m.fwd_date,
|
||||
m.fwd_saved_from_peer_type,
|
||||
m.fwd_saved_from_peer_id,
|
||||
m.fwd_saved_from_msg_id,
|
||||
m.saved_peer_type,
|
||||
m.saved_peer_id,
|
||||
m.pts,
|
||||
m.media::text AS media_json,
|
||||
m.media_unread,
|
||||
m.reaction_unread,
|
||||
m.pinned,
|
||||
m.via_bot_id,
|
||||
m.grouped_id,
|
||||
m.effect,
|
||||
m.reply_markup::text AS reply_markup_json,
|
||||
m.rich_message::text AS rich_message_json,
|
||||
COALESCE(peer_u.id, 0)::bigint AS peer_user_id,
|
||||
COALESCE(peer_u.access_hash, 0)::bigint AS peer_access_hash,
|
||||
COALESCE(peer_u.phone, '')::text AS peer_phone,
|
||||
COALESCE(peer_u.first_name, '')::text AS peer_first_name,
|
||||
COALESCE(peer_u.last_name, '')::text AS peer_last_name,
|
||||
COALESCE(peer_u.username, '')::text AS peer_username,
|
||||
COALESCE(peer_u.country_code, '')::text AS peer_country_code,
|
||||
COALESCE(peer_u.verified, false)::boolean AS peer_verified,
|
||||
COALESCE(peer_u.support, false)::boolean AS peer_support,
|
||||
COALESCE(peer_u.is_bot, false)::boolean AS peer_is_bot,
|
||||
COALESCE(peer_u.bot_info_version, 0)::int AS peer_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM peer_u.premium_expires_at), 0)::bigint AS peer_premium_until,
|
||||
COALESCE(peer_u.emoji_status_document_id, 0)::bigint AS peer_emoji_status_document_id,
|
||||
COALESCE(peer_u.emoji_status_until, 0)::bigint AS peer_emoji_status_until,
|
||||
COALESCE(peer_u.last_seen_at, 0)::bigint AS peer_last_seen_at,
|
||||
COALESCE(from_u.id, 0)::bigint AS from_user_user_id,
|
||||
COALESCE(from_u.access_hash, 0)::bigint AS from_user_access_hash,
|
||||
COALESCE(from_u.phone, '')::text AS from_user_phone,
|
||||
COALESCE(from_u.first_name, '')::text AS from_user_first_name,
|
||||
COALESCE(from_u.last_name, '')::text AS from_user_last_name,
|
||||
COALESCE(from_u.username, '')::text AS from_user_username,
|
||||
COALESCE(from_u.country_code, '')::text AS from_user_country_code,
|
||||
COALESCE(from_u.verified, false)::boolean AS from_user_verified,
|
||||
COALESCE(from_u.support, false)::boolean AS from_user_support,
|
||||
COALESCE(from_u.is_bot, false)::boolean AS from_user_is_bot,
|
||||
COALESCE(from_u.bot_info_version, 0)::int AS from_user_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM from_u.premium_expires_at), 0)::bigint AS from_user_premium_until,
|
||||
COALESCE(from_u.emoji_status_document_id, 0)::bigint AS from_user_emoji_status_document_id,
|
||||
COALESCE(from_u.emoji_status_until, 0)::bigint AS from_user_emoji_status_until,
|
||||
COALESCE(from_u.last_seen_at, 0)::bigint AS from_user_last_seen_at
|
||||
FROM message_boxes m
|
||||
LEFT JOIN users peer_u ON m.peer_type = 'user' AND peer_u.id = m.peer_id
|
||||
LEFT JOIN users from_u ON from_u.id = m.from_user_id
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND NOT m.deleted
|
||||
AND (
|
||||
NOT sqlc.arg(has_peer)::boolean
|
||||
OR (m.peer_type = sqlc.arg(peer_type)::text AND m.peer_id = sqlc.arg(peer_id)::bigint)
|
||||
)
|
||||
AND (
|
||||
sqlc.arg(query)::text = ''
|
||||
OR m.body ILIKE ('%' || sqlc.arg(query)::text || '%')
|
||||
)
|
||||
AND (sqlc.arg(max_id)::int <= 0 OR m.box_id < sqlc.arg(max_id)::int)
|
||||
AND (sqlc.arg(min_id)::int <= 0 OR m.box_id > sqlc.arg(min_id)::int)
|
||||
AND (NOT sqlc.arg(pinned_only)::boolean OR m.pinned)
|
||||
AND (
|
||||
NOT sqlc.arg(music_only)::boolean
|
||||
OR (
|
||||
m.media->>'kind' = 'document'
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM jsonb_array_elements(COALESCE(m.media #> '{document,attributes}', '[]'::jsonb)) AS attr
|
||||
WHERE attr->>'kind' = 'audio'
|
||||
AND COALESCE((attr->>'voice')::boolean, false) = false
|
||||
)
|
||||
)
|
||||
)
|
||||
AND (
|
||||
sqlc.arg(saved_peer_type)::text = ''
|
||||
OR (m.saved_peer_type = sqlc.arg(saved_peer_type)::text AND m.saved_peer_id = sqlc.arg(saved_peer_id)::bigint)
|
||||
)
|
||||
AND (
|
||||
(sqlc.arg(offset_date)::int > 0 AND m.message_date < sqlc.arg(offset_date)::int)
|
||||
OR (sqlc.arg(offset_date)::int <= 0 AND (sqlc.arg(offset_id)::int <= 0 OR m.box_id < sqlc.arg(offset_id)::int))
|
||||
)
|
||||
ORDER BY m.box_id DESC
|
||||
OFFSET GREATEST(sqlc.arg(row_offset)::int, 0)
|
||||
LIMIT sqlc.arg(limit_count)::int;
|
||||
|
||||
-- name: CountMessagesByUser :one
|
||||
-- ListMessagesByUser total CTE 的独立化:相同 base 过滤(不含分页 anchor),
|
||||
-- 仅 NeedTotalCount 时发,避免热路径(getHistory 恒不需 total)次次规划 count 子树。
|
||||
SELECT count(*)::int AS total_count
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND NOT m.deleted
|
||||
AND (
|
||||
NOT sqlc.arg(has_peer)::boolean
|
||||
OR (m.peer_type = sqlc.arg(peer_type)::text AND m.peer_id = sqlc.arg(peer_id)::bigint)
|
||||
)
|
||||
AND (
|
||||
sqlc.arg(query)::text = ''
|
||||
OR m.body ILIKE ('%' || sqlc.arg(query)::text || '%')
|
||||
)
|
||||
AND (sqlc.arg(max_id)::int <= 0 OR m.box_id < sqlc.arg(max_id)::int)
|
||||
AND (sqlc.arg(min_id)::int <= 0 OR m.box_id > sqlc.arg(min_id)::int)
|
||||
AND (NOT sqlc.arg(pinned_only)::boolean OR m.pinned)
|
||||
AND (
|
||||
NOT sqlc.arg(music_only)::boolean
|
||||
OR (
|
||||
m.media->>'kind' = 'document'
|
||||
AND EXISTS (
|
||||
SELECT 1
|
||||
FROM jsonb_array_elements(COALESCE(m.media #> '{document,attributes}', '[]'::jsonb)) AS attr
|
||||
WHERE attr->>'kind' = 'audio'
|
||||
AND COALESCE((attr->>'voice')::boolean, false) = false
|
||||
)
|
||||
)
|
||||
)
|
||||
AND (
|
||||
sqlc.arg(saved_peer_type)::text = ''
|
||||
OR (m.saved_peer_type = sqlc.arg(saved_peer_type)::text AND m.saved_peer_id = sqlc.arg(saved_peer_id)::bigint)
|
||||
);
|
||||
|
||||
-- name: GetMessageBoxesByIDs :many
|
||||
SELECT
|
||||
wanted.box_id AS requested_box_id,
|
||||
|
|
@ -532,6 +835,8 @@ SELECT
|
|||
m.peer_id,
|
||||
m.from_user_id,
|
||||
m.message_date,
|
||||
m.ttl_period,
|
||||
m.expires_at,
|
||||
m.edit_date,
|
||||
m.outgoing,
|
||||
m.body,
|
||||
|
|
@ -542,6 +847,7 @@ SELECT
|
|||
m.reply_to_peer_type,
|
||||
m.reply_to_peer_id,
|
||||
m.reply_to_top_id,
|
||||
m.reply_to_story_id,
|
||||
m.quote_text,
|
||||
m.quote_entities::text AS quote_entities_json,
|
||||
m.quote_offset,
|
||||
|
|
@ -549,10 +855,21 @@ SELECT
|
|||
m.fwd_from_peer_id,
|
||||
m.fwd_from_name,
|
||||
m.fwd_date,
|
||||
m.fwd_saved_from_peer_type,
|
||||
m.fwd_saved_from_peer_id,
|
||||
m.fwd_saved_from_msg_id,
|
||||
m.saved_peer_type,
|
||||
m.saved_peer_id,
|
||||
m.pts,
|
||||
m.media::text AS media_json,
|
||||
m.media_unread,
|
||||
m.reaction_unread,
|
||||
m.pinned,
|
||||
m.via_bot_id,
|
||||
m.grouped_id,
|
||||
m.effect,
|
||||
m.reply_markup::text AS reply_markup_json,
|
||||
m.rich_message::text AS rich_message_json,
|
||||
COALESCE(peer_u.id, 0)::bigint AS peer_user_id,
|
||||
COALESCE(peer_u.access_hash, 0)::bigint AS peer_access_hash,
|
||||
COALESCE(peer_u.phone, '')::text AS peer_phone,
|
||||
|
|
@ -562,6 +879,11 @@ SELECT
|
|||
COALESCE(peer_u.country_code, '')::text AS peer_country_code,
|
||||
COALESCE(peer_u.verified, false)::boolean AS peer_verified,
|
||||
COALESCE(peer_u.support, false)::boolean AS peer_support,
|
||||
COALESCE(peer_u.is_bot, false)::boolean AS peer_is_bot,
|
||||
COALESCE(peer_u.bot_info_version, 0)::int AS peer_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM peer_u.premium_expires_at), 0)::bigint AS peer_premium_until,
|
||||
COALESCE(peer_u.emoji_status_document_id, 0)::bigint AS peer_emoji_status_document_id,
|
||||
COALESCE(peer_u.emoji_status_until, 0)::bigint AS peer_emoji_status_until,
|
||||
COALESCE(peer_u.last_seen_at, 0)::bigint AS peer_last_seen_at,
|
||||
COALESCE(from_u.id, 0)::bigint AS from_user_user_id,
|
||||
COALESCE(from_u.access_hash, 0)::bigint AS from_user_access_hash,
|
||||
|
|
@ -572,6 +894,11 @@ SELECT
|
|||
COALESCE(from_u.country_code, '')::text AS from_user_country_code,
|
||||
COALESCE(from_u.verified, false)::boolean AS from_user_verified,
|
||||
COALESCE(from_u.support, false)::boolean AS from_user_support,
|
||||
COALESCE(from_u.is_bot, false)::boolean AS from_user_is_bot,
|
||||
COALESCE(from_u.bot_info_version, 0)::int AS from_user_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM from_u.premium_expires_at), 0)::bigint AS from_user_premium_until,
|
||||
COALESCE(from_u.emoji_status_document_id, 0)::bigint AS from_user_emoji_status_document_id,
|
||||
COALESCE(from_u.emoji_status_until, 0)::bigint AS from_user_emoji_status_until,
|
||||
COALESCE(from_u.last_seen_at, 0)::bigint AS from_user_last_seen_at
|
||||
FROM unnest(@box_ids::int[]) WITH ORDINALITY AS wanted(box_id, ord)
|
||||
JOIN message_boxes m
|
||||
|
|
@ -592,6 +919,8 @@ SELECT
|
|||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
ttl_period,
|
||||
expires_at,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
|
|
@ -602,6 +931,7 @@ SELECT
|
|||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
reply_to_story_id,
|
||||
quote_text,
|
||||
quote_entities::text AS quote_entities_json,
|
||||
quote_offset,
|
||||
|
|
@ -609,10 +939,21 @@ SELECT
|
|||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
fwd_saved_from_peer_type,
|
||||
fwd_saved_from_peer_id,
|
||||
fwd_saved_from_msg_id,
|
||||
saved_peer_type,
|
||||
saved_peer_id,
|
||||
pts,
|
||||
media::text AS media_json,
|
||||
media_unread,
|
||||
reaction_unread
|
||||
reaction_unread,
|
||||
pinned,
|
||||
via_bot_id,
|
||||
grouped_id,
|
||||
effect,
|
||||
reply_markup::text AS reply_markup_json,
|
||||
rich_message::text AS rich_message_json
|
||||
FROM message_boxes
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND box_id = sqlc.arg(box_id)::int
|
||||
|
|
@ -632,6 +973,8 @@ SELECT
|
|||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
ttl_period,
|
||||
expires_at,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
|
|
@ -642,6 +985,7 @@ SELECT
|
|||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
reply_to_story_id,
|
||||
quote_text,
|
||||
quote_entities::text AS quote_entities_json,
|
||||
quote_offset,
|
||||
|
|
@ -649,12 +993,24 @@ SELECT
|
|||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
fwd_saved_from_peer_type,
|
||||
fwd_saved_from_peer_id,
|
||||
fwd_saved_from_msg_id,
|
||||
saved_peer_type,
|
||||
saved_peer_id,
|
||||
pts,
|
||||
media::text AS media_json,
|
||||
media_unread,
|
||||
reaction_unread
|
||||
reaction_unread,
|
||||
pinned,
|
||||
via_bot_id,
|
||||
grouped_id,
|
||||
effect,
|
||||
reply_markup::text AS reply_markup_json,
|
||||
rich_message::text AS rich_message_json
|
||||
FROM message_boxes
|
||||
WHERE message_sender_id = sqlc.arg(message_sender_id)::bigint
|
||||
WHERE owner_user_id = ANY(sqlc.arg(owner_user_ids)::bigint[])
|
||||
AND message_sender_id = sqlc.arg(message_sender_id)::bigint
|
||||
AND private_message_id = sqlc.arg(private_message_id)::bigint
|
||||
AND NOT deleted
|
||||
ORDER BY owner_user_id ASC, box_id ASC
|
||||
|
|
@ -664,7 +1020,11 @@ FOR UPDATE;
|
|||
UPDATE private_messages
|
||||
SET body = sqlc.arg(body)::text,
|
||||
entities = sqlc.arg(entities_json)::jsonb,
|
||||
edit_date = sqlc.arg(edit_date)::int
|
||||
edit_date = sqlc.arg(edit_date)::int,
|
||||
reply_markup = CASE
|
||||
WHEN sqlc.arg(set_reply_markup)::boolean THEN sqlc.arg(reply_markup_json)::jsonb
|
||||
ELSE reply_markup
|
||||
END
|
||||
WHERE sender_user_id = sqlc.arg(sender_user_id)::bigint
|
||||
AND id = sqlc.arg(private_message_id)::bigint;
|
||||
|
||||
|
|
@ -673,7 +1033,11 @@ UPDATE message_boxes
|
|||
SET body = sqlc.arg(body)::text,
|
||||
entities = sqlc.arg(entities_json)::jsonb,
|
||||
edit_date = sqlc.arg(edit_date)::int,
|
||||
pts = sqlc.arg(pts)::int
|
||||
pts = sqlc.arg(pts)::int,
|
||||
reply_markup = CASE
|
||||
WHEN sqlc.arg(set_reply_markup)::boolean THEN sqlc.arg(reply_markup_json)::jsonb
|
||||
ELSE reply_markup
|
||||
END
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND box_id = sqlc.arg(box_id)::int
|
||||
AND NOT deleted
|
||||
|
|
@ -686,6 +1050,8 @@ RETURNING
|
|||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
ttl_period,
|
||||
expires_at,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
|
|
@ -696,6 +1062,7 @@ RETURNING
|
|||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
reply_to_story_id,
|
||||
quote_text,
|
||||
quote_entities::text AS quote_entities_json,
|
||||
quote_offset,
|
||||
|
|
@ -703,10 +1070,21 @@ RETURNING
|
|||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
fwd_saved_from_peer_type,
|
||||
fwd_saved_from_peer_id,
|
||||
fwd_saved_from_msg_id,
|
||||
saved_peer_type,
|
||||
saved_peer_id,
|
||||
pts,
|
||||
media::text AS media_json,
|
||||
media_unread,
|
||||
reaction_unread;
|
||||
reaction_unread,
|
||||
pinned,
|
||||
via_bot_id,
|
||||
grouped_id,
|
||||
effect,
|
||||
reply_markup::text AS reply_markup_json,
|
||||
rich_message::text AS rich_message_json;
|
||||
|
||||
-- name: GetDialogReadStateForUpdate :one
|
||||
SELECT
|
||||
|
|
@ -761,7 +1139,6 @@ SET
|
|||
),
|
||||
unread_mark = false,
|
||||
unread_mentions_count = 0,
|
||||
unread_reactions_count = 0,
|
||||
updated_at = now()
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
|
|
@ -863,6 +1240,8 @@ WITH target AS (
|
|||
AND m.peer_type = sqlc.arg(peer_type)::text
|
||||
AND m.peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND (sqlc.arg(max_id)::int <= 0 OR m.box_id <= sqlc.arg(max_id)::int)
|
||||
AND (sqlc.arg(min_date)::int <= 0 OR m.message_date >= sqlc.arg(min_date)::int)
|
||||
AND (sqlc.arg(max_date)::int <= 0 OR m.message_date <= sqlc.arg(max_date)::int)
|
||||
AND NOT m.deleted
|
||||
ORDER BY m.box_id DESC
|
||||
LIMIT sqlc.arg(limit_count)::int
|
||||
|
|
@ -900,6 +1279,8 @@ SELECT EXISTS (
|
|||
AND m.peer_type = sqlc.arg(peer_type)::text
|
||||
AND m.peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND (sqlc.arg(max_id)::int <= 0 OR m.box_id <= sqlc.arg(max_id)::int)
|
||||
AND (sqlc.arg(min_date)::int <= 0 OR m.message_date >= sqlc.arg(min_date)::int)
|
||||
AND (sqlc.arg(max_date)::int <= 0 OR m.message_date <= sqlc.arg(max_date)::int)
|
||||
AND NOT m.deleted
|
||||
LIMIT 1
|
||||
)::boolean AS more;
|
||||
|
|
@ -908,19 +1289,24 @@ SELECT EXISTS (
|
|||
WITH requested AS (
|
||||
SELECT
|
||||
(sqlc.arg(message_sender_ids)::bigint[])[i] AS message_sender_id,
|
||||
(sqlc.arg(private_message_ids)::bigint[])[i] AS private_message_id
|
||||
(sqlc.arg(private_message_ids)::bigint[])[i] AS private_message_id,
|
||||
(sqlc.arg(owner_user_ids)::bigint[])[i] AS owner_user_id
|
||||
FROM generate_subscripts(sqlc.arg(private_message_ids)::bigint[], 1) AS g(i)
|
||||
WHERE i <= cardinality(sqlc.arg(message_sender_ids)::bigint[])
|
||||
AND i <= cardinality(sqlc.arg(owner_user_ids)::bigint[])
|
||||
),
|
||||
deduped AS (
|
||||
SELECT DISTINCT message_sender_id, private_message_id
|
||||
SELECT DISTINCT message_sender_id, private_message_id, owner_user_id
|
||||
FROM requested
|
||||
WHERE owner_user_id <> 0
|
||||
),
|
||||
updated AS (
|
||||
UPDATE message_boxes m
|
||||
SET deleted = true
|
||||
FROM deduped d
|
||||
WHERE m.message_sender_id = d.message_sender_id
|
||||
WHERE m.owner_user_id = ANY(sqlc.arg(owner_user_ids)::bigint[])
|
||||
AND m.owner_user_id = d.owner_user_id
|
||||
AND m.message_sender_id = d.message_sender_id
|
||||
AND m.private_message_id = d.private_message_id
|
||||
AND NOT m.deleted
|
||||
RETURNING
|
||||
|
|
@ -952,3 +1338,132 @@ WHERE owner_user_id = $1
|
|||
AND NOT deleted
|
||||
ORDER BY box_id DESC
|
||||
LIMIT 1;
|
||||
|
||||
-- name: ListUnreadReactionMessageBoxes :many
|
||||
SELECT
|
||||
box_id,
|
||||
private_message_id,
|
||||
owner_user_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
ttl_period,
|
||||
expires_at,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
entities::text AS entities_json,
|
||||
silent,
|
||||
noforwards,
|
||||
reply_to_msg_id,
|
||||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
reply_to_story_id,
|
||||
quote_text,
|
||||
quote_entities::text AS quote_entities_json,
|
||||
quote_offset,
|
||||
fwd_from_peer_type,
|
||||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
fwd_saved_from_peer_type,
|
||||
fwd_saved_from_peer_id,
|
||||
fwd_saved_from_msg_id,
|
||||
saved_peer_type,
|
||||
saved_peer_id,
|
||||
pts,
|
||||
media::text AS media_json,
|
||||
media_unread,
|
||||
reaction_unread,
|
||||
pinned,
|
||||
via_bot_id,
|
||||
grouped_id,
|
||||
effect,
|
||||
reply_markup::text AS reply_markup_json,
|
||||
rich_message::text AS rich_message_json
|
||||
FROM message_boxes
|
||||
WHERE owner_user_id = @owner_user_id
|
||||
AND peer_type = @peer_type
|
||||
AND peer_id = @peer_id
|
||||
AND NOT deleted
|
||||
AND reaction_unread
|
||||
ORDER BY box_id DESC
|
||||
LIMIT @page_limit;
|
||||
|
||||
-- name: GetMessageBoxForPin :one
|
||||
SELECT
|
||||
box_id,
|
||||
private_message_id,
|
||||
message_sender_id,
|
||||
pinned,
|
||||
media::text AS media_json
|
||||
FROM message_boxes
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND peer_type = sqlc.arg(peer_type)::text
|
||||
AND peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND box_id = sqlc.arg(box_id)::int
|
||||
AND NOT deleted
|
||||
LIMIT 1
|
||||
FOR UPDATE;
|
||||
|
||||
-- name: SetMessageBoxPinned :execrows
|
||||
UPDATE message_boxes
|
||||
SET pinned = sqlc.arg(pinned)::boolean
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND box_id = sqlc.arg(box_id)::int
|
||||
AND NOT deleted
|
||||
AND pinned <> sqlc.arg(pinned)::boolean;
|
||||
|
||||
-- name: UnpinAllMessageBoxesByPeer :many
|
||||
-- 按批清除(affectedHistory.offset 续清语义),单条 updatePinnedMessages
|
||||
-- 的 messages 向量随之有界。
|
||||
WITH target AS (
|
||||
SELECT m.owner_user_id, m.box_id
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = sqlc.arg(peer_type)::text
|
||||
AND m.peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND m.pinned
|
||||
AND NOT m.deleted
|
||||
ORDER BY m.box_id DESC
|
||||
LIMIT sqlc.arg(limit_count)::int
|
||||
FOR UPDATE
|
||||
)
|
||||
UPDATE message_boxes m
|
||||
SET pinned = false
|
||||
FROM target t
|
||||
WHERE m.owner_user_id = t.owner_user_id
|
||||
AND m.box_id = t.box_id
|
||||
RETURNING m.box_id, m.private_message_id, m.message_sender_id;
|
||||
|
||||
-- name: HasPinnedMessageBoxByPeer :one
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = sqlc.arg(peer_type)::text
|
||||
AND m.peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND m.pinned
|
||||
AND NOT m.deleted
|
||||
LIMIT 1
|
||||
)::boolean AS more;
|
||||
|
||||
-- name: UnpinMessageBoxesByPrivateMessages :many
|
||||
WITH requested AS (
|
||||
SELECT
|
||||
(sqlc.arg(message_sender_ids)::bigint[])[i] AS message_sender_id,
|
||||
(sqlc.arg(private_message_ids)::bigint[])[i] AS private_message_id
|
||||
FROM generate_subscripts(sqlc.arg(private_message_ids)::bigint[], 1) AS g(i)
|
||||
WHERE i <= cardinality(sqlc.arg(message_sender_ids)::bigint[])
|
||||
)
|
||||
UPDATE message_boxes m
|
||||
SET pinned = false
|
||||
FROM requested r
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.message_sender_id = r.message_sender_id
|
||||
AND m.private_message_id = r.private_message_id
|
||||
AND m.pinned
|
||||
AND NOT m.deleted
|
||||
RETURNING m.box_id;
|
||||
|
|
|
|||
337
internal/store/postgres/queries/saved_dialog.sql
Normal file
337
internal/store/postgres/queries/saved_dialog.sql
Normal file
|
|
@ -0,0 +1,337 @@
|
|||
-- Saved Messages 分会话(saved dialogs)查询组。
|
||||
-- 子会话 = self-chat box 行按 saved_peer 分组;top message 不物化,由
|
||||
-- MAX(box_id) 聚合现算(box_id 单调于时间,date 序与 id 序一致),
|
||||
-- 删除/清史后的一致性由查询本身保证。
|
||||
|
||||
-- name: ListSavedDialogTops :many
|
||||
WITH tops AS (
|
||||
SELECT m.saved_peer_type, m.saved_peer_id, MAX(m.box_id) AS top_box_id
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = 'user'
|
||||
AND m.peer_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND NOT m.deleted
|
||||
AND m.saved_peer_type <> ''
|
||||
GROUP BY m.saved_peer_type, m.saved_peer_id
|
||||
)
|
||||
SELECT
|
||||
t.saved_peer_type AS dialog_peer_type,
|
||||
t.saved_peer_id AS dialog_peer_id,
|
||||
(p.user_id IS NOT NULL)::boolean AS dialog_pinned,
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.owner_user_id,
|
||||
m.peer_type,
|
||||
m.peer_id,
|
||||
m.from_user_id,
|
||||
m.message_date,
|
||||
m.ttl_period,
|
||||
m.expires_at,
|
||||
m.edit_date,
|
||||
m.outgoing,
|
||||
m.body,
|
||||
m.entities::text AS entities_json,
|
||||
m.silent,
|
||||
m.noforwards,
|
||||
m.reply_to_msg_id,
|
||||
m.reply_to_peer_type,
|
||||
m.reply_to_peer_id,
|
||||
m.reply_to_top_id,
|
||||
m.reply_to_story_id,
|
||||
m.quote_text,
|
||||
m.quote_entities::text AS quote_entities_json,
|
||||
m.quote_offset,
|
||||
m.fwd_from_peer_type,
|
||||
m.fwd_from_peer_id,
|
||||
m.fwd_from_name,
|
||||
m.fwd_date,
|
||||
m.fwd_saved_from_peer_type,
|
||||
m.fwd_saved_from_peer_id,
|
||||
m.fwd_saved_from_msg_id,
|
||||
m.saved_peer_type,
|
||||
m.saved_peer_id,
|
||||
m.pts,
|
||||
m.media::text AS media_json,
|
||||
m.media_unread,
|
||||
m.reaction_unread,
|
||||
m.via_bot_id,
|
||||
m.grouped_id,
|
||||
m.effect,
|
||||
m.reply_markup::text AS reply_markup_json,
|
||||
m.rich_message::text AS rich_message_json,
|
||||
m.pinned
|
||||
FROM tops t
|
||||
JOIN message_boxes m
|
||||
ON m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.box_id = t.top_box_id
|
||||
LEFT JOIN saved_dialog_pins p
|
||||
ON p.user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND p.peer_type = t.saved_peer_type
|
||||
AND p.peer_id = t.saved_peer_id
|
||||
WHERE (sqlc.arg(offset_id)::int <= 0 OR t.top_box_id < sqlc.arg(offset_id)::int)
|
||||
AND (NOT sqlc.arg(exclude_pinned)::boolean OR p.user_id IS NULL)
|
||||
ORDER BY t.top_box_id DESC
|
||||
LIMIT sqlc.arg(limit_count)::int;
|
||||
|
||||
-- name: ListPinnedSavedDialogTops :many
|
||||
WITH tops AS (
|
||||
SELECT m.saved_peer_type, m.saved_peer_id, MAX(m.box_id) AS top_box_id
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = 'user'
|
||||
AND m.peer_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND NOT m.deleted
|
||||
AND m.saved_peer_type <> ''
|
||||
GROUP BY m.saved_peer_type, m.saved_peer_id
|
||||
)
|
||||
SELECT
|
||||
t.saved_peer_type AS dialog_peer_type,
|
||||
t.saved_peer_id AS dialog_peer_id,
|
||||
true::boolean AS dialog_pinned,
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.owner_user_id,
|
||||
m.peer_type,
|
||||
m.peer_id,
|
||||
m.from_user_id,
|
||||
m.message_date,
|
||||
m.ttl_period,
|
||||
m.expires_at,
|
||||
m.edit_date,
|
||||
m.outgoing,
|
||||
m.body,
|
||||
m.entities::text AS entities_json,
|
||||
m.silent,
|
||||
m.noforwards,
|
||||
m.reply_to_msg_id,
|
||||
m.reply_to_peer_type,
|
||||
m.reply_to_peer_id,
|
||||
m.reply_to_top_id,
|
||||
m.reply_to_story_id,
|
||||
m.quote_text,
|
||||
m.quote_entities::text AS quote_entities_json,
|
||||
m.quote_offset,
|
||||
m.fwd_from_peer_type,
|
||||
m.fwd_from_peer_id,
|
||||
m.fwd_from_name,
|
||||
m.fwd_date,
|
||||
m.fwd_saved_from_peer_type,
|
||||
m.fwd_saved_from_peer_id,
|
||||
m.fwd_saved_from_msg_id,
|
||||
m.saved_peer_type,
|
||||
m.saved_peer_id,
|
||||
m.pts,
|
||||
m.media::text AS media_json,
|
||||
m.media_unread,
|
||||
m.reaction_unread,
|
||||
m.via_bot_id,
|
||||
m.grouped_id,
|
||||
m.effect,
|
||||
m.reply_markup::text AS reply_markup_json,
|
||||
m.rich_message::text AS rich_message_json,
|
||||
m.pinned
|
||||
FROM saved_dialog_pins p
|
||||
JOIN tops t
|
||||
ON t.saved_peer_type = p.peer_type
|
||||
AND t.saved_peer_id = p.peer_id
|
||||
JOIN message_boxes m
|
||||
ON m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.box_id = t.top_box_id
|
||||
WHERE p.user_id = sqlc.arg(owner_user_id)::bigint
|
||||
ORDER BY p.pinned_order ASC, p.peer_id ASC;
|
||||
|
||||
-- name: ListSavedDialogTopsByPeers :many
|
||||
WITH requested AS (
|
||||
SELECT
|
||||
(sqlc.arg(peer_types)::text[])[i] AS peer_type,
|
||||
(sqlc.arg(peer_ids)::bigint[])[i] AS peer_id
|
||||
FROM generate_subscripts(sqlc.arg(peer_ids)::bigint[], 1) AS g(i)
|
||||
WHERE i <= cardinality(sqlc.arg(peer_types)::text[])
|
||||
),
|
||||
tops AS (
|
||||
SELECT m.saved_peer_type, m.saved_peer_id, MAX(m.box_id) AS top_box_id
|
||||
FROM message_boxes m
|
||||
JOIN requested r
|
||||
ON r.peer_type = m.saved_peer_type
|
||||
AND r.peer_id = m.saved_peer_id
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = 'user'
|
||||
AND m.peer_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND NOT m.deleted
|
||||
GROUP BY m.saved_peer_type, m.saved_peer_id
|
||||
)
|
||||
SELECT
|
||||
t.saved_peer_type AS dialog_peer_type,
|
||||
t.saved_peer_id AS dialog_peer_id,
|
||||
(p.user_id IS NOT NULL)::boolean AS dialog_pinned,
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.owner_user_id,
|
||||
m.peer_type,
|
||||
m.peer_id,
|
||||
m.from_user_id,
|
||||
m.message_date,
|
||||
m.ttl_period,
|
||||
m.expires_at,
|
||||
m.edit_date,
|
||||
m.outgoing,
|
||||
m.body,
|
||||
m.entities::text AS entities_json,
|
||||
m.silent,
|
||||
m.noforwards,
|
||||
m.reply_to_msg_id,
|
||||
m.reply_to_peer_type,
|
||||
m.reply_to_peer_id,
|
||||
m.reply_to_top_id,
|
||||
m.reply_to_story_id,
|
||||
m.quote_text,
|
||||
m.quote_entities::text AS quote_entities_json,
|
||||
m.quote_offset,
|
||||
m.fwd_from_peer_type,
|
||||
m.fwd_from_peer_id,
|
||||
m.fwd_from_name,
|
||||
m.fwd_date,
|
||||
m.fwd_saved_from_peer_type,
|
||||
m.fwd_saved_from_peer_id,
|
||||
m.fwd_saved_from_msg_id,
|
||||
m.saved_peer_type,
|
||||
m.saved_peer_id,
|
||||
m.pts,
|
||||
m.media::text AS media_json,
|
||||
m.media_unread,
|
||||
m.reaction_unread,
|
||||
m.via_bot_id,
|
||||
m.grouped_id,
|
||||
m.effect,
|
||||
m.reply_markup::text AS reply_markup_json,
|
||||
m.rich_message::text AS rich_message_json,
|
||||
m.pinned
|
||||
FROM tops t
|
||||
JOIN message_boxes m
|
||||
ON m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.box_id = t.top_box_id
|
||||
LEFT JOIN saved_dialog_pins p
|
||||
ON p.user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND p.peer_type = t.saved_peer_type
|
||||
AND p.peer_id = t.saved_peer_id
|
||||
ORDER BY t.top_box_id DESC;
|
||||
|
||||
-- name: CountSavedDialogs :one
|
||||
SELECT count(*)::int AS dialog_count
|
||||
FROM (
|
||||
SELECT m.saved_peer_type, m.saved_peer_id
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = 'user'
|
||||
AND m.peer_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND NOT m.deleted
|
||||
AND m.saved_peer_type <> ''
|
||||
GROUP BY m.saved_peer_type, m.saved_peer_id
|
||||
) d
|
||||
LEFT JOIN saved_dialog_pins p
|
||||
ON p.user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND p.peer_type = d.saved_peer_type
|
||||
AND p.peer_id = d.saved_peer_id
|
||||
WHERE NOT sqlc.arg(exclude_pinned)::boolean OR p.user_id IS NULL;
|
||||
|
||||
-- name: CountSavedDialogPins :one
|
||||
SELECT count(*)::int AS pin_count
|
||||
FROM saved_dialog_pins
|
||||
WHERE user_id = $1;
|
||||
|
||||
-- name: UpsertSavedDialogPinFront :execrows
|
||||
INSERT INTO saved_dialog_pins (user_id, peer_type, peer_id, pinned_order)
|
||||
VALUES (
|
||||
sqlc.arg(user_id)::bigint,
|
||||
sqlc.arg(peer_type)::text,
|
||||
sqlc.arg(peer_id)::bigint,
|
||||
COALESCE((SELECT MIN(pinned_order) - 1 FROM saved_dialog_pins WHERE user_id = sqlc.arg(user_id)::bigint), 0)
|
||||
)
|
||||
ON CONFLICT (user_id, peer_type, peer_id) DO NOTHING;
|
||||
|
||||
-- name: DeleteSavedDialogPin :execrows
|
||||
DELETE FROM saved_dialog_pins
|
||||
WHERE user_id = $1
|
||||
AND peer_type = $2
|
||||
AND peer_id = $3;
|
||||
|
||||
-- name: ClearSavedDialogPinsNotInOrder :exec
|
||||
DELETE FROM saved_dialog_pins p
|
||||
WHERE p.user_id = sqlc.arg(user_id)::bigint
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM generate_subscripts(sqlc.arg(peer_ids)::bigint[], 1) AS g(i)
|
||||
WHERE i <= cardinality(sqlc.arg(peer_types)::text[])
|
||||
AND (sqlc.arg(peer_types)::text[])[i] = p.peer_type
|
||||
AND (sqlc.arg(peer_ids)::bigint[])[i] = p.peer_id
|
||||
);
|
||||
|
||||
-- name: ReorderSavedDialogPins :exec
|
||||
INSERT INTO saved_dialog_pins (user_id, peer_type, peer_id, pinned_order)
|
||||
SELECT
|
||||
sqlc.arg(user_id)::bigint,
|
||||
(sqlc.arg(peer_types)::text[])[i],
|
||||
(sqlc.arg(peer_ids)::bigint[])[i],
|
||||
(i - 1)::int
|
||||
FROM generate_subscripts(sqlc.arg(peer_ids)::bigint[], 1) AS g(i)
|
||||
WHERE i <= cardinality(sqlc.arg(peer_types)::text[])
|
||||
ON CONFLICT (user_id, peer_type, peer_id) DO UPDATE SET pinned_order = EXCLUDED.pinned_order;
|
||||
|
||||
-- name: DeleteMessageBoxesBySavedPeerBatch :many
|
||||
WITH target AS (
|
||||
SELECT
|
||||
m.owner_user_id,
|
||||
m.box_id
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = 'user'
|
||||
AND m.peer_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.saved_peer_type = sqlc.arg(saved_peer_type)::text
|
||||
AND m.saved_peer_id = sqlc.arg(saved_peer_id)::bigint
|
||||
AND (sqlc.arg(max_id)::int <= 0 OR m.box_id <= sqlc.arg(max_id)::int)
|
||||
AND (sqlc.arg(min_date)::int <= 0 OR m.message_date >= sqlc.arg(min_date)::int)
|
||||
AND (sqlc.arg(max_date)::int <= 0 OR m.message_date <= sqlc.arg(max_date)::int)
|
||||
AND NOT m.deleted
|
||||
ORDER BY m.box_id DESC
|
||||
LIMIT sqlc.arg(limit_count)::int
|
||||
FOR UPDATE SKIP LOCKED
|
||||
),
|
||||
updated AS (
|
||||
UPDATE message_boxes m
|
||||
SET deleted = true
|
||||
FROM target t
|
||||
WHERE m.owner_user_id = t.owner_user_id
|
||||
AND m.box_id = t.box_id
|
||||
RETURNING
|
||||
m.owner_user_id,
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.message_sender_id,
|
||||
m.peer_type,
|
||||
m.peer_id
|
||||
)
|
||||
SELECT
|
||||
owner_user_id,
|
||||
box_id,
|
||||
private_message_id,
|
||||
message_sender_id,
|
||||
peer_type,
|
||||
peer_id
|
||||
FROM updated
|
||||
ORDER BY box_id ASC;
|
||||
|
||||
-- name: HasDeletableMessageBoxBySavedPeer :one
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = 'user'
|
||||
AND m.peer_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.saved_peer_type = sqlc.arg(saved_peer_type)::text
|
||||
AND m.saved_peer_id = sqlc.arg(saved_peer_id)::bigint
|
||||
AND (sqlc.arg(max_id)::int <= 0 OR m.box_id <= sqlc.arg(max_id)::int)
|
||||
AND (sqlc.arg(min_date)::int <= 0 OR m.message_date >= sqlc.arg(min_date)::int)
|
||||
AND (sqlc.arg(max_date)::int <= 0 OR m.message_date <= sqlc.arg(max_date)::int)
|
||||
AND NOT m.deleted
|
||||
LIMIT 1
|
||||
)::boolean AS more;
|
||||
|
|
@ -21,3 +21,12 @@ SELECT
|
|||
encrypted_message
|
||||
FROM temp_auth_key_bindings
|
||||
WHERE temp_auth_key_id = $1;
|
||||
|
||||
-- name: DeleteExpiredTempAuthKeys :execrows
|
||||
DELETE FROM auth_keys
|
||||
WHERE auth_key_id IN (
|
||||
SELECT temp_auth_key_id
|
||||
FROM temp_auth_key_bindings
|
||||
WHERE expires_at < $1
|
||||
LIMIT $2
|
||||
);
|
||||
|
|
|
|||
|
|
@ -8,10 +8,10 @@ WHERE auth_key_id = $1
|
|||
INSERT INTO update_states (auth_key_id, user_id, pts, qts, date, seq)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
ON CONFLICT (auth_key_id, user_id) DO UPDATE SET
|
||||
pts = EXCLUDED.pts,
|
||||
qts = EXCLUDED.qts,
|
||||
date = EXCLUDED.date,
|
||||
seq = EXCLUDED.seq,
|
||||
pts = GREATEST(update_states.pts, EXCLUDED.pts),
|
||||
qts = GREATEST(update_states.qts, EXCLUDED.qts),
|
||||
date = GREATEST(update_states.date, EXCLUDED.date),
|
||||
seq = GREATEST(update_states.seq, EXCLUDED.seq),
|
||||
updated_at = now();
|
||||
|
||||
-- name: DeleteUpdateState :exec
|
||||
|
|
|
|||
|
|
@ -32,6 +32,17 @@ WITH matched AS (
|
|||
u.country_code,
|
||||
u.verified,
|
||||
u.support,
|
||||
u.is_bot,
|
||||
u.bot_info_version,
|
||||
u.premium_expires_at,
|
||||
u.emoji_status_document_id,
|
||||
u.emoji_status_until,
|
||||
u.color_set,
|
||||
u.color,
|
||||
u.color_background_emoji_id,
|
||||
u.profile_color_set,
|
||||
u.profile_color,
|
||||
u.profile_color_background_emoji_id,
|
||||
u.last_seen_at,
|
||||
(c.contact_user_id IS NOT NULL)::boolean AS contact,
|
||||
COALESCE(c.mutual, false)::boolean AS mutual,
|
||||
|
|
@ -69,6 +80,17 @@ SELECT
|
|||
country_code,
|
||||
verified,
|
||||
support,
|
||||
is_bot,
|
||||
bot_info_version,
|
||||
premium_expires_at,
|
||||
emoji_status_document_id,
|
||||
emoji_status_until,
|
||||
color_set,
|
||||
color,
|
||||
color_background_emoji_id,
|
||||
profile_color_set,
|
||||
profile_color,
|
||||
profile_color_background_emoji_id,
|
||||
last_seen_at,
|
||||
contact,
|
||||
mutual
|
||||
|
|
@ -77,8 +99,8 @@ ORDER BY contact DESC, rank, id
|
|||
LIMIT sqlc.arg(limit_count);
|
||||
|
||||
-- name: CreateUser :one
|
||||
INSERT INTO users (access_hash, phone, first_name, last_name, username, country_code)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
INSERT INTO users (access_hash, phone, first_name, last_name, username, country_code, premium_expires_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7)
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUserUsername :one
|
||||
|
|
@ -102,3 +124,72 @@ SET first_name = $2,
|
|||
updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: SetUserPremiumUntil :one
|
||||
UPDATE users
|
||||
SET premium_expires_at = sqlc.narg(premium_expires_at)::timestamptz,
|
||||
updated_at = now()
|
||||
WHERE id = sqlc.arg(id)::bigint
|
||||
RETURNING *;
|
||||
|
||||
-- name: SetUserVerified :one
|
||||
UPDATE users
|
||||
SET verified = sqlc.arg(verified)::boolean,
|
||||
updated_at = now()
|
||||
WHERE id = sqlc.arg(id)::bigint
|
||||
RETURNING *;
|
||||
|
||||
-- name: SweepExpiredPremium :many
|
||||
UPDATE users
|
||||
SET premium_expires_at = NULL,
|
||||
updated_at = now()
|
||||
WHERE id IN (
|
||||
SELECT id FROM users
|
||||
WHERE premium_expires_at IS NOT NULL
|
||||
AND premium_expires_at <= sqlc.arg(now)::timestamptz
|
||||
ORDER BY premium_expires_at
|
||||
LIMIT sqlc.arg(limit_count)::int
|
||||
)
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUserEmojiStatus :one
|
||||
UPDATE users
|
||||
SET emoji_status_document_id = sqlc.arg(emoji_status_document_id)::bigint,
|
||||
emoji_status_until = sqlc.arg(emoji_status_until)::bigint,
|
||||
updated_at = now()
|
||||
WHERE id = sqlc.arg(id)::bigint
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUserBirthday :one
|
||||
UPDATE users
|
||||
SET birthday_day = sqlc.arg(birthday_day)::int,
|
||||
birthday_month = sqlc.arg(birthday_month)::int,
|
||||
birthday_year = sqlc.arg(birthday_year)::int,
|
||||
updated_at = now()
|
||||
WHERE id = sqlc.arg(id)::bigint
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUserPersonalChannel :one
|
||||
UPDATE users
|
||||
SET personal_channel_id = sqlc.arg(personal_channel_id)::bigint,
|
||||
updated_at = now()
|
||||
WHERE id = sqlc.arg(id)::bigint
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUserColor :one
|
||||
UPDATE users
|
||||
SET color_set = sqlc.arg(color_set)::boolean,
|
||||
color = sqlc.arg(color)::int,
|
||||
color_background_emoji_id = sqlc.arg(background_emoji_id)::bigint,
|
||||
updated_at = now()
|
||||
WHERE id = sqlc.arg(id)::bigint
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUserProfileColor :one
|
||||
UPDATE users
|
||||
SET profile_color_set = sqlc.arg(color_set)::boolean,
|
||||
profile_color = sqlc.arg(color)::int,
|
||||
profile_color_background_emoji_id = sqlc.arg(background_emoji_id)::bigint,
|
||||
updated_at = now()
|
||||
WHERE id = sqlc.arg(id)::bigint
|
||||
RETURNING *;
|
||||
|
|
|
|||
|
|
@ -12,13 +12,17 @@ INSERT INTO user_update_events (
|
|||
dialog_filter,
|
||||
filter_order,
|
||||
folder_peers,
|
||||
story_payload,
|
||||
reaction_payload,
|
||||
message_box_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
filter_id,
|
||||
max_id,
|
||||
still_unread_count,
|
||||
tags_enabled
|
||||
channel_pts,
|
||||
tags_enabled,
|
||||
folder_id
|
||||
) VALUES (
|
||||
$1,
|
||||
$2,
|
||||
|
|
@ -32,15 +36,18 @@ INSERT INTO user_update_events (
|
|||
sqlc.arg(dialog_filter)::jsonb,
|
||||
sqlc.arg(filter_order)::jsonb,
|
||||
sqlc.arg(folder_peers)::jsonb,
|
||||
sqlc.arg(story_payload)::jsonb,
|
||||
sqlc.arg(reaction_payload)::jsonb,
|
||||
sqlc.narg(message_box_id),
|
||||
sqlc.narg(peer_type)::text,
|
||||
sqlc.narg(peer_id)::bigint,
|
||||
sqlc.arg(filter_id)::int,
|
||||
sqlc.arg(max_id)::int,
|
||||
sqlc.arg(still_unread_count)::int,
|
||||
sqlc.arg(tags_enabled)::boolean
|
||||
)
|
||||
ON CONFLICT (user_id, pts) DO NOTHING;
|
||||
sqlc.arg(channel_pts)::int,
|
||||
sqlc.arg(tags_enabled)::boolean,
|
||||
sqlc.arg(folder_id)::int
|
||||
);
|
||||
|
||||
-- name: ListUserUpdateEventsAfter :many
|
||||
SELECT
|
||||
|
|
@ -56,12 +63,16 @@ SELECT
|
|||
COALESCE(e.dialog_filter::text, '{}')::text AS dialog_filter_json,
|
||||
COALESCE(e.filter_order::text, '[]')::text AS filter_order_json,
|
||||
COALESCE(e.folder_peers::text, '[]')::text AS folder_peers_json,
|
||||
COALESCE(e.story_payload::text, '{}')::text AS story_payload_json,
|
||||
COALESCE(e.reaction_payload::text, '{}')::text AS reaction_payload_json,
|
||||
COALESCE(e.peer_type, '')::text AS event_peer_type,
|
||||
COALESCE(e.peer_id, 0)::bigint AS event_peer_id,
|
||||
e.filter_id,
|
||||
e.max_id,
|
||||
e.still_unread_count,
|
||||
e.channel_pts,
|
||||
e.tags_enabled,
|
||||
e.folder_id,
|
||||
COALESCE(m.box_id, 0)::int AS message_id,
|
||||
COALESCE(m.private_message_id, 0)::bigint AS private_message_id,
|
||||
COALESCE(m.owner_user_id, 0)::bigint AS owner_user_id,
|
||||
|
|
@ -69,6 +80,8 @@ SELECT
|
|||
COALESCE(m.peer_id, 0)::bigint AS peer_id,
|
||||
COALESCE(m.from_user_id, 0)::bigint AS from_user_id,
|
||||
COALESCE(m.message_date, 0)::int AS message_date,
|
||||
COALESCE(m.ttl_period, 0)::int AS ttl_period,
|
||||
COALESCE(m.expires_at, 0)::int AS expires_at,
|
||||
COALESCE(m.edit_date, 0)::int AS edit_date,
|
||||
COALESCE(m.outgoing, false)::boolean AS outgoing,
|
||||
COALESCE(m.body, '')::text AS body,
|
||||
|
|
@ -79,6 +92,7 @@ SELECT
|
|||
COALESCE(m.reply_to_peer_type, '')::text AS reply_to_peer_type,
|
||||
COALESCE(m.reply_to_peer_id, 0)::bigint AS reply_to_peer_id,
|
||||
COALESCE(m.reply_to_top_id, 0)::int AS reply_to_top_id,
|
||||
COALESCE(m.reply_to_story_id, 0)::int AS reply_to_story_id,
|
||||
COALESCE(m.quote_text, '')::text AS quote_text,
|
||||
COALESCE(m.quote_entities::text, '[]')::text AS quote_entities_json,
|
||||
COALESCE(m.quote_offset, 0)::int AS quote_offset,
|
||||
|
|
@ -86,9 +100,20 @@ SELECT
|
|||
COALESCE(m.fwd_from_peer_id, 0)::bigint AS fwd_from_peer_id,
|
||||
COALESCE(m.fwd_from_name, '')::text AS fwd_from_name,
|
||||
COALESCE(m.fwd_date, 0)::int AS fwd_date,
|
||||
COALESCE(m.fwd_saved_from_peer_type, '')::text AS fwd_saved_from_peer_type,
|
||||
COALESCE(m.fwd_saved_from_peer_id, 0)::bigint AS fwd_saved_from_peer_id,
|
||||
COALESCE(m.fwd_saved_from_msg_id, 0)::int AS fwd_saved_from_msg_id,
|
||||
COALESCE(m.saved_peer_type, '')::text AS saved_peer_type,
|
||||
COALESCE(m.saved_peer_id, 0)::bigint AS saved_peer_id,
|
||||
COALESCE(m.media::text, '{}')::text AS media_json,
|
||||
COALESCE(m.media_unread, false)::boolean AS media_unread,
|
||||
COALESCE(m.reaction_unread, false)::boolean AS reaction_unread,
|
||||
COALESCE(m.pinned, false)::boolean AS pinned,
|
||||
COALESCE(m.via_bot_id, 0)::bigint AS via_bot_id,
|
||||
COALESCE(m.grouped_id, 0)::bigint AS grouped_id,
|
||||
COALESCE(m.effect, 0)::bigint AS effect,
|
||||
COALESCE(m.reply_markup::text, '{}')::text AS reply_markup_json,
|
||||
COALESCE(m.rich_message::text, '{}')::text AS rich_message_json,
|
||||
COALESCE(peer_u.id, 0)::bigint AS peer_user_id,
|
||||
COALESCE(peer_u.access_hash, 0)::bigint AS peer_access_hash,
|
||||
COALESCE(peer_u.phone, '')::text AS peer_phone,
|
||||
|
|
@ -98,6 +123,11 @@ SELECT
|
|||
COALESCE(peer_u.country_code, '')::text AS peer_country_code,
|
||||
COALESCE(peer_u.verified, false)::boolean AS peer_verified,
|
||||
COALESCE(peer_u.support, false)::boolean AS peer_support,
|
||||
COALESCE(peer_u.is_bot, false)::boolean AS peer_is_bot,
|
||||
COALESCE(peer_u.bot_info_version, 0)::int AS peer_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM peer_u.premium_expires_at), 0)::bigint AS peer_premium_until,
|
||||
COALESCE(peer_u.emoji_status_document_id, 0)::bigint AS peer_emoji_status_document_id,
|
||||
COALESCE(peer_u.emoji_status_until, 0)::bigint AS peer_emoji_status_until,
|
||||
COALESCE(from_u.id, 0)::bigint AS from_user_user_id,
|
||||
COALESCE(from_u.access_hash, 0)::bigint AS from_user_access_hash,
|
||||
COALESCE(from_u.phone, '')::text AS from_user_phone,
|
||||
|
|
@ -107,6 +137,11 @@ SELECT
|
|||
COALESCE(from_u.country_code, '')::text AS from_user_country_code,
|
||||
COALESCE(from_u.verified, false)::boolean AS from_user_verified,
|
||||
COALESCE(from_u.support, false)::boolean AS from_user_support,
|
||||
COALESCE(from_u.is_bot, false)::boolean AS from_user_is_bot,
|
||||
COALESCE(from_u.bot_info_version, 0)::int AS from_user_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM from_u.premium_expires_at), 0)::bigint AS from_user_premium_until,
|
||||
COALESCE(from_u.emoji_status_document_id, 0)::bigint AS from_user_emoji_status_document_id,
|
||||
COALESCE(from_u.emoji_status_until, 0)::bigint AS from_user_emoji_status_until,
|
||||
COALESCE(fwd_u.id, 0)::bigint AS fwd_user_id,
|
||||
COALESCE(fwd_u.access_hash, 0)::bigint AS fwd_user_access_hash,
|
||||
COALESCE(fwd_u.phone, '')::text AS fwd_user_phone,
|
||||
|
|
@ -116,6 +151,11 @@ SELECT
|
|||
COALESCE(fwd_u.country_code, '')::text AS fwd_user_country_code,
|
||||
COALESCE(fwd_u.verified, false)::boolean AS fwd_user_verified,
|
||||
COALESCE(fwd_u.support, false)::boolean AS fwd_user_support,
|
||||
COALESCE(fwd_u.is_bot, false)::boolean AS fwd_user_is_bot,
|
||||
COALESCE(fwd_u.bot_info_version, 0)::int AS fwd_user_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM fwd_u.premium_expires_at), 0)::bigint AS fwd_user_premium_until,
|
||||
COALESCE(fwd_u.emoji_status_document_id, 0)::bigint AS fwd_user_emoji_status_document_id,
|
||||
COALESCE(fwd_u.emoji_status_until, 0)::bigint AS fwd_user_emoji_status_until,
|
||||
COALESCE(reply_u.id, 0)::bigint AS reply_user_id,
|
||||
COALESCE(reply_u.access_hash, 0)::bigint AS reply_user_access_hash,
|
||||
COALESCE(reply_u.phone, '')::text AS reply_user_phone,
|
||||
|
|
@ -125,62 +165,17 @@ SELECT
|
|||
COALESCE(reply_u.country_code, '')::text AS reply_user_country_code,
|
||||
COALESCE(reply_u.verified, false)::boolean AS reply_user_verified,
|
||||
COALESCE(reply_u.support, false)::boolean AS reply_user_support,
|
||||
COALESCE(fwd_ch.id, 0)::bigint AS fwd_channel_id,
|
||||
COALESCE(fwd_ch.access_hash, 0)::bigint AS fwd_channel_access_hash,
|
||||
COALESCE(fwd_ch.creator_user_id, 0)::bigint AS fwd_channel_creator_user_id,
|
||||
COALESCE(fwd_ch.title, '')::text AS fwd_channel_title,
|
||||
COALESCE(fwd_ch.about, '')::text AS fwd_channel_about,
|
||||
COALESCE(fwd_ch.username, '')::text AS fwd_channel_username,
|
||||
COALESCE(fwd_ch.broadcast, false)::boolean AS fwd_channel_broadcast,
|
||||
COALESCE(fwd_ch.megagroup, false)::boolean AS fwd_channel_megagroup,
|
||||
COALESCE(fwd_ch.forum, false)::boolean AS fwd_channel_forum,
|
||||
COALESCE(fwd_ch.noforwards, false)::boolean AS fwd_channel_noforwards,
|
||||
COALESCE(fwd_ch.signatures, false)::boolean AS fwd_channel_signatures,
|
||||
COALESCE(fwd_ch.pre_history_hidden, false)::boolean AS fwd_channel_pre_history_hidden,
|
||||
COALESCE(fwd_ch.slowmode_seconds, 0)::int AS fwd_channel_slowmode_seconds,
|
||||
COALESCE(fwd_ch.default_banned_rights::text, '{}')::text AS fwd_channel_default_banned_rights,
|
||||
COALESCE(fwd_ch.participants_count, 0)::int AS fwd_channel_participants_count,
|
||||
COALESCE(fwd_ch.admins_count, 0)::int AS fwd_channel_admins_count,
|
||||
COALESCE(fwd_ch.kicked_count, 0)::int AS fwd_channel_kicked_count,
|
||||
COALESCE(fwd_ch.banned_count, 0)::int AS fwd_channel_banned_count,
|
||||
COALESCE(fwd_ch.top_message_id, 0)::int AS fwd_channel_top_message_id,
|
||||
COALESCE(fwd_ch.pinned_message_id, 0)::int AS fwd_channel_pinned_message_id,
|
||||
COALESCE(fwd_ch.pts, 0)::int AS fwd_channel_pts,
|
||||
COALESCE(fwd_ch.ttl_period, 0)::int AS fwd_channel_ttl_period,
|
||||
COALESCE(fwd_ch.date, 0)::int AS fwd_channel_date,
|
||||
COALESCE(fwd_ch.deleted, false)::boolean AS fwd_channel_deleted,
|
||||
COALESCE(reply_ch.id, 0)::bigint AS reply_channel_id,
|
||||
COALESCE(reply_ch.access_hash, 0)::bigint AS reply_channel_access_hash,
|
||||
COALESCE(reply_ch.creator_user_id, 0)::bigint AS reply_channel_creator_user_id,
|
||||
COALESCE(reply_ch.title, '')::text AS reply_channel_title,
|
||||
COALESCE(reply_ch.about, '')::text AS reply_channel_about,
|
||||
COALESCE(reply_ch.username, '')::text AS reply_channel_username,
|
||||
COALESCE(reply_ch.broadcast, false)::boolean AS reply_channel_broadcast,
|
||||
COALESCE(reply_ch.megagroup, false)::boolean AS reply_channel_megagroup,
|
||||
COALESCE(reply_ch.forum, false)::boolean AS reply_channel_forum,
|
||||
COALESCE(reply_ch.noforwards, false)::boolean AS reply_channel_noforwards,
|
||||
COALESCE(reply_ch.signatures, false)::boolean AS reply_channel_signatures,
|
||||
COALESCE(reply_ch.pre_history_hidden, false)::boolean AS reply_channel_pre_history_hidden,
|
||||
COALESCE(reply_ch.slowmode_seconds, 0)::int AS reply_channel_slowmode_seconds,
|
||||
COALESCE(reply_ch.default_banned_rights::text, '{}')::text AS reply_channel_default_banned_rights,
|
||||
COALESCE(reply_ch.participants_count, 0)::int AS reply_channel_participants_count,
|
||||
COALESCE(reply_ch.admins_count, 0)::int AS reply_channel_admins_count,
|
||||
COALESCE(reply_ch.kicked_count, 0)::int AS reply_channel_kicked_count,
|
||||
COALESCE(reply_ch.banned_count, 0)::int AS reply_channel_banned_count,
|
||||
COALESCE(reply_ch.top_message_id, 0)::int AS reply_channel_top_message_id,
|
||||
COALESCE(reply_ch.pinned_message_id, 0)::int AS reply_channel_pinned_message_id,
|
||||
COALESCE(reply_ch.pts, 0)::int AS reply_channel_pts,
|
||||
COALESCE(reply_ch.ttl_period, 0)::int AS reply_channel_ttl_period,
|
||||
COALESCE(reply_ch.date, 0)::int AS reply_channel_date,
|
||||
COALESCE(reply_ch.deleted, false)::boolean AS reply_channel_deleted
|
||||
COALESCE(reply_u.is_bot, false)::boolean AS reply_user_is_bot,
|
||||
COALESCE(reply_u.bot_info_version, 0)::int AS reply_user_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM reply_u.premium_expires_at), 0)::bigint AS reply_user_premium_until,
|
||||
COALESCE(reply_u.emoji_status_document_id, 0)::bigint AS reply_user_emoji_status_document_id,
|
||||
COALESCE(reply_u.emoji_status_until, 0)::bigint AS reply_user_emoji_status_until
|
||||
FROM user_update_events e
|
||||
LEFT JOIN message_boxes m ON m.owner_user_id = e.user_id AND m.box_id = e.message_box_id
|
||||
LEFT JOIN users peer_u ON m.peer_type = 'user' AND peer_u.id = m.peer_id
|
||||
LEFT JOIN users from_u ON from_u.id = m.from_user_id
|
||||
LEFT JOIN users fwd_u ON m.fwd_from_peer_type = 'user' AND fwd_u.id = m.fwd_from_peer_id
|
||||
LEFT JOIN users reply_u ON m.reply_to_peer_type = 'user' AND reply_u.id = m.reply_to_peer_id
|
||||
LEFT JOIN channels fwd_ch ON m.fwd_from_peer_type = 'channel' AND fwd_ch.id = m.fwd_from_peer_id
|
||||
LEFT JOIN channels reply_ch ON m.reply_to_peer_type = 'channel' AND reply_ch.id = m.reply_to_peer_id
|
||||
WHERE e.user_id = $1
|
||||
AND e.pts > $2
|
||||
ORDER BY e.pts ASC
|
||||
|
|
@ -191,46 +186,11 @@ SELECT COALESCE(MAX(pts), 0)::int AS max_pts
|
|||
FROM user_update_events
|
||||
WHERE user_id = $1;
|
||||
|
||||
-- name: RecentUserPts :many
|
||||
-- 取某 user 最近的一段 pts(降序),供计算「最大连续已提交 pts」用。
|
||||
-- 只看顶部窗口:瞬时空洞只可能出现在最近在途事务区,窗口足够大即可覆盖其下方连续。
|
||||
SELECT pts, pts_count
|
||||
FROM user_update_events
|
||||
WHERE user_id = $1
|
||||
ORDER BY pts DESC
|
||||
LIMIT sqlc.arg(window_size);
|
||||
|
||||
-- name: EnsureUserUpdateWatermark :exec
|
||||
INSERT INTO user_update_watermarks (user_id, contiguous_pts)
|
||||
VALUES ($1, 0)
|
||||
ON CONFLICT (user_id) DO NOTHING;
|
||||
|
||||
-- name: GetUserUpdateWatermark :one
|
||||
SELECT contiguous_pts
|
||||
FROM user_update_watermarks
|
||||
WHERE user_id = $1;
|
||||
|
||||
-- name: LockUserUpdateWatermark :one
|
||||
SELECT contiguous_pts
|
||||
FROM user_update_watermarks
|
||||
WHERE user_id = $1
|
||||
FOR UPDATE;
|
||||
|
||||
-- name: NextUserPtsAfter :many
|
||||
SELECT pts, pts_count
|
||||
FROM user_update_events
|
||||
WHERE user_id = $1
|
||||
AND pts > $2
|
||||
ORDER BY pts ASC
|
||||
LIMIT sqlc.arg(limit_count);
|
||||
|
||||
-- name: SaveUserUpdateWatermark :exec
|
||||
INSERT INTO user_update_watermarks (user_id, contiguous_pts, updated_at)
|
||||
VALUES ($1, $2, now())
|
||||
ON CONFLICT (user_id) DO UPDATE SET
|
||||
contiguous_pts = GREATEST(user_update_watermarks.contiguous_pts, EXCLUDED.contiguous_pts),
|
||||
updated_at = now();
|
||||
|
||||
-- name: EnqueueDispatch :exec
|
||||
INSERT INTO dispatch_outbox (
|
||||
target_user_id,
|
||||
|
|
@ -245,17 +205,17 @@ ON CONFLICT DO NOTHING;
|
|||
|
||||
-- name: ClaimDispatchOutbox :many
|
||||
WITH picked AS (
|
||||
SELECT target_user_id, id
|
||||
FROM dispatch_outbox
|
||||
SELECT d.target_user_id, d.id
|
||||
FROM dispatch_outbox d
|
||||
WHERE (
|
||||
status = 'pending'
|
||||
AND next_attempt_at <= now()
|
||||
d.status = 'pending'
|
||||
AND d.next_attempt_at <= now()
|
||||
)
|
||||
OR (
|
||||
status = 'dispatching'
|
||||
AND updated_at < now() - make_interval(secs => sqlc.arg(lease_seconds)::int)
|
||||
d.status = 'dispatching'
|
||||
AND d.updated_at < now() - make_interval(secs => sqlc.arg(lease_seconds)::int)
|
||||
)
|
||||
ORDER BY next_attempt_at ASC, target_user_id ASC, id ASC
|
||||
ORDER BY d.next_attempt_at ASC, d.target_user_id ASC, d.pts ASC, d.id ASC
|
||||
LIMIT sqlc.arg(limit_count)
|
||||
FOR UPDATE SKIP LOCKED
|
||||
)
|
||||
|
|
@ -312,12 +272,16 @@ SELECT
|
|||
COALESCE(e.dialog_filter::text, '{}')::text AS dialog_filter_json,
|
||||
COALESCE(e.filter_order::text, '[]')::text AS filter_order_json,
|
||||
COALESCE(e.folder_peers::text, '[]')::text AS folder_peers_json,
|
||||
COALESCE(e.story_payload::text, '{}')::text AS story_payload_json,
|
||||
COALESCE(e.reaction_payload::text, '{}')::text AS reaction_payload_json,
|
||||
COALESCE(e.peer_type, '')::text AS event_peer_type,
|
||||
COALESCE(e.peer_id, 0)::bigint AS event_peer_id,
|
||||
e.filter_id,
|
||||
e.max_id,
|
||||
e.still_unread_count,
|
||||
e.channel_pts,
|
||||
e.tags_enabled,
|
||||
e.folder_id,
|
||||
COALESCE(m.box_id, 0)::int AS message_id,
|
||||
COALESCE(m.private_message_id, 0)::bigint AS private_message_id,
|
||||
COALESCE(m.owner_user_id, 0)::bigint AS owner_user_id,
|
||||
|
|
@ -325,6 +289,8 @@ SELECT
|
|||
COALESCE(m.peer_id, 0)::bigint AS peer_id,
|
||||
COALESCE(m.from_user_id, 0)::bigint AS from_user_id,
|
||||
COALESCE(m.message_date, 0)::int AS message_date,
|
||||
COALESCE(m.ttl_period, 0)::int AS ttl_period,
|
||||
COALESCE(m.expires_at, 0)::int AS expires_at,
|
||||
COALESCE(m.edit_date, 0)::int AS edit_date,
|
||||
COALESCE(m.outgoing, false)::boolean AS outgoing,
|
||||
COALESCE(m.body, '')::text AS body,
|
||||
|
|
@ -335,6 +301,7 @@ SELECT
|
|||
COALESCE(m.reply_to_peer_type, '')::text AS reply_to_peer_type,
|
||||
COALESCE(m.reply_to_peer_id, 0)::bigint AS reply_to_peer_id,
|
||||
COALESCE(m.reply_to_top_id, 0)::int AS reply_to_top_id,
|
||||
COALESCE(m.reply_to_story_id, 0)::int AS reply_to_story_id,
|
||||
COALESCE(m.quote_text, '')::text AS quote_text,
|
||||
COALESCE(m.quote_entities::text, '[]')::text AS quote_entities_json,
|
||||
COALESCE(m.quote_offset, 0)::int AS quote_offset,
|
||||
|
|
@ -342,9 +309,20 @@ SELECT
|
|||
COALESCE(m.fwd_from_peer_id, 0)::bigint AS fwd_from_peer_id,
|
||||
COALESCE(m.fwd_from_name, '')::text AS fwd_from_name,
|
||||
COALESCE(m.fwd_date, 0)::int AS fwd_date,
|
||||
COALESCE(m.fwd_saved_from_peer_type, '')::text AS fwd_saved_from_peer_type,
|
||||
COALESCE(m.fwd_saved_from_peer_id, 0)::bigint AS fwd_saved_from_peer_id,
|
||||
COALESCE(m.fwd_saved_from_msg_id, 0)::int AS fwd_saved_from_msg_id,
|
||||
COALESCE(m.saved_peer_type, '')::text AS saved_peer_type,
|
||||
COALESCE(m.saved_peer_id, 0)::bigint AS saved_peer_id,
|
||||
COALESCE(m.media::text, '{}')::text AS media_json,
|
||||
COALESCE(m.media_unread, false)::boolean AS media_unread,
|
||||
COALESCE(m.reaction_unread, false)::boolean AS reaction_unread,
|
||||
COALESCE(m.pinned, false)::boolean AS pinned,
|
||||
COALESCE(m.via_bot_id, 0)::bigint AS via_bot_id,
|
||||
COALESCE(m.grouped_id, 0)::bigint AS grouped_id,
|
||||
COALESCE(m.effect, 0)::bigint AS effect,
|
||||
COALESCE(m.reply_markup::text, '{}')::text AS reply_markup_json,
|
||||
COALESCE(m.rich_message::text, '{}')::text AS rich_message_json,
|
||||
COALESCE(peer_u.id, 0)::bigint AS peer_user_id,
|
||||
COALESCE(peer_u.access_hash, 0)::bigint AS peer_access_hash,
|
||||
COALESCE(peer_u.phone, '')::text AS peer_phone,
|
||||
|
|
@ -354,6 +332,11 @@ SELECT
|
|||
COALESCE(peer_u.country_code, '')::text AS peer_country_code,
|
||||
COALESCE(peer_u.verified, false)::boolean AS peer_verified,
|
||||
COALESCE(peer_u.support, false)::boolean AS peer_support,
|
||||
COALESCE(peer_u.is_bot, false)::boolean AS peer_is_bot,
|
||||
COALESCE(peer_u.bot_info_version, 0)::int AS peer_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM peer_u.premium_expires_at), 0)::bigint AS peer_premium_until,
|
||||
COALESCE(peer_u.emoji_status_document_id, 0)::bigint AS peer_emoji_status_document_id,
|
||||
COALESCE(peer_u.emoji_status_until, 0)::bigint AS peer_emoji_status_until,
|
||||
COALESCE(from_u.id, 0)::bigint AS from_user_user_id,
|
||||
COALESCE(from_u.access_hash, 0)::bigint AS from_user_access_hash,
|
||||
COALESCE(from_u.phone, '')::text AS from_user_phone,
|
||||
|
|
@ -363,6 +346,11 @@ SELECT
|
|||
COALESCE(from_u.country_code, '')::text AS from_user_country_code,
|
||||
COALESCE(from_u.verified, false)::boolean AS from_user_verified,
|
||||
COALESCE(from_u.support, false)::boolean AS from_user_support,
|
||||
COALESCE(from_u.is_bot, false)::boolean AS from_user_is_bot,
|
||||
COALESCE(from_u.bot_info_version, 0)::int AS from_user_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM from_u.premium_expires_at), 0)::bigint AS from_user_premium_until,
|
||||
COALESCE(from_u.emoji_status_document_id, 0)::bigint AS from_user_emoji_status_document_id,
|
||||
COALESCE(from_u.emoji_status_until, 0)::bigint AS from_user_emoji_status_until,
|
||||
COALESCE(fwd_u.id, 0)::bigint AS fwd_user_id,
|
||||
COALESCE(fwd_u.access_hash, 0)::bigint AS fwd_user_access_hash,
|
||||
COALESCE(fwd_u.phone, '')::text AS fwd_user_phone,
|
||||
|
|
@ -372,6 +360,11 @@ SELECT
|
|||
COALESCE(fwd_u.country_code, '')::text AS fwd_user_country_code,
|
||||
COALESCE(fwd_u.verified, false)::boolean AS fwd_user_verified,
|
||||
COALESCE(fwd_u.support, false)::boolean AS fwd_user_support,
|
||||
COALESCE(fwd_u.is_bot, false)::boolean AS fwd_user_is_bot,
|
||||
COALESCE(fwd_u.bot_info_version, 0)::int AS fwd_user_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM fwd_u.premium_expires_at), 0)::bigint AS fwd_user_premium_until,
|
||||
COALESCE(fwd_u.emoji_status_document_id, 0)::bigint AS fwd_user_emoji_status_document_id,
|
||||
COALESCE(fwd_u.emoji_status_until, 0)::bigint AS fwd_user_emoji_status_until,
|
||||
COALESCE(reply_u.id, 0)::bigint AS reply_user_id,
|
||||
COALESCE(reply_u.access_hash, 0)::bigint AS reply_user_access_hash,
|
||||
COALESCE(reply_u.phone, '')::text AS reply_user_phone,
|
||||
|
|
@ -381,54 +374,11 @@ SELECT
|
|||
COALESCE(reply_u.country_code, '')::text AS reply_user_country_code,
|
||||
COALESCE(reply_u.verified, false)::boolean AS reply_user_verified,
|
||||
COALESCE(reply_u.support, false)::boolean AS reply_user_support,
|
||||
COALESCE(fwd_ch.id, 0)::bigint AS fwd_channel_id,
|
||||
COALESCE(fwd_ch.access_hash, 0)::bigint AS fwd_channel_access_hash,
|
||||
COALESCE(fwd_ch.creator_user_id, 0)::bigint AS fwd_channel_creator_user_id,
|
||||
COALESCE(fwd_ch.title, '')::text AS fwd_channel_title,
|
||||
COALESCE(fwd_ch.about, '')::text AS fwd_channel_about,
|
||||
COALESCE(fwd_ch.username, '')::text AS fwd_channel_username,
|
||||
COALESCE(fwd_ch.broadcast, false)::boolean AS fwd_channel_broadcast,
|
||||
COALESCE(fwd_ch.megagroup, false)::boolean AS fwd_channel_megagroup,
|
||||
COALESCE(fwd_ch.forum, false)::boolean AS fwd_channel_forum,
|
||||
COALESCE(fwd_ch.noforwards, false)::boolean AS fwd_channel_noforwards,
|
||||
COALESCE(fwd_ch.signatures, false)::boolean AS fwd_channel_signatures,
|
||||
COALESCE(fwd_ch.pre_history_hidden, false)::boolean AS fwd_channel_pre_history_hidden,
|
||||
COALESCE(fwd_ch.slowmode_seconds, 0)::int AS fwd_channel_slowmode_seconds,
|
||||
COALESCE(fwd_ch.default_banned_rights::text, '{}')::text AS fwd_channel_default_banned_rights,
|
||||
COALESCE(fwd_ch.participants_count, 0)::int AS fwd_channel_participants_count,
|
||||
COALESCE(fwd_ch.admins_count, 0)::int AS fwd_channel_admins_count,
|
||||
COALESCE(fwd_ch.kicked_count, 0)::int AS fwd_channel_kicked_count,
|
||||
COALESCE(fwd_ch.banned_count, 0)::int AS fwd_channel_banned_count,
|
||||
COALESCE(fwd_ch.top_message_id, 0)::int AS fwd_channel_top_message_id,
|
||||
COALESCE(fwd_ch.pinned_message_id, 0)::int AS fwd_channel_pinned_message_id,
|
||||
COALESCE(fwd_ch.pts, 0)::int AS fwd_channel_pts,
|
||||
COALESCE(fwd_ch.ttl_period, 0)::int AS fwd_channel_ttl_period,
|
||||
COALESCE(fwd_ch.date, 0)::int AS fwd_channel_date,
|
||||
COALESCE(fwd_ch.deleted, false)::boolean AS fwd_channel_deleted,
|
||||
COALESCE(reply_ch.id, 0)::bigint AS reply_channel_id,
|
||||
COALESCE(reply_ch.access_hash, 0)::bigint AS reply_channel_access_hash,
|
||||
COALESCE(reply_ch.creator_user_id, 0)::bigint AS reply_channel_creator_user_id,
|
||||
COALESCE(reply_ch.title, '')::text AS reply_channel_title,
|
||||
COALESCE(reply_ch.about, '')::text AS reply_channel_about,
|
||||
COALESCE(reply_ch.username, '')::text AS reply_channel_username,
|
||||
COALESCE(reply_ch.broadcast, false)::boolean AS reply_channel_broadcast,
|
||||
COALESCE(reply_ch.megagroup, false)::boolean AS reply_channel_megagroup,
|
||||
COALESCE(reply_ch.forum, false)::boolean AS reply_channel_forum,
|
||||
COALESCE(reply_ch.noforwards, false)::boolean AS reply_channel_noforwards,
|
||||
COALESCE(reply_ch.signatures, false)::boolean AS reply_channel_signatures,
|
||||
COALESCE(reply_ch.pre_history_hidden, false)::boolean AS reply_channel_pre_history_hidden,
|
||||
COALESCE(reply_ch.slowmode_seconds, 0)::int AS reply_channel_slowmode_seconds,
|
||||
COALESCE(reply_ch.default_banned_rights::text, '{}')::text AS reply_channel_default_banned_rights,
|
||||
COALESCE(reply_ch.participants_count, 0)::int AS reply_channel_participants_count,
|
||||
COALESCE(reply_ch.admins_count, 0)::int AS reply_channel_admins_count,
|
||||
COALESCE(reply_ch.kicked_count, 0)::int AS reply_channel_kicked_count,
|
||||
COALESCE(reply_ch.banned_count, 0)::int AS reply_channel_banned_count,
|
||||
COALESCE(reply_ch.top_message_id, 0)::int AS reply_channel_top_message_id,
|
||||
COALESCE(reply_ch.pinned_message_id, 0)::int AS reply_channel_pinned_message_id,
|
||||
COALESCE(reply_ch.pts, 0)::int AS reply_channel_pts,
|
||||
COALESCE(reply_ch.ttl_period, 0)::int AS reply_channel_ttl_period,
|
||||
COALESCE(reply_ch.date, 0)::int AS reply_channel_date,
|
||||
COALESCE(reply_ch.deleted, false)::boolean AS reply_channel_deleted
|
||||
COALESCE(reply_u.is_bot, false)::boolean AS reply_user_is_bot,
|
||||
COALESCE(reply_u.bot_info_version, 0)::int AS reply_user_bot_info_version,
|
||||
COALESCE(EXTRACT(EPOCH FROM reply_u.premium_expires_at), 0)::bigint AS reply_user_premium_until,
|
||||
COALESCE(reply_u.emoji_status_document_id, 0)::bigint AS reply_user_emoji_status_document_id,
|
||||
COALESCE(reply_u.emoji_status_until, 0)::bigint AS reply_user_emoji_status_until
|
||||
FROM unnest(@user_ids::bigint[]) WITH ORDINALITY AS u(user_id, ord)
|
||||
JOIN unnest(@pts_list::int[]) WITH ORDINALITY AS p(pts, ord) USING (ord)
|
||||
JOIN user_update_events e ON e.user_id = u.user_id AND e.pts = p.pts
|
||||
|
|
@ -436,12 +386,10 @@ LEFT JOIN message_boxes m ON m.owner_user_id = e.user_id AND m.box_id = e.messag
|
|||
LEFT JOIN users peer_u ON m.peer_type = 'user' AND peer_u.id = m.peer_id
|
||||
LEFT JOIN users from_u ON from_u.id = m.from_user_id
|
||||
LEFT JOIN users fwd_u ON m.fwd_from_peer_type = 'user' AND fwd_u.id = m.fwd_from_peer_id
|
||||
LEFT JOIN users reply_u ON m.reply_to_peer_type = 'user' AND reply_u.id = m.reply_to_peer_id
|
||||
LEFT JOIN channels fwd_ch ON m.fwd_from_peer_type = 'channel' AND fwd_ch.id = m.fwd_from_peer_id
|
||||
LEFT JOIN channels reply_ch ON m.reply_to_peer_type = 'channel' AND reply_ch.id = m.reply_to_peer_id;
|
||||
LEFT JOIN users reply_u ON m.reply_to_peer_type = 'user' AND reply_u.id = m.reply_to_peer_id;
|
||||
|
||||
-- name: MarkDispatchDeliveredBatch :exec
|
||||
-- 批量删除一批已投递的 (target_user_id, id);target_user_id 入 WHERE 保证分区裁剪。
|
||||
-- 批量删除一批已投递的 (target_user_id, id);target_user_id 入 WHERE 命中唯一索引并避免串删。
|
||||
DELETE FROM dispatch_outbox d
|
||||
USING unnest(@target_user_ids::bigint[]) WITH ORDINALITY AS tu(target_user_id, ord)
|
||||
JOIN unnest(@ids::bigint[]) WITH ORDINALITY AS di(id, ord) USING (ord)
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue