On this page:
4.1 Entities
entity
prop: entity
struct-has-entity?
struct-entity
4.2 Relationships
4.3 Attributes
attribute
entity-has-attribute?
entity-attribute
4.4 Attribute types
type
boolean-type
integer-type
real-type
string-type
symbol-type
time-utc-type
time-tai-type
4.5 Shorthand types
type: boolean
type: integer
type: real
type: string
type: symbol
type: time-utc
type: time-tai
4.6 Persistent structure utilities
struct-attributes
struct-has-attribute?
struct-attribute
set-struct-attribute!
set-struct-attributes!
make-persistent-struct/ defaults
copy-persistent-struct
update-persistent-struct-from-copy!
Version: 4.1.3.3

4 Entities, relationships and attributes

Snooze attaches ERA metadata to persistent struct types, providing information on how to serialize and deserialize structures and create aliases for use in queries:

4.1 Entities

(struct entity (name
    table-name
    struct-type
    constructor
    predicate
    attributes
    save-pipeline
    insert-pipeline
    update-pipeline
    delete-pipeline))
  name : symbol?
  table-name : symbol?
  struct-type : struct-type?
  constructor : (any ... -> persistent-struct?)
  predicate : (any -> boolean?)
  attributes : (listof attribute?)
  save-pipeline : (listof procedure?)
  insert-pipeline : (listof procedure?)
  update-pipeline : (listof procedure?)
  delete-pipeline : (listof procedure?)

Metadata describing a particular struct-type. Pipeline procedures are of type:

  (connection? persistent-struct? -> persistent-struct?)

While the entity itself is useful to application programmers in a number of circumstances, most of the information inside the entity does not need to be accessed form application code. define-persistent-struct automatically binds an identifier of the form entity:foo to the entity for each persistent struct type:

  > (define-persistent-struct person
      ([name type:string]
       [age  type:integer]))
  > entity:person

  #<entity:person>

prop:entity : property?

A structure type property used to attach entity metadata to persistent structure types.

(struct-has-entity? struct)  boolean?
  struct : any

Returns #t if struct is a structure or structure type that has a value for prop:entity.

Examples:

  > (struct-has-entity? struct:person)

  #t

  > (struct-has-entity? (make-person "Dave" 30))

  #t

(struct-entity struct)  entity?
  struct : (U struct? struct-type?)

Returns the value of prop:entity that is associated with struct.

Examples:

  > (struct-entity struct:person)

  #<entity:person>

  > (struct-entity (make-person "Dave" 30))

  #<entity:person>

4.2 Relationships

Snooze does not currently have explicit support for relationships. These are planned for a future release. For now, the recommended way of creating a relationship between two structures is by using a foreign key field of type:integer:

  (define-persistent-struct person
    ([name type:string]))
  (define-persistent-struct pet
    ([name     type:string]
     [owner-id type:integer]))

A caveat to this approach is that you have to make sure the target structure is saved before you reference its ID for the foreign key:

  ; This is incorrect.
  ; The person will not have an ID because it has not been saved:
  (make-pet "Garfield" (person-id (make-person "Jon")))
  ; This is correct.
  ; The call to save! allocates an ID for the person:
  (make-pet "Garfield" (person-id (save! (make-person "Jon"))))

4.3 Attributes

(struct attribute (name
    column-name
    entity
    index
    accessor
    mutator
    type))
  name : symbol?
  column-name : symbol?
  entity : entity?
  index : natural?
  accessor : (persistent-struct? -> any)
  mutator : (persistent-struct? any -> void?)
  type : type?

Metadata describing a particular attribute (or field or column) of an entity.

define-persistent-struct automatically binds an identifier of the form attr:foo-bar for each attribute of each persistent struct type:

  > attr:person-id

  #<attr:person-id>

  > attr:person-revision

  #<attr:person-revision>

  > attr:person-name

  #<attr:person-name>

  > attr:person-age

  #<attr:person-age>

(entity-has-attribute? entity attribute)  boolean?
  entity : entity?
  attribute : (U attribute? symbol?)

Returns #t if entity has the supplied attribute, #f otherwise. attribute can be an attribute structure or an attribute name.

Examples:

  > (entity-has-attribute? entity:person attr:person-name)

  #t

  > (entity-has-attribute? entity:person 'name)

  #t

(entity-attribute entity name)  attribute?
  entity : entity?
  name : (U attribute? symbol?)

Determines if entity has the supplied attribute. Returns the attribute exists; raises exn:fail otherwise.

Examples:

  > (entity-attribute entity:person attr:person-name)

  #<attr:person-name>

  > (entity-attribute entity:person 'name)

  #<attr:person-name>

  > (entity-attribute entity:person 'nom)

  Attribute not found: #<entity:person> nom

4.4 Attribute types

Each attribute has an associated type that determines the type of column used in the database. Types come in several flavours, described below. Note that the reflection of a type may be different in different DBMS types. For example, SQLite does not support the SQL TIMESTAMP data type, so Snooze uses integers to serialize time values.

(struct type (allows-null? default))
  allows-null? : boolean?
  default : any

(struct (boolean-type type) ())

Stores #t and #f values. There is no direct Scheme representation of NULL; NULL values in the database are mapped to #f in Scheme.

(struct (integer-type type) ())

Stores integer values. NULL values in the database are mapped to #f in Scheme.

(struct (real-type type) ())

Stores real number values. NULL values in the database are mapped to #f in Scheme.

(struct (string-type type) (max-length))
  max-length : integer?

Stores string values as VARCHARs or arbitrary length TEXTs. The value of max-length determines the SQL type. NULL values in the database are mapped to #f in Scheme.

(struct (symbol-type type) (max-length))
  max-length : integer?

Like string-type but for symbol values.

(struct (time-utc-type type) (max-length))
  max-length : integer?

Stores SRFI 19 UTC times as GMT TIMESTAMP WITHOUT TIME ZONEs (or INTEGERs in SQLite). NULL values in the database are mapped to #f in Scheme.

(struct (time-tai-type type) (max-length))
  max-length : integer?

Like time-utc-type but for SRFI 19 TAI times.

4.5 Shorthand types

Snooze provides a number of short-hand types. The types below all allow and default to NULL, and type:string and type:symbol allow data of arbitrary length:

type:boolean : type?

type:integer : type?

type:real : type?

type:string : type?

type:symbol : type?

type:time-utc : type?

type:time-tai : type?

4.6 Persistent structure utilities

(struct-attributes struct)  list?
  struct : persistent-struct?

Returns a list of the values of the attributes of struct (including its ID and revision).

Examples:

  > (define-persistent-struct person
      ([name type:string] [age type:integer]))
  > (define dave (make-person "Dave" 30))
  > (struct-attributes dave)

  (#f #f "Dave" 30)

(struct-has-attribute? struct name)  boolean?
  struct : persistent-struct?
  name : (U attribute? symbol?)

Returns #t if struct has an attribute with the supplied name, #f otherwise.

Examples:

  > (struct-has-attribute? dave attr:person-name)

  #t

  > (struct-has-attribute? dave 'age)

  #t

  > (struct-has-attribute? dave 'nom)

  #f

(struct-attribute struct name)  any
  struct : persistent-struct?
  name : (U attribute? symbol?)

Returns the value from struct of the attribute with the supplied name. Raises exn:fail:contract if struct does not have a corresponding attribute.

Examples:

  > (struct-attribute dave attr:person-name)

  "Dave"

  > (struct-attribute dave 'age)

  30

  > (struct-attribute dave 'nom)

  Attribute not found: #<entity:person> nom

(set-struct-attribute! struct name value)  void?
  struct : persistent-struct?
  name : (U attribute? symbol?)
  value : any

Mutates struct, setting the value of the attribute with the supplied name.

Examples:

  > (set-struct-attribute! dave attr:person-name "Noel")
  > (set-struct-attribute! dave 'age #f)
  > (struct-attributes dave)

  (#f #f "Noel" #f)

(set-struct-attributes! struct vals)  void?
  struct : persistent-struct?
  vals : list?

Mutates struct, setting the values of all its attributes. vals must contain an ID, a revision, and one value for each attribute of struct in the order specified inthe define-persistent-struct form.

Examples:

  > (set-struct-attributes! dave (list #f #f "Dave" 30))
  > (struct-attributes dave)

  (#f #f "Dave" 30)

(make-persistent-struct/defaults entity 
  attr 
  value 
  attr2 
  value2 ...) 
  persistent-struct?
  entity : entity?
  attr : (U attribute? symbol?)
  value : any
  attr2 : (U attribute? symbol?)
  value2 : any

Returns a new persistent of the supplied type, with default values for all attributes except those specified in the arguments. Used in the implementation of the keyword constructor created by define-persistent-struct.

Each attr must be followed by a corresponding value.

Examples:

  > (make-persistent-struct/defaults
     entity:person attr:person-name "Noel")

  #(struct:person #f #f "Noel" #f)

(copy-persistent-struct struct    
  attr    
  value    
  attr2    
  value2 ...)  persistent-struct?
  struct : persistent-struct?
  attr : (U attribute? symbol?)
  value : any
  attr2 : (U attribute? symbol?)
  value2 : any

Returns a new persistent structure with the same type and attributes of struct, except where new values are supplied in the arguments. Used in the implentation of the copy procedure created by define-persistent-struct.

Each attr must be followed by a corresponding value.

(update-persistent-struct-from-copy! struct 
  copy) 
  persistent-struct?
  struct : persistent-struct?
  copy : persistent-struct?

Mutates struct to be the same as copy. Used when rolling back cancelled transactions.

Examples:

  > (copy-persistent-struct dave attr:person-name "Noel")

  #(struct:person #f #f "Noel" 30)