Last active
December 20, 2022 13:47
-
-
Save rynkowsg/690ca7f7985e702df70623500d806199 to your computer and use it in GitHub Desktop.
Atom DB with nav support
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
(ns atom-db | |
(:require | |
[clojure.core.protocols :as ccp] | |
[clojure.datafy :as cd])) | |
(defn init-db [] | |
(atom {})) | |
(defn- navigify [db path] | |
(vary-meta | |
path | |
assoc | |
:db db | |
`ccp/datafy (fn [v] | |
(with-meta | |
{:value v} | |
{`ccp/nav (fn [xs k v] | |
(let [db (-> xs k meta :db deref)] | |
(get-in db v)))})))) | |
(defn add-item [db path item] | |
(let [res (atom nil) | |
assoc-next (fn [s] | |
(let [items-count (count (get-in s path)) | |
item-id items-count | |
full-path (navigify db (conj path item-id)) | |
ident (last path) | |
item-with-id (assoc item ident item-id) | |
item' (vary-meta item-with-id assoc :path full-path)] | |
(reset! res full-path) | |
(assoc-in s full-path item')))] | |
(swap! db assoc-next) | |
@res)) | |
(defn get-item | |
([path] | |
(get-in (some-> path meta :db deref) path)) | |
([db path] | |
(get-in (-> db deref) path))) | |
(comment | |
@(def db (init-db)) | |
@(def product0 (add-item db [:product/id] {:name "backpack"})) | |
@(def product1 (add-item db [:product/id] {:name "laptop"})) | |
@(def product2 (add-item db [:product/id] {:name "ball"})) | |
@(def person0 (add-item db [:person/id] {:name "Mike" :friends []})) | |
@(def person1 (add-item db [:person/id] {:name "Tom" :friends [person0]})) | |
@(def person2 (add-item db [:person/id] {:name "Alice" :friends [person0 person1]})) | |
@(def tx0 (add-item db [:tx/id] {:kind :purchase :person person0 :product product0})) | |
@(def tx1 (add-item db [:tx/id] {:kind :purchase :person person1 :product product1})) | |
@(def tx2 (add-item db [:tx/id] {:kind :purchase :person person2 :product product2})) | |
(deref db) | |
(get-item db [:person/id 2]) | |
(get-item person2) | |
(get-item db [:product/id 2]) | |
(get-item product2) | |
(get-item db [:tx/id 2]) | |
(get-item tx2) | |
(as-> | |
;; pick third tx | |
(get-item db [:tx/id 2]) $ | |
;; pick person from the tx | |
(:person $) | |
;; datafy it & nav | |
(cd/datafy $) | |
(cd/nav $ :value (:value $)) | |
;; pick second friend of that person | |
(cd/nav $ :friends (:friends $)) | |
(cd/nav $ 1 (get $ 1)) | |
;; datafy it & nav | |
(cd/datafy $) | |
(cd/nav $ :value (:value $)) | |
;; pick only friend of that person | |
(cd/nav $ :friends (:friends $)) | |
(cd/nav $ 0 (get $ 0)) | |
;; datafy it & nav | |
(cd/datafy $) | |
(cd/nav $ :value (:value $)))) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment