(ns auto-ap.solr (:require [auto-ap.datomic :refer [conn pull-id]] [cemerick.url :as url] [auto-ap.time :as atime] [clj-http.client :as client] [clj-time.coerce :as c] [clojure.data.json :as json] [clojure.string :as str] [config.core :refer [env]] [datomic.api :as dc])) (defn escape [s] (str/escape s (into {} (for [c "\\+-&&||!(){}[]^\"~*?:/"] [c (str "\\" c)])))) (def solr-uri (:solr-uri env)) (defn fmt-amount [a] (with-precision 2 (some-> a bigdec (.setScale 2 java.math.RoundingMode/HALF_UP) (double)))) (defmulti datomic->solr (fn [d] (let [entity (dc/pull (dc/db conn) '[:transaction/date :invoice/date :payment/date :journal-entry/date] d)] (cond (:transaction/date entity) "transaction" (:invoice/date entity) "invoice" (:payment/date entity) "payment" (:journal-entry/date entity) "journal-entry" :else nil)))) (defmethod datomic->solr "transaction" [d] (let [i (dc/pull (dc/db conn) '[:db/id :transaction/description-original :transaction/amount {:transaction/client [:client/code :db/id] :transaction/vendor [:vendor/name :db/id]} :transaction/date] d)] {"id" (-> i :db/id) "client_id" (-> i :transaction/client :db/id) "client_code" (-> i :transaction/client :client/code) "date" (some-> i :transaction/date c/to-date-time (atime/unparse atime/iso-date) (str "T00:00:00Z")) "amount" (-> i :transaction/amount fmt-amount) "description" (-> i :transaction/description-original) "vendor_name" (-> i :transaction/vendor :vendor/name) "vendor_id" (-> i :transaction/vendor :db/id) "type" "transaction"})) (defmethod datomic->solr nil [d] nil) (defmethod datomic->solr "journal-entry" [d] (let [i (dc/pull (dc/db conn) '[:db/id :journal-entry/amount :journal-entry/source {:journal-entry/client [:client/code :db/id] :journal-entry/vendor [:vendor/name :db/id] :journal-entry/line-items [{:journal-entry-line/account [:account/name :account/numeric-code]}]} :journal-entry/date] d)] {"id" (-> i :db/id) "client_id" (-> i :journal-entry/client :db/id) "client_code" (-> i :journal-entry/client :client/code) "date" (some-> i :journal-entry/date c/to-date-time (atime/unparse atime/iso-date) (str "T00:00:00Z")) "amount" (-> i :journal-entry/amount fmt-amount) "description" (str (when (:journal-entry/source i) (str (:journal-entry/source i) ": ")) (str/join ", " (set (map (fn [li] (format "%s (%s)" (:account/name (:journal-entry-line/account li)) (:account/numeric-code (:journal-entry-line/account li)))) (:journal-entry/line-items i))))) "vendor_name" (-> i :journal-entry/vendor :vendor/name) "vendor_id" (-> i :journal-entry/vendor :db/id) "type" "journal-entry"})) (defmethod datomic->solr "invoice" [d] (let [i (dc/pull (dc/db conn) '[:db/id :invoice/invoice-number :invoice/total {:invoice/client [:client/code :db/id] :invoice/vendor [:vendor/name :db/id]} :invoice/date] d)] {"id" (-> i :db/id) "client_id" (-> i :invoice/client :db/id) "client_code" (-> i :invoice/client :client/code) "date" (some-> i :invoice/date c/to-date-time (atime/unparse atime/iso-date) (str "T00:00:00Z")) "amount" (-> i :invoice/total fmt-amount) "number" (-> i :invoice/invoice-number) "vendor_name" (-> i :invoice/vendor :vendor/name) "vendor_id" (-> i :invoice/vendor :db/id) "type" "invoice"})) (defmethod datomic->solr "payment" [d] (let [i (dc/pull (dc/db conn) '[:db/id :payment/check-number :payment/amount {:payment/client [:client/code :db/id] :payment/vendor [:vendor/name :db/id]} :payment/date] d)] {"id" (-> i :db/id) "client_id" (-> i :payment/client :db/id) "client_code" (-> i :payment/client :client/code) "date" (some-> i :payment/date c/to-date-time (atime/unparse atime/iso-date) (str "T00:00:00Z")) "amount" (-> i :payment/amount fmt-amount) "description" (-> i :payment/check-number) "vendor_name" (-> i :payment/vendor :vendor/name) "vendor_id" (-> i :payment/vendor :db/id) "type" "payment"})) (defprotocol SolrClient (index-documents-raw [this index xs]) (index-documents [this index xs]) (query [this index q]) (delete [this index])) (defrecord RealSolrClient [solr-uri] SolrClient (index-documents-raw [this index xs] (client/post (str (assoc (url/url solr-uri "solr" index "update") :query {"commitWithin" 5000 "commit" true})) {:headers {"Content-Type" "application/json"} :socket-timeout 30000 :connection-timeout 30000 :method "POST" :body (json/write-str xs)})) (index-documents [this index xs] (client/post (str (assoc (url/url solr-uri "solr" index "update") :query {"commitWithin" 5000 "commit" true})) {:headers {"Content-Type" "application/json"} :socket-timeout 30000 :connection-timeout 30000 :method "POST" :body (json/write-str (filter identity (map datomic->solr xs)))})) (query [this index q] (-> (client/post (str (url/url solr-uri "solr" index "query")) {:body (json/write-str q ) :socket-timeout 30000 :connection-timeout 30000 :headers {"Content-Type" "application/json"} :as :json} ) :body :response :docs)) (delete [this index] (client/post (str (assoc (url/url solr-uri "solr" index "update") :query {"commitWithin" 15000 "commit" true})) {:headers {"Content-Type" "application/json"} :method "POST" :body (json/write-str {"delete" {"query" "*:*"}})}))) (defrecord MockSolrClient [] SolrClient (index-documents [this index xs] nil) (index-documents-raw [this index xs] nil) (query [this index q] nil) (delete [this index] nil)) (def impl (if (= :solr (:solr-impl env)) (->RealSolrClient (:solr-uri env)) (->MockSolrClient ))) (defn touch-with-ledger [i] (index-documents impl "invoices" [i [:journal-entry/original-entity i]])) (defn touch ([i] (touch i "invoices")) ([i index] (index-documents impl index [i]))) (defrecord InMemSolrClient [data-set-atom] SolrClient (index-documents [this index xs] (swap! data-set-atom (fn [data-set] (reduce (fn [data-set x] (let [thing (datomic->solr x)] (update data-set index conj [(str/join " " (vals x)) thing]))) data-set xs))) nil) (index-documents-raw [this index xs] (swap! data-set-atom (fn [data-set] (reduce (fn [data-set x] (update data-set index conj [(str/join " " (vals x)) x])) data-set xs)))) (query [this index q] (filter (fn [[x e]] (str/includes? x (get q "query"))) (get @data-set-atom index))) (delete [this index] (swap! data-set-atom dissoc index)))