If you want to support additional types in paths you can use the defpathtype
macro.
It takes the following parameters:
hex-code
- a number used for type identification in the database0x0
is used internally and off limits- built-in codes which should not be overwritten are:
0x10
,0x20
,0x21
,0x24
,0x25
,0x30
,0x31
,0x32
,0x68
,0x69
,0x70
,0xa0
. Attempts to overwrite them (or generally change encodings) should print a warning.
types
- the types to be encoded (generally there should only be one)encoder
- a function which takes elements of the types specified intypes
and returns a string representationdecoder
- a function which takes the string reprensentations generated by the encoder and reconstructs a value of the appropriate type
You can see which types and hex-codes are already assigned by calling the path-encoding-assignments
function
Additionally, you should use the check-encoding
function to test that your encoding and decodings match.
It returns a map with four keys:
:equal
- indicates if the decoded value is equal to the initial value:initial
- the supplied value before encoding:decoded
- the value after it has been decoded:encoded
- the encoded (string) representation of the value
;; setup namespace
(require '(clojure [string :as str]))
(use 'codax.core)
;; create a record type
(defrecord Point [x y])
;; find an unused hex-code
(path-encoding-assignments) ;{:hex-codes ("0x20" "0xa0" "0x21" "0x24" "0x25" "0x68" "0x69" "0x10" "0x30" "0x70" "0x31" "0x32"),
; :types (nil java.time.Instant java.lang.Double clojure.lang.Symbol java.lang.String ...}
;; define a path type using 0x50 as the identifier code.
;; 0x50 is chosen arbitrarily, because it is unassigned.
(defpathtype [0x50 Point]
(fn point-encoder [pt]
(str (:x pt) "x" (:y pt))) ;; e.g. path-type-demo.Point{:x 10 :y 20} becomes "10x20"
(fn point-decoder [encoded-pt]
(let [[x y] (str/split encoded-pt #"x")] ;; split the str representation on "x"
(Point. (read-string x) (read-string y))))) ;; read the x and y values and use them to reconstruct the point
;; test the encoder/decoder pair
(check-path-encoding (Point. 10 20)) ;{:equal true,
; :initial #path_type_demo.Point{:x 10, :y 20},
; :decoded #path_type_demo.Point{:x 10, :y 20},
; :encoded "10x20"}
;; now the type can be used in any path
;; e.g. (assoc-at! some-database [:points (Point. 10 20)] true)
- Creating custom path types is advanced functionality which is not required for the vast majority of applications.
- A database using custom pathtypes will (probably) be unreadable in any program which does not define the exact same pathtype
- If you believe that a custom pathtype you have defined has generally applicable utility, please submit a PR or open an issue!