packages feed

pgmq-hasql-0.5.0.0: CHANGELOG.md

# Revision history for pgmq-hasql

## 0.5.0.0 -- 2026-08-06

### Breaking Changes

* `changeVisibilityTimeout` and `setVisibilityTimeoutAt` now return `Maybe Message`
  instead of `Message`, at both the statement and session layers. `pgmq.set_vt` is
  `RETURNS SETOF` and yields zero rows when the target message no longer exists (already
  deleted, archived, or popped). Decoding that with a single-row decoder raised an
  `UnexpectedRowCountStatementError` — the same error shape a genuine infrastructure
  failure has — so a caller extending a lease could not distinguish a lost race from a
  broken database. Callers that used the result must now handle `Nothing`; callers that
  discarded it compile unchanged. The batch variants are unaffected.
* Queue names read back from the database are re-validated by `queueDecoder` against the
  tightened `parseQueueName` in pgmq-core 0.5. See that package's changelog for the
  required `pgmq.meta` remediation, and `listQueuesUnvalidated` below for the lenient
  read.

### New Features

* `notifyChannelName` is re-exported from the `Pgmq` umbrella module (defined in
  pgmq-core). Use it instead of assembling the LISTEN/NOTIFY channel name by hand — the
  name this package previously documented was wrong; see Documentation below.
* `listQueuesUnvalidated` (statement, session, and `Pgmq` re-export) reads `pgmq.meta`
  with the queue name decoded as `Text`, yielding `UnvalidatedQueue` rows. pgmq's
  server-side validator checks only length, so any co-tenant client can create a name
  `parseQueueName` rejects, and the typed `listQueues` decoder fails the whole listing on
  one such row. The typed `listQueues` keeps its strict decoding for API consumers.
* `listFifoIndexQueueNames` reports which queues already carry a `q_<name>_fifo_idx`. pgmq exposes
  no index-existence query — `create_fifo_index` delegates to `CREATE INDEX IF NOT EXISTS`
  and reports nothing back — so this reads the `pg_indexes` catalog view. It is the first
  statement in this package that queries a PostgreSQL catalog rather than calling a
  `pgmq.*` function.

### Bug Fixes

* `pop` with `qty = Nothing` now pops one message, as documented. It previously deleted
  and returned every visible message in the queue. The `Maybe` parameter was encoded as a
  nullable bind, so `Nothing` reached PostgreSQL as SQL NULL; a plpgsql parameter
  `DEFAULT` applies only to omitted arguments, and NULL in a `LIMIT` clause means
  `LIMIT ALL`. Because `pop` deletes, there was no visibility timeout to recover the
  messages.
* `readMessage` and `readWithPoll` with `batchSize = Nothing` now read one message, as
  documented. They previously leased the entire queue through the same `LIMIT NULL` path,
  hiding every message from other consumers for the visibility timeout.
* `enableNotifyInsert` with `throttleIntervalMs = Nothing` now installs the documented
  250 ms throttle. It previously failed with SQLSTATE 23502 on every call, because a
  column `DEFAULT` does not apply to an explicitly supplied NULL.
* `ReadMessage.conditional` now filters. The field existed and was documented, but was
  never encoded, so a `Just` filter was silently ignored and every visible message was
  returned. `readWithPoll`'s conditional already worked.
* A message whose body is SQL NULL no longer poisons every read batch. The `message`
  column is nullable and `pgmq.send('q', NULL::jsonb)` is legal SQL for any non-Haskell
  producer; one such row made every batch containing it fail at decode — after the read
  statement had already bumped `vt` and `read_ct` for the whole batch — and the row could
  not be seen or archived through this client. A SQL NULL body now decodes as JSON `null`
  (`MessageBody Aeson.Null`, deliberately indistinguishable from an explicitly-sent JSON
  `null` body), so the row is readable, identifiable, and archivable through the normal
  API.

### Documentation

* The documented LISTEN/NOTIFY channel name was wrong. `enableNotifyInsert` claimed
  notifications arrive on `pgmq_<queue_name>`; the real channel is
  `pgmq.q_<lowercased queue name>.INSERT`, so anyone following the documentation listened
  on a channel that never receives anything. Corrected on the Haddock and in
  `docs/design/006-queue-notifications.md`, and replaced by `notifyChannelName`. The full
  contract — including the poll-fallback requirement and the crash fail-open semantics —
  is in `docs/design/015-notification-delivery-contract.md`.

### Other Changes

* Bumped `pgmq-core` dependency bound to `>=0.5 && <0.6`.

## 0.4.0.1 -- 2026-07-14

* Version bump only — coordinated release with pgmq-migration 0.4.0.1.
  No source-level changes since 0.4.0.0.

## 0.4.0.0 -- 2026-07-14

* Version bump only — coordinated release with pgmq-migration 0.4.0.0.
  No library source changes since 0.3.0.0; the test suite was updated for the
  native `pgmq-migration` API.
* Bumped `pgmq-core` dependency bound to `>=0.4 && <0.5`.

## 0.3.0.0 -- 2026-05-31

* Version bump only — coordinated release with pgmq-effectful 0.3.0.0.
  No source-level changes since 0.2.0.0.
* Bumped `pgmq-core` dependency bound to `>=0.3 && <0.4`.

## 0.2.0.0 -- 2026-04-23

* Version bump only — coordinated release with pgmq-effectful 0.2.0.0.
  No source-level changes since 0.1.3.0.
* Bumped `pgmq-core` dependency bound to `>=0.2 && <0.3`.

## 0.1.3.0 -- 2026-03-12

### Other Changes

* Update documentation URLs from tembo.io to pgmq.github.io
* Update repository homepage URL to shinzui/pgmq-hs

## 0.1.2.0 -- 2026-03-03

* Version bump only (no changes)

## 0.1.1.0 -- 2026-02-23

### New Features

#### pgmq 1.11.0+ Support

* Topic management: `bindTopic`, `unbindTopic`, `validateRoutingKey`, `validateTopicPattern`, `testRouting`, `listTopicBindings`, `listTopicBindingsForQueue`
* Topic sending: `sendTopic`, `sendTopicWithHeaders`, `batchSendTopic`, `batchSendTopicForLater`, `batchSendTopicWithHeaders`, `batchSendTopicWithHeadersForLater`
* Notification management: `listNotifyInsertThrottles`, `updateNotifyInsert`
* New parameter types: `BindTopic`, `UnbindTopic`, `SendTopic`, `SendTopicWithHeaders`, `BatchSendTopic`, `BatchSendTopicForLater`, `BatchSendTopicWithHeaders`, `BatchSendTopicWithHeadersForLater`, `UpdateNotifyInsert`

## 0.1.0.0 -- 2026-02-21

### New Features

#### pgmq 1.5.0+ Support
- Message headers: `sendMessageWithHeaders`, `sendMessageWithHeadersForLater`,
  `batchSendMessageWithHeaders`, `batchSendMessageWithHeadersForLater`
- Conditional read filtering via `conditional` field in `ReadMessage`
- Added `queueVisibleLength` to `QueueMetrics`

#### pgmq 1.7.0+ Support
- Pop with quantity via `PopMessage` type
- Queue notifications: `enableNotifyInsert`, `disableNotifyInsert`

#### pgmq 1.8.0+ Support
- Batch visibility timeout: `batchChangeVisibilityTimeout`
- Notification throttling via `throttleIntervalMs` in `EnableNotifyInsert`
- FIFO read functions:
  - `readGrouped`: SQS-style batch filling from same message group
  - `readGroupedWithPoll`: Same with polling support
- FIFO index management:
  - `createFifoIndex`: Create FIFO index for a specific queue
  - `createFifoIndexesAll`: Create FIFO indexes for all queues
- New types: `ReadGrouped`, `ReadGroupedWithPoll`

#### pgmq 1.9.0+ Support
- Round-robin FIFO read functions:
  - `readGroupedRoundRobin`: Fair distribution across message groups
  - `readGroupedRoundRobinWithPoll`: Same with polling support
- Note: FIFO functions do not support `conditional` parameter (removed in pgmq 1.9.0)

#### pgmq 1.10.0+ Support
- Timestamp-based `set_vt` API
- `lastReadAt` field on `Message` type

### Deprecations

- `detachArchive` is now deprecated (no-op in pgmq, will be removed in pgmq 2.0)

* Initial release with full PGMQ API coverage