Fork me on GitHub
#datomic
<
2024-02-05
>
az00:02:58

Hi everyone 👋, I need to deal with date calculations, and I'm running into some issues. I hope someone here can offer some insights or guidance. Here's the code snippet of my query:

(let [query '[:find (pull ?e [:*])
              :in $ ?now
              :where
              [?e :data-source/uri]
              [?e :schedule/interval-millis ?freq]
              [?e :data-source/history ?h]
              [?h :event/instant ?i]
              [(>
                (.minus ?now (java.time.Duration/ofMillis ?freq))
                ?i)]]
      db (d/db (resolver/get-db-connection))]
  (d/q query db (time-utils/now)))
The objective of this query is to find data sources that need to be updated based on their schedule. Essentially, I want to compare the current time (`?now`) with the :event/instant (`?i`) of each data source's history, considering the :schedule/interval-millis (`?freq`). However, when I try to run this query, I encounter the following issues: • Unable to resolve symbol: ?now in this contextUnable to resolve symbol: ?freq or ?i in this context I believe the issue lies in how I'm trying to use the ?now, ?freq, and ?i symbols within the (.minus ?now (java.time.Duration/ofMillis ?freq)) function call. Could anyone provide insights on the correct way to handle date calculations within a Datomic query? Is there a better approach to comparing dates in this context? Any help or pointers would be greatly appreciated! Thank you in advance! 🙏

favila01:02:31

Datalog variables are only found and understood in the first level of the expression. Your form has it nested

az01:02:59

Hi @U09R86PA4, thank you. Do you have any ideas how I might be able to get the result I'm after? I'm not stuck with this approach, but I need a way to filter on dates at query time. In this example each data-source will have a different frequency and that would cause things to go stale at different times, so I can't hardcode the date to check against

favila01:02:32

Keeping the same approach you can split the expressions up

az01:02:09

I'm sorry, I'm not sure how I would do that. Could you show me a short example? Do bind each part like (.minus ?now (java.time.Duration/ofMillis ?freq)) somehow? I tried this is this what you mean?

(let [query '[:find (pull ?e [:*])
                :in $ ?now
                :where
                [?e :data-source/uri]
                [?e :schedule/interval-millis ?freq]
                [?e :data-source/history ?h]
                [?h :event/instant ?i]
                [?my-freq _ (java.time.Duration/ofMillis ?freq)]
                [?my-something _ (.minus ?now ?freq)]
                [(> ?i ?my-something)]]
        db (d/db (resolver/get-db-connection))]
    (d/q query db (time-utils/now)))
This at least runs, but I need to fix the logic

az02:02:04

Yeah not sure if that does anything @U09R86PA4, I think you must mean something else

az02:02:30

Ah I think I got it:

(let [query '[:find ?elapsed
                :in $ ?now
                :where
                [?e :data-source/uri]
                [?e :schedule/interval-millis ?freq]
                [?e :data-source/history ?h]
                [?h :event/instant ?i]
                [(com.sajb.time-utils.interface/duration-between ?i ?now) ?elapsed] 
                [(> ?elapsed ?freq)]]
        db (d/db (resolver/get-db-connection))]
    (d/q query db (time-utils/now)))

az02:02:31

Works! Thank you @U09R86PA4

favila02:02:18

Yeah you got it. I just meant something like this (I assume ?now is java.time.Instant and :event/instant is :db.type/instant/`java.util.Date` from your code):

[?e :schedule/interval-millis ?freq]
[(.minusMillis ^java.time.Instant ?now ?freq) ?threshold-inst]
[(java.util.Date/from ?threshold-inst) ?threshold]
[?e :data-source/history ?h]
[?h :event/instant ?i]
[(< ?i ?threshold)]

❤️ 1
favila02:02:47

Notice all the function expressions have datalog variables on the outer list only

favila02:02:20

You have to bind all the intermediate values, or do the work in a function

az02:02:23

Got it. Do you think it's better to use built in java methods over custom clojure functions?

az02:02:12

is there a difference when it comes time to deploy?

favila02:02:45

are you using on-prem or cloud?

az02:02:53

going to use cloud

favila03:02:17

yes, you need to include them in the ion and allow-list them: https://docs.datomic.com/cloud/query/query-data-reference.html#deploying

favila03:02:38

for on-prem you don’t need to do anything--the query executes in the same process as the querying code, so the function is already available.

az03:02:05

Got it, thanks so much for all the help

Aviv10:02:16

Hey everyone, I’m using Datomic-ions, I created lambda entrypoints for Query/Transact/Pull API (labmda proxy to datomic). How can I expose the results of these APIs? (json?) I want to be able to read it in other services written in different languages. Thanks 🙏

cch115:02:09

If your goal is to expose the results of datomic queries/tx results to HTTP clients then you will need to write a web service whose entry point is the :http-direct value in your ion-config.edn file. It's not hard, but it certainly introduces a much bigger design space than just handling lambda requests. (I'm not certain I really understood your question, so please add some more details if you think I missed the target here).

👍 1
Aviv07:02:53

Hey, my main question is focusing on the response payload format, I am already using the lambdas to query/tx (not by http-direct). I want to turn the Datomic responses into JSON, so I would be able to read it from my python service (the response from the lambda). I have already tried using some libs for writing the Datomic results into string, but transact results for example, contains some clojure features like tags such as #datom which I can’t parse: tx response: [#datom[13194139533423 50 #inst "2024-02-05T09:15:16.762-00:00" 13194139533423 true]] how can I turn this to JSON? Thanks 🙏

cch113:02:48

In Cloud (and probably on-prem) datoms can be thought of as 5-tuples that can be access sequentially (IIRC) and associatively with :e, :a, :v, :tx and :added. That's all the information content of a datom AFAIK. So you could easily write something that turns each datom into an array or map and further into JSON. You'll probably face a similar problem with the :db-after and :db-before values. There, I think the valuable information content is the "t" value and if you are already presenting the datoms then the t value is somewhat less useful since it can be derived from the tx of the datoms. But you could convey it to your callers as well.

Rodrigo Cavalcanti20:02:13

Hi everyone, I'm trying to setup datomic cloud but I'm finding the following error:

Caused by: clojure.lang.ExceptionInfo: Unable to execute HTTP request:  {:cognitect.anomalies/category :cognitect.anomalies/fault, :cognitect.anomalies/message "Unable to execute HTTP request: "}
PS: I've changed the URL to "<compute-stack-url" in purpose in the message I've basecally followed the steps specified here: https://docs.datomic.com/cloud/getting-started/start-system.html I would be really grateful if someone could help me with this ❤️

Rodrigo Cavalcanti20:02:51

A little more on the problem: I'm creating a little testing client just so I could connect it to datomic. The code base has just these lines of code:

(ns client.core
 (:require [client.env :as env]
           [datomic.client.api :as d]))

(def cfg {:server-type :cloud
          :region "as-east-1" ;; e.g. us-east-1
          :system "nu-futuro-cache-rod"
          :creds-profile "nufuturo"
          :endpoint ""})

(def client (d/client cfg))
(d/create-database client {:db-name "movies"})
The error points to the last line, on "create-database" function

az22:02:12

Would love to help but I'm not there yet myself. Hopefully someone chimes in soon

cch123:02:26

as-east-1 vs sa-east-1

☝️ 2
Rodrigo Cavalcanti14:02:37

Omg, thank you! It worked ❤️