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))]))])])]]))