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:
each persistent struct type has an associated entity that provides structural information on structures of that type;
each entity contains, among other things, a list of attributes that provides information on the fields of the struct type;
support for relationships between entities is planned for a future version of Snooze.
4.1 Entities
define-persistent-struct binds the struct name to the entity metadata for each persistent struct type:
| |||
> person | |||
#<entity:person> |
(connection? persistent-struct? -> persistent-struct?)
Examples: |
> (struct-has-entity? struct:person) |
#t |
> (struct-has-entity? (make-person "Dave" 30)) |
#t |
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
Examples: |
> (attr person id) |
#<attr:person-id> |
> (attr person revision) |
#<attr:person-revision> |
> (attr person name) |
#<attr:person-name> |
> (attr person age) |
#<attr:person-age> |
| |||||||||||||||||||||||||||||||||||
name : symbol? | |||||||||||||||||||||||||||||||||||
column-name : symbol? | |||||||||||||||||||||||||||||||||||
entity : entity? | |||||||||||||||||||||||||||||||||||
index : natural? | |||||||||||||||||||||||||||||||||||
accessor : (persistent-struct? -> any) | |||||||||||||||||||||||||||||||||||
mutator : (persistent-struct? any -> void?) | |||||||||||||||||||||||||||||||||||
type : type? |
(entity-has-attribute? entity attribute) → boolean? |
entity : entity? |
attribute : (U attribute? symbol?) |
Examples: |
> (entity-has-attribute? person (attr person name)) |
#t |
> (entity-has-attribute? person 'name) |
#t |
Examples: |
> (entity-attribute person (attr person name)) |
#<attr:person-name> |
> (entity-attribute person 'name) |
#<attr:person-name> |
> (entity-attribute 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 |
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:
4.6 Persistent structure utilities
Examples: | ||
| ||
> (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?) |
Examples: |
> (struct-has-attribute? dave (attr person name)) |
#t |
> (struct-has-attribute? dave 'age) |
#t |
> (struct-has-attribute? dave 'nom) |
#f |
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 |
Examples: |
> (set-struct-attribute! dave (attr person name) "Noel") |
> (set-struct-attribute! dave 'age #f) |
> (struct-attributes dave) |
(#f #f "Noel" #f) |
Examples: |
> (set-struct-attributes! dave (list #f #f "Dave" 30)) |
> (struct-attributes dave) |
(#f #f "Dave" 30) |
| ||||||||||||||||||||
→ persistent-struct? | ||||||||||||||||||||
entity : entity? | ||||||||||||||||||||
attr : (U attribute? symbol?) | ||||||||||||||||||||
value : any | ||||||||||||||||||||
attr2 : (U attribute? symbol?) | ||||||||||||||||||||
value2 : any |
Each attr must be followed by a corresponding value.
Example: | ||
| ||
#(struct:person #f #f "Noel" #f) |
| |||||||||||||||||||||||||||||||||||
struct : persistent-struct? | |||||||||||||||||||||||||||||||||||
attr : (U attribute? symbol?) | |||||||||||||||||||||||||||||||||||
value : any | |||||||||||||||||||||||||||||||||||
attr2 : (U attribute? symbol?) | |||||||||||||||||||||||||||||||||||
value2 : any |
Each attr must be followed by a corresponding value.
| ||||||||
→ persistent-struct? | ||||||||
struct : persistent-struct? | ||||||||
copy : persistent-struct? |
Example: |
> (copy-persistent-struct dave (attr person name) "Noel") |
#(struct:person #f #f "Noel" 30) |