|
|
@ -108,14 +108,23 @@ every time the relations of its base relvar are updated.
|
|
|
|
|
|
|
|
|
|
|
|
(defprotocol PRelVar
|
|
|
|
(defprotocol PRelVar
|
|
|
|
(restrict [this criteria])
|
|
|
|
(restrict [this criteria])
|
|
|
|
|
|
|
|
(restrict [this criteria & constraints])
|
|
|
|
(project [this attributes])
|
|
|
|
(project [this attributes])
|
|
|
|
|
|
|
|
(project [this attributes & constraints])
|
|
|
|
(product [this relvar])
|
|
|
|
(product [this relvar])
|
|
|
|
|
|
|
|
(product [this relvar & constraints])
|
|
|
|
(union [this relvar])
|
|
|
|
(union [this relvar])
|
|
|
|
|
|
|
|
(union [this relvar & constraints])
|
|
|
|
(intersection [this relvar])
|
|
|
|
(intersection [this relvar])
|
|
|
|
|
|
|
|
(intersection [this relvar & contstraints])
|
|
|
|
(difference [this relvar])
|
|
|
|
(difference [this relvar])
|
|
|
|
|
|
|
|
(difference [this relvar & constraints])
|
|
|
|
(join [this relvar])
|
|
|
|
(join [this relvar])
|
|
|
|
|
|
|
|
(join [this relvar & constraints])
|
|
|
|
(divide [this relvar])
|
|
|
|
(divide [this relvar])
|
|
|
|
(rename [this renames]))
|
|
|
|
(divide [this relvar & constraints])
|
|
|
|
|
|
|
|
(rename [this renames])
|
|
|
|
|
|
|
|
(rename [this renames & constraints]))
|
|
|
|
#+END_SRC
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
|
|
|
|
** Part 1. of Infrastructure for Essential State
|
|
|
|
** Part 1. of Infrastructure for Essential State
|
|
|
@ -147,7 +156,7 @@ implementing these types/functions.
|
|
|
|
(declare project-)
|
|
|
|
(declare project-)
|
|
|
|
(declare restrict-)
|
|
|
|
(declare restrict-)
|
|
|
|
|
|
|
|
|
|
|
|
(deftype RelVar [relvar xf]
|
|
|
|
(deftype RelVar [relvar xf constraints]
|
|
|
|
PRelVar
|
|
|
|
PRelVar
|
|
|
|
<<relational algebra for derived relvars>>
|
|
|
|
<<relational algebra for derived relvars>>
|
|
|
|
|
|
|
|
|
|
|
@ -164,11 +173,11 @@ implementing these types/functions.
|
|
|
|
clojure.lang.IDeref
|
|
|
|
clojure.lang.IDeref
|
|
|
|
(deref [_] @store))
|
|
|
|
(deref [_] @store))
|
|
|
|
|
|
|
|
|
|
|
|
(defn project- [relvar xf]
|
|
|
|
(defn project- [relvar xf constraints]
|
|
|
|
(->RelVar relvar xf))
|
|
|
|
(->RelVar relvar xf constraints))
|
|
|
|
|
|
|
|
|
|
|
|
(defn restrict- [relvar xf]
|
|
|
|
(defn restrict- [relvar xf constraints]
|
|
|
|
(->RelVar relvar xf))
|
|
|
|
(->RelVar relvar xf constraints))
|
|
|
|
|
|
|
|
|
|
|
|
<<constraints>>
|
|
|
|
<<constraints>>
|
|
|
|
#+END_SRC
|
|
|
|
#+END_SRC
|
|
|
@ -180,21 +189,21 @@ map/select-keys can be replaced by =set/project=.
|
|
|
|
#+NAME: relational algebra for derived relvars
|
|
|
|
#+NAME: relational algebra for derived relvars
|
|
|
|
#+BEGIN_SRC clojure
|
|
|
|
#+BEGIN_SRC clojure
|
|
|
|
(project
|
|
|
|
(project
|
|
|
|
[this attributes]
|
|
|
|
[this attributes constraints]
|
|
|
|
(project- this (map #(select-keys % attributes))))
|
|
|
|
(project- this (map #(select-keys % attributes)) constraints))
|
|
|
|
(restrict
|
|
|
|
(restrict
|
|
|
|
[this criteria]
|
|
|
|
[this criteria constraints]
|
|
|
|
(restrict- this (filter criteria)))
|
|
|
|
(restrict- this (filter criteria) constraints))
|
|
|
|
#+END_SRC
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
|
|
|
|
#+NAME: relational algebra for base relvars
|
|
|
|
#+NAME: relational algebra for base relvars
|
|
|
|
#+BEGIN_SRC clojure
|
|
|
|
#+BEGIN_SRC clojure
|
|
|
|
(project
|
|
|
|
(project
|
|
|
|
[this attributes]
|
|
|
|
[this attributes constraints]
|
|
|
|
(project- this (map #(select-keys % attributes))))
|
|
|
|
(project- this (map #(select-keys % attributes)) constraints))
|
|
|
|
(restrict
|
|
|
|
(restrict
|
|
|
|
[this criteria]
|
|
|
|
[this criteria constraints]
|
|
|
|
(restrict- this (filter criteria)))
|
|
|
|
(restrict- this (filter criteria) constraints))
|
|
|
|
#+END_SRC
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
|
|
|
|
#+NAME: relations manipulations
|
|
|
|
#+NAME: relations manipulations
|
|
|
@ -202,20 +211,22 @@ map/select-keys can be replaced by =set/project=.
|
|
|
|
(load! [this relations] (reset! store relations))
|
|
|
|
(load! [this relations] (reset! store relations))
|
|
|
|
(insert!
|
|
|
|
(insert!
|
|
|
|
[this relation]
|
|
|
|
[this relation]
|
|
|
|
|
|
|
|
(let [new-relation (conj @store relation)]
|
|
|
|
(run!
|
|
|
|
(run!
|
|
|
|
(fn [constraint]
|
|
|
|
(fn [constraint]
|
|
|
|
(when (constraint @this)
|
|
|
|
(when (not (every? true? (constraint new-relation)))
|
|
|
|
(throw (ex-info "Constraint Exception" {}))))
|
|
|
|
(throw (ex-info "Constraint Exception" {}))))
|
|
|
|
constraints)
|
|
|
|
constraints)
|
|
|
|
(swap! store conj relation))
|
|
|
|
(reset! store new-relation)))
|
|
|
|
(insert!
|
|
|
|
(insert!
|
|
|
|
[this & relations]
|
|
|
|
[this & relations]
|
|
|
|
|
|
|
|
(let [new-relation (set/union @store (into #{} relations))]
|
|
|
|
(run!
|
|
|
|
(run!
|
|
|
|
(fn [constraint]
|
|
|
|
(fn [constraint]
|
|
|
|
(when (constraint @this)
|
|
|
|
(when (not (every? true? (constraint new-relation)))
|
|
|
|
(throw (ex-info "Constraint Exception" {}))))
|
|
|
|
(throw (ex-info "Constraint Exception" {}))))
|
|
|
|
constraints)
|
|
|
|
constraints)
|
|
|
|
(swap! store set/union (into #{} relations)))
|
|
|
|
(reset! store new-relation)))
|
|
|
|
#+END_SRC
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
|
|
|
|
** Relvar infrastructure
|
|
|
|
** Relvar infrastructure
|
|
|
@ -271,6 +282,21 @@ loaded
|
|
|
|
`(->BaseRelVar '~relvar-name (atom #{}) [~@constraints]))
|
|
|
|
`(->BaseRelVar '~relvar-name (atom #{}) [~@constraints]))
|
|
|
|
#+END_SRC
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
#+NAME: test defrelvar
|
|
|
|
|
|
|
|
#+BEGIN_SRC clojure
|
|
|
|
|
|
|
|
(deftest test-defrelvar
|
|
|
|
|
|
|
|
(testing "failed constraint raises"
|
|
|
|
|
|
|
|
(let [Offer (frp/defrelvar Offer (fn [offers] (map #(> (:price %) 0) offers)))]
|
|
|
|
|
|
|
|
(is (thrown-with-msg?
|
|
|
|
|
|
|
|
Exception
|
|
|
|
|
|
|
|
#"Constraint Exception"
|
|
|
|
|
|
|
|
(frp/insert! Offer {:price -1})))))
|
|
|
|
|
|
|
|
(testing "passed constraint doesn't raise"
|
|
|
|
|
|
|
|
(let [Offer (frp/defrelvar Offer (fn [offers] (map #(> (:price %) 0) offers)))]
|
|
|
|
|
|
|
|
(frp/insert! Offer {:price 20})
|
|
|
|
|
|
|
|
(is (= @Offer #{{:price 20}})))))
|
|
|
|
|
|
|
|
#+END_SRC
|
|
|
|
|
|
|
|
|
|
|
|
#+NAME: essential state infrastructure
|
|
|
|
#+NAME: essential state infrastructure
|
|
|
|
#+BEGIN_SRC clojure :noweb no-export
|
|
|
|
#+BEGIN_SRC clojure :noweb no-export
|
|
|
|
|
|
|
|
|
|
|
@ -473,7 +499,7 @@ Despite this the intention is not for observers to be used as a substitute for t
|
|
|
|
|
|
|
|
|
|
|
|
* Tests
|
|
|
|
* Tests
|
|
|
|
|
|
|
|
|
|
|
|
#+BEGIN_SRC clojure :tangle ../../../../test/com/owoga/frp/infrastructure-test.clj
|
|
|
|
#+BEGIN_SRC clojure :noweb yes :tangle ../../../../test/com/owoga/frp/infrastructure-test.clj
|
|
|
|
(ns com.owoga.frp.infrastructure-test
|
|
|
|
(ns com.owoga.frp.infrastructure-test
|
|
|
|
(:require [com.owoga.frp.infrastructure :as frp]
|
|
|
|
(:require [com.owoga.frp.infrastructure :as frp]
|
|
|
|
[clojure.test :refer [deftest is testing]]))
|
|
|
|
[clojure.test :refer [deftest is testing]]))
|
|
|
@ -491,11 +517,5 @@ Despite this the intention is not for observers to be used as a substitute for t
|
|
|
|
(frp/insert! Offer {:address "123 Fake St." :price 1.5e5})
|
|
|
|
(frp/insert! Offer {:address "123 Fake St." :price 1.5e5})
|
|
|
|
(is (= @Offer #{{:address "123 Fake St." :price 1.5e5}})))))
|
|
|
|
(is (= @Offer #{{:address "123 Fake St." :price 1.5e5}})))))
|
|
|
|
|
|
|
|
|
|
|
|
(deftest test-defrelvar
|
|
|
|
<<test defrelvar>>
|
|
|
|
(testing "macro works"
|
|
|
|
|
|
|
|
(let [Offer (frp/defrelvar Offer (fn [offers] (map #(> (:price %) 0) offers)))]
|
|
|
|
|
|
|
|
(is (thrown-with-msg?
|
|
|
|
|
|
|
|
Exception
|
|
|
|
|
|
|
|
#"Constraint Exception"
|
|
|
|
|
|
|
|
(frp/insert! Offer {:price -1}))))))
|
|
|
|
|
|
|
|
#+END_SRC
|
|
|
|
#+END_SRC
|
|
|
|