Common utility functions useful throughout the codebase.
Common utility functions useful throughout the codebase.
(auto-retry num-retries & body)
Execute body
and return the results.
If body
fails with an exception, retry execution up to num-retries
times until it succeeds.
Execute `body` and return the results. If `body` fails with an exception, retry execution up to `num-retries` times until it succeeds.
(base64-string? s)
Is s
a Base-64 encoded string?
Is `s` a Base-64 encoded string?
(decode-base64 input)
Decodes a Base64 string to a UTF-8 string
Decodes a Base64 string to a UTF-8 string
(deref-with-timeout reff timeout-ms)
Call deref
on a something derefable (e.g. a future or promise), and throw an exception if it takes more than
timeout-ms
. If ref
is a future it will attempt to cancel it as well.
Call `deref` on a something derefable (e.g. a future or promise), and throw an exception if it takes more than `timeout-ms`. If `ref` is a future it will attempt to cancel it as well.
(do-with-auto-retries num-retries f)
Execute f
, a function that takes no arguments, and return the results.
If f
fails with an exception, retry f
up to num-retries
times until it succeeds.
Consider using the auto-retry
macro instead of calling this function directly.
Execute `f`, a function that takes no arguments, and return the results. If `f` fails with an exception, retry `f` up to `num-retries` times until it succeeds. Consider using the `auto-retry` macro instead of calling this function directly.
(do-with-us-locale f)
Implementation for with-us-locale
macro; see below.
Implementation for `with-us-locale` macro; see below.
(drop-first-arg f)
Returns a new fn that drops its first arg and applies the rest to the original.
Useful for creating extend
method maps when you don't care about the this
param. :flushed:
((drop-first-arg :value) xyz {:value 100}) -> (apply :value [{:value 100}]) -> 100
Returns a new fn that drops its first arg and applies the rest to the original. Useful for creating `extend` method maps when you don't care about the `this` param. :flushed: ((drop-first-arg :value) xyz {:value 100}) -> (apply :value [{:value 100}]) -> 100
(email? s)
Is s
a valid email address string?
Is `s` a valid email address string?
(emoji emoji-string)
Returns the emoji-string
passed in if emoji in logs are enabled, otherwise always returns an empty string.
Returns the `emoji-string` passed in if emoji in logs are enabled, otherwise always returns an empty string.
(encode-base64 input)
Encodes a string to a Base64 string
Encodes a string to a Base64 string
(filtered-stacktrace this)
Get the stack trace associated with E and return it as a vector with non-metabase frames after the last Metabase frame filtered out.
Get the stack trace associated with E and return it as a vector with non-metabase frames after the last Metabase frame filtered out.
(format-bytes num-bytes)
Nicely format num-bytes
as kilobytes/megabytes/etc.
(format-bytes 1024) ; -> 2.0 KB
Nicely format `num-bytes` as kilobytes/megabytes/etc. (format-bytes 1024) ; -> 2.0 KB
(format-color color x)
(format-color color format-string & args)
Like format
, but colorizes the output. color
should be a symbol or keyword like green
, red
, yellow
, blue
,
cyan
, magenta
, etc. See the entire list of avaliable
colors here.
(format-color :red "Fatal error: %s" error-message)
Like `format`, but colorizes the output. `color` should be a symbol or keyword like `green`, `red`, `yellow`, `blue`, `cyan`, `magenta`, etc. See the entire list of avaliable colors [here](https://github.com/ibdknox/colorize/blob/master/src/colorize/core.clj). (format-color :red "Fatal error: %s" error-message)
(get-id object-or-id)
If passed an integer ID, returns it. If passed a map containing an :id
key, returns the value if it is an integer.
Otherwise, throws an Exception.
Provided as a convenience to allow model-layer functions to easily accept either an object or raw ID, and to assert that you have a valid ID.
If passed an integer ID, returns it. If passed a map containing an `:id` key, returns the value if it is an integer. Otherwise, throws an Exception. Provided as a convenience to allow model-layer functions to easily accept either an object or raw ID, and to assert that you have a valid ID.
(hexadecimal-string? new-value)
Returns truthy if new-value
is a hexadecimal-string
Returns truthy if `new-value` is a hexadecimal-string
(host-port-up? hostname port)
Returns true if the port is active on a given host, false otherwise
Returns true if the port is active on a given host, false otherwise
(host-up? hostname)
Returns true if the host given by hostname is reachable, false otherwise
Returns true if the host given by hostname is reachable, false otherwise
(id object-or-id)
If passed an integer ID, returns it. If passed a map containing an :id
key, returns the value if it is an integer.
Otherwise returns nil
.
Provided as a convenience to allow model-layer functions to easily accept either an object or raw ID. Use this in
cases where the ID/object is allowed to be nil
. Use get-id
below in cases where you would also like to guarantee
it is non-nil
.
If passed an integer ID, returns it. If passed a map containing an `:id` key, returns the value if it is an integer. Otherwise returns `nil`. Provided as a convenience to allow model-layer functions to easily accept either an object or raw ID. Use this in cases where the ID/object is allowed to be `nil`. Use `get-id` below in cases where you would also like to guarantee it is non-`nil`.
(ignore-exceptions & body)
Simple macro which wraps the given expression in a try/catch block and ignores the exception if caught.
Simple macro which wraps the given expression in a try/catch block and ignores the exception if caught.
(index-of pred coll)
Return index of the first element in coll
for which pred
reutrns true.
Return index of the first element in `coll` for which `pred` reutrns true.
(is-java-9-or-higher?)
(is-java-9-or-higher? java-version-str)
Are we running on Java 9 or above?
Are we running on Java 9 or above?
(jdbc-clob->str this)
Convert a Postgres/H2/SQLServer JDBC Clob to a string. (If object isn't a Clob, this function returns it as-is.)
Convert a Postgres/H2/SQLServer JDBC Clob to a string. (If object isn't a Clob, this function returns it as-is.)
(key-by f coll)
Convert a sequential coll
to a map of (f item)
-> item
.
This is similar to group-by
, but the resultant map's values are single items from coll
rather than sequences of
items. (Because only a single item is kept for each value of f
, items producing duplicate values will be
discarded).
(key-by :id [{:id 1, :name :a} {:id 2, :name :b}]) -> {1 {:id 1, :name :a}, 2 {:id 2, :name :b}}
Convert a sequential `coll` to a map of `(f item)` -> `item`. This is similar to `group-by`, but the resultant map's values are single items from `coll` rather than sequences of items. (Because only a single item is kept for each value of `f`, items producing duplicate values will be discarded). (key-by :id [{:id 1, :name :a} {:id 2, :name :b}]) -> {1 {:id 1, :name :a}, 2 {:id 2, :name :b}}
(keyword->qualified-name k)
Return keyword K as a string, including its namespace, if any (unlike name
).
(keyword->qualified-name :type/FK) -> "type/FK"
Return keyword K as a string, including its namespace, if any (unlike `name`). (keyword->qualified-name :type/FK) -> "type/FK"
(maybe? f x)
Returns true
if X is nil
, otherwise calls (F X).
This can be used to see something is either nil
or statisfies a predicate function:
(string? nil) -> false (string? "A") -> true (maybe? string? nil) -> true (maybe? string? "A") -> true
It can also be used to make sure a given function won't throw a NullPointerException
:
(str/lower-case nil) -> NullPointerException (str/lower-case "ABC") -> "abc" (maybe? str/lower-case nil) -> true (maybe? str/lower-case "ABC") -> "abc"
The latter use-case can be useful for things like sorting where some values in a collection
might be nil
:
(sort-by (partial maybe? s/lower-case) some-collection)
Returns `true` if X is `nil`, otherwise calls (F X). This can be used to see something is either `nil` or statisfies a predicate function: (string? nil) -> false (string? "A") -> true (maybe? string? nil) -> true (maybe? string? "A") -> true It can also be used to make sure a given function won't throw a `NullPointerException`: (str/lower-case nil) -> NullPointerException (str/lower-case "ABC") -> "abc" (maybe? str/lower-case nil) -> true (maybe? str/lower-case "ABC") -> "abc" The latter use-case can be useful for things like sorting where some values in a collection might be `nil`: (sort-by (partial maybe? s/lower-case) some-collection)
Delay to a vector of symbols of all Metabase namespaces, excluding test namespaces.
This is intended for use by various routines that load related namespaces, such as task and events initialization.
Using ns-find/find-namespaces
is fairly slow, and can take as much as half a second to iterate over the thousand
or so namespaces that are part of the Metabase project; use this instead for a massive performance increase.
Delay to a vector of symbols of all Metabase namespaces, excluding test namespaces. This is intended for use by various routines that load related namespaces, such as task and events initialization. Using `ns-find/find-namespaces` is fairly slow, and can take as much as half a second to iterate over the thousand or so namespaces that are part of the Metabase project; use this instead for a massive performance increase.
(occurances-of-substring s substr)
Return the number of times SUBSTR occurs in string S.
Return the number of times SUBSTR occurs in string S.
(one-or-many arg)
Wraps a single element in a sequence; returns sequences as-is. In lots of situations we'd like to accept either a single value or a collection of values as an argument to a function, and then loop over them; rather than repeat logic to check whether something is a collection and wrap if not everywhere, this utility function is provided for your convenience.
(u/one-or-many 1) ; -> [1] (u/one-or-many [1 2]) ; -> [1 2]
Wraps a single element in a sequence; returns sequences as-is. In lots of situations we'd like to accept either a single value or a collection of values as an argument to a function, and then loop over them; rather than repeat logic to check whether something is a collection and wrap if not everywhere, this utility function is provided for your convenience. (u/one-or-many 1) ; -> [1] (u/one-or-many [1 2]) ; -> [1 2]
(optional pred? args)
(optional pred? args default)
Helper function for defining functions that accept optional arguments. If pred?
is true of the first item in args
,
a pair like [first-arg other-args]
is returned; otherwise, a pair like [default other-args]
is returned.
If default
is not specified, nil
will be returned when pred?
is false.
(defn ^{:arglists ([key? numbers])} wrap-nums [& args] (let [[k nums] (optional keyword? args :nums)] {k nums})) (wrap-nums 1 2 3) -> {:nums [1 2 3]} (wrap-nums :numbers 1 2 3) -> {:numbers [1 2 3]}
Helper function for defining functions that accept optional arguments. If `pred?` is true of the first item in `args`, a pair like `[first-arg other-args]` is returned; otherwise, a pair like `[default other-args]` is returned. If `default` is not specified, `nil` will be returned when `pred?` is false. (defn ^{:arglists ([key? numbers])} wrap-nums [& args] (let [[k nums] (optional keyword? args :nums)] {k nums})) (wrap-nums 1 2 3) -> {:nums [1 2 3]} (wrap-nums :numbers 1 2 3) -> {:numbers [1 2 3]}
(order-of-magnitude x)
Return the order of magnitude as a power of 10 of a given number.
Return the order of magnitude as a power of 10 of a given number.
(pdoseq [binding collection] & body)
(Almost) just like doseq
but runs in parallel. Doesn't support advanced binding forms like :let
or :when
and
only supports a single binding </3
(Almost) just like `doseq` but runs in parallel. Doesn't support advanced binding forms like `:let` or `:when` and only supports a single binding </3
(pprint-to-str x)
(pprint-to-str color-symb x)
Returns the output of pretty-printing x
as a string.
Optionally accepts color-symb
, which colorizes the output with the corresponding
function from colorize.core
.
(pprint-to-str 'green some-obj)
Returns the output of pretty-printing `x` as a string. Optionally accepts `color-symb`, which colorizes the output with the corresponding function from `colorize.core`. (pprint-to-str 'green some-obj)
(prog1 first-form & body)
Execute first-form
, then any other expressions in body
, presumably for side-effects; return the result of
first-form
.
(def numbers (atom []))
(defn find-or-add [n] (or (first-index-satisfying (partial = n) @numbers) (prog1 (count @numbers) (swap! numbers conj n))))
(find-or-add 100) -> 0 (find-or-add 200) -> 1 (find-or-add 100) -> 0
The result of first-form
is bound to the anaphor <>
, which is convenient for logging:
(prog1 (some-expression) (println "RESULTS:" <>))
prog1
is an anaphoric version of the traditional macro of the same name in
Emacs Lisp
and Common Lisp.
Style note: Prefer doto
when appropriate, e.g. when dealing with Java objects.
Execute `first-form`, then any other expressions in `body`, presumably for side-effects; return the result of `first-form`. (def numbers (atom [])) (defn find-or-add [n] (or (first-index-satisfying (partial = n) @numbers) (prog1 (count @numbers) (swap! numbers conj n)))) (find-or-add 100) -> 0 (find-or-add 200) -> 1 (find-or-add 100) -> 0 The result of `first-form` is bound to the anaphor `<>`, which is convenient for logging: (prog1 (some-expression) (println "RESULTS:" <>)) `prog1` is an anaphoric version of the traditional macro of the same name in [Emacs Lisp](http://www.gnu.org/software/emacs/manual/html_node/elisp/Sequencing.html#index-prog1) and [Common Lisp](http://www.lispworks.com/documentation/HyperSpec/Body/m_prog1c.htm#prog1). Style note: Prefer `doto` when appropriate, e.g. when dealing with Java objects.
(recursive-map-keys f m)
Recursively replace the keys in a map with the value of (f key)
.
Recursively replace the keys in a map with the value of `(f key)`.
(remove-diacritical-marks s)
Return a version of S with diacritical marks removed.
Return a version of S with diacritical marks removed.
(round-to-decimals decimal-place number)
Round (presumabily floating-point) NUMBER to DECIMAL-PLACE. Returns a Double
.
(round-to-decimals 2 35.5058998M) -> 35.51
Round (presumabily floating-point) NUMBER to DECIMAL-PLACE. Returns a `Double`. (round-to-decimals 2 35.5058998M) -> 35.51
(rpartial f & bound-args)
Like partial
, but applies additional args before BOUND-ARGS.
Inspired by -rpartial
from dash.el
((partial - 5) 8) -> (- 5 8) -> -3 ((rpartial - 5) 8) -> (- 8 5) -> 3
DEPRECATED: just use #()
function literals instead. No need to be needlessly confusing.
Like `partial`, but applies additional args *before* BOUND-ARGS. Inspired by [`-rpartial` from dash.el](https://github.com/magnars/dash.el#-rpartial-fn-rest-args) ((partial - 5) 8) -> (- 5 8) -> -3 ((rpartial - 5) 8) -> (- 8 5) -> 3 DEPRECATED: just use `#()` function literals instead. No need to be needlessly confusing.
(safe-inc n)
Increment n
if it is non-nil
, otherwise return 1
(e.g. as if incrementing 0
).
Increment `n` if it is non-`nil`, otherwise return `1` (e.g. as if incrementing `0`).
(select-keys-when m & {:keys [present non-nil] :as options})
Returns a map that only contains keys that are either :present
or :non-nil
. Combines behavior of select-keys
and select-non-nil-keys
. This is useful for API endpoints that update a model, which often have complex rules
about what gets updated (some keys are updated if nil
, others only if non-nil).
(select-keys-when {:a 100, :b nil, :d 200, :e nil} :present #{:a :b :c} :non-nil #{:d :e :f}) ;; -> {:a 100, :b nil, :d 200}
Returns a map that only contains keys that are either `:present` or `:non-nil`. Combines behavior of `select-keys` and `select-non-nil-keys`. This is useful for API endpoints that update a model, which often have complex rules about what gets updated (some keys are updated if `nil`, others only if non-nil). (select-keys-when {:a 100, :b nil, :d 200, :e nil} :present #{:a :b :c} :non-nil #{:d :e :f}) ;; -> {:a 100, :b nil, :d 200}
(select-nested-keys m keyseq)
Like select-keys
, but can also handle nested keypaths:
(select-nested-keys {:a 100, :b {:c 200, :d 300}} [:a [:b :d] :c]) ;; -> {:a 100, :b {:d 300}}
The values of keyseq
can be either regular keys, which work the same way as select-keys
,
or vectors of the form [k & nested-keys]
, which call select-nested-keys
recursively
on the value of k
.
Like `select-keys`, but can also handle nested keypaths: (select-nested-keys {:a 100, :b {:c 200, :d 300}} [:a [:b :d] :c]) ;; -> {:a 100, :b {:d 300}} The values of `keyseq` can be either regular keys, which work the same way as `select-keys`, or vectors of the form `[k & nested-keys]`, which call `select-nested-keys` recursively on the value of `k`.
(select-non-nil-keys m ks)
Like select-keys
, but returns a map only containing keys in KS that are present and non-nil in M.
(select-non-nil-keys {:a 100, :b nil} #{:a :b :c}) ;; -> {:a 100}
Like `select-keys`, but returns a map only containing keys in KS that are present *and non-nil* in M. (select-non-nil-keys {:a 100, :b nil} #{:a :b :c}) ;; -> {:a 100}
(slugify s)
(slugify s max-length)
Return a version of String s
appropriate for use as a URL slug.
Downcase the name, remove diacritcal marks, and replace non-alphanumeric ASCII characters with underscores;
URL-encode non-ASCII characters. (Non-ASCII characters are encoded rather than replaced with underscores in order
to support languages that don't use the Latin alphabet; see issue #3818).
Optionally specify max-length
which will truncate the slug after that many characters.
Return a version of String `s` appropriate for use as a URL slug. Downcase the name, remove diacritcal marks, and replace non-alphanumeric *ASCII* characters with underscores; URL-encode non-ASCII characters. (Non-ASCII characters are encoded rather than replaced with underscores in order to support languages that don't use the Latin alphabet; see issue #3818). Optionally specify `max-length` which will truncate the slug after that many characters.
(snake-key k)
Convert a keyword or string k
from lisp-case
to snake-case
.
Convert a keyword or string `k` from `lisp-case` to `snake-case`.
(snake-keys m)
Convert the keys in a map from lisp-case
to snake-case
.
Convert the keys in a map from `lisp-case` to `snake-case`.
(strict-extend atype protocol method-map & more)
A strict version of extend
that throws an exception if any methods declared in the protocol are missing or any
methods not declared in the protocol are provided.
Since this has better compile-time error-checking, prefer strict-extend
to regular extend
in all situations, and
to extend-protocol
/ extend-type
going forward.
A strict version of `extend` that throws an exception if any methods declared in the protocol are missing or any methods not declared in the protocol are provided. Since this has better compile-time error-checking, prefer `strict-extend` to regular `extend` in all situations, and to `extend-protocol`/ `extend-type` going forward.
(update-in-when m k f & args)
Like clojure.core/update-in
but does not create new keys if they do not exist. Useful when you don't want to create
cruft.
Like `clojure.core/update-in` but does not create new keys if they do not exist. Useful when you don't want to create cruft.
(update-when m k f & args)
Like clojure.core/update
but does not create a new key if it does not exist. Useful when you don't want to create
cruft.
Like `clojure.core/update` but does not create a new key if it does not exist. Useful when you don't want to create cruft.
(url? s)
Is s
a valid HTTP/HTTPS URL string?
Is `s` a valid HTTP/HTTPS URL string?
A regular expression for matching canonical string representations of UUIDs.
A regular expression for matching canonical string representations of UUIDs.
(varargs klass & [objects])
Make a properly-tagged Java interop varargs argument. This is basically the same as into-array
but properly tags
the result.
(u/varargs String) (u/varargs String ["A" "B"])
Make a properly-tagged Java interop varargs argument. This is basically the same as `into-array` but properly tags the result. (u/varargs String) (u/varargs String ["A" "B"])
(with-timeout timeout-ms & body)
Run body
in a future
and throw an exception if it fails to complete after timeout-ms
.
Run `body` in a `future` and throw an exception if it fails to complete after `timeout-ms`.
(with-us-locale & body)
Execute body
with the default system locale temporarily set to locale
. Why would you want to do this? Tons of
code relies on String/toUpperCase
which converts a string to uppercase based on the default locale. Normally, this
does what you'd expect, but when the default locale is Turkish, all hell breaks loose:
;; Locale is Turkish / -Duser.language=tr (.toUpperCase "filename") ;; -> "FİLENAME"
Rather than submit PRs to every library in the world to use (.toUpperCase <str> Locale/US)
, it's simpler just to
temporarily bind the default Locale to something predicatable (i.e. US English) when doing something important that
tends to break like running Liquibase migrations.)
Note that because Locale/setDefault
and Locale/getDefault
aren't thread-local (as far as I know) I've had to put
a lock in place to prevent race conditions where threads simulataneously attempt to fetch and change the default
Locale. Thus this macro should be used sparingly, and only in places that are already single-threaded (such as the
launch code that runs Liquibase).
DO NOT use this macro in API endpoints or other places that are multithreaded or performance will be negatively
impacted. (You shouldn't have a good reason for using this there anyway. Rewrite your code to pass Locale/US
when
you call .toUpperCase
or str/upper-case
. Only use this macro if the calls in question are part of a 3rd-party
library.)
Execute `body` with the default system locale temporarily set to `locale`. Why would you want to do this? Tons of code relies on `String/toUpperCase` which converts a string to uppercase based on the default locale. Normally, this does what you'd expect, but when the default locale is Turkish, all hell breaks loose: ;; Locale is Turkish / -Duser.language=tr (.toUpperCase "filename") ;; -> "FİLENAME" Rather than submit PRs to every library in the world to use `(.toUpperCase <str> Locale/US)`, it's simpler just to temporarily bind the default Locale to something predicatable (i.e. US English) when doing something important that tends to break like running Liquibase migrations.) Note that because `Locale/setDefault` and `Locale/getDefault` aren't thread-local (as far as I know) I've had to put a lock in place to prevent race conditions where threads simulataneously attempt to fetch and change the default Locale. Thus this macro should be used sparingly, and only in places that are already single-threaded (such as the launch code that runs Liquibase). DO NOT use this macro in API endpoints or other places that are multithreaded or performance will be negatively impacted. (You shouldn't have a good reason for using this there anyway. Rewrite your code to pass `Locale/US` when you call `.toUpperCase` or `str/upper-case`. Only use this macro if the calls in question are part of a 3rd-party library.)
(xor x y & more)
Exclusive or. (Because this is implemented as a function, rather than a macro, it is not short-circuting the way or
is.)
Exclusive or. (Because this is implemented as a function, rather than a macro, it is not short-circuting the way `or` is.)
(xor-pred & preds)
Takes a set of predicates and returns a function that is true if exactly one of its composing predicates returns a
logically true value. Compare to every-pred
.
Takes a set of predicates and returns a function that is true if *exactly one* of its composing predicates returns a logically true value. Compare to `every-pred`.
cljdoc is a website building & hosting documentation for Clojure/Script libraries
× close