#lang scheme/base
(require mzlib/etc
scheme/contract
scheme/match
(only-in srfi/1/list iota)
srfi/26/cut
(planet untyped/unlib:3/pipeline)
"base.ss"
"schema.ss"
"era/era.ss"
"era/era-dummy.ss")
(define (make-persistent-struct-type
name
attr-names
attr-types
#:table-name [table-name name]
#:column-names [column-names attr-names]
#:on-save [save-pipeline null]
#:on-insert [insert-pipeline null]
#:on-update [update-pipeline null]
#:on-delete [delete-pipeline null]
#:properties [properties null])
(define num-attrs
(let ([num-attrs (length attr-names)])
(cond [(not (= num-attrs (length attr-types)))
(raise-exn exn:fail:contract (format "Expected ~a attribute types, received: ~s" num-attrs attr-types))]
[(not (= num-attrs (length column-names)))
(raise-exn exn:fail:contract (format "Expected ~a attribute DB names, received: ~s" num-attrs column-names))]
[else num-attrs])))
(define entity
(make-entity name
table-name
#f (make-dummy-constructor name) (make-dummy-predicate name) (make-dummy-accessor name) (make-dummy-mutator name) null save-pipeline
insert-pipeline
update-pipeline
delete-pipeline))
(define-values (struct-type private-constructor predicate private-accessor private-mutator)
(make-struct-type
name struct:persistent-struct num-attrs 0 (void) (cons (cons prop:entity entity) properties) #f))
(define (constructor . args)
(if (= (length args) num-attrs)
(apply private-constructor
(type-default type:id)
(type-default type:revision)
args)
(raise-exn exn:fail:contract:arity
(format "Expected ~a arguments, received ~a" num-attrs args))))
(define attributes
(append (map (lambda (attr)
(make-attribute (attribute-name attr)
(attribute-column-name attr)
entity
(attribute-index attr)
(attribute-accessor attr)
(attribute-mutator attr)
(attribute-type attr)))
(entity-attributes entity:persistent-struct))
(map (lambda (index attr-name column-name type)
(make-attribute attr-name
column-name
entity
(+ index (length (entity-attributes entity:persistent-struct)))
(make-persistent-struct-field-accessor private-accessor index attr-name)
(make-persistent-struct-field-mutator private-mutator index attr-name)
type))
(iota num-attrs)
attr-names
column-names
attr-types)))
(set-entity-struct-type! entity struct-type)
(set-entity-constructor! entity private-constructor)
(set-entity-predicate! entity predicate)
(set-entity-accessor! entity private-accessor)
(set-entity-mutator! entity private-mutator)
(set-entity-attributes! entity attributes)
(add-schema-entity! entity)
(values entity struct-type constructor predicate))
(define pipeline-name/c
(symbols 'save 'insert 'update 'delete))
(define pipeline/c
(listof stage?))
(define prop:entity/c
(flat-named-contract 'prop:entity/c (cut eq? <> prop:entity)))
(define not-prop:entity/c
(and/c struct-type-property? (not/c prop:entity/c)))
(provide/contract
[make-persistent-struct-type
(->* (symbol? (listof symbol?) (listof type?))
(#:table-name symbol?
#:column-names (listof symbol?)
#:on-save (listof stage?)
#:on-insert (listof stage?)
#:on-update (listof stage?)
#:on-delete (listof stage?)
#:properties (listof (cons/c not-prop:entity/c any/c)))
(values entity?
struct-type?
procedure?
procedure?))])