owpengram-server/internal/store/postgres/sqlcgen/dialog.sql.go

2117 lines
60 KiB
Go
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: dialog.sql
package sqlcgen
import (
"context"
)
const advanceDialogReadInboxFloor = `-- name: AdvanceDialogReadInboxFloor :exec
UPDATE dialogs
SET read_inbox_max_id = GREATEST(read_inbox_max_id, $1::int),
updated_at = now()
WHERE user_id = $2
AND peer_type = $3
AND peer_id = $4
`
type AdvanceDialogReadInboxFloorParams struct {
ReadInboxMaxID int32
UserID int64
PeerType string
PeerID int64
}
func (q *Queries) AdvanceDialogReadInboxFloor(ctx context.Context, arg AdvanceDialogReadInboxFloorParams) error {
_, err := q.db.Exec(ctx, advanceDialogReadInboxFloor,
arg.ReadInboxMaxID,
arg.UserID,
arg.PeerType,
arg.PeerID,
)
return err
}
const clearDialogAfterHistoryDelete = `-- name: ClearDialogAfterHistoryDelete :exec
UPDATE dialogs d
SET
top_message_id = 0,
top_message_date = 0,
read_inbox_max_id = GREATEST(d.read_inbox_max_id, d.top_message_id),
read_outbox_max_id = GREATEST(d.read_outbox_max_id, d.top_message_id),
unread_count = 0,
unread_mark = false,
unread_mentions_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 = $1::bigint
AND d.peer_type = $2::text
AND d.peer_id = $3::bigint
`
type ClearDialogAfterHistoryDeleteParams struct {
UserID int64
PeerType string
PeerID int64
}
func (q *Queries) ClearDialogAfterHistoryDelete(ctx context.Context, arg ClearDialogAfterHistoryDeleteParams) error {
_, err := q.db.Exec(ctx, clearDialogAfterHistoryDelete, arg.UserID, arg.PeerType, arg.PeerID)
return err
}
const clearDialogDrafts = `-- name: ClearDialogDrafts :many
WITH doomed AS (
SELECT d.user_id, d.peer_type, d.peer_id, d.top_message_id
FROM dialog_drafts d
WHERE d.user_id = $1
ORDER BY d.date DESC, d.peer_type ASC, d.peer_id DESC, d.top_message_id DESC
LIMIT $2
),
deleted AS (
DELETE FROM dialog_drafts d
USING doomed
WHERE d.user_id = doomed.user_id
AND d.peer_type = doomed.peer_type
AND d.peer_id = doomed.peer_id
AND d.top_message_id = doomed.top_message_id
RETURNING d.draft::text AS draft_json
)
SELECT draft_json
FROM deleted
`
type ClearDialogDraftsParams struct {
UserID int64
LimitCount int32
}
func (q *Queries) ClearDialogDrafts(ctx context.Context, arg ClearDialogDraftsParams) ([]string, error) {
rows, err := q.db.Query(ctx, clearDialogDrafts, arg.UserID, arg.LimitCount)
if err != nil {
return nil, err
}
defer rows.Close()
var items []string
for rows.Next() {
var draft_json string
if err := rows.Scan(&draft_json); err != nil {
return nil, err
}
items = append(items, draft_json)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const clearPinnedDialogsNotInOrder = `-- name: ClearPinnedDialogsNotInOrder :exec
WITH requested AS (
SELECT
($3::text[])[i] AS peer_type,
($4::bigint[])[i] AS peer_id
FROM generate_subscripts($4::bigint[], 1) AS g(i)
WHERE i <= cardinality($3::text[])
)
UPDATE dialogs d
SET pinned = false,
pinned_order = 0,
updated_at = now()
WHERE d.user_id = $1::bigint
AND d.pinned
AND d.folder_id = $2::int
AND NOT EXISTS (
SELECT 1
FROM requested r
WHERE r.peer_type = d.peer_type
AND r.peer_id = d.peer_id
)
`
type ClearPinnedDialogsNotInOrderParams struct {
UserID int64
FolderID int32
PeerTypes []string
PeerIds []int64
}
func (q *Queries) ClearPinnedDialogsNotInOrder(ctx context.Context, arg ClearPinnedDialogsNotInOrderParams) error {
_, err := q.db.Exec(ctx, clearPinnedDialogsNotInOrder,
arg.UserID,
arg.FolderID,
arg.PeerTypes,
arg.PeerIds,
)
return err
}
const countArchiveUnreadDialogs = `-- name: CountArchiveUnreadDialogs :one
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
`
type CountArchiveUnreadDialogsRow struct {
UnreadPeers int32
UnreadMessages int32
}
// 归档folder_id=1未读聚合有未读或手动标记未读的会话数 + 未读消息总数。
func (q *Queries) CountArchiveUnreadDialogs(ctx context.Context, userID int64) (CountArchiveUnreadDialogsRow, error) {
row := q.db.QueryRow(ctx, countArchiveUnreadDialogs, userID)
var i CountArchiveUnreadDialogsRow
err := row.Scan(&i.UnreadPeers, &i.UnreadMessages)
return i, err
}
const deleteDialogByPeer = `-- name: DeleteDialogByPeer :exec
WITH dropped_drafts AS (
-- 删除会话同时丢弃该 peer 的云草稿,避免对端重建会话后旧草稿复活。
DELETE FROM dialog_drafts dd
WHERE dd.user_id = $1::bigint
AND dd.peer_type = $2::text
AND dd.peer_id = $3::bigint
)
DELETE FROM dialogs d
WHERE d.user_id = $1::bigint
AND d.peer_type = $2::text
AND d.peer_id = $3::bigint
`
type DeleteDialogByPeerParams struct {
UserID int64
PeerType string
PeerID int64
}
func (q *Queries) DeleteDialogByPeer(ctx context.Context, arg DeleteDialogByPeerParams) error {
_, err := q.db.Exec(ctx, deleteDialogByPeer, arg.UserID, arg.PeerType, arg.PeerID)
return err
}
const deleteDialogDraft = `-- name: DeleteDialogDraft :one
WITH deleted AS (
DELETE FROM dialog_drafts
WHERE user_id = $1
AND peer_type = $2
AND peer_id = $3
AND top_message_id = $4
RETURNING user_id
)
SELECT EXISTS (SELECT 1 FROM deleted)::boolean AS changed
`
type DeleteDialogDraftParams struct {
UserID int64
PeerType string
PeerID int64
TopMessageID int32
}
func (q *Queries) DeleteDialogDraft(ctx context.Context, arg DeleteDialogDraftParams) (bool, error) {
row := q.db.QueryRow(ctx, deleteDialogDraft,
arg.UserID,
arg.PeerType,
arg.PeerID,
arg.TopMessageID,
)
var changed bool
err := row.Scan(&changed)
return changed, err
}
const deleteDialogFolder = `-- name: DeleteDialogFolder :exec
DELETE FROM dialog_filters
WHERE user_id = $1
AND filter_id = $2
`
type DeleteDialogFolderParams struct {
UserID int64
FilterID int32
}
func (q *Queries) DeleteDialogFolder(ctx context.Context, arg DeleteDialogFolderParams) error {
_, err := q.db.Exec(ctx, deleteDialogFolder, arg.UserID, arg.FilterID)
return err
}
const editDialogPeerFolders = `-- name: EditDialogPeerFolders :exec
WITH requested AS (
SELECT
($2::text[])[i] AS peer_type,
($3::bigint[])[i] AS peer_id,
($4::int[])[i] AS folder_id
FROM generate_subscripts($3::bigint[], 1) AS g(i)
WHERE i <= cardinality($2::text[])
AND i <= cardinality($4::int[])
),
deduped AS (
SELECT DISTINCT ON (peer_type, peer_id)
peer_type,
peer_id,
folder_id
FROM requested
WHERE folder_id IN (0, 1)
ORDER BY peer_type, peer_id
)
UPDATE dialogs d
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 = $1::bigint
AND d.peer_type = deduped.peer_type
AND d.peer_id = deduped.peer_id
`
type EditDialogPeerFoldersParams struct {
UserID int64
PeerTypes []string
PeerIds []int64
FolderIds []int32
}
// 换 folder 时清 pinnedTDesktop History::setFolderPointer 在归档/还原时
// 本地无条件 unpin服务端保留旧 pin 会在下次 getDialogs 时把状态漂移回来。
func (q *Queries) EditDialogPeerFolders(ctx context.Context, arg EditDialogPeerFoldersParams) error {
_, err := q.db.Exec(ctx, editDialogPeerFolders,
arg.UserID,
arg.PeerTypes,
arg.PeerIds,
arg.FolderIds,
)
return err
}
const getDialogArchivePinned = `-- name: GetDialogArchivePinned :one
SELECT archive_pinned
FROM dialog_filter_settings
WHERE user_id = $1
`
func (q *Queries) GetDialogArchivePinned(ctx context.Context, userID int64) (bool, error) {
row := q.db.QueryRow(ctx, getDialogArchivePinned, userID)
var archive_pinned bool
err := row.Scan(&archive_pinned)
return archive_pinned, err
}
const getDialogFolder = `-- name: GetDialogFolder :one
SELECT
filter_id,
is_chatlist,
filter::text AS filter_json
FROM dialog_filters
WHERE user_id = $1
AND filter_id = $2
`
type GetDialogFolderParams struct {
UserID int64
FilterID int32
}
type GetDialogFolderRow struct {
FilterID int32
IsChatlist bool
FilterJson string
}
func (q *Queries) GetDialogFolder(ctx context.Context, arg GetDialogFolderParams) (GetDialogFolderRow, error) {
row := q.db.QueryRow(ctx, getDialogFolder, arg.UserID, arg.FilterID)
var i GetDialogFolderRow
err := row.Scan(&i.FilterID, &i.IsChatlist, &i.FilterJson)
return i, err
}
const getDialogFolderTags = `-- name: GetDialogFolderTags :one
SELECT tags_enabled
FROM dialog_filter_settings
WHERE user_id = $1
`
func (q *Queries) GetDialogFolderTags(ctx context.Context, userID int64) (bool, error) {
row := q.db.QueryRow(ctx, getDialogFolderTags, userID)
var tags_enabled bool
err := row.Scan(&tags_enabled)
return tags_enabled, err
}
const getPeerSettingsBarHidden = `-- name: GetPeerSettingsBarHidden :one
SELECT hidden_peer_settings_bar
FROM dialogs
WHERE user_id = $1
AND peer_type = $2
AND peer_id = $3
`
type GetPeerSettingsBarHiddenParams struct {
UserID int64
PeerType string
PeerID int64
}
func (q *Queries) GetPeerSettingsBarHidden(ctx context.Context, arg GetPeerSettingsBarHiddenParams) (bool, error) {
row := q.db.QueryRow(ctx, getPeerSettingsBarHidden, arg.UserID, arg.PeerType, arg.PeerID)
var hidden_peer_settings_bar bool
err := row.Scan(&hidden_peer_settings_bar)
return hidden_peer_settings_bar, err
}
const listDialogDrafts = `-- name: ListDialogDrafts :many
SELECT draft::text AS draft_json
FROM dialog_drafts
WHERE user_id = $1
ORDER BY date DESC, peer_type ASC, peer_id DESC, top_message_id DESC
LIMIT $2
`
type ListDialogDraftsParams struct {
UserID int64
LimitCount int32
}
func (q *Queries) ListDialogDrafts(ctx context.Context, arg ListDialogDraftsParams) ([]string, error) {
rows, err := q.db.Query(ctx, listDialogDrafts, arg.UserID, arg.LimitCount)
if err != nil {
return nil, err
}
defer rows.Close()
var items []string
for rows.Next() {
var draft_json string
if err := rows.Scan(&draft_json); err != nil {
return nil, err
}
items = append(items, draft_json)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listDialogFolders = `-- name: ListDialogFolders :many
SELECT
filter_id,
is_chatlist,
filter::text AS filter_json
FROM dialog_filters
WHERE user_id = $1
ORDER BY order_value ASC, filter_id ASC
`
type ListDialogFoldersRow struct {
FilterID int32
IsChatlist bool
FilterJson string
}
func (q *Queries) ListDialogFolders(ctx context.Context, userID int64) ([]ListDialogFoldersRow, error) {
rows, err := q.db.Query(ctx, listDialogFolders, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListDialogFoldersRow
for rows.Next() {
var i ListDialogFoldersRow
if err := rows.Scan(&i.FilterID, &i.IsChatlist, &i.FilterJson); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listDialogSummaryByUser = `-- name: ListDialogSummaryByUser :many
SELECT
d.peer_type,
d.peer_id,
d.folder_id,
d.top_message_id,
d.top_message_date,
d.read_inbox_max_id,
d.read_outbox_max_id,
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,
d.hidden_peer_settings_bar
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 $2::boolean AND d.folder_id = 0)
OR (
$2::boolean
AND $3::int < 2
AND d.folder_id = $3::int
)
OR (
$3::int >= 2
AND NOT ($4::boolean AND d.folder_id = 1)
AND NOT ($5::boolean AND d.unread_count = 0 AND NOT d.unread_mark)
AND NOT EXISTS (
SELECT 1
FROM (
SELECT fpt.peer_type, fpi.peer_id
FROM unnest($6::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
JOIN unnest($7::bigint[]) WITH ORDINALITY AS fpi(peer_id, ord) USING (ord)
) fp
WHERE fp.peer_type = d.peer_type AND fp.peer_id = d.peer_id
)
AND (
EXISTS (
SELECT 1
FROM (
SELECT fpt.peer_type, fpi.peer_id
FROM unnest($8::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
JOIN unnest($9::bigint[]) WITH ORDINALITY AS fpi(peer_id, ord) USING (ord)
) fp
WHERE fp.peer_type = d.peer_type AND fp.peer_id = d.peer_id
)
OR EXISTS (
SELECT 1
FROM (
SELECT fpt.peer_type, fpi.peer_id
FROM unnest($10::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
JOIN unnest($11::bigint[]) WITH ORDINALITY AS fpi(peer_id, ord) USING (ord)
) fp
WHERE fp.peer_type = d.peer_type AND fp.peer_id = d.peer_id
)
OR ($12::boolean AND c.contact_user_id IS NOT NULL)
OR ($13::boolean AND c.contact_user_id IS NULL)
)
)
)
AND (NOT $14::boolean OR d.pinned)
AND (NOT $15::boolean OR NOT d.pinned)
ORDER BY
d.pinned DESC,
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
`
type ListDialogSummaryByUserParams struct {
UserID int64
HasFolderID bool
FolderID int32
FolderExcludeArchived bool
FolderExcludeRead bool
FolderExcludePeerTypes []string
FolderExcludePeerIds []int64
FolderIncludePeerTypes []string
FolderIncludePeerIds []int64
FolderPinnedPeerTypes []string
FolderPinnedPeerIds []int64
FolderContacts bool
FolderNonContacts bool
PinnedOnly bool
ExcludePinned bool
}
type ListDialogSummaryByUserRow struct {
PeerType string
PeerID int64
FolderID int32
TopMessageID int32
TopMessageDate int32
ReadInboxMaxID int32
ReadOutboxMaxID int32
UnreadCount int32
UnreadMentionsCount int32
UnreadReactionsCount int32
TtlPeriod int32
ThemeEmoticon string
HasScheduled bool
Pinned bool
PinnedOrder int32
UnreadMark bool
HiddenPeerSettingsBar bool
}
func (q *Queries) ListDialogSummaryByUser(ctx context.Context, arg ListDialogSummaryByUserParams) ([]ListDialogSummaryByUserRow, error) {
rows, err := q.db.Query(ctx, listDialogSummaryByUser,
arg.UserID,
arg.HasFolderID,
arg.FolderID,
arg.FolderExcludeArchived,
arg.FolderExcludeRead,
arg.FolderExcludePeerTypes,
arg.FolderExcludePeerIds,
arg.FolderIncludePeerTypes,
arg.FolderIncludePeerIds,
arg.FolderPinnedPeerTypes,
arg.FolderPinnedPeerIds,
arg.FolderContacts,
arg.FolderNonContacts,
arg.PinnedOnly,
arg.ExcludePinned,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListDialogSummaryByUserRow
for rows.Next() {
var i ListDialogSummaryByUserRow
if err := rows.Scan(
&i.PeerType,
&i.PeerID,
&i.FolderID,
&i.TopMessageID,
&i.TopMessageDate,
&i.ReadInboxMaxID,
&i.ReadOutboxMaxID,
&i.UnreadCount,
&i.UnreadMentionsCount,
&i.UnreadReactionsCount,
&i.TtlPeriod,
&i.ThemeEmoticon,
&i.HasScheduled,
&i.Pinned,
&i.PinnedOrder,
&i.UnreadMark,
&i.HiddenPeerSettingsBar,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listDialogUnreadMarks = `-- name: ListDialogUnreadMarks :many
SELECT
peer_type,
peer_id
FROM dialogs
WHERE user_id = $1
AND unread_mark
ORDER BY top_message_date DESC, top_message_id DESC, peer_id DESC
`
type ListDialogUnreadMarksRow struct {
PeerType string
PeerID int64
}
func (q *Queries) ListDialogUnreadMarks(ctx context.Context, userID int64) ([]ListDialogUnreadMarksRow, error) {
rows, err := q.db.Query(ctx, listDialogUnreadMarks, userID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListDialogUnreadMarksRow
for rows.Next() {
var i ListDialogUnreadMarksRow
if err := rows.Scan(&i.PeerType, &i.PeerID); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listDialogsByPeers = `-- name: ListDialogsByPeers :many
WITH requested AS (
SELECT
($1::text[])[i] AS peer_type,
($2::bigint[])[i] AS peer_id,
i::int AS ord
FROM generate_subscripts($2::bigint[], 1) AS g(i)
WHERE i <= cardinality($1::text[])
),
deduped AS (
SELECT DISTINCT ON (peer_type, peer_id)
peer_type,
peer_id,
ord
FROM requested
ORDER BY peer_type, peer_id, ord
),
base AS (
SELECT
$3::bigint AS user_id,
r.peer_type,
r.peer_id,
COALESCE(d.folder_id, 0)::int AS folder_id,
COALESCE(d.top_message_id, 0)::int AS top_message_id,
COALESCE(d.top_message_date, 0)::int AS top_message_date,
COALESCE(d.read_inbox_max_id, 0)::int AS read_inbox_max_id,
COALESCE(d.read_outbox_max_id, 0)::int AS read_outbox_max_id,
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,
COALESCE(d.hidden_peer_settings_bar, false)::boolean AS hidden_peer_settings_bar,
COALESCE(u.id, 0)::bigint AS peer_user_id,
COALESCE(u.access_hash, 0)::bigint AS peer_access_hash,
COALESCE(NULLIF(c.contact_phone, ''), u.phone, '')::text AS peer_phone,
COALESCE(NULLIF(c.contact_first_name, ''), u.first_name, '')::text AS peer_first_name,
COALESCE(c.contact_last_name, u.last_name, '')::text AS peer_last_name,
COALESCE(u.username, '')::text AS peer_username,
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
ON d.user_id = $3::bigint
AND d.peer_type = r.peer_type
AND d.peer_id = r.peer_id
LEFT JOIN users u ON r.peer_type = 'user' AND u.id = r.peer_id
LEFT JOIN contacts c ON r.peer_type = 'user' AND c.user_id = $3::bigint AND c.contact_user_id = r.peer_id
LEFT JOIN message_boxes m ON m.owner_user_id = $3::bigint AND m.box_id = d.top_message_id AND NOT m.deleted
)
SELECT
user_id,
peer_type::text AS peer_type,
peer_id::bigint AS peer_id,
folder_id,
top_message_id,
top_message_date,
read_inbox_max_id,
read_outbox_max_id,
unread_count,
unread_mentions_count,
unread_reactions_count,
ttl_period,
theme_emoticon,
has_scheduled,
pinned,
pinned_order,
unread_mark,
hidden_peer_settings_bar,
peer_user_id,
peer_access_hash,
peer_phone,
peer_first_name,
peer_last_name,
peer_username,
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_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
`
type ListDialogsByPeersParams struct {
PeerTypes []string
PeerIds []int64
UserID int64
}
type ListDialogsByPeersRow struct {
UserID int64
PeerType string
PeerID int64
FolderID int32
TopMessageID int32
TopMessageDate int32
ReadInboxMaxID int32
ReadOutboxMaxID int32
UnreadCount int32
UnreadMentionsCount int32
UnreadReactionsCount int32
TtlPeriod int32
ThemeEmoticon string
HasScheduled bool
Pinned bool
PinnedOrder int32
UnreadMark bool
HiddenPeerSettingsBar bool
PeerUserID int64
PeerAccessHash int64
PeerPhone string
PeerFirstName string
PeerLastName string
PeerUsername string
PeerCountryCode string
PeerVerified bool
PeerSupport bool
PeerIsBot bool
PeerBotInfoVersion int32
PeerPremiumUntil int64
PeerEmojiStatusDocumentID int64
PeerEmojiStatusUntil int64
PeerLastSeenAt int64
PeerContact bool
PeerMutual bool
MessageID int32
MessagePrivateMessageID int64
MessageFromUserID int64
MessageDate int32
MessageOutgoing bool
MessageBody string
MessageEntitiesJson string
MessageMediaJson string
MessageTtlPeriod int32
MessageExpiresAt int32
MessageEditDate int32
MessageSilent bool
MessageNoforwards bool
MessageReplyToMsgID int32
MessageReplyToPeerType string
MessageReplyToPeerID int64
MessageReplyToTopID int32
MessageReplyToStoryID int32
MessageQuoteText string
MessageQuoteEntitiesJson string
MessageQuoteOffset int32
MessageFwdFromPeerType string
MessageFwdFromPeerID int64
MessageFwdFromName string
MessageFwdDate int32
MessageFwdSavedFromPeerType string
MessageFwdSavedFromPeerID int64
MessageFwdSavedFromMsgID int32
MessageSavedPeerType string
MessageSavedPeerID int64
MessageMediaUnread bool
MessageReactionUnread bool
MessageViaBotID int64
MessageGroupedID int64
MessageEffect int64
MessageReplyMarkupJson string
MessageRichMessageJson string
MessagePinned bool
}
func (q *Queries) ListDialogsByPeers(ctx context.Context, arg ListDialogsByPeersParams) ([]ListDialogsByPeersRow, error) {
rows, err := q.db.Query(ctx, listDialogsByPeers, arg.PeerTypes, arg.PeerIds, arg.UserID)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListDialogsByPeersRow
for rows.Next() {
var i ListDialogsByPeersRow
if err := rows.Scan(
&i.UserID,
&i.PeerType,
&i.PeerID,
&i.FolderID,
&i.TopMessageID,
&i.TopMessageDate,
&i.ReadInboxMaxID,
&i.ReadOutboxMaxID,
&i.UnreadCount,
&i.UnreadMentionsCount,
&i.UnreadReactionsCount,
&i.TtlPeriod,
&i.ThemeEmoticon,
&i.HasScheduled,
&i.Pinned,
&i.PinnedOrder,
&i.UnreadMark,
&i.HiddenPeerSettingsBar,
&i.PeerUserID,
&i.PeerAccessHash,
&i.PeerPhone,
&i.PeerFirstName,
&i.PeerLastName,
&i.PeerUsername,
&i.PeerCountryCode,
&i.PeerVerified,
&i.PeerSupport,
&i.PeerIsBot,
&i.PeerBotInfoVersion,
&i.PeerPremiumUntil,
&i.PeerEmojiStatusDocumentID,
&i.PeerEmojiStatusUntil,
&i.PeerLastSeenAt,
&i.PeerContact,
&i.PeerMutual,
&i.MessageID,
&i.MessagePrivateMessageID,
&i.MessageFromUserID,
&i.MessageDate,
&i.MessageOutgoing,
&i.MessageBody,
&i.MessageEntitiesJson,
&i.MessageMediaJson,
&i.MessageTtlPeriod,
&i.MessageExpiresAt,
&i.MessageEditDate,
&i.MessageSilent,
&i.MessageNoforwards,
&i.MessageReplyToMsgID,
&i.MessageReplyToPeerType,
&i.MessageReplyToPeerID,
&i.MessageReplyToTopID,
&i.MessageReplyToStoryID,
&i.MessageQuoteText,
&i.MessageQuoteEntitiesJson,
&i.MessageQuoteOffset,
&i.MessageFwdFromPeerType,
&i.MessageFwdFromPeerID,
&i.MessageFwdFromName,
&i.MessageFwdDate,
&i.MessageFwdSavedFromPeerType,
&i.MessageFwdSavedFromPeerID,
&i.MessageFwdSavedFromMsgID,
&i.MessageSavedPeerType,
&i.MessageSavedPeerID,
&i.MessageMediaUnread,
&i.MessageReactionUnread,
&i.MessageViaBotID,
&i.MessageGroupedID,
&i.MessageEffect,
&i.MessageReplyMarkupJson,
&i.MessageRichMessageJson,
&i.MessagePinned,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const listDialogsByUser = `-- name: ListDialogsByUser :many
WITH base AS (
SELECT
d.user_id,
d.peer_type,
d.peer_id,
d.folder_id,
d.top_message_id,
d.top_message_date,
d.read_inbox_max_id,
d.read_outbox_max_id,
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,
d.hidden_peer_settings_bar,
COALESCE(u.id, 0)::bigint AS peer_user_id,
COALESCE(u.access_hash, 0)::bigint AS peer_access_hash,
COALESCE(NULLIF(c.contact_phone, ''), u.phone, '')::text AS peer_phone,
COALESCE(NULLIF(c.contact_first_name, ''), u.first_name, '')::text AS peer_first_name,
COALESCE(c.contact_last_name, u.last_name, '')::text AS peer_last_name,
COALESCE(u.username, '')::text AS peer_username,
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
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 (
-- 不带 folder_id flag 视为主列表folder 0官方语义下归档对话只以
-- dialogFolder 聚合条目出现在主列表DrKLO Android 主列表请求不设 flag。
(NOT $3::boolean AND d.folder_id = 0)
OR (
$3::boolean
AND $4::int < 2
AND d.folder_id = $4::int
)
OR (
$4::int >= 2
AND NOT ($5::boolean AND d.folder_id = 1)
AND NOT ($6::boolean AND d.unread_count = 0 AND NOT d.unread_mark)
AND NOT EXISTS (
SELECT 1
FROM (
SELECT fpt.peer_type, fpi.peer_id
FROM unnest($7::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
JOIN unnest($8::bigint[]) WITH ORDINALITY AS fpi(peer_id, ord) USING (ord)
) fp
WHERE fp.peer_type = d.peer_type AND fp.peer_id = d.peer_id
)
AND (
EXISTS (
SELECT 1
FROM (
SELECT fpt.peer_type, fpi.peer_id
FROM unnest($9::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
JOIN unnest($10::bigint[]) WITH ORDINALITY AS fpi(peer_id, ord) USING (ord)
) fp
WHERE fp.peer_type = d.peer_type AND fp.peer_id = d.peer_id
)
OR EXISTS (
SELECT 1
FROM (
SELECT fpt.peer_type, fpi.peer_id
FROM unnest($11::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
JOIN unnest($12::bigint[]) WITH ORDINALITY AS fpi(peer_id, ord) USING (ord)
) fp
WHERE fp.peer_type = d.peer_type AND fp.peer_id = d.peer_id
)
OR ($13::boolean AND c.contact_user_id IS NOT NULL)
OR ($14::boolean AND c.contact_user_id IS NULL)
)
)
)
AND (NOT $15::boolean OR d.pinned)
AND (NOT $16::boolean OR NOT d.pinned)
),
paged AS (
SELECT user_id, peer_type, peer_id, folder_id, top_message_id, top_message_date, read_inbox_max_id, read_outbox_max_id, unread_count, unread_mentions_count, unread_reactions_count, ttl_period, theme_emoticon, has_scheduled, pinned, pinned_order, unread_mark, hidden_peer_settings_bar, peer_user_id, peer_access_hash, peer_phone, peer_first_name, peer_last_name, peer_username, 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_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
WHERE (
($17::int <= 0 AND $18::int <= 0)
OR (
$17::int > 0
AND (
top_message_date < $17::int
OR (
top_message_date = $17::int
AND (
$18::int <= 0
OR top_message_id < $18::int
OR (
top_message_id = $18::int
AND $19::boolean
AND peer_id < $20::bigint
)
)
)
)
)
OR (
$17::int <= 0
AND $18::int > 0
AND (
top_message_id < $18::int
OR (
top_message_id = $18::int
AND $19::boolean
AND peer_id < $20::bigint
)
)
)
)
)
SELECT
user_id,
peer_type::text AS peer_type,
peer_id::bigint AS peer_id,
folder_id,
top_message_id,
top_message_date,
read_inbox_max_id,
read_outbox_max_id,
unread_count,
unread_mentions_count,
unread_reactions_count,
ttl_period,
theme_emoticon,
has_scheduled,
pinned,
pinned_order,
unread_mark,
hidden_peer_settings_bar,
peer_user_id,
peer_access_hash,
peer_phone,
peer_first_name,
peer_last_name,
peer_username,
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_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(pinned_order, 0) ELSE 0 END DESC,
top_message_date DESC,
top_message_id DESC,
peer_id DESC
LIMIT $2
`
type ListDialogsByUserParams struct {
UserID int64
LimitCount int32
HasFolderID bool
FolderID int32
FolderExcludeArchived bool
FolderExcludeRead bool
FolderExcludePeerTypes []string
FolderExcludePeerIds []int64
FolderIncludePeerTypes []string
FolderIncludePeerIds []int64
FolderPinnedPeerTypes []string
FolderPinnedPeerIds []int64
FolderContacts bool
FolderNonContacts bool
PinnedOnly bool
ExcludePinned bool
OffsetDate int32
OffsetID int32
HasOffsetPeer bool
OffsetPeerID int64
}
type ListDialogsByUserRow struct {
UserID int64
PeerType string
PeerID int64
FolderID int32
TopMessageID int32
TopMessageDate int32
ReadInboxMaxID int32
ReadOutboxMaxID int32
UnreadCount int32
UnreadMentionsCount int32
UnreadReactionsCount int32
TtlPeriod int32
ThemeEmoticon string
HasScheduled bool
Pinned bool
PinnedOrder int32
UnreadMark bool
HiddenPeerSettingsBar bool
PeerUserID int64
PeerAccessHash int64
PeerPhone string
PeerFirstName string
PeerLastName string
PeerUsername string
PeerCountryCode string
PeerVerified bool
PeerSupport bool
PeerIsBot bool
PeerBotInfoVersion int32
PeerPremiumUntil int64
PeerEmojiStatusDocumentID int64
PeerEmojiStatusUntil int64
PeerLastSeenAt int64
PeerContact bool
PeerMutual bool
MessageID int32
MessagePrivateMessageID int64
MessageFromUserID int64
MessageDate int32
MessageOutgoing bool
MessageBody string
MessageEntitiesJson string
MessageMediaJson string
MessageTtlPeriod int32
MessageExpiresAt int32
MessageEditDate int32
MessageSilent bool
MessageNoforwards bool
MessageReplyToMsgID int32
MessageReplyToPeerType string
MessageReplyToPeerID int64
MessageReplyToTopID int32
MessageReplyToStoryID int32
MessageQuoteText string
MessageQuoteEntitiesJson string
MessageQuoteOffset int32
MessageFwdFromPeerType string
MessageFwdFromPeerID int64
MessageFwdFromName string
MessageFwdDate int32
MessageFwdSavedFromPeerType string
MessageFwdSavedFromPeerID int64
MessageFwdSavedFromMsgID int32
MessageSavedPeerType string
MessageSavedPeerID int64
MessageMediaUnread bool
MessageReactionUnread bool
MessageViaBotID int64
MessageGroupedID int64
MessageEffect int64
MessageReplyMarkupJson string
MessageRichMessageJson string
MessagePinned bool
}
func (q *Queries) ListDialogsByUser(ctx context.Context, arg ListDialogsByUserParams) ([]ListDialogsByUserRow, error) {
rows, err := q.db.Query(ctx, listDialogsByUser,
arg.UserID,
arg.LimitCount,
arg.HasFolderID,
arg.FolderID,
arg.FolderExcludeArchived,
arg.FolderExcludeRead,
arg.FolderExcludePeerTypes,
arg.FolderExcludePeerIds,
arg.FolderIncludePeerTypes,
arg.FolderIncludePeerIds,
arg.FolderPinnedPeerTypes,
arg.FolderPinnedPeerIds,
arg.FolderContacts,
arg.FolderNonContacts,
arg.PinnedOnly,
arg.ExcludePinned,
arg.OffsetDate,
arg.OffsetID,
arg.HasOffsetPeer,
arg.OffsetPeerID,
)
if err != nil {
return nil, err
}
defer rows.Close()
var items []ListDialogsByUserRow
for rows.Next() {
var i ListDialogsByUserRow
if err := rows.Scan(
&i.UserID,
&i.PeerType,
&i.PeerID,
&i.FolderID,
&i.TopMessageID,
&i.TopMessageDate,
&i.ReadInboxMaxID,
&i.ReadOutboxMaxID,
&i.UnreadCount,
&i.UnreadMentionsCount,
&i.UnreadReactionsCount,
&i.TtlPeriod,
&i.ThemeEmoticon,
&i.HasScheduled,
&i.Pinned,
&i.PinnedOrder,
&i.UnreadMark,
&i.HiddenPeerSettingsBar,
&i.PeerUserID,
&i.PeerAccessHash,
&i.PeerPhone,
&i.PeerFirstName,
&i.PeerLastName,
&i.PeerUsername,
&i.PeerCountryCode,
&i.PeerVerified,
&i.PeerSupport,
&i.PeerIsBot,
&i.PeerBotInfoVersion,
&i.PeerPremiumUntil,
&i.PeerEmojiStatusDocumentID,
&i.PeerEmojiStatusUntil,
&i.PeerLastSeenAt,
&i.PeerContact,
&i.PeerMutual,
&i.MessageID,
&i.MessagePrivateMessageID,
&i.MessageFromUserID,
&i.MessageDate,
&i.MessageOutgoing,
&i.MessageBody,
&i.MessageEntitiesJson,
&i.MessageMediaJson,
&i.MessageTtlPeriod,
&i.MessageExpiresAt,
&i.MessageEditDate,
&i.MessageSilent,
&i.MessageNoforwards,
&i.MessageReplyToMsgID,
&i.MessageReplyToPeerType,
&i.MessageReplyToPeerID,
&i.MessageReplyToTopID,
&i.MessageReplyToStoryID,
&i.MessageQuoteText,
&i.MessageQuoteEntitiesJson,
&i.MessageQuoteOffset,
&i.MessageFwdFromPeerType,
&i.MessageFwdFromPeerID,
&i.MessageFwdFromName,
&i.MessageFwdDate,
&i.MessageFwdSavedFromPeerType,
&i.MessageFwdSavedFromPeerID,
&i.MessageFwdSavedFromMsgID,
&i.MessageSavedPeerType,
&i.MessageSavedPeerID,
&i.MessageMediaUnread,
&i.MessageReactionUnread,
&i.MessageViaBotID,
&i.MessageGroupedID,
&i.MessageEffect,
&i.MessageReplyMarkupJson,
&i.MessageRichMessageJson,
&i.MessagePinned,
); err != nil {
return nil, err
}
items = append(items, i)
}
if err := rows.Err(); err != nil {
return nil, err
}
return items, nil
}
const markDialogRead = `-- name: MarkDialogRead :one
WITH target AS (
SELECT
d.user_id,
d.peer_type,
d.peer_id,
d.top_message_id,
d.read_inbox_max_id,
d.unread_count,
LEAST(
d.top_message_id,
CASE WHEN $4::int > 0 THEN $4::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
AND d.peer_id = $3
),
updated AS (
UPDATE dialogs d
SET
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_mark = false,
unread_mentions_count = 0,
updated_at = now()
FROM target
WHERE d.user_id = target.user_id
AND d.peer_type = target.peer_type
AND d.peer_id = target.peer_id
RETURNING
d.user_id,
d.peer_type,
d.peer_id,
d.read_inbox_max_id,
d.unread_count,
(
target.unread_count > 0
OR target.requested_read_max_id > target.read_inbox_max_id
)::boolean AS changed
)
SELECT
user_id,
peer_type,
peer_id,
read_inbox_max_id,
unread_count,
changed
FROM updated
`
type MarkDialogReadParams struct {
UserID int64
PeerType string
PeerID int64
MaxID int32
}
type MarkDialogReadRow struct {
UserID int64
PeerType string
PeerID int64
ReadInboxMaxID int32
UnreadCount int32
Changed bool
}
func (q *Queries) MarkDialogRead(ctx context.Context, arg MarkDialogReadParams) (MarkDialogReadRow, error) {
row := q.db.QueryRow(ctx, markDialogRead,
arg.UserID,
arg.PeerType,
arg.PeerID,
arg.MaxID,
)
var i MarkDialogReadRow
err := row.Scan(
&i.UserID,
&i.PeerType,
&i.PeerID,
&i.ReadInboxMaxID,
&i.UnreadCount,
&i.Changed,
)
return i, err
}
const refreshDialogAfterMessageDelete = `-- name: RefreshDialogAfterMessageDelete :exec
UPDATE dialogs d
SET
top_message_id = $1::int,
top_message_date = $2::int,
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 > d.read_inbox_max_id
),
unread_mentions_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 = $3::bigint
AND d.peer_type = $4::text
AND d.peer_id = $5::bigint
`
type RefreshDialogAfterMessageDeleteParams struct {
TopMessageID int32
TopMessageDate int32
UserID int64
PeerType string
PeerID int64
}
func (q *Queries) RefreshDialogAfterMessageDelete(ctx context.Context, arg RefreshDialogAfterMessageDeleteParams) error {
_, err := q.db.Exec(ctx, refreshDialogAfterMessageDelete,
arg.TopMessageID,
arg.TopMessageDate,
arg.UserID,
arg.PeerType,
arg.PeerID,
)
return err
}
const reorderDialogFolders = `-- name: ReorderDialogFolders :exec
WITH requested AS (
SELECT filter_id, ord::int AS order_value
FROM unnest($2::int[]) WITH ORDINALITY AS t(filter_id, ord)
),
deduped AS (
SELECT DISTINCT ON (filter_id)
filter_id,
order_value
FROM requested
WHERE filter_id >= 2
ORDER BY filter_id, order_value
)
UPDATE dialog_filters f
SET order_value = deduped.order_value,
updated_at = now()
FROM deduped
WHERE f.user_id = $1::bigint
AND f.filter_id = deduped.filter_id
`
type ReorderDialogFoldersParams struct {
UserID int64
FilterIds []int32
}
func (q *Queries) ReorderDialogFolders(ctx context.Context, arg ReorderDialogFoldersParams) error {
_, err := q.db.Exec(ctx, reorderDialogFolders, arg.UserID, arg.FilterIds)
return err
}
const reorderPinnedDialogs = `-- name: ReorderPinnedDialogs :exec
WITH requested AS (
SELECT
($3::text[])[i] AS peer_type,
($4::bigint[])[i] AS peer_id,
i::int AS pos
FROM generate_subscripts($4::bigint[], 1) AS g(i)
WHERE i <= cardinality($3::text[])
),
deduped AS (
-- 请求数组首位是置顶区最顶部;统一编码为"值越大越靠前",与频道
-- reorder、toggle 的 MAX+1 分配以及合并层排序方向一致。
SELECT DISTINCT ON (peer_type, peer_id)
peer_type,
peer_id,
(cardinality($4::bigint[]) - pos + 1)::int AS ord
FROM requested
ORDER BY peer_type, peer_id, pos
)
UPDATE dialogs d
SET pinned = true,
pinned_order = deduped.ord,
updated_at = now()
FROM deduped
WHERE d.user_id = $1::bigint
AND d.peer_type = deduped.peer_type
AND d.peer_id = deduped.peer_id
AND d.folder_id = $2::int
`
type ReorderPinnedDialogsParams struct {
UserID int64
FolderID int32
PeerTypes []string
PeerIds []int64
}
func (q *Queries) ReorderPinnedDialogs(ctx context.Context, arg ReorderPinnedDialogsParams) error {
_, err := q.db.Exec(ctx, reorderPinnedDialogs,
arg.UserID,
arg.FolderID,
arg.PeerTypes,
arg.PeerIds,
)
return err
}
const setDialogArchivePinned = `-- name: SetDialogArchivePinned :one
WITH current AS (
SELECT archive_pinned
FROM dialog_filter_settings
WHERE user_id = $2::bigint
),
upserted AS (
INSERT INTO dialog_filter_settings (user_id, archive_pinned)
VALUES ($2::bigint, $1::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 $1::boolean)::boolean AS changed
FROM upserted
`
type SetDialogArchivePinnedParams struct {
Pinned bool
UserID int64
}
// archive folder 行本身的置顶状态toggleDialogPin(inputDialogPeerFolder))。
// 无行时官方默认视为 pinned=true所以这里总是落一行显式值。
func (q *Queries) SetDialogArchivePinned(ctx context.Context, arg SetDialogArchivePinnedParams) (bool, error) {
row := q.db.QueryRow(ctx, setDialogArchivePinned, arg.Pinned, arg.UserID)
var changed bool
err := row.Scan(&changed)
return changed, err
}
const setDialogFolderTags = `-- name: SetDialogFolderTags :exec
INSERT INTO dialog_filter_settings (
user_id,
tags_enabled
) VALUES (
$1,
$2
)
ON CONFLICT (user_id) DO UPDATE SET
tags_enabled = EXCLUDED.tags_enabled,
updated_at = now()
`
type SetDialogFolderTagsParams struct {
UserID int64
TagsEnabled bool
}
func (q *Queries) SetDialogFolderTags(ctx context.Context, arg SetDialogFolderTagsParams) error {
_, err := q.db.Exec(ctx, setDialogFolderTags, arg.UserID, arg.TagsEnabled)
return err
}
const setDialogPinned = `-- name: SetDialogPinned :one
WITH target AS (
SELECT d.folder_id
FROM dialogs d
WHERE d.user_id = $1::bigint
AND d.peer_type = $2::text
AND d.peer_id = $3::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 = $1::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 = $1::bigint
AND cd.pinned
AND COALESCE(cd.folder_id, 0) = t.folder_id
), 0)
)::int + 1 AS value
),
updated AS (
UPDATE dialogs d
SET pinned = $4::boolean,
pinned_order = CASE
WHEN $4::boolean THEN
CASE WHEN d.pinned_order > 0 THEN d.pinned_order ELSE next_order.value END
ELSE 0
END,
updated_at = now()
FROM next_order
WHERE d.user_id = $1::bigint
AND d.peer_type = $2::text
AND d.peer_id = $3::bigint
RETURNING d.folder_id
)
SELECT
EXISTS (SELECT 1 FROM updated)::boolean AS changed,
COALESCE((SELECT folder_id FROM updated), 0)::int AS folder_id
`
type SetDialogPinnedParams struct {
UserID int64
PeerType string
PeerID int64
Pinned bool
}
type SetDialogPinnedRow struct {
Changed bool
FolderID int32
}
// 置顶顺序在 dialog 当前 folder0 主列表/1 归档)内独立分配,
// 返回 folder_id 供 updateDialogPinned.folder_id 使用。
func (q *Queries) SetDialogPinned(ctx context.Context, arg SetDialogPinnedParams) (SetDialogPinnedRow, error) {
row := q.db.QueryRow(ctx, setDialogPinned,
arg.UserID,
arg.PeerType,
arg.PeerID,
arg.Pinned,
)
var i SetDialogPinnedRow
err := row.Scan(&i.Changed, &i.FolderID)
return i, err
}
const setDialogUnreadMark = `-- name: SetDialogUnreadMark :one
WITH updated AS (
UPDATE dialogs d
SET unread_mark = $1::boolean,
updated_at = now()
WHERE d.user_id = $2::bigint
AND d.peer_type = $3::text
AND d.peer_id = $4::bigint
AND d.unread_mark IS DISTINCT FROM $1::boolean
RETURNING d.user_id
)
SELECT EXISTS (SELECT 1 FROM updated)::boolean AS changed
`
type SetDialogUnreadMarkParams struct {
Unread bool
UserID int64
PeerType string
PeerID int64
}
// 值守卫 IS DISTINCT FROM重复标记同一值不应算 changed否则上层会记一条
// 幽灵 durable 未读标事件并多推一次 update对齐频道侧 SetChannelDialogUnreadMark
func (q *Queries) SetDialogUnreadMark(ctx context.Context, arg SetDialogUnreadMarkParams) (bool, error) {
row := q.db.QueryRow(ctx, setDialogUnreadMark,
arg.Unread,
arg.UserID,
arg.PeerType,
arg.PeerID,
)
var changed bool
err := row.Scan(&changed)
return changed, err
}
const setPeerSettingsBarHidden = `-- name: SetPeerSettingsBarHidden :one
WITH updated AS (
UPDATE dialogs d
SET hidden_peer_settings_bar = true,
updated_at = now()
WHERE d.user_id = $1::bigint
AND d.peer_type = $2::text
AND d.peer_id = $3::bigint
RETURNING d.user_id
)
SELECT EXISTS (SELECT 1 FROM updated)::boolean AS changed
`
type SetPeerSettingsBarHiddenParams struct {
UserID int64
PeerType string
PeerID int64
}
func (q *Queries) SetPeerSettingsBarHidden(ctx context.Context, arg SetPeerSettingsBarHiddenParams) (bool, error) {
row := q.db.QueryRow(ctx, setPeerSettingsBarHidden, arg.UserID, arg.PeerType, arg.PeerID)
var changed bool
err := row.Scan(&changed)
return changed, err
}
const upsertDialog = `-- name: UpsertDialog :exec
INSERT INTO dialogs (
user_id,
peer_type,
peer_id,
top_message_id,
top_message_date,
read_inbox_max_id,
read_outbox_max_id,
unread_count,
unread_mentions_count,
unread_reactions_count,
pinned,
unread_mark
) VALUES (
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12
)
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,
read_inbox_max_id = EXCLUDED.read_inbox_max_id,
read_outbox_max_id = EXCLUDED.read_outbox_max_id,
unread_count = EXCLUDED.unread_count,
unread_mentions_count = EXCLUDED.unread_mentions_count,
unread_reactions_count = EXCLUDED.unread_reactions_count,
pinned = EXCLUDED.pinned,
unread_mark = EXCLUDED.unread_mark,
updated_at = now()
`
type UpsertDialogParams struct {
UserID int64
PeerType string
PeerID int64
TopMessageID int32
TopMessageDate int32
ReadInboxMaxID int32
ReadOutboxMaxID int32
UnreadCount int32
UnreadMentionsCount int32
UnreadReactionsCount int32
Pinned bool
UnreadMark bool
}
func (q *Queries) UpsertDialog(ctx context.Context, arg UpsertDialogParams) error {
_, err := q.db.Exec(ctx, upsertDialog,
arg.UserID,
arg.PeerType,
arg.PeerID,
arg.TopMessageID,
arg.TopMessageDate,
arg.ReadInboxMaxID,
arg.ReadOutboxMaxID,
arg.UnreadCount,
arg.UnreadMentionsCount,
arg.UnreadReactionsCount,
arg.Pinned,
arg.UnreadMark,
)
return err
}
const upsertDialogDraft = `-- name: UpsertDialogDraft :exec
INSERT INTO dialog_drafts (
user_id,
peer_type,
peer_id,
top_message_id,
date,
draft
) VALUES (
$1,
$2,
$3,
$4,
$5,
$6::jsonb
)
ON CONFLICT (user_id, peer_type, peer_id, top_message_id) DO UPDATE SET
date = EXCLUDED.date,
draft = EXCLUDED.draft,
updated_at = now()
`
type UpsertDialogDraftParams struct {
UserID int64
PeerType string
PeerID int64
TopMessageID int32
Date int32
DraftJson []byte
}
func (q *Queries) UpsertDialogDraft(ctx context.Context, arg UpsertDialogDraftParams) error {
_, err := q.db.Exec(ctx, upsertDialogDraft,
arg.UserID,
arg.PeerType,
arg.PeerID,
arg.TopMessageID,
arg.Date,
arg.DraftJson,
)
return err
}
const upsertDialogFolder = `-- name: UpsertDialogFolder :exec
INSERT INTO dialog_filters (
user_id,
filter_id,
is_chatlist,
filter,
order_value
) VALUES (
$1,
$2,
$3,
$4::jsonb,
COALESCE(
(SELECT order_value FROM dialog_filters WHERE user_id = $1 AND filter_id = $2),
(SELECT COALESCE(MAX(order_value), 0) + 1 FROM dialog_filters WHERE user_id = $1)
)
)
ON CONFLICT (user_id, filter_id) DO UPDATE SET
is_chatlist = EXCLUDED.is_chatlist,
filter = EXCLUDED.filter,
updated_at = now()
`
type UpsertDialogFolderParams struct {
UserID int64
FilterID int32
IsChatlist bool
FilterJson []byte
}
func (q *Queries) UpsertDialogFolder(ctx context.Context, arg UpsertDialogFolderParams) error {
_, err := q.db.Exec(ctx, upsertDialogFolder,
arg.UserID,
arg.FilterID,
arg.IsChatlist,
arg.FilterJson,
)
return err
}
const upsertInboxDialog = `-- name: UpsertInboxDialog :exec
INSERT INTO dialogs (
user_id,
peer_type,
peer_id,
top_message_id,
top_message_date,
unread_count
) VALUES (
$1, $2, $3, $4, $5, 1
)
ON CONFLICT (user_id, peer_type, peer_id) DO UPDATE SET
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()
`
type UpsertInboxDialogParams struct {
UserID int64
PeerType string
PeerID int64
TopMessageID int32
TopMessageDate int32
}
func (q *Queries) UpsertInboxDialog(ctx context.Context, arg UpsertInboxDialogParams) error {
_, err := q.db.Exec(ctx, upsertInboxDialog,
arg.UserID,
arg.PeerType,
arg.PeerID,
arg.TopMessageID,
arg.TopMessageDate,
)
return err
}
const upsertOutboxDialog = `-- name: UpsertOutboxDialog :exec
INSERT INTO dialogs (
user_id,
peer_type,
peer_id,
top_message_id,
top_message_date,
unread_count
) VALUES (
$1, $2, $3, $4, $5, 0
)
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()
`
type UpsertOutboxDialogParams struct {
UserID int64
PeerType string
PeerID int64
TopMessageID int32
TopMessageDate int32
}
// 发送方向该会话发出消息即视为已知晓内容:清除手动未读标记,
// 与 channel 发送路径、readHistory 清除语义对齐。
func (q *Queries) UpsertOutboxDialog(ctx context.Context, arg UpsertOutboxDialogParams) error {
_, err := q.db.Exec(ctx, upsertOutboxDialog,
arg.UserID,
arg.PeerType,
arg.PeerID,
arg.TopMessageID,
arg.TopMessageDate,
)
return err
}