pgmq-core (empty) → 0.1.0.0
raw patch · 4 files changed
+161/−0 lines, 4 filesdep +aesondep +basedep +template-haskell
Dependencies added: aeson, base, template-haskell, text, time
Files
- CHANGELOG.md +8/−0
- LICENSE +20/−0
- pgmq-core.cabal +43/−0
- src/Pgmq/Types.hs +90/−0
+ CHANGELOG.md view
@@ -0,0 +1,8 @@+# Revision history for pgmq-core++## 0.1.0.0 -- 2026-02-21++* Initial release+* Core types: `Message`, `MessageBody`, `MessageHeaders`, `MessageId`, `Queue`, `QueueName`, `PgmqError`+* Queue name validation following pgmq-rs conventions+* Template Haskell `Lift` instance for `QueueName`
+ LICENSE view
@@ -0,0 +1,20 @@+Copyright (c) 2025 Nadeem Bitar++Permission is hereby granted, free of charge, to any person obtaining+a copy of this software and associated documentation files (the+"Software"), to deal in the Software without restriction, including+without limitation the rights to use, copy, modify, merge, publish,+distribute, sublicense, and/or sell copies of the Software, and to+permit persons to whom the Software is furnished to do so, subject to+the following conditions:++The above copyright notice and this permission notice shall be included+in all copies or substantial portions of the Software.++THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,+EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF+MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.+IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY+CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,+TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE+SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+ pgmq-core.cabal view
@@ -0,0 +1,43 @@+cabal-version: 3.4+name: pgmq-core+version: 0.1.0.0+synopsis: Core types for pgmq-hs, a Haskell client for PGMQ+description:+ Core types and type classes for pgmq-hs, a Haskell client library+ for PGMQ (PostgreSQL Message Queue). Provides Message, Queue,+ QueueName, and related types used across pgmq-hs packages.++homepage: https://github.com/topagentnetwork/pgmq-hs+license: MIT+license-file: LICENSE+author: Nadeem Bitar+maintainer: nadeem@topagentnetwork.com+category: Database+build-type: Simple+extra-doc-files: CHANGELOG.md++common warnings+ ghc-options:+ -Wall -Wcompat -Widentities -Wincomplete-uni-patterns+ -Wincomplete-record-updates -Wredundant-constraints+ -fhide-source-paths -Wmissing-export-lists -Wpartial-fields+ -Wmissing-deriving-strategies++library+ import: warnings+ exposed-modules: Pgmq.Types+ default-extensions:+ DeriveGeneric+ GeneralisedNewtypeDeriving+ ImportQualifiedPost+ OverloadedStrings++ build-depends:+ , aeson ^>=2.2+ , base >=4.18 && <5+ , template-haskell >=2.20 && <3+ , text ^>=2.1+ , time ^>=1.14++ hs-source-dirs: src+ default-language: GHC2024
+ src/Pgmq/Types.hs view
@@ -0,0 +1,90 @@+{-# LANGUAGE TemplateHaskellQuotes #-}++module Pgmq.Types+ ( MessageBody (..),+ MessageHeaders (..),+ MessageId (..),+ Message (..),+ Queue (..),+ QueueName,+ parseQueueName,+ queueNameToText,+ PgmqError (..),+ )+where++import Data.Aeson (FromJSON, ToJSON, Value)+import Data.Char (isAlphaNum, isAscii)+import Data.Int (Int64)+import Data.Text (Text)+import Data.Text qualified as T+import Data.Time (UTCTime)+import GHC.Generics (Generic)+import Language.Haskell.TH.Syntax (Lift (..))++newtype MessageBody = MessageBody {unMessageBody :: Value}+ deriving newtype (Eq, Ord, FromJSON, ToJSON)+ deriving stock (Show, Generic)++-- | Message headers for metadata (routing, tracing, etc.)+-- Added in pgmq 1.5.0+newtype MessageHeaders = MessageHeaders {unMessageHeaders :: Value}+ deriving newtype (Eq, Ord, FromJSON, ToJSON)+ deriving stock (Show, Generic)++newtype MessageId = MessageId {unMessageId :: Int64}+ deriving newtype (Eq, Ord, FromJSON, ToJSON)+ deriving stock (Show, Generic)++data Queue = Queue+ { name :: !QueueName,+ createdAt :: !UTCTime,+ isPartitioned :: !Bool,+ isUnlogged :: !Bool+ }+ deriving stock (Eq, Generic, Show)++-- | https://tembo.io/pgmq/api/sql/types/+-- Note: headers field added in pgmq 1.5.0+-- Note: lastReadAt field added in pgmq 1.10.0+data Message = Message+ { messageId :: !MessageId,+ visibilityTime :: !UTCTime,+ enqueuedAt :: !UTCTime,+ lastReadAt :: !(Maybe UTCTime),+ readCount :: !Int64,+ body :: !MessageBody,+ headers :: !(Maybe Value)+ }+ deriving stock (Eq, Generic, Show)++newtype QueueName = QueueName Text+ deriving newtype (Eq, Ord, FromJSON, ToJSON)+ deriving stock (Show, Generic)++instance Lift QueueName where+ lift (QueueName t) = [|QueueName t|]+ liftTyped (QueueName t) = [||QueueName t||]++queueNameToText :: QueueName -> Text+queueNameToText (QueueName t) = t++newtype PgmqError = InvalidQueueName Text+ deriving stock (Show, Generic)++-- Adopted from https://github.com/tembo-io/pgmq/blob/e4d4b84bf302df77be2d1f877c5cf8ef8861bfc7/pgmq-rs/src/util.rs#L94+parseQueueName :: Text -> Either PgmqError QueueName+parseQueueName t+ | not isShortEnough = Left $ InvalidQueueName "The queue name is too long."+ | not hasValidCharacters = Left $ InvalidQueueName "The queue name contains invalid characters."+ | otherwise = Right $ QueueName t+ where+ isShortEnough = T.length t <= maxQueueNameLength+ hasValidCharacters = T.all isValidChar t+ isValidChar c = (isAscii c && isAlphaNum c) || c == '_'++ -- PostgreSQL identifier length information+ -- https://www.postgresql.org/docs/current/sql-syntax-lexical.html#SQL-SYNTAX-IDENTIFIERS+ maxIdentifierLength = 63 -- PostgreSQL truncates beyond this length+ longestPrefix :: Text = "archived_at_idx_"+ maxQueueNameLength = maxIdentifierLength - T.length longestPrefix