3 Persistent structures
A persistent structure is a PLT structure that Snooze can save to a database. Snooze attaches entity metadata to each persistent struct type via a property called prop:entity. The metadata serves two purposes:
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
Creates a new persistent structure, and binds variables related to the new structure type. A define-persistent-struct with n attributes defines the following identifiers:
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 16))" "top"))
The #:on-save, #:on-insert, #:on-update and #:on-delete keywords allow you to specify pipelines to be run during calls to save! and delete!.
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.
(struct-id struct) → (U integer? #f) |
struct : persistent-struct? |
Returns the ID of struct, or #f if struct is not saved in the database.
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.
(set-struct-id! struct id) → void? |
struct : persistent-struct? |
id : (U integer? #f) |
Sets the id of struct. You should not normally have to use this procedure: Snooze does this automatically when you save or delete a struct.
(struct-revision struct) → (U integer? #f) |
struct : persistent-struct? |
Returns the last revision number of struct, or #f if struct is not saved in the database.
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.
(set-struct-revision! struct rev) → void? |
struct : persistent-struct? |
rev : (U integer? #f) |
Sets the revision number of struct to rev. You should not normally have to use this procedure: Snooze does this automatically when you save or delete a struct.
(struct-saved? struct) → boolean? |
struct : persistent-struct? |
Returns #t if struct has been saved to the database and #f if it has not.