{"id":24435282,"url":"https://github.com/rlperez/pgmq-clj","last_synced_at":"2026-02-15T19:12:01.306Z","repository":{"id":270511393,"uuid":"910601402","full_name":"rlperez/pgmq-clj","owner":"rlperez","description":"A Clojure library that wraps the PGMQ extension for Postgres. It comes packaged with support connecting HikariCP and is capable of being extended.","archived":false,"fork":false,"pushed_at":"2025-11-18T02:56:49.000Z","size":120,"stargazers_count":0,"open_issues_count":2,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-11-18T04:25:26.396Z","etag":null,"topics":["clojure","clojure-library","pgmq"],"latest_commit_sha":null,"homepage":"","language":"Clojure","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/rlperez.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":"COPYRIGHT","agents":null,"dco":null,"cla":null},"funding":{"github":"rlperez","patreon":null,"open_collective":null,"ko_fi":"kablamooo","tidelift":null,"community_bridge":null,"liberapay":"kablamooo","issuehunt":null,"lfx_crowdfunding":null,"polar":null,"buy_me_a_coffee":null,"thanks_dev":null,"custom":null}},"created_at":"2024-12-31T19:15:48.000Z","updated_at":"2025-11-18T02:56:52.000Z","dependencies_parsed_at":"2024-12-31T20:21:13.068Z","dependency_job_id":"ae8dcd37-f750-4284-8cb0-3cf6067b5b01","html_url":"https://github.com/rlperez/pgmq-clj","commit_stats":null,"previous_names":["rlperez/pgmq-clj"],"tags_count":5,"template":false,"template_full_name":null,"purl":"pkg:github/rlperez/pgmq-clj","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlperez%2Fpgmq-clj","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlperez%2Fpgmq-clj/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlperez%2Fpgmq-clj/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlperez%2Fpgmq-clj/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/rlperez","download_url":"https://codeload.github.com/rlperez/pgmq-clj/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/rlperez%2Fpgmq-clj/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29487413,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-15T15:33:17.885Z","status":"ssl_error","status_checked_at":"2026-02-15T15:32:53.698Z","response_time":118,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["clojure","clojure-library","pgmq"],"created_at":"2025-01-20T17:18:56.906Z","updated_at":"2026-02-15T19:12:01.300Z","avatar_url":"https://github.com/rlperez.png","language":"Clojure","funding_links":["https://github.com/sponsors/rlperez","https://ko-fi.com/kablamooo","https://liberapay.com/kablamooo"],"categories":[],"sub_categories":[],"readme":"\u003c!-- Make README.md changes here. README.md is a generated file and changes will be overwritten. --\u003e\n\n[![codecov](https://codecov.io/github/rlperez/pgmq-clj/graph/badge.svg?token=KIC7UP13WY)](https://codecov.io/github/rlperez/pgmq-clj)\n[![checks](https://badgen.net/github/checks/rlperez/pgmq-clj)](https://github.com/rlperez/pgmq-clj/actions)\n[![license](https://badgen.net/github/license/rlperez/pgmq-clj)](https://opensource.org/license/mit)\n[![latest-release](https://badgen.net/github/release/rlperez/pgmq-clj)](https://github.com/rlperez/pgmq-clj/releases)\n[![latest-tag](https://badgen.net/github/tag/rlperez/pgmq-clj)](https://github.com/rlperez/pgmq-clj/tags)\n\n# pgmq-clj\nA library that provides a wrapper of [PGMQ](https://github.com/tembo-io/pgmq), a [PostgreSQL](https://www.postgresql.org/) message queue implementation, making it easier to integrate into your application. As designed you can implement your own database access layer by implementing an `Adapter` conforming to a simple [protocol](https://github.com/rlperez/pgmq-clj/blob/master/src/com/thirstysink/pgmq_clj/db/adapter.clj). The provided adapter utilizes [HikariCP](https://github.com/brettwooldridge/HikariCP) and [next.jdbc](https://github.com/seancorfield/next-jdbc).\n\n## Types of Documentation\n\n* [Documentation](#documentation)\n  This is documentation that will contain explanations of the functions as well as usage examples when appropriate. It is generated from the docstrings present in code generated by [quickdoc](https://github.com/borkdude/quickdoc). This documentation has a complete table of contents.\n\n* [Specs](#specs)\n  This project uses [clojure.spec.alpha](https://github.com/clojure/spec.alpha/) to provide a means of validating expectations. Using this project, leveraging the `clojure.spec.alpha/describe`, documentation is generated describing functions, return types, and their expected inputs. They are organized by a namespaced function name followed by the arguments of that function.\n\n## Build Jar\n\nThis will build a jar that can be used directly in your applications.\n\n```\n# babashka\nbb jar\n\n# build tools\nclj -T:build all\n```\n\n## Execute Tests\n\nThis will run all tests. Tests currently include an integration test using test containers against postgresql 15, 16, and 17.\n\n```\n# babashka\nbb test\nbb test coverage\nbb test watch\n\n# build tools\nclj -M:test --profile test\nclj -M:test --profile coverage\nclj -M:test --profile watch\n```\n\n## Update Dependencies\n\nThis will update the local depencies in `deps.edn` and `bb.edn`.\n\n```\n# babashka\nbb upgrade\n\n# build tools\nclj -M:upgrade\n```\n\n---\n\n\n# Documentation\n# Table of contents\n-  [`com.thirstysink.pgmq-clj.core`](#com.thirstysink.pgmq-clj.core) \n    -  [`archive-messages`](#com.thirstysink.pgmq-clj.core/archive-messages) - Archives messages \u003ccode\u003emsg-ids\u003c/code\u003e in a queue named \u003ccode\u003equeue-name\u003c/code\u003e using a given \u003ccode\u003eadapter\u003c/code\u003e.\n    -  [`create-queue`](#com.thirstysink.pgmq-clj.core/create-queue) - Create a queue named \u003ccode\u003equeue-name\u003c/code\u003e using a given \u003ccode\u003eadapter\u003c/code\u003e.\n    -  [`delete-message`](#com.thirstysink.pgmq-clj.core/delete-message) - Permanently deletes message with id \u003ccode\u003emsg-id\u003c/code\u003e in the queue named \u003ccode\u003equeue-name\u003c/code\u003e using a given \u003ccode\u003eadapter\u003c/code\u003e.\n    -  [`delete-message-batch`](#com.thirstysink.pgmq-clj.core/delete-message-batch) - Deletes all \u003ccode\u003emsg-ids\u003c/code\u003e messages in queue \u003ccode\u003equeue-name\u003c/code\u003e using a given \u003ccode\u003eadapter\u003c/code\u003e.\n    -  [`drop-queue`](#com.thirstysink.pgmq-clj.core/drop-queue) - Drop queue named \u003ccode\u003equeue-name\u003c/code\u003e using a given \u003ccode\u003eadapter\u003c/code\u003e.\n    -  [`list-queues`](#com.thirstysink.pgmq-clj.core/list-queues) - List all queues using a given \u003ccode\u003eadapter\u003c/code\u003e.\n    -  [`pop-message`](#com.thirstysink.pgmq-clj.core/pop-message) - Pops one message from the queue named \u003ccode\u003equeue-name\u003c/code\u003e using a given \u003ccode\u003eadapter\u003c/code\u003e.\n    -  [`purge-queue`](#com.thirstysink.pgmq-clj.core/purge-queue) - Purge queue named \u003ccode\u003equeue-name\u003c/code\u003e contents using a given \u003ccode\u003eadapter\u003c/code\u003e then and return count of purged items.\n    -  [`read-message`](#com.thirstysink.pgmq-clj.core/read-message) - Read a \u003ccode\u003equantity\u003c/code\u003e of messages from \u003ccode\u003equeue-name\u003c/code\u003e marking them invisible for \u003ccode\u003evisible_time\u003c/code\u003e seconds using a given \u003ccode\u003eadapter\u003c/code\u003e.\n    -  [`send-message`](#com.thirstysink.pgmq-clj.core/send-message) - Send one message to a queue \u003ccode\u003equeue-name\u003c/code\u003e with a \u003ccode\u003epayload\u003c/code\u003e that will not be read for \u003ccode\u003edelay\u003c/code\u003e seconds using a given \u003ccode\u003eadapter\u003c/code\u003e.\n    -  [`send-message-batch`](#com.thirstysink.pgmq-clj.core/send-message-batch) - Sends \u003ccode\u003epayload\u003c/code\u003e to the queue named \u003ccode\u003equeue-name\u003c/code\u003e as a collection of messages that cannot be read for \u003ccode\u003edelay\u003c/code\u003e seconds using a given \u003ccode\u003eadapter\u003c/code\u003e.\n-  [`com.thirstysink.pgmq-clj.db.adapter`](#com.thirstysink.pgmq-clj.db.adapter) \n    -  [`Adapter`](#com.thirstysink.pgmq-clj.db.adapter/adapter)\n    -  [`close`](#com.thirstysink.pgmq-clj.db.adapter/close) - Performs database connection cleanup using \u003ccode\u003ethis\u003c/code\u003e.\n    -  [`execute!`](#com.thirstysink.pgmq-clj.db.adapter/execute!) - Execute a \u003ccode\u003esql\u003c/code\u003e statement and \u003ccode\u003eparams\u003c/code\u003e with 0 or more return values using \u003ccode\u003ethis\u003c/code\u003e.\n    -  [`execute-one!`](#com.thirstysink.pgmq-clj.db.adapter/execute-one!) - Execute a \u003ccode\u003esql\u003c/code\u003e statement and \u003ccode\u003eparams\u003c/code\u003e with 0 or 1 return values using \u003ccode\u003ethis\u003c/code\u003e.\n    -  [`query`](#com.thirstysink.pgmq-clj.db.adapter/query) - Query the database with a given \u003ccode\u003esql\u003c/code\u003e, \u003ccode\u003eparams\u003c/code\u003e, and return results using \u003ccode\u003ethis\u003c/code\u003e.\n    -  [`with-transaction`](#com.thirstysink.pgmq-clj.db.adapter/with-transaction) - Wrap a function \u003ccode\u003ef\u003c/code\u003e in a database transaction using \u003ccode\u003ethis\u003c/code\u003e.\n-  [`com.thirstysink.pgmq-clj.db.adapters.hikari-adapter`](#com.thirstysink.pgmq-clj.db.adapters.hikari-adapter) \n    -  [`-\u003epgobject`](#com.thirstysink.pgmq-clj.db.adapters.hikari-adapter/-\u003epgobject) - Transforms Clojure data to a PGobject \u003ccode\u003ex\u003c/code\u003e that contains the data as JSON.\n    -  [`\u003c-pgobject`](#com.thirstysink.pgmq-clj.db.adapters.hikari-adapter/\u003c-pgobject) - Transform PGobject \u003ccode\u003ev\u003c/code\u003e containing \u003ccode\u003ejson\u003c/code\u003e or \u003ccode\u003ejsonb\u003c/code\u003e value to Clojure data.\n    -  [`ensure-pgmq-extension`](#com.thirstysink.pgmq-clj.db.adapters.hikari-adapter/ensure-pgmq-extension) - Checks the database to verify that the \u003ccode\u003epgmq\u003c/code\u003e extension is installed using the \u003ccode\u003eadapter\u003c/code\u003e.\n    -  [`make-hikari-adapter`](#com.thirstysink.pgmq-clj.db.adapters.hikari-adapter/make-hikari-adapter) - Create a new [\u003ccode\u003eHikariAdapter\u003c/code\u003e](#com.thirstysink.pgmq-clj.db.adapters.hikari-adapter/hikariadapter) instance.\n-  [`com.thirstysink.pgmq-clj.instrumentation`](#com.thirstysink.pgmq-clj.instrumentation) \n    -  [`disable-instrumentation`](#com.thirstysink.pgmq-clj.instrumentation/disable-instrumentation) - Disables \u003ccode\u003eclojure.specs.alpha\u003c/code\u003e specs instrumentation.\n    -  [`enable-instrumentation`](#com.thirstysink.pgmq-clj.instrumentation/enable-instrumentation) - Enables \u003ccode\u003eclojure.specs.alpha\u003c/code\u003e specs instrumentation.\n    -  [`instrumentation-enabled?`](#com.thirstysink.pgmq-clj.instrumentation/instrumentation-enabled?) - A flag that indicates if instrumentation is enabled.\n-  [`com.thirstysink.pgmq-clj.json`](#com.thirstysink.pgmq-clj.json) \n    -  [`-\u003ejson`](#com.thirstysink.pgmq-clj.json/-\u003ejson) - Returns a JSON-encoding String for the given Clojure object.\n-  [`com.thirstysink.pgmq-clj.specs`](#com.thirstysink.pgmq-clj.specs) \n\n-----\n# \u003ca name=\"com.thirstysink.pgmq-clj.core\"\u003ecom.thirstysink.pgmq-clj.core\u003c/a\u003e\n\n\n\n\n\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.core/archive-messages\"\u003e`archive-messages`\u003c/a\u003e\n``` clojure\n(archive-messages adapter queue-name msg-ids)\n```\nFunction.\n\nArchives messages `msg-ids` in a queue named `queue-name` using a given `adapter`.\n  This will remove the message from `queue-name` and place it in a archive table\n  which is named `a_{queue-name}`.\n\n  Example:\n  (core/archive-messages adapter \"test-queue\" [3])\n  ;; =\u003e ()\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/core.clj#L162-L173\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.core/create-queue\"\u003e`create-queue`\u003c/a\u003e\n``` clojure\n(create-queue adapter queue-name)\n```\nFunction.\n\nCreate a queue named `queue-name` using a given `adapter`.\n\n  Example:\n  ```clojure\n  (core/create-queue adapter \"test-queue\")\n  ;; =\u003e nil\n  ```\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/core.clj#L9-L20\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.core/delete-message\"\u003e`delete-message`\u003c/a\u003e\n``` clojure\n(delete-message adapter queue-name msg-id)\n```\nFunction.\n\nPermanently deletes message with id `msg-id` in the queue\n  named `queue-name` using a given `adapter`.\n\n  Example:\n   (core/delete-message adapter \"test-queue\" 3)\n   ;; =\u003e true\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/core.clj#L132-L142\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.core/delete-message-batch\"\u003e`delete-message-batch`\u003c/a\u003e\n``` clojure\n(delete-message-batch adapter queue-name msg-ids)\n```\nFunction.\n\nDeletes all `msg-ids` messages in queue `queue-name` using a given `adapter`.\n\n  Example:\n  (core/delete-message-batch adapter \"test-queue\" [2 5 6])\n  ;; =\u003e [2 5 6]\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/core.clj#L203-L212\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.core/drop-queue\"\u003e`drop-queue`\u003c/a\u003e\n``` clojure\n(drop-queue adapter queue-name)\n```\nFunction.\n\nDrop queue named `queue-name` using a given `adapter`.\n\n  Example:\n  ```clojure\n  (core/drop-queue adapter \"test-queue-2\")\n  ;; =\u003e true\n  ```\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/core.clj#L22-L33\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.core/list-queues\"\u003e`list-queues`\u003c/a\u003e\n``` clojure\n(list-queues adapter)\n```\nFunction.\n\nList all queues using a given `adapter`.\n  Example:\n  (core/list-queues adapter)\n  ;; =\u003e [{:queue-name \"test-queue\",\n    :is-partitioned false,\n    :is-unlogged false,\n    :created-at\n    #object[java.time.Instant 0x680b0f16 \"2025-03-20T01:01:42.842248Z\"]}\n   {:queue-name \"test-queue-2\",\n    :is-partitioned false,\n    :is-unlogged false,\n    :created-at\n    #object[java.time.Instant 0x45e79bdf \"2025-03-20T01:01:46.292274Z\"]}\n   {:queue-name \"test-queue-3\",\n    :is-partitioned false,\n    :is-unlogged false,\n    :created-at\n    #object[java.time.Instant 0x19767429 \"2025-03-20T01:01:54.665295Z\"]}]\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/core.clj#L49-L71\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.core/pop-message\"\u003e`pop-message`\u003c/a\u003e\n``` clojure\n(pop-message adapter queue-name)\n```\nFunction.\n\nPops one message from the queue named `queue-name` using a given `adapter`. The side-effect of\n  this function is equivalent to reading and deleting a message. See also\n  [[read-message]] and [[delete-message]].\n\n  Example:\n  (core/pop-message adapter \"test-queue\")\n  ;; =\u003e {:msg-id 1,\n         :read-ct 0,\n         :enqueued-at #object[java.time.Instant 0x79684534 \"2025-03-20T01:29:15.298975Z\"],\n         :vt #object[java.time.Instant 0x391acb50 \"2025-03-20T01:30:45.300696Z\"],\n         :message {:user-id \"0f83fbeb-345b-41ca-bbec-3bace0cff5b4\", :order-count 12},\n         :headers {:TENANT \"b5bda77b-8283-4a6d-8de8-40a5041a60ee\"}\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/core.clj#L144-L160\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.core/purge-queue\"\u003e`purge-queue`\u003c/a\u003e\n``` clojure\n(purge-queue adapter queue-name)\n```\nFunction.\n\nPurge queue named `queue-name` contents using a given `adapter` then\n   and return count of purged items.\n\n   Example:\n   ```clojure\n   (c/purge-queue adapter queue-name)\n   ;; =\u003e 2\n   ```\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/core.clj#L35-L47\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.core/read-message\"\u003e`read-message`\u003c/a\u003e\n``` clojure\n(read-message adapter queue-name visible_time quantity filter)\n```\nFunction.\n\nRead a `quantity` of messages from `queue-name` marking them invisible for\n  `visible_time` seconds using a given `adapter`. This function supports the\n  ability to `filter` messages received when making a read request.\n\n  Here are some examples of how this conditional works:\n  - If conditional is an empty JSON object ('{}'::jsonb), the condition always evaluates to TRUE, and all messages are considered matching.\n\n\n  - If conditional is a JSON object with a single key-value pair, such as {'key': 'value'}, the condition checks if the message column contains a JSON object with the same key-value pair. For example:\n  ```\n  message = {'key': 'value', 'other_key': 'other_value'}: // matches\n  message = {'other_key': 'other_value'}: // does not match\n  ```\n\n  - If conditional is a JSON object with multiple key-value pairs, such as {'key1': 'value1', 'key2': 'value2'}, the condition checks if the message column contains a JSON object with all the specified key-value pairs. For example:\n  ```\n  message = {'key1': 'value1', 'key2': 'value2', 'other_key': 'other_value'}: // matches\n  message = {'key1': 'value1', 'other_key': 'other_value'}: // does not match\n  ```\n\n  Some examples of conditional JSONB values and their effects on the query:\n  * `{}`: matches all messages\n  * `{'type': 'error'}`: matches messages with a type key equal to 'error'\n  * `{'type': 'error', 'severity': 'high'}`: matches messages with both type equal to 'error' and severity equal to 'high'\n  * `{'user_id': 123}`: matches messages with a user_id key equal to 123\n\n  Example:\n  (core/read-message adapter \"test-queue\" 10 88 nil)\n  ;; =\u003e ({:msg-id 2,\n          :read-ct 1,\n          :enqueued-at #object[java.time.Instant 0x5f794b3d \"2025-03-21T01:14:00.831673Z\"],\n          :vt #object[java.time.Instant 0x3fcde164 \"2025-03-21T01:15:32.988540Z\"],\n          :message {:user-id \"0f83fbeb-345b-41ca-bbec-3bace0cff5b4\", :order-count 12},\n          :headers {:TENANT \"b5bda77b-8283-4a6d-8de8-40a5041a60ee\"}})\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/core.clj#L92-L130\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.core/send-message\"\u003e`send-message`\u003c/a\u003e\n``` clojure\n(send-message adapter queue-name payload delay)\n```\nFunction.\n\nSend one message to a queue `queue-name` with a `payload`\n  that will not be read for `delay` seconds using a given `adapter`.\n  A `delay` of 0 indicates it may be read immediately.\n\n  Example Payloads:\n  - `{:data {:foo \"bad\"} :headers {:x-data \"baz\"}}`\n  - `{:data \"feed\" :headers {:version \"3\"}}`\n\n  Example:\n  (core/send-message adapter \"test-queue\" {:data {:order-count 12 :user-id \"0f83fbeb-345b-41ca-bbec-3bace0cff5b4\"} :headers {:TENANT \"b5bda77b-8283-4a6d-8de8-40a5041a60ee\"}} 90)\n  ;; =\u003e 1\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/core.clj#L73-L90\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.core/send-message-batch\"\u003e`send-message-batch`\u003c/a\u003e\n``` clojure\n(send-message-batch adapter queue-name payload delay)\n```\nFunction.\n\nSends `payload` to the queue named `queue-name` as a collection of messages\n  that cannot be read for `delay` seconds using a given `adapter`. The payload\n  should be a sequence of valid JSON objects. See also [[send-message]].\n\n  Example Payloads:\n   - `[{:data {:foo \"bar\"} :headers {:x-data \"bat\"}}]`\n   - `[{:data 10002 :headers {}} {:data \"feed\" :headers {:version \"2\"}} ]`\n  Example:\n  (core/send-message-batch adapter\n                               \"test-queue\"\n                               [{:data {:order-count 12 :user-id \"0f83fbeb-345b-41ca-bbec-3bace0cff5b4\"} :headers {:X-SESS-ID \"b5bda77b-8283-4a6d-8de8-40a5041a60ee\"}}\n                                {:data {:order-count 12 :user-id \"da04bf11-018f-45c4-908f-62c33b6e8aa6\"} :headers {:X-SESS-ID \"b0ef0d6a-e587-4c28-b995-1efe8cb31c9e\"}}]\n                               15)\n  ;; =\u003e [5 6]\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/core.clj#L181-L201\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n-----\n# \u003ca name=\"com.thirstysink.pgmq-clj.db.adapter\"\u003ecom.thirstysink.pgmq-clj.db.adapter\u003c/a\u003e\n\n\n\n\n\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.db.adapter/adapter\"\u003e`Adapter`\u003c/a\u003e\n\n\n\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/db/adapter.clj#L3-L8\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.db.adapter/close\"\u003e`close`\u003c/a\u003e\n``` clojure\n(close this)\n```\nFunction.\n\nPerforms database connection cleanup using `this`.\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/db/adapter.clj#L8-L8\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.db.adapter/execute!\"\u003e`execute!`\u003c/a\u003e\n``` clojure\n(execute! this sql params)\n```\nFunction.\n\nExecute a `sql` statement and `params` with 0 or more return values using `this`.\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/db/adapter.clj#L5-L5\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.db.adapter/execute-one!\"\u003e`execute-one!`\u003c/a\u003e\n``` clojure\n(execute-one! this sql params)\n```\nFunction.\n\nExecute a `sql` statement and `params` with 0 or 1 return values using `this`.\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/db/adapter.clj#L4-L4\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.db.adapter/query\"\u003e`query`\u003c/a\u003e\n``` clojure\n(query this sql params)\n```\nFunction.\n\nQuery the database with a given `sql`, `params`, and return results using `this`.\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/db/adapter.clj#L6-L6\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.db.adapter/with-transaction\"\u003e`with-transaction`\u003c/a\u003e\n``` clojure\n(with-transaction this f)\n```\nFunction.\n\nWrap a function `f` in a database transaction using `this`.\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/db/adapter.clj#L7-L7\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n-----\n# \u003ca name=\"com.thirstysink.pgmq-clj.db.adapters.hikari-adapter\"\u003ecom.thirstysink.pgmq-clj.db.adapters.hikari-adapter\u003c/a\u003e\n\n\n\n\n\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.db.adapters.hikari-adapter/-\u003epgobject\"\u003e`-\u003epgobject`\u003c/a\u003e\n``` clojure\n(-\u003epgobject x)\n```\nFunction.\n\nTransforms Clojure data to a PGobject `x` that contains the data as\n  JSON. PGObject type defaults to `jsonb` but can be changed via\n  metadata key `:pgtype`\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/db/adapters/hikari_adapter.clj#L79-L87\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.db.adapters.hikari-adapter/\u003c-pgobject\"\u003e`\u003c-pgobject`\u003c/a\u003e\n``` clojure\n(\u003c-pgobject v)\n```\nFunction.\n\nTransform PGobject `v` containing `json` or `jsonb` value to Clojure data.\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/db/adapters/hikari_adapter.clj#L89-L99\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.db.adapters.hikari-adapter/ensure-pgmq-extension\"\u003e`ensure-pgmq-extension`\u003c/a\u003e\n``` clojure\n(ensure-pgmq-extension adapter)\n```\nFunction.\n\nChecks the database to verify that the `pgmq` extension is installed\n  using the `adapter`. If it is not then it will throw an exception.\n  Example:\n  (hikari/ensure-pgmq-extension adapter)\n  ;; =\u003e nil\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/db/adapters/hikari_adapter.clj#L121-L131\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.db.adapters.hikari-adapter/make-hikari-adapter\"\u003e`make-hikari-adapter`\u003c/a\u003e\n``` clojure\n(make-hikari-adapter config)\n```\nFunction.\n\nCreate a new [`HikariAdapter`](#com.thirstysink.pgmq-clj.db.adapters.hikari-adapter/hikariadapter) instance. The argument `config`\n  provides database connection values. See https://github.com/tomekw/hikari-cp\n  for additional details on the configuration options.\n\n  | Setting           | Description                                                                                                  |\n  | :---------------- | :----------------------------------------------------------------------------------------------------------- |\n  | jdbc-url          | This property sets the JDBC connection URL.                                                                            |\n  | username          | This property sets the default authentication username used when obtaining Connections from the underlying driver.     |\n  | password          | This property sets the default authentication password used when obtaining Connections from the underlying driver.     |\n  | maximum-pool-size | This property controls the maximum size that the pool is allowed to reach, including both idle and in-use connections. |\n  | minimum-idle      | This property controls the minimum number of idle connections that HikariCP tries to maintain in the pool.             |\n\n  Example:\n  ```clojure\n  (def adapter (hikari/make-hikari-adapter {:jdbc-url \"jdbc:postgresql://0.0.0.0:5432/postgres\" :username \"postgres\" :password \"postgres\"}))\n  ;; =\u003e #'user/adapter\n  ```\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/db/adapters/hikari_adapter.clj#L133-L160\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n-----\n# \u003ca name=\"com.thirstysink.pgmq-clj.instrumentation\"\u003ecom.thirstysink.pgmq-clj.instrumentation\u003c/a\u003e\n\n\n\n\n\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.instrumentation/disable-instrumentation\"\u003e`disable-instrumentation`\u003c/a\u003e\n``` clojure\n(disable-instrumentation)\n(disable-instrumentation ns)\n```\nFunction.\n\nDisables `clojure.specs.alpha` specs instrumentation. If\n  no namespace `ns` is provided it will disable instrumentation\n  for [`com.thirstysink.pgmq-clj.core`](#com.thirstysink.pgmq-clj.core).\n\n  [Learn more](https://github.com/clojure/spec.alpha)\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/instrumentation.clj#L26-L36\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.instrumentation/enable-instrumentation\"\u003e`enable-instrumentation`\u003c/a\u003e\n``` clojure\n(enable-instrumentation)\n(enable-instrumentation ns)\n```\nFunction.\n\nEnables `clojure.specs.alpha` specs instrumentation. If\n  no namespace `ns` is provided it will instrument\n  [`com.thirstysink.pgmq-clj.core`](#com.thirstysink.pgmq-clj.core).\n\n  [Learn more](https://github.com/clojure/spec.alpha)\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/instrumentation.clj#L15-L24\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.instrumentation/instrumentation-enabled?\"\u003e`instrumentation-enabled?`\u003c/a\u003e\n\n\n\n\nA flag that indicates if instrumentation is enabled.\n  This is determined by the value of the environment variable `PGMQCLJ_INSTRUMENTAION_ENABLED`.\n  If the environment variable is set, the value will be true; otherwise, false.\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/instrumentation.clj#L4-L8\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n-----\n# \u003ca name=\"com.thirstysink.pgmq-clj.json\"\u003ecom.thirstysink.pgmq-clj.json\u003c/a\u003e\n\n\n\n\n\n\n## \u003ca name=\"com.thirstysink.pgmq-clj.json/-\u003ejson\"\u003e`-\u003ejson`\u003c/a\u003e\n\n\n\n\nReturns a JSON-encoding String for the given Clojure object. Takes an\n  optional date format string that Date objects will be encoded with.\n\n  The default date format (in UTC) is: `yyyy-MM-dd'T'HH:mm:ss'Z'`\n\u003cp\u003e\u003csub\u003e\u003ca href=\"/blob/main/src/com/thirstysink/pgmq_clj/json.clj#L4-L9\"\u003eSource\u003c/a\u003e\u003c/sub\u003e\u003c/p\u003e\n\n-----\n\n\n# Specs\n\n---\n\n### com.thirstysink.pgmq-clj.core/delete-message\n```clojure\n(fspec :args (cat :adapter :com.thirstysink.pgmq-clj.specs/adapter :queue-name :com.thirstysink.pgmq-clj.specs/queue-name :msg-id :com.thirstysink.pgmq-clj.specs/msg-id) :ret boolean? :fn nil)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/header-key\n```clojure\n(or :string string? :keyword keyword?)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/is-unlogged\n```clojure\nboolean?\n```\n\n#### :com.thirstysink.pgmq-clj.specs/vt\n```clojure\n(instance? java.time.Instant %)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/msg-id\n```clojure\n(and number? pos?)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/timestamp\n```clojure\n(instance? java.time.Instant %)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/read-ct\n```clojure\nint?\n```\n\n---\n\n### com.thirstysink.pgmq-clj.core/read-message\n```clojure\n(fspec :args (cat :adapter :com.thirstysink.pgmq-clj.specs/adapter :queue-name :com.thirstysink.pgmq-clj.specs/queue-name :visibility_time :com.thirstysink.pgmq-clj.specs/visibility_time :quantity :com.thirstysink.pgmq-clj.specs/quantity :filter :com.thirstysink.pgmq-clj.specs/json) :ret :com.thirstysink.pgmq-clj.specs/message-records :fn nil)\n```\n\n#### :clojure.spec.alpha/kvs-\u003emap\n```clojure\n(conformer (zipmap (map :clojure.spec.alpha/k %) (map :clojure.spec.alpha/v %)) (map (fn [[k v]] #:clojure.spec.alpha{:k k, :v v}) %))\n```\n\n#### :com.thirstysink.pgmq-clj.specs/data\n```clojure\n(fn [x] (or (map? x) (vector? x) (string? x) (number? x) (boolean? x) (nil? x)))\n```\n\n#### :com.thirstysink.pgmq-clj.specs/message\n```clojure\n(fn [x] (or (map? x) (vector? x) (string? x) (number? x) (boolean? x) (nil? x)))\n```\n\n#### :com.thirstysink.pgmq-clj.specs/msg-ids\n```clojure\n(coll-of :com.thirstysink.pgmq-clj.specs/msg-id)\n```\n\n---\n\n### com.thirstysink.pgmq-clj.core/send-message-batch\n```clojure\n(fspec :args (cat :adapter :com.thirstysink.pgmq-clj.specs/adapter :queue-name :com.thirstysink.pgmq-clj.specs/queue-name :payload :com.thirstysink.pgmq-clj.specs/payload-objects :delay :com.thirstysink.pgmq-clj.specs/delay) :ret :com.thirstysink.pgmq-clj.specs/msg-ids :fn nil)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/created-at\n```clojure\n(fn [x] (fn* [] (instance? java.time.Instant x)))\n```\n\n#### :com.thirstysink.pgmq-clj.specs/headers\n```clojure\n(nilable (map-of :com.thirstysink.pgmq-clj.specs/header-key :com.thirstysink.pgmq-clj.specs/header-value :min-count 0))\n```\n\n---\n\n### com.thirstysink.pgmq-clj.core/archive-message\n```clojure\n(fspec :args (cat :adapter :com.thirstysink.pgmq-clj.specs/adapter :queue-name :com.thirstysink.pgmq-clj.specs/queue-name :msg-ids :com.thirstysink.pgmq-clj.specs/msg-ids) :ret :com.thirstysink.pgmq-clj.specs/msg-ids :fn nil)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/queue-name\n```clojure\nvalid-queue-name?\n```\n\n#### :com.thirstysink.pgmq-clj.specs/is-partitioned\n```clojure\nboolean?\n```\n\n---\n\n### com.thirstysink.pgmq-clj.core/create-queue\n```clojure\n(fspec :args (cat :adapter :com.thirstysink.pgmq-clj.specs/adapter :queue-name :com.thirstysink.pgmq-clj.specs/queue-name) :ret nil :fn nil)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/non-empty-msg-ids\n```clojure\n(and :com.thirstysink.pgmq-clj.specs/msg-ids (complement empty?))\n```\n\n#### :com.thirstysink.pgmq-clj.specs/queue-result\n```clojure\n(coll-of :com.thirstysink.pgmq-clj.specs/queue-record)\n```\n\n---\n\n### com.thirstysink.pgmq-clj.core/pop-message\n```clojure\n(fspec :args (cat :adapter :com.thirstysink.pgmq-clj.specs/adapter :queue-name :com.thirstysink.pgmq-clj.specs/queue-name) :ret :com.thirstysink.pgmq-clj.specs/message-record :fn nil)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/visibility_time\n```clojure\n(and int? (\u003e= % 0))\n```\n\n---\n\n### com.thirstysink.pgmq-clj.core/delete-message-batch\n```clojure\n(fspec :args (cat :adapter :com.thirstysink.pgmq-clj.specs/adapter :queue-name :com.thirstysink.pgmq-clj.specs/queue-name :msg-ids :com.thirstysink.pgmq-clj.specs/non-empty-msg-ids) :ret :com.thirstysink.pgmq-clj.specs/msg-ids :fn nil)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/payload-objects\n```clojure\n(coll-of :com.thirstysink.pgmq-clj.specs/payload-object)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/payload-object\n```clojure\n(keys :req-un [:com.thirstysink.pgmq-clj.specs/data :com.thirstysink.pgmq-clj.specs/headers])\n```\n\n#### :com.thirstysink.pgmq-clj.specs/adapter\n```clojure\n(satisfies? Adapter %)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/delay\n```clojure\nint?\n```\n\n---\n\n### com.thirstysink.pgmq-clj.core/drop-queue\n```clojure\n(fspec :args (cat :adapter :com.thirstysink.pgmq-clj.specs/adapter :queue-name :com.thirstysink.pgmq-clj.specs/queue-name) :ret boolean? :fn nil)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/message-record\n```clojure\n(keys :req-un [:com.thirstysink.pgmq-clj.specs/msg-id :com.thirstysink.pgmq-clj.specs/read-ct :com.thirstysink.pgmq-clj.specs/enqueued-at :com.thirstysink.pgmq-clj.specs/vt :com.thirstysink.pgmq-clj.specs/message] :opt-un [:com.thirstysink.pgmq-clj.specs/headers])\n```\n\n---\n\n### com.thirstysink.pgmq-clj.core/list-queues\n```clojure\n(fspec :args (cat :adapter :com.thirstysink.pgmq-clj.specs/adapter) :ret :com.thirstysink.pgmq-clj.specs/queue-result :fn nil)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/header-value\n```clojure\n(or :string string? :number number? :list (coll-of (or :string string? :number number?)))\n```\n\n#### :com.thirstysink.pgmq-clj.specs/enqueued-at\n```clojure\n(instance? java.time.Instant %)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/json\n```clojure\n(fn [x] (or (map? x) (vector? x) (string? x) (number? x) (boolean? x) (nil? x)))\n```\n\n---\n\n### com.thirstysink.pgmq-clj.core/send-message\n```clojure\n(fspec :args (cat :adapter :com.thirstysink.pgmq-clj.specs/adapter :queue-name :com.thirstysink.pgmq-clj.specs/queue-name :payload :com.thirstysink.pgmq-clj.specs/payload-object :delay :com.thirstysink.pgmq-clj.specs/delay) :ret :com.thirstysink.pgmq-clj.specs/msg-id :fn nil)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/queue-record\n```clojure\n(keys :req-un [:com.thirstysink.pgmq-clj.specs/queue-name :com.thirstysink.pgmq-clj.specs/is-partitioned :com.thirstysink.pgmq-clj.specs/is-unlogged :com.thirstysink.pgmq-clj.specs/created-at])\n```\n\n#### :com.thirstysink.pgmq-clj.specs/quantity\n```clojure\n(and int? (\u003e % 0))\n```\n\n---\n\n### com.thirstysink.pgmq-clj.core/purge-queue\n```clojure\n(fspec :args (cat :adapter :com.thirstysink.pgmq-clj.specs/adapter :queue-name :com.thirstysink.pgmq-clj.specs/queue-name) :ret integer? :fn nil)\n```\n\n#### :com.thirstysink.pgmq-clj.specs/message-records\n```clojure\n(coll-of :com.thirstysink.pgmq-clj.specs/mesage-record)\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frlperez%2Fpgmq-clj","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Frlperez%2Fpgmq-clj","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Frlperez%2Fpgmq-clj/lists"}