-
Notifications
You must be signed in to change notification settings - Fork 8
/
entity.cljs
115 lines (100 loc) · 3.73 KB
/
entity.cljs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
(ns datalog-console.components.entity
{:no-doc true}
(:require [datascript.core :as d]
[reagent.core :as r]
[cljs.reader]
[goog.object]
[clojure.string :as str]
[datalog-console.components.tree-table :as c.tree-table]))
(defn entity? [v]
(try
(not (nil? (:db/id v)))
(catch js/Error _e false)))
(defn expandable-row? [[_a v]]
(if (set? v)
(entity? (first v))
(entity? v)))
(defn keyword->reverse-ref [kw]
(keyword (str (namespace kw) "/_" (name kw))))
(defn ^:export reverse-refs [entity]
(->> (d/q '[:find ?ref-attr ?e
:in $ ?ref-id [?ref-attr ...]
:where [?e ?ref-attr ?ref-id]]
(d/entity-db entity)
(:db/id entity)
(for [[attr props] (:schema (d/entity-db entity))
:when (= :db.type/ref (:db/valueType props))]
attr))
(group-by first)
(reduce-kv (fn [acc k v]
(conj acc [(keyword->reverse-ref k)
(set (for [[_ eid] v] (d/entity (d/entity-db entity) eid)))]))
[])))
(defn entity->rows [entity]
(concat
[[:db/id (:db/id entity)]]
(sort (seq entity))
(sort (reverse-refs entity))))
(defn expand-row [[a v]]
(cond
(set? v) (map-indexed (fn [i vv] [(str a " " i) vv]) v)
(entity? v) (entity->rows v)))
(defn string-cell []
(let [expanded-text? (r/atom false)]
(fn [s]
(if (< (count s) 45)
[:div s]
[:div {:class (str "cursor-pointer " (if-not @expanded-text? "min-w-max" "w-96"))
:on-click #(reset! expanded-text? (not @expanded-text?))}
(if @expanded-text? s (str (subs s 0 45) "..."))]))))
(defn render-col [col]
(cond
(set? col) (str "#[" (count col) " item" (when (< 1 (count col)) "s") "]")
(entity? col) (str (select-keys col [:db/id]))
(string? col) [string-cell col]
:else (str col)))
(defn lookup-form []
(let [lookup (r/atom "")
input-error (r/atom nil)]
(fn [conn on-submit]
[:div
[:form {:class "flex items-end"
:on-submit
(fn [e]
(.preventDefault e)
(try
(d/entity @conn (cljs.reader/read-string @lookup))
(on-submit @lookup)
(reset! lookup "")
(reset! input-error nil)
(catch js/Error e
(reset! input-error (goog.object/get e "message")))))}
[:label {:class "block pl-1"}
[:p {:class "font-bold"} "Entity lookup"]
[:input {:type "text"
:name "lookup"
:value @lookup
:on-change (fn [e] (reset! lookup (goog.object/getValueByKeys e #js ["target" "value"])))
:placeholder "id or [:uniq-attr1 \"v1\" ...]"
:class "border py-1 px-2 rounded w-56"}]]
[:button {:type "submit"
:class "ml-1 py-1 px-2 rounded bg-gray-200 border"}
"Get entity"]]
(when @input-error
[:div {:class "bg-red-200 m-4 p-4 rounded"}
[:p @input-error]])])))
(defn entity []
(fn [conn entity-lookup-ratom]
(let [entity (d/entity @conn (cljs.reader/read-string @entity-lookup-ratom))]
[:div {:class "flex flex-col w-full pb-5"}
[lookup-form conn #(reset! entity-lookup-ratom %)]
[:div {:class "pt-2"}
(when entity
[c.tree-table/tree-table
{:caption (str "entity " (select-keys entity [:db/id]))
:conn conn
:head-row ["Attribute", "Value"]
:rows (entity->rows entity)
:expandable-row? expandable-row?
:expand-row expand-row
:render-col render-col}])]])))