Add insert! to frp

main
Eric Ihli 4 years ago
parent f5aedcb510
commit d780502a7c

@ -1,8 +1,11 @@
(ns com.owoga.frp.infrastructure)
(ns com.owoga.frp.infrastructure
(:require [clojure.set :as set]))
(defprotocol PRelations
(load! [this relations])
(insert! [this relation])
(delete! [this relation])
(insert!
[this relation]
[this & relations])
(delete! [this & relations])
(update! [this old-relation new-relation])
(clear! [this]))
@ -17,12 +20,16 @@
(divide [this relvar])
(rename [this renames]))
(declare project-)
(declare restrict-)
(deftype RelVar [relvar xf]
PRelVar
(project
[this attributes]
(project- this (map #(select-keys % attributes))))
(restrict
[this criteria]
(restrict- this (filter criteria)))
clojure.lang.IDeref
(deref [_] (into #{} xf @relvar)))
@ -32,9 +39,18 @@
(project
[this attributes]
(project- this (map #(select-keys % attributes))))
(restrict
[this criteria]
(restrict- this (filter criteria)))
PRelations
(load! [this relations] (reset! store relations))
(insert!
[this relation]
(swap! store conj relation))
(insert!
[this & relations]
(swap! store set/union (into #{} relations)))
clojure.lang.IDeref
(deref [_] @store))
@ -42,5 +58,8 @@
(defn project- [relvar xf]
(->RelVar relvar xf))
(defn restrict- [relvar xf]
(->RelVar relvar xf))
(defmacro defrelvar
[relvar-name & specs])

@ -91,8 +91,10 @@ Let's start by imagining a nice syntax for this.
#+BEGIN_SRC clojure :noweb no-export
(defprotocol PRelations
(load! [this relations])
(insert! [this relation])
(delete! [this relation])
(insert!
[this relation]
[this & relations])
(delete! [this & relations])
(update! [this old-relation new-relation])
(clear! [this]))
@ -110,9 +112,32 @@ Let's start by imagining a nice syntax for this.
** Relvar implementation
The =project= function of a relvar will be returning another relvar. The
implementation might look something like this:
#+BEGIN_SRC clojure
(deftype DerivedRelvar [relvar xf]
PRelVar
(project [this attributes] (->DerivedRelvar this (map #(select-keys % attributes)))))
#+END_SRC
I noticed though that an implementation can't refer to the type that it's
defined in. =->DerivedRelvar= isn't yet defined when you try to use it inside
that =project= function.
A workaround I'm using is to declare a =project-= function before the =deftype=
and use that declared function in the implementation. Then implement the
aforementioned declared function after the deftype.
Clojure is still fairly new to me. I'm curious if this "makes sense" as a way of
implementing these types/functions.
=RelVar= will implement =IDeref= which will be a way to access the relation associated with the =RelVar=.
#+NAME: relvar implementations
#+BEGIN_SRC clojure :noweb yes
(declare project-)
(declare restrict-)
(deftype RelVar [relvar xf]
PRelVar
@ -134,6 +159,9 @@ Let's start by imagining a nice syntax for this.
(defn project- [relvar xf]
(->RelVar relvar xf))
(defn restrict- [relvar xf]
(->RelVar relvar xf))
(defmacro defrelvar
[relvar-name & specs])
#+END_SRC
@ -143,6 +171,9 @@ Let's start by imagining a nice syntax for this.
(project
[this attributes]
(project- this (map #(select-keys % attributes))))
(restrict
[this criteria]
(restrict- this (filter criteria)))
#+END_SRC
#+NAME: relational algebra for base relvars
@ -150,22 +181,32 @@ Let's start by imagining a nice syntax for this.
(project
[this attributes]
(project- this (map #(select-keys % attributes))))
(restrict
[this criteria]
(restrict- this (filter criteria)))
#+END_SRC
#+NAME: relations manipulations
#+BEGIN_SRC clojure
(load! [this relations] (reset! store relations))
(insert!
[this relation]
(swap! store conj relation))
(insert!
[this & relations]
(swap! store set/union (into #{} relations)))
#+END_SRC
** Relvar infrastructure
#+BEGIN_SRC clojure :noweb no-export :tangle ../frp/infrastructure.clj
(ns com.owoga.frp.infrastructure)
(ns com.owoga.frp.infrastructure
(:require [clojure.set :as set]))
<<relvar protocols>>
<<relvar implementations>>
#+END_SRC
#+BEGIN_SRC clojure
#+BEGIN_SRC clojure :results pp
(ns example
(:require [com.owoga.frp.infrastructure :refer [->BaseRelVar project load!]]))
@ -173,15 +214,13 @@ Let's start by imagining a nice syntax for this.
(def OfferPrices (project Offer [:price]))
(load! Offer #{{:address "123 Fake St." :price 2e5}})
(println @OfferPrices)
(assert (= #{{:price 2e5}} @OfferPrices))
(print @OfferPrices)
#+END_SRC
#+RESULTS:
| class java.lang.IllegalAccessError |
| class clojure.lang.Compiler$CompilerException |
| class clojure.lang.Compiler$CompilerException |
| class clojure.lang.Compiler$CompilerException |
| class java.lang.ClassCastException |
: #{{:price 200000.0}}
:
** Derived Relvar implementation
@ -194,9 +233,6 @@ every time the relations of its base relvar are updated.
#+NAME: essential state infrastructure
#+BEGIN_SRC clojure :noweb no-export
(defprotocol PRelVar
(relset! [this relations]))
(def constraints (atom {}))
(defmacro candidate-key [relvar tuple]
@ -328,7 +364,6 @@ A specification of the required interfaces to the outside world.
<<interface (feeders and observers)>>
#+END_SRC
* Essential Logic
Derived relvar names and definitions.
@ -403,3 +438,24 @@ Despite this the intention is not for observers to be used as a substitute for t
(fn [key ref old-state new-state]
(pprint new-state)))
#+END_SRC
* Tests
#+BEGIN_SRC clojure :tangle ../../../../test/com/owoga/frp/infrastructure-test.clj
(ns com.owoga.frp.infrastructure-test
(:require [com.owoga.frp.infrastructure :as frp]
[clojure.test :refer [deftest is testing]]))
(deftest test-project
(testing "projection"
(let [Offer (frp/->BaseRelVar 'Offer nil (atom #{}))
OfferPrices (frp/project Offer [:price])]
(frp/load! Offer #{{:address "123 Fake St." :price 2e5}})
(is (= @OfferPrices #{{:price 2e5}})))))
(deftest test-insert!
(testing "insert!"
(let [Offer (frp/->BaseRelVar 'Offer nil (atom #{}))]
(frp/insert! Offer {:address "123 Fake St." :price 1.5e5})
(is (= @Offer #{{:address "123 Fake St." :price 1.5e5}})))))
#+END_SRC

@ -0,0 +1,17 @@
(ns com.owoga.frp.infrastructure-test
(:require [com.owoga.frp.infrastructure :as frp]
[clojure.test :refer [deftest is testing]]))
(deftest test-insert!
(testing "insert!"
(let [Offer (frp/->BaseRelVar 'Offer nil (atom #{}))]
(frp/insert! Offer {:address "123 Fake St." :price 1.5e5})
(is (= @Offer #{{:address "123 Fake St." :price 1.5e5}})))))
(deftest test-project
(testing "projection"
(let [Offer (frp/->BaseRelVar 'Offer nil (atom #{}))
OfferPrices (frp/project Offer [:price])]
(frp/load! Offer #{{:address "123 Fake St." :price 2e5}})
(is (= @OfferPrices #{{:price 2e5}})))))
Loading…
Cancel
Save