diff --git a/src/wanijo/public/db.clj b/src/wanijo/public/db.clj
index d55430a..15c43ec 100644
--- a/src/wanijo/public/db.clj
+++ b/src/wanijo/public/db.clj
@@ -200,8 +200,16 @@
WHERE toLower(i.name) =~ toLower('(?s).*' + {term} + '.*')
OR toLower(p.name) =~ toLower('(?s).*' + {term} + '.*')
OR toLower(p.value) =~ toLower('(?s).*' + {term} + '.*')
+ MATCH (cocs:instance)
+ WHERE cocs.uuid IN {coc_uuids}
+ WITH i, p, s,
+ shortestPath((i)<-[:link*0..5]-(cocs)) AS path
+ WHERE path IS NOT NULL
+ UNWIND nodes(path) AS segment
+ MATCH (segment)-[:of]->(segment_schema:schema)
RETURN i, p, s,
- (i)--(:instance {uuid:{coc_uuids}}) AS path,
+ segment,
+ segment_schema,
CASE
WHEN toLower(i.name) =~ toLower('(?s).*' + {term} + '.*') THEN
i.name
@@ -209,7 +217,45 @@
p.name
ELSE
p.value
- END AS m")
+ END AS hit")
+(defn uuid->coc-key [instance-uuid]
+ (-> coc-instance-uuids
+ map-invert
+ (get instance-uuid)
+ keyword))
+(comment
+ (uuid->coc-key "73f69c1b-5106-44bb-b5e1-90c4f3847037")
+ (uuid->coc-key "2c507f67-600d-4add-b648-2ea62d5a4ffc"))
+(defn build-path [segments segment-schemas]
+ (let [merged (map (fn merge-segment-schema [seg schema]
+ (assoc seg :schema schema))
+ segments segment-schemas)]
+ (map (fn assoc-coc-key [row]
+ (if (= :coc (-> row :schema :which))
+ (assoc row :key
+ (uuid->coc-key (:uuid row)))
+ row))
+ merged)))
+(comment
+ (build-path [{:uuid "73f69c1b-5106-44bb-b5e1-90c4f3847037"}
+ {:uuid "bla bla"}]
+ [{:which :coc}
+ {:which :comp}]))
+(defn group-search-result [[instance row]]
+ (let [segments (map :segment row)
+ segment-schemas (->> row
+ (map :segment_schema)
+ (map #(assoc % :which
+ (get (map-invert schema-uuids)
+ (:uuid %)))))]
+ (assoc instance
+ :props (->> row
+ (map :p)
+ (filter some?)
+ distinct)
+ :match (-> row first :hit)
+ :schema (-> row first :s)
+ :path-to-coc (build-path segments segment-schemas))))
(spec/def ::props
(spec/coll-of
(spec/keys :req-un [::specs/created_at
@@ -217,6 +263,7 @@
::specs/uuid
::specs/value])))
(spec/def ::which (set (keys schema-uuids)))
+(spec/def ::key (set (map keyword (keys coc-instance-uuids))))
(spec/def ::schema
(spec/keys :req-un [::specs/name
::specs/created_at
@@ -224,6 +271,12 @@
::which]))
(spec/def ::match (spec/and string?
not-empty))
+(spec/def ::path-to-coc
+ (spec/coll-of
+ (spec/keys :req-un [::specs/name
+ ::specs/uuid
+ ::schema]
+ :opt-un [::key])))
(spec/def ::search-result-list
(spec/coll-of
(spec/keys :req-un [::specs/name
@@ -232,18 +285,17 @@
::specs/uuid
::props
::match
- ::schema])))
+ ::schema
+ ::path-to-coc
+ ::which])))
(defn search! [term]
{:post [(spec/assert ::search-result-list %)]}
- (let [results (->> (neo4j/exec-query! search {:term term
- :coc_uuids (vals coc-instance-uuids)})
+ (let [results (->> (neo4j/exec-query!
+ search
+ {:term term
+ :coc_uuids (vals coc-instance-uuids)})
(group-by :i)
- (map #(assoc (key %)
- :props (filter some?
- (map :p (val %)))
- :match (-> (val %) first :m)
- :schema (-> (val %) first :s)
- :path (-> (val %) first :path)))
+ (map group-search-result)
(sort-by :updated_at #(compare %2 %1)))]
(map (fn [finding]
(assoc-in finding
@@ -254,4 +306,18 @@
(comment
(search! "Builtools")
(search! "Arschitektur")
- (search! "Angular"))
+ (search! "Angular")
+ (neo4j/exec-query!
+ search
+ {:term "Angular"
+ :coc_uuids (vals coc-instance-uuids)})
+ (neo4j/defquery path-query
+ "match
+ (coc:instance)-[:of]->(:schema {uuid:'f0dae806-c82e-4ced-a39e-c7aef5442579'}),
+ (i:instance {uuid:'0b30521a-0727-4a6b-b69e-6f3c554a81b2'})
+ with i,
+ shortestPath((i)<-[:link*..4]-(coc)) as path
+ where path is not null
+ return i,
+ nodes(path) as path")
+ (neo4j/exec-query! path-query {}))
diff --git a/src/wanijo/public/view.clj b/src/wanijo/public/view.clj
index 91b4222..8c11ca8 100644
--- a/src/wanijo/public/view.clj
+++ b/src/wanijo/public/view.clj
@@ -220,10 +220,38 @@
(h (:name module))]]
[:li.breadcrumb-item.active (h (:name comp))])]))
-(defn replace-with-mark [s term]
- (string/replace (h s)
- (re-pattern (str "(?i)" term))
- #(str "" % "")))
+(defn highlight-match [s term]
+ (let [matches (re-find (re-pattern (str "(?im)^(.*)(" term ")(.*)$"))
+ (h s))]
+ (str (nth matches 1)
+ ""
+ (nth matches 2)
+ ""
+ (last matches))))
+
+(defn search-result-link [schema path-to-coc]
+ (let [coc-key (name (:key (last path-to-coc)))
+ find-uuid (fn [which]
+ (->> path-to-coc
+ (filter #(= which (-> % :schema :which)))
+ first
+ :uuid))]
+ (case (:which schema)
+ :coc (path :public-coc
+ {:coc coc-key})
+ :role (path :public-role
+ {:coc coc-key
+ :role (find-uuid :role)})
+ :level (path :public-level
+ {:coc coc-key
+ :level (find-uuid :level)})
+ :module (path :public-module
+ {:coc coc-key
+ :module (find-uuid :module)})
+ :component (path :public-comp
+ {:coc coc-key
+ :module (find-uuid :module)
+ :comp (find-uuid :component)}))))
(defn show-search-result [term results]
(layout
@@ -234,10 +262,17 @@
[:p.mt-5 "Es konnten keine Ergebnisse gefunden werden"])
(when (seq results)
[:div.list-group.mt-5
- (for [{:keys [name updated_at match]} results]
+ (for [{:keys [name updated_at match
+ schema path-to-coc]} results]
[:div.list-group-item.list-group-item-action
[:div.d-flex.w-100.justify-content-between
- [:h5.mb-1 (replace-with-mark name term)]
+ [:h5.mb-1
+ [:a {:href (search-result-link schema path-to-coc)}
+ (if (= match name)
+ (highlight-match name term)
+ (h name))]]
[:small (prettify-dt updated_at)]]
(when (not= match name)
- (list [:p [:pre (replace-with-mark match term)]]))])])]]))
+ (list [:p.markdown-content
+ (md/md-to-html-string
+ (highlight-match match term))]))])])]]))