Well ok, so my point still stands @marshall • What happens if there's a network failure while fetching the data from the storage? Is the peer library going to retry that automatically? What if it fails continuously? Will I ultimately see a thrown exception out of nowhere?
Yes it will retry. It may eventually time out and/or throw
Ok understood. So although the db value is immutable, it might fail to deliver the data in edge cases. That clarifies, thanks a lot!
Is it possible to pull all attributes, but with a default? I’m imagining something like:
(pull [(* :default :no-value)] …
I don't see how that could be possible. "*" means all attributes that an entity has so there can't be a default.
i.e., there is no info on what an entity does not have.
So I have the following query:
{:query
{:find [?e],
:in [$ ?string-val-0],
:where
[(or-join
[?e]
(and
[?e :exception/message ?message-0]
[(.contains ?message-0 ?string-val-0)])
(and
[?e :exception/message ?explanation-0]
[?explanation-0 :message/explanation ?explanation-val-0]
[(.contains ?message-0 ?string-val-0)]))]},
:args
[#object[compute.datomic_client_memdb.core.LocalDb 0x2a589f86 "compute.datomic_client_memdb.core.LocalDb@2a589f86"]
"abc"]}
But I'm getting Execution error (Exceptions$IllegalArgumentExceptionInfo) at datomic.error/arg (error.clj:57).
:db.error/insufficient-binding [?string-val-0] not bound in expression clause: [(.contains ?message-0 ?string-val-0)]
, and I'm not sure why
Let me try to explain how I would do it in two queries.
Is it not enought to have ?string-val-0
defined in the in
list?
(let [attributes (d/q '[:find [?a ...]
:where
[?e ?a _]]
db)
pattern (mapv (fn [attribute]
`(~attribute :default :no-value))
attributes)]
(d/q `[:find (pull $ ~pattern ?e)
:in $
:where
[?e _ _]]
db))
Something along those lines.
If you want ?string-val-0
to unify the outer clause you’ll need to include it in the rules-vars
vector: (or-join [?e ?string-val-0] …)
At least I suspect that’s what’s wrong.
Definitely not something built in. I'd advise against that. What is your use case?
I'm trying to figure out how to format db.type/instant values, for display in a UI. Using clojure.java-time as follows:
(:require [java-time :as t])
evaluating
(t/format #inst "2020-09-26T23:08:27.619-00:00")
returns "Sun Sep 27 01:08:27 CEST 2020"
but if I add a custom format
(t/format "dd/MM/yyyy" #inst "2020-09-26T23:08:27.619-00:00")
I get the error
Execution error (ClassCastException) at java-time.format/format (format.clj:50).
java.util.Date cannot be cast to java.time.temporal.TemporalAccessor
Any suggestions for formatting db.type/instant values ?
You need to coerce the Java.util.date to an instant
@seancorfield Thanks very much! I've confirmed that both approaches work as expected with an #inst returned from datomic.
I've learned a lot here, both by dipping my toes into the clojure.java-time
and tick
libraries, and getting a more practical sense of how java interop works through your example.
@nando I meant something like this (sorry, was on a phone earlier):
(let [d #inst"2020-10-03T12:18:02.445-00:00"
f (-> (java.time.format.DateTimeFormatter/ofPattern "dd/MM/yyyy")
(.withZone (java.time.ZoneId/systemDefault)))]
(.format f (.toInstant d)))
I avoid java.text.SimpleDateFormat because it’s the “old” way and it’s not thread-safe
I think what sean posted is nearly the equivalent, except he coerces to a zoned date time instead of specifying the zone in the formatter
but I’m not familiar with clojure.java-time, I just use java.time directly
@favila I see what you originally meant evaluating
(let [d #inst"2020-10-03T12:18:02.445-00:00"
f (-> (java.time.format.DateTimeFormatter/ofPattern "dd/MM/yyyy")
(.withZone (java.time.ZoneId/systemDefault)))]
(.format f d))
The same error is produced without the date being wrapped in a .toInstant call.
In what type of use case would the fact that SimpleDateFormat is not thread safe produce an unexpected result, particularly in the context of a web application?
Def the format object and then use it in functions running in my tools threads
*multiple
There are a few strata of Java date systems
The oldest is Java.util.date objects. The newest is Java.time.*, which represents instants as Java.time.Instant objects instead.
There are some in between that aren’t worth learning anymore
Yup, going via Java Time is definitely the safest route and the best set of APIs to learn. At work, over the past decade we've gone from java.util.Date
to date-clj
(date arithmetic for that old Date
type), to clj-time
(wrapping Joda Time), to Java Time (with clojure.java-time
in some parts of the code and plain interop in a lot of places). Converting java.util.Date
to java.time.Instant
and doing everything in Java Time is a bit painful/verbose, but you can write utility functions for stuff you need frequently to hide that interop/verbosity.
toInstant method
(t/instant #inst "2020-09-26T23:08:27.619-00:00")
=> #time/instant "2020-09-26T23:08:27.619Z"
(t/format "yyyy/MM/dd" (t/instant #inst "2020-09-26T23:08:27.619-00:00"))
=> Execution error (UnsupportedTemporalTypeException) at java.time.Instant/getLong (Instant.java:603).
Unsupported field: YearOfEra
the clojure.java-time docs for t/instant say this function "Creates an Instant" https://cljdoc.org/d/clojure.java-time/clojure.java-time/0.3.2/api/java-time.temporal#instant