textmachine/platform/internal/pgstore/sessions.sql.go

149 lines
4.5 KiB
Go

// Code generated by sqlc. DO NOT EDIT.
// versions:
// sqlc v1.31.1
// source: sessions.sql
package pgstore
import (
"context"
"time"
)
const createSession = `-- name: CreateSession :exec
insert into sessions (token_sha256, user_id, created_at, last_used_at, idle_expires_at, absolute_expires_at)
values ($1, $2, $3, $3,
$4, $5)
`
type CreateSessionParams struct {
TokenSha256 []byte
UserID string
Now time.Time
IdleExpiresAt time.Time
AbsoluteExpiresAt time.Time
}
func (q *Queries) CreateSession(ctx context.Context, arg CreateSessionParams) error {
_, err := q.db.Exec(ctx, createSession,
arg.TokenSha256,
arg.UserID,
arg.Now,
arg.IdleExpiresAt,
arg.AbsoluteExpiresAt,
)
return err
}
const lookupSession = `-- name: LookupSession :one
select user_id, idle_expires_at, absolute_expires_at
from sessions
where token_sha256 = $1
and revoked_at is null
and idle_expires_at > $2
and absolute_expires_at > $2
`
type LookupSessionParams struct {
TokenSha256 []byte
Now time.Time
}
type LookupSessionRow struct {
UserID string
IdleExpiresAt time.Time
AbsoluteExpiresAt time.Time
}
// Sessions. Parameters are NAMED with sqlc.arg rather than left as $n, so that the generated params
// struct carries field names: two adjacent time.Time arguments at a call site are exactly the shape
// that transposes silently, and a named field is the cheapest defence against it.
// Expiry and revocation are clauses of THIS query, not checks a caller could forget: a row that
// comes back is live by construction.
func (q *Queries) LookupSession(ctx context.Context, arg LookupSessionParams) (LookupSessionRow, error) {
row := q.db.QueryRow(ctx, lookupSession, arg.TokenSha256, arg.Now)
var i LookupSessionRow
err := row.Scan(&i.UserID, &i.IdleExpiresAt, &i.AbsoluteExpiresAt)
return i, err
}
const revokeSession = `-- name: RevokeSession :exec
update sessions set revoked_at = $1::timestamptz
where token_sha256 = $2 and revoked_at is null
`
type RevokeSessionParams struct {
Now time.Time
TokenSha256 []byte
}
// The cast is not decoration: revoked_at is NULLABLE, so without it sqlc types the parameter from
// the column and hands the caller a *time.Time for a value that is never absent.
func (q *Queries) RevokeSession(ctx context.Context, arg RevokeSessionParams) error {
_, err := q.db.Exec(ctx, revokeSession, arg.Now, arg.TokenSha256)
return err
}
const sessionStillLive = `-- name: SessionStillLive :one
select 1
from sessions
where token_sha256 = $1
and revoked_at is null
and absolute_expires_at > $2
`
type SessionStillLiveParams struct {
TokenSha256 []byte
Now time.Time
}
// ⚠ THE IDLE CLAUSE IS DELIBERATELY ABSENT. The idle window slides on a REQUEST, and the event
// stream is ONE request that lives for hours, so a stream cannot slide its own window and asking the
// idle question here would end the stream of a user who is sitting and watching it.
func (q *Queries) SessionStillLive(ctx context.Context, arg SessionStillLiveParams) (int32, error) {
row := q.db.QueryRow(ctx, sessionStillLive, arg.TokenSha256, arg.Now)
var column_1 int32
err := row.Scan(&column_1)
return column_1, err
}
const sweepSessions = `-- name: SweepSessions :execrows
delete from sessions
where absolute_expires_at <= $1
or idle_expires_at <= $1
or revoked_at is not null
`
// Deletes rows nothing can authenticate with again: past either expiry, or revoked. A revoked row is
// the one a compromised account most wants gone. The audit lives in the login journal, not here.
func (q *Queries) SweepSessions(ctx context.Context, now time.Time) (int64, error) {
result, err := q.db.Exec(ctx, sweepSessions, now)
if err != nil {
return 0, err
}
return result.RowsAffected(), nil
}
const touchSession = `-- name: TouchSession :exec
update sessions
set last_used_at = $1,
idle_expires_at = least($2::timestamptz, absolute_expires_at)
where token_sha256 = $3
and revoked_at is null
and idle_expires_at > $1
and absolute_expires_at > $1
`
type TouchSessionParams struct {
Now time.Time
IdleDeadline time.Time
TokenSha256 []byte
}
// Slides the idle window and never moves the absolute expiry — that is the point of having two
// clocks. Its WHERE matches LookupSession's, idle clause included (PD-4).
func (q *Queries) TouchSession(ctx context.Context, arg TouchSessionParams) error {
_, err := q.db.Exec(ctx, touchSession, arg.Now, arg.IdleDeadline, arg.TokenSha256)
return err
}