Skip to content

Instantly share code, notes, and snippets.

@bernik
Created September 9, 2018 11:41
Show Gist options
  • Save bernik/11ad910b63e2be026b3b89d910e788bf to your computer and use it in GitHub Desktop.
Save bernik/11ad910b63e2be026b3b89d910e788bf to your computer and use it in GitHub Desktop.
evotest
{:deps {datascript {:mvn/version "0.16.6"}
clj-time {:mvn/version "0.14.4"}
org.clojure/test.check {:mvn/version "0.9.0"}}}
(ns hello
(:require
[clj-time.core :as t]
[clj-time.format :as tf]
[datascript.core :as d]
[clojure.spec.alpha :as spec]
[clojure.spec.gen.alpha :as gen]))
;; utils
(defn spy [v] (println v) v)
;; generate sequence of dates from Jan 1 2018
(def dates (iterate #(t/plus % (t/days 1)) (t/date-time 2018 01 01)))
;; specs
(spec/def ::sum (into #{} (range 5 100 2)))
(spec/def ::user (into #{} (range 1 2000)))
(spec/def ::date (into #{} (take 100 dates)))
(spec/def ::entity (spec/keys :req-un [::user ::date ::sum]))
;; db generation
(def conn
(-> (d/empty-db)
(d/db-with (gen/sample (spec/gen ::entity) 10000))
d/conn-from-db))
;; find first row when user reached limit for sum
(defn reach-limit [coll limit]
(loop [total-sum 0
rows (sort-by second coll)]
(let [[user date sum] (first rows)
sum' (+ total-sum sum)]
(if (>= sum' limit)
[user (tf/unparse (tf/formatter :date) date) sum']
(recur sum' (rest rows))))))
;; find all users who reached the limit and return dates and sums
(defn find-by-limit [db limit]
(->> db
(d/q '[:find ?u (sum ?s)
:with ?e
:where [?e :sum ?s]
[?e :user ?u]])
(d/q '[:find ?u ?d (sum ?s)
:with ?e
:in $ limit [[?u ?total-sum]]
:where [?e :user ?u]
[?e :date ?d]
[?e :sum ?s]
[(>= ?total-sum limit)]]
db
limit)
(group-by first)
vals
(map #(reach-limit % limit))))
(println (find-by-limit @conn 500))
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment