chickadee » gromit

gromit

Description

gromit - A Graph-like Object Persistence Toolkit.

Source Code

https://github.com/register-dynamics/gromit

Author

Andy Bennett

Requirements

API

make-object-id

make-object-id node-id seqnoprocedure

define-attribute-type

(make-object-id type 'SQL-TYPE serialiser: serialiser deserialiser: deserialiser initialiser: initialiser setter: setter getter: getter)syntax

Creates a new type of attribute.

  column-type : The type of the underlying column that is used for the
                serialised value when it is stored in the database.
 
   serialiser : Called when an object or property is being saved back to the
                database. A procedure of one argument that receives the
                current value of the attribute in memory and returns a
                serialised version of the attribute suitable for storing in
                SQLite. Each time an attempt is made to write the object or
                property back to the database, this is called no more than
                once.
 
 deserialiser : Called when an object or property is being read from the
                database. A procedure of one argument that receives the value
                of the attribute from the database and returns a deserialied
                version of the attribute suitable for storing in memory. Each
                time an attempt is makde to read the object or property back
                from the database, this is called no more than once.
 
 initialiser  : Called when a new object that contains this attribute is being
                allocated. A procedure of no arguments that must return the
                initial value for the attribute. The value returned must be a
                deserialised value suitable for storing in memory.
                Defaults to #f.
                This is called the first time an attempt is made to allocate
                the object or property. If the allocation subsequently fails,
                it will not be called again.
 
       setter : Called when user code tries to set the value of an attribute.
                A procedure of one argument that receives the value supplied
                by the user as used in CHICKEN code and returns the value
                suitable for storing in memory. Usually the identity procedure
                or a guard. If the attribute is marked as constant by the
                structure that uses it then the setter procedure is only
                called before the structure has been written to disk for the
                first time.
                Defaults to the identity procedure.
 
       getter : Called when user code tries to get the value of an attribute.
                A procedure of one argument that receives the value stored in
                memory and returns a value for the user, suitable for use in
                CHICKEN code.
                Defaults to the identity procedure.

The built-in attribute types are:

  • integer
  • text
  • blob
  • boolean
  • symbol
  • wallclock
  • node-id/current-node
  • timestamp/next
  • current-user/node-id
  • current-user/seqno

See `gromit-types.scm` for more examples.

(define constantly-NULL
  (constantly NULL))

(define (value-or-NULL v)
  (if v v NULL))

(define-attribute-type integer 'INTEGER
		       serialiser:   value-or-NULL
		       deserialiser: value-or-false
		       initialiser:  constantly-NULL
		       setter:       (lambda (i)
				       (cond
					 ((integer? i) i)
					 ((eq? #f i)   i)
					 (else
					   (assert #f (conc "integer field expected an integer or #f. We got " i "!")))))
		       getter:       identity)

define-property-type

(define-property-type name table fields...)syntax

Creates a property type. An Object's field list can consist of attribute types or property types. Attributes are simple types that are stored in a single column in the object's database table. Properties are more complex types that are stored in their own database table. A property's field list can consist of attribute types only: property types cannot be nested. An Object's property fields can have zero or more values. If an Object needs to have a property field with more than one value then you must denote some of the property fields as keys. The key, which may consist of several fields, must be unique for each property of that type for a particular Object.

  (define-property-type password 'prop_password
  		      (set        wallclock required constant (key 0))
  		      (algorithm  symbol    required constant)
  		      (iterations integer   required constant)
  		      (salt       text      required constant)
  		      (crypt      blob      required constant))

define-property-constructor

(define-property-constructor name type proc)syntax

Defines a constructor, `proc`, for a property type. `proc` takes a freshly made, but uninitialised, property as its first argument. Any subsequent arguments are user defined. `proc` then manipulates the provided property using the regular property accessors. When `proc` has finished executing, the constructed property is returned to the user. The return value of `proc` is ignored.

  (define-property-constructor make-password* password
    (lambda (p plaintext)
      ; https://ruby-doc.org/stdlib-2.0.0/libdoc/openssl/rdoc/OpenSSL/PKCS5.html
      (let ((iterations 10000)
  	  (salt       (make-salt 32)) ; 256 bits matching 256 bit digest function.
  	  (dklen      32))            ; (/ 256 8)
        (password-algorithm  p 'pbkdf2-hmac-sha256)
        (password-iterations p iterations)
        (password-salt       p salt)
        (password-crypt      p (pbkdf2-hmac-sha256 plaintext salt iterations dklen 'blob)))))

create-table-%metadata

<symbol>create-table-%metadata</symbol>

The create table statement for the object metadata table:

  #;2> create-table-%metadata
  "CREATE TABLE objects (\"node-id\" INTEGER NOT NULL, \"seqno\" INTEGER NOT NULL, \"name\" TEXT, \"description\" TEXT, \"version-ts\" INTEGER NOT NULL, \"version-node-id\" INTEGER NOT NULL, \"created\" INTEGER NOT NULL, \"created-by-node-id\" INTEGER NOT NULL, \"created-by-seqno\" INTEGER NOT NULL, \"last-modified\" INTEGER NOT NULL, \"last-modified-by-node-id\" INTEGER NOT NULL, \"last-modified-by-seqno\" INTEGER NOT NULL, PRIMARY KEY (\"node-id\", \"seqno\"))"

object-metadata-name

object-metadata-description

object-metadata-version

object-metadata-created

object-metadata-created-by

object-metadata-last-modified

object-metadata-last-modified-by

object-metadata-name object #!optional valueprocedure
object-metadata-description object #!optional valueprocedure
object-metadata-version object #!optional valueprocedure
object-metadata-created object #!optional valueprocedure
object-metadata-created-by object #!optional valueprocedure
object-metadata-last-modified object #!optional valueprocedure
object-metadata-last-modified-by object #!optional valueprocedure

Getters/setters for the object metadata.

object-id

object-id objectprocedure

Gets the object ID of the object if it has been allocated in the database, otherwise #f.

object-type

object-type objectprocedure

Returns a symbol denoting the type of the object, as declared in `define-object-type`.

define-object-type

(define-object-type name table fields...)syntax

Creates an object type. An Object's field list can consist of attribute types or property types. Attributes are simple types that are stored in a single column in the object's database table. Properties are more complex types that are stored in their own database table. An Object's property fields can have zero or more values.

  (define-object-type email-address 'attrib_email_address
  		    (domain-part            text     required constant)
  		    (local-part             text     required constant)
  		    (local-part-ci          text     required constant)
  		    (use-for-notifications  boolean  required)
  		    (verified               integer)
  		    (preferred-content-type symbol   required))

...or one that has a field that's a property (as defined with `define-property-type`) rather than an attribute:

  (define-object-type account 'attrib_account
  		    (onboarding  integer)
  		    (password    password))

define-object-constructor

(define-object-constructor name type proc)syntax

Defines a constructor, `proc`, for an object type. `proc` takes a freshly made, but uninitialised, object as its first argument. Any subsequent arguments are user defined. `proc` then manipulates the provided object using the regular object accessors. When `proc` has finished executing, the constructed object is returned to the user. The return value of `proc` is ignored.

  (define-object-constructor make-email-address* email-address
    (lambda (e address use-for-notifications)
  
      (assert (string? address))
  
      (let ((addr (x-email-address address)))
        (assert addr (conc "mail-email-address*: Expected a valid eMail address. We got " address "!"))
        (email-address-domain-part            e (domain-part->string   addr))
        (email-address-local-part             e (local-part->string    addr))
        (email-address-local-part-ci          e (local-part->string-ci addr))
        (email-address-use-for-notifications  e use-for-notifications)
        (email-address-verified               e #f)
        (email-address-preferred-content-type e 'fancy-html))))

define-object-finder

(define-object-finder signature type conditions)syntax

Defines a procedure that finds an object of the specified type using the condition specified. The argument list in the signature consists of argument names and argument types. The argument names can then be used in the conditions.

(define-object-finder (find-email-address
			(local-part  text)
			(domain-part text))
		      email-address
		      `(and (= (@ domain-part) ,domain-part)
			     (= (@ local-part)  ,local-part)
			     (> (@ verified)    ,*some-time*)))

current-gromit-db

current-gromit-dbparameter

Must be set to something returned by `open-gromit-database`.

open-gromit-database

open-gromit-database filenameprocedure

filename is an SQLite database file.

current-gromit-user

current-gromit-userparameter

An object id created with `make-object-id`. Operations performed on the database are done as this user. i.e this ID is stamped into the created-by and last-modified-by fields of objects that are created or save!ed.

Built-in Field Types

See `gromit-types.scm` for details.

License

 Copyright (C) 2019, Andy Bennett, Register Dynamics Limited.
 All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
 
 Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.
 Redistributions in binary form must reproduce the above copyright notice,
 this list of conditions and the following disclaimer in the documentation
 and/or other materials provided with the distribution.
 Neither the name of the author nor the names of its contributors may be
 used to endorse or promote products derived from this software without
 specific prior written permission.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE
 LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
 SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
 INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
 CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
 POSSIBILITY OF SUCH DAMAGE.

Version History

Contents »