Giter Site home page Giter Site logo

balat / pgocaml Goto Github PK

View Code? Open in Web Editor NEW

This project forked from darioteixeira/pgocaml

0.0 0.0 0.0 1.23 MB

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.

License: Other

OCaml 99.23% Common Lisp 0.77%

pgocaml's Introduction

PG'OCaml is a set of OCaml bindings for the PostgreSQL database.

Please note that this is not the first or only PGSQL bindings for OCaml. Here are the others which you may want to consider:

  • postgresql-ocaml PostgreSQL-OCaml by Markus Mottl

  • ocamlodbc ODBC bindings by Max Guesdon which can be used to access PostgreSQL

  • ocamldbi a Perl-like DBI layer by the present author

PG'OCAML is different than the above bindings:

  • It ISN'T just a wrapper around the C libpq library. Instead it's a pure OCaml library which talks the frontend/backend protocol directly with the database.

  • It has a PPX (macro) layer which lets you write SQL statements directly in your code, TYPE SAFE at compile time, with TYPE INFERENCE into the SQL, and using the full PostgreSQL SQL grammar (sub-selects, PG-specific SQL, etc.). But the flip side of this is that you need to have access to the database at compile time, so the type checking magic can be done; also if you change the database schema, you will need to recompile your code to check it is still correctly typed.

  • (A minor point) - It requires PostgreSQL >= 7.4. The default interface (PGOCaml) provided is synchronous. But it also supports any asynchronous interface that implements the PGOCaml_generic.THREAD signature.

  • It doesn't work with other databases, nor will it ever work with other databases.

Usage

PG'OCaml uses environment variables (or in-code parameters, which are [ill advised] (https://hackernoon.com/how-to-use-environment-variables-keep-your-secret-keys-safe-secure-8b1a7877d69c)) to connect to your database both at compile-time and at runtime.

Variable Default Additional information
PGHOST If this starts with a / or is unspecified, PG'OCaml assumes you're specifying a Unix domain socket.
PGPORT 5432 This is also the default PostgreSQL port.
PGUSER The username of the current user, or postgres if that can't be found.
PGDATABASE falls back on PGUSER
PGPASSWORD empty string
PGPROFILING no profiling Indicates the file to write profiling information to. If it doesn't exist, don't profile
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.
PGCUSTOM_CONVERTERS_CONFIG nothing Points to a file containing custom type conversions

Using the PPX

The PPX aims to be more or less a carbon copy of the former extension.

let () =
  let dbh = PGOCaml.connect () in
  let insert name salary =
    [%pgsql dbh "insert into employees (name, salary) VALUES ($name, $salary)"]
  in
  ignore(insert "Chris" 1_000.0);
  let get name =
    [%pgsql dbh "select salary from employees where name = $name"]
  in
  let () = [%pgsql dbh
      "execute"
      "CREATE TEMP TABLE IF NOT EXISTS employees (
        name TEXT PRIMARY KEY,
        salary FLOAT)"]
  in
  let name = "Chris" in
  let salary = get name
    |> List.hd
    |> function
        | Some(x) -> x
        | None -> raise(Failure "The database is probably broken.")
  in
  Printf.printf "%s's salary is %.02f\n" name salary;
  PGOCaml.close(dbh)

The PPX allows you to specify that queries returning results should be returned as objects, rather than tuples.

let%lwt res =
  [%pgsql.object dbh "SELECT * FROM employees"]
in
List.iter
  (fun row ->
    Printf.printf "%s makes $%f\n" row#name row#salary)
  res

The PPX now also supports ${...} expansions.

(* where [e] is a row returned by a [pgsql.object] query *)
let%lwt incr_sal e =
  [%pgsql dbh "UPDATE employees SET salary = ${e#salary +. 1.0}"]

You may wish to print all the fields of an object for debugging purposes.

let%lwt rows = [%pgsql.object dbh "show" "SELECT * FROM employees"] in
List.iter
  (fun row -> print_endline row#show)
  rows

The above code will not work if one of the selected fields is named show. The PPX allows one to explicitly name the pretty-printer method as follows:

let%lwt rows = [%pgsql.object dbh "show=pp" "SELECT * FROM employees"] in
List.iter
  (fun row -> print_endline row#pp)
  rows

It's important to note that the show directive causes values to be printed in the same format used by the Postgres API, so things like Calendar.t values and custom converters (see below) may not work as expected.

Custom Type Conversions

Custom serializers and deserializers may be provided in a configuration file specified by PGCUSTOM_CONVERTERS_CONFIG (see above). An example configuration file follows:

( ( ( Or
      ( (Rule (typnam userid)) ; userid is a fully abstract type
        (Rule (colnam userid))
      )
    )
    ( (serialize Userid.to_string)
      (deserialize Userid.from_string)
    )
  )
  ( ( Or
      ( (Rule (typnam cash_money)) ; for strings beginning with a $ and possibly needing to be trimmed
        (And ; there exists a column elsewhere also named salary, but it has a different type
          ( (Rule (typnam float))
            (Rule (colnam salary))
          )
        )
      )
    )
    ( (serialize "fun x -> String.(sub x 1 (length x - 1)) |> String.trim")
      (deserialize "fun x -> \"$\" ^ x")
    )
  )
)

In case you're working on a large project, and don't want to write many convoluted rules to play nicely with your existing database structure, you can selectively enable custom serialization for individual queries:

let rows =
  [%pgsql.object
    dbh
    "load_custom_from=tests_ppx/config.sexp"
    "show"
    "SELECT * FROM customtable"]
in
...

PG'OCaml's PPX is not given type information by the compiler, so it will sometimes have trouble figuring the correct types for arguments. While one may find a parameter's serializer based in its name, this is not ideal, particularly when using ${...} parameters. In cases like this, you may use a syntax similar to OCaml's native type constraint:

let () = [%pgsql dbh "INSERT INTO users VALUES ${u : userid}"] in
...

Please note that the ${u : userid} above will NOT be compiled into an OCaml type constraint. Its only effect is to supply userid as the typnam to the serializer resolver.


PG'OCaml (C) Copyright 2005-2009 Merjis Ltd, Richard W.M. Jones ([email protected]) and other authors (see CONTRIBUTORS.txt for details).

This software is distributed under the GNU LGPL with OCaml linking exception. Please see the file COPYING.LIB for full license.


For an example, please see tests

pgocaml's People

Contributors

darioteixeira avatar rgrinberg avatar chrismamo1 avatar vouillon avatar zbroyar avatar jaapb avatar vbmithr avatar kit-ty-kate avatar rwmjones avatar ghuysmans avatar maxtori avatar j0sh avatar eras avatar tizoc avatar bikallem avatar lepoetemaudit avatar rittere avatar et7f3 avatar johnlepikhin avatar mfp avatar vasilisp avatar balat avatar kuy avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.