datomic

Ask questions on the official Q&A site at https://ask.datomic.com!
vncz 2020-10-02T00:32:49.175100Z

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?

marshall 2020-10-02T00:33:50.175300Z

Yes it will retry. It may eventually time out and/or throw

vncz 2020-10-02T01:20:18.175500Z

Ok understood. So although the db value is immutable, it might fail to deliver the data in edge cases. That clarifies, thanks a lot!

zane 2020-10-02T17:39:58.180Z

Is it possible to pull all attributes, but with a default? I’m imagining something like:

(pull [(* :default :no-value)]  …

kenny 2020-10-02T17:43:30.180200Z

I don't see how that could be possible. "*" means all attributes that an entity has so there can't be a default.

kenny 2020-10-02T17:44:16.180400Z

i.e., there is no info on what an entity does not have.

donyorm 2020-10-02T17:45:21.180800Z

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"]}

donyorm 2020-10-02T17:45:49.181300Z

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

zane 2020-10-02T17:45:49.181400Z

Let me try to explain how I would do it in two queries.

donyorm 2020-10-02T17:46:36.182200Z

Is it not enought to have ?string-val-0 defined in the in list?

zane 2020-10-02T17:48:18.182300Z

(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))

zane 2020-10-02T17:48:23.182500Z

Something along those lines.

zane 2020-10-02T17:59:34.183500Z

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] …)

zane 2020-10-02T17:59:39.183700Z

At least I suspect that’s what’s wrong.

kenny 2020-10-02T21:53:35.183900Z

Definitely not something built in. I'd advise against that. What is your use case?

nando 2020-10-02T22:30:27.186600Z

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

nando 2020-10-02T22:36:24.187900Z

Any suggestions for formatting db.type/instant values ?

favila 2020-10-02T23:31:03.188700Z

You need to coerce the Java.util.date to an instant

nando 2020-10-03T10:51:36.191400Z

@seancorfield Thanks very much! I've confirmed that both approaches work as expected with an #inst returned from datomic.

nando 2020-10-03T11:37:18.191600Z

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.

favila 2020-10-03T12:33:27.192100Z

@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)))

favila 2020-10-03T12:33:50.192300Z

I avoid java.text.SimpleDateFormat because it’s the “old” way and it’s not thread-safe

favila 2020-10-03T12:35:28.192500Z

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

favila 2020-10-03T12:35:46.192700Z

but I’m not familiar with clojure.java-time, I just use java.time directly

nando 2020-10-03T13:30:48.192900Z

@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))

nando 2020-10-03T13:32:13.193100Z

The same error is produced without the date being wrapped in a .toInstant call.

nando 2020-10-03T13:40:30.193300Z

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?

favila 2020-10-03T14:19:52.194500Z

Def the format object and then use it in functions running in my tools threads

favila 2020-10-03T14:20:12.195Z

*multiple

favila 2020-10-03T14:24:04.197700Z

There are a few strata of Java date systems

favila 2020-10-03T14:25:50.200100Z

The oldest is Java.util.date objects. The newest is Java.time.*, which represents instants as Java.time.Instant objects instead.

favila 2020-10-03T14:26:16.200800Z

There are some in between that aren’t worth learning anymore

seancorfield 2020-10-03T17:55:04.201Z

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.

favila 2020-10-02T23:31:38.189100Z

toInstant method

nando 2020-10-02T23:44:11.189300Z

(t/instant #inst "2020-09-26T23:08:27.619-00:00") => #time/instant "2020-09-26T23:08:27.619Z"

nando 2020-10-02T23:45:32.189500Z

(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

nando 2020-10-02T23:47:51.189700Z

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