feat: sync public links and phone change updates
This commit is contained in:
parent
41c7f1d018
commit
da04c0fa6a
53 changed files with 3029 additions and 111 deletions
|
|
@ -285,9 +285,7 @@ func (s *ChannelStore) SetChannelVerified(ctx context.Context, channelID int64,
|
|||
}
|
||||
|
||||
func (s *ChannelStore) ResolvePublicChannelUsername(ctx context.Context, viewerUserID int64, username string) (domain.Channel, bool, error) {
|
||||
if viewerUserID == 0 {
|
||||
return domain.Channel{}, false, domain.ErrChannelInvalid
|
||||
}
|
||||
_ = viewerUserID // zero is the anonymous public-web view; this query is viewer-independent.
|
||||
usernameLower := strings.ToLower(strings.TrimSpace(strings.TrimPrefix(username, "@")))
|
||||
if usernameLower == "" {
|
||||
return domain.Channel{}, false, nil
|
||||
|
|
|
|||
|
|
@ -59,6 +59,10 @@ func TestChannelStoreResolvePublicUsernameRejectsStaleIndex(t *testing.T) {
|
|||
if _, found, err := channels.ResolvePublicChannelUsername(ctx, viewer.ID, usernames[1]); err != nil || found {
|
||||
t.Fatalf("resolve missing username found %v err %v, want not found", found, err)
|
||||
}
|
||||
anonymous, found, err := channels.ResolvePublicChannelUsername(ctx, 0, strings.ToUpper(publicUsername))
|
||||
if err != nil || !found || anonymous.ID != publicChannel.ID {
|
||||
t.Fatalf("anonymous resolve public username = %+v found=%v err=%v", anonymous, found, err)
|
||||
}
|
||||
if _, err := channels.UpdateUsername(ctx, domain.UpdateChannelUsernameRequest{
|
||||
UserID: owner.ID,
|
||||
ChannelID: publicChannel.ID,
|
||||
|
|
|
|||
112
internal/store/postgres/phone_change.go
Normal file
112
internal/store/postgres/phone_change.go
Normal file
|
|
@ -0,0 +1,112 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/jackc/pgx/v5"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
"telesrv/internal/store/postgres/sqlcgen"
|
||||
)
|
||||
|
||||
// PhoneChangeStore 把 users.phone、账号 pts、durable event 与 dispatch outbox
|
||||
// 作为一个事务提交,避免任何一边单独可见。
|
||||
type PhoneChangeStore struct {
|
||||
db sqlcgen.DBTX
|
||||
q *sqlcgen.Queries
|
||||
}
|
||||
|
||||
func NewPhoneChangeStore(db sqlcgen.DBTX) *PhoneChangeStore {
|
||||
return &PhoneChangeStore{db: db, q: sqlcgen.New(db)}
|
||||
}
|
||||
|
||||
func (*PhoneChangeStore) UsesReliableDispatch() bool { return true }
|
||||
|
||||
func (s *PhoneChangeStore) ChangePhone(ctx context.Context, req domain.PhoneChangeRequest) (domain.PhoneChangeResult, error) {
|
||||
if s == nil || req.UserID == 0 || !domain.ValidPhone(req.Phone) {
|
||||
return domain.PhoneChangeResult{}, domain.ErrPhoneNumberInvalid
|
||||
}
|
||||
beginner, ok := s.db.(txBeginner)
|
||||
if !ok {
|
||||
return domain.PhoneChangeResult{}, fmt.Errorf("change phone: db does not support transactions")
|
||||
}
|
||||
tx, err := beginner.Begin(ctx)
|
||||
if err != nil {
|
||||
return domain.PhoneChangeResult{}, fmt.Errorf("begin change phone: %w", err)
|
||||
}
|
||||
committed := false
|
||||
defer func() {
|
||||
if !committed {
|
||||
_ = tx.Rollback(ctx)
|
||||
}
|
||||
}()
|
||||
qtx := s.q.WithTx(tx)
|
||||
|
||||
var currentPhone string
|
||||
if err := tx.QueryRow(ctx, `SELECT phone FROM users WHERE id = $1 FOR UPDATE`, req.UserID).Scan(¤tPhone); err != nil {
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return domain.PhoneChangeResult{}, domain.ErrUserNotFound
|
||||
}
|
||||
return domain.PhoneChangeResult{}, fmt.Errorf("lock user for phone change: %w", err)
|
||||
}
|
||||
if currentPhone == req.Phone {
|
||||
row, err := qtx.GetUserByID(ctx, req.UserID)
|
||||
if err != nil {
|
||||
return domain.PhoneChangeResult{}, fmt.Errorf("reload unchanged phone user: %w", err)
|
||||
}
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
return domain.PhoneChangeResult{}, fmt.Errorf("commit unchanged phone: %w", err)
|
||||
}
|
||||
committed = true
|
||||
return domain.PhoneChangeResult{User: userFromModel(row)}, nil
|
||||
}
|
||||
|
||||
row, err := qtx.UpdateUserPhone(ctx, sqlcgen.UpdateUserPhoneParams{ID: req.UserID, Phone: req.Phone})
|
||||
if err != nil {
|
||||
if isUniqueConstraint(err, "users_phone_unique_idx") {
|
||||
return domain.PhoneChangeResult{}, domain.ErrPhoneNumberOccupied
|
||||
}
|
||||
if errors.Is(err, pgx.ErrNoRows) {
|
||||
return domain.PhoneChangeResult{}, domain.ErrUserNotFound
|
||||
}
|
||||
return domain.PhoneChangeResult{}, fmt.Errorf("update user phone: %w", err)
|
||||
}
|
||||
date := req.Date
|
||||
if date == 0 {
|
||||
date = int(time.Now().Unix())
|
||||
}
|
||||
event := domain.UpdateEvent{
|
||||
UserID: req.UserID,
|
||||
Type: domain.UpdateEventUserPhone,
|
||||
Date: date,
|
||||
Phone: req.Phone,
|
||||
PtsCount: 1,
|
||||
}
|
||||
event.Pts, err = reserveUserPts(ctx, tx, req.UserID, event.PtsCount)
|
||||
if err != nil {
|
||||
return domain.PhoneChangeResult{}, fmt.Errorf("reserve phone change pts: %w", err)
|
||||
}
|
||||
if err := appendUserUpdateEvent(ctx, tx, qtx, req.UserID, event); err != nil {
|
||||
return domain.PhoneChangeResult{}, fmt.Errorf("append phone change event: %w", err)
|
||||
}
|
||||
if err := qtx.EnqueueDispatch(ctx, sqlcgen.EnqueueDispatchParams{
|
||||
TargetUserID: req.UserID,
|
||||
Pts: int32(event.Pts),
|
||||
EventType: string(event.Type),
|
||||
ExcludeAuthKeyID: authKeyIDToInt64(req.ExcludeAuthKeyID),
|
||||
ExcludeSessionID: req.ExcludeSessionID,
|
||||
}); err != nil {
|
||||
return domain.PhoneChangeResult{}, fmt.Errorf("enqueue phone change dispatch: %w", err)
|
||||
}
|
||||
if err := tx.Commit(ctx); err != nil {
|
||||
if isUniqueConstraint(err, "users_phone_unique_idx") {
|
||||
return domain.PhoneChangeResult{}, domain.ErrPhoneNumberOccupied
|
||||
}
|
||||
return domain.PhoneChangeResult{}, fmt.Errorf("commit phone change: %w", err)
|
||||
}
|
||||
committed = true
|
||||
return domain.PhoneChangeResult{User: userFromModel(row), Event: event, Changed: true}, nil
|
||||
}
|
||||
86
internal/store/postgres/phone_change_integration_test.go
Normal file
86
internal/store/postgres/phone_change_integration_test.go
Normal file
|
|
@ -0,0 +1,86 @@
|
|||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"telesrv/internal/domain"
|
||||
)
|
||||
|
||||
func TestPhoneChangeStoreAtomicUserEventOutboxPostgres(t *testing.T) {
|
||||
pool := testPool(t)
|
||||
ctx := context.Background()
|
||||
users := NewUserStore(pool)
|
||||
changes := NewPhoneChangeStore(pool)
|
||||
events := NewUpdateEventStore(pool)
|
||||
suffix := time.Now().UnixNano() % 1_000_000_000
|
||||
oldPhone := fmt.Sprintf("1661%d01", suffix)
|
||||
occupiedPhone := fmt.Sprintf("1661%d02", suffix)
|
||||
newPhone := fmt.Sprintf("1661%d03", suffix)
|
||||
u1, err := users.Create(ctx, domain.User{AccessHash: 301, Phone: oldPhone, FirstName: "PhoneOne"})
|
||||
if err != nil {
|
||||
t.Fatalf("create user1: %v", err)
|
||||
}
|
||||
u2, err := users.Create(ctx, domain.User{AccessHash: 302, Phone: occupiedPhone, FirstName: "PhoneTwo"})
|
||||
if err != nil {
|
||||
t.Fatalf("create user2: %v", err)
|
||||
}
|
||||
t.Cleanup(func() {
|
||||
_, _ = pool.Exec(context.Background(), "DELETE FROM dispatch_outbox WHERE target_user_id = ANY($1::bigint[])", []int64{u1.ID, u2.ID})
|
||||
_, _ = pool.Exec(context.Background(), "DELETE FROM user_update_events WHERE user_id = ANY($1::bigint[])", []int64{u1.ID, u2.ID})
|
||||
_, _ = pool.Exec(context.Background(), "DELETE FROM user_update_watermarks WHERE user_id = ANY($1::bigint[])", []int64{u1.ID, u2.ID})
|
||||
_, _ = pool.Exec(context.Background(), "DELETE FROM users WHERE id = ANY($1::bigint[])", []int64{u1.ID, u2.ID})
|
||||
})
|
||||
|
||||
authKeyID := [8]byte{7, 6, 5, 4}
|
||||
result, err := changes.ChangePhone(ctx, domain.PhoneChangeRequest{
|
||||
UserID: u1.ID, Phone: newPhone, Date: 1700000001,
|
||||
ExcludeAuthKeyID: authKeyID, ExcludeSessionID: 77,
|
||||
})
|
||||
if err != nil {
|
||||
t.Fatalf("change phone: %v", err)
|
||||
}
|
||||
if !result.Changed || result.User.Phone != newPhone || result.Event.Pts != 1 || result.Event.Phone != newPhone {
|
||||
t.Fatalf("result = %+v", result)
|
||||
}
|
||||
loaded, found, err := users.ByID(ctx, u1.ID)
|
||||
if err != nil || !found || loaded.Phone != newPhone {
|
||||
t.Fatalf("loaded user = %+v found=%v err=%v", loaded, found, err)
|
||||
}
|
||||
storedEvents, err := events.ListAfter(ctx, u1.ID, 0, 10)
|
||||
if err != nil || len(storedEvents) != 1 || storedEvents[0].Type != domain.UpdateEventUserPhone || storedEvents[0].Phone != newPhone {
|
||||
t.Fatalf("stored events = %+v err=%v", storedEvents, err)
|
||||
}
|
||||
var outboxCount int
|
||||
var excludedAuth, excludedSession int64
|
||||
if err := pool.QueryRow(ctx, `SELECT count(*), max(exclude_auth_key_id), max(exclude_session_id) FROM dispatch_outbox WHERE target_user_id = $1 AND pts = $2`, u1.ID, result.Event.Pts).Scan(&outboxCount, &excludedAuth, &excludedSession); err != nil {
|
||||
t.Fatalf("query outbox: %v", err)
|
||||
}
|
||||
if outboxCount != 1 || excludedAuth != authKeyIDToInt64(authKeyID) || excludedSession != 77 {
|
||||
t.Fatalf("outbox count/auth/session = %d/%d/%d", outboxCount, excludedAuth, excludedSession)
|
||||
}
|
||||
|
||||
// 同号重试是幂等读,不得重复推进 pts 或重复入 outbox。
|
||||
retry, err := changes.ChangePhone(ctx, domain.PhoneChangeRequest{UserID: u1.ID, Phone: newPhone, Date: 1700000002})
|
||||
if err != nil || retry.Changed || retry.Event.Pts != 0 || retry.User.Phone != newPhone {
|
||||
t.Fatalf("idempotent retry = %+v err=%v", retry, err)
|
||||
}
|
||||
if pts, err := events.MaxContiguousPts(ctx, u1.ID); err != nil || pts != 1 {
|
||||
t.Fatalf("pts after retry = %d err=%v", pts, err)
|
||||
}
|
||||
|
||||
// 冲突更新整体回滚:号码和 pts/event 都不变。
|
||||
if _, err := changes.ChangePhone(ctx, domain.PhoneChangeRequest{UserID: u2.ID, Phone: newPhone}); !errors.Is(err, domain.ErrPhoneNumberOccupied) {
|
||||
t.Fatalf("occupied change err = %v", err)
|
||||
}
|
||||
loaded2, found, err := users.ByID(ctx, u2.ID)
|
||||
if err != nil || !found || loaded2.Phone != occupiedPhone {
|
||||
t.Fatalf("occupied rollback user = %+v found=%v err=%v", loaded2, found, err)
|
||||
}
|
||||
if pts, err := events.MaxContiguousPts(ctx, u2.ID); err != nil || pts != 0 {
|
||||
t.Fatalf("occupied rollback pts = %d err=%v", pts, err)
|
||||
}
|
||||
}
|
||||
|
|
@ -125,6 +125,13 @@ SET first_name = $2,
|
|||
WHERE id = $1
|
||||
RETURNING *;
|
||||
|
||||
-- name: UpdateUserPhone :one
|
||||
UPDATE users
|
||||
SET phone = sqlc.arg(phone)::text,
|
||||
updated_at = now()
|
||||
WHERE id = sqlc.arg(id)::bigint
|
||||
RETURNING *;
|
||||
|
||||
-- name: SetUserPremiumUntil :one
|
||||
UPDATE users
|
||||
SET premium_expires_at = sqlc.narg(premium_expires_at)::timestamptz,
|
||||
|
|
|
|||
|
|
@ -6,6 +6,7 @@ INSERT INTO user_update_events (
|
|||
date,
|
||||
event_type,
|
||||
event_bool,
|
||||
event_phone,
|
||||
event_peers,
|
||||
peer_settings,
|
||||
message_ids,
|
||||
|
|
@ -30,6 +31,7 @@ INSERT INTO user_update_events (
|
|||
$4,
|
||||
$5,
|
||||
sqlc.arg(event_bool)::boolean,
|
||||
sqlc.arg(event_phone)::text,
|
||||
sqlc.arg(event_peers)::jsonb,
|
||||
sqlc.arg(peer_settings)::jsonb,
|
||||
sqlc.arg(message_ids)::jsonb,
|
||||
|
|
@ -57,6 +59,7 @@ SELECT
|
|||
e.date,
|
||||
e.event_type,
|
||||
e.event_bool,
|
||||
e.event_phone,
|
||||
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,
|
||||
|
|
@ -267,6 +270,7 @@ SELECT
|
|||
e.date,
|
||||
e.event_type,
|
||||
e.event_bool,
|
||||
e.event_phone,
|
||||
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,
|
||||
|
|
|
|||
|
|
@ -7,6 +7,8 @@ package sqlcgen
|
|||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/jackc/pgx/v5/pgtype"
|
||||
)
|
||||
|
||||
const getAuthKey = `-- name: GetAuthKey :one
|
||||
|
|
@ -15,9 +17,16 @@ FROM auth_keys
|
|||
WHERE auth_key_id = $1
|
||||
`
|
||||
|
||||
func (q *Queries) GetAuthKey(ctx context.Context, authKeyID int64) (AuthKey, error) {
|
||||
type GetAuthKeyRow struct {
|
||||
AuthKeyID int64
|
||||
Body []byte
|
||||
ServerSalt int64
|
||||
CreatedAt pgtype.Timestamptz
|
||||
}
|
||||
|
||||
func (q *Queries) GetAuthKey(ctx context.Context, authKeyID int64) (GetAuthKeyRow, error) {
|
||||
row := q.db.QueryRow(ctx, getAuthKey, authKeyID)
|
||||
var i AuthKey
|
||||
var i GetAuthKeyRow
|
||||
err := row.Scan(
|
||||
&i.AuthKeyID,
|
||||
&i.Body,
|
||||
|
|
|
|||
|
|
@ -164,10 +164,16 @@ type AttachMenuUserState struct {
|
|||
}
|
||||
|
||||
type AuthKey struct {
|
||||
AuthKeyID int64
|
||||
Body []byte
|
||||
ServerSalt int64
|
||||
CreatedAt pgtype.Timestamptz
|
||||
AuthKeyID int64
|
||||
Body []byte
|
||||
ServerSalt int64
|
||||
CreatedAt pgtype.Timestamptz
|
||||
Layer int32
|
||||
DeviceModel string
|
||||
Platform string
|
||||
SystemVersion string
|
||||
ApiID int32
|
||||
AppVersion string
|
||||
}
|
||||
|
||||
type Authorization struct {
|
||||
|
|
@ -201,6 +207,22 @@ type AvailableReaction struct {
|
|||
SortOrder int32
|
||||
}
|
||||
|
||||
type BootstrapUpdateJob struct {
|
||||
ID int64
|
||||
Kind string
|
||||
UserID int64
|
||||
AuthKeyID int64
|
||||
SessionID int64
|
||||
MessageBoxID int32
|
||||
Status string
|
||||
Attempts int32
|
||||
LastError string
|
||||
CreatedAt pgtype.Timestamptz
|
||||
UpdatedAt pgtype.Timestamptz
|
||||
ReadyAt pgtype.Timestamptz
|
||||
PublishedAt pgtype.Timestamptz
|
||||
}
|
||||
|
||||
type Bot struct {
|
||||
BotUserID int64
|
||||
OwnerUserID int64
|
||||
|
|
@ -218,6 +240,24 @@ type Bot struct {
|
|||
BotInlineGeo bool
|
||||
}
|
||||
|
||||
type BotApiUpdate struct {
|
||||
ID int64
|
||||
BotUserID int64
|
||||
UpdateKind string
|
||||
PeerType string
|
||||
PeerID int64
|
||||
MessageID int32
|
||||
SourcePts int32
|
||||
Date int32
|
||||
CreatedAt pgtype.Timestamptz
|
||||
}
|
||||
|
||||
type BotApiUpdateState struct {
|
||||
BotUserID int64
|
||||
ConfirmedUpdateID int64
|
||||
UpdatedAt pgtype.Timestamptz
|
||||
}
|
||||
|
||||
type BotApp struct {
|
||||
ID int64
|
||||
BotUserID int64
|
||||
|
|
@ -663,6 +703,30 @@ type ChannelUpdateEvent struct {
|
|||
CreatedAt pgtype.Timestamptz
|
||||
}
|
||||
|
||||
type ChatlistInvite struct {
|
||||
ID int64
|
||||
OwnerUserID int64
|
||||
FilterID int32
|
||||
Slug string
|
||||
Title string
|
||||
Peers []byte
|
||||
Revoked bool
|
||||
Deleted bool
|
||||
CreatedAt pgtype.Timestamptz
|
||||
UpdatedAt pgtype.Timestamptz
|
||||
}
|
||||
|
||||
type ChatlistMembership struct {
|
||||
UserID int64
|
||||
LocalFilterID int32
|
||||
OwnerUserID int64
|
||||
OwnerFilterID int32
|
||||
Slug string
|
||||
HiddenUpdates bool
|
||||
JoinedAt pgtype.Timestamptz
|
||||
UpdatedAt pgtype.Timestamptz
|
||||
}
|
||||
|
||||
type Contact struct {
|
||||
UserID int64
|
||||
ContactUserID int64
|
||||
|
|
@ -857,6 +921,8 @@ type GroupCall struct {
|
|||
InviteLink string
|
||||
RandomID int64
|
||||
MigratedFromPhoneCallID int64
|
||||
RtmpStream bool
|
||||
ScheduleDate int32
|
||||
}
|
||||
|
||||
type GroupCallChainBlock struct {
|
||||
|
|
@ -895,6 +961,7 @@ type GroupCallParticipant struct {
|
|||
LastCheckDate int32
|
||||
PublicKey []byte
|
||||
JoinBlock []byte
|
||||
JoinAsChannelID int64
|
||||
}
|
||||
|
||||
type GroupCallParticipantOverride struct {
|
||||
|
|
@ -905,6 +972,17 @@ type GroupCallParticipantOverride struct {
|
|||
Volume int32
|
||||
}
|
||||
|
||||
type GroupCallRtmpKey struct {
|
||||
ChannelID int64
|
||||
StreamKey string
|
||||
UpdatedAt int32
|
||||
}
|
||||
|
||||
type GroupCallScheduleSubscriber struct {
|
||||
CallID int64
|
||||
UserID int64
|
||||
}
|
||||
|
||||
type LangPack struct {
|
||||
LangPack string
|
||||
LangCode string
|
||||
|
|
@ -1197,6 +1275,7 @@ type ScheduledMessage struct {
|
|||
Body string
|
||||
Entities []byte
|
||||
Media []byte
|
||||
RichMessage []byte
|
||||
Silent bool
|
||||
Noforwards bool
|
||||
ReplyToMsgID int32
|
||||
|
|
@ -1555,6 +1634,7 @@ type UserUpdateEvent struct {
|
|||
QuickReplyMessage []byte
|
||||
StoryPayload []byte
|
||||
ReactionPayload []byte
|
||||
EventPhone string
|
||||
}
|
||||
|
||||
type UserUpdateWatermark struct {
|
||||
|
|
|
|||
|
|
@ -881,6 +881,56 @@ func (q *Queries) UpdateUserPersonalChannel(ctx context.Context, arg UpdateUserP
|
|||
return i, err
|
||||
}
|
||||
|
||||
const updateUserPhone = `-- name: UpdateUserPhone :one
|
||||
UPDATE users
|
||||
SET phone = $1::text,
|
||||
updated_at = now()
|
||||
WHERE id = $2::bigint
|
||||
RETURNING id, access_hash, phone, first_name, last_name, username, country_code, created_at, updated_at, verified, support, about, last_seen_at, default_history_ttl_period, is_bot, bot_info_version, premium_expires_at, emoji_status_document_id, emoji_status_until, color_set, color, color_background_emoji_id, profile_color_set, profile_color, profile_color_background_emoji_id, birthday_day, birthday_month, birthday_year, personal_channel_id
|
||||
`
|
||||
|
||||
type UpdateUserPhoneParams struct {
|
||||
Phone string
|
||||
ID int64
|
||||
}
|
||||
|
||||
func (q *Queries) UpdateUserPhone(ctx context.Context, arg UpdateUserPhoneParams) (User, error) {
|
||||
row := q.db.QueryRow(ctx, updateUserPhone, arg.Phone, arg.ID)
|
||||
var i User
|
||||
err := row.Scan(
|
||||
&i.ID,
|
||||
&i.AccessHash,
|
||||
&i.Phone,
|
||||
&i.FirstName,
|
||||
&i.LastName,
|
||||
&i.Username,
|
||||
&i.CountryCode,
|
||||
&i.CreatedAt,
|
||||
&i.UpdatedAt,
|
||||
&i.Verified,
|
||||
&i.Support,
|
||||
&i.About,
|
||||
&i.LastSeenAt,
|
||||
&i.DefaultHistoryTtlPeriod,
|
||||
&i.IsBot,
|
||||
&i.BotInfoVersion,
|
||||
&i.PremiumExpiresAt,
|
||||
&i.EmojiStatusDocumentID,
|
||||
&i.EmojiStatusUntil,
|
||||
&i.ColorSet,
|
||||
&i.Color,
|
||||
&i.ColorBackgroundEmojiID,
|
||||
&i.ProfileColorSet,
|
||||
&i.ProfileColor,
|
||||
&i.ProfileColorBackgroundEmojiID,
|
||||
&i.BirthdayDay,
|
||||
&i.BirthdayMonth,
|
||||
&i.BirthdayYear,
|
||||
&i.PersonalChannelID,
|
||||
)
|
||||
return i, err
|
||||
}
|
||||
|
||||
const updateUserProfile = `-- name: UpdateUserProfile :one
|
||||
UPDATE users
|
||||
SET first_name = $2,
|
||||
|
|
|
|||
|
|
@ -17,6 +17,7 @@ INSERT INTO user_update_events (
|
|||
date,
|
||||
event_type,
|
||||
event_bool,
|
||||
event_phone,
|
||||
event_peers,
|
||||
peer_settings,
|
||||
message_ids,
|
||||
|
|
@ -41,7 +42,7 @@ INSERT INTO user_update_events (
|
|||
$4,
|
||||
$5,
|
||||
$6::boolean,
|
||||
$7::jsonb,
|
||||
$7::text,
|
||||
$8::jsonb,
|
||||
$9::jsonb,
|
||||
$10::jsonb,
|
||||
|
|
@ -49,15 +50,16 @@ INSERT INTO user_update_events (
|
|||
$12::jsonb,
|
||||
$13::jsonb,
|
||||
$14::jsonb,
|
||||
$15,
|
||||
$16::text,
|
||||
$17::bigint,
|
||||
$18::int,
|
||||
$15::jsonb,
|
||||
$16,
|
||||
$17::text,
|
||||
$18::bigint,
|
||||
$19::int,
|
||||
$20::int,
|
||||
$21::int,
|
||||
$22::boolean,
|
||||
$23::int
|
||||
$22::int,
|
||||
$23::boolean,
|
||||
$24::int
|
||||
)
|
||||
`
|
||||
|
||||
|
|
@ -68,6 +70,7 @@ type AppendUserUpdateEventParams struct {
|
|||
Date int32
|
||||
EventType string
|
||||
EventBool bool
|
||||
EventPhone string
|
||||
EventPeers []byte
|
||||
PeerSettings []byte
|
||||
MessageIds []byte
|
||||
|
|
@ -95,6 +98,7 @@ func (q *Queries) AppendUserUpdateEvent(ctx context.Context, arg AppendUserUpdat
|
|||
arg.Date,
|
||||
arg.EventType,
|
||||
arg.EventBool,
|
||||
arg.EventPhone,
|
||||
arg.EventPeers,
|
||||
arg.PeerSettings,
|
||||
arg.MessageIds,
|
||||
|
|
@ -124,6 +128,7 @@ SELECT
|
|||
e.date,
|
||||
e.event_type,
|
||||
e.event_bool,
|
||||
e.event_phone,
|
||||
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,
|
||||
|
|
@ -260,6 +265,7 @@ type BatchListDispatchEventsRow struct {
|
|||
Date int32
|
||||
EventType string
|
||||
EventBool bool
|
||||
EventPhone string
|
||||
EventPeersJson string
|
||||
PeerSettingsJson string
|
||||
MessageIdsJson string
|
||||
|
|
@ -394,6 +400,7 @@ func (q *Queries) BatchListDispatchEvents(ctx context.Context, arg BatchListDisp
|
|||
&i.Date,
|
||||
&i.EventType,
|
||||
&i.EventBool,
|
||||
&i.EventPhone,
|
||||
&i.EventPeersJson,
|
||||
&i.PeerSettingsJson,
|
||||
&i.MessageIdsJson,
|
||||
|
|
@ -681,6 +688,7 @@ SELECT
|
|||
e.date,
|
||||
e.event_type,
|
||||
e.event_bool,
|
||||
e.event_phone,
|
||||
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,
|
||||
|
|
@ -820,6 +828,7 @@ type ListUserUpdateEventsAfterRow struct {
|
|||
Date int32
|
||||
EventType string
|
||||
EventBool bool
|
||||
EventPhone string
|
||||
EventPeersJson string
|
||||
PeerSettingsJson string
|
||||
MessageIdsJson string
|
||||
|
|
@ -952,6 +961,7 @@ func (q *Queries) ListUserUpdateEventsAfter(ctx context.Context, arg ListUserUpd
|
|||
&i.Date,
|
||||
&i.EventType,
|
||||
&i.EventBool,
|
||||
&i.EventPhone,
|
||||
&i.EventPeersJson,
|
||||
&i.PeerSettingsJson,
|
||||
&i.MessageIdsJson,
|
||||
|
|
|
|||
|
|
@ -218,6 +218,7 @@ func appendUserUpdateEvent(ctx context.Context, db sqlcgen.DBTX, q *sqlcgen.Quer
|
|||
Date: int32(event.Date),
|
||||
EventType: string(event.Type),
|
||||
EventBool: event.Bool,
|
||||
EventPhone: event.Phone,
|
||||
EventPeers: peers,
|
||||
PeerSettings: settings,
|
||||
MessageIds: messageIDs,
|
||||
|
|
@ -406,6 +407,7 @@ func (s *UpdateEventStore) ListAfter(ctx context.Context, userID int64, pts, lim
|
|||
Story: story,
|
||||
Peers: peers,
|
||||
Bool: row.EventBool,
|
||||
Phone: row.EventPhone,
|
||||
Settings: settings,
|
||||
MessageIDs: messageIDs,
|
||||
MaxID: int(row.MaxID),
|
||||
|
|
@ -599,6 +601,7 @@ func (s *UpdateEventStore) BatchByCursor(ctx context.Context, cursors []store.Ev
|
|||
Story: story,
|
||||
Peers: peers,
|
||||
Bool: row.EventBool,
|
||||
Phone: row.EventPhone,
|
||||
Settings: settings,
|
||||
MessageIDs: messageIDs,
|
||||
MaxID: int(row.MaxID),
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue