On this page:

1 Data Class Mapping

Mapping of Racket classes to database tables is performed using data-class, which extends a Racket class with expressions for mapping a database table and columns to the data class. Below is an example of a data-class with mapping expressions.

(define vehicle%
  (data-class object%
    (table-name "Vehicle")
    (column (vehicle-id #f "Vehicle_Id") (make #f "Make")
            (year 0 "Year") (axels 1 "Axels"))
    (primary-key vehicle-id)
    (join [owner customer% #:cardinality 'one-to-one
                 (where (= (customer% id) (vehicle% customer-id)))])
    (define/public (wheels)
      (* (get-column axels this) 2))

Here a database table named "Vehicle" is mapped to the vehicle% data class. Columns are defined mapping the columns of the table to a field of the data class, as well as default value for the field. There is also an expression which defines the primary key. This table also has a join field owner which defines a one-to-one join to a customer% object.


(data-class* superclass-expr (interface-expr ...)
data-class-clause = (table-name table-name external-name)
  | (init-column column-decl ...)
  | (column column-decl ...)
  | (join join-table-id join-decl ...)
  | (primary-key primary-key-decl auto-increment-kw)
  | class-clause
  | ...
init-column-decl = (maybe-renamed column-name-decl)
  | (maybe-renamed default-value-expr column-name-decl)
column-decl = (maybe-renamed default-value-expr column-name)
maybe-renamed = id
  | (internal-id external-id)
column-name-decl = column-name
  | (column-name external-name)
join-decl = (join-name joined-table-id cardinality-kw where-clause)
cardinality-kw = 
  | #:cardinality cardinality-expr
primary-key-decl = column-id
  | (column-ids ...)
auto-increment-kw = 
  | #:autoincrement auto-increment-expr
Produces a data class value used for persisting data objects from a database.

The table-name expression is a string that names the database table that the data class is mapped to. An optional external class name can also be defined. This external name is used when the class is exported to JSON or XML using the Racquel data class mixins.

The column and init-column are analogous to class field and init-field expressions. The difference being that columns are mapped to columns of a database and are persistent. A data class may also contain field columns, but the fields, as they are not mapped to database columns are not persisted.

Data classes can map joins to other data classes, using a join expression so that objects related to the object can be contained as part of the object. For example a join can be defined so that a field of the object can contain a list of order for a customer. The path of a join is defined using an RQL expression (see RQL: The Racquel Query Language) which allows for considerable flexibility in regard to what the contained objects are, e.g. a join could be defined so that only customer order in the last six months are contained in the object. The cardinality of the join is also definable using a keyword. Valid values for the cardinality keyword are 'one-to-one and 'one-to-many.

Joined objects are loaded lazily, that is, they are not loaded from the database until they are first referenced.

The primary-key expression defines the primary key for the mapped table. If a primary key consists of multiple parts then the columns must be defined in a list. An optional keyword #:autoincrement can be used to indicate that the primary key is an auto-incrementing a.k.a. identity column. Typically the value for this keyword is simply #t, however if the type of database being mapped to is PostgreSQL or Oracle, then the value of the keyword must be a string defining the name of the sequence entity being used for the table.

A data-class automatically defines a inspect with a value of #f, as class transparancy is necessary for persistent mechanism. Therefore defining an inspect expression will generate an error that an inspect expression has already been defined.


(data-class superclass-expr class-clause ...)

This is analagous to the class definition, where the interface expression is omitted.


(data-class? v)  boolean?

  v : any/c
Returns #t if v is a data class, #f otherwise.


(data-class-info class)

(listof (listof identifier? string? string?))
(listof (listof identifier? identifier? identifier? any/c))
(or/c identifier? (listof identifier?))
(or/c #t string? #f)
(or/c string? #f)
  class : data-class?
Returns eight values, analogous to the returnvalues of class-info: