3 Persistent structures
it tells Snooze how to serialize and deserialize structs of that type;
- it indirectly allows the programmer to refer to the entity in queries.
A persistent structure type with n fields is mapped to a database table with n+2 columns: an integer id which acts as a primary key for table, an integer revision number which helps prevent against concurrent writes in multi-threaded applications, and a column for each attribute in the type definition. ids and revisions are automatically allocated by Snooze and should not normally be updated by application code: the lifecycle of these fields is described in Saving and deleting structures.
3.1 Defining persistent structure types
- id, an entity metadata value that can be used in queries and other Snooze procedures, doubles as a transformer binding that can be used with PLT forms such as shared and match ;
- struct:id, the usual structure type descriptor defined by define-struct;
make-id, a constructor procedure that takes n arguments and returns a new struct;
make-id/defaults, a keyword constructor that takes up to n+2 keyword arguments and returns a new struct. The keywords accepted include #:id, #:revision and the various attr-ids: where a keyword is omitted, the default value of the attribute is used;
copy-id, a copy constructor that takes a persistent structure and up to n+2 keyword arguments and returns a new struct. The keywords accepted include #:id, #:revision and the various attr-ids: where a keyword is omitted, the value of the attribute in the existing structure is used;
id?, a predicate that returns #t for instances of the structure type and #f for any other value;
id-attr-id, a set of accessor procedures, including id-id and id-revision, that take a persistent structure as an argument and return the value of the corresponding attribute;
set-id-attr-id!, a set of mutator procedures, including set-id-id! and set-id-revision!, that take a persistent structure and an arbitrary Scheme value as arguments, and mutate the structure to set the corresponding attribute to the supplied value;
- id, the transformer binding provided by define-struct, used with PLT forms such as shared and match;
entity:id, an alias for id, is provided for backwards compatibility only (replaced by id);
attr:id-attr-id, a set of attribute metadata values, are provided for backwards compatibility only (replaced by the attr macro);
By default, persistent structures are stored in rows in a database table of the same name. The #:table-name entity option allows you to override the default table name and provide something more user-friendly: hyphen characters in table names must be escaped in most DBMSs. Similarly, the #:column-name attribute option allows you to override the default column name for each attribute. The column names for id and revision may not be changed.
(part ("(planet pipeline.ss (untyped unlib.plt 3 23))" "top"))
Persistent structures are completely inspectable. ids and revisions are visible in their printed forms and are exposed by the struct form from scheme/match. For example:
; person : (persistent-struct (U string #f) (U integer #f)) | |||
| |||
; dave : person | |||
| |||
; Print dave: id and revision shown: | |||
> dave | |||
#(struct:person #f #f "Dave" 30) | |||
; Match against dave: no id and revision: | |||
| |||
(#f #f "Dave" 30) |
Persistent structure types are not meant to be subtyped, although this feature is planned for a future version of Snooze.
3.2 IDs and revisions
Every persistent struct has an ID and a revision. The ID acts as a primary key in the database, and the revision helps protect against concurrent database updates.
Warning: Use struct-saved? rather than struct-id to check whether or not a struct has been saved to the database. Changes in later versions of Snooze may affect whether struct-id returns #f for unsaved structs.
The revision number is set to 0 when a structure is first saved and is incremented on each subsequent save. Snooze raises exn:fail:snooze:revision if a structure has an incompatible revision number when you try to save it. This protects against common concurrency problems.