Skip to content

Commit

Permalink
Fix Date Search
Browse files Browse the repository at this point in the history
Closes: #412
  • Loading branch information
alexanderkiel committed Dec 16, 2022
1 parent 7282dd5 commit 004c124
Show file tree
Hide file tree
Showing 14 changed files with 815 additions and 509 deletions.
3 changes: 1 addition & 2 deletions dev/blaze/dev/decompiler.clj
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
(ns blaze.dev.decompiler
(:require [clojure.test :refer :all]))
(ns blaze.dev.decompiler)


(comment
Expand Down
3 changes: 3 additions & 0 deletions modules/byte-buffer/src/blaze/byte_buffer.clj
Original file line number Diff line number Diff line change
Expand Up @@ -200,6 +200,9 @@


(defn get-byte!
"The 1-arity variant reads the byte at the current position of `byte-buffer`
and increments the position afterwards. The 2-arity variant uses absolute
`index` access."
{:inline
(fn
([byte-buffer]
Expand Down
123 changes: 14 additions & 109 deletions modules/db/src/blaze/db/impl/codec.clj
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@
[blaze.byte-string :as bs]
[blaze.fhir.spec.type.system])
(:import
[blaze.fhir.spec.type.system DateTimeYear DateTimeYearMonth
DateTimeYearMonthDay]
[com.github.benmanes.caffeine.cache CacheLoader Caffeine]
[com.google.common.hash Hashing]
[java.nio.charset StandardCharsets]
[java.time LocalDate LocalDateTime OffsetDateTime Year YearMonth
ZoneId ZoneOffset]
[java.util Arrays]))


Expand All @@ -26,7 +22,6 @@
(def ^:const ^long tid-size Integer/BYTES)
(def ^:const ^long t-size Long/BYTES)
(def ^:const ^long state-size Long/BYTES)
(def ^:const ^long tx-time-size Long/BYTES)
(def ^:const ^long max-id-size 64)


Expand Down Expand Up @@ -431,110 +426,20 @@
bs/from-byte-buffer!)))))


(defn- epoch-seconds ^long [^LocalDateTime date-time ^ZoneId zone-id]
(.toEpochSecond (.atZone date-time zone-id)))


(defprotocol DateLowerBound
(-date-lb [date-time zone-id]))


(extend-protocol DateLowerBound
Year
(-date-lb [year zone-id]
(number (epoch-seconds (.atStartOfDay (.atDay year 1)) zone-id)))
DateTimeYear
(-date-lb [year zone-id]
(number (epoch-seconds (.atStartOfDay (.atDay ^Year (.-year year) 1)) zone-id)))
YearMonth
(-date-lb [year-month zone-id]
(number (epoch-seconds (.atStartOfDay (.atDay year-month 1)) zone-id)))
DateTimeYearMonth
(-date-lb [year-month zone-id]
(number (epoch-seconds (.atStartOfDay (.atDay ^YearMonth (.-year_month year-month) 1)) zone-id)))
LocalDate
(-date-lb [date zone-id]
(number (epoch-seconds (.atStartOfDay date) zone-id)))
DateTimeYearMonthDay
(-date-lb [date zone-id]
(number (epoch-seconds (.atStartOfDay ^LocalDate (.date date)) zone-id)))
LocalDateTime
(-date-lb [date-time zone-id]
(number (epoch-seconds date-time zone-id)))
OffsetDateTime
(-date-lb [date-time _]
(number (.toEpochSecond date-time))))


(defn date-lb
"Returns the lower bound of the implicit range the `date-time` value spans."
[zone-id date-time]
(-date-lb date-time zone-id))


(defprotocol DateUpperBound
(-date-ub [date-time zone-id]))


(extend-protocol DateUpperBound
Year
(-date-ub [year zone-id]
(number (dec (epoch-seconds (.atStartOfDay (.atDay (.plusYears year 1) 1)) zone-id))))
DateTimeYear
(-date-ub [year zone-id]
(number (dec (epoch-seconds (.atStartOfDay (.atDay (.plusYears ^Year (.year year) 1) 1)) zone-id))))
YearMonth
(-date-ub [year-month zone-id]
(number (dec (epoch-seconds (.atStartOfDay (.atDay (.plusMonths year-month 1) 1)) zone-id))))
DateTimeYearMonth
(-date-ub [year-month zone-id]
(number (dec (epoch-seconds (.atStartOfDay (.atDay (.plusMonths ^YearMonth (.-year_month year-month) 1) 1)) zone-id))))
LocalDate
(-date-ub [date zone-id]
(number (dec (epoch-seconds (.atStartOfDay (.plusDays date 1)) zone-id))))
DateTimeYearMonthDay
(-date-ub [date zone-id]
(number (dec (epoch-seconds (.atStartOfDay (.plusDays ^LocalDate (.date date) 1)) zone-id))))
LocalDateTime
(-date-ub [date-time zone-id]
(number (epoch-seconds date-time zone-id)))
OffsetDateTime
(-date-ub [date-time _]
(number (.toEpochSecond date-time))))


(defn date-ub
"Returns the upper bound of the implicit range the `date-time` value spans."
[zone-id date-time]
(-date-ub date-time zone-id))


(def date-min-bound
(date-lb (ZoneOffset/ofHours 0) (Year/of 1)))


(def date-max-bound
(date-ub (ZoneOffset/ofHours 0) (Year/of 9999)))


(defn date-lb-ub [lb ub]
(-> (bb/allocate (+ 2 (bs/size lb) (bs/size ub)))
(bb/put-byte-string! lb)
(bb/put-byte! 0)
(bb/put-byte-string! ub)
(bb/put-byte! (bs/size lb))
bb/flip!
bs/from-byte-buffer!))


(defn date-lb-ub->lb [lb-ub]
(bs/subs lb-ub 0 (bs/nth lb-ub (unchecked-dec-int (bs/size lb-ub)))))


(defn date-lb-ub->ub [lb-ub]
(let [lb-size-idx (unchecked-dec-int (bs/size lb-ub))
start (unchecked-inc-int (int (bs/nth lb-ub lb-size-idx)))]
(bs/subs lb-ub start lb-size-idx)))
(defn decode-number [byte-string]
(let [bb (bs/as-read-only-byte-buffer byte-string)
header (bit-and (long (bb/get-byte! bb)) 0xFF)
mask (bit-and (bit-shift-right (unchecked-byte (bit-xor header 0x80)) 7) 0xFF)
n (bit-and (bit-xor (bit-shift-right header 3) mask) 0x0F)]
(loop [val (bit-shift-left (bit-and (bit-xor header mask) 0x07) (* 8 n))
i 1]
(if (<= i n)
(let [byte (bit-and (long (bb/get-byte! bb)) 0xFF)]
(recur
(+ val (bit-shift-left (bit-xor byte mask) (* 8 (- n i))))
(inc i)))
(let [final-mask (bit-shift-right (bit-shift-left mask 63) 63)]
(bit-xor val final-mask))))))


(defn quantity [unit value]
Expand Down
127 changes: 127 additions & 0 deletions modules/db/src/blaze/db/impl/codec/date.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
(ns blaze.db.impl.codec.date
(:require
[blaze.byte-buffer :as bb]
[blaze.byte-string :as bs]
[blaze.db.impl.codec :refer [number]]
[blaze.fhir.spec.type.system])
(:import
[blaze.fhir.spec.type.system DateTimeYear DateTimeYearMonth
DateTimeYearMonthDay]
[java.time LocalDate LocalDateTime OffsetDateTime Year YearMonth
ZoneOffset]))


(set! *warn-on-reflection* true)


(defn- epoch-seconds ^long [^LocalDateTime date-time]
(.toEpochSecond (.atOffset date-time (ZoneOffset/UTC))))


(defprotocol LowerBound
(-encode-lower-bound [date-time]))


(extend-protocol LowerBound
Year
(-encode-lower-bound [year]
(number (epoch-seconds (.atStartOfDay (.atDay year 1)))))
DateTimeYear
(-encode-lower-bound [year]
(number (epoch-seconds (.atStartOfDay (.atDay ^Year (.-year year) 1)))))
YearMonth
(-encode-lower-bound [year-month]
(number (epoch-seconds (.atStartOfDay (.atDay year-month 1)))))
DateTimeYearMonth
(-encode-lower-bound [year-month]
(number (epoch-seconds (.atStartOfDay (.atDay ^YearMonth (.-year_month year-month) 1)))))
LocalDate
(-encode-lower-bound [date]
(number (epoch-seconds (.atStartOfDay date))))
DateTimeYearMonthDay
(-encode-lower-bound [date]
(number (epoch-seconds (.atStartOfDay ^LocalDate (.date date)))))
LocalDateTime
(-encode-lower-bound [date-time]
(number (epoch-seconds date-time)))
OffsetDateTime
(-encode-lower-bound [date-time]
(number (.toEpochSecond date-time))))


(defn encode-lower-bound
"Encodes the lower bound of the implicit range of `date-time`."
[date-time]
(-encode-lower-bound date-time))


(defprotocol UpperBound
(-encode-upper-bound [date-time]))


(extend-protocol UpperBound
Year
(-encode-upper-bound [year]
(number (dec (epoch-seconds (.atStartOfDay (.atDay (.plusYears year 1) 1))))))
DateTimeYear
(-encode-upper-bound [year]
(number (dec (epoch-seconds (.atStartOfDay (.atDay (.plusYears ^Year (.year year) 1) 1))))))
YearMonth
(-encode-upper-bound [year-month]
(number (dec (epoch-seconds (.atStartOfDay (.atDay (.plusMonths year-month 1) 1))))))
DateTimeYearMonth
(-encode-upper-bound [year-month]
(number (dec (epoch-seconds (.atStartOfDay (.atDay (.plusMonths ^YearMonth (.-year_month year-month) 1) 1))))))
LocalDate
(-encode-upper-bound [date]
(number (dec (epoch-seconds (.atStartOfDay (.plusDays date 1))))))
DateTimeYearMonthDay
(-encode-upper-bound [date]
(number (dec (epoch-seconds (.atStartOfDay (.plusDays ^LocalDate (.date date) 1))))))
LocalDateTime
(-encode-upper-bound [date-time]
(number (epoch-seconds date-time)))
OffsetDateTime
(-encode-upper-bound [date-time]
(number (.toEpochSecond date-time))))


(defn encode-upper-bound
"Encodes the upper bound of the implicit range of `date-time`."
[date-time]
(-encode-upper-bound date-time))


(defn- encode-range* [lower-bound upper-bound]
(-> (bb/allocate (+ 2 (bs/size lower-bound) (bs/size upper-bound)))
(bb/put-byte-string! lower-bound)
(bb/put-byte! 0)
(bb/put-byte-string! upper-bound)
(bb/put-byte! (bs/size lower-bound))
bb/flip!
bs/from-byte-buffer!))


(defn encode-range
"Encodes the implicit range of `date-time` or the explicit range from `start`
to `end`."
([date-time]
(encode-range date-time date-time))
([start end]
(encode-range* (encode-lower-bound (or start (Year/of 1)))
(encode-upper-bound (or end (Year/of 9999))))))


(defn lower-bound-bytes
"Returns the bytes of the lower bound from the encoded `date-range-bytes`."
[date-range-bytes]
(let [lower-bound-size-idx (unchecked-dec-int (bs/size date-range-bytes))]
(bs/subs date-range-bytes 0 (bs/nth date-range-bytes lower-bound-size-idx))))


(defn upper-bound-bytes
"Returns the bytes of the upper bound from the encoded `date-range-bytes`."
[date-range-bytes]
(let [lower-bound-size-idx (unchecked-dec-int (bs/size date-range-bytes))
start (unchecked-inc-int (int (bs/nth date-range-bytes lower-bound-size-idx)))]
(bs/subs date-range-bytes start lower-bound-size-idx)))
Loading

0 comments on commit 004c124

Please sign in to comment.