datomic

Ask questions on the official Q&A site at https://ask.datomic.com!
cmdrdats 2020-08-19T08:05:22.214200Z

I have a schema with two attributes - :ent/uuid :db.unique/identity and :ent/context :db.type/ref - is there a way I can make this automatically create the referenced entity?

(d/transact datomic
  [{:ent/context [:ent/uuid (d/squuid)]}])
(obviously this is a contrived example, the (d/squuid) would almost always be a uuid from somewhere else)

cmdrdats 2020-08-19T08:06:40.215100Z

(ideally, there's a schema attribute that can set this as a property of :ent/uuid - but I suspect I'll have to actually go lookup and create the entity if it doesn't exist?)

cmdrdats 2020-08-19T11:24:51.216300Z

hmm

(d/transact datomic
  [{:ent/uuid #uuid "093eaee6-ebc7-45f2-9a3f-b923f4864e5c"} 
   {:ent/user [:ent/uuid #uuid "093eaee6-ebc7-45f2-9a3f-b923f4864e5c"]}])
doesn't work? that's a shame - am I looking at this wrong, or do I pretty much have to resort to lookup+tempid's?

cmdrdats 2020-08-19T11:25:56.217600Z

(for context, I'm wanting to write my code for adaptive gradual backfill of existing entities with uuid's from other databases - as opposed to a dedicated ETL process)

joshkh 2020-08-19T12:16:10.219900Z

if i'm reading this correctly, you want to transact an entity while also transacting a reference to that entity in the same transaction, right?

joshkh 2020-08-19T12:18:07.220100Z

if so, then you can use temporary ids within the same transaction

(d/transact datomic
            [{:ent/uuid #uuid "093eaee6-ebc7-45f2-9a3f-b923f4864e5c"
              :db/id "newuser"}
             {:ent/user "newuser"}])

cmdrdats 2020-08-19T12:19:31.220300Z

ye, that's basically what I'm doing as a workaround (using d/tempid ) - trouble is that you have to actually have to think about it, at a higher level

cmdrdats 2020-08-19T12:21:26.220500Z

where I would have preferred to just (effectively):

(->>
  [(when user-not-found {:ent/uuid #uuid "093eaee6-ebc7-45f2-9a3f-b923f4864e5c"})
   {:ent/user [:ent/uuid #uuid "093eaee6-ebc7-45f2-9a3f-b923f4864e5c"]}]
  (remove nil?))
instead, I need to collaborate the two pieces of code to pass the temporary id around

cmdrdats 2020-08-19T12:21:54.220700Z

not a major problem, but seems a bit odd, given how lovely lookup refs are

joshkh 2020-08-19T12:22:19.220900Z

> I'm wanting to write my code for adaptive gradual backfill of existing entities with uuid's from other database i do something similar from time to time, and what i do is first transact the entities in the DB, and then in a second transaction i establish their references. you might be able to do something clever, like walk your input data and create a tempid out of the uuid (i never had to go that far)

joshkh 2020-08-19T12:22:48.221100Z

it's a pain though 😉

cmdrdats 2020-08-19T12:25:28.221300Z

ye, I'm trying to whittle down a simple paradigm for consistently interacting with datomic that I can then teach to the team.. save then load would work, but a bit too much of fickle

cmdrdats 2020-08-19T12:25:32.221500Z

but thanks 🙂

joshkh 2020-08-19T12:28:48.221700Z

well if you ever write a generic walker/id replacer for the input code let us know! in my case i migrate slices of the datomic graph from one database to another, and over time i have just added steps for each "kind" of entity. another useful tool would be to replace UUIDs with new ones.. in other words clone parts of the graph and their relationships (within the same db).

joshkh 2020-08-19T12:32:45.222Z

just another thought, and i don't know if this applies to your scenario, but you can transact new entities as reference values if the reference is a component

joshkh 2020-08-19T12:34:57.222200Z

{:tx-data [{:user/id      #uuid "093eaee6-ebc7-45f2-9a3f-b923f4864e5c"
            :user/address {:address/id           #uuid"f0ef5f94-8125-4aa1-a906-524ec0274941"
                           :address/street       "Maple Street"
                           :address/country-code "US"}}]}

cmdrdats 2020-08-19T12:48:44.222400Z

that is good to know, thanks! but no, this is for the generic case, not really components

cmdrdats 2020-08-19T12:50:56.222600Z

I guess I could handle a generic walker, but that would add a bunch of overhead for 99% of the code that doesn't need it + be an extra bit of complexity to keep having to think about

cmdrdats 2020-08-19T12:51:06.222800Z

so prefer to just shift paradigm a little xD

marshall 2020-08-19T13:49:40.223Z

You can transact the whole thing as a nested map:

[{:ent/user {:ent/uid #uuid "MY_UUID_HERE"}}]

cmdrdats 2020-08-19T13:55:18.223200Z

ooh - even without being a component?

cmdrdats 2020-08-19T13:55:33.223400Z

and if you do it twice, it just works?

cmdrdats 2020-08-19T13:56:03.223600Z

[{:ent/user {:ent/uid #uuid "MY_UUID_HERE"} :ent/ident "1"}
 {:ent/user {:ent/uid #uuid "MY_UUID_HERE"} :ent/ident "2"}]
for instance

cmdrdats 2020-08-19T13:59:06.223800Z

also - is that infinitely nestable?

marshall 2020-08-19T13:59:16.224Z

sure

cmdrdats 2020-08-19T13:59:34.224200Z

very cool - I'll be abusing that, thanks!

marshall 2020-08-19T14:00:32.224600Z

there are a couple of caveats ^

cmdrdats 2020-08-19T14:01:36.224800Z

hehe, thanks - I'll have a read 🙂

marshall 2020-08-19T14:01:44.225Z

in particular you need a unique attribute in the inside entity

marshall 2020-08-19T14:01:49.225200Z

or it has to be component

cmdrdats 2020-08-19T14:03:44.225400Z

cool - ye, I'll be enforcing :ent/uuid - so that it can always gradually converge to the same entity.. I do have a few more identity attributes, but there's a possibility of creating two rows for the same entity, then not being able to reconcile later.

marshall 2020-08-19T14:21:28.225600Z

yep, you'd need to make sure that was handled when you build the nested map

cmdrdats 2020-08-19T14:23:00.225800Z

:thumbsup: thank you!

frankitox 2020-08-19T15:23:36.227800Z

Does anyone actually uses the schema type :db.type/uri ? There's some real benefit apart from semantics? Using :db.type/string works just fine and I don't need any code to serialize/deserialize the data.

favila 2020-08-19T15:28:31.227900Z

I have used it. I like that it rejects invalid uris. I also see more types as a bonus.

favila 2020-08-19T15:29:19.228100Z

I don’t think there’s anything wrong with using strings instead

twashing 2020-08-19T17:12:56.228800Z

I took this :db.type/tuple schema example from Datomic’s On-Prem documentation. https://docs.datomic.com/on-prem/schema.html#heterogeneous-tuples

{:db/ident :player/location
 :db/valueType :db.type/tuple
 :db/tupleTypes [:db.type/long :db.type/long]
 :db/cardinality :db.cardinality/one}

twashing 2020-08-19T17:13:48.229500Z

But I get this error when running a transact (with com.datomic/client-pro “0.9.57” ( also tried “0.9.63" )). Is this just a bug? Or is there something else to making tuple types work?

Caused by: datomic.impl.Exceptions$IllegalArgumentExceptionInfo: :db.error/not-an-entity Unable to resolve entity: :db/tupleTypes
{:entity :db/tupleTypes, :db/error :db.error/not-an-entity}

favila 2020-08-19T17:20:08.229600Z

Did you upgrade your base schema? https://docs.datomic.com/cloud/operation/howto.html#upgrade-base-schema

frankitox 2020-08-19T17:20:38.229800Z

Oh, I didn't have that in mind. Thanks! I think I'll use :db.type/uri because of the free type checking.

twashing 2020-08-19T17:23:51.230Z

I haven’t deployed yet. This is all in development, with this version.

com.datomic/client-pro "0.9.57"

favila 2020-08-19T17:33:12.230200Z

This is all tied to the storage not the client

favila 2020-08-19T17:33:40.230400Z

The db you are connecting to: was it created with a version of datomic earlier than the one that started supporting tuples?

favila 2020-08-19T17:33:50.230600Z

if so, then you need to follow the instructions to upgrade the base schema

favila 2020-08-19T17:34:50.230800Z

upgrading the base schema will transact entities like :db/tupleType

twashing 2020-08-19T18:10:40.231Z

Hmm, right. Probably something with the datomic engine. Ok, cheers.

Jon Walch 2020-08-19T20:54:08.232500Z

Has anyone gotten dev-local working on windows 10? I'm having a hard time with specifying {:storage-dir "C:\\Users\user\foo"}

Execution error at datomic.dev-local.impl/user-config (impl.clj:324).
Unsupported escape character: \U

alexmiller 2020-08-19T21:00:53.233100Z

you probably need "C:\\\\Users\\user\\foo" to escape the \'s ?

Jon Walch 2020-08-19T21:01:41.234200Z

@alexmiller Different error message, but still doesnt work

alexmiller 2020-08-19T21:01:51.234400Z

what's the error?

Jon Walch 2020-08-19T21:02:21.234600Z

Execution error (ExceptionInfo) at datomic.core.anomalies/throw-if-anom (anomalies.clj:94).
You must specify an absolute path under :storage-dir in a map in
your ~/.datomic/dev-local.edn file, or in your call to client.

alexmiller 2020-08-19T21:02:54.235100Z

interesting, it's checking for absolute path - maybe "\\C:\\\\Users\\user\\foo" ?

Jon Walch 2020-08-19T21:03:22.235700Z

Same error with that unfortunately

alexmiller 2020-08-19T21:07:07.237300Z

sorry, that extra pair of \\ isn't needed and paths on windows starting with the drive should be considered absolute. "C:\\Users\\user\\foo" I would expect to work, but maybe I'm missing something

Jon Walch 2020-08-19T21:08:03.237700Z

Sadly, same error again. Thanks for your help alex!

alexmiller 2020-08-19T21:08:23.238100Z

well, I'll invoke @jaret and @marshall to check with the Datomic team then :)

👍 1
jaret 2020-08-19T21:30:27.238500Z

Hi @jonwalch could you try:

{:storage-dir "C:\\Users\\user\\foo"}

Jon Walch 2020-08-19T21:32:47.239100Z

@jaret yes, that's the last one I tried

jaret 2020-08-19T21:38:33.240300Z

Firing up a windows machine to test. Will update here or on the ticket 🙂

Jon Walch 2020-08-19T21:39:31.241300Z

Cool, thanks @jaret! this isn't super urgent for me. my main box is debian. my clojure code talks to a game that I'm running on my Windows machine. Going to go forward with ngrok in the mean time.