caml-list - the Caml user's mailing list
 help / color / mirror / Atom feed
* [Caml-list] Re:  New Features (Common Database Interface)
@ 2003-02-14 22:35 Matt Boyd
  2003-02-15 13:56 ` cashin
  0 siblings, 1 reply; 2+ messages in thread
From: Matt Boyd @ 2003-02-14 22:35 UTC (permalink / raw)
  To: caml-list

[-- Attachment #1: Type: text/plain, Size: 338 bytes --]


This is what I've been using.  It has been useful for creating a common
database interface that, at least, meets my basic needs.  I've written
bindings for ODBC, PostgreSQL, and Sybase(dblib).  The bindparam stuff
hasn't been worked on too much, but I haven't really needed it.  

If anyone thinks this is a starting point, let me know.

[-- Attachment #2: camlDB.mli --]
[-- Type: text/plain, Size: 11817 bytes --]


(**
  {b Caml Database Interface}

  Common interface for connecting to databases.
*)


(** {3 Exceptions} *)

exception End_of_rows
(** Raised when query results ends. *)


exception Row_failure of string * string
(** 
  {b Row_failure ({e table}, {e row-as-string})}
  {ul
    {li {e table}:  Table query failed.}
    {li {e row-as-string}:  Actual row contents changed to a string}}
*)

(** {3 Data Types} *)

(** {4 Date and Time Types} *)

(** Basic date components *)
type date = {
    year : int;
    month : int;
    day : int
  } 

(** Basic time components *)
type time = {
    hour : int;
    minute : int;
    second : int
  } 

(** Database timestamp type *)
type timestamp = {
    date : date;
    time : time;
    fraction : int
  } 

(** {4 Fields and rows} *)

(** Database field data types *)
type data = 
  | Null 
  | String of string
  | Integer of int
  | Float of float
  | Date of date
  | Time of time
  | Timestamp of timestamp
(** A row is a list of fields *)
type row = data list

(** {4 Conversion to String} *)

val string_of_date : date -> string
val string_of_time : time -> string
val string_of_timestamp : timestamp -> string
val string_of_data : data -> string
val string_of_row : row -> string
val raise_row_failure : string -> row -> 'a
(** 
  {b raise_row_failure {e table row}}
  {ul
    {li {e table}:  Name of the table}
    {li {e row}:  Row that was actually retrieved}}
  @raise Row_failure Raised when this function is called.
  @return
    Nothing.  Raises {e Row_failure} with the parameters.
*)

(** {4 Conversion from Unix Time} *)

val timestamp_of_unix_time : float -> timestamp
val date_of_unix_time : float -> date
val time_of_unix_time : float -> time

(** {4 Conversion to Unix Time} *)

val unix_time : Unix.tm -> float
val unix_time_of_timestamp : timestamp -> float
val unix_time_of_date : date -> float
val unix_time_of_time : time -> float

(** Bind parameter direction *)
type bind_io =
  | Input
  | Output

(** {3 Caml Database Signatures} *)

(** Basic database interface *)
module type ELT = 
  sig
    (** 
      Implement this signature for a type of database and you can 
      use it interchangeably in applications.
    *)

    type args         (** Connection arguments *)
    type connection   (** Connection type *)
    type result       (** Result set *)

    (** {5 Connection functions} *)

    val connect : args -> connection
    (**
      {b connect {e connection-args}}
      {ul
        {li {e connection-args}:  Arguments needed to initiate a connection}}
      @return 
        A connection.  An exception that is database-specific will be 
        raised if a connection cannot be established.
    *)
    val disconnect : connection -> unit
    (**
      {b disconnect {e connection}}
      {ul
        {li {e connection}:  A valid connection}}
      @return
        Nothing.  If the connection has already been disconnected, then
        it's unspecified how this will behave (It may just return or it
        may raise an exception)
    *)
    val useConn : (connection -> 'a) -> args -> 'a
    (**
      {b useConn {e conn-function conn-args}}
      {ul
        {li {e conn-function}:  A function which takes a {e connection}
          argument}
        {li {e conn-args}:  Arguments to the {e connect} function which
          can be used to create a connection.}}
      @return
        The result of applying {e conn-function} to the connection established
        with {e conn-args}. 
    *)

    (** {5 Query functions} *)

    val direct : string -> connection -> unit 
    (**
      {b direct {e query connection}}
      {ul
        {li {e query}:  The query string.}
        {li {e connection}:  The connection.}}
      @return 
        Nothing.  Executes the query.  Any results will be
        discarded.
    *)
    val execute : string -> connection -> result 
    (**
      {b execute {e query connection}}
      {ul
        {li {e query}:  Query string.}
        {li {e connection}:  Connection}}
      @return
        A result set.  The query is executed and the results are returned
        as a result type.  
    *)
    val cancel : result -> unit
    (**
      {b cancel {e result}}
      {ul
        {li {e result}:  The result set.}}
      @return
        Nothing.  The result information is cleaned-up if there is any.
        This may raise an exception or may not.  In most cases it should
        just return even if the result has already been cancelled.
    *)
    val useQuery : (result -> 'a) -> string -> connection -> 'a
    (**
      {b useQuery {e result-fun query conn}}
      {ul
        {li {e result-fun}:  
          Function to pass the result returned by executing {e query}
          using {e connection}.}
        {li {e query}:  The query string}
        {li {e conn}:  The connection.}}
      @return
        The result of applying {e result-fun} to the result returned by
        executing {e query} with {e conn}.
    *)

    (** {5 Row Information Functions} *)

    val numberOfColumns : result -> int
    (**
      {b numberOfColumns {e result}}
      {ul {li {e result}:  The result set.}}
      @return The number of columns in each row
    *)
    val numberOfRows : result -> int
    (**
      {b numberOfRows {e result}}
      {ul {li {e result}:  The result set.}}
      @return the number of rows returned by the query.
    *)
    val nextRow : result -> row
    (**
      {b nextRow {e result}}
      {ul {li {e result}:  The result set.}}
      @return the next row in the set of rows.
    *)

    (** {5 Higher-level Functions} *)

    val iter : string -> (row -> unit) -> connection -> unit
    (** 
      {b iter {e query iter-fun conn}}
      {ul
        {li {e query}:  The query string.}
        {li {e iter-fun}:  
          Function to execute for each row in the query set.}
        {li {e conn}:  The connection}}
      @return
        Nothing.  Executes {e query} and then iterates over the 
        rows returned with {e iter-fun}.
    *)

    val map : string -> (row -> 'b) -> connection -> 'b list
    (**
      {b map {e query map-fun conn}}
      {ul
        {li {e query}:  The query string.}
        {li {e map-fun}:  Function to run on each row.}
        {li {e conn}:  Connection to use.}}
      @return
        A list of all elements returned by applying {e map-fun} to
        every row returned by executing {e query}.
    *)

    val stream : string -> connection -> data Stream.t
    (**
      {b stream {e query conn}}
      {ul
        {li {e query}:  The query string.}
        {li {e conn}:  Connection.}}
      @return
        A stream that will return the next row when used with
        {e Stream.next}.
    *)

  end

(** Bind Signature Interface *)
module type BIND = 
  sig
    type result

    (** Bind result columns *)
    module Col : 
      sig
        type t

        val bind : result -> int -> data ->t
        (**
          {b bind {e result column data}}
          {ul
            {li {e result}:  Result returned by executing a query.}
            {li {e column}:  Column number.}
            {li {e data}:  Initialized data value.}}
          @return A column binding value.
        *)

        val free : t -> unit
        (**
          {b free {e binding}}
          {ul {li {e binding}:  Binding to free}}
          @return Nothing.  The binding is undone.
        *)

        val replace : t -> data -> unit
        (**
          {b replace {e binding data}}
          {ul
            {li {e binding}:  Binding to use.}
            {li {e data}:  Data to replace in the binding.}}
          @return.  Nothing.  Replace the data in {e binding}
        *)

        val get : t -> data
        (**
          {b get {e binding}}
          {ul {li {e binding}:  Binding to extract from.}}
          @return.  The information contained in {e binding}
        *)

        val use : (t -> 'a) -> result -> int -> data -> 'a
        (**
          {b use {e bind-fun result col init}}
          {ul
            {li {e bind-fun}:  Function which uses binding.}
            {li {e result}:  Used to create binding.}
            {li {e col}:  Used to create binding.}
            {li {e init}:  Initial binding value.}}
          @return
            The result returned by applying {e bind-fun} to
            the binding created with the other parameters.
        *)
      end

    (** Bind query parameters *)
    module Param : 
      sig
        type t

        val bind : result -> int -> bind_io -> data ->t
        (**
          {b bind {e result param-num bind-dir data}}
          {ul 
            {li {e result}:  The query result set.}
            {li {e param-num}:  The parameter number to bind to.}
            {li {e bind-dir}:  The parameter direction.}
            {li {e data}:  Initial binding value.}}
          @return  A bound value.
        *)

        val free : t -> unit
        (**
          {b free {e binding}}
          {ul {li {e binding}:  Binding to free}}
          @return Nothing.  The binding is undone.
        *)

        val replace : t -> data -> unit
        (**
          {b replace {e binding data}}
          {ul
            {li {e binding}:  Binding to use.}
            {li {e data}:  Data to replace in the binding.}}
          @return.  Nothing.  Replace the data in {e binding}
        *)

        val get : t -> data
        (**
          {b get {e binding}}
          {ul {li {e binding}:  Binding to extract from.}}
          @return.  The information contained in {e binding}
        *)

        val use : (t -> 'a) -> result -> int -> bind_io -> data -> 'a
        (**
          {b use {e bind-fun result param-num bind-dir init}}
          {ul
            {li {e bind-fun}:  Function which uses binding.}
            {li {e result}:  Used to create binding.}
            {li {e param-num}:  Used to create binding.}
            {li {e bind-dir}:  The parameter direction.}
            {li {e init}:  Initial binding value.}}
          @return
            The result returned by applying {e bind-fun} to
            the binding created with the other parameters.
        *)
      end
  end

(** {4 Row Manipulation Signatures} *)

(** Row Constructor *)
module type ROW =
  sig
    type t
    val of_row : row -> t
    (** 
      {b of_row {e row}}
      {ul {li {e row}:  Row to convert.}}
      @raise Row_failure if it cannot convert the row.
      @return the result of constructing {e t} from a {e row}.
    *)
  end

(** Row Stream Interface *)
module type ROW_STREAM =
  sig
    type t
    type connection
    type result
    val of_row : row -> t
    (** 
      {b of_row {e row}}
      {ul {li {e row}:  Row to convert.}}
      @raise Row_failure if it cannot convert the row.
      @return the result of constructing {e t} from a {e row}.
    *)

    val next_row : result -> t
    (**
      {b next_row {e result}}
      {ul
        {li {e result};  Result to convert.}}
      @return the construction of a {e t} from the next row in {e result}.
    *)

    val iter : string -> (t -> unit) -> connection -> unit
    val map : string -> (t -> 'a) -> connection -> 'a list
    val stream : string -> connection -> t Stream.t
    val fold : string -> (t -> 'a -> 'a) -> 'a -> connection -> 'a
  end

module MakeRow (Elt : ELT)(Row : ROW) : 
  ROW_STREAM 
    with type t = Row.t 
     and type connection = Elt.connection
     and type result = Elt.result


^ permalink raw reply	[flat|nested] 2+ messages in thread

* Re: [Caml-list] Re:  New Features (Common Database Interface)
  2003-02-14 22:35 [Caml-list] Re: New Features (Common Database Interface) Matt Boyd
@ 2003-02-15 13:56 ` cashin
  0 siblings, 0 replies; 2+ messages in thread
From: cashin @ 2003-02-15 13:56 UTC (permalink / raw)
  To: caml-list

Thanks to Matt for sharing the code, by the way.

Matt Boyd <mattwb@alve.com> writes:

...
> exception End_of_rows
> (** Raised when query results ends. *)

I didn't really read the code, but I noticed the End_of_rows exception
and I'd like to know folks' opinions about it.

I know that's analogous to End_of_file, but since an infinite number
of rows would be a lot more exceptional than a finite number, isn't
this a strange use of exceptions?  I would guess that iteration or
recursion would be more efficient and expressive.

-- 
--Ed L Cashin            |   PGP public key:
  ecashin@uga.edu        |   http://noserose.net/e/pgp/

-------------------
To unsubscribe, mail caml-list-request@inria.fr Archives: http://caml.inria.fr
Bug reports: http://caml.inria.fr/bin/caml-bugs FAQ: http://caml.inria.fr/FAQ/
Beginner's list: http://groups.yahoo.com/group/ocaml_beginners


^ permalink raw reply	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2003-02-15 13:56 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2003-02-14 22:35 [Caml-list] Re: New Features (Common Database Interface) Matt Boyd
2003-02-15 13:56 ` cashin

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).