2021-06-21 12:39:41 +00:00
|
|
|
;;; SPDX-License-Identifier: LGPL-3.0-or-later
|
2022-01-16 08:48:18 +00:00
|
|
|
;;; SPDX-FileCopyrightText: Copyright © 2016-2022 Tony Garnock-Jones <tonyg@leastfixedpoint.com>
|
2021-06-21 12:39:41 +00:00
|
|
|
|
|
|
|
#lang racket/base
|
|
|
|
;;; Long-running and immediate queries over dataspace contents.
|
|
|
|
|
|
|
|
(provide query-value
|
|
|
|
query-count
|
|
|
|
query-set
|
|
|
|
query-hash
|
|
|
|
query-value*
|
|
|
|
query-count*
|
|
|
|
query-set*
|
|
|
|
query-hash*
|
|
|
|
define/query-value
|
|
|
|
define/query-count
|
|
|
|
define/query-set
|
|
|
|
define/query-hash
|
|
|
|
|
|
|
|
let/query)
|
|
|
|
|
|
|
|
(require (for-syntax racket/base))
|
|
|
|
(require (for-syntax syntax/parse))
|
|
|
|
|
|
|
|
(require racket/match)
|
|
|
|
(require racket/set)
|
|
|
|
|
|
|
|
(require "pattern.rkt")
|
|
|
|
(require "syntax.rkt")
|
|
|
|
(require "bag.rkt")
|
|
|
|
|
2021-07-01 07:40:52 +00:00
|
|
|
(require "schemas/dataspace.rkt")
|
2021-06-21 12:39:41 +00:00
|
|
|
|
|
|
|
(begin-for-syntax
|
|
|
|
(define-splicing-syntax-class on-add
|
|
|
|
(pattern (~optional (~seq #:on-add expr) #:defaults ([expr #'#f]))))
|
|
|
|
(define-splicing-syntax-class on-remove
|
|
|
|
(pattern (~optional (~seq #:on-remove expr) #:defaults ([expr #'#f])))))
|
|
|
|
|
|
|
|
(define-syntax-rule (-define-query (query-name field-name query-args ...) init query*-name)
|
|
|
|
(define-syntax-rule (query-name field-name query-args ...)
|
|
|
|
(let()
|
|
|
|
(define-field field-name init)
|
|
|
|
(query*-name field-name query-args ...)
|
|
|
|
field-name)))
|
|
|
|
|
|
|
|
(-define-query (query-value field-name absent-expr args ...) absent-expr query-value*)
|
|
|
|
|
|
|
|
(define-syntax (query-value* stx)
|
|
|
|
(syntax-parse stx
|
|
|
|
[(_ field-name absent-expr P expr on-add:on-add on-remove:on-remove)
|
|
|
|
(quasisyntax/loc stx
|
|
|
|
(let ((F field-name) (assertion-count 0))
|
|
|
|
(assert
|
|
|
|
(Observe (:pattern P)
|
|
|
|
(ref (entity #:name 'field-name
|
|
|
|
#:assert
|
|
|
|
(lambda (bindings handle)
|
2022-12-24 08:08:57 +00:00
|
|
|
(pattern-binding-let [P bindings]
|
|
|
|
(set! assertion-count (+ assertion-count 1))
|
|
|
|
(F expr)
|
|
|
|
on-add.expr))
|
2021-06-21 12:39:41 +00:00
|
|
|
#:retract
|
|
|
|
(lambda (_handle)
|
|
|
|
(set! assertion-count (- assertion-count 1))
|
|
|
|
(when (zero? assertion-count)
|
|
|
|
(F absent-expr)
|
|
|
|
on-remove.expr))))))))]))
|
|
|
|
|
|
|
|
(-define-query (query-count field-name args ...) (bag) query-count*)
|
|
|
|
|
|
|
|
(define-syntax (query-count* stx)
|
|
|
|
(syntax-parse stx
|
|
|
|
[(_ field-name P expr on-add:on-add on-remove:on-remove)
|
|
|
|
(quasisyntax/loc stx
|
|
|
|
(let ((F field-name))
|
|
|
|
(assert
|
|
|
|
(Observe (:pattern P)
|
|
|
|
(object #:name 'field-name
|
2022-12-24 08:08:57 +00:00
|
|
|
[#:asserted* bindings
|
|
|
|
(pattern-binding-let [P bindings]
|
|
|
|
(define v expr)
|
|
|
|
(define-values (bag1 outcome1) (bag-change (F) v 1))
|
|
|
|
(F bag1)
|
|
|
|
(when (eq? outcome1 'absent->present) on-add.expr)
|
|
|
|
(lambda ()
|
|
|
|
(define-values (bag2 outcome2) (bag-change (F) v -1))
|
|
|
|
(F bag2)
|
|
|
|
(when (eq? outcome2 'present->absent) on-remove.expr)))])))))]))
|
2021-06-21 12:39:41 +00:00
|
|
|
|
|
|
|
(-define-query (query-set field-name args ...) (set) query-set*)
|
|
|
|
|
|
|
|
(define-syntax (query-set* stx)
|
|
|
|
(syntax-parse stx
|
|
|
|
[(_ field-name P expr on-add:on-add on-remove:on-remove)
|
|
|
|
(quasisyntax/loc stx
|
|
|
|
(let ((F field-name)
|
|
|
|
(b (make-bag)))
|
|
|
|
(assert
|
|
|
|
(Observe (:pattern P)
|
|
|
|
(object #:name 'field-name
|
2022-12-24 08:08:57 +00:00
|
|
|
[#:asserted* bindings
|
|
|
|
(pattern-binding-let [P bindings]
|
|
|
|
(define v expr)
|
|
|
|
(when (eq? (bag-change! b v 1) 'absent->present)
|
|
|
|
(F (set-add (F) v))
|
|
|
|
on-add.expr)
|
|
|
|
(lambda ()
|
|
|
|
(when (eq? (bag-change! b v -1) 'present->absent)
|
|
|
|
(F (set-remove (F) v))
|
|
|
|
on-remove.expr)))])))))]))
|
2021-06-21 12:39:41 +00:00
|
|
|
|
|
|
|
(-define-query (query-hash field-name args ...) (hash) query-hash*)
|
|
|
|
|
|
|
|
(define-syntax (query-hash* stx)
|
|
|
|
(syntax-parse stx
|
|
|
|
[(_ field-name P key-expr value-expr on-add:on-add on-remove:on-remove)
|
|
|
|
(quasisyntax/loc stx
|
|
|
|
(let ((F field-name))
|
|
|
|
(assert
|
|
|
|
(Observe (:pattern P)
|
|
|
|
(object #:name 'field-name
|
2022-12-24 08:08:57 +00:00
|
|
|
[#:asserted* bindings
|
|
|
|
(pattern-binding-let [P bindings]
|
|
|
|
(define k key-expr)
|
|
|
|
(define v value-expr)
|
|
|
|
(when (hash-has-key? (F) k)
|
|
|
|
(log-warning
|
|
|
|
"query-hash: field ~s with pattern ~s: overwriting existing entry ~s"
|
|
|
|
'field-name
|
|
|
|
'P
|
|
|
|
k))
|
|
|
|
(F (hash-set (F) k v))
|
|
|
|
on-add.expr
|
|
|
|
(lambda ()
|
|
|
|
(F (hash-remove (F) k))
|
|
|
|
on-remove.expr))])))))]))
|
2021-06-21 12:39:41 +00:00
|
|
|
|
|
|
|
(define-syntax-rule (define/query-value id ae P x ...) (define id (query-value id ae P x ...)))
|
|
|
|
(define-syntax-rule (define/query-count id P x ...) (define id (query-count id P x ...)))
|
|
|
|
(define-syntax-rule (define/query-set id P x ...) (define id (query-set id P x ...)))
|
|
|
|
(define-syntax-rule (define/query-hash id P x ...) (define id (query-hash id P x ...)))
|
|
|
|
|
|
|
|
(define-syntax (let/query stx)
|
|
|
|
(syntax-case stx ()
|
|
|
|
[(_ ((name (op args ...)) ...) body ...)
|
|
|
|
(syntax/loc stx
|
2022-11-25 12:50:36 +00:00
|
|
|
(begin (react (define name (op query-result args ...)) ...
|
|
|
|
(sync! this-target
|
|
|
|
(stop-current-facet body ...)))
|
|
|
|
(void)))]))
|
2021-06-21 12:39:41 +00:00
|
|
|
|
|
|
|
;;---------------------------------------------------------------------------
|
|
|
|
;;; Local Variables:
|
|
|
|
;;; eval: (put 'let/query 'racket-indent-function 1)
|
|
|
|
;;; End:
|