db

package
v0.0.0-...-95efd2c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 12, 2026 License: Apache-2.0 Imports: 17 Imported by: 0

Documentation

Overview

Package db implements the SQLite storage engine backing every stateful feature in tdlib. It opens a CGO-free modernc.org/sqlite database in WAL mode, runs embedded golang-migrate migrations, and exposes a typed key-value store, a crash-safe binlog of pending operations, and one domain method per file.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

This section is empty.

Types

type BinlogEntry

type BinlogEntry struct {
	// ID is the auto-assigned row id; used to confirm the entry.
	ID int64
	// OpType is a short string tag identifying the operation kind, e.g.
	// "send_message".
	OpType string
	// Payload is the serialised operation data (caller-chosen encoding).
	Payload []byte
	// CreatedAt is the wall-clock time the entry was appended.
	CreatedAt time.Time
}

BinlogEntry is one pending operation that survives a crash. An entry is appended before the network call and confirmed (deleted) on success; unconfirmed entries are replayed on startup in ascending ID order.

type Chat

type Chat struct {
	ID                      int64
	Type                    int
	Title                   string
	UserID                  int64
	AccessHash              int64
	LastMessageID           int64
	LastMessageDate         int64
	Pinned                  bool
	UnreadCount             int
	LastReadInboxMessageID  int64
	LastReadOutboxMessageID int64
	DraftText               string
	InList                  bool
}

Chat is the chat row as stored by internal/db. It is self-contained (no root dependency); the root package converts to/from tdlib.Chat.

type DB

type DB struct {
	// contains filtered or unexported fields
}

DB wraps a *sql.DB with the squirrel builder pre-configured for SQLite (question-mark placeholders). Domain methods are declared as receivers on this type, one file per domain.

func Open

func Open(ctx context.Context, path string, key EncryptionKey, providers obs.Providers, logger log.Logger) (*DB, error)

Open opens (or creates) the SQLite database at path, applies embedded migrations, and returns a ready-to-use DB. When providers carry a real meter or tracer, the handle is instrumented via otelsql. The key parameter is reserved for at-rest encryption and is currently ignored.

The returned DB must be closed via DB.Close.

func (*DB) AllocFileID

func (d *DB) AllocFileID(ctx context.Context) (id int64, err error)

AllocFileID atomically increments and returns the next file-id sequence value.

func (*DB) BinlogAppend

func (d *DB) BinlogAppend(ctx context.Context, tx *sql.Tx, opType string, payload []byte) (int64, error)

BinlogAppend writes a pending-operation entry. When tx is non-nil the insert runs inside it, so the domain change and the log entry commit or roll back together; pass nil to use the pool directly. It returns the new entry id.

func (*DB) BinlogConfirm

func (d *DB) BinlogConfirm(ctx context.Context, id int64) error

BinlogConfirm deletes the entry with the given id after its network operation has succeeded.

func (*DB) BinlogConfirmBatch

func (d *DB) BinlogConfirmBatch(ctx context.Context, ids []int64) error

BinlogConfirmBatch deletes multiple entries in a single statement, used when one network response confirms several queued operations at once.

func (*DB) BinlogReplay

func (d *DB) BinlogReplay(ctx context.Context) ([]BinlogEntry, error)

BinlogReplay returns all unconfirmed entries in ascending id order. It is called once on startup before accepting new operations.

func (*DB) Close

func (d *DB) Close() error

Close releases the underlying database connection.

func (*DB) ConfirmPendingSend

func (d *DB) ConfirmPendingSend(ctx context.Context, binlogID, chatID, oldID, newID int64) (err error)

ConfirmPendingSend promotes a confirmed send: it remaps the message primary key from oldID to newID (clearing the pending state), removes the pending_sends mapping, and confirms (deletes) the binlog entry — atomically.

func (*DB) DB

func (d *DB) DB() *sql.DB

DB returns the raw *sql.DB for callers that need it (e.g. transactions that span a domain write and a binlog append).

func (*DB) DeleteMessages

func (d *DB) DeleteMessages(ctx context.Context, chatID int64, ids []int64) error

DeleteMessages removes messages from the cache; a no-op for absent ids.

func (*DB) DeleteOption

func (d *DB) DeleteOption(ctx context.Context, name string) error

DeleteOption removes the named option row; a no-op when absent.

func (*DB) FailPendingSend

func (d *DB) FailPendingSend(ctx context.Context, binlogID, chatID, msgID int64) (err error)

FailPendingSend marks a send as failed: it sets the message's sending_state to 2, removes the pending_sends mapping, and confirms the binlog entry (a terminal failure must not be replayed) — atomically.

func (*DB) ForEachChannels

func (d *DB) ForEachChannels(ctx context.Context, userID int64, f func(ctx context.Context, channelID int64, pts int) error) error

ForEachChannels implements updates.StateStorage.

func (*DB) GetAllOptions

func (d *DB) GetAllOptions(ctx context.Context) (map[string][]byte, error)

GetAllOptions returns all rows from the option table as a map[name]value. Used by the option manager to load persisted state at startup.

func (*DB) GetChannelAccessHash

func (d *DB) GetChannelAccessHash(ctx context.Context, _ int64, channelID int64) (int64, bool, error)

GetChannelAccessHash implements updates.ChannelAccessHasher.

func (*DB) GetChannelPts

func (d *DB) GetChannelPts(ctx context.Context, userID, channelID int64) (int, bool, error)

GetChannelPts implements updates.StateStorage.

func (*DB) GetChat

func (d *DB) GetChat(ctx context.Context, id int64) (*Chat, error)

GetChat returns the cached chat, or (nil, nil) when absent.

func (*DB) GetChatHistory

func (d *DB) GetChatHistory(ctx context.Context, chatID, fromMessageID int64, offset, limit int) ([]*Message, error)

GetChatHistory returns a page of cached messages for chatID, newest first. fromMessageID is the exclusive upper bound (zero = newest); offset shifts the window; limit is capped at 100.

func (*DB) GetContacts

func (d *DB) GetContacts(ctx context.Context) ([]*User, error)

GetContacts returns all contact-flagged users ordered by id ascending.

func (*DB) GetFile

func (d *DB) GetFile(ctx context.Context, id int64) (*File, error)

GetFile returns the stored file, or (nil, nil) when absent.

func (*DB) GetFileByRemoteID

func (d *DB) GetFileByRemoteID(ctx context.Context, remoteID int64) (*File, error)

GetFileByRemoteID returns the file with the given remote (document) id, or (nil, nil).

func (*DB) GetFileByUniqueID

func (d *DB) GetFileByUniqueID(ctx context.Context, uniqueID string) (*File, error)

GetFileByUniqueID returns the file with the given unique id, or (nil, nil).

func (*DB) GetFileReference

func (d *DB) GetFileReference(ctx context.Context, id int64) ([]byte, error)

GetFileReference returns the stored file_reference bytes, or (nil, nil).

func (*DB) GetMessage

func (d *DB) GetMessage(ctx context.Context, chatID, id int64) (*Message, error)

GetMessage returns the cached message for (chatID, id), or (nil, nil).

func (*DB) GetMessageByRandomID

func (d *DB) GetMessageByRandomID(ctx context.Context, randomID int64) (*Message, error)

GetMessageByRandomID returns the message bound to randomID via pending_sends, or (nil, nil) when there is no such pending send.

func (*DB) GetMessages

func (d *DB) GetMessages(ctx context.Context, chatID int64, ids []int64) ([]*Message, error)

GetMessages returns cached messages for ids within chatID; missing ones are omitted.

func (*DB) GetMyID

func (d *DB) GetMyID(ctx context.Context) (int64, error)

GetMyID returns the persisted self-user id, or (0, nil) when unset.

func (*DB) GetOption

func (d *DB) GetOption(ctx context.Context, name string) ([]byte, error)

GetOption returns the stored bytes for name, or (nil, nil) when not found.

func (*DB) GetState

func (d *DB) GetState(ctx context.Context, userID int64) (updates.State, bool, error)

GetState implements updates.StateStorage.

func (*DB) GetUser

func (d *DB) GetUser(ctx context.Context, id int64) (*User, error)

GetUser returns the cached user, or (nil, nil) when absent.

func (*DB) GetUserAccessHash

func (d *DB) GetUserAccessHash(ctx context.Context, _ int64, targetUserID int64) (int64, bool, error)

GetUserAccessHash implements updates.UserAccessHasher.

func (*DB) GetUsers

func (d *DB) GetUsers(ctx context.Context, ids []int64) ([]*User, error)

GetUsers returns cached records for ids; missing entries are omitted.

func (*DB) InsertPendingSend

func (d *DB) InsertPendingSend(ctx context.Context, m *Message, opType string, payload []byte) (binlogID int64, err error)

InsertPendingSend atomically records an optimistic outgoing message: it upserts the message row (with its pending sending_state and random_id), inserts the pending_sends mapping, and appends a binlog entry — all in one transaction so intent and state commit together. It returns the binlog id.

func (*DB) KVDelete

func (d *DB) KVDelete(ctx context.Context, ns KVNamespace, key string) error

KVDelete removes the entry at (namespace, key); a no-op when absent.

func (*DB) KVGet

func (d *DB) KVGet(ctx context.Context, ns KVNamespace, key string) ([]byte, error)

KVGet returns the value stored under (namespace, key), or (nil, nil) when the key does not exist.

func (*DB) KVGetAll

func (d *DB) KVGetAll(ctx context.Context, ns KVNamespace) (map[string][]byte, error)

KVGetAll returns all entries under namespace as a map[key]value.

func (*DB) KVSet

func (d *DB) KVSet(ctx context.Context, ns KVNamespace, key string, value []byte) error

KVSet upserts a value under (namespace, key).

func (*DB) ListDialogs

func (d *DB) ListDialogs(ctx context.Context) ([]*Chat, error)

ListDialogs returns all in-list chats ordered by (pinned DESC, date DESC).

func (*DB) SetChannelAccessHash

func (d *DB) SetChannelAccessHash(ctx context.Context, _ int64, channelID, accessHash int64) error

SetChannelAccessHash implements updates.ChannelAccessHasher. It upserts the chats row's access_hash with the never-overwrite-with-zero rule (RFC 0009).

func (*DB) SetChannelPts

func (d *DB) SetChannelPts(ctx context.Context, userID, channelID int64, pts int) error

SetChannelPts implements updates.StateStorage.

func (*DB) SetContact

func (d *DB) SetContact(ctx context.Context, id int64, isContact, isMutual bool) error

SetContact updates the contact flags for a user.

func (*DB) SetDate

func (d *DB) SetDate(ctx context.Context, userID int64, date int) error

SetDate implements updates.StateStorage.

func (*DB) SetDateSeq

func (d *DB) SetDateSeq(ctx context.Context, userID int64, date, seq int) error

SetDateSeq implements updates.StateStorage.

func (*DB) SetFileReference

func (d *DB) SetFileReference(ctx context.Context, id int64, ref []byte) error

SetFileReference updates the file_reference bytes for id.

func (*DB) SetMyID

func (d *DB) SetMyID(ctx context.Context, id int64) error

SetMyID persists the self-user id.

func (*DB) SetOption

func (d *DB) SetOption(ctx context.Context, name string, value []byte) error

SetOption upserts a named option value. It demonstrates the domain-method pattern that subsequent RFCs follow, and is functionally complete for RFC 0007's core needs.

func (*DB) SetPts

func (d *DB) SetPts(ctx context.Context, userID int64, pts int) error

SetPts implements updates.StateStorage.

func (*DB) SetQts

func (d *DB) SetQts(ctx context.Context, userID int64, qts int) error

SetQts implements updates.StateStorage.

func (*DB) SetSeq

func (d *DB) SetSeq(ctx context.Context, userID int64, seq int) error

SetSeq implements updates.StateStorage.

func (*DB) SetState

func (d *DB) SetState(ctx context.Context, userID int64, s updates.State) error

SetState implements updates.StateStorage.

func (*DB) SetUserAccessHash

func (d *DB) SetUserAccessHash(ctx context.Context, _ int64, targetUserID, accessHash int64) error

SetUserAccessHash implements updates.UserAccessHasher. It delegates to the users-table upsert (which carries the never-overwrite-with-zero CASE).

func (*DB) SetUserStatus

func (d *DB) SetUserStatus(ctx context.Context, id int64, kind int, expires, wasOnline int64) error

SetUserStatus updates only the status columns of a user, leaving every other column (notably access_hash and names) intact. It is a no-op for an unknown id.

func (*DB) UpdateChatDraft

func (d *DB) UpdateChatDraft(ctx context.Context, id int64, draftText string) error

UpdateChatDraft persists the draft text.

func (*DB) UpdateChatLastMessage

func (d *DB) UpdateChatLastMessage(ctx context.Context, id, lastMsgID, lastMsgDate int64) error

UpdateChatLastMessage updates the top message id and order key.

func (*DB) UpdateChatReadInbox

func (d *DB) UpdateChatReadInbox(ctx context.Context, id, lastRead int64, unread int) error

UpdateChatReadInbox advances the inbox high-water mark and unread count.

func (*DB) UpdateChatReadOutbox

func (d *DB) UpdateChatReadOutbox(ctx context.Context, id, lastRead int64) error

UpdateChatReadOutbox advances the outbox high-water mark.

func (*DB) UpsertChat

func (d *DB) UpsertChat(ctx context.Context, c *Chat) error

UpsertChat inserts or updates a chat header. The access_hash CASE never overwrites a stored non-zero hash with zero; in_list only ratchets up (a header upsert never removes a chat from the dialog list).

func (*DB) UpsertFile

func (d *DB) UpsertFile(ctx context.Context, f *File) error

UpsertFile inserts or updates file metadata keyed by file_id.

func (*DB) UpsertMessage

func (d *DB) UpsertMessage(ctx context.Context, m *Message) error

UpsertMessage inserts or updates a single message row.

func (*DB) UpsertMessages

func (d *DB) UpsertMessages(ctx context.Context, msgs []*Message) (err error)

UpsertMessages inserts or updates a batch in one transaction.

func (*DB) UpsertUser

func (d *DB) UpsertUser(ctx context.Context, u *User) error

UpsertUser inserts or updates the user row. The access_hash column is guarded by a CASE so a zero or min-user incoming value never overwrites a stored non-zero hash; phone is likewise preserved when the incoming value is empty.

type EncryptionKey

type EncryptionKey []byte

EncryptionKey is reserved for future at-rest encryption (the TDLib DbKey analogue). Passing nil disables encryption; the parameter exists so the Open signature does not change when encryption lands.

type File

type File struct {
	FileID                 int64
	RemoteID               int64
	UniqueID               string
	AccessHash             int64
	FileReference          []byte
	DCID                   int
	LocalPath              string
	Size                   int64
	DownloadedSize         int64
	IsDownloadingCompleted bool
	IsUploadingCompleted   bool
	UploadedSize           int64
}

File is the file row as stored by internal/db (self-contained; the root package converts to/from tdlib.File).

type KVNamespace

type KVNamespace string

KVNamespace scopes key-value entries to avoid collisions between subsystems.

It lives in this package (not the root) so internal/db stays self-contained and the root package can import db without an import cycle.

const (
	// KVNamespaceOptions stores account option values (RFC 0007).
	KVNamespaceOptions KVNamespace = "options"
	// KVNamespaceSession stores the gotd/td session bytes (RFC 0005).
	KVNamespaceSession KVNamespace = "session"
	// KVNamespaceUpdates stores update-state counters (RFC 0013).
	KVNamespaceUpdates KVNamespace = "updates"
	// KVNamespaceAuth stores the authorization state machine's persisted state
	// (RFC 0006).
	KVNamespaceAuth KVNamespace = "auth"
	// KVNamespaceUsers stores user-domain scalars such as my_id (RFC 0008).
	KVNamespaceUsers KVNamespace = "users"
	// KVNamespaceFiles stores the file-id sequence counter (RFC 0012).
	KVNamespaceFiles KVNamespace = "files"
)

Key-value namespaces.

type Message

type Message struct {
	ChatID        int64
	ID            int64
	SenderID      int64
	Date          int64
	EditDate      int64
	IsOutgoing    bool
	ReplyToChatID int64
	ReplyToMsgID  int64
	ContentKind   int
	ContentText   string
	SendingState  int
	RandomID      int64
}

Message is the message row as stored by internal/db (self-contained; the root package converts to/from tdlib.Message).

type User

type User struct {
	ID              int64
	AccessHash      int64
	FirstName       string
	LastName        string
	Username        string
	Usernames       []string
	Phone           string
	StatusKind      int
	StatusExpires   int64
	StatusWasOnline int64
	IsBot           bool
	IsContact       bool
	IsMutualContact bool
	IsSelf          bool
	IsMin           bool
}

User is the user row as stored by internal/db. It is a plain data type with no dependency on the root package, so internal/db stays self-contained; the root package converts between this and tdlib.User.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL