{-# LANGUAGE OverloadedStrings #-}

-- | Schema-scoped watermark gates for global tasks (refresh groups, sweep stale
-- workers). One row per task holding @last_run_at@. 'Arbiter.Core.Operations.runGated'
-- claims the row with @SELECT ... FOR UPDATE SKIP LOCKED@ once the interval has
-- elapsed. At most one worker pool runs the task per interval.
module Arbiter.Core.Gates
  ( arbiterGatesTable
  , arbiterGatesTableName
  , createGatesTableSQL
  , addGateMetadataColumnSQL
  ) where

import Data.Text (Text)
import Data.Text qualified as T

import Arbiter.Core.Job.Schema (SchemaName)
import Arbiter.Core.SqlLiterals (quoteIdentifier)

-- | Qualified name of the gates table.
arbiterGatesTable :: SchemaName -> Text
arbiterGatesTable :: Text -> Text
arbiterGatesTable Text
schemaName = Text -> Text
quoteIdentifier Text
schemaName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
"." Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
arbiterGatesTableName

-- | Bare name of the gates table, for catalog lookups by relname.
arbiterGatesTableName :: Text
arbiterGatesTableName :: Text
arbiterGatesTableName = Text
"arbiter_gates"

-- | DDL for the @arbiter_gates@ table.
createGatesTableSQL :: SchemaName -> Text
createGatesTableSQL :: Text -> Text
createGatesTableSQL Text
schemaName =
  [Text] -> Text
T.unlines
    [ Text
"CREATE TABLE IF NOT EXISTS " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
arbiterGatesTable Text
schemaName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" ("
    , Text
"  task_name TEXT PRIMARY KEY,"
    , Text
"  last_run_at TIMESTAMPTZ NOT NULL DEFAULT '1970-01-01'::timestamptz"
    , Text
");"
    ]

-- | Add the column a task publishes its result into.
addGateMetadataColumnSQL :: SchemaName -> Text
addGateMetadataColumnSQL :: Text -> Text
addGateMetadataColumnSQL Text
schemaName =
  Text
"ALTER TABLE " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text -> Text
arbiterGatesTable Text
schemaName Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" ADD COLUMN IF NOT EXISTS metadata JSONB;"