2089 lines
59 KiB
Go
2089 lines
59 KiB
Go
// 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 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 时清 pinned:TDesktop 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.hide_edited, false)::boolean AS message_hide_edited,
|
||
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_hide_edited,
|
||
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
|
||
MessageHideEdited bool
|
||
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.MessageHideEdited,
|
||
&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.hide_edited, false)::boolean AS message_hide_edited,
|
||
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_hide_edited, 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_hide_edited,
|
||
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
|
||
MessageHideEdited bool
|
||
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.MessageHideEdited,
|
||
&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 当前 folder(0 主列表/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
|
||
}
|