{"id":13726265,"url":"https://github.com/darioteixeira/pgocaml","last_synced_at":"2025-04-09T23:29:46.889Z","repository":{"id":1969500,"uuid":"13802185","full_name":"darioteixeira/pgocaml","owner":"darioteixeira","description":"PG'OCaml provides an interface to PostgreSQL databases for OCaml applications. It uses Camlp4 to extend the OCaml syntax, enabling one to directly embed SQL statements inside the OCaml code.","archived":false,"fork":false,"pushed_at":"2025-03-14T00:15:59.000Z","size":1289,"stargazers_count":161,"open_issues_count":49,"forks_count":36,"subscribers_count":6,"default_branch":"master","last_synced_at":"2025-03-14T01:25:54.018Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"OCaml","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"other","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/darioteixeira.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.txt","contributing":null,"funding":null,"license":"LICENSE.txt","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null}},"created_at":"2013-10-23T12:32:12.000Z","updated_at":"2025-03-14T00:16:03.000Z","dependencies_parsed_at":"2024-01-06T02:03:32.864Z","dependency_job_id":"377f23b6-33d0-48c4-8b6a-b0e4266c9938","html_url":"https://github.com/darioteixeira/pgocaml","commit_stats":{"total_commits":233,"total_committers":29,"mean_commits":8.03448275862069,"dds":0.6008583690987124,"last_synced_commit":"ef199d2861826ba0248c21700f7838d572075570"},"previous_names":[],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darioteixeira%2Fpgocaml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darioteixeira%2Fpgocaml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darioteixeira%2Fpgocaml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/darioteixeira%2Fpgocaml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/darioteixeira","download_url":"https://codeload.github.com/darioteixeira/pgocaml/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248129181,"owners_count":21052525,"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":[],"created_at":"2024-08-03T01:02:57.480Z","updated_at":"2025-04-09T23:29:46.854Z","avatar_url":"https://github.com/darioteixeira.png","language":"OCaml","funding_links":[],"categories":["OCaml"],"sub_categories":[],"readme":"# PG'OCaml is a set of OCaml bindings for the PostgreSQL database.\n\nPlease note that this is not the first or only PGSQL bindings for\nOCaml. Here are the others which you may want to consider:\n\n* [postgresql-ocaml](https://mmottl.github.io/postgresql-ocaml/)\nPostgreSQL-OCaml by Markus Mottl\n\n* [ocamlodbc](http://home.gna.org/ocamlodbc/)\nODBC bindings by Max Guesdon which can be used to access PostgreSQL\n\n* [ocamldbi](http://download.savannah.nongnu.org/releases/modcaml/) a Perl-like\nDBI layer by the present author\n\nPG'OCAML is different than the above bindings:\n\n* It ISN'T just a wrapper around the C libpq library.  Instead it's a pure\nOCaml library which talks the frontend/backend protocol directly with the\ndatabase.\n\n* It has a PPX (macro) layer which lets you write SQL statements directly in your\ncode, TYPE SAFE at compile time, with TYPE INFERENCE into the SQL, and using\nthe full PostgreSQL SQL grammar (sub-selects, PG-specific SQL, etc.).  But\nthe flip side of this is that you need to have access to the database at\n_compile_ time, so the type checking magic can be done; also if you change\nthe database schema, you will need to recompile your code to check it is\nstill correctly typed.\n\n* (A minor point) - It requires PostgreSQL \u003e= 7.4. The default interface\n(`PGOCaml`) provided is synchronous. But it also supports any asynchronous\ninterface that implements the `PGOCaml_generic.THREAD` signature.\n\n* It doesn't work with other databases, nor will it ever work with other\ndatabases.\n\n# Usage\n\nPG'OCaml uses environment variables (or in-code parameters, which are [ill advised]\n(https://hackernoon.com/how-to-use-environment-variables-keep-your-secret-keys-safe-secure-8b1a7877d69c))\nto connect to your database both at compile-time and at runtime.\n\n| Variable      | Default       | Additional information |\n| ------------- | ------------- | ---------------------- |\n| `PGHOST`      | | If this starts with a `/` or is unspecified, PG'OCaml assumes you're specifying a Unix domain socket. |\n| `PGPORT`      | `5432`        | This is also the default PostgreSQL port. |\n| `PGUSER`      | The username of the current user, or `postgres` if that can't be found. | |\n| `PGDATABASE`  | falls back on `PGUSER` | |\n| `PGPASSWORD`  | empty string  | |\n| `PGPROFILING` | no profiling  | Indicates the file to write profiling information to. If it doesn't exist, don't profile |\n| `COMMENT_SRC_LOC` | `no`      | If set to `yes`, `1`, or `on`, PG'OCaml will append a comment to each query indicating where it appears in the OCaml source code. This can be useful for logging. |\n| `PGCUSTOM_CONVERTERS_CONFIG` | nothing | Points to a file containing custom type conversions |\n\n# Using the PPX\n\nThe PPX aims to be more or less a carbon copy of the former extension.\n\n```ocaml\nlet () =\n  let dbh = PGOCaml.connect () in\n  let insert name salary =\n    [%pgsql dbh \"insert into employees (name, salary) VALUES ($name, $salary)\"]\n  in\n  ignore(insert \"Chris\" 1_000.0);\n  let get name =\n    [%pgsql dbh \"select salary from employees where name = $name\"]\n  in\n  let () = [%pgsql dbh\n      \"execute\"\n      \"CREATE TEMP TABLE IF NOT EXISTS employees (\n        name TEXT PRIMARY KEY,\n        salary FLOAT)\"]\n  in\n  let name = \"Chris\" in\n  let salary = get name\n    |\u003e List.hd\n    |\u003e function\n        | Some(x) -\u003e x\n        | None -\u003e raise(Failure \"The database is probably broken.\")\n  in\n  Printf.printf \"%s's salary is %.02f\\n\" name salary;\n  PGOCaml.close(dbh)\n```\n\nThe PPX allows you to specify that queries returning results should be returned as\nobjects, rather than tuples.\n\n```ocaml\nlet%lwt res =\n  [%pgsql.object dbh \"SELECT * FROM employees\"]\nin\nList.iter\n  (fun row -\u003e\n    Printf.printf \"%s makes $%f\\n\" row#name row#salary)\n  res\n```\n\nThe PPX now also supports `${...}` expansions.\n\n```ocaml\n(* where [e] is a row returned by a [pgsql.object] query *)\nlet%lwt incr_sal e =\n  [%pgsql dbh \"UPDATE employees SET salary = ${e#salary +. 1.0}\"]\n```\n\nYou may wish to print all the fields of an object for debugging purposes.\n\n```ocaml\nlet%lwt rows = [%pgsql.object dbh \"show\" \"SELECT * FROM employees\"] in\nList.iter\n  (fun row -\u003e print_endline row#show)\n  rows\n```\n\nThe above code will not work if one of the selected fields is named `show`. The\nPPX allows one to explicitly name the pretty-printer method as follows:\n\n```ocaml\nlet%lwt rows = [%pgsql.object dbh \"show=pp\" \"SELECT * FROM employees\"] in\nList.iter\n  (fun row -\u003e print_endline row#pp)\n  rows\n```\n\nIt's important to note that the `show` directive causes values to be printed in\nthe same format used by the Postgres API, so things like `Calendar.t` values and\ncustom converters (see below) may not work as expected.\n\n## Custom Type Conversions\n\nCustom serializers and deserializers may be provided in a configuration file\nspecified by `PGCUSTOM_CONVERTERS_CONFIG` (see above). An example configuration\nfile follows:\n\n```lisp\n( ( ( Or\n      ( (Rule (typnam userid)) ; userid is a fully abstract type\n        (Rule (colnam userid))\n      )\n    )\n    ( (serialize Userid.to_string)\n      (deserialize Userid.from_string)\n    )\n  )\n  ( ( Or\n      ( (Rule (typnam cash_money)) ; for strings beginning with a $ and possibly needing to be trimmed\n        (And ; there exists a column elsewhere also named salary, but it has a different type\n          ( (Rule (typnam float))\n            (Rule (colnam salary))\n          )\n        )\n      )\n    )\n    ( (serialize \"fun x -\u003e String.(sub x 1 (length x - 1)) |\u003e String.trim\")\n      (deserialize \"fun x -\u003e \\\"$\\\" ^ x\")\n    )\n  )\n)\n```\n\nIn case you're working on a large project, and don't want to write many\nconvoluted rules to play nicely with your existing database structure, you can\nselectively enable custom serialization for individual queries:\n\n```ocaml\nlet rows =\n  [%pgsql.object\n    dbh\n    \"load_custom_from=tests_ppx/config.sexp\"\n    \"show\"\n    \"SELECT * FROM customtable\"]\nin\n...\n```\n\nPG'OCaml's PPX is not given type information by the compiler, so it will\nsometimes have trouble figuring the correct types for arguments. While one may\nfind a parameter's serializer based in its name, this is not ideal,\nparticularly when using `${...}` parameters. In cases like this, you may use a\nsyntax similar to OCaml's native type constraint:\n\n```ocaml\nlet () = [%pgsql dbh \"INSERT INTO users VALUES ${u : userid}\"] in\n...\n```\n\nPlease note that the `${u : userid}` above will NOT be compiled into an OCaml\ntype constraint. Its only effect is to supply `userid` as the `typnam` to the\nserializer resolver.\n\n----------------------------------------------------------------------\n\nPG'OCaml (C) Copyright 2005-2009 Merjis Ltd, Richard W.M. Jones (rich@annexia.org)\nand other authors (see CONTRIBUTORS.txt for details).\n\nThis software is distributed under the GNU LGPL with OCaml linking\nexception.  Please see the file COPYING.LIB for full license.\n\n----------------------------------------------------------------------\n\nFor an example, please see [tests](https://github.com/darioteixeira/pgocaml/blob/master/tests/test_pgocaml_highlevel.ml)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarioteixeira%2Fpgocaml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdarioteixeira%2Fpgocaml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdarioteixeira%2Fpgocaml/lists"}