{"id":13392534,"url":"https://github.com/will/crystal-pg","last_synced_at":"2025-04-04T07:09:49.093Z","repository":{"id":31076775,"uuid":"34635730","full_name":"will/crystal-pg","owner":"will","description":"a postgres driver for crystal","archived":false,"fork":false,"pushed_at":"2024-07-24T12:02:26.000Z","size":403,"stargazers_count":463,"open_issues_count":35,"forks_count":77,"subscribers_count":17,"default_branch":"master","last_synced_at":"2024-10-04T21:32:05.394Z","etag":null,"topics":["crystal","postgres"],"latest_commit_sha":null,"homepage":"","language":"Crystal","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"bsd-3-clause","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/will.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG","contributing":"CONTRIBUTING.md","funding":null,"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}},"created_at":"2015-04-26T23:13:54.000Z","updated_at":"2024-09-20T17:45:33.000Z","dependencies_parsed_at":"2024-05-02T19:55:35.731Z","dependency_job_id":"6cbef07e-e794-4576-a88e-02ccb5e21753","html_url":"https://github.com/will/crystal-pg","commit_stats":null,"previous_names":[],"tags_count":47,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will%2Fcrystal-pg","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will%2Fcrystal-pg/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will%2Fcrystal-pg/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/will%2Fcrystal-pg/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/will","download_url":"https://codeload.github.com/will/crystal-pg/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247135147,"owners_count":20889421,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","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":["crystal","postgres"],"created_at":"2024-07-30T17:00:26.972Z","updated_at":"2025-04-04T07:09:49.072Z","avatar_url":"https://github.com/will.png","language":"Crystal","funding_links":[],"categories":["Database Drivers","Crystal","Database Drivers/Clients"],"sub_categories":[],"readme":"# crystal-pg\nA native, non-blocking Postgres driver for Crystal\n\n[![CI](https://github.com/will/crystal-pg/actions/workflows/ci.yml/badge.svg)](https://github.com/will/crystal-pg/actions/workflows/ci.yml)\n\n## usage\n\nThis driver now uses the `crystal-db` project. Documentation on connecting,\nquerying, etc, can be found at:\n\n* https://crystal-lang.org/docs/database/\n* https://crystal-lang.org/docs/database/connection_pool.html\n\n### shards\n\nAdd this to your `shard.yml` on a generated crystal project, \nand run `shards install`\n\n``` yml\ndependencies:\n  pg:\n    github: will/crystal-pg\n```\n\n### Example usage\n\n``` crystal\nrequire \"db\"\nrequire \"pg\"\n\nDB.open(\"postgres://user:pass@host:port/db_name?option1=a\u0026option2=b\") do |db|\n   ... use db ...\nend\n```\n\n### More\n\n`crystal-pg` also supports some functionality past the typical `crystal-db` usage:\n\n### Listen/Notify\n\nThere are two ways to listen for notifications. For docs on `NOTIFY`, please\nread \u003chttps://www.postgresql.org/docs/current/static/sql-notify.html\u003e.\n\n1. Any connection can be given a callback to run on notifications. However they\n   are only received when other traffic is going on.\n2. A special listen-only connection can be established for instant notification\n   processing with `PG.connect_listen`.\n\n``` crystal\n# see full example in examples/listen_notify.cr\nPG.connect_listen(\"postgres:///\", \"a\", \"b\") do |n| # connect and  listen on \"a\" and \"b\"\n  puts \"    got: #{n.payload} on #{n.channel}\"     # print notifications as they come in\nend\n```\n\n### Arrays\n\nCrystal-pg supports several popular array types. If you only need a 1\ndimensional array, you can cast down to the appropriate Crystal type:\n\n``` crystal\nPG_DB.query_one(\"select ARRAY[1, null, 3]\", \u0026.read(Array(Int32?))\n# =\u003e [1, nil, 3]\n\nPG_DB.query_one(\"select '{hello, world}'::text[]\", \u0026.read(Array(String))\n# =\u003e [\"hello\", \"world\"]\n```\n\n### Error Handling\nIt is possible to catch errors and notifications and pass them along to Crystal for further handling.\n```Crystal\nDB.connect(\"postgres:///\") do |cnn|\n  # Capture and print all exceptions\n  cnn.on_notice { |x| puts \"pgSQL #{x}\" }\n\n  # A function that raises exceptions\n  cnn.exec(\n    \u003c\u003c-SQL\n      CREATE OR REPLACE FUNCTION foo(IN str TEXT)\n        RETURNS VOID\n        LANGUAGE 'plpgsql'\n        AS $$\n          BEGIN\n            IF str = 'yes' THEN\n                    RAISE NOTICE 'Glad we agree!';\n            ELSE\n              RAISE EXCEPTION 'You know nothing John Snow!';\n            END IF;\n          END;\n        $$;\n    SQL\n  )\n\n  # Notice handling example\n  cnn.exec(\n    \u003c\u003c-SQL\n      SELECT foo('yes');\n    SQL\n  )\n  # =\u003e pgSQL NOTICE: Glad we agree!\n\n  # Exception handling example\n  cnn.exec(\n    \u003c\u003c-SQL\n      SELECT foo('no');\n    SQL\n  )\n  # =\u003e pgSQL ERROR: You know nothing John Snow!\n  #    Unhandled exception: You know nothing John Snow! (PQ::PQError)\n  #     from lib/pg/src/pq/connection.cr:203:7 in 'handle_error'\n  #     from lib/pg/src/pq/connection.cr:186:7 in 'handle_async_frames'\n  #     from lib/pg/src/pq/connection.cr:162:7 in 'read'\n  #     from lib/pg/src/pq/connection.cr:386:18 in 'expect_frame'\n  #     from lib/pg/src/pq/connection.cr:370:9 in 'read_next_row_start'\n  #     from lib/pg/src/pg/result_set.cr:39:8 in 'move_next'\n  #     from lib/pg/src/pg/statement.cr:39:13 in 'perform_exec'\n  #     from lib/db/src/db/statement.cr:82:14 in 'perform_exec_and_release'\n  #     from lib/db/src/db/statement.cr:68:7 in 'exec:args'\n  #     from lib/db/src/db/query_methods.cr:271:7 in 'exec'\n  #     from spec/cerebrum_spec.cr:84:3 in '__crystal_main'\n  #     from /usr/share/crystal/src/crystal/main.cr:97:5 in 'main_user_code'\n  #     from /usr/share/crystal/src/crystal/main.cr:86:7 in 'main'\n  #     from /usr/share/crystal/src/crystal/main.cr:106:3 in 'main'\n  #     from __libc_start_main\n  #     from _start\n  #     from ???\n```\n\n## Requirements\n\nCrystal-pg is [regularly tested on](https://github.com/will/crystal-pg/actions)\nthe Postgres versions the [Postgres project itself supports](https://www.postgresql.org/support/versioning/).\nSince it uses protocol version 3, older versions probably also work but are not guaranteed.\n\n## Supported Datatypes\n\n- text\n- boolean\n- int8, int4, int2\n- float4, float8\n- timestamptz, date, timestamp (but no one should use ts when tstz exists!)\n- json and jsonb\n- uuid\n- bytea\n- numeric/decimal (1)\n- varchar\n- regtype\n- geo types: point, box, path, lseg, polygon, circle, line\n- array types: int8, int4, int2, float8, float4, bool, text, numeric, timestamptz, date, timestamp\n- interval (2)\n\n1: A note on numeric: In Postgres this type has arbitrary precision. In this\n    driver, it is represented as a `PG::Numeric` which retains all precision, but\n    if you need to do any math on it, you will probably need to cast it to a\n    float first. If you need true arbitrary precision, you can optionally\n    require `pg_ext/big_rational` which adds `#to_big_r`, but requires that you\n    have LibGMP installed.\n\n2: A note on interval: A Postgres interval can not be directly mapped to a built\n    in Crystal datatype. Therfore we provide a `PG::Interval` type that can be converted to\n    `Time::Span` and `Time::MonthSpan`.\n\n# Authentication Methods\n\nBy default this driver will accept `scram-sha-256` and `md5`, as well as\n`trust`. However `cleartext` is disabled by default. You can control exactly\nwhich auth methods the client will accept by passing in a comma separated list\nto the `auth_methods` parameter, for example\n\n``` crystal\n DB.open(\"postgres://example.com/dbname?auth_methods=cleartext,md5,scram-sha-256\")\n```\n\n**DO NOT TURN `cleartext` ON UNLESS YOU ABSOLUTELY NEED IT!** Merely by having\nthis option enabled exposes a postgres client to downgrade man-in-the-middle\nattacks, even if the server is configured to not support cleartext. Even if you\nuse TLS, you are not safe unless you are fully verifying the server's cert, as\nthe attacker can terminate TLS and re-negotiate a connection with the server.\n\n\n```\nclient                     attacker                     server\n----------------------------------------------------------------------------\nI want to connect \\\n                   \\-\u003e  intercepts, forwards\n                        I want to connect \\\n                                           \\-----\u003e  receives connection request\n\n                                                  / I support scram and/or md5 only\n                        intercepts, sends      \u003c-/\n                     /  I only support cleartext\nreceives attacker \u003c-/\nclaiming server\nonly supports cleartext\nsends password because\ncleartext enabled \\\n                   \\-\u003e  receives clear password,\n                        negotiates scram/md5\n                        with real server      \\\n                                               \\--\u003e accepts scram/md5 auth\n\n```\n\nIt is a mistake for any driver to support cleartext by default, and it's a\nmistake that postgres continues to have this as an option at all.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwill%2Fcrystal-pg","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fwill%2Fcrystal-pg","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fwill%2Fcrystal-pg/lists"}