// Code generated by sqlc. DO NOT EDIT.
// versions:
//   sqlc v1.29.0
// source: ticker.sql

package sqlcv1

import (
	"context"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5/pgtype"
)

const createTicker = `-- name: CreateTicker :one
INSERT INTO
    "Ticker" ("id", "lastHeartbeatAt", "isActive")
VALUES
    ($1::uuid, CURRENT_TIMESTAMP, 't')
RETURNING id, "createdAt", "updatedAt", "lastHeartbeatAt", "isActive"
`

func (q *Queries) CreateTicker(ctx context.Context, db DBTX, id uuid.UUID) (*Ticker, error) {
	row := db.QueryRow(ctx, createTicker, id)
	var i Ticker
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeatAt,
		&i.IsActive,
	)
	return &i, err
}

const deactivateTicker = `-- name: DeactivateTicker :one
UPDATE
    "Ticker" t
SET
    "isActive" = false
WHERE
    "id" = $1::uuid
RETURNING id, "createdAt", "updatedAt", "lastHeartbeatAt", "isActive"
`

func (q *Queries) DeactivateTicker(ctx context.Context, db DBTX, id uuid.UUID) (*Ticker, error) {
	row := db.QueryRow(ctx, deactivateTicker, id)
	var i Ticker
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeatAt,
		&i.IsActive,
	)
	return &i, err
}

const isTenantAlertActive = `-- name: IsTenantAlertActive :one
WITH active_setting AS (
    SELECT
        1
    FROM
        "TenantAlertingSettings" as alerts
    WHERE
        "tenantId" = $1::uuid AND
        (
            "lastAlertedAt" IS NULL OR
            "lastAlertedAt" <= NOW() - convert_duration_to_interval(alerts."maxFrequency")
        ) AND
        "enableWorkflowRunFailureAlerts" = true
)
SELECT
    EXISTS (
        select 1 from active_setting
    ) as "isActive",
    "lastAlertedAt" as "lastAlertedAt"
FROM
    "TenantAlertingSettings" as alerts
WHERE
    "tenantId" = $1::uuid
`

type IsTenantAlertActiveRow struct {
	IsActive      bool             `json:"isActive"`
	LastAlertedAt pgtype.Timestamp `json:"lastAlertedAt"`
}

func (q *Queries) IsTenantAlertActive(ctx context.Context, db DBTX, tenantid uuid.UUID) (*IsTenantAlertActiveRow, error) {
	row := db.QueryRow(ctx, isTenantAlertActive, tenantid)
	var i IsTenantAlertActiveRow
	err := row.Scan(&i.IsActive, &i.LastAlertedAt)
	return &i, err
}

const listActiveTickers = `-- name: ListActiveTickers :many
SELECT
    tickers.id, tickers."createdAt", tickers."updatedAt", tickers."lastHeartbeatAt", tickers."isActive"
FROM "Ticker" as tickers
WHERE
    -- last heartbeat greater than 15 seconds
    "lastHeartbeatAt" > NOW () - INTERVAL '15 seconds'
    -- active
    AND "isActive" = true
`

type ListActiveTickersRow struct {
	Ticker Ticker `json:"ticker"`
}

func (q *Queries) ListActiveTickers(ctx context.Context, db DBTX) ([]*ListActiveTickersRow, error) {
	rows, err := db.Query(ctx, listActiveTickers)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*ListActiveTickersRow
	for rows.Next() {
		var i ListActiveTickersRow
		if err := rows.Scan(
			&i.Ticker.ID,
			&i.Ticker.CreatedAt,
			&i.Ticker.UpdatedAt,
			&i.Ticker.LastHeartbeatAt,
			&i.Ticker.IsActive,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listNewlyStaleTickers = `-- name: ListNewlyStaleTickers :many
SELECT
    tickers.id, tickers."createdAt", tickers."updatedAt", tickers."lastHeartbeatAt", tickers."isActive"
FROM "Ticker" as tickers
WHERE
    -- last heartbeat older than 15 seconds
    "lastHeartbeatAt" < NOW () - INTERVAL '15 seconds'
    -- active
    AND "isActive" = true
`

type ListNewlyStaleTickersRow struct {
	Ticker Ticker `json:"ticker"`
}

func (q *Queries) ListNewlyStaleTickers(ctx context.Context, db DBTX) ([]*ListNewlyStaleTickersRow, error) {
	rows, err := db.Query(ctx, listNewlyStaleTickers)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*ListNewlyStaleTickersRow
	for rows.Next() {
		var i ListNewlyStaleTickersRow
		if err := rows.Scan(
			&i.Ticker.ID,
			&i.Ticker.CreatedAt,
			&i.Ticker.UpdatedAt,
			&i.Ticker.LastHeartbeatAt,
			&i.Ticker.IsActive,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const listTickers = `-- name: ListTickers :many
SELECT
    id, "createdAt", "updatedAt", "lastHeartbeatAt", "isActive"
FROM
    "Ticker" as tickers
WHERE
    (
        $1::boolean IS NULL OR
        "isActive" = $1::boolean
    )
    AND
    (
        $2::timestamp IS NULL OR
        tickers."lastHeartbeatAt" > $2::timestamp
    )
`

type ListTickersParams struct {
	IsActive           bool             `json:"isActive"`
	LastHeartbeatAfter pgtype.Timestamp `json:"lastHeartbeatAfter"`
}

func (q *Queries) ListTickers(ctx context.Context, db DBTX, arg ListTickersParams) ([]*Ticker, error) {
	rows, err := db.Query(ctx, listTickers, arg.IsActive, arg.LastHeartbeatAfter)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*Ticker
	for rows.Next() {
		var i Ticker
		if err := rows.Scan(
			&i.ID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.LastHeartbeatAt,
			&i.IsActive,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const pollCronSchedules = `-- name: PollCronSchedules :many
WITH eligible_cron_with_versions AS MATERIALIZED (
    SELECT
        cronSchedule."parentId",
        cronSchedule."cron",
        cronSchedule."name",
        triggers."workflowVersionId",
        triggers."tenantId",
        versions."workflowId",
        versions."order"
    FROM
        "WorkflowTriggerCronRef" as cronSchedule
    JOIN
        "WorkflowTriggers" as triggers ON triggers."id" = cronSchedule."parentId"
    JOIN
        "WorkflowVersion" as versions ON versions."id" = triggers."workflowVersionId"
    JOIN
        "Tenant" as tenant ON tenant."id" = triggers."tenantId"
    WHERE cronSchedule."enabled" = TRUE
        AND versions."deletedAt" IS NULL
        AND tenant."deletedAt" IS NULL
        AND (
            cronSchedule."tickerId" IS NULL
            OR NOT EXISTS (
                SELECT 1 FROM "Ticker" WHERE "id" = cronSchedule."tickerId" AND "isActive" = true AND "lastHeartbeatAt" >= NOW() - INTERVAL '10 seconds'
            )
            OR cronSchedule."tickerId" = $1::uuid
        )
    FOR UPDATE OF cronSchedule SKIP LOCKED
),
latest_workflow_versions AS (
    SELECT
        DISTINCT ON ("workflowId")
        "workflowId",
        "id"
    FROM
        "WorkflowVersion"
    WHERE
        "deletedAt" IS NULL
    ORDER BY "workflowId", "order" DESC
),
eligible_cron_schedules AS (
    SELECT
        ecv."parentId",
        ecv."cron",
        ecv."name",
        ecv."workflowVersionId",
        ecv."tenantId"
    FROM
        eligible_cron_with_versions as ecv
    JOIN
        latest_workflow_versions as l ON ecv."workflowId" = l."workflowId" AND ecv."workflowVersionId" = l."id"
)
UPDATE
    "WorkflowTriggerCronRef" as cronSchedules
SET
    "tickerId" = $1::uuid
FROM
    eligible_cron_schedules
WHERE
    cronSchedules."parentId" = eligible_cron_schedules."parentId"
    AND cronSchedules."cron" = eligible_cron_schedules."cron"
    AND cronSchedules."name" = eligible_cron_schedules."name"

RETURNING cronschedules."parentId", cronschedules.cron, cronschedules."tickerId", cronschedules.input, cronschedules.enabled, cronschedules."additionalMetadata", cronschedules."createdAt", cronschedules."deletedAt", cronschedules."updatedAt", cronschedules.name, cronschedules.id, cronschedules.method, cronschedules.priority, eligible_cron_schedules."workflowVersionId", eligible_cron_schedules."tenantId"
`

type PollCronSchedulesRow struct {
	ParentId           uuid.UUID                     `json:"parentId"`
	Cron               string                        `json:"cron"`
	TickerId           *uuid.UUID                    `json:"tickerId"`
	Input              []byte                        `json:"input"`
	Enabled            bool                          `json:"enabled"`
	AdditionalMetadata []byte                        `json:"additionalMetadata"`
	CreatedAt          pgtype.Timestamp              `json:"createdAt"`
	DeletedAt          pgtype.Timestamp              `json:"deletedAt"`
	UpdatedAt          pgtype.Timestamp              `json:"updatedAt"`
	Name               pgtype.Text                   `json:"name"`
	ID                 uuid.UUID                     `json:"id"`
	Method             WorkflowTriggerCronRefMethods `json:"method"`
	Priority           int32                         `json:"priority"`
	WorkflowVersionId  uuid.UUID                     `json:"workflowVersionId"`
	TenantId           uuid.UUID                     `json:"tenantId"`
}

func (q *Queries) PollCronSchedules(ctx context.Context, db DBTX, tickerid uuid.UUID) ([]*PollCronSchedulesRow, error) {
	rows, err := db.Query(ctx, pollCronSchedules, tickerid)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*PollCronSchedulesRow
	for rows.Next() {
		var i PollCronSchedulesRow
		if err := rows.Scan(
			&i.ParentId,
			&i.Cron,
			&i.TickerId,
			&i.Input,
			&i.Enabled,
			&i.AdditionalMetadata,
			&i.CreatedAt,
			&i.DeletedAt,
			&i.UpdatedAt,
			&i.Name,
			&i.ID,
			&i.Method,
			&i.Priority,
			&i.WorkflowVersionId,
			&i.TenantId,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const pollExpiringTokens = `-- name: PollExpiringTokens :many
WITH expiring_tokens AS (
    SELECT
        t0."id", t0."name", t0."expiresAt"
    FROM
        "APIToken" as t0
    JOIN
        "Tenant" as tenant ON tenant."id" = t0."tenantId"
    WHERE
        tenant."deletedAt" IS NULL
        AND t0."revoked" = false
        AND t0."expiresAt" <= NOW() + INTERVAL '7 days'
        AND t0."expiresAt" >= NOW()
        AND (
            t0."nextAlertAt" IS NULL OR
            t0."nextAlertAt" <= NOW()
        )
        AND t0."internal" = false
    FOR UPDATE SKIP LOCKED
    LIMIT 100
)
UPDATE
    "APIToken" as t1
SET
    "nextAlertAt" = NOW() + INTERVAL '1 day'
FROM
    expiring_tokens
WHERE
    t1."id" = expiring_tokens."id"
RETURNING
    t1."id",
    t1."name",
    t1."tenantId",
    t1."expiresAt"
`

type PollExpiringTokensRow struct {
	ID        uuid.UUID        `json:"id"`
	Name      pgtype.Text      `json:"name"`
	TenantId  *uuid.UUID       `json:"tenantId"`
	ExpiresAt pgtype.Timestamp `json:"expiresAt"`
}

func (q *Queries) PollExpiringTokens(ctx context.Context, db DBTX) ([]*PollExpiringTokensRow, error) {
	rows, err := db.Query(ctx, pollExpiringTokens)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*PollExpiringTokensRow
	for rows.Next() {
		var i PollExpiringTokensRow
		if err := rows.Scan(
			&i.ID,
			&i.Name,
			&i.TenantId,
			&i.ExpiresAt,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const pollScheduledWorkflows = `-- name: PollScheduledWorkflows :many
WITH latest_workflow_versions AS (
    SELECT
        DISTINCT ON("workflowId")
        "workflowId",
        "id"
    FROM
        "WorkflowVersion"
    WHERE
        "deletedAt" IS NULL
    ORDER BY "workflowId", "order" DESC
), not_run_scheduled_workflows AS (
    SELECT
        scheduledWorkflow."id",
        latestVersions."id" AS "workflowVersionId",
        workflow."tenantId" AS "tenantId",
        scheduledWorkflow."additionalMetadata" AS "additionalMetadata"
    FROM
        "WorkflowTriggerScheduledRef" AS scheduledWorkflow
    JOIN
        "WorkflowVersion" AS versions ON versions."id" = scheduledWorkflow."parentId"
    JOIN
        "Workflow" AS workflow ON workflow."id" = versions."workflowId"
    JOIN
        "Tenant" AS tenant ON tenant."id" = workflow."tenantId"
    JOIN
        latest_workflow_versions AS latestVersions ON latestVersions."workflowId" = workflow."id"
    WHERE
        "triggerAt" <= NOW() + INTERVAL '5 seconds'
        AND versions."deletedAt" IS NULL
        AND workflow."deletedAt" IS NULL
        AND tenant."deletedAt" IS NULL
        AND (
            "tickerId" IS NULL
            OR NOT EXISTS (
                SELECT 1 FROM "Ticker" WHERE "id" = scheduledWorkflow."tickerId" AND "isActive" = true AND "lastHeartbeatAt" >= NOW() - INTERVAL '10 seconds'
            )
            OR "tickerId" = $1::uuid
        )
        AND NOT EXISTS (
            SELECT 1
            FROM "WorkflowRunTriggeredBy" AS runTriggeredBy
            WHERE runTriggeredBy."scheduledId" = scheduledWorkflow."id"
        )
    ORDER BY scheduledWorkflow."triggerAt" ASC, scheduledWorkflow."id" ASC
),
active_scheduled_workflows AS (
    SELECT
        id, "parentId", "triggerAt", "tickerId", input, "childIndex", "childKey", "parentStepRunId", "parentWorkflowRunId", "additionalMetadata", "createdAt", "deletedAt", "updatedAt", method, priority
    FROM
        "WorkflowTriggerScheduledRef"
    WHERE "id" IN (SELECT "id" FROM not_run_scheduled_workflows)
    ORDER BY "triggerAt" ASC, "id" ASC
    FOR UPDATE SKIP LOCKED
)

UPDATE
    "WorkflowTriggerScheduledRef" as scheduledWorkflows
SET
    "tickerId" = $1::uuid
FROM
    active_scheduled_workflows
JOIN "WorkflowVersion" as versions ON versions."id" = active_scheduled_workflows."parentId"
JOIN "Workflow" as workflow ON workflow."id" = versions."workflowId"
WHERE
    scheduledWorkflows."id" = active_scheduled_workflows."id"
RETURNING scheduledworkflows.id, scheduledworkflows."parentId", scheduledworkflows."triggerAt", scheduledworkflows."tickerId", scheduledworkflows.input, scheduledworkflows."childIndex", scheduledworkflows."childKey", scheduledworkflows."parentStepRunId", scheduledworkflows."parentWorkflowRunId", scheduledworkflows."additionalMetadata", scheduledworkflows."createdAt", scheduledworkflows."deletedAt", scheduledworkflows."updatedAt", scheduledworkflows.method, scheduledworkflows.priority, versions."id" AS "workflowVersionId", workflow."tenantId"
`

type PollScheduledWorkflowsRow struct {
	ID                  uuid.UUID                          `json:"id"`
	ParentId            uuid.UUID                          `json:"parentId"`
	TriggerAt           pgtype.Timestamp                   `json:"triggerAt"`
	TickerId            *uuid.UUID                         `json:"tickerId"`
	Input               []byte                             `json:"input"`
	ChildIndex          pgtype.Int4                        `json:"childIndex"`
	ChildKey            pgtype.Text                        `json:"childKey"`
	ParentStepRunId     *uuid.UUID                         `json:"parentStepRunId"`
	ParentWorkflowRunId *uuid.UUID                         `json:"parentWorkflowRunId"`
	AdditionalMetadata  []byte                             `json:"additionalMetadata"`
	CreatedAt           pgtype.Timestamp                   `json:"createdAt"`
	DeletedAt           pgtype.Timestamp                   `json:"deletedAt"`
	UpdatedAt           pgtype.Timestamp                   `json:"updatedAt"`
	Method              WorkflowTriggerScheduledRefMethods `json:"method"`
	Priority            int32                              `json:"priority"`
	WorkflowVersionId   uuid.UUID                          `json:"workflowVersionId"`
	TenantId            uuid.UUID                          `json:"tenantId"`
}

// Finds workflows that are either past their execution time or will be in the next 5 seconds and assigns them
// to a ticker, or finds workflows that were assigned to a ticker that is no longer active
func (q *Queries) PollScheduledWorkflows(ctx context.Context, db DBTX, tickerid uuid.UUID) ([]*PollScheduledWorkflowsRow, error) {
	rows, err := db.Query(ctx, pollScheduledWorkflows, tickerid)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*PollScheduledWorkflowsRow
	for rows.Next() {
		var i PollScheduledWorkflowsRow
		if err := rows.Scan(
			&i.ID,
			&i.ParentId,
			&i.TriggerAt,
			&i.TickerId,
			&i.Input,
			&i.ChildIndex,
			&i.ChildKey,
			&i.ParentStepRunId,
			&i.ParentWorkflowRunId,
			&i.AdditionalMetadata,
			&i.CreatedAt,
			&i.DeletedAt,
			&i.UpdatedAt,
			&i.Method,
			&i.Priority,
			&i.WorkflowVersionId,
			&i.TenantId,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const pollTenantAlerts = `-- name: PollTenantAlerts :many
WITH active_tenant_alerts AS (
    SELECT
        alerts.id, alerts."createdAt", alerts."updatedAt", alerts."deletedAt", alerts."tenantId", alerts."maxFrequency", alerts."lastAlertedAt", alerts."tickerId", alerts."enableExpiringTokenAlerts", alerts."enableWorkflowRunFailureAlerts", alerts."enableTenantResourceLimitAlerts"
    FROM
        "TenantAlertingSettings" as alerts
    JOIN
        "Tenant" as tenant ON tenant."id" = alerts."tenantId"
    WHERE
        tenant."deletedAt" IS NULL
        AND (
            "lastAlertedAt" IS NULL OR
            "lastAlertedAt" <= NOW() - convert_duration_to_interval(alerts."maxFrequency")
        )
    FOR UPDATE SKIP LOCKED
),
failed_run_count_by_tenant AS (
    SELECT
        workflowRun."tenantId",
        COUNT(*) as "failedWorkflowRunCount"
    FROM
        "WorkflowRun" as workflowRun
    JOIN
        active_tenant_alerts ON active_tenant_alerts."tenantId" = workflowRun."tenantId"
    WHERE
        "status" = 'FAILED'
        AND workflowRun."deletedAt" IS NULL
        AND (
            (
                "lastAlertedAt" IS NULL AND
                workflowRun."finishedAt" >= NOW() - convert_duration_to_interval(active_tenant_alerts."maxFrequency")
            ) OR
            workflowRun."finishedAt" >= "lastAlertedAt"
        )
    GROUP BY workflowRun."tenantId"
)
UPDATE
    "TenantAlertingSettings" as alerts
SET
    "tickerId" = $1::uuid,
    "lastAlertedAt" = NOW()
FROM
    active_tenant_alerts
WHERE
    alerts."id" = active_tenant_alerts."id" AND
    alerts."tenantId" IN (SELECT "tenantId" FROM failed_run_count_by_tenant WHERE "failedWorkflowRunCount" > 0)
RETURNING alerts.id, alerts."createdAt", alerts."updatedAt", alerts."deletedAt", alerts."tenantId", alerts."maxFrequency", alerts."lastAlertedAt", alerts."tickerId", alerts."enableExpiringTokenAlerts", alerts."enableWorkflowRunFailureAlerts", alerts."enableTenantResourceLimitAlerts", active_tenant_alerts."lastAlertedAt" AS "prevLastAlertedAt"
`

type PollTenantAlertsRow struct {
	ID                              uuid.UUID        `json:"id"`
	CreatedAt                       pgtype.Timestamp `json:"createdAt"`
	UpdatedAt                       pgtype.Timestamp `json:"updatedAt"`
	DeletedAt                       pgtype.Timestamp `json:"deletedAt"`
	TenantId                        uuid.UUID        `json:"tenantId"`
	MaxFrequency                    string           `json:"maxFrequency"`
	LastAlertedAt                   pgtype.Timestamp `json:"lastAlertedAt"`
	TickerId                        *uuid.UUID       `json:"tickerId"`
	EnableExpiringTokenAlerts       bool             `json:"enableExpiringTokenAlerts"`
	EnableWorkflowRunFailureAlerts  bool             `json:"enableWorkflowRunFailureAlerts"`
	EnableTenantResourceLimitAlerts bool             `json:"enableTenantResourceLimitAlerts"`
	PrevLastAlertedAt               pgtype.Timestamp `json:"prevLastAlertedAt"`
}

// Finds tenant alerts which haven't alerted since their frequency and assigns them to a ticker
func (q *Queries) PollTenantAlerts(ctx context.Context, db DBTX, tickerid uuid.UUID) ([]*PollTenantAlertsRow, error) {
	rows, err := db.Query(ctx, pollTenantAlerts, tickerid)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*PollTenantAlertsRow
	for rows.Next() {
		var i PollTenantAlertsRow
		if err := rows.Scan(
			&i.ID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.DeletedAt,
			&i.TenantId,
			&i.MaxFrequency,
			&i.LastAlertedAt,
			&i.TickerId,
			&i.EnableExpiringTokenAlerts,
			&i.EnableWorkflowRunFailureAlerts,
			&i.EnableTenantResourceLimitAlerts,
			&i.PrevLastAlertedAt,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const pollTenantResourceLimitAlerts = `-- name: PollTenantResourceLimitAlerts :many
WITH alerting_resource_limits AS (
    SELECT
        rl."id" AS "resourceLimitId",
        rl."tenantId",
        rl."resource",
        rl."limitValue",
        rl."alarmValue",
        rl."value",
        rl."window",
        rl."lastRefill",
        CASE
            WHEN rl."value" >= rl."limitValue" THEN 'Exhausted'
            WHEN rl."alarmValue" IS NOT NULL AND rl."value" >= rl."alarmValue" THEN 'Alarm'
        END AS "alertType"
    FROM
        "TenantResourceLimit" AS rl
    JOIN
        "TenantAlertingSettings" AS ta
    ON
        ta."tenantId" = rl."tenantId"::uuid
    JOIN
        "Tenant" AS tenant ON tenant."id" = rl."tenantId"
    WHERE
        tenant."deletedAt" IS NULL
        AND ta."enableTenantResourceLimitAlerts" = true
        AND (
            (rl."alarmValue" IS NOT NULL AND rl."value" >= rl."alarmValue")
            OR rl."value" >= rl."limitValue"
        )
    FOR UPDATE SKIP LOCKED
),
new_alerts AS (
    SELECT
        arl."resourceLimitId",
        arl."tenantId",
        arl."resource",
        arl."alertType",
        arl."value",
        arl."limitValue" AS "limit",
        EXISTS (
            SELECT 1
            FROM "TenantResourceLimitAlert" AS trla
            WHERE trla."resourceLimitId" = arl."resourceLimitId"
            AND trla."alertType" = arl."alertType"::"TenantResourceLimitAlertType"
            AND trla."createdAt" >= NOW() - arl."window"::INTERVAL
        ) AS "existingAlert"
    FROM
        alerting_resource_limits AS arl
)
INSERT INTO "TenantResourceLimitAlert" (
    "id",
    "createdAt",
    "updatedAt",
    "resourceLimitId",
    "resource",
    "alertType",
    "value",
    "limit",
    "tenantId"
)
SELECT
    gen_random_uuid(),
    NOW(),
    NOW(),
    na."resourceLimitId",
    na."resource",
    na."alertType"::"TenantResourceLimitAlertType",
    na."value",
    na."limit",
    na."tenantId"
FROM
    new_alerts AS na
WHERE
    na."existingAlert" = false
RETURNING id, "createdAt", "updatedAt", "resourceLimitId", "tenantId", resource, "alertType", value, "limit"
`

func (q *Queries) PollTenantResourceLimitAlerts(ctx context.Context, db DBTX) ([]*TenantResourceLimitAlert, error) {
	rows, err := db.Query(ctx, pollTenantResourceLimitAlerts)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*TenantResourceLimitAlert
	for rows.Next() {
		var i TenantResourceLimitAlert
		if err := rows.Scan(
			&i.ID,
			&i.CreatedAt,
			&i.UpdatedAt,
			&i.ResourceLimitId,
			&i.TenantId,
			&i.Resource,
			&i.AlertType,
			&i.Value,
			&i.Limit,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const setTickersInactive = `-- name: SetTickersInactive :many
UPDATE
    "Ticker" as tickers
SET
    "isActive" = false
WHERE
    "id" = ANY ($1::uuid[])
RETURNING
    tickers.id, tickers."createdAt", tickers."updatedAt", tickers."lastHeartbeatAt", tickers."isActive"
`

type SetTickersInactiveRow struct {
	Ticker Ticker `json:"ticker"`
}

func (q *Queries) SetTickersInactive(ctx context.Context, db DBTX, ids []uuid.UUID) ([]*SetTickersInactiveRow, error) {
	rows, err := db.Query(ctx, setTickersInactive, ids)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []*SetTickersInactiveRow
	for rows.Next() {
		var i SetTickersInactiveRow
		if err := rows.Scan(
			&i.Ticker.ID,
			&i.Ticker.CreatedAt,
			&i.Ticker.UpdatedAt,
			&i.Ticker.LastHeartbeatAt,
			&i.Ticker.IsActive,
		); err != nil {
			return nil, err
		}
		items = append(items, &i)
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

const updateTicker = `-- name: UpdateTicker :one
UPDATE
    "Ticker" as tickers
SET
    "lastHeartbeatAt" = $1::timestamp
WHERE
    "id" = $2::uuid
RETURNING id, "createdAt", "updatedAt", "lastHeartbeatAt", "isActive"
`

type UpdateTickerParams struct {
	LastHeartbeatAt pgtype.Timestamp `json:"lastHeartbeatAt"`
	ID              uuid.UUID        `json:"id"`
}

func (q *Queries) UpdateTicker(ctx context.Context, db DBTX, arg UpdateTickerParams) (*Ticker, error) {
	row := db.QueryRow(ctx, updateTicker, arg.LastHeartbeatAt, arg.ID)
	var i Ticker
	err := row.Scan(
		&i.ID,
		&i.CreatedAt,
		&i.UpdatedAt,
		&i.LastHeartbeatAt,
		&i.IsActive,
	)
	return &i, err
}
