Crud1

[ Application | crud1.urp | crud.urs | crud.ur | crud1.ur ]

This example pulls together much of what we have seen so far. It involves a generic "admin interface" builder. That is, we have the Crud.Make functor, which takes in a description of a table and outputs a sub-application for viewing and editing that table.

The signature of Crud.Make is based around a type function colMeta, which describes which supporting values we need for each column. This function is declared with the keyword con, which stands for "constructor," the general class of "compile-time things" that includes types. An argument to colMeta has kind (Type * Type), which means that it must be a type-level tuple. The first type is how the column is represented in SQL, and the second is how we represent it in HTML forms. In order, the components of the resulting record give:

  1. A display name
  2. A way of pretty-printing values of the column
  3. A way of generating an HTML form widget to input this column
  4. A way of generating an HTML form widget with an initial value specified
  5. A way of parsing values of the column from strings
  6. A type class witness, showing that the SQL representation can really be included in SQL

The function colsMeta lifts colMeta over type-level records of type pairs. The Crud module also defines reasonable default colMeta values for some primitive types.

The functor signature tells us (in order) that an input must contain:

  1. A type pair record cols
  2. A proof that cols does not contain a field named Id
  3. A SQL table tab with an Id field of type int and other fields whose names and types are read off of cols
  4. A display title for the admin interface
  5. A record of meta-data for the columns

Looking at crud1.ur, we see that a use of the functor is almost trivial. Only the value components of the argument structure must be provided. The column row type is inferred, and the disjointness constraint is proved automatically.

We won't go into detail on the implementation of Crud.Make. The types of the functions used there can be found in the signatures of the built-in Basis module and the Top module from the standard library. The signature of the first and the signature and implementation of the second can be found in the lib/ur directory of the Ur/Web distribution.