On this page:
relation?
relation-heading
relation-tuples
relation
make-relation
relation-add-lookup
relation-index
in-relation
relation-find
relation-ref
relation-ref-all
relation-prepare-find
relation-prepare-ref
relation-prepare-ref-all
8.16.0.4

13 Relations🔗

The relation structure itself is immutable, but they may contains mutable field values. Mutating a field value may cause the relation’s lookups to behave incorrectly.

The relations perform all field comparisons using equal?.

 (require scramble/relation) package: scramble-lib

Added in version 0.4 of package scramble-lib.

procedure

(relation? v)  boolean?

  v : any/c
Returns #t if v is a relation created by relation or make-relation; otherwise, returns #f.

procedure

(relation-heading rel)  (vectorof symbol?)

  rel : relation?

procedure

(relation-tuples rel)  (vectorof vector?)

  rel : relation?
Returns the relations’s heading and tuples, respectively. The heading is a vector of field names, and each tuple in the relation is a vector of the same length.

syntax

(relation maybe-name heading tuples lookup ...)

 
maybe-name = 
  | #:name name-expr
     
heading = #:heading [field-name-expr ...]
     
tuples = #:tuples [field-value-expr ...] ...
     
lookup = #:lookup field-name-expr
  | #:unique field-name-expr
 
  field-name-expr : symbol?
Creates a relation. The result of name-expr, if present, is only used by the printer to aid debugging. The heading defines the symbolic names of the relation’s fields. Each tuple consists of the same number of field value expressions, where each field value’s position corresponds to the field’s position in the heading.

A “lookup” would be called an “index” in database terminology, but this library uses the term “lookup” to avoid ambiguity with “index” as a numeric position.

Each lookup declaration causes the relation to include a hash mapping field values to tuples. If the lookup is declared #:unique, then the relation must contain at most one tuple for a given field value.

Examples:
> (define food
    (relation #:name 'food
              #:heading
              ['food 'type 'color]
              #:tuples
              ['apple 'fruit 'red]
              ['banana 'fruit 'yellow]
              ['shishkebab 'meat 'brown]
              ['artichoke 'vegetable 'green]
              ['broccoli 'vegetable 'green]
              #:unique 'food))
> food

#<relation:food>

procedure

(make-relation name heading tuples)  relation?

  name : (or/c #f symbol?)
  heading : (or/c (listof symbol?) (vectorof symbol?))
  tuples : 
(let ([tuple/c (or/c list? vector?)])
  (or/c (listof tuple/c) (vectorof tuple/c)))
Creates a relation using the given name, heading, and tuples. Lookups must be added separately using relation-add-lookup.

procedure

(relation-add-lookup rel field unique?)  relation?

  rel : relation?
  field : symbol?
  unique? : boolean?
Produces a relation like rel but with a lookup for field. If unique? is true, then each field value in rel for field must be distinct; otherwise, an exception is raised.

procedure

(relation-index rel field)

  (or/c #f exact-nonnegative-integer?)
  rel : relation?
  field : symbol?
Returns the position of field in the relation rel’s heading, or #f if rel’s heading does not contain field.

Examples:
> (relation-index food 'food)

0

> (relation-index food 'color)

2

> (relation-index food 'calories)

#f

procedure

(in-relation rel field/s)  sequence?

  rel : relation?
  field/s : (or/c symbol? (listof symbol?))
Returns a sequence that produces one element for each tuple in rel. If field/s is a single symbol, then each element is the tuple’s value for that field. If field/s is a list of symbols, then each element is a list of the corresponding field values.

Examples:
> (sequence->list (in-relation food 'type))

'(fruit fruit meat vegetable vegetable)

> (sequence->list (in-relation food '(food type)))

'((apple fruit)

  (banana fruit)

  (shishkebab meat)

  (artichoke vegetable)

  (broccoli vegetable))

procedure

(relation-find rel key-field key-value [all?])

  (if/c all? (listof vector?) (or/c vector? #f))
  rel : relation?
  key-field : symbol?
  key-value : any/c
  all? : boolean? = #f
Find tuples whose value for key-field is equal to key-value. If all? is true, then a list of all matching tuples is returned. If all? is false, then only the first tuple is returned, or #f if no tuple matches.

Examples:
> (relation-find food 'type 'fruit)

'#(apple fruit red)

> (relation-find food 'type 'vegetable #t)

'(#(artichoke vegetable green) #(broccoli vegetable green))

procedure

(relation-ref rel    
  key-field    
  key-value    
  result-field/s    
  [default])  any
  rel : relation?
  key-field : symbol?
  key-value : any/c
  result-field/s : (or/c symbol? (listof symbol?))
  default : any/c = #f
Returns the result-field/s for the first tuple in rel whose value for key-field is equal to key-value.

If result-field/s is a single symbol, then the corresponding field value is returned. If result-field/s is a list of symbols, then a list of the corresponding field values is returned.

If rel contains no matching tuple, default is called if it is a procedure or returned otherwise. Note that unlike hash-ref, the default value of dfault is #f, not an error-raising procedure.

Examples:
> (relation-ref food 'food 'apple 'type)

'fruit

> (relation-ref food 'food 'brie 'type)

#f

> (relation-ref food 'food 'artichoke '(type color))

'(vegetable green)

procedure

(relation-ref-all rel    
  key-field    
  key-value    
  result-field/s)  list?
  rel : relation?
  key-field : symbol?
  key-value : any/c
  result-field/s : (or/c symbool? (listof symbol?))
Like relation-ref, but returns a list of results based on all matching tuples.

Example:
> (relation-ref-all food 'type 'fruit '(food color))

'((apple red) (banana yellow))

procedure

(relation-prepare-find rel key-field [all?])

  
(-> any/c
    (if/c all? (listof vector?) (or/c #f vector?)))
  rel : relation?
  key-field : symbol?
  all? : boolean? = #f

procedure

(relation-prepare-ref rel 
  key-field 
  result-field/s) 
  (->* [any/c] [any/c] any)
  rel : relation?
  key-field : symbol?
  result-field/s : (or/c symbol? (listof symbol?))

procedure

(relation-prepare-ref-all rel    
  key-field    
  result-field/s)  (-> any/c list?)
  rel : relation?
  key-field : symbol?
  result-field/s : (or/c symbol? (listof symbol?))
Like relation-find, relation-ref, and relation-ref-all, except that the field value is not supplied immediately, and the result is a procedure. Calling the prepared procedure with the field value produces the relation’s result.

Examples:
> (define food-color (relation-prepare-ref food 'food 'color))
> (food-color 'banana)

'yellow

> (food-color 'artichoke)

'green

> (food-color 'haggis 'unknown)

'unknown