Skip to content

Commit

Permalink
Refactoring a query parser for job
Browse files Browse the repository at this point in the history
  • Loading branch information
kawasima committed Sep 26, 2016
1 parent d69c186 commit 7508cd8
Show file tree
Hide file tree
Showing 3 changed files with 82 additions and 51 deletions.
97 changes: 56 additions & 41 deletions src/clj/job_streamer/control_bus/component/jobs.clj
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@
(:require [clojure.tools.logging :as log]
[clojure.edn :as edn]
[com.stuartsierra.component :as component]
[bouncer.core :as b]
[bouncer.validators :as v]
[liberator.core :as liberator]
[clojure.string :as str]

[clj-time.format :as f]
(job-streamer.control-bus [notification :as notification]
[validation :refer [validate]]
[util :refer [parse-body edn->datoms to-int]])
Expand Down Expand Up @@ -70,56 +71,70 @@
[?job :job/name ?job-name]]}
app-name job-name))

(defn- parse-query-since [q]
(let [since (.substring q (count "since:"))]
(when (b/valid? {:since since}
:since [[v/datetime (:date f/formatters)]])
{:since (f/parse (:date f/formatters) since)})))

(defn- parse-query-until [q]
(let [until (.substring q (count "until:"))]
(when (b/valid? {:until until}
:until [[v/datetime (:date f/formatters)]])
{:until (f/parse (:date f/formatters) until)})))

(defn- parse-query-exit-status [q]
(let [exit-status (.substring q (count "exit-status:"))]
(when (b/valid? {:exit-status exit-status}
:exit-status v/required)
{:exit-status exit-status})))

(defn parse-query [query]
(loop [query-vector (str/split query #"\s")
query-map {:job-names []}]
(if-let [query-unit (first query-vector)]
(if (.startsWith query-unit "since:")
(recur (rest query-vector) (assoc query-map :since (java.sql.Date/valueOf (.substring query-unit 6))))
(if (.startsWith query-unit "until:")
(recur (rest query-vector) (assoc query-map :until (java.sql.Date/valueOf (.substring query-unit 6))))
(if (.startsWith query-unit "exit-status:")
(recur (rest query-vector) (assoc query-map :exit-status (.substring query-unit 12)))
(recur (rest query-vector) (update-in query-map [:job-names] conj query-unit)))))
query-map)))
(when (not-empty query)
(->> (str/split query #"\s")
(map #(cond
(.startsWith % "since:") (parse-query-since %)
(.startsWith % "until:") (parse-query-until %)
(.startsWith % "exit-status:") (parse-query-exit-status %)
:default {:job-name [%]}))
(apply merge-with concat {:job-name nil}))))

(defn find-all [{:keys [datomic]} app-name query & [offset limit]]
(let [query-map (if query (parse-query query) nil)
(let [qmap (parse-query query)
base-query '{:find [?job]
:in [$ ?app-name [?job-name-condition ...] ?since-condition ?until-condition ?exit-status-condition]
:where [[?app :application/name ?app-name]
[?app :application/jobs ?job]]}
job-name-condition (:job-names query-map)
since-condition (:since query-map)
until-condition (:until query-map)
exit-status-condition (:exit-status query-map)
jobs (d/query datomic
(cond-> base-query
(not-empty job-name-condition)
(update-in [:where] conj
'[?job :job/name ?job-name]
'[(.contains ^String ?job-name ?job-name-condition)])
(or since-condition until-condition exit-status-condition)
(update-in [:where] conj
'[?job :job/executions ?job-executions]
'[?job-execution :job-execution/create-time ?create-time]
'[(max ?create-time)]
'[?job-executions :job-execution/exit-status ?exit-status]
'[?job-executions :job-execution/end-time ?end-time])
since-condition
(update-in [:where] conj
'[(>= ?end-time ?since-condition)])
until-condition
(update-in [:where] conj
'[(<= ?end-time ?until-condition)])
exit-status-condition
(update-in [:where] conj
'[(.contains ^String ?exit-status ?exit-status-condition)]))
(not-empty (:job-name qmap))
(update-in [:where] conj
'[?job :job/name ?job-name]
'[(.contains ^String ?job-name ?job-name-condition)])
(or (:since qmap) (:until qmap) (:exit-status qmap))
(update-in [:where] conj
'[?job :job/executions ?job-executions]
'[?job-execution :job-execution/create-time ?create-time]
'[(max ?create-time)]
'[?job-executions :job-execution/exit-status ?exit-status]
'[?job-executions :job-execution/end-time ?end-time])

(:since qmap)
(update-in [:where] conj
'[(>= ?end-time ?since-condition)])

(:until qmap)
(update-in [:where] conj
'[(<= ?end-time ?until-condition)])

(:exit-status qmap)
(update-in [:where] conj
'[(.contains ^String ?exit-status ?exit-status-condition)]))
app-name
(or (not-empty job-name-condition) [""])
(or since-condition "")
(or until-condition "")
(or exit-status-condition ""))]
(:job-name qmap [])
(:since qmap "")
(:until qmap "")
(:exit-status qmap ""))]

{:results (->> jobs
(drop (dec (or offset 0)))
Expand Down
7 changes: 2 additions & 5 deletions src/clj/job_streamer/control_bus/system.clj
Original file line number Diff line number Diff line change
Expand Up @@ -21,9 +21,7 @@
[socketapp :refer [socketapp-component]])
(job-streamer.control-bus.endpoint
[api :refer [api-endpoint]])
[job-streamer.control-bus.endpoint.api :refer [api-endpoint]])
(:use ring.middleware.stacktrace))

[job-streamer.control-bus.endpoint.api :refer [api-endpoint]]))

(defn wrap-same-origin-policy [handler alias]
(fn [req]
Expand All @@ -39,8 +37,7 @@
(def base-config
{:app {:middleware [[wrap-not-found :not-found]
[wrap-same-origin-policy :same-origin]
[wrap-defaults :defaults]
[ring.middleware.stacktrace/wrap-stacktrace :stacktrace]]
[wrap-defaults :defaults]]

:not-found "Resource Not Found"
:defaults (meta-merge api-defaults {})}})
Expand Down
29 changes: 24 additions & 5 deletions test/clj/job_streamer/control_bus/component/jobs_test.clj
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,8 @@
[meta-merge.core :refer [meta-merge]]
[clojure.test :refer :all]
[clojure.pprint :refer :all]
[clojure.edn :as edn]))
[clojure.edn :as edn]
[clj-time.format :as f]))



Expand Down Expand Up @@ -75,7 +76,25 @@
(deftest parse-query
(testing "parse-query"
(let [result (jobs/parse-query "a b since:2016-09-01 until:2016-09-02 exit-status:COMPLETED")]
(is (= "a" (first (:job-names result))))
(is (= (java.sql.Date/valueOf "2016-09-01") (:since result)))
(is (= (java.sql.Date/valueOf "2016-09-02") (:until result)))
(is (= "COMPLETED" (:exit-status result))))))
(is (= "a" (first (:job-name result))))
(is (= "2016-09-01" (f/unparse (:date f/formatters) (:since result))))
(is (= "2016-09-02" (f/unparse (:date f/formatters) (:until result))))
(is (= "COMPLETED" (:exit-status result)))))
(testing "nil query returns nil"
(let [result (jobs/parse-query nil)]
(is (nil? result))))
(testing "empty query returns nil"
(let [result (jobs/parse-query "")]
(is (nil? result))))

(testing "single simple query"
(let [result (jobs/parse-query "a")]
(is (= {:job-name '("a")} result))))

(testing "single simple query"
(let [result (jobs/parse-query "a")]
(is (= {:job-name '("a")} result))))

(testing "ignore breaking tokens in a query"
(let [result (jobs/parse-query "a since: until: since:xxx until:yyy")]
(is (= {:job-name '("a")} result)))))

0 comments on commit 7508cd8

Please sign in to comment.