Initial open source release
This commit is contained in:
commit
74992e893f
377 changed files with 118084 additions and 0 deletions
22
internal/store/postgres/queries/account.sql
Normal file
22
internal/store/postgres/queries/account.sql
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
-- name: GetPasswordByUser :one
|
||||
SELECT
|
||||
user_id, has_recovery, has_secure_values, has_password, hint,
|
||||
email_unconfirmed_pattern, login_email_pattern, secure_random
|
||||
FROM account_passwords
|
||||
WHERE user_id = $1;
|
||||
|
||||
-- name: UpsertPassword :exec
|
||||
INSERT INTO account_passwords (
|
||||
user_id, has_recovery, has_secure_values, has_password, hint,
|
||||
email_unconfirmed_pattern, login_email_pattern, secure_random
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8)
|
||||
ON CONFLICT (user_id) DO UPDATE SET
|
||||
has_recovery = EXCLUDED.has_recovery,
|
||||
has_secure_values = EXCLUDED.has_secure_values,
|
||||
has_password = EXCLUDED.has_password,
|
||||
hint = EXCLUDED.hint,
|
||||
email_unconfirmed_pattern = EXCLUDED.email_unconfirmed_pattern,
|
||||
login_email_pattern = EXCLUDED.login_email_pattern,
|
||||
secure_random = EXCLUDED.secure_random,
|
||||
updated_at = now();
|
||||
10
internal/store/postgres/queries/authkey.sql
Normal file
10
internal/store/postgres/queries/authkey.sql
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
-- name: GetAuthKey :one
|
||||
SELECT auth_key_id, body, server_salt, created_at
|
||||
FROM auth_keys
|
||||
WHERE auth_key_id = $1;
|
||||
|
||||
-- name: UpsertAuthKey :exec
|
||||
INSERT INTO auth_keys (auth_key_id, body, server_salt)
|
||||
VALUES ($1, $2, $3)
|
||||
ON CONFLICT (auth_key_id) DO UPDATE
|
||||
SET body = EXCLUDED.body, server_salt = EXCLUDED.server_salt;
|
||||
24
internal/store/postgres/queries/authorization.sql
Normal file
24
internal/store/postgres/queries/authorization.sql
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
-- name: UpsertAuthorization :exec
|
||||
INSERT INTO authorizations (auth_key_id, user_id, layer, device_model, platform, system_version, api_id, app_version, ip)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9)
|
||||
ON CONFLICT (auth_key_id) DO UPDATE SET
|
||||
user_id = EXCLUDED.user_id,
|
||||
layer = EXCLUDED.layer,
|
||||
device_model = EXCLUDED.device_model,
|
||||
platform = EXCLUDED.platform,
|
||||
system_version = EXCLUDED.system_version,
|
||||
api_id = EXCLUDED.api_id,
|
||||
app_version = EXCLUDED.app_version,
|
||||
ip = EXCLUDED.ip,
|
||||
active_at = now();
|
||||
|
||||
-- name: GetAuthorizationByAuthKey :one
|
||||
SELECT * FROM authorizations WHERE auth_key_id = $1;
|
||||
|
||||
-- name: ListAuthorizationsByUser :many
|
||||
SELECT * FROM authorizations
|
||||
WHERE user_id = $1
|
||||
ORDER BY active_at DESC, auth_key_id DESC;
|
||||
|
||||
-- name: DeleteAuthorization :exec
|
||||
DELETE FROM authorizations WHERE auth_key_id = $1;
|
||||
168
internal/store/postgres/queries/contact.sql
Normal file
168
internal/store/postgres/queries/contact.sql
Normal file
|
|
@ -0,0 +1,168 @@
|
|||
-- name: ListContactsByUser :many
|
||||
SELECT
|
||||
c.contact_user_id,
|
||||
c.mutual,
|
||||
c.contact_phone,
|
||||
c.contact_first_name,
|
||||
c.contact_last_name,
|
||||
c.note,
|
||||
COALESCE(c.note_entities::text, '[]')::text AS note_entities_json,
|
||||
u.id,
|
||||
u.access_hash,
|
||||
COALESCE(NULLIF(c.contact_phone, ''), u.phone)::text AS phone,
|
||||
COALESCE(NULLIF(c.contact_first_name, ''), u.first_name)::text AS first_name,
|
||||
COALESCE(c.contact_last_name, u.last_name)::text AS last_name,
|
||||
u.username,
|
||||
u.country_code,
|
||||
u.verified,
|
||||
u.support,
|
||||
u.last_seen_at
|
||||
FROM contacts c
|
||||
JOIN users u ON u.id = c.contact_user_id
|
||||
WHERE c.user_id = $1
|
||||
ORDER BY c.contact_first_name, c.contact_last_name, u.first_name, u.last_name, u.id;
|
||||
|
||||
-- name: GetContact :one
|
||||
SELECT
|
||||
c.contact_user_id,
|
||||
c.mutual,
|
||||
c.contact_phone,
|
||||
c.contact_first_name,
|
||||
c.contact_last_name,
|
||||
c.note,
|
||||
COALESCE(c.note_entities::text, '[]')::text AS note_entities_json,
|
||||
u.id,
|
||||
u.access_hash,
|
||||
COALESCE(NULLIF(c.contact_phone, ''), u.phone)::text AS phone,
|
||||
COALESCE(NULLIF(c.contact_first_name, ''), u.first_name)::text AS first_name,
|
||||
COALESCE(c.contact_last_name, u.last_name)::text AS last_name,
|
||||
u.username,
|
||||
u.country_code,
|
||||
u.verified,
|
||||
u.support,
|
||||
u.last_seen_at
|
||||
FROM contacts c
|
||||
JOIN users u ON u.id = c.contact_user_id
|
||||
WHERE c.user_id = $1
|
||||
AND c.contact_user_id = $2;
|
||||
|
||||
-- name: UpsertContact :one
|
||||
WITH reverse AS (
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM contacts
|
||||
WHERE user_id = sqlc.arg(contact_user_id)::bigint
|
||||
AND contact_user_id = sqlc.arg(user_id)::bigint
|
||||
)::boolean AS mutual
|
||||
),
|
||||
upserted AS (
|
||||
INSERT INTO contacts (
|
||||
user_id,
|
||||
contact_user_id,
|
||||
contact_phone,
|
||||
contact_first_name,
|
||||
contact_last_name,
|
||||
note,
|
||||
note_entities,
|
||||
mutual
|
||||
)
|
||||
SELECT
|
||||
sqlc.arg(user_id)::bigint,
|
||||
sqlc.arg(contact_user_id)::bigint,
|
||||
sqlc.arg(contact_phone)::text,
|
||||
sqlc.arg(contact_first_name)::text,
|
||||
sqlc.arg(contact_last_name)::text,
|
||||
sqlc.arg(note)::text,
|
||||
sqlc.arg(note_entities)::jsonb,
|
||||
reverse.mutual
|
||||
FROM reverse
|
||||
ON CONFLICT (user_id, contact_user_id) DO UPDATE SET
|
||||
contact_phone = EXCLUDED.contact_phone,
|
||||
contact_first_name = EXCLUDED.contact_first_name,
|
||||
contact_last_name = EXCLUDED.contact_last_name,
|
||||
note = EXCLUDED.note,
|
||||
note_entities = EXCLUDED.note_entities,
|
||||
mutual = contacts.mutual OR EXCLUDED.mutual,
|
||||
updated_at = now()
|
||||
RETURNING *
|
||||
),
|
||||
reverse_updated AS (
|
||||
UPDATE contacts c
|
||||
SET mutual = true,
|
||||
updated_at = now()
|
||||
WHERE c.user_id = sqlc.arg(contact_user_id)::bigint
|
||||
AND c.contact_user_id = sqlc.arg(user_id)::bigint
|
||||
AND NOT c.mutual
|
||||
RETURNING c.user_id
|
||||
)
|
||||
SELECT
|
||||
c.contact_user_id,
|
||||
c.mutual,
|
||||
c.contact_phone,
|
||||
c.contact_first_name,
|
||||
c.contact_last_name,
|
||||
c.note,
|
||||
COALESCE(c.note_entities::text, '[]')::text AS note_entities_json,
|
||||
u.id,
|
||||
u.access_hash,
|
||||
COALESCE(NULLIF(c.contact_phone, ''), u.phone)::text AS phone,
|
||||
COALESCE(NULLIF(c.contact_first_name, ''), u.first_name)::text AS first_name,
|
||||
COALESCE(c.contact_last_name, u.last_name)::text AS last_name,
|
||||
u.username,
|
||||
u.country_code,
|
||||
u.verified,
|
||||
u.support,
|
||||
u.last_seen_at,
|
||||
EXISTS (SELECT 1 FROM reverse_updated)::boolean AS reverse_mutual_changed
|
||||
FROM upserted c
|
||||
JOIN users u ON u.id = c.contact_user_id;
|
||||
|
||||
-- name: UpdateContactNote :one
|
||||
WITH updated AS (
|
||||
UPDATE contacts c
|
||||
SET note = sqlc.arg(note)::text,
|
||||
note_entities = sqlc.arg(note_entities)::jsonb,
|
||||
updated_at = now()
|
||||
WHERE c.user_id = sqlc.arg(user_id)::bigint
|
||||
AND c.contact_user_id = sqlc.arg(contact_user_id)::bigint
|
||||
RETURNING *
|
||||
)
|
||||
SELECT
|
||||
c.contact_user_id,
|
||||
c.mutual,
|
||||
c.contact_phone,
|
||||
c.contact_first_name,
|
||||
c.contact_last_name,
|
||||
c.note,
|
||||
COALESCE(c.note_entities::text, '[]')::text AS note_entities_json,
|
||||
u.id,
|
||||
u.access_hash,
|
||||
COALESCE(NULLIF(c.contact_phone, ''), u.phone)::text AS phone,
|
||||
COALESCE(NULLIF(c.contact_first_name, ''), u.first_name)::text AS first_name,
|
||||
COALESCE(c.contact_last_name, u.last_name)::text AS last_name,
|
||||
u.username,
|
||||
u.country_code,
|
||||
u.verified,
|
||||
u.support,
|
||||
u.last_seen_at
|
||||
FROM updated c
|
||||
JOIN users u ON u.id = c.contact_user_id;
|
||||
|
||||
-- name: DeleteContacts :one
|
||||
WITH deleted AS (
|
||||
DELETE FROM contacts
|
||||
WHERE user_id = sqlc.arg(user_id)::bigint
|
||||
AND contact_user_id = ANY(sqlc.arg(contact_user_ids)::bigint[])
|
||||
RETURNING contact_user_id
|
||||
),
|
||||
reverse_updated AS (
|
||||
UPDATE contacts c
|
||||
SET mutual = false,
|
||||
updated_at = now()
|
||||
FROM deleted d
|
||||
WHERE c.user_id = d.contact_user_id
|
||||
AND c.contact_user_id = sqlc.arg(user_id)::bigint
|
||||
RETURNING c.user_id
|
||||
)
|
||||
SELECT COUNT(*)::int AS deleted_count
|
||||
FROM deleted;
|
||||
773
internal/store/postgres/queries/dialog.sql
Normal file
773
internal/store/postgres/queries/dialog.sql
Normal file
|
|
@ -0,0 +1,773 @@
|
|||
-- 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.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.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.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
|
||||
FROM dialogs d
|
||||
LEFT JOIN users u ON d.peer_type = 'user' AND u.id = d.peer_id
|
||||
LEFT JOIN contacts c ON d.peer_type = 'user' AND c.user_id = d.user_id AND c.contact_user_id = d.peer_id
|
||||
LEFT JOIN message_boxes m ON m.owner_user_id = d.user_id AND m.box_id = d.top_message_id AND NOT m.deleted
|
||||
WHERE d.user_id = $1
|
||||
AND (
|
||||
NOT sqlc.arg(has_folder_id)::boolean
|
||||
OR (
|
||||
sqlc.arg(folder_id)::int < 2
|
||||
AND d.folder_id = sqlc.arg(folder_id)::int
|
||||
)
|
||||
OR (
|
||||
sqlc.arg(folder_id)::int >= 2
|
||||
AND NOT (sqlc.arg(folder_exclude_archived)::boolean AND d.folder_id = 1)
|
||||
AND NOT (sqlc.arg(folder_exclude_read)::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(sqlc.arg(folder_exclude_peer_types)::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
|
||||
JOIN unnest(sqlc.arg(folder_exclude_peer_ids)::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(sqlc.arg(folder_include_peer_types)::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
|
||||
JOIN unnest(sqlc.arg(folder_include_peer_ids)::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(sqlc.arg(folder_pinned_peer_types)::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
|
||||
JOIN unnest(sqlc.arg(folder_pinned_peer_ids)::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 (sqlc.arg(folder_contacts)::boolean AND c.contact_user_id IS NOT NULL)
|
||||
OR (sqlc.arg(folder_non_contacts)::boolean AND c.contact_user_id IS NULL)
|
||||
)
|
||||
)
|
||||
)
|
||||
AND (NOT sqlc.arg(pinned_only)::boolean OR d.pinned)
|
||||
AND (NOT sqlc.arg(exclude_pinned)::boolean OR NOT d.pinned)
|
||||
),
|
||||
paged AS (
|
||||
SELECT *
|
||||
FROM base
|
||||
WHERE (
|
||||
(sqlc.arg(offset_date)::int <= 0 AND sqlc.arg(offset_id)::int <= 0)
|
||||
OR (
|
||||
sqlc.arg(offset_date)::int > 0
|
||||
AND (
|
||||
top_message_date < sqlc.arg(offset_date)::int
|
||||
OR (
|
||||
top_message_date = sqlc.arg(offset_date)::int
|
||||
AND (
|
||||
sqlc.arg(offset_id)::int <= 0
|
||||
OR top_message_id < sqlc.arg(offset_id)::int
|
||||
OR (
|
||||
top_message_id = sqlc.arg(offset_id)::int
|
||||
AND sqlc.arg(has_offset_peer)::boolean
|
||||
AND peer_id < sqlc.arg(offset_peer_id)::bigint
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
OR (
|
||||
sqlc.arg(offset_date)::int <= 0
|
||||
AND sqlc.arg(offset_id)::int > 0
|
||||
AND (
|
||||
top_message_id < sqlc.arg(offset_id)::int
|
||||
OR (
|
||||
top_message_id = sqlc.arg(offset_id)::int
|
||||
AND sqlc.arg(has_offset_peer)::boolean
|
||||
AND peer_id < sqlc.arg(offset_peer_id)::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,
|
||||
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_last_seen_at,
|
||||
peer_contact,
|
||||
peer_mutual,
|
||||
message_id,
|
||||
message_from_user_id,
|
||||
message_date,
|
||||
message_outgoing,
|
||||
message_body,
|
||||
message_entities_json
|
||||
FROM paged
|
||||
ORDER BY
|
||||
pinned DESC,
|
||||
CASE WHEN pinned THEN COALESCE(NULLIF(pinned_order, 0), 2147483647) ELSE 2147483647 END ASC,
|
||||
top_message_date DESC,
|
||||
top_message_id DESC,
|
||||
peer_id DESC
|
||||
LIMIT sqlc.arg(limit_count);
|
||||
|
||||
-- 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.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 sqlc.arg(has_folder_id)::boolean
|
||||
OR (
|
||||
sqlc.arg(folder_id)::int < 2
|
||||
AND d.folder_id = sqlc.arg(folder_id)::int
|
||||
)
|
||||
OR (
|
||||
sqlc.arg(folder_id)::int >= 2
|
||||
AND NOT (sqlc.arg(folder_exclude_archived)::boolean AND d.folder_id = 1)
|
||||
AND NOT (sqlc.arg(folder_exclude_read)::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(sqlc.arg(folder_exclude_peer_types)::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
|
||||
JOIN unnest(sqlc.arg(folder_exclude_peer_ids)::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(sqlc.arg(folder_include_peer_types)::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
|
||||
JOIN unnest(sqlc.arg(folder_include_peer_ids)::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(sqlc.arg(folder_pinned_peer_types)::text[]) WITH ORDINALITY AS fpt(peer_type, ord)
|
||||
JOIN unnest(sqlc.arg(folder_pinned_peer_ids)::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 (sqlc.arg(folder_contacts)::boolean AND c.contact_user_id IS NOT NULL)
|
||||
OR (sqlc.arg(folder_non_contacts)::boolean AND c.contact_user_id IS NULL)
|
||||
)
|
||||
)
|
||||
)
|
||||
AND (NOT sqlc.arg(pinned_only)::boolean OR d.pinned)
|
||||
AND (NOT sqlc.arg(exclude_pinned)::boolean OR NOT d.pinned)
|
||||
ORDER BY
|
||||
d.pinned DESC,
|
||||
CASE WHEN d.pinned THEN COALESCE(NULLIF(d.pinned_order, 0), 2147483647) ELSE 2147483647 END ASC,
|
||||
d.top_message_date DESC,
|
||||
d.top_message_id DESC,
|
||||
d.peer_id DESC;
|
||||
|
||||
-- name: ListDialogsByPeers :many
|
||||
WITH requested AS (
|
||||
SELECT
|
||||
(sqlc.arg(peer_types)::text[])[i] AS peer_type,
|
||||
(sqlc.arg(peer_ids)::bigint[])[i] AS peer_id,
|
||||
i::int AS ord
|
||||
FROM generate_subscripts(sqlc.arg(peer_ids)::bigint[], 1) AS g(i)
|
||||
WHERE i <= cardinality(sqlc.arg(peer_types)::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
|
||||
sqlc.arg(user_id)::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.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.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.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,
|
||||
r.ord
|
||||
FROM deduped r
|
||||
LEFT JOIN dialogs d
|
||||
ON d.user_id = sqlc.arg(user_id)::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 = sqlc.arg(user_id)::bigint AND c.contact_user_id = r.peer_id
|
||||
LEFT JOIN message_boxes m ON m.owner_user_id = sqlc.arg(user_id)::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,
|
||||
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_last_seen_at,
|
||||
peer_contact,
|
||||
peer_mutual,
|
||||
message_id,
|
||||
message_from_user_id,
|
||||
message_date,
|
||||
message_outgoing,
|
||||
message_body,
|
||||
message_entities_json
|
||||
FROM base
|
||||
ORDER BY ord;
|
||||
|
||||
-- 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();
|
||||
|
||||
-- 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,
|
||||
updated_at = now();
|
||||
|
||||
-- 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 = EXCLUDED.top_message_id,
|
||||
top_message_date = EXCLUDED.top_message_date,
|
||||
unread_count = dialogs.unread_count + 1,
|
||||
updated_at = now();
|
||||
|
||||
-- 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
|
||||
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,
|
||||
CASE WHEN sqlc.arg(max_id)::int > 0 THEN sqlc.arg(max_id)::int ELSE d.top_message_id END
|
||||
),
|
||||
unread_count = 0,
|
||||
unread_mark = false,
|
||||
unread_mentions_count = 0,
|
||||
unread_reactions_count = 0,
|
||||
updated_at = now()
|
||||
FROM target
|
||||
WHERE d.user_id = target.user_id
|
||||
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 (
|
||||
CASE WHEN sqlc.arg(max_id)::int > 0 THEN sqlc.arg(max_id)::int ELSE target.top_message_id END
|
||||
) > target.read_inbox_max_id
|
||||
)::boolean AS changed
|
||||
)
|
||||
SELECT
|
||||
user_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
read_inbox_max_id,
|
||||
unread_count,
|
||||
changed
|
||||
FROM updated;
|
||||
|
||||
-- name: SetDialogPinned :one
|
||||
WITH next_order AS (
|
||||
SELECT COALESCE(MAX(pinned_order), 0)::int + 1 AS value
|
||||
FROM dialogs
|
||||
WHERE user_id = sqlc.arg(user_id)::bigint
|
||||
AND pinned
|
||||
),
|
||||
updated AS (
|
||||
UPDATE dialogs d
|
||||
SET pinned = sqlc.arg(pinned)::boolean,
|
||||
pinned_order = CASE
|
||||
WHEN sqlc.arg(pinned)::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 = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
AND d.peer_id = sqlc.arg(peer_id)::bigint
|
||||
RETURNING d.user_id
|
||||
)
|
||||
SELECT EXISTS (SELECT 1 FROM updated)::boolean AS changed;
|
||||
|
||||
-- name: SetDialogUnreadMark :one
|
||||
WITH updated AS (
|
||||
UPDATE dialogs d
|
||||
SET unread_mark = sqlc.arg(unread)::boolean,
|
||||
updated_at = now()
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
AND d.peer_id = sqlc.arg(peer_id)::bigint
|
||||
RETURNING d.user_id
|
||||
)
|
||||
SELECT EXISTS (SELECT 1 FROM updated)::boolean AS changed;
|
||||
|
||||
-- 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;
|
||||
|
||||
-- name: SetPeerSettingsBarHidden :one
|
||||
WITH updated AS (
|
||||
UPDATE dialogs d
|
||||
SET hidden_peer_settings_bar = true,
|
||||
updated_at = now()
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
AND d.peer_id = sqlc.arg(peer_id)::bigint
|
||||
RETURNING d.user_id
|
||||
)
|
||||
SELECT EXISTS (SELECT 1 FROM updated)::boolean AS changed;
|
||||
|
||||
-- name: GetPeerSettingsBarHidden :one
|
||||
SELECT hidden_peer_settings_bar
|
||||
FROM dialogs
|
||||
WHERE user_id = $1
|
||||
AND peer_type = $2
|
||||
AND peer_id = $3;
|
||||
|
||||
-- name: ReorderPinnedDialogs :exec
|
||||
WITH requested AS (
|
||||
SELECT
|
||||
(sqlc.arg(peer_types)::text[])[i] AS peer_type,
|
||||
(sqlc.arg(peer_ids)::bigint[])[i] AS peer_id,
|
||||
i::int AS pos
|
||||
FROM generate_subscripts(sqlc.arg(peer_ids)::bigint[], 1) AS g(i)
|
||||
WHERE i <= cardinality(sqlc.arg(peer_types)::text[])
|
||||
),
|
||||
deduped AS (
|
||||
SELECT DISTINCT ON (peer_type, peer_id)
|
||||
peer_type,
|
||||
peer_id,
|
||||
pos::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 = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = deduped.peer_type
|
||||
AND d.peer_id = deduped.peer_id;
|
||||
|
||||
-- name: EditDialogPeerFolders :exec
|
||||
WITH requested AS (
|
||||
SELECT
|
||||
(sqlc.arg(peer_types)::text[])[i] AS peer_type,
|
||||
(sqlc.arg(peer_ids)::bigint[])[i] AS peer_id,
|
||||
(sqlc.arg(folder_ids)::int[])[i] AS folder_id
|
||||
FROM generate_subscripts(sqlc.arg(peer_ids)::bigint[], 1) AS g(i)
|
||||
WHERE i <= cardinality(sqlc.arg(peer_types)::text[])
|
||||
AND i <= cardinality(sqlc.arg(folder_ids)::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,
|
||||
updated_at = now()
|
||||
FROM deduped
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = deduped.peer_type
|
||||
AND d.peer_id = deduped.peer_id;
|
||||
|
||||
-- name: ClearPinnedDialogsNotInOrder :exec
|
||||
WITH requested AS (
|
||||
SELECT
|
||||
(sqlc.arg(peer_types)::text[])[i] AS peer_type,
|
||||
(sqlc.arg(peer_ids)::bigint[])[i] AS peer_id
|
||||
FROM generate_subscripts(sqlc.arg(peer_ids)::bigint[], 1) AS g(i)
|
||||
WHERE i <= cardinality(sqlc.arg(peer_types)::text[])
|
||||
)
|
||||
UPDATE dialogs d
|
||||
SET pinned = false,
|
||||
pinned_order = 0,
|
||||
updated_at = now()
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.pinned
|
||||
AND NOT EXISTS (
|
||||
SELECT 1
|
||||
FROM requested r
|
||||
WHERE r.peer_type = d.peer_type
|
||||
AND r.peer_id = d.peer_id
|
||||
);
|
||||
|
||||
-- name: RefreshDialogAfterMessageDelete :exec
|
||||
UPDATE dialogs d
|
||||
SET
|
||||
top_message_id = sqlc.arg(top_message_id)::int,
|
||||
top_message_date = sqlc.arg(top_message_date)::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 = 0,
|
||||
updated_at = now()
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
AND d.peer_id = sqlc.arg(peer_id)::bigint;
|
||||
|
||||
-- name: 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 = 0,
|
||||
updated_at = now()
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
AND d.peer_id = sqlc.arg(peer_id)::bigint;
|
||||
|
||||
-- name: DeleteDialogByPeer :exec
|
||||
DELETE FROM dialogs
|
||||
WHERE user_id = $1
|
||||
AND peer_type = $2
|
||||
AND peer_id = $3;
|
||||
|
||||
-- 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;
|
||||
|
||||
-- name: GetDialogFolder :one
|
||||
SELECT
|
||||
filter_id,
|
||||
is_chatlist,
|
||||
filter::text AS filter_json
|
||||
FROM dialog_filters
|
||||
WHERE user_id = $1
|
||||
AND filter_id = $2;
|
||||
|
||||
-- name: UpsertDialogFolder :exec
|
||||
INSERT INTO dialog_filters (
|
||||
user_id,
|
||||
filter_id,
|
||||
is_chatlist,
|
||||
filter,
|
||||
order_value
|
||||
) VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
sqlc.arg(filter_json)::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();
|
||||
|
||||
-- name: DeleteDialogFolder :exec
|
||||
DELETE FROM dialog_filters
|
||||
WHERE user_id = $1
|
||||
AND filter_id = $2;
|
||||
|
||||
-- name: ReorderDialogFolders :exec
|
||||
WITH requested AS (
|
||||
SELECT filter_id, ord::int AS order_value
|
||||
FROM unnest(sqlc.arg(filter_ids)::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 = sqlc.arg(user_id)::bigint
|
||||
AND f.filter_id = deduped.filter_id;
|
||||
|
||||
-- name: GetDialogFolderTags :one
|
||||
SELECT tags_enabled
|
||||
FROM dialog_filter_settings
|
||||
WHERE user_id = $1;
|
||||
|
||||
-- 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();
|
||||
|
||||
-- name: UpsertDialogDraft :exec
|
||||
INSERT INTO dialog_drafts (
|
||||
user_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
top_message_id,
|
||||
date,
|
||||
draft
|
||||
) VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
sqlc.arg(draft_json)::jsonb
|
||||
)
|
||||
ON CONFLICT (user_id, peer_type, peer_id, top_message_id) DO UPDATE SET
|
||||
date = EXCLUDED.date,
|
||||
draft = EXCLUDED.draft,
|
||||
updated_at = now();
|
||||
|
||||
-- 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;
|
||||
|
||||
-- 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 sqlc.arg(limit_count);
|
||||
|
||||
-- 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 sqlc.arg(limit_count)
|
||||
),
|
||||
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;
|
||||
43
internal/store/postgres/queries/help.sql
Normal file
43
internal/store/postgres/queries/help.sql
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
-- name: GetAppConfig :one
|
||||
SELECT client, hash, config_json::text AS config_json
|
||||
FROM app_configs
|
||||
WHERE client = $1;
|
||||
|
||||
-- name: UpsertAppConfig :exec
|
||||
INSERT INTO app_configs (client, hash, config_json)
|
||||
VALUES ($1, $2, sqlc.arg(config_json)::jsonb)
|
||||
ON CONFLICT (client) DO UPDATE SET
|
||||
hash = EXCLUDED.hash,
|
||||
config_json = EXCLUDED.config_json,
|
||||
updated_at = now();
|
||||
|
||||
-- name: ListCountries :many
|
||||
SELECT
|
||||
c.iso2,
|
||||
c.default_name,
|
||||
c.name,
|
||||
c.hidden,
|
||||
cc.country_code,
|
||||
cc.prefixes,
|
||||
cc.patterns
|
||||
FROM countries c
|
||||
JOIN country_codes cc ON cc.iso2 = c.iso2
|
||||
ORDER BY c.order_index, c.iso2, cc.order_index, cc.country_code;
|
||||
|
||||
-- name: UpsertCountry :exec
|
||||
INSERT INTO countries (iso2, default_name, name, hidden, order_index)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
ON CONFLICT (iso2) DO UPDATE SET
|
||||
default_name = EXCLUDED.default_name,
|
||||
name = EXCLUDED.name,
|
||||
hidden = EXCLUDED.hidden,
|
||||
order_index = EXCLUDED.order_index,
|
||||
updated_at = now();
|
||||
|
||||
-- name: UpsertCountryCode :exec
|
||||
INSERT INTO country_codes (iso2, country_code, prefixes, patterns, order_index)
|
||||
VALUES ($1, $2, $3, $4, $5)
|
||||
ON CONFLICT (iso2, country_code) DO UPDATE SET
|
||||
prefixes = EXCLUDED.prefixes,
|
||||
patterns = EXCLUDED.patterns,
|
||||
order_index = EXCLUDED.order_index;
|
||||
47
internal/store/postgres/queries/langpack.sql
Normal file
47
internal/store/postgres/queries/langpack.sql
Normal file
|
|
@ -0,0 +1,47 @@
|
|||
-- name: GetLangPackMeta :one
|
||||
SELECT lang_pack, lang_code, version, strings_count
|
||||
FROM lang_packs
|
||||
WHERE lang_pack = $1 AND lang_code = $2;
|
||||
|
||||
-- name: UpsertLangPackMeta :exec
|
||||
INSERT INTO lang_packs (lang_pack, lang_code, version, strings_count)
|
||||
VALUES ($1, $2, $3, $4)
|
||||
ON CONFLICT (lang_pack, lang_code) DO UPDATE SET
|
||||
version = EXCLUDED.version,
|
||||
strings_count = EXCLUDED.strings_count,
|
||||
updated_at = now();
|
||||
|
||||
-- name: UpsertLangPackString :exec
|
||||
INSERT INTO lang_pack_strings (
|
||||
lang_pack, lang_code, key, version, pluralized, value,
|
||||
zero_value, one_value, two_value, few_value, many_value, other_value, deleted
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11, $12, $13)
|
||||
ON CONFLICT (lang_pack, lang_code, key) DO UPDATE SET
|
||||
version = EXCLUDED.version,
|
||||
pluralized = EXCLUDED.pluralized,
|
||||
value = EXCLUDED.value,
|
||||
zero_value = EXCLUDED.zero_value,
|
||||
one_value = EXCLUDED.one_value,
|
||||
two_value = EXCLUDED.two_value,
|
||||
few_value = EXCLUDED.few_value,
|
||||
many_value = EXCLUDED.many_value,
|
||||
other_value = EXCLUDED.other_value,
|
||||
deleted = EXCLUDED.deleted,
|
||||
updated_at = now();
|
||||
|
||||
-- name: ListLangPackStrings :many
|
||||
SELECT
|
||||
lang_pack, lang_code, key, version, pluralized, value,
|
||||
zero_value, one_value, two_value, few_value, many_value, other_value, deleted
|
||||
FROM lang_pack_strings
|
||||
WHERE lang_pack = $1 AND lang_code = $2 AND NOT deleted
|
||||
ORDER BY key;
|
||||
|
||||
-- name: GetLangPackStringsByKeys :many
|
||||
SELECT
|
||||
lang_pack, lang_code, key, version, pluralized, value,
|
||||
zero_value, one_value, two_value, few_value, many_value, other_value, deleted
|
||||
FROM lang_pack_strings
|
||||
WHERE lang_pack = $1 AND lang_code = $2 AND key = ANY(sqlc.arg(keys)::text[]) AND NOT deleted
|
||||
ORDER BY key;
|
||||
331
internal/store/postgres/queries/media.sql
Normal file
331
internal/store/postgres/queries/media.sql
Normal file
|
|
@ -0,0 +1,331 @@
|
|||
-- upload_parts ----------------------------------------------------------------
|
||||
|
||||
-- name: SaveUploadPart :exec
|
||||
INSERT INTO upload_parts (owner_user_id, file_id, part, total_parts, is_big, bytes)
|
||||
VALUES (
|
||||
sqlc.arg(owner_user_id)::bigint,
|
||||
sqlc.arg(file_id)::bigint,
|
||||
sqlc.arg(part)::int,
|
||||
sqlc.arg(total_parts)::int,
|
||||
sqlc.arg(is_big)::boolean,
|
||||
sqlc.arg(bytes)::bytea
|
||||
)
|
||||
ON CONFLICT (owner_user_id, file_id, part) DO UPDATE SET
|
||||
total_parts = EXCLUDED.total_parts,
|
||||
is_big = EXCLUDED.is_big,
|
||||
bytes = EXCLUDED.bytes;
|
||||
|
||||
-- name: ListUploadParts :many
|
||||
SELECT part, total_parts, is_big, bytes
|
||||
FROM upload_parts
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND file_id = sqlc.arg(file_id)::bigint
|
||||
ORDER BY part ASC;
|
||||
|
||||
-- name: DeleteUploadParts :exec
|
||||
DELETE FROM upload_parts
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND file_id = sqlc.arg(file_id)::bigint;
|
||||
|
||||
-- file_blobs ------------------------------------------------------------------
|
||||
|
||||
-- name: PutFileBlob :exec
|
||||
INSERT INTO file_blobs (location_key, backend, object_key, size, sha256, mime_type)
|
||||
VALUES (
|
||||
sqlc.arg(location_key)::text,
|
||||
sqlc.arg(backend)::text,
|
||||
sqlc.arg(object_key)::text,
|
||||
sqlc.arg(size)::bigint,
|
||||
sqlc.arg(sha256)::bytea,
|
||||
sqlc.arg(mime_type)::text
|
||||
)
|
||||
ON CONFLICT (location_key) DO UPDATE SET
|
||||
backend = EXCLUDED.backend,
|
||||
object_key = EXCLUDED.object_key,
|
||||
size = EXCLUDED.size,
|
||||
sha256 = EXCLUDED.sha256,
|
||||
mime_type = EXCLUDED.mime_type;
|
||||
|
||||
-- name: GetFileBlob :one
|
||||
SELECT location_key, backend, object_key, size, sha256, mime_type
|
||||
FROM file_blobs
|
||||
WHERE location_key = sqlc.arg(location_key)::text;
|
||||
|
||||
-- documents -------------------------------------------------------------------
|
||||
|
||||
-- name: PutDocument :exec
|
||||
INSERT INTO documents (id, access_hash, file_reference, date, mime_type, size, dc_id, attributes, thumbs)
|
||||
VALUES (
|
||||
sqlc.arg(id)::bigint,
|
||||
sqlc.arg(access_hash)::bigint,
|
||||
sqlc.arg(file_reference)::bytea,
|
||||
sqlc.arg(date)::int,
|
||||
sqlc.arg(mime_type)::text,
|
||||
sqlc.arg(size)::bigint,
|
||||
sqlc.arg(dc_id)::int,
|
||||
sqlc.arg(attributes_json)::jsonb,
|
||||
sqlc.arg(thumbs_json)::jsonb
|
||||
)
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
access_hash = EXCLUDED.access_hash,
|
||||
file_reference = EXCLUDED.file_reference,
|
||||
date = EXCLUDED.date,
|
||||
mime_type = EXCLUDED.mime_type,
|
||||
size = EXCLUDED.size,
|
||||
dc_id = EXCLUDED.dc_id,
|
||||
attributes = EXCLUDED.attributes,
|
||||
thumbs = EXCLUDED.thumbs;
|
||||
|
||||
-- name: GetDocument :one
|
||||
SELECT id, access_hash, file_reference, date, mime_type, size, dc_id,
|
||||
attributes::text AS attributes_json,
|
||||
thumbs::text AS thumbs_json
|
||||
FROM documents
|
||||
WHERE id = sqlc.arg(id)::bigint;
|
||||
|
||||
-- name: GetDocuments :many
|
||||
SELECT id, access_hash, file_reference, date, mime_type, size, dc_id,
|
||||
attributes::text AS attributes_json,
|
||||
thumbs::text AS thumbs_json
|
||||
FROM documents
|
||||
WHERE id = ANY(sqlc.arg(ids)::bigint[]);
|
||||
|
||||
-- photos ----------------------------------------------------------------------
|
||||
|
||||
-- name: PutPhoto :exec
|
||||
INSERT INTO photos (id, access_hash, file_reference, date, dc_id, has_stickers, sizes)
|
||||
VALUES (
|
||||
sqlc.arg(id)::bigint,
|
||||
sqlc.arg(access_hash)::bigint,
|
||||
sqlc.arg(file_reference)::bytea,
|
||||
sqlc.arg(date)::int,
|
||||
sqlc.arg(dc_id)::int,
|
||||
sqlc.arg(has_stickers)::boolean,
|
||||
sqlc.arg(sizes_json)::jsonb
|
||||
)
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
access_hash = EXCLUDED.access_hash,
|
||||
file_reference = EXCLUDED.file_reference,
|
||||
date = EXCLUDED.date,
|
||||
dc_id = EXCLUDED.dc_id,
|
||||
has_stickers = EXCLUDED.has_stickers,
|
||||
sizes = EXCLUDED.sizes;
|
||||
|
||||
-- name: GetPhoto :one
|
||||
SELECT id, access_hash, file_reference, date, dc_id, has_stickers,
|
||||
sizes::text AS sizes_json
|
||||
FROM photos
|
||||
WHERE id = sqlc.arg(id)::bigint;
|
||||
|
||||
-- sticker_sets ----------------------------------------------------------------
|
||||
|
||||
-- name: PutStickerSet :exec
|
||||
INSERT INTO sticker_sets (
|
||||
id, access_hash, short_name, title, count, hash, set_kind,
|
||||
official, animated, videos, emojis, masks, installed, archived, installed_date,
|
||||
thumb_document_id, thumbs, thumb_dc_id, thumb_version, document_ids, packs, sort_order, system_key
|
||||
) VALUES (
|
||||
sqlc.arg(id)::bigint,
|
||||
sqlc.arg(access_hash)::bigint,
|
||||
sqlc.arg(short_name)::text,
|
||||
sqlc.arg(title)::text,
|
||||
sqlc.arg(count)::int,
|
||||
sqlc.arg(hash)::int,
|
||||
sqlc.arg(set_kind)::text,
|
||||
sqlc.arg(official)::boolean,
|
||||
sqlc.arg(animated)::boolean,
|
||||
sqlc.arg(videos)::boolean,
|
||||
sqlc.arg(emojis)::boolean,
|
||||
sqlc.arg(masks)::boolean,
|
||||
sqlc.arg(installed)::boolean,
|
||||
sqlc.arg(archived)::boolean,
|
||||
sqlc.arg(installed_date)::int,
|
||||
sqlc.arg(thumb_document_id)::bigint,
|
||||
sqlc.arg(thumbs_json)::jsonb,
|
||||
sqlc.arg(thumb_dc_id)::int,
|
||||
sqlc.arg(thumb_version)::int,
|
||||
sqlc.arg(document_ids_json)::jsonb,
|
||||
sqlc.arg(packs_json)::jsonb,
|
||||
sqlc.arg(sort_order)::int,
|
||||
sqlc.arg(system_key)::text
|
||||
)
|
||||
ON CONFLICT (id) DO UPDATE SET
|
||||
access_hash = EXCLUDED.access_hash,
|
||||
short_name = EXCLUDED.short_name,
|
||||
title = EXCLUDED.title,
|
||||
count = EXCLUDED.count,
|
||||
hash = EXCLUDED.hash,
|
||||
set_kind = EXCLUDED.set_kind,
|
||||
official = EXCLUDED.official,
|
||||
animated = EXCLUDED.animated,
|
||||
videos = EXCLUDED.videos,
|
||||
emojis = EXCLUDED.emojis,
|
||||
masks = EXCLUDED.masks,
|
||||
installed = EXCLUDED.installed,
|
||||
archived = EXCLUDED.archived,
|
||||
installed_date = EXCLUDED.installed_date,
|
||||
thumb_document_id = EXCLUDED.thumb_document_id,
|
||||
thumbs = EXCLUDED.thumbs,
|
||||
thumb_dc_id = EXCLUDED.thumb_dc_id,
|
||||
thumb_version = EXCLUDED.thumb_version,
|
||||
document_ids = EXCLUDED.document_ids,
|
||||
packs = EXCLUDED.packs,
|
||||
sort_order = EXCLUDED.sort_order,
|
||||
system_key = EXCLUDED.system_key;
|
||||
|
||||
-- name: GetStickerSetByID :one
|
||||
SELECT
|
||||
id, access_hash, short_name, title, count, hash, set_kind,
|
||||
official, animated, videos, emojis, masks, installed, archived, installed_date,
|
||||
thumb_document_id, thumbs::text AS thumbs_json, thumb_dc_id, thumb_version,
|
||||
document_ids::text AS document_ids_json, packs::text AS packs_json, sort_order, system_key
|
||||
FROM sticker_sets
|
||||
WHERE id = sqlc.arg(id)::bigint;
|
||||
|
||||
-- name: GetStickerSetByShortName :one
|
||||
SELECT
|
||||
id, access_hash, short_name, title, count, hash, set_kind,
|
||||
official, animated, videos, emojis, masks, installed, archived, installed_date,
|
||||
thumb_document_id, thumbs::text AS thumbs_json, thumb_dc_id, thumb_version,
|
||||
document_ids::text AS document_ids_json, packs::text AS packs_json, sort_order, system_key
|
||||
FROM sticker_sets
|
||||
WHERE short_name = sqlc.arg(short_name)::text;
|
||||
|
||||
-- name: GetStickerSetBySystemKey :one
|
||||
SELECT
|
||||
id, access_hash, short_name, title, count, hash, set_kind,
|
||||
official, animated, videos, emojis, masks, installed, archived, installed_date,
|
||||
thumb_document_id, thumbs::text AS thumbs_json, thumb_dc_id, thumb_version,
|
||||
document_ids::text AS document_ids_json, packs::text AS packs_json, sort_order, system_key
|
||||
FROM sticker_sets
|
||||
WHERE system_key = sqlc.arg(system_key)::text;
|
||||
|
||||
-- name: ListStickerSetsByKind :many
|
||||
SELECT
|
||||
id, access_hash, short_name, title, count, hash, set_kind,
|
||||
official, animated, videos, emojis, masks, installed, archived, installed_date,
|
||||
thumb_document_id, thumbs::text AS thumbs_json, thumb_dc_id, thumb_version,
|
||||
document_ids::text AS document_ids_json, packs::text AS packs_json, sort_order, system_key
|
||||
FROM sticker_sets
|
||||
WHERE set_kind = sqlc.arg(set_kind)::text
|
||||
ORDER BY sort_order ASC, id ASC;
|
||||
|
||||
-- name: CountStickerSets :one
|
||||
SELECT count(*)::int AS total FROM sticker_sets;
|
||||
|
||||
-- available_reactions ---------------------------------------------------------
|
||||
|
||||
-- name: PutAvailableReaction :exec
|
||||
INSERT INTO available_reactions (
|
||||
reaction, title, inactive, premium,
|
||||
static_icon_id, appear_animation_id, select_animation_id,
|
||||
activate_animation_id, effect_animation_id, around_animation_id, center_icon_id, sort_order
|
||||
) VALUES (
|
||||
sqlc.arg(reaction)::text,
|
||||
sqlc.arg(title)::text,
|
||||
sqlc.arg(inactive)::boolean,
|
||||
sqlc.arg(premium)::boolean,
|
||||
sqlc.arg(static_icon_id)::bigint,
|
||||
sqlc.arg(appear_animation_id)::bigint,
|
||||
sqlc.arg(select_animation_id)::bigint,
|
||||
sqlc.arg(activate_animation_id)::bigint,
|
||||
sqlc.arg(effect_animation_id)::bigint,
|
||||
sqlc.arg(around_animation_id)::bigint,
|
||||
sqlc.arg(center_icon_id)::bigint,
|
||||
sqlc.arg(sort_order)::int
|
||||
)
|
||||
ON CONFLICT (reaction) DO UPDATE SET
|
||||
title = EXCLUDED.title,
|
||||
inactive = EXCLUDED.inactive,
|
||||
premium = EXCLUDED.premium,
|
||||
static_icon_id = EXCLUDED.static_icon_id,
|
||||
appear_animation_id = EXCLUDED.appear_animation_id,
|
||||
select_animation_id = EXCLUDED.select_animation_id,
|
||||
activate_animation_id = EXCLUDED.activate_animation_id,
|
||||
effect_animation_id = EXCLUDED.effect_animation_id,
|
||||
around_animation_id = EXCLUDED.around_animation_id,
|
||||
center_icon_id = EXCLUDED.center_icon_id,
|
||||
sort_order = EXCLUDED.sort_order;
|
||||
|
||||
-- name: ListAvailableReactions :many
|
||||
SELECT
|
||||
reaction, title, inactive, premium,
|
||||
static_icon_id, appear_animation_id, select_animation_id,
|
||||
activate_animation_id, effect_animation_id, around_animation_id, center_icon_id, sort_order
|
||||
FROM available_reactions
|
||||
ORDER BY sort_order ASC, reaction ASC;
|
||||
|
||||
-- name: CountAvailableReactions :one
|
||||
SELECT count(*)::int AS total FROM available_reactions;
|
||||
|
||||
-- profile_photos --------------------------------------------------------------
|
||||
|
||||
-- name: AddProfilePhoto :exec
|
||||
INSERT INTO profile_photos (owner_peer_type, owner_peer_id, photo_id, date, active, sort_order)
|
||||
VALUES (
|
||||
sqlc.arg(owner_peer_type)::text,
|
||||
sqlc.arg(owner_peer_id)::bigint,
|
||||
sqlc.arg(photo_id)::bigint,
|
||||
sqlc.arg(date)::int,
|
||||
true,
|
||||
sqlc.arg(sort_order)::bigint
|
||||
)
|
||||
ON CONFLICT (owner_peer_type, owner_peer_id, photo_id) DO UPDATE SET
|
||||
date = EXCLUDED.date,
|
||||
active = true,
|
||||
sort_order = EXCLUDED.sort_order;
|
||||
|
||||
-- name: NextProfilePhotoOrder :one
|
||||
SELECT COALESCE(MAX(sort_order), 0)::bigint AS max_order
|
||||
FROM profile_photos
|
||||
WHERE owner_peer_type = sqlc.arg(owner_peer_type)::text
|
||||
AND owner_peer_id = sqlc.arg(owner_peer_id)::bigint;
|
||||
|
||||
-- name: CurrentProfilePhoto :one
|
||||
SELECT photo_id
|
||||
FROM profile_photos
|
||||
WHERE owner_peer_type = sqlc.arg(owner_peer_type)::text
|
||||
AND owner_peer_id = sqlc.arg(owner_peer_id)::bigint
|
||||
AND active
|
||||
ORDER BY sort_order DESC
|
||||
LIMIT 1;
|
||||
|
||||
-- name: CurrentProfilePhotosForOwners :many
|
||||
SELECT DISTINCT ON (pp.owner_peer_id)
|
||||
pp.owner_peer_id,
|
||||
pp.photo_id,
|
||||
ph.dc_id,
|
||||
ph.sizes::text AS sizes_json
|
||||
FROM profile_photos pp
|
||||
JOIN photos ph ON ph.id = pp.photo_id
|
||||
WHERE pp.owner_peer_type = sqlc.arg(owner_peer_type)::text
|
||||
AND pp.owner_peer_id = ANY(sqlc.arg(owner_ids)::bigint[])
|
||||
AND pp.active
|
||||
ORDER BY pp.owner_peer_id, pp.sort_order DESC;
|
||||
|
||||
-- name: ListProfilePhotos :many
|
||||
SELECT photo_id
|
||||
FROM profile_photos
|
||||
WHERE owner_peer_type = sqlc.arg(owner_peer_type)::text
|
||||
AND owner_peer_id = sqlc.arg(owner_peer_id)::bigint
|
||||
AND active
|
||||
AND (sqlc.arg(max_id)::bigint <= 0 OR photo_id < sqlc.arg(max_id)::bigint)
|
||||
ORDER BY sort_order DESC
|
||||
OFFSET sqlc.arg(offset_count)::int
|
||||
LIMIT sqlc.arg(limit_count)::int;
|
||||
|
||||
-- name: CountProfilePhotos :one
|
||||
SELECT count(*)::int AS total
|
||||
FROM profile_photos
|
||||
WHERE owner_peer_type = sqlc.arg(owner_peer_type)::text
|
||||
AND owner_peer_id = sqlc.arg(owner_peer_id)::bigint
|
||||
AND active;
|
||||
|
||||
-- name: DeactivateProfilePhotos :many
|
||||
UPDATE profile_photos
|
||||
SET active = false
|
||||
WHERE owner_peer_type = sqlc.arg(owner_peer_type)::text
|
||||
AND owner_peer_id = sqlc.arg(owner_peer_id)::bigint
|
||||
AND photo_id = ANY(sqlc.arg(photo_ids)::bigint[])
|
||||
AND active
|
||||
RETURNING photo_id;
|
||||
932
internal/store/postgres/queries/message.sql
Normal file
932
internal/store/postgres/queries/message.sql
Normal file
|
|
@ -0,0 +1,932 @@
|
|||
-- name: CreateMessage :one
|
||||
WITH pm AS (
|
||||
INSERT INTO private_messages (
|
||||
sender_user_id,
|
||||
recipient_user_id,
|
||||
random_id,
|
||||
message_date,
|
||||
body,
|
||||
entities
|
||||
) VALUES (
|
||||
sqlc.arg(from_user_id),
|
||||
sqlc.arg(owner_user_id),
|
||||
0,
|
||||
sqlc.arg(message_date),
|
||||
sqlc.arg(body),
|
||||
sqlc.arg(entities_json)::jsonb
|
||||
)
|
||||
RETURNING id, sender_user_id
|
||||
),
|
||||
box AS (
|
||||
INSERT INTO message_boxes (
|
||||
owner_user_id,
|
||||
box_id,
|
||||
private_message_id,
|
||||
message_sender_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
outgoing,
|
||||
body,
|
||||
entities,
|
||||
pts
|
||||
)
|
||||
SELECT
|
||||
sqlc.arg(owner_user_id),
|
||||
sqlc.arg(box_id),
|
||||
pm.id,
|
||||
pm.sender_user_id,
|
||||
sqlc.arg(peer_type),
|
||||
sqlc.arg(peer_id),
|
||||
sqlc.arg(from_user_id),
|
||||
sqlc.arg(message_date),
|
||||
sqlc.arg(outgoing),
|
||||
sqlc.arg(body),
|
||||
sqlc.arg(entities_json)::jsonb,
|
||||
sqlc.arg(pts)
|
||||
FROM pm
|
||||
RETURNING
|
||||
box_id,
|
||||
private_message_id,
|
||||
owner_user_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
entities::text AS entities_json,
|
||||
pts
|
||||
)
|
||||
SELECT
|
||||
box_id,
|
||||
private_message_id,
|
||||
owner_user_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
entities_json,
|
||||
pts
|
||||
FROM box;
|
||||
|
||||
-- name: CreatePrivateMessage :one
|
||||
INSERT INTO private_messages (
|
||||
sender_user_id,
|
||||
recipient_user_id,
|
||||
random_id,
|
||||
message_date,
|
||||
body,
|
||||
entities,
|
||||
silent,
|
||||
noforwards,
|
||||
reply_to_msg_id,
|
||||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
quote_text,
|
||||
quote_entities,
|
||||
quote_offset,
|
||||
fwd_from_peer_type,
|
||||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
media
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, sqlc.arg(entities_json)::jsonb,
|
||||
sqlc.arg(silent)::boolean,
|
||||
sqlc.arg(noforwards)::boolean,
|
||||
sqlc.arg(reply_to_msg_id)::int,
|
||||
sqlc.arg(reply_to_peer_type)::text,
|
||||
sqlc.arg(reply_to_peer_id)::bigint,
|
||||
sqlc.arg(reply_to_top_id)::int,
|
||||
sqlc.arg(quote_text)::text,
|
||||
sqlc.arg(quote_entities_json)::jsonb,
|
||||
sqlc.arg(quote_offset)::int,
|
||||
sqlc.arg(fwd_from_peer_type)::text,
|
||||
sqlc.arg(fwd_from_peer_id)::bigint,
|
||||
sqlc.arg(fwd_from_name)::text,
|
||||
sqlc.arg(fwd_date)::int,
|
||||
sqlc.arg(media_json)::jsonb
|
||||
)
|
||||
ON CONFLICT (sender_user_id, random_id) WHERE random_id <> 0 DO NOTHING
|
||||
RETURNING
|
||||
id,
|
||||
sender_user_id,
|
||||
recipient_user_id,
|
||||
random_id,
|
||||
message_date,
|
||||
edit_date,
|
||||
body,
|
||||
entities::text AS entities_json;
|
||||
|
||||
-- name: GetPrivateMessageByRandomID :one
|
||||
SELECT
|
||||
id,
|
||||
sender_user_id,
|
||||
recipient_user_id,
|
||||
random_id,
|
||||
message_date,
|
||||
edit_date,
|
||||
body,
|
||||
entities::text AS entities_json
|
||||
FROM private_messages
|
||||
WHERE sender_user_id = $1
|
||||
AND random_id = $2
|
||||
AND random_id <> 0;
|
||||
|
||||
-- name: CreateMessageBox :one
|
||||
INSERT INTO message_boxes (
|
||||
owner_user_id,
|
||||
box_id,
|
||||
private_message_id,
|
||||
message_sender_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
outgoing,
|
||||
body,
|
||||
entities,
|
||||
silent,
|
||||
noforwards,
|
||||
reply_to_msg_id,
|
||||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
quote_text,
|
||||
quote_entities,
|
||||
quote_offset,
|
||||
fwd_from_peer_type,
|
||||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
pts,
|
||||
media
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5, $6, $7, $8, $9, $10, sqlc.arg(entities_json)::jsonb,
|
||||
sqlc.arg(silent)::boolean,
|
||||
sqlc.arg(noforwards)::boolean,
|
||||
sqlc.arg(reply_to_msg_id)::int,
|
||||
sqlc.arg(reply_to_peer_type)::text,
|
||||
sqlc.arg(reply_to_peer_id)::bigint,
|
||||
sqlc.arg(reply_to_top_id)::int,
|
||||
sqlc.arg(quote_text)::text,
|
||||
sqlc.arg(quote_entities_json)::jsonb,
|
||||
sqlc.arg(quote_offset)::int,
|
||||
sqlc.arg(fwd_from_peer_type)::text,
|
||||
sqlc.arg(fwd_from_peer_id)::bigint,
|
||||
sqlc.arg(fwd_from_name)::text,
|
||||
sqlc.arg(fwd_date)::int,
|
||||
sqlc.arg(pts)::int,
|
||||
sqlc.arg(media_json)::jsonb
|
||||
)
|
||||
RETURNING
|
||||
box_id,
|
||||
private_message_id,
|
||||
owner_user_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
entities::text AS entities_json,
|
||||
silent,
|
||||
noforwards,
|
||||
reply_to_msg_id,
|
||||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
quote_text,
|
||||
quote_entities::text AS quote_entities_json,
|
||||
quote_offset,
|
||||
fwd_from_peer_type,
|
||||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
pts,
|
||||
media::text AS media_json;
|
||||
|
||||
-- name: GetMessageBoxByPrivateMessage :one
|
||||
SELECT
|
||||
box_id,
|
||||
private_message_id,
|
||||
owner_user_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
entities::text AS entities_json,
|
||||
silent,
|
||||
noforwards,
|
||||
reply_to_msg_id,
|
||||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
quote_text,
|
||||
quote_entities::text AS quote_entities_json,
|
||||
quote_offset,
|
||||
fwd_from_peer_type,
|
||||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
pts,
|
||||
media::text AS media_json
|
||||
FROM message_boxes
|
||||
WHERE owner_user_id = $1
|
||||
AND private_message_id = $2
|
||||
AND NOT deleted;
|
||||
|
||||
-- name: GetMessageBoxForReply :one
|
||||
SELECT
|
||||
box_id,
|
||||
private_message_id,
|
||||
message_sender_id
|
||||
FROM message_boxes
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND peer_type = sqlc.arg(peer_type)::text
|
||||
AND peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND box_id = sqlc.arg(box_id)::int
|
||||
AND NOT deleted
|
||||
LIMIT 1;
|
||||
|
||||
-- name: GetMessageBoxesForForward :many
|
||||
WITH requested AS (
|
||||
SELECT
|
||||
id::int AS box_id,
|
||||
ord::int AS ord
|
||||
FROM unnest(sqlc.arg(box_ids)::int[]) WITH ORDINALITY AS r(id, ord)
|
||||
)
|
||||
SELECT
|
||||
r.ord,
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.owner_user_id,
|
||||
m.message_sender_id,
|
||||
m.peer_type,
|
||||
m.peer_id,
|
||||
m.from_user_id,
|
||||
m.message_date,
|
||||
m.edit_date,
|
||||
m.outgoing,
|
||||
m.body,
|
||||
m.entities::text AS entities_json,
|
||||
m.silent,
|
||||
m.noforwards,
|
||||
m.reply_to_msg_id,
|
||||
m.reply_to_peer_type,
|
||||
m.reply_to_peer_id,
|
||||
m.reply_to_top_id,
|
||||
m.quote_text,
|
||||
m.quote_entities::text AS quote_entities_json,
|
||||
m.quote_offset,
|
||||
m.fwd_from_peer_type,
|
||||
m.fwd_from_peer_id,
|
||||
m.fwd_from_name,
|
||||
m.fwd_date,
|
||||
m.pts,
|
||||
m.media::text AS media_json
|
||||
FROM requested r
|
||||
JOIN message_boxes m
|
||||
ON m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = sqlc.arg(peer_type)::text
|
||||
AND m.peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND m.box_id = r.box_id
|
||||
AND NOT m.deleted
|
||||
ORDER BY r.ord ASC;
|
||||
|
||||
-- name: MaxMessageBoxID :one
|
||||
SELECT COALESCE(MAX(box_id), 0)::int AS max_box_id
|
||||
FROM message_boxes
|
||||
WHERE owner_user_id = $1;
|
||||
|
||||
-- name: ListMessagesByUser :many
|
||||
WITH load_params AS (
|
||||
SELECT
|
||||
sqlc.arg(offset_id)::int AS offset_id,
|
||||
sqlc.arg(offset_date)::int AS offset_date,
|
||||
sqlc.arg(add_offset)::int AS add_offset,
|
||||
sqlc.arg(limit_count)::int AS limit_count,
|
||||
CASE
|
||||
WHEN sqlc.arg(add_offset)::int >= 0 THEN 'backward'
|
||||
WHEN sqlc.arg(add_offset)::int + sqlc.arg(limit_count)::int > 0 THEN 'around'
|
||||
ELSE 'forward'
|
||||
END::text AS load_type
|
||||
),
|
||||
base AS NOT MATERIALIZED (
|
||||
SELECT
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.owner_user_id,
|
||||
m.peer_type,
|
||||
m.peer_id,
|
||||
m.from_user_id,
|
||||
m.message_date,
|
||||
m.edit_date,
|
||||
m.outgoing,
|
||||
m.body,
|
||||
m.entities::text AS entities_json,
|
||||
m.silent,
|
||||
m.noforwards,
|
||||
m.reply_to_msg_id,
|
||||
m.reply_to_peer_type,
|
||||
m.reply_to_peer_id,
|
||||
m.reply_to_top_id,
|
||||
m.quote_text,
|
||||
m.quote_entities::text AS quote_entities_json,
|
||||
m.quote_offset,
|
||||
m.fwd_from_peer_type,
|
||||
m.fwd_from_peer_id,
|
||||
m.fwd_from_name,
|
||||
m.fwd_date,
|
||||
m.pts,
|
||||
m.media::text AS media_json,
|
||||
COALESCE(peer_u.id, 0)::bigint AS peer_user_id,
|
||||
COALESCE(peer_u.access_hash, 0)::bigint AS peer_access_hash,
|
||||
COALESCE(peer_u.phone, '')::text AS peer_phone,
|
||||
COALESCE(peer_u.first_name, '')::text AS peer_first_name,
|
||||
COALESCE(peer_u.last_name, '')::text AS peer_last_name,
|
||||
COALESCE(peer_u.username, '')::text AS peer_username,
|
||||
COALESCE(peer_u.country_code, '')::text AS peer_country_code,
|
||||
COALESCE(peer_u.verified, false)::boolean AS peer_verified,
|
||||
COALESCE(peer_u.support, false)::boolean AS peer_support,
|
||||
COALESCE(peer_u.last_seen_at, 0)::bigint AS peer_last_seen_at,
|
||||
COALESCE(from_u.id, 0)::bigint AS from_user_user_id,
|
||||
COALESCE(from_u.access_hash, 0)::bigint AS from_user_access_hash,
|
||||
COALESCE(from_u.phone, '')::text AS from_user_phone,
|
||||
COALESCE(from_u.first_name, '')::text AS from_user_first_name,
|
||||
COALESCE(from_u.last_name, '')::text AS from_user_last_name,
|
||||
COALESCE(from_u.username, '')::text AS from_user_username,
|
||||
COALESCE(from_u.country_code, '')::text AS from_user_country_code,
|
||||
COALESCE(from_u.verified, false)::boolean AS from_user_verified,
|
||||
COALESCE(from_u.support, false)::boolean AS from_user_support,
|
||||
COALESCE(from_u.last_seen_at, 0)::bigint AS from_user_last_seen_at
|
||||
FROM message_boxes m
|
||||
LEFT JOIN users peer_u ON m.peer_type = 'user' AND peer_u.id = m.peer_id
|
||||
LEFT JOIN users from_u ON from_u.id = m.from_user_id
|
||||
WHERE m.owner_user_id = $1
|
||||
AND NOT m.deleted
|
||||
AND (
|
||||
NOT sqlc.arg(has_peer)::boolean
|
||||
OR (m.peer_type = sqlc.arg(peer_type)::text AND m.peer_id = sqlc.arg(peer_id)::bigint)
|
||||
)
|
||||
AND (
|
||||
sqlc.arg(query)::text = ''
|
||||
OR m.body ILIKE ('%' || sqlc.arg(query)::text || '%')
|
||||
)
|
||||
AND (sqlc.arg(max_id)::int <= 0 OR m.box_id < sqlc.arg(max_id)::int)
|
||||
AND (sqlc.arg(min_id)::int <= 0 OR m.box_id > sqlc.arg(min_id)::int)
|
||||
),
|
||||
total AS (
|
||||
SELECT count(*)::int AS total_count
|
||||
FROM base
|
||||
WHERE sqlc.arg(need_total_count)::boolean
|
||||
),
|
||||
backward AS (
|
||||
SELECT b.*
|
||||
FROM base b
|
||||
CROSS JOIN load_params p
|
||||
WHERE p.load_type = 'backward'
|
||||
AND (
|
||||
(p.offset_date > 0 AND b.message_date < p.offset_date)
|
||||
OR (p.offset_date <= 0 AND (p.offset_id <= 0 OR b.box_id < p.offset_id))
|
||||
)
|
||||
ORDER BY b.box_id DESC
|
||||
OFFSET GREATEST((SELECT add_offset FROM load_params), 0)
|
||||
LIMIT (SELECT limit_count FROM load_params)
|
||||
),
|
||||
around_forward AS (
|
||||
SELECT f.*
|
||||
FROM (
|
||||
SELECT b.*
|
||||
FROM base b
|
||||
CROSS JOIN load_params p
|
||||
WHERE p.load_type = 'around'
|
||||
AND (
|
||||
(p.offset_date > 0 AND b.message_date >= p.offset_date)
|
||||
OR (p.offset_date <= 0 AND p.offset_id > 0 AND b.box_id > p.offset_id)
|
||||
)
|
||||
ORDER BY b.box_id ASC
|
||||
LIMIT LEAST(-(SELECT add_offset FROM load_params), (SELECT limit_count FROM load_params))
|
||||
) f
|
||||
),
|
||||
around_backward AS (
|
||||
SELECT b.*
|
||||
FROM base b
|
||||
CROSS JOIN load_params p
|
||||
WHERE p.load_type = 'around'
|
||||
AND (
|
||||
(p.offset_date > 0 AND b.message_date < p.offset_date)
|
||||
OR (p.offset_date <= 0 AND (p.offset_id <= 0 OR b.box_id <= p.offset_id))
|
||||
)
|
||||
ORDER BY b.box_id DESC
|
||||
LIMIT GREATEST((SELECT limit_count + add_offset FROM load_params), 0)
|
||||
),
|
||||
forward AS (
|
||||
SELECT f.*
|
||||
FROM (
|
||||
SELECT b.*
|
||||
FROM base b
|
||||
CROSS JOIN load_params p
|
||||
WHERE p.load_type = 'forward'
|
||||
AND (
|
||||
(p.offset_date > 0 AND b.message_date >= p.offset_date)
|
||||
OR (p.offset_date <= 0 AND p.offset_id > 0 AND b.box_id > p.offset_id)
|
||||
)
|
||||
ORDER BY b.box_id ASC
|
||||
LIMIT (SELECT limit_count FROM load_params)
|
||||
) f
|
||||
),
|
||||
paged AS (
|
||||
SELECT * FROM backward
|
||||
UNION ALL
|
||||
SELECT * FROM around_forward
|
||||
UNION ALL
|
||||
SELECT * FROM around_backward
|
||||
UNION ALL
|
||||
SELECT * FROM forward
|
||||
)
|
||||
SELECT
|
||||
box_id,
|
||||
private_message_id,
|
||||
owner_user_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
entities_json,
|
||||
silent,
|
||||
noforwards,
|
||||
reply_to_msg_id,
|
||||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
quote_text,
|
||||
quote_entities_json,
|
||||
quote_offset,
|
||||
fwd_from_peer_type,
|
||||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
pts,
|
||||
media_json,
|
||||
peer_user_id,
|
||||
peer_access_hash,
|
||||
peer_phone,
|
||||
peer_first_name,
|
||||
peer_last_name,
|
||||
peer_username,
|
||||
peer_country_code,
|
||||
peer_verified,
|
||||
peer_support,
|
||||
peer_last_seen_at,
|
||||
from_user_user_id,
|
||||
from_user_access_hash,
|
||||
from_user_phone,
|
||||
from_user_first_name,
|
||||
from_user_last_name,
|
||||
from_user_username,
|
||||
from_user_country_code,
|
||||
from_user_verified,
|
||||
from_user_support,
|
||||
from_user_last_seen_at,
|
||||
COALESCE(total.total_count, 0)::int AS total_count
|
||||
FROM paged
|
||||
CROSS JOIN total
|
||||
ORDER BY box_id DESC;
|
||||
|
||||
-- name: GetMessageBoxesByIDs :many
|
||||
SELECT
|
||||
wanted.box_id AS requested_box_id,
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.owner_user_id,
|
||||
m.peer_type,
|
||||
m.peer_id,
|
||||
m.from_user_id,
|
||||
m.message_date,
|
||||
m.edit_date,
|
||||
m.outgoing,
|
||||
m.body,
|
||||
m.entities::text AS entities_json,
|
||||
m.silent,
|
||||
m.noforwards,
|
||||
m.reply_to_msg_id,
|
||||
m.reply_to_peer_type,
|
||||
m.reply_to_peer_id,
|
||||
m.reply_to_top_id,
|
||||
m.quote_text,
|
||||
m.quote_entities::text AS quote_entities_json,
|
||||
m.quote_offset,
|
||||
m.fwd_from_peer_type,
|
||||
m.fwd_from_peer_id,
|
||||
m.fwd_from_name,
|
||||
m.fwd_date,
|
||||
m.pts,
|
||||
m.media::text AS media_json,
|
||||
COALESCE(peer_u.id, 0)::bigint AS peer_user_id,
|
||||
COALESCE(peer_u.access_hash, 0)::bigint AS peer_access_hash,
|
||||
COALESCE(peer_u.phone, '')::text AS peer_phone,
|
||||
COALESCE(peer_u.first_name, '')::text AS peer_first_name,
|
||||
COALESCE(peer_u.last_name, '')::text AS peer_last_name,
|
||||
COALESCE(peer_u.username, '')::text AS peer_username,
|
||||
COALESCE(peer_u.country_code, '')::text AS peer_country_code,
|
||||
COALESCE(peer_u.verified, false)::boolean AS peer_verified,
|
||||
COALESCE(peer_u.support, false)::boolean AS peer_support,
|
||||
COALESCE(peer_u.last_seen_at, 0)::bigint AS peer_last_seen_at,
|
||||
COALESCE(from_u.id, 0)::bigint AS from_user_user_id,
|
||||
COALESCE(from_u.access_hash, 0)::bigint AS from_user_access_hash,
|
||||
COALESCE(from_u.phone, '')::text AS from_user_phone,
|
||||
COALESCE(from_u.first_name, '')::text AS from_user_first_name,
|
||||
COALESCE(from_u.last_name, '')::text AS from_user_last_name,
|
||||
COALESCE(from_u.username, '')::text AS from_user_username,
|
||||
COALESCE(from_u.country_code, '')::text AS from_user_country_code,
|
||||
COALESCE(from_u.verified, false)::boolean AS from_user_verified,
|
||||
COALESCE(from_u.support, false)::boolean AS from_user_support,
|
||||
COALESCE(from_u.last_seen_at, 0)::bigint AS from_user_last_seen_at
|
||||
FROM unnest(@box_ids::int[]) WITH ORDINALITY AS wanted(box_id, ord)
|
||||
JOIN message_boxes m
|
||||
ON m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.box_id = wanted.box_id
|
||||
AND NOT m.deleted
|
||||
LEFT JOIN users peer_u ON m.peer_type = 'user' AND peer_u.id = m.peer_id
|
||||
LEFT JOIN users from_u ON from_u.id = m.from_user_id
|
||||
ORDER BY wanted.ord ASC;
|
||||
|
||||
-- name: GetMessageBoxForEdit :one
|
||||
SELECT
|
||||
box_id,
|
||||
private_message_id,
|
||||
owner_user_id,
|
||||
message_sender_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
entities::text AS entities_json,
|
||||
silent,
|
||||
noforwards,
|
||||
reply_to_msg_id,
|
||||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
quote_text,
|
||||
quote_entities::text AS quote_entities_json,
|
||||
quote_offset,
|
||||
fwd_from_peer_type,
|
||||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
pts,
|
||||
media::text AS media_json
|
||||
FROM message_boxes
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND box_id = sqlc.arg(box_id)::int
|
||||
AND peer_type = sqlc.arg(peer_type)::text
|
||||
AND peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND NOT deleted
|
||||
LIMIT 1
|
||||
FOR UPDATE;
|
||||
|
||||
-- name: ListVisibleMessageBoxesByPrivateMessage :many
|
||||
SELECT
|
||||
box_id,
|
||||
private_message_id,
|
||||
owner_user_id,
|
||||
message_sender_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
entities::text AS entities_json,
|
||||
silent,
|
||||
noforwards,
|
||||
reply_to_msg_id,
|
||||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
quote_text,
|
||||
quote_entities::text AS quote_entities_json,
|
||||
quote_offset,
|
||||
fwd_from_peer_type,
|
||||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
pts,
|
||||
media::text AS media_json
|
||||
FROM message_boxes
|
||||
WHERE message_sender_id = sqlc.arg(message_sender_id)::bigint
|
||||
AND private_message_id = sqlc.arg(private_message_id)::bigint
|
||||
AND NOT deleted
|
||||
ORDER BY owner_user_id ASC, box_id ASC
|
||||
FOR UPDATE;
|
||||
|
||||
-- name: UpdatePrivateMessageEdit :exec
|
||||
UPDATE private_messages
|
||||
SET body = sqlc.arg(body)::text,
|
||||
entities = sqlc.arg(entities_json)::jsonb,
|
||||
edit_date = sqlc.arg(edit_date)::int
|
||||
WHERE sender_user_id = sqlc.arg(sender_user_id)::bigint
|
||||
AND id = sqlc.arg(private_message_id)::bigint;
|
||||
|
||||
-- name: UpdateMessageBoxEdit :one
|
||||
UPDATE message_boxes
|
||||
SET body = sqlc.arg(body)::text,
|
||||
entities = sqlc.arg(entities_json)::jsonb,
|
||||
edit_date = sqlc.arg(edit_date)::int,
|
||||
pts = sqlc.arg(pts)::int
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND box_id = sqlc.arg(box_id)::int
|
||||
AND NOT deleted
|
||||
RETURNING
|
||||
box_id,
|
||||
private_message_id,
|
||||
owner_user_id,
|
||||
message_sender_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
from_user_id,
|
||||
message_date,
|
||||
edit_date,
|
||||
outgoing,
|
||||
body,
|
||||
entities::text AS entities_json,
|
||||
silent,
|
||||
noforwards,
|
||||
reply_to_msg_id,
|
||||
reply_to_peer_type,
|
||||
reply_to_peer_id,
|
||||
reply_to_top_id,
|
||||
quote_text,
|
||||
quote_entities::text AS quote_entities_json,
|
||||
quote_offset,
|
||||
fwd_from_peer_type,
|
||||
fwd_from_peer_id,
|
||||
fwd_from_name,
|
||||
fwd_date,
|
||||
pts,
|
||||
media::text AS media_json;
|
||||
|
||||
-- name: GetDialogReadStateForUpdate :one
|
||||
SELECT
|
||||
user_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
top_message_id,
|
||||
read_inbox_max_id,
|
||||
unread_count
|
||||
FROM dialogs
|
||||
WHERE user_id = sqlc.arg(user_id)::bigint
|
||||
AND peer_type = sqlc.arg(peer_type)::text
|
||||
AND peer_id = sqlc.arg(peer_id)::bigint
|
||||
FOR UPDATE;
|
||||
|
||||
-- name: LatestIncomingReadReceiptCandidate :one
|
||||
SELECT
|
||||
m.message_sender_id,
|
||||
m.private_message_id,
|
||||
sender_box.owner_user_id AS sender_owner_user_id,
|
||||
sender_box.box_id AS sender_box_id
|
||||
FROM message_boxes m
|
||||
JOIN message_boxes sender_box
|
||||
ON sender_box.message_sender_id = m.message_sender_id
|
||||
AND sender_box.private_message_id = m.private_message_id
|
||||
AND sender_box.owner_user_id = m.message_sender_id
|
||||
AND sender_box.outgoing
|
||||
AND NOT sender_box.deleted
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = sqlc.arg(peer_type)::text
|
||||
AND m.peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND NOT m.outgoing
|
||||
AND NOT m.deleted
|
||||
AND m.box_id > sqlc.arg(old_read_inbox_max_id)::int
|
||||
AND m.box_id <= sqlc.arg(new_read_inbox_max_id)::int
|
||||
ORDER BY m.box_id DESC
|
||||
LIMIT 1;
|
||||
|
||||
-- name: UpdateDialogReadInbox :one
|
||||
UPDATE dialogs d
|
||||
SET
|
||||
read_inbox_max_id = GREATEST(d.read_inbox_max_id, sqlc.arg(read_inbox_max_id)::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 > GREATEST(d.read_inbox_max_id, sqlc.arg(read_inbox_max_id)::int)
|
||||
),
|
||||
unread_mark = false,
|
||||
unread_mentions_count = 0,
|
||||
unread_reactions_count = 0,
|
||||
updated_at = now()
|
||||
WHERE d.user_id = sqlc.arg(user_id)::bigint
|
||||
AND d.peer_type = sqlc.arg(peer_type)::text
|
||||
AND d.peer_id = sqlc.arg(peer_id)::bigint
|
||||
RETURNING
|
||||
d.read_inbox_max_id,
|
||||
d.unread_count;
|
||||
|
||||
-- name: UpdateDialogReadOutbox :one
|
||||
UPDATE dialogs
|
||||
SET
|
||||
read_outbox_max_id = GREATEST(read_outbox_max_id, sqlc.arg(read_outbox_max_id)::int),
|
||||
updated_at = now()
|
||||
WHERE user_id = sqlc.arg(user_id)::bigint
|
||||
AND peer_type = sqlc.arg(peer_type)::text
|
||||
AND peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND read_outbox_max_id < sqlc.arg(read_outbox_max_id)::int
|
||||
RETURNING read_outbox_max_id;
|
||||
|
||||
-- name: GetOutboxMessageForReadDate :one
|
||||
SELECT box_id
|
||||
FROM message_boxes
|
||||
WHERE owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND peer_type = sqlc.arg(peer_type)::text
|
||||
AND peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND box_id = sqlc.arg(box_id)::int
|
||||
AND outgoing
|
||||
AND NOT deleted
|
||||
LIMIT 1;
|
||||
|
||||
-- name: GetOutboxReadDate :one
|
||||
SELECT COALESCE(MIN(date), 0)::int AS read_date
|
||||
FROM user_update_events
|
||||
WHERE user_id = sqlc.arg(user_id)::bigint
|
||||
AND event_type = 'read_history_outbox'
|
||||
AND peer_type = sqlc.arg(peer_type)::text
|
||||
AND peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND max_id >= sqlc.arg(message_id)::int;
|
||||
|
||||
-- name: DeleteMessageBoxesByIDs :many
|
||||
WITH updated AS (
|
||||
UPDATE message_boxes m
|
||||
SET deleted = true
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.box_id = ANY(sqlc.arg(box_ids)::int[])
|
||||
AND NOT m.deleted
|
||||
RETURNING
|
||||
m.owner_user_id,
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.message_sender_id,
|
||||
m.peer_type,
|
||||
m.peer_id
|
||||
)
|
||||
SELECT
|
||||
owner_user_id,
|
||||
box_id,
|
||||
private_message_id,
|
||||
message_sender_id,
|
||||
peer_type,
|
||||
peer_id
|
||||
FROM updated
|
||||
ORDER BY box_id ASC;
|
||||
|
||||
-- name: DeleteMessageBoxesByPeer :many
|
||||
WITH updated AS (
|
||||
UPDATE message_boxes m
|
||||
SET deleted = true
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = sqlc.arg(peer_type)::text
|
||||
AND m.peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND (sqlc.arg(max_id)::int <= 0 OR m.box_id <= sqlc.arg(max_id)::int)
|
||||
AND NOT m.deleted
|
||||
RETURNING
|
||||
m.owner_user_id,
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.message_sender_id,
|
||||
m.peer_type,
|
||||
m.peer_id
|
||||
)
|
||||
SELECT
|
||||
owner_user_id,
|
||||
box_id,
|
||||
private_message_id,
|
||||
message_sender_id,
|
||||
peer_type,
|
||||
peer_id
|
||||
FROM updated
|
||||
ORDER BY box_id ASC;
|
||||
|
||||
-- name: DeleteMessageBoxesByPeerBatch :many
|
||||
WITH target AS (
|
||||
SELECT
|
||||
m.owner_user_id,
|
||||
m.box_id
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = sqlc.arg(peer_type)::text
|
||||
AND m.peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND (sqlc.arg(max_id)::int <= 0 OR m.box_id <= sqlc.arg(max_id)::int)
|
||||
AND NOT m.deleted
|
||||
ORDER BY m.box_id DESC
|
||||
LIMIT sqlc.arg(limit_count)::int
|
||||
FOR UPDATE SKIP LOCKED
|
||||
),
|
||||
updated AS (
|
||||
UPDATE message_boxes m
|
||||
SET deleted = true
|
||||
FROM target t
|
||||
WHERE m.owner_user_id = t.owner_user_id
|
||||
AND m.box_id = t.box_id
|
||||
RETURNING
|
||||
m.owner_user_id,
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.message_sender_id,
|
||||
m.peer_type,
|
||||
m.peer_id
|
||||
)
|
||||
SELECT
|
||||
owner_user_id,
|
||||
box_id,
|
||||
private_message_id,
|
||||
message_sender_id,
|
||||
peer_type,
|
||||
peer_id
|
||||
FROM updated
|
||||
ORDER BY box_id ASC;
|
||||
|
||||
-- name: HasDeletableMessageBoxByPeer :one
|
||||
SELECT EXISTS (
|
||||
SELECT 1
|
||||
FROM message_boxes m
|
||||
WHERE m.owner_user_id = sqlc.arg(owner_user_id)::bigint
|
||||
AND m.peer_type = sqlc.arg(peer_type)::text
|
||||
AND m.peer_id = sqlc.arg(peer_id)::bigint
|
||||
AND (sqlc.arg(max_id)::int <= 0 OR m.box_id <= sqlc.arg(max_id)::int)
|
||||
AND NOT m.deleted
|
||||
LIMIT 1
|
||||
)::boolean AS more;
|
||||
|
||||
-- name: DeleteMessageBoxesByPrivateMessages :many
|
||||
WITH requested AS (
|
||||
SELECT
|
||||
(sqlc.arg(message_sender_ids)::bigint[])[i] AS message_sender_id,
|
||||
(sqlc.arg(private_message_ids)::bigint[])[i] AS private_message_id
|
||||
FROM generate_subscripts(sqlc.arg(private_message_ids)::bigint[], 1) AS g(i)
|
||||
WHERE i <= cardinality(sqlc.arg(message_sender_ids)::bigint[])
|
||||
),
|
||||
deduped AS (
|
||||
SELECT DISTINCT message_sender_id, private_message_id
|
||||
FROM requested
|
||||
),
|
||||
updated AS (
|
||||
UPDATE message_boxes m
|
||||
SET deleted = true
|
||||
FROM deduped d
|
||||
WHERE m.message_sender_id = d.message_sender_id
|
||||
AND m.private_message_id = d.private_message_id
|
||||
AND NOT m.deleted
|
||||
RETURNING
|
||||
m.owner_user_id,
|
||||
m.box_id,
|
||||
m.private_message_id,
|
||||
m.message_sender_id,
|
||||
m.peer_type,
|
||||
m.peer_id
|
||||
)
|
||||
SELECT
|
||||
owner_user_id,
|
||||
box_id,
|
||||
private_message_id,
|
||||
message_sender_id,
|
||||
peer_type,
|
||||
peer_id
|
||||
FROM updated
|
||||
ORDER BY owner_user_id ASC, box_id ASC;
|
||||
|
||||
-- name: TopVisibleMessageBoxByPeer :one
|
||||
SELECT
|
||||
box_id,
|
||||
message_date
|
||||
FROM message_boxes
|
||||
WHERE owner_user_id = $1
|
||||
AND peer_type = $2
|
||||
AND peer_id = $3
|
||||
AND NOT deleted
|
||||
ORDER BY box_id DESC
|
||||
LIMIT 1;
|
||||
23
internal/store/postgres/queries/temp_auth_key.sql
Normal file
23
internal/store/postgres/queries/temp_auth_key.sql
Normal file
|
|
@ -0,0 +1,23 @@
|
|||
-- name: UpsertTempAuthKeyBinding :exec
|
||||
INSERT INTO temp_auth_key_bindings (
|
||||
temp_auth_key_id, perm_auth_key_id, nonce, temp_session_id, expires_at, encrypted_message
|
||||
)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
ON CONFLICT (temp_auth_key_id) DO UPDATE SET
|
||||
perm_auth_key_id = EXCLUDED.perm_auth_key_id,
|
||||
nonce = EXCLUDED.nonce,
|
||||
temp_session_id = EXCLUDED.temp_session_id,
|
||||
expires_at = EXCLUDED.expires_at,
|
||||
encrypted_message = EXCLUDED.encrypted_message,
|
||||
created_at = now();
|
||||
|
||||
-- name: GetTempAuthKeyBinding :one
|
||||
SELECT
|
||||
temp_auth_key_id,
|
||||
perm_auth_key_id,
|
||||
nonce,
|
||||
temp_session_id,
|
||||
expires_at,
|
||||
encrypted_message
|
||||
FROM temp_auth_key_bindings
|
||||
WHERE temp_auth_key_id = $1;
|
||||
24
internal/store/postgres/queries/update_state.sql
Normal file
24
internal/store/postgres/queries/update_state.sql
Normal file
|
|
@ -0,0 +1,24 @@
|
|||
-- name: GetUpdateState :one
|
||||
SELECT auth_key_id, user_id, pts, qts, date, seq
|
||||
FROM update_states
|
||||
WHERE auth_key_id = $1
|
||||
AND user_id = $2;
|
||||
|
||||
-- name: UpsertUpdateState :exec
|
||||
INSERT INTO update_states (auth_key_id, user_id, pts, qts, date, seq)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
ON CONFLICT (auth_key_id, user_id) DO UPDATE SET
|
||||
pts = EXCLUDED.pts,
|
||||
qts = EXCLUDED.qts,
|
||||
date = EXCLUDED.date,
|
||||
seq = EXCLUDED.seq,
|
||||
updated_at = now();
|
||||
|
||||
-- name: DeleteUpdateState :exec
|
||||
DELETE FROM update_states
|
||||
WHERE auth_key_id = $1
|
||||
AND user_id = $2;
|
||||
|
||||
-- name: DeleteUpdateStatesByAuthKey :exec
|
||||
DELETE FROM update_states
|
||||
WHERE auth_key_id = $1;
|
||||
104
internal/store/postgres/queries/user.sql
Normal file
104
internal/store/postgres/queries/user.sql
Normal file
|
|
@ -0,0 +1,104 @@
|
|||
-- name: GetUserByID :one
|
||||
SELECT * FROM users WHERE id = $1;
|
||||
|
||||
-- name: GetUsersByIDs :many
|
||||
SELECT *
|
||||
FROM users
|
||||
WHERE id = ANY(sqlc.arg(ids)::bigint[])
|
||||
ORDER BY id;
|
||||
|
||||
-- name: GetUserByPhone :one
|
||||
SELECT * FROM users WHERE phone = $1;
|
||||
|
||||
-- name: GetUsersByPhones :many
|
||||
SELECT *
|
||||
FROM users
|
||||
WHERE phone = ANY(sqlc.arg(phones)::text[])
|
||||
ORDER BY id;
|
||||
|
||||
-- name: GetUserByUsername :one
|
||||
SELECT * FROM users WHERE lower(username) = lower($1) AND username <> '';
|
||||
|
||||
-- name: SearchUsers :many
|
||||
WITH matched AS (
|
||||
SELECT
|
||||
u.id,
|
||||
u.access_hash,
|
||||
COALESCE(NULLIF(c.contact_phone, ''), u.phone)::text AS phone,
|
||||
COALESCE(NULLIF(c.contact_first_name, ''), u.first_name)::text AS first_name,
|
||||
COALESCE(c.contact_last_name, u.last_name)::text AS last_name,
|
||||
u.about,
|
||||
u.username,
|
||||
u.country_code,
|
||||
u.verified,
|
||||
u.support,
|
||||
u.last_seen_at,
|
||||
(c.contact_user_id IS NOT NULL)::boolean AS contact,
|
||||
COALESCE(c.mutual, false)::boolean AS mutual,
|
||||
CASE
|
||||
WHEN sqlc.arg(phone_query)::text <> '' AND u.phone = sqlc.arg(phone_query)::text THEN 0
|
||||
WHEN lower(u.username) = sqlc.arg(query_lower)::text THEN 1
|
||||
WHEN lower(COALESCE(NULLIF(c.contact_first_name, ''), u.first_name)) = sqlc.arg(query_lower)::text THEN 2
|
||||
WHEN lower(u.first_name) = sqlc.arg(query_lower)::text THEN 3
|
||||
WHEN c.contact_user_id IS NOT NULL THEN 4
|
||||
ELSE 5
|
||||
END AS rank
|
||||
FROM users u
|
||||
LEFT JOIN contacts c ON c.user_id = sqlc.arg(current_user_id)::bigint AND c.contact_user_id = u.id
|
||||
WHERE u.id <> sqlc.arg(current_user_id)::bigint
|
||||
AND sqlc.arg(query_lower)::text <> ''
|
||||
AND (
|
||||
(sqlc.arg(phone_query)::text <> '' AND u.phone LIKE sqlc.arg(phone_query)::text || '%')
|
||||
OR lower(u.username) LIKE sqlc.arg(query_like)::text || '%' ESCAPE '\'
|
||||
OR lower(u.first_name) LIKE '%' || sqlc.arg(query_like)::text || '%' ESCAPE '\'
|
||||
OR lower(u.last_name) LIKE '%' || sqlc.arg(query_like)::text || '%' ESCAPE '\'
|
||||
OR lower(trim(u.first_name || ' ' || u.last_name)) LIKE '%' || sqlc.arg(query_like)::text || '%' ESCAPE '\'
|
||||
OR lower(c.contact_first_name) LIKE '%' || sqlc.arg(query_like)::text || '%' ESCAPE '\'
|
||||
OR lower(c.contact_last_name) LIKE '%' || sqlc.arg(query_like)::text || '%' ESCAPE '\'
|
||||
OR lower(trim(c.contact_first_name || ' ' || c.contact_last_name)) LIKE '%' || sqlc.arg(query_like)::text || '%' ESCAPE '\'
|
||||
)
|
||||
)
|
||||
SELECT
|
||||
id,
|
||||
access_hash,
|
||||
phone,
|
||||
first_name,
|
||||
last_name,
|
||||
about,
|
||||
username,
|
||||
country_code,
|
||||
verified,
|
||||
support,
|
||||
last_seen_at,
|
||||
contact,
|
||||
mutual
|
||||
FROM matched
|
||||
ORDER BY contact DESC, rank, id
|
||||
LIMIT sqlc.arg(limit_count);
|
||||
|
||||
-- name: CreateUser :one
|
||||
INSERT INTO users (access_hash, phone, first_name, last_name, username, country_code)
|
||||
VALUES ($1, $2, $3, $4, $5, $6)
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUserUsername :one
|
||||
UPDATE users
|
||||
SET username = $2,
|
||||
updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUserLastSeen :exec
|
||||
UPDATE users
|
||||
SET last_seen_at = GREATEST(last_seen_at, sqlc.arg(last_seen_at)::bigint),
|
||||
updated_at = now()
|
||||
WHERE id = sqlc.arg(id)::bigint;
|
||||
|
||||
-- name: UpdateUserProfile :one
|
||||
UPDATE users
|
||||
SET first_name = $2,
|
||||
last_name = $3,
|
||||
about = $4,
|
||||
updated_at = now()
|
||||
WHERE id = $1
|
||||
RETURNING *;
|
||||
464
internal/store/postgres/queries/user_update_event.sql
Normal file
464
internal/store/postgres/queries/user_update_event.sql
Normal file
|
|
@ -0,0 +1,464 @@
|
|||
-- name: AppendUserUpdateEvent :exec
|
||||
INSERT INTO user_update_events (
|
||||
user_id,
|
||||
pts,
|
||||
pts_count,
|
||||
date,
|
||||
event_type,
|
||||
event_bool,
|
||||
event_peers,
|
||||
peer_settings,
|
||||
message_ids,
|
||||
dialog_filter,
|
||||
filter_order,
|
||||
folder_peers,
|
||||
message_box_id,
|
||||
peer_type,
|
||||
peer_id,
|
||||
filter_id,
|
||||
max_id,
|
||||
still_unread_count,
|
||||
tags_enabled
|
||||
) VALUES (
|
||||
$1,
|
||||
$2,
|
||||
$3,
|
||||
$4,
|
||||
$5,
|
||||
sqlc.arg(event_bool)::boolean,
|
||||
sqlc.arg(event_peers)::jsonb,
|
||||
sqlc.arg(peer_settings)::jsonb,
|
||||
sqlc.arg(message_ids)::jsonb,
|
||||
sqlc.arg(dialog_filter)::jsonb,
|
||||
sqlc.arg(filter_order)::jsonb,
|
||||
sqlc.arg(folder_peers)::jsonb,
|
||||
sqlc.narg(message_box_id),
|
||||
sqlc.narg(peer_type)::text,
|
||||
sqlc.narg(peer_id)::bigint,
|
||||
sqlc.arg(filter_id)::int,
|
||||
sqlc.arg(max_id)::int,
|
||||
sqlc.arg(still_unread_count)::int,
|
||||
sqlc.arg(tags_enabled)::boolean
|
||||
)
|
||||
ON CONFLICT (user_id, pts) DO NOTHING;
|
||||
|
||||
-- name: ListUserUpdateEventsAfter :many
|
||||
SELECT
|
||||
e.user_id,
|
||||
e.pts,
|
||||
e.pts_count,
|
||||
e.date,
|
||||
e.event_type,
|
||||
e.event_bool,
|
||||
COALESCE(e.event_peers::text, '[]')::text AS event_peers_json,
|
||||
COALESCE(e.peer_settings::text, '{}')::text AS peer_settings_json,
|
||||
COALESCE(e.message_ids::text, '[]')::text AS message_ids_json,
|
||||
COALESCE(e.dialog_filter::text, '{}')::text AS dialog_filter_json,
|
||||
COALESCE(e.filter_order::text, '[]')::text AS filter_order_json,
|
||||
COALESCE(e.folder_peers::text, '[]')::text AS folder_peers_json,
|
||||
COALESCE(e.peer_type, '')::text AS event_peer_type,
|
||||
COALESCE(e.peer_id, 0)::bigint AS event_peer_id,
|
||||
e.filter_id,
|
||||
e.max_id,
|
||||
e.still_unread_count,
|
||||
e.tags_enabled,
|
||||
COALESCE(m.box_id, 0)::int AS message_id,
|
||||
COALESCE(m.private_message_id, 0)::bigint AS private_message_id,
|
||||
COALESCE(m.owner_user_id, 0)::bigint AS owner_user_id,
|
||||
COALESCE(m.peer_type, '')::text AS peer_type,
|
||||
COALESCE(m.peer_id, 0)::bigint AS peer_id,
|
||||
COALESCE(m.from_user_id, 0)::bigint AS from_user_id,
|
||||
COALESCE(m.message_date, 0)::int AS message_date,
|
||||
COALESCE(m.edit_date, 0)::int AS edit_date,
|
||||
COALESCE(m.outgoing, false)::boolean AS outgoing,
|
||||
COALESCE(m.body, '')::text AS body,
|
||||
COALESCE(m.entities::text, '[]')::text AS message_entities_json,
|
||||
COALESCE(m.silent, false)::boolean AS silent,
|
||||
COALESCE(m.noforwards, false)::boolean AS noforwards,
|
||||
COALESCE(m.reply_to_msg_id, 0)::int AS reply_to_msg_id,
|
||||
COALESCE(m.reply_to_peer_type, '')::text AS reply_to_peer_type,
|
||||
COALESCE(m.reply_to_peer_id, 0)::bigint AS reply_to_peer_id,
|
||||
COALESCE(m.reply_to_top_id, 0)::int AS reply_to_top_id,
|
||||
COALESCE(m.quote_text, '')::text AS quote_text,
|
||||
COALESCE(m.quote_entities::text, '[]')::text AS quote_entities_json,
|
||||
COALESCE(m.quote_offset, 0)::int AS quote_offset,
|
||||
COALESCE(m.fwd_from_peer_type, '')::text AS fwd_from_peer_type,
|
||||
COALESCE(m.fwd_from_peer_id, 0)::bigint AS fwd_from_peer_id,
|
||||
COALESCE(m.fwd_from_name, '')::text AS fwd_from_name,
|
||||
COALESCE(m.fwd_date, 0)::int AS fwd_date,
|
||||
COALESCE(m.media::text, '{}')::text AS media_json,
|
||||
COALESCE(peer_u.id, 0)::bigint AS peer_user_id,
|
||||
COALESCE(peer_u.access_hash, 0)::bigint AS peer_access_hash,
|
||||
COALESCE(peer_u.phone, '')::text AS peer_phone,
|
||||
COALESCE(peer_u.first_name, '')::text AS peer_first_name,
|
||||
COALESCE(peer_u.last_name, '')::text AS peer_last_name,
|
||||
COALESCE(peer_u.username, '')::text AS peer_username,
|
||||
COALESCE(peer_u.country_code, '')::text AS peer_country_code,
|
||||
COALESCE(peer_u.verified, false)::boolean AS peer_verified,
|
||||
COALESCE(peer_u.support, false)::boolean AS peer_support,
|
||||
COALESCE(from_u.id, 0)::bigint AS from_user_user_id,
|
||||
COALESCE(from_u.access_hash, 0)::bigint AS from_user_access_hash,
|
||||
COALESCE(from_u.phone, '')::text AS from_user_phone,
|
||||
COALESCE(from_u.first_name, '')::text AS from_user_first_name,
|
||||
COALESCE(from_u.last_name, '')::text AS from_user_last_name,
|
||||
COALESCE(from_u.username, '')::text AS from_user_username,
|
||||
COALESCE(from_u.country_code, '')::text AS from_user_country_code,
|
||||
COALESCE(from_u.verified, false)::boolean AS from_user_verified,
|
||||
COALESCE(from_u.support, false)::boolean AS from_user_support,
|
||||
COALESCE(fwd_u.id, 0)::bigint AS fwd_user_id,
|
||||
COALESCE(fwd_u.access_hash, 0)::bigint AS fwd_user_access_hash,
|
||||
COALESCE(fwd_u.phone, '')::text AS fwd_user_phone,
|
||||
COALESCE(fwd_u.first_name, '')::text AS fwd_user_first_name,
|
||||
COALESCE(fwd_u.last_name, '')::text AS fwd_user_last_name,
|
||||
COALESCE(fwd_u.username, '')::text AS fwd_user_username,
|
||||
COALESCE(fwd_u.country_code, '')::text AS fwd_user_country_code,
|
||||
COALESCE(fwd_u.verified, false)::boolean AS fwd_user_verified,
|
||||
COALESCE(fwd_u.support, false)::boolean AS fwd_user_support,
|
||||
COALESCE(reply_u.id, 0)::bigint AS reply_user_id,
|
||||
COALESCE(reply_u.access_hash, 0)::bigint AS reply_user_access_hash,
|
||||
COALESCE(reply_u.phone, '')::text AS reply_user_phone,
|
||||
COALESCE(reply_u.first_name, '')::text AS reply_user_first_name,
|
||||
COALESCE(reply_u.last_name, '')::text AS reply_user_last_name,
|
||||
COALESCE(reply_u.username, '')::text AS reply_user_username,
|
||||
COALESCE(reply_u.country_code, '')::text AS reply_user_country_code,
|
||||
COALESCE(reply_u.verified, false)::boolean AS reply_user_verified,
|
||||
COALESCE(reply_u.support, false)::boolean AS reply_user_support,
|
||||
COALESCE(fwd_ch.id, 0)::bigint AS fwd_channel_id,
|
||||
COALESCE(fwd_ch.access_hash, 0)::bigint AS fwd_channel_access_hash,
|
||||
COALESCE(fwd_ch.creator_user_id, 0)::bigint AS fwd_channel_creator_user_id,
|
||||
COALESCE(fwd_ch.title, '')::text AS fwd_channel_title,
|
||||
COALESCE(fwd_ch.about, '')::text AS fwd_channel_about,
|
||||
COALESCE(fwd_ch.username, '')::text AS fwd_channel_username,
|
||||
COALESCE(fwd_ch.broadcast, false)::boolean AS fwd_channel_broadcast,
|
||||
COALESCE(fwd_ch.megagroup, false)::boolean AS fwd_channel_megagroup,
|
||||
COALESCE(fwd_ch.forum, false)::boolean AS fwd_channel_forum,
|
||||
COALESCE(fwd_ch.noforwards, false)::boolean AS fwd_channel_noforwards,
|
||||
COALESCE(fwd_ch.signatures, false)::boolean AS fwd_channel_signatures,
|
||||
COALESCE(fwd_ch.pre_history_hidden, false)::boolean AS fwd_channel_pre_history_hidden,
|
||||
COALESCE(fwd_ch.slowmode_seconds, 0)::int AS fwd_channel_slowmode_seconds,
|
||||
COALESCE(fwd_ch.default_banned_rights::text, '{}')::text AS fwd_channel_default_banned_rights,
|
||||
COALESCE(fwd_ch.participants_count, 0)::int AS fwd_channel_participants_count,
|
||||
COALESCE(fwd_ch.admins_count, 0)::int AS fwd_channel_admins_count,
|
||||
COALESCE(fwd_ch.kicked_count, 0)::int AS fwd_channel_kicked_count,
|
||||
COALESCE(fwd_ch.banned_count, 0)::int AS fwd_channel_banned_count,
|
||||
COALESCE(fwd_ch.top_message_id, 0)::int AS fwd_channel_top_message_id,
|
||||
COALESCE(fwd_ch.pinned_message_id, 0)::int AS fwd_channel_pinned_message_id,
|
||||
COALESCE(fwd_ch.pts, 0)::int AS fwd_channel_pts,
|
||||
COALESCE(fwd_ch.ttl_period, 0)::int AS fwd_channel_ttl_period,
|
||||
COALESCE(fwd_ch.date, 0)::int AS fwd_channel_date,
|
||||
COALESCE(fwd_ch.deleted, false)::boolean AS fwd_channel_deleted,
|
||||
COALESCE(reply_ch.id, 0)::bigint AS reply_channel_id,
|
||||
COALESCE(reply_ch.access_hash, 0)::bigint AS reply_channel_access_hash,
|
||||
COALESCE(reply_ch.creator_user_id, 0)::bigint AS reply_channel_creator_user_id,
|
||||
COALESCE(reply_ch.title, '')::text AS reply_channel_title,
|
||||
COALESCE(reply_ch.about, '')::text AS reply_channel_about,
|
||||
COALESCE(reply_ch.username, '')::text AS reply_channel_username,
|
||||
COALESCE(reply_ch.broadcast, false)::boolean AS reply_channel_broadcast,
|
||||
COALESCE(reply_ch.megagroup, false)::boolean AS reply_channel_megagroup,
|
||||
COALESCE(reply_ch.forum, false)::boolean AS reply_channel_forum,
|
||||
COALESCE(reply_ch.noforwards, false)::boolean AS reply_channel_noforwards,
|
||||
COALESCE(reply_ch.signatures, false)::boolean AS reply_channel_signatures,
|
||||
COALESCE(reply_ch.pre_history_hidden, false)::boolean AS reply_channel_pre_history_hidden,
|
||||
COALESCE(reply_ch.slowmode_seconds, 0)::int AS reply_channel_slowmode_seconds,
|
||||
COALESCE(reply_ch.default_banned_rights::text, '{}')::text AS reply_channel_default_banned_rights,
|
||||
COALESCE(reply_ch.participants_count, 0)::int AS reply_channel_participants_count,
|
||||
COALESCE(reply_ch.admins_count, 0)::int AS reply_channel_admins_count,
|
||||
COALESCE(reply_ch.kicked_count, 0)::int AS reply_channel_kicked_count,
|
||||
COALESCE(reply_ch.banned_count, 0)::int AS reply_channel_banned_count,
|
||||
COALESCE(reply_ch.top_message_id, 0)::int AS reply_channel_top_message_id,
|
||||
COALESCE(reply_ch.pinned_message_id, 0)::int AS reply_channel_pinned_message_id,
|
||||
COALESCE(reply_ch.pts, 0)::int AS reply_channel_pts,
|
||||
COALESCE(reply_ch.ttl_period, 0)::int AS reply_channel_ttl_period,
|
||||
COALESCE(reply_ch.date, 0)::int AS reply_channel_date,
|
||||
COALESCE(reply_ch.deleted, false)::boolean AS reply_channel_deleted
|
||||
FROM user_update_events e
|
||||
LEFT JOIN message_boxes m ON m.owner_user_id = e.user_id AND m.box_id = e.message_box_id
|
||||
LEFT JOIN users peer_u ON m.peer_type = 'user' AND peer_u.id = m.peer_id
|
||||
LEFT JOIN users from_u ON from_u.id = m.from_user_id
|
||||
LEFT JOIN users fwd_u ON m.fwd_from_peer_type = 'user' AND fwd_u.id = m.fwd_from_peer_id
|
||||
LEFT JOIN users reply_u ON m.reply_to_peer_type = 'user' AND reply_u.id = m.reply_to_peer_id
|
||||
LEFT JOIN channels fwd_ch ON m.fwd_from_peer_type = 'channel' AND fwd_ch.id = m.fwd_from_peer_id
|
||||
LEFT JOIN channels reply_ch ON m.reply_to_peer_type = 'channel' AND reply_ch.id = m.reply_to_peer_id
|
||||
WHERE e.user_id = $1
|
||||
AND e.pts > $2
|
||||
ORDER BY e.pts ASC
|
||||
LIMIT sqlc.arg(limit_count);
|
||||
|
||||
-- name: MaxUserPts :one
|
||||
SELECT COALESCE(MAX(pts), 0)::int AS max_pts
|
||||
FROM user_update_events
|
||||
WHERE user_id = $1;
|
||||
|
||||
-- name: RecentUserPts :many
|
||||
-- 取某 user 最近的一段 pts(降序),供计算「最大连续已提交 pts」用。
|
||||
-- 只看顶部窗口:瞬时空洞只可能出现在最近在途事务区,窗口足够大即可覆盖其下方连续。
|
||||
SELECT pts, pts_count
|
||||
FROM user_update_events
|
||||
WHERE user_id = $1
|
||||
ORDER BY pts DESC
|
||||
LIMIT sqlc.arg(window_size);
|
||||
|
||||
-- name: EnsureUserUpdateWatermark :exec
|
||||
INSERT INTO user_update_watermarks (user_id, contiguous_pts)
|
||||
VALUES ($1, 0)
|
||||
ON CONFLICT (user_id) DO NOTHING;
|
||||
|
||||
-- name: GetUserUpdateWatermark :one
|
||||
SELECT contiguous_pts
|
||||
FROM user_update_watermarks
|
||||
WHERE user_id = $1;
|
||||
|
||||
-- name: LockUserUpdateWatermark :one
|
||||
SELECT contiguous_pts
|
||||
FROM user_update_watermarks
|
||||
WHERE user_id = $1
|
||||
FOR UPDATE;
|
||||
|
||||
-- name: NextUserPtsAfter :many
|
||||
SELECT pts, pts_count
|
||||
FROM user_update_events
|
||||
WHERE user_id = $1
|
||||
AND pts > $2
|
||||
ORDER BY pts ASC
|
||||
LIMIT sqlc.arg(limit_count);
|
||||
|
||||
-- name: SaveUserUpdateWatermark :exec
|
||||
INSERT INTO user_update_watermarks (user_id, contiguous_pts, updated_at)
|
||||
VALUES ($1, $2, now())
|
||||
ON CONFLICT (user_id) DO UPDATE SET
|
||||
contiguous_pts = GREATEST(user_update_watermarks.contiguous_pts, EXCLUDED.contiguous_pts),
|
||||
updated_at = now();
|
||||
|
||||
-- name: EnqueueDispatch :exec
|
||||
INSERT INTO dispatch_outbox (
|
||||
target_user_id,
|
||||
pts,
|
||||
event_type,
|
||||
exclude_auth_key_id,
|
||||
exclude_session_id
|
||||
) VALUES (
|
||||
$1, $2, $3, $4, $5
|
||||
)
|
||||
ON CONFLICT DO NOTHING;
|
||||
|
||||
-- name: ClaimDispatchOutbox :many
|
||||
WITH picked AS (
|
||||
SELECT target_user_id, id
|
||||
FROM dispatch_outbox
|
||||
WHERE (
|
||||
status = 'pending'
|
||||
AND next_attempt_at <= now()
|
||||
)
|
||||
OR (
|
||||
status = 'dispatching'
|
||||
AND updated_at < now() - make_interval(secs => sqlc.arg(lease_seconds)::int)
|
||||
)
|
||||
ORDER BY next_attempt_at ASC, target_user_id ASC, id ASC
|
||||
LIMIT sqlc.arg(limit_count)
|
||||
FOR UPDATE SKIP LOCKED
|
||||
)
|
||||
UPDATE dispatch_outbox d
|
||||
SET
|
||||
status = 'dispatching',
|
||||
attempts = d.attempts + 1,
|
||||
updated_at = now()
|
||||
FROM picked p
|
||||
WHERE d.target_user_id = p.target_user_id
|
||||
AND d.id = p.id
|
||||
RETURNING
|
||||
d.id,
|
||||
d.target_user_id,
|
||||
d.pts,
|
||||
d.event_type,
|
||||
d.exclude_auth_key_id,
|
||||
d.exclude_session_id,
|
||||
d.attempts;
|
||||
|
||||
-- name: MarkDispatchDelivered :exec
|
||||
-- 方案 A:投递成功即删除。outbox 是任务队列,delivered 行无保留价值
|
||||
-- (消息在 message_boxes、离线补偿在 user_update_events),删除让表维持「未完成任务」小稳态。
|
||||
DELETE FROM dispatch_outbox
|
||||
WHERE target_user_id = $1
|
||||
AND id = $2;
|
||||
|
||||
-- name: MarkDispatchFailed :exec
|
||||
UPDATE dispatch_outbox
|
||||
SET
|
||||
status = CASE WHEN attempts >= 5 THEN 'failed' ELSE 'pending' END,
|
||||
next_attempt_at = CASE
|
||||
WHEN attempts >= 5 THEN next_attempt_at
|
||||
ELSE now() + make_interval(secs => LEAST(60, attempts * attempts))
|
||||
END,
|
||||
last_error = $3,
|
||||
updated_at = now()
|
||||
WHERE target_user_id = $1
|
||||
AND id = $2;
|
||||
|
||||
-- name: BatchListDispatchEvents :many
|
||||
-- 按 (user_id, pts) 精确批量取账号事件,供 outbox worker 一次性加载一批 claim 的事件详情,
|
||||
-- 取代逐条 ListUserUpdateEventsAfter。列与 ListUserUpdateEventsAfter 完全一致以复用转换逻辑。
|
||||
SELECT
|
||||
e.user_id,
|
||||
e.pts,
|
||||
e.pts_count,
|
||||
e.date,
|
||||
e.event_type,
|
||||
e.event_bool,
|
||||
COALESCE(e.event_peers::text, '[]')::text AS event_peers_json,
|
||||
COALESCE(e.peer_settings::text, '{}')::text AS peer_settings_json,
|
||||
COALESCE(e.message_ids::text, '[]')::text AS message_ids_json,
|
||||
COALESCE(e.dialog_filter::text, '{}')::text AS dialog_filter_json,
|
||||
COALESCE(e.filter_order::text, '[]')::text AS filter_order_json,
|
||||
COALESCE(e.folder_peers::text, '[]')::text AS folder_peers_json,
|
||||
COALESCE(e.peer_type, '')::text AS event_peer_type,
|
||||
COALESCE(e.peer_id, 0)::bigint AS event_peer_id,
|
||||
e.filter_id,
|
||||
e.max_id,
|
||||
e.still_unread_count,
|
||||
e.tags_enabled,
|
||||
COALESCE(m.box_id, 0)::int AS message_id,
|
||||
COALESCE(m.private_message_id, 0)::bigint AS private_message_id,
|
||||
COALESCE(m.owner_user_id, 0)::bigint AS owner_user_id,
|
||||
COALESCE(m.peer_type, '')::text AS peer_type,
|
||||
COALESCE(m.peer_id, 0)::bigint AS peer_id,
|
||||
COALESCE(m.from_user_id, 0)::bigint AS from_user_id,
|
||||
COALESCE(m.message_date, 0)::int AS message_date,
|
||||
COALESCE(m.edit_date, 0)::int AS edit_date,
|
||||
COALESCE(m.outgoing, false)::boolean AS outgoing,
|
||||
COALESCE(m.body, '')::text AS body,
|
||||
COALESCE(m.entities::text, '[]')::text AS message_entities_json,
|
||||
COALESCE(m.silent, false)::boolean AS silent,
|
||||
COALESCE(m.noforwards, false)::boolean AS noforwards,
|
||||
COALESCE(m.reply_to_msg_id, 0)::int AS reply_to_msg_id,
|
||||
COALESCE(m.reply_to_peer_type, '')::text AS reply_to_peer_type,
|
||||
COALESCE(m.reply_to_peer_id, 0)::bigint AS reply_to_peer_id,
|
||||
COALESCE(m.reply_to_top_id, 0)::int AS reply_to_top_id,
|
||||
COALESCE(m.quote_text, '')::text AS quote_text,
|
||||
COALESCE(m.quote_entities::text, '[]')::text AS quote_entities_json,
|
||||
COALESCE(m.quote_offset, 0)::int AS quote_offset,
|
||||
COALESCE(m.fwd_from_peer_type, '')::text AS fwd_from_peer_type,
|
||||
COALESCE(m.fwd_from_peer_id, 0)::bigint AS fwd_from_peer_id,
|
||||
COALESCE(m.fwd_from_name, '')::text AS fwd_from_name,
|
||||
COALESCE(m.fwd_date, 0)::int AS fwd_date,
|
||||
COALESCE(m.media::text, '{}')::text AS media_json,
|
||||
COALESCE(peer_u.id, 0)::bigint AS peer_user_id,
|
||||
COALESCE(peer_u.access_hash, 0)::bigint AS peer_access_hash,
|
||||
COALESCE(peer_u.phone, '')::text AS peer_phone,
|
||||
COALESCE(peer_u.first_name, '')::text AS peer_first_name,
|
||||
COALESCE(peer_u.last_name, '')::text AS peer_last_name,
|
||||
COALESCE(peer_u.username, '')::text AS peer_username,
|
||||
COALESCE(peer_u.country_code, '')::text AS peer_country_code,
|
||||
COALESCE(peer_u.verified, false)::boolean AS peer_verified,
|
||||
COALESCE(peer_u.support, false)::boolean AS peer_support,
|
||||
COALESCE(from_u.id, 0)::bigint AS from_user_user_id,
|
||||
COALESCE(from_u.access_hash, 0)::bigint AS from_user_access_hash,
|
||||
COALESCE(from_u.phone, '')::text AS from_user_phone,
|
||||
COALESCE(from_u.first_name, '')::text AS from_user_first_name,
|
||||
COALESCE(from_u.last_name, '')::text AS from_user_last_name,
|
||||
COALESCE(from_u.username, '')::text AS from_user_username,
|
||||
COALESCE(from_u.country_code, '')::text AS from_user_country_code,
|
||||
COALESCE(from_u.verified, false)::boolean AS from_user_verified,
|
||||
COALESCE(from_u.support, false)::boolean AS from_user_support,
|
||||
COALESCE(fwd_u.id, 0)::bigint AS fwd_user_id,
|
||||
COALESCE(fwd_u.access_hash, 0)::bigint AS fwd_user_access_hash,
|
||||
COALESCE(fwd_u.phone, '')::text AS fwd_user_phone,
|
||||
COALESCE(fwd_u.first_name, '')::text AS fwd_user_first_name,
|
||||
COALESCE(fwd_u.last_name, '')::text AS fwd_user_last_name,
|
||||
COALESCE(fwd_u.username, '')::text AS fwd_user_username,
|
||||
COALESCE(fwd_u.country_code, '')::text AS fwd_user_country_code,
|
||||
COALESCE(fwd_u.verified, false)::boolean AS fwd_user_verified,
|
||||
COALESCE(fwd_u.support, false)::boolean AS fwd_user_support,
|
||||
COALESCE(reply_u.id, 0)::bigint AS reply_user_id,
|
||||
COALESCE(reply_u.access_hash, 0)::bigint AS reply_user_access_hash,
|
||||
COALESCE(reply_u.phone, '')::text AS reply_user_phone,
|
||||
COALESCE(reply_u.first_name, '')::text AS reply_user_first_name,
|
||||
COALESCE(reply_u.last_name, '')::text AS reply_user_last_name,
|
||||
COALESCE(reply_u.username, '')::text AS reply_user_username,
|
||||
COALESCE(reply_u.country_code, '')::text AS reply_user_country_code,
|
||||
COALESCE(reply_u.verified, false)::boolean AS reply_user_verified,
|
||||
COALESCE(reply_u.support, false)::boolean AS reply_user_support,
|
||||
COALESCE(fwd_ch.id, 0)::bigint AS fwd_channel_id,
|
||||
COALESCE(fwd_ch.access_hash, 0)::bigint AS fwd_channel_access_hash,
|
||||
COALESCE(fwd_ch.creator_user_id, 0)::bigint AS fwd_channel_creator_user_id,
|
||||
COALESCE(fwd_ch.title, '')::text AS fwd_channel_title,
|
||||
COALESCE(fwd_ch.about, '')::text AS fwd_channel_about,
|
||||
COALESCE(fwd_ch.username, '')::text AS fwd_channel_username,
|
||||
COALESCE(fwd_ch.broadcast, false)::boolean AS fwd_channel_broadcast,
|
||||
COALESCE(fwd_ch.megagroup, false)::boolean AS fwd_channel_megagroup,
|
||||
COALESCE(fwd_ch.forum, false)::boolean AS fwd_channel_forum,
|
||||
COALESCE(fwd_ch.noforwards, false)::boolean AS fwd_channel_noforwards,
|
||||
COALESCE(fwd_ch.signatures, false)::boolean AS fwd_channel_signatures,
|
||||
COALESCE(fwd_ch.pre_history_hidden, false)::boolean AS fwd_channel_pre_history_hidden,
|
||||
COALESCE(fwd_ch.slowmode_seconds, 0)::int AS fwd_channel_slowmode_seconds,
|
||||
COALESCE(fwd_ch.default_banned_rights::text, '{}')::text AS fwd_channel_default_banned_rights,
|
||||
COALESCE(fwd_ch.participants_count, 0)::int AS fwd_channel_participants_count,
|
||||
COALESCE(fwd_ch.admins_count, 0)::int AS fwd_channel_admins_count,
|
||||
COALESCE(fwd_ch.kicked_count, 0)::int AS fwd_channel_kicked_count,
|
||||
COALESCE(fwd_ch.banned_count, 0)::int AS fwd_channel_banned_count,
|
||||
COALESCE(fwd_ch.top_message_id, 0)::int AS fwd_channel_top_message_id,
|
||||
COALESCE(fwd_ch.pinned_message_id, 0)::int AS fwd_channel_pinned_message_id,
|
||||
COALESCE(fwd_ch.pts, 0)::int AS fwd_channel_pts,
|
||||
COALESCE(fwd_ch.ttl_period, 0)::int AS fwd_channel_ttl_period,
|
||||
COALESCE(fwd_ch.date, 0)::int AS fwd_channel_date,
|
||||
COALESCE(fwd_ch.deleted, false)::boolean AS fwd_channel_deleted,
|
||||
COALESCE(reply_ch.id, 0)::bigint AS reply_channel_id,
|
||||
COALESCE(reply_ch.access_hash, 0)::bigint AS reply_channel_access_hash,
|
||||
COALESCE(reply_ch.creator_user_id, 0)::bigint AS reply_channel_creator_user_id,
|
||||
COALESCE(reply_ch.title, '')::text AS reply_channel_title,
|
||||
COALESCE(reply_ch.about, '')::text AS reply_channel_about,
|
||||
COALESCE(reply_ch.username, '')::text AS reply_channel_username,
|
||||
COALESCE(reply_ch.broadcast, false)::boolean AS reply_channel_broadcast,
|
||||
COALESCE(reply_ch.megagroup, false)::boolean AS reply_channel_megagroup,
|
||||
COALESCE(reply_ch.forum, false)::boolean AS reply_channel_forum,
|
||||
COALESCE(reply_ch.noforwards, false)::boolean AS reply_channel_noforwards,
|
||||
COALESCE(reply_ch.signatures, false)::boolean AS reply_channel_signatures,
|
||||
COALESCE(reply_ch.pre_history_hidden, false)::boolean AS reply_channel_pre_history_hidden,
|
||||
COALESCE(reply_ch.slowmode_seconds, 0)::int AS reply_channel_slowmode_seconds,
|
||||
COALESCE(reply_ch.default_banned_rights::text, '{}')::text AS reply_channel_default_banned_rights,
|
||||
COALESCE(reply_ch.participants_count, 0)::int AS reply_channel_participants_count,
|
||||
COALESCE(reply_ch.admins_count, 0)::int AS reply_channel_admins_count,
|
||||
COALESCE(reply_ch.kicked_count, 0)::int AS reply_channel_kicked_count,
|
||||
COALESCE(reply_ch.banned_count, 0)::int AS reply_channel_banned_count,
|
||||
COALESCE(reply_ch.top_message_id, 0)::int AS reply_channel_top_message_id,
|
||||
COALESCE(reply_ch.pinned_message_id, 0)::int AS reply_channel_pinned_message_id,
|
||||
COALESCE(reply_ch.pts, 0)::int AS reply_channel_pts,
|
||||
COALESCE(reply_ch.ttl_period, 0)::int AS reply_channel_ttl_period,
|
||||
COALESCE(reply_ch.date, 0)::int AS reply_channel_date,
|
||||
COALESCE(reply_ch.deleted, false)::boolean AS reply_channel_deleted
|
||||
FROM unnest(@user_ids::bigint[]) WITH ORDINALITY AS u(user_id, ord)
|
||||
JOIN unnest(@pts_list::int[]) WITH ORDINALITY AS p(pts, ord) USING (ord)
|
||||
JOIN user_update_events e ON e.user_id = u.user_id AND e.pts = p.pts
|
||||
LEFT JOIN message_boxes m ON m.owner_user_id = e.user_id AND m.box_id = e.message_box_id
|
||||
LEFT JOIN users peer_u ON m.peer_type = 'user' AND peer_u.id = m.peer_id
|
||||
LEFT JOIN users from_u ON from_u.id = m.from_user_id
|
||||
LEFT JOIN users fwd_u ON m.fwd_from_peer_type = 'user' AND fwd_u.id = m.fwd_from_peer_id
|
||||
LEFT JOIN users reply_u ON m.reply_to_peer_type = 'user' AND reply_u.id = m.reply_to_peer_id
|
||||
LEFT JOIN channels fwd_ch ON m.fwd_from_peer_type = 'channel' AND fwd_ch.id = m.fwd_from_peer_id
|
||||
LEFT JOIN channels reply_ch ON m.reply_to_peer_type = 'channel' AND reply_ch.id = m.reply_to_peer_id;
|
||||
|
||||
-- name: MarkDispatchDeliveredBatch :exec
|
||||
-- 批量删除一批已投递的 (target_user_id, id);target_user_id 入 WHERE 保证分区裁剪。
|
||||
DELETE FROM dispatch_outbox d
|
||||
USING unnest(@target_user_ids::bigint[]) WITH ORDINALITY AS tu(target_user_id, ord)
|
||||
JOIN unnest(@ids::bigint[]) WITH ORDINALITY AS di(id, ord) USING (ord)
|
||||
WHERE d.target_user_id = tu.target_user_id
|
||||
AND d.id = di.id;
|
||||
|
||||
-- name: DeleteFailedDispatchOutbox :one
|
||||
WITH doomed AS (
|
||||
SELECT target_user_id, id
|
||||
FROM dispatch_outbox
|
||||
WHERE status = 'failed'
|
||||
AND updated_at < now() - make_interval(secs => sqlc.arg(older_than_seconds)::int)
|
||||
ORDER BY updated_at ASC, target_user_id ASC, id ASC
|
||||
LIMIT sqlc.arg(limit_count)
|
||||
),
|
||||
deleted AS (
|
||||
DELETE FROM dispatch_outbox d
|
||||
USING doomed x
|
||||
WHERE d.target_user_id = x.target_user_id
|
||||
AND d.id = x.id
|
||||
RETURNING d.id
|
||||
)
|
||||
SELECT count(*)::int AS deleted_count
|
||||
FROM deleted;
|
||||
Loading…
Add table
Add a link
Reference in a new issue