git.fiddlerwoaroof.com
Raw Blame History
(page "index.html"
  (:require [datascript.core :as d]
            [clojure.string :as cstr]))

(def db (let [schema {:aka {:db/cardinality :db.cardinality/many}}
              conn (d/create-conn schema)]
          (d/transact! conn [ {:db/id -1
                               :name "Maksim"
                               :age 45
                               :aka ["." "Max Otto von Stierlitz", "Jack Ryan"]} ])
          (d/transact! conn [ {:db/id -1
                               :name "Foom"
                               :age 45
                               :aka ["."]} ])
          conn))

(def search-query
  '[:find  ?n (distinct ?k)
    :in $ ?startsWith %
    :where
    (dothings ?startsWith ?e)
    [?e :name ?n]
    [?e :aka ?k]])

(def search-rules
  '[[(dothings ?startsWith ?e)
     [?e :name ?n]
     [(?startsWith ?n)]]
    [(dothings ?startsWith ?e)
     [?e :aka ?n]
     [(?startsWith ?n)]]])

(defn do-query [prefix]
  (d/q search-query
       @db
       (fn [e] (cstr/starts-with? (cstr/lower-case e)
                                  (cstr/lower-case prefix)))
       search-rules))

(def initial-state
  {})

(defn init-search-panel [state]
  (let [initial-search ""
        initial-results (do-query initial-search)]
    (assoc state :search-panel {:current-search initial-search
                                :search-results initial-results})))

(defn init-add-contact [state]
  (assoc state :add-contact {}))

(defc state
  ((comp init-search-panel
         init-add-contact)
   initial-state))

(defc= search-panel
  (get state :search-panel)
  #(dosync
    (swap! state assoc :search-panel %)))

(defc= search
  (get search-panel :current-search)
  #(dosync
    (reset! search-panel {:current-search %
                          :search-results (do-query %)})))

(d/listen! db :datascript->hoplon #(swap! search-panel assoc :search-results
                                          (do-query (:current-search @search-panel))))

(defc= search-results (get search-panel :search-results))

(defc= add-contact-data
  (:add-contact state)
  #(swap! state assoc :add-contact %))

(defc= new-contact-name
  (:name add-contact-data)
  #(swap! add-contact-data assoc :name %))

(defc= new-contact-age
  (:age add-contact-data)
  #(swap! add-contact-data assoc :age %))

(defc= new-contact-aka
  (:aka add-contact-data)
  #(swap! add-contact-data assoc :aka ["." %]))

(defn starts-with? [s ss]
  (cstr/starts-with? s ss))

(def event-value
  #(.-value (.-target %)))

(html
 (head (link :href "app.css" :rel "stylesheet" :type "text/css"))
 (body (h1 "My Contacts")
       (section :id "add-contact"
                (form (input :type "text"
                             :placeholder "name"
                             :value new-contact-name
                             :keyup #(reset! new-contact-name (event-value %)))
                      (input :type "text"
                             :placeholder "age"
                             :value new-contact-age
                             :keyup #(reset! new-contact-age (event-value %)))
                      (input :type "text"
                             :placeholder "aka"
                             :value (cell= (and new-contact-aka (second new-contact-aka)))
                             :keyup #(reset! new-contact-aka (event-value %)))
                      (button :click #(do (.preventDefault %)
                                          (d/transact! db
                                                       [{:db/id -1
                                                         :name @new-contact-name
                                                         :age @new-contact-age
                                                         :aka @new-contact-aka}]))
                              "Add Contact")))
       (section :id "do-search"
                (div search)
                (input :type "text" :value search :keyup #(reset! search (event-value %))
                       :placeholder "query »")

                (div :id "results"
                     (for-tpl [[name aka] search-results]
                       (div (h2 name)
                            (ul
                             (for-tpl [alias (cell= (rest aka))]
                               (li alias)))))))
       ))