// Code generated by sqlc. DO NOT EDIT. // versions: // sqlc v1.31.1 // source: media.sql package sqlcgen import ( "context" "github.com/jackc/pgx/v5/pgtype" ) const addProfilePhoto = `-- name: AddProfilePhoto :exec INSERT INTO profile_photos (owner_peer_type, owner_peer_id, photo_id, date, active, sort_order) VALUES ( $1::text, $2::bigint, $3::bigint, $4::int, true, $5::bigint ) ON CONFLICT (owner_peer_type, owner_peer_id, photo_id) DO UPDATE SET date = EXCLUDED.date, active = true, sort_order = EXCLUDED.sort_order ` type AddProfilePhotoParams struct { OwnerPeerType string OwnerPeerID int64 PhotoID int64 Date int32 SortOrder int64 } // profile_photos -------------------------------------------------------------- func (q *Queries) AddProfilePhoto(ctx context.Context, arg AddProfilePhotoParams) error { _, err := q.db.Exec(ctx, addProfilePhoto, arg.OwnerPeerType, arg.OwnerPeerID, arg.PhotoID, arg.Date, arg.SortOrder, ) return err } const clearDocumentOrphan = `-- name: ClearDocumentOrphan :exec UPDATE documents SET orphaned_at = NULL WHERE id = $1::bigint AND orphaned_at IS NOT NULL ` func (q *Queries) ClearDocumentOrphan(ctx context.Context, mediaID int64) error { _, err := q.db.Exec(ctx, clearDocumentOrphan, mediaID) return err } const clearPhotoOrphan = `-- name: ClearPhotoOrphan :exec UPDATE photos SET orphaned_at = NULL WHERE id = $1::bigint AND orphaned_at IS NOT NULL ` func (q *Queries) ClearPhotoOrphan(ctx context.Context, mediaID int64) error { _, err := q.db.Exec(ctx, clearPhotoOrphan, mediaID) return err } const countAvailableReactions = `-- name: CountAvailableReactions :one SELECT count(*)::int AS total FROM available_reactions ` func (q *Queries) CountAvailableReactions(ctx context.Context) (int32, error) { row := q.db.QueryRow(ctx, countAvailableReactions) var total int32 err := row.Scan(&total) return total, err } const countFileBlobRefs = `-- name: CountFileBlobRefs :one SELECT COUNT(*)::int FROM file_blobs WHERE backend = $1::text AND object_key = $2::text ` type CountFileBlobRefsParams struct { Backend string ObjectKey string } func (q *Queries) CountFileBlobRefs(ctx context.Context, arg CountFileBlobRefsParams) (int32, error) { row := q.db.QueryRow(ctx, countFileBlobRefs, arg.Backend, arg.ObjectKey) var column_1 int32 err := row.Scan(&column_1) return column_1, err } const countProfilePhotos = `-- name: CountProfilePhotos :one SELECT count(*)::int AS total FROM profile_photos WHERE owner_peer_type = $1::text AND owner_peer_id = $2::bigint AND active ` type CountProfilePhotosParams struct { OwnerPeerType string OwnerPeerID int64 } func (q *Queries) CountProfilePhotos(ctx context.Context, arg CountProfilePhotosParams) (int32, error) { row := q.db.QueryRow(ctx, countProfilePhotos, arg.OwnerPeerType, arg.OwnerPeerID) var total int32 err := row.Scan(&total) return total, err } const countStickerSets = `-- name: CountStickerSets :one SELECT count(*)::int AS total FROM sticker_sets ` func (q *Queries) CountStickerSets(ctx context.Context) (int32, error) { row := q.db.QueryRow(ctx, countStickerSets) var total int32 err := row.Scan(&total) return total, err } const currentProfilePhoto = `-- name: CurrentProfilePhoto :one SELECT photo_id FROM profile_photos WHERE owner_peer_type = $1::text AND owner_peer_id = $2::bigint AND active ORDER BY sort_order DESC LIMIT 1 ` type CurrentProfilePhotoParams struct { OwnerPeerType string OwnerPeerID int64 } func (q *Queries) CurrentProfilePhoto(ctx context.Context, arg CurrentProfilePhotoParams) (int64, error) { row := q.db.QueryRow(ctx, currentProfilePhoto, arg.OwnerPeerType, arg.OwnerPeerID) var photo_id int64 err := row.Scan(&photo_id) return photo_id, err } const currentProfilePhotosForOwners = `-- 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 = $1::text AND pp.owner_peer_id = ANY($2::bigint[]) AND pp.active ORDER BY pp.owner_peer_id, pp.sort_order DESC ` type CurrentProfilePhotosForOwnersParams struct { OwnerPeerType string OwnerIds []int64 } type CurrentProfilePhotosForOwnersRow struct { OwnerPeerID int64 PhotoID int64 DcID int32 SizesJson string } func (q *Queries) CurrentProfilePhotosForOwners(ctx context.Context, arg CurrentProfilePhotosForOwnersParams) ([]CurrentProfilePhotosForOwnersRow, error) { rows, err := q.db.Query(ctx, currentProfilePhotosForOwners, arg.OwnerPeerType, arg.OwnerIds) if err != nil { return nil, err } defer rows.Close() var items []CurrentProfilePhotosForOwnersRow for rows.Next() { var i CurrentProfilePhotosForOwnersRow if err := rows.Scan( &i.OwnerPeerID, &i.PhotoID, &i.DcID, &i.SizesJson, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const deactivateProfilePhotos = `-- name: DeactivateProfilePhotos :many UPDATE profile_photos SET active = false WHERE owner_peer_type = $1::text AND owner_peer_id = $2::bigint AND photo_id = ANY($3::bigint[]) AND active RETURNING photo_id ` type DeactivateProfilePhotosParams struct { OwnerPeerType string OwnerPeerID int64 PhotoIds []int64 } func (q *Queries) DeactivateProfilePhotos(ctx context.Context, arg DeactivateProfilePhotosParams) ([]int64, error) { rows, err := q.db.Query(ctx, deactivateProfilePhotos, arg.OwnerPeerType, arg.OwnerPeerID, arg.PhotoIds) if err != nil { return nil, err } defer rows.Close() var items []int64 for rows.Next() { var photo_id int64 if err := rows.Scan(&photo_id); err != nil { return nil, err } items = append(items, photo_id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const deleteDocumentRow = `-- name: DeleteDocumentRow :exec DELETE FROM documents WHERE id = $1::bigint ` func (q *Queries) DeleteDocumentRow(ctx context.Context, id int64) error { _, err := q.db.Exec(ctx, deleteDocumentRow, id) return err } const deleteExpiredUploadParts = `-- name: DeleteExpiredUploadParts :many WITH doomed AS ( SELECT owner_user_id, file_id, part FROM upload_parts WHERE created_at < $1::timestamptz ORDER BY created_at ASC LIMIT $2::int ) DELETE FROM upload_parts p USING doomed d WHERE p.owner_user_id = d.owner_user_id AND p.file_id = d.file_id AND p.part = d.part RETURNING p.object_key ` type DeleteExpiredUploadPartsParams struct { Before pgtype.Timestamptz BatchLimit int32 } func (q *Queries) DeleteExpiredUploadParts(ctx context.Context, arg DeleteExpiredUploadPartsParams) ([]string, error) { rows, err := q.db.Query(ctx, deleteExpiredUploadParts, arg.Before, arg.BatchLimit) if err != nil { return nil, err } defer rows.Close() var items []string for rows.Next() { var object_key string if err := rows.Scan(&object_key); err != nil { return nil, err } items = append(items, object_key) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const deleteFileBlobRow = `-- name: DeleteFileBlobRow :exec DELETE FROM file_blobs WHERE location_key = $1::text ` func (q *Queries) DeleteFileBlobRow(ctx context.Context, locationKey string) error { _, err := q.db.Exec(ctx, deleteFileBlobRow, locationKey) return err } const deletePhotoRow = `-- name: DeletePhotoRow :exec DELETE FROM photos WHERE id = $1::bigint ` func (q *Queries) DeletePhotoRow(ctx context.Context, id int64) error { _, err := q.db.Exec(ctx, deletePhotoRow, id) return err } const deleteUploadParts = `-- name: DeleteUploadParts :many DELETE FROM upload_parts WHERE owner_user_id = $1::bigint AND file_id = $2::bigint RETURNING object_key ` type DeleteUploadPartsParams struct { OwnerUserID int64 FileID int64 } func (q *Queries) DeleteUploadParts(ctx context.Context, arg DeleteUploadPartsParams) ([]string, error) { rows, err := q.db.Query(ctx, deleteUploadParts, arg.OwnerUserID, arg.FileID) if err != nil { return nil, err } defer rows.Close() var items []string for rows.Next() { var object_key string if err := rows.Scan(&object_key); err != nil { return nil, err } items = append(items, object_key) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getDocument = `-- 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, owner_user_id FROM documents WHERE id = $1::bigint ` type GetDocumentRow struct { ID int64 AccessHash int64 FileReference []byte Date int32 MimeType string Size int64 DcID int32 AttributesJson string ThumbsJson string OwnerUserID int64 } func (q *Queries) GetDocument(ctx context.Context, id int64) (GetDocumentRow, error) { row := q.db.QueryRow(ctx, getDocument, id) var i GetDocumentRow err := row.Scan( &i.ID, &i.AccessHash, &i.FileReference, &i.Date, &i.MimeType, &i.Size, &i.DcID, &i.AttributesJson, &i.ThumbsJson, &i.OwnerUserID, ) return i, err } const getDocuments = `-- 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, owner_user_id FROM documents WHERE id = ANY($1::bigint[]) ` type GetDocumentsRow struct { ID int64 AccessHash int64 FileReference []byte Date int32 MimeType string Size int64 DcID int32 AttributesJson string ThumbsJson string OwnerUserID int64 } func (q *Queries) GetDocuments(ctx context.Context, ids []int64) ([]GetDocumentsRow, error) { rows, err := q.db.Query(ctx, getDocuments, ids) if err != nil { return nil, err } defer rows.Close() var items []GetDocumentsRow for rows.Next() { var i GetDocumentsRow if err := rows.Scan( &i.ID, &i.AccessHash, &i.FileReference, &i.Date, &i.MimeType, &i.Size, &i.DcID, &i.AttributesJson, &i.ThumbsJson, &i.OwnerUserID, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const getFileBlob = `-- name: GetFileBlob :one SELECT location_key, backend, object_key, size, sha256, mime_type FROM file_blobs WHERE location_key = $1::text ` type GetFileBlobRow struct { LocationKey string Backend string ObjectKey string Size int64 Sha256 []byte MimeType string } func (q *Queries) GetFileBlob(ctx context.Context, locationKey string) (GetFileBlobRow, error) { row := q.db.QueryRow(ctx, getFileBlob, locationKey) var i GetFileBlobRow err := row.Scan( &i.LocationKey, &i.Backend, &i.ObjectKey, &i.Size, &i.Sha256, &i.MimeType, ) return i, err } const getPhoto = `-- name: GetPhoto :one SELECT id, access_hash, file_reference, date, dc_id, has_stickers, sizes::text AS sizes_json, owner_user_id FROM photos WHERE id = $1::bigint ` type GetPhotoRow struct { ID int64 AccessHash int64 FileReference []byte Date int32 DcID int32 HasStickers bool SizesJson string OwnerUserID int64 } func (q *Queries) GetPhoto(ctx context.Context, id int64) (GetPhotoRow, error) { row := q.db.QueryRow(ctx, getPhoto, id) var i GetPhotoRow err := row.Scan( &i.ID, &i.AccessHash, &i.FileReference, &i.Date, &i.DcID, &i.HasStickers, &i.SizesJson, &i.OwnerUserID, ) return i, err } const getStickerSetByID = `-- 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 = $1::bigint ` type GetStickerSetByIDRow struct { ID int64 AccessHash int64 ShortName string Title string Count int32 Hash int32 SetKind string Official bool Animated bool Videos bool Emojis bool Masks bool Installed bool Archived bool InstalledDate int32 ThumbDocumentID int64 ThumbsJson string ThumbDcID int32 ThumbVersion int32 DocumentIdsJson string PacksJson string SortOrder int32 SystemKey string } func (q *Queries) GetStickerSetByID(ctx context.Context, id int64) (GetStickerSetByIDRow, error) { row := q.db.QueryRow(ctx, getStickerSetByID, id) var i GetStickerSetByIDRow err := row.Scan( &i.ID, &i.AccessHash, &i.ShortName, &i.Title, &i.Count, &i.Hash, &i.SetKind, &i.Official, &i.Animated, &i.Videos, &i.Emojis, &i.Masks, &i.Installed, &i.Archived, &i.InstalledDate, &i.ThumbDocumentID, &i.ThumbsJson, &i.ThumbDcID, &i.ThumbVersion, &i.DocumentIdsJson, &i.PacksJson, &i.SortOrder, &i.SystemKey, ) return i, err } const getStickerSetByShortName = `-- 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 = $1::text ` type GetStickerSetByShortNameRow struct { ID int64 AccessHash int64 ShortName string Title string Count int32 Hash int32 SetKind string Official bool Animated bool Videos bool Emojis bool Masks bool Installed bool Archived bool InstalledDate int32 ThumbDocumentID int64 ThumbsJson string ThumbDcID int32 ThumbVersion int32 DocumentIdsJson string PacksJson string SortOrder int32 SystemKey string } func (q *Queries) GetStickerSetByShortName(ctx context.Context, shortName string) (GetStickerSetByShortNameRow, error) { row := q.db.QueryRow(ctx, getStickerSetByShortName, shortName) var i GetStickerSetByShortNameRow err := row.Scan( &i.ID, &i.AccessHash, &i.ShortName, &i.Title, &i.Count, &i.Hash, &i.SetKind, &i.Official, &i.Animated, &i.Videos, &i.Emojis, &i.Masks, &i.Installed, &i.Archived, &i.InstalledDate, &i.ThumbDocumentID, &i.ThumbsJson, &i.ThumbDcID, &i.ThumbVersion, &i.DocumentIdsJson, &i.PacksJson, &i.SortOrder, &i.SystemKey, ) return i, err } const getStickerSetBySystemKey = `-- 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 = $1::text ` type GetStickerSetBySystemKeyRow struct { ID int64 AccessHash int64 ShortName string Title string Count int32 Hash int32 SetKind string Official bool Animated bool Videos bool Emojis bool Masks bool Installed bool Archived bool InstalledDate int32 ThumbDocumentID int64 ThumbsJson string ThumbDcID int32 ThumbVersion int32 DocumentIdsJson string PacksJson string SortOrder int32 SystemKey string } func (q *Queries) GetStickerSetBySystemKey(ctx context.Context, systemKey string) (GetStickerSetBySystemKeyRow, error) { row := q.db.QueryRow(ctx, getStickerSetBySystemKey, systemKey) var i GetStickerSetBySystemKeyRow err := row.Scan( &i.ID, &i.AccessHash, &i.ShortName, &i.Title, &i.Count, &i.Hash, &i.SetKind, &i.Official, &i.Animated, &i.Videos, &i.Emojis, &i.Masks, &i.Installed, &i.Archived, &i.InstalledDate, &i.ThumbDocumentID, &i.ThumbsJson, &i.ThumbDcID, &i.ThumbVersion, &i.DocumentIdsJson, &i.PacksJson, &i.SortOrder, &i.SystemKey, ) return i, err } const getUploadPartSlot = `-- name: GetUploadPartSlot :one SELECT COALESCE(( SELECT size FROM upload_parts WHERE owner_user_id = $1::bigint AND file_id = $2::bigint AND part = $3::int ), -1)::bigint AS existing_bytes, COALESCE(( SELECT object_key FROM upload_parts WHERE owner_user_id = $1::bigint AND file_id = $2::bigint AND part = $3::int ), '')::text AS object_key, ( SELECT COUNT(*)::int FROM upload_parts WHERE owner_user_id = $1::bigint AND file_id = $2::bigint )::int AS file_parts ` type GetUploadPartSlotParams struct { OwnerUserID int64 FileID int64 Part int32 } type GetUploadPartSlotRow struct { ExistingBytes int64 ObjectKey string FileParts int32 } func (q *Queries) GetUploadPartSlot(ctx context.Context, arg GetUploadPartSlotParams) (GetUploadPartSlotRow, error) { row := q.db.QueryRow(ctx, getUploadPartSlot, arg.OwnerUserID, arg.FileID, arg.Part) var i GetUploadPartSlotRow err := row.Scan(&i.ExistingBytes, &i.ObjectKey, &i.FileParts) return i, err } const getUploadPartUsage = `-- name: GetUploadPartUsage :one SELECT COALESCE(SUM(size), 0)::bigint AS bytes, COUNT(*)::int AS parts, COUNT(DISTINCT file_id)::int AS files FROM upload_parts WHERE owner_user_id = $1::bigint ` type GetUploadPartUsageRow struct { Bytes int64 Parts int32 Files int32 } func (q *Queries) GetUploadPartUsage(ctx context.Context, ownerUserID int64) (GetUploadPartUsageRow, error) { row := q.db.QueryRow(ctx, getUploadPartUsage, ownerUserID) var i GetUploadPartUsageRow err := row.Scan(&i.Bytes, &i.Parts, &i.Files) return i, err } const insertMediaReference = `-- name: InsertMediaReference :exec INSERT INTO media_references (media_kind, media_id, ref_kind, ref_key) VALUES ($1::text, $2::bigint, $3::text, $4::text) ON CONFLICT DO NOTHING ` type InsertMediaReferenceParams struct { MediaKind string MediaID int64 RefKind string RefKey string } // media_references / storage retention ----------------------------------------- func (q *Queries) InsertMediaReference(ctx context.Context, arg InsertMediaReferenceParams) error { _, err := q.db.Exec(ctx, insertMediaReference, arg.MediaKind, arg.MediaID, arg.RefKind, arg.RefKey, ) return err } const listAvailableReactions = `-- 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 ` func (q *Queries) ListAvailableReactions(ctx context.Context) ([]AvailableReaction, error) { rows, err := q.db.Query(ctx, listAvailableReactions) if err != nil { return nil, err } defer rows.Close() var items []AvailableReaction for rows.Next() { var i AvailableReaction if err := rows.Scan( &i.Reaction, &i.Title, &i.Inactive, &i.Premium, &i.StaticIconID, &i.AppearAnimationID, &i.SelectAnimationID, &i.ActivateAnimationID, &i.EffectAnimationID, &i.AroundAnimationID, &i.CenterIconID, &i.SortOrder, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listAvatarOrphanedPhotoIDsOlderThan = `-- name: ListAvatarOrphanedPhotoIDsOlderThan :many SELECT p.id FROM photos p WHERE p.orphaned_at IS NOT NULL AND p.orphaned_at < $1::timestamptz AND EXISTS (SELECT 1 FROM profile_photos pp WHERE pp.photo_id = p.id AND pp.active) ORDER BY p.orphaned_at ASC LIMIT $2::int ` type ListAvatarOrphanedPhotoIDsOlderThanParams struct { Cutoff pgtype.Timestamptz BatchLimit int32 } // Same as ListOrphanedPhotoIDsOlderThan but only photos currently active as // someone's avatar (profile_photos.active) -- lets the Avatar category carry // its own retention age. In practice a live avatar is never orphaned (an // active profile_photos row is itself a media_references entry), so this // bucket is expected to stay empty under "orphan" mode; kept for symmetry // with the "hard" mode avatar split, which is the one that actually matters. func (q *Queries) ListAvatarOrphanedPhotoIDsOlderThan(ctx context.Context, arg ListAvatarOrphanedPhotoIDsOlderThanParams) ([]int64, error) { rows, err := q.db.Query(ctx, listAvatarOrphanedPhotoIDsOlderThan, arg.Cutoff, arg.BatchLimit) if err != nil { return nil, err } defer rows.Close() var items []int64 for rows.Next() { var id int64 if err := rows.Scan(&id); err != nil { return nil, err } items = append(items, id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listAvatarPhotoIDsForHardRetentionOlderThan = `-- name: ListAvatarPhotoIDsForHardRetentionOlderThan :many SELECT p.id FROM photos p WHERE p.created_at < $1::timestamptz AND EXISTS (SELECT 1 FROM profile_photos pp WHERE pp.photo_id = p.id AND pp.active) AND EXISTS ( SELECT 1 FROM file_blobs fb WHERE fb.location_key = 'photo:' || p.id::text OR fb.location_key LIKE 'photo:' || p.id::text || ':%' ) ORDER BY p.created_at ASC LIMIT $2::int ` type ListAvatarPhotoIDsForHardRetentionOlderThanParams struct { Cutoff pgtype.Timestamptz BatchLimit int32 } // Same as ListPhotoIDsForHardRetentionOlderThan but only photos currently // active as someone's avatar (profile_photos.active) -- lets the Avatar // category carry its own retention age, independent of ordinary shared-media // photos. func (q *Queries) ListAvatarPhotoIDsForHardRetentionOlderThan(ctx context.Context, arg ListAvatarPhotoIDsForHardRetentionOlderThanParams) ([]int64, error) { rows, err := q.db.Query(ctx, listAvatarPhotoIDsForHardRetentionOlderThan, arg.Cutoff, arg.BatchLimit) if err != nil { return nil, err } defer rows.Close() var items []int64 for rows.Next() { var id int64 if err := rows.Scan(&id); err != nil { return nil, err } items = append(items, id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listDocumentIDsForHardRetentionOlderThan = `-- name: ListDocumentIDsForHardRetentionOlderThan :many SELECT d.id FROM documents d WHERE d.created_at < $1::timestamptz AND d.category = $2::smallint AND EXISTS ( SELECT 1 FROM file_blobs fb WHERE fb.location_key = 'doc:' || d.id::text OR fb.location_key LIKE 'doc:' || d.id::text || ':%' ) ORDER BY d.created_at ASC LIMIT $3::int ` type ListDocumentIDsForHardRetentionOlderThanParams struct { Cutoff pgtype.Timestamptz Category int16 BatchLimit int32 } // "Hard" retention mode: candidates are documents older than cutoff (by // upload/created_at, NOT orphaned_at -- a live reference does not exempt // them) that still own at least one file_blobs row. The EXISTS check is what // keeps this sweep from re-selecting the same document forever: once its // blob bytes are purged (DeleteFileBlobsForDocument removes the file_blobs // rows but deliberately leaves this documents row in place), it naturally // drops out of this query on the next pass. category scopes to one // documents.category bucket per sweep tick -- see // ListOrphanedDocumentIDsOlderThan for the 0/None fallback note. func (q *Queries) ListDocumentIDsForHardRetentionOlderThan(ctx context.Context, arg ListDocumentIDsForHardRetentionOlderThanParams) ([]int64, error) { rows, err := q.db.Query(ctx, listDocumentIDsForHardRetentionOlderThan, arg.Cutoff, arg.Category, arg.BatchLimit) if err != nil { return nil, err } defer rows.Close() var items []int64 for rows.Next() { var id int64 if err := rows.Scan(&id); err != nil { return nil, err } items = append(items, id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listFileBlobsByLocationPrefix = `-- name: ListFileBlobsByLocationPrefix :many SELECT location_key, backend, object_key, size FROM file_blobs WHERE location_key = $1::text OR location_key LIKE $2::text ` type ListFileBlobsByLocationPrefixParams struct { ExactKey string PrefixPattern string } type ListFileBlobsByLocationPrefixRow struct { LocationKey string Backend string ObjectKey string Size int64 } // Matches a media's main blob (exact_key, e.g. "doc:123") plus every // variant keyed off it (prefix_pattern, e.g. "doc:123:%" for thumbnails / // "photo:456:%" for each rendition size) -- a document/photo can own // multiple file_blobs rows. func (q *Queries) ListFileBlobsByLocationPrefix(ctx context.Context, arg ListFileBlobsByLocationPrefixParams) ([]ListFileBlobsByLocationPrefixRow, error) { rows, err := q.db.Query(ctx, listFileBlobsByLocationPrefix, arg.ExactKey, arg.PrefixPattern) if err != nil { return nil, err } defer rows.Close() var items []ListFileBlobsByLocationPrefixRow for rows.Next() { var i ListFileBlobsByLocationPrefixRow if err := rows.Scan( &i.LocationKey, &i.Backend, &i.ObjectKey, &i.Size, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listMediaReferences = `-- name: ListMediaReferences :many SELECT media_kind, media_id, ref_kind, ref_key FROM media_references WHERE media_kind = $1::text AND media_id = $2::bigint ` type ListMediaReferencesParams struct { MediaKind string MediaID int64 } type ListMediaReferencesRow struct { MediaKind string MediaID int64 RefKind string RefKey string } // Every live reference to a document/photo -- used by the storage retention // sweep to turn a hard-retention/eviction blob purge into a visible notice on // every message that still embeds the purged media (see // files.notifyRetentionPurge). profile_photo/sticker_set/gift refs have no // message to edit and are filtered by the caller, not this query. func (q *Queries) ListMediaReferences(ctx context.Context, arg ListMediaReferencesParams) ([]ListMediaReferencesRow, error) { rows, err := q.db.Query(ctx, listMediaReferences, arg.MediaKind, arg.MediaID) if err != nil { return nil, err } defer rows.Close() var items []ListMediaReferencesRow for rows.Next() { var i ListMediaReferencesRow if err := rows.Scan( &i.MediaKind, &i.MediaID, &i.RefKind, &i.RefKey, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listOldestDocumentsForEviction = `-- name: ListOldestDocumentsForEviction :many SELECT d.id, d.created_at FROM documents d WHERE EXISTS ( SELECT 1 FROM file_blobs fb WHERE fb.location_key = 'doc:' || d.id::text OR fb.location_key LIKE 'doc:' || d.id::text || ':%' ) ORDER BY d.created_at ASC LIMIT $1::int ` type ListOldestDocumentsForEvictionRow struct { ID int64 CreatedAt pgtype.Timestamptz } // Active eviction (TELESRV_STORAGE_EVICTION_ENABLE): candidates are every // document that still owns at least one file_blobs row, oldest-uploaded // first, REGARDLESS of category or age -- unlike the retention sweeps above, // eviction only cares about reclaiming bytes once the total physical budget // (TELESRV_STORAGE_MAX_TOTAL_BYTES) is exceeded. created_at is returned so // the caller can interleave these with ListOldestPhotosForEviction by actual // age instead of draining one table before touching the other. func (q *Queries) ListOldestDocumentsForEviction(ctx context.Context, batchLimit int32) ([]ListOldestDocumentsForEvictionRow, error) { rows, err := q.db.Query(ctx, listOldestDocumentsForEviction, batchLimit) if err != nil { return nil, err } defer rows.Close() var items []ListOldestDocumentsForEvictionRow for rows.Next() { var i ListOldestDocumentsForEvictionRow if err := rows.Scan(&i.ID, &i.CreatedAt); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listOldestPhotosForEviction = `-- name: ListOldestPhotosForEviction :many SELECT p.id, p.created_at FROM photos p WHERE EXISTS ( SELECT 1 FROM file_blobs fb WHERE fb.location_key = 'photo:' || p.id::text OR fb.location_key LIKE 'photo:' || p.id::text || ':%' ) ORDER BY p.created_at ASC LIMIT $1::int ` type ListOldestPhotosForEvictionRow struct { ID int64 CreatedAt pgtype.Timestamptz } // See ListOldestDocumentsForEviction -- same oldest-first eviction candidate // selection, for photos (avatars included: eviction is bytes-only and does // not honor the Avatar category's separate retention age). func (q *Queries) ListOldestPhotosForEviction(ctx context.Context, batchLimit int32) ([]ListOldestPhotosForEvictionRow, error) { rows, err := q.db.Query(ctx, listOldestPhotosForEviction, batchLimit) if err != nil { return nil, err } defer rows.Close() var items []ListOldestPhotosForEvictionRow for rows.Next() { var i ListOldestPhotosForEvictionRow if err := rows.Scan(&i.ID, &i.CreatedAt); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listOrphanedDocumentIDsOlderThan = `-- name: ListOrphanedDocumentIDsOlderThan :many SELECT id FROM documents WHERE orphaned_at IS NOT NULL AND orphaned_at < $1::timestamptz AND category = $2::smallint ORDER BY orphaned_at ASC LIMIT $3::int ` type ListOrphanedDocumentIDsOlderThanParams struct { Cutoff pgtype.Timestamptz Category int16 BatchLimit int32 } // category selects one documents.category bucket per sweep tick (per-category // retention age, see internal/app/files/retention.go) -- 0 (MediaCategoryNone) // covers unclassified documents (e.g. stickers), which always use the shared // global age since there is no per-category override for that bucket. func (q *Queries) ListOrphanedDocumentIDsOlderThan(ctx context.Context, arg ListOrphanedDocumentIDsOlderThanParams) ([]int64, error) { rows, err := q.db.Query(ctx, listOrphanedDocumentIDsOlderThan, arg.Cutoff, arg.Category, arg.BatchLimit) if err != nil { return nil, err } defer rows.Close() var items []int64 for rows.Next() { var id int64 if err := rows.Scan(&id); err != nil { return nil, err } items = append(items, id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listOrphanedPhotoIDsOlderThan = `-- name: ListOrphanedPhotoIDsOlderThan :many SELECT p.id FROM photos p WHERE p.orphaned_at IS NOT NULL AND p.orphaned_at < $1::timestamptz AND NOT EXISTS (SELECT 1 FROM profile_photos pp WHERE pp.photo_id = p.id AND pp.active) ORDER BY p.orphaned_at ASC LIMIT $2::int ` type ListOrphanedPhotoIDsOlderThanParams struct { Cutoff pgtype.Timestamptz BatchLimit int32 } // Excludes photos currently active as someone's avatar -- see // ListAvatarOrphanedPhotoIDsOlderThan for that split-off bucket. func (q *Queries) ListOrphanedPhotoIDsOlderThan(ctx context.Context, arg ListOrphanedPhotoIDsOlderThanParams) ([]int64, error) { rows, err := q.db.Query(ctx, listOrphanedPhotoIDsOlderThan, arg.Cutoff, arg.BatchLimit) if err != nil { return nil, err } defer rows.Close() var items []int64 for rows.Next() { var id int64 if err := rows.Scan(&id); err != nil { return nil, err } items = append(items, id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listPhotoIDsForHardRetentionOlderThan = `-- name: ListPhotoIDsForHardRetentionOlderThan :many SELECT p.id FROM photos p WHERE p.created_at < $1::timestamptz AND NOT EXISTS (SELECT 1 FROM profile_photos pp WHERE pp.photo_id = p.id AND pp.active) AND EXISTS ( SELECT 1 FROM file_blobs fb WHERE fb.location_key = 'photo:' || p.id::text OR fb.location_key LIKE 'photo:' || p.id::text || ':%' ) ORDER BY p.created_at ASC LIMIT $2::int ` type ListPhotoIDsForHardRetentionOlderThanParams struct { Cutoff pgtype.Timestamptz BatchLimit int32 } // See ListDocumentIDsForHardRetentionOlderThan -- same "hard" retention // candidate selection, for photos. Excludes photos currently active as // someone's avatar -- see ListAvatarPhotoIDsForHardRetentionOlderThan. func (q *Queries) ListPhotoIDsForHardRetentionOlderThan(ctx context.Context, arg ListPhotoIDsForHardRetentionOlderThanParams) ([]int64, error) { rows, err := q.db.Query(ctx, listPhotoIDsForHardRetentionOlderThan, arg.Cutoff, arg.BatchLimit) if err != nil { return nil, err } defer rows.Close() var items []int64 for rows.Next() { var id int64 if err := rows.Scan(&id); err != nil { return nil, err } items = append(items, id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listProfilePhotos = `-- name: ListProfilePhotos :many SELECT photo_id FROM profile_photos WHERE owner_peer_type = $1::text AND owner_peer_id = $2::bigint AND active AND ($3::bigint <= 0 OR photo_id < $3::bigint) ORDER BY sort_order DESC OFFSET $4::int LIMIT $5::int ` type ListProfilePhotosParams struct { OwnerPeerType string OwnerPeerID int64 MaxID int64 OffsetCount int32 LimitCount int32 } func (q *Queries) ListProfilePhotos(ctx context.Context, arg ListProfilePhotosParams) ([]int64, error) { rows, err := q.db.Query(ctx, listProfilePhotos, arg.OwnerPeerType, arg.OwnerPeerID, arg.MaxID, arg.OffsetCount, arg.LimitCount, ) if err != nil { return nil, err } defer rows.Close() var items []int64 for rows.Next() { var photo_id int64 if err := rows.Scan(&photo_id); err != nil { return nil, err } items = append(items, photo_id) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listStickerSetsByKind = `-- 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 = $1::text ORDER BY sort_order ASC, id ASC ` type ListStickerSetsByKindRow struct { ID int64 AccessHash int64 ShortName string Title string Count int32 Hash int32 SetKind string Official bool Animated bool Videos bool Emojis bool Masks bool Installed bool Archived bool InstalledDate int32 ThumbDocumentID int64 ThumbsJson string ThumbDcID int32 ThumbVersion int32 DocumentIdsJson string PacksJson string SortOrder int32 SystemKey string } func (q *Queries) ListStickerSetsByKind(ctx context.Context, setKind string) ([]ListStickerSetsByKindRow, error) { rows, err := q.db.Query(ctx, listStickerSetsByKind, setKind) if err != nil { return nil, err } defer rows.Close() var items []ListStickerSetsByKindRow for rows.Next() { var i ListStickerSetsByKindRow if err := rows.Scan( &i.ID, &i.AccessHash, &i.ShortName, &i.Title, &i.Count, &i.Hash, &i.SetKind, &i.Official, &i.Animated, &i.Videos, &i.Emojis, &i.Masks, &i.Installed, &i.Archived, &i.InstalledDate, &i.ThumbDocumentID, &i.ThumbsJson, &i.ThumbDcID, &i.ThumbVersion, &i.DocumentIdsJson, &i.PacksJson, &i.SortOrder, &i.SystemKey, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const listUploadParts = `-- name: ListUploadParts :many SELECT part, total_parts, is_big, backend, object_key, size, sha256 FROM upload_parts WHERE owner_user_id = $1::bigint AND file_id = $2::bigint ORDER BY part ASC ` type ListUploadPartsParams struct { OwnerUserID int64 FileID int64 } type ListUploadPartsRow struct { Part int32 TotalParts int32 IsBig bool Backend string ObjectKey string Size int64 Sha256 []byte } func (q *Queries) ListUploadParts(ctx context.Context, arg ListUploadPartsParams) ([]ListUploadPartsRow, error) { rows, err := q.db.Query(ctx, listUploadParts, arg.OwnerUserID, arg.FileID) if err != nil { return nil, err } defer rows.Close() var items []ListUploadPartsRow for rows.Next() { var i ListUploadPartsRow if err := rows.Scan( &i.Part, &i.TotalParts, &i.IsBig, &i.Backend, &i.ObjectKey, &i.Size, &i.Sha256, ); err != nil { return nil, err } items = append(items, i) } if err := rows.Err(); err != nil { return nil, err } return items, nil } const nextProfilePhotoOrder = `-- name: NextProfilePhotoOrder :one SELECT COALESCE(MAX(sort_order), 0)::bigint AS max_order FROM profile_photos WHERE owner_peer_type = $1::text AND owner_peer_id = $2::bigint ` type NextProfilePhotoOrderParams struct { OwnerPeerType string OwnerPeerID int64 } func (q *Queries) NextProfilePhotoOrder(ctx context.Context, arg NextProfilePhotoOrderParams) (int64, error) { row := q.db.QueryRow(ctx, nextProfilePhotoOrder, arg.OwnerPeerType, arg.OwnerPeerID) var max_order int64 err := row.Scan(&max_order) return max_order, err } const orphanDocumentIfUnreferenced = `-- name: OrphanDocumentIfUnreferenced :exec UPDATE documents SET orphaned_at = now() WHERE id = $1::bigint AND orphaned_at IS NULL AND NOT EXISTS ( SELECT 1 FROM media_references WHERE media_kind = 'document' AND media_id = $1::bigint ) ` func (q *Queries) OrphanDocumentIfUnreferenced(ctx context.Context, mediaID int64) error { _, err := q.db.Exec(ctx, orphanDocumentIfUnreferenced, mediaID) return err } const orphanPhotoIfUnreferenced = `-- name: OrphanPhotoIfUnreferenced :exec UPDATE photos SET orphaned_at = now() WHERE id = $1::bigint AND orphaned_at IS NULL AND NOT EXISTS ( SELECT 1 FROM media_references WHERE media_kind = 'photo' AND media_id = $1::bigint ) ` func (q *Queries) OrphanPhotoIfUnreferenced(ctx context.Context, mediaID int64) error { _, err := q.db.Exec(ctx, orphanPhotoIfUnreferenced, mediaID) return err } const putAvailableReaction = `-- 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 ( $1::text, $2::text, $3::boolean, $4::boolean, $5::bigint, $6::bigint, $7::bigint, $8::bigint, $9::bigint, $10::bigint, $11::bigint, $12::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 ` type PutAvailableReactionParams struct { Reaction string Title string Inactive bool Premium bool StaticIconID int64 AppearAnimationID int64 SelectAnimationID int64 ActivateAnimationID int64 EffectAnimationID int64 AroundAnimationID int64 CenterIconID int64 SortOrder int32 } // available_reactions --------------------------------------------------------- func (q *Queries) PutAvailableReaction(ctx context.Context, arg PutAvailableReactionParams) error { _, err := q.db.Exec(ctx, putAvailableReaction, arg.Reaction, arg.Title, arg.Inactive, arg.Premium, arg.StaticIconID, arg.AppearAnimationID, arg.SelectAnimationID, arg.ActivateAnimationID, arg.EffectAnimationID, arg.AroundAnimationID, arg.CenterIconID, arg.SortOrder, ) return err } const putDocument = `-- name: PutDocument :exec INSERT INTO documents (id, access_hash, file_reference, date, mime_type, size, dc_id, attributes, thumbs, owner_user_id) VALUES ( $1::bigint, $2::bigint, $3::bytea, $4::int, $5::text, $6::bigint, $7::int, $8::jsonb, $9::jsonb, $10::bigint ) 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 ` type PutDocumentParams struct { ID int64 AccessHash int64 FileReference []byte Date int32 MimeType string Size int64 DcID int32 AttributesJson []byte ThumbsJson []byte OwnerUserID int64 } // documents ------------------------------------------------------------------- // owner_user_id is intentionally NOT in the UPDATE SET list: a document id is // only ever (re-)upserted by its original uploader's own request replay, and // keeping the first-write owner sticky avoids any risk of a later call // (e.g. a forward re-touching the row) reassigning ownership. func (q *Queries) PutDocument(ctx context.Context, arg PutDocumentParams) error { _, err := q.db.Exec(ctx, putDocument, arg.ID, arg.AccessHash, arg.FileReference, arg.Date, arg.MimeType, arg.Size, arg.DcID, arg.AttributesJson, arg.ThumbsJson, arg.OwnerUserID, ) return err } const putFileBlob = `-- name: PutFileBlob :exec INSERT INTO file_blobs (location_key, backend, object_key, size, sha256, mime_type) VALUES ( $1::text, $2::text, $3::text, $4::bigint, $5::bytea, $6::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 ` type PutFileBlobParams struct { LocationKey string Backend string ObjectKey string Size int64 Sha256 []byte MimeType string } // file_blobs ------------------------------------------------------------------ func (q *Queries) PutFileBlob(ctx context.Context, arg PutFileBlobParams) error { _, err := q.db.Exec(ctx, putFileBlob, arg.LocationKey, arg.Backend, arg.ObjectKey, arg.Size, arg.Sha256, arg.MimeType, ) return err } const putPhoto = `-- name: PutPhoto :exec INSERT INTO photos (id, access_hash, file_reference, date, dc_id, has_stickers, sizes, owner_user_id) VALUES ( $1::bigint, $2::bigint, $3::bytea, $4::int, $5::int, $6::boolean, $7::jsonb, $8::bigint ) 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 ` type PutPhotoParams struct { ID int64 AccessHash int64 FileReference []byte Date int32 DcID int32 HasStickers bool SizesJson []byte OwnerUserID int64 } // photos ---------------------------------------------------------------------- // owner_user_id intentionally not updated on conflict, see PutDocument. func (q *Queries) PutPhoto(ctx context.Context, arg PutPhotoParams) error { _, err := q.db.Exec(ctx, putPhoto, arg.ID, arg.AccessHash, arg.FileReference, arg.Date, arg.DcID, arg.HasStickers, arg.SizesJson, arg.OwnerUserID, ) return err } const putStickerSet = `-- 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 ( $1::bigint, $2::bigint, $3::text, $4::text, $5::int, $6::int, $7::text, $8::boolean, $9::boolean, $10::boolean, $11::boolean, $12::boolean, $13::boolean, $14::boolean, $15::int, $16::bigint, $17::jsonb, $18::int, $19::int, $20::jsonb, $21::jsonb, $22::int, $23::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 ` type PutStickerSetParams struct { ID int64 AccessHash int64 ShortName string Title string Count int32 Hash int32 SetKind string Official bool Animated bool Videos bool Emojis bool Masks bool Installed bool Archived bool InstalledDate int32 ThumbDocumentID int64 ThumbsJson []byte ThumbDcID int32 ThumbVersion int32 DocumentIdsJson []byte PacksJson []byte SortOrder int32 SystemKey string } // sticker_sets ---------------------------------------------------------------- func (q *Queries) PutStickerSet(ctx context.Context, arg PutStickerSetParams) error { _, err := q.db.Exec(ctx, putStickerSet, arg.ID, arg.AccessHash, arg.ShortName, arg.Title, arg.Count, arg.Hash, arg.SetKind, arg.Official, arg.Animated, arg.Videos, arg.Emojis, arg.Masks, arg.Installed, arg.Archived, arg.InstalledDate, arg.ThumbDocumentID, arg.ThumbsJson, arg.ThumbDcID, arg.ThumbVersion, arg.DocumentIdsJson, arg.PacksJson, arg.SortOrder, arg.SystemKey, ) return err } const removeMediaReference = `-- name: RemoveMediaReference :exec DELETE FROM media_references WHERE media_kind = $1::text AND media_id = $2::bigint AND ref_kind = $3::text AND ref_key = $4::text ` type RemoveMediaReferenceParams struct { MediaKind string MediaID int64 RefKind string RefKey string } func (q *Queries) RemoveMediaReference(ctx context.Context, arg RemoveMediaReferenceParams) error { _, err := q.db.Exec(ctx, removeMediaReference, arg.MediaKind, arg.MediaID, arg.RefKind, arg.RefKey, ) return err } const saveUploadPart = `-- name: SaveUploadPart :exec INSERT INTO upload_parts (owner_user_id, file_id, part, total_parts, is_big, backend, object_key, size, sha256) VALUES ( $1::bigint, $2::bigint, $3::int, $4::int, $5::boolean, $6::text, $7::text, $8::bigint, $9::bytea ) ON CONFLICT (owner_user_id, file_id, part) DO UPDATE SET total_parts = EXCLUDED.total_parts, is_big = EXCLUDED.is_big, backend = EXCLUDED.backend, object_key = EXCLUDED.object_key, size = EXCLUDED.size, sha256 = EXCLUDED.sha256, created_at = now() ` type SaveUploadPartParams struct { OwnerUserID int64 FileID int64 Part int32 TotalParts int32 IsBig bool Backend string ObjectKey string Size int64 Sha256 []byte } // upload_parts ---------------------------------------------------------------- func (q *Queries) SaveUploadPart(ctx context.Context, arg SaveUploadPartParams) error { _, err := q.db.Exec(ctx, saveUploadPart, arg.OwnerUserID, arg.FileID, arg.Part, arg.TotalParts, arg.IsBig, arg.Backend, arg.ObjectKey, arg.Size, arg.Sha256, ) return err } const sumFileBlobBytes = `-- name: SumFileBlobBytes :one SELECT COALESCE(SUM(size), 0)::bigint FROM file_blobs ` // Physical bytes actually held by the blob backend (dedup-aware: identical // content uploaded by different users is one row here). Used by the // low-space guard's cached usage gauge and the admin panel's "physical // usage" stat. func (q *Queries) SumFileBlobBytes(ctx context.Context) (int64, error) { row := q.db.QueryRow(ctx, sumFileBlobBytes) var column_1 int64 err := row.Scan(&column_1) return column_1, err }