Fork me on GitHub

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)


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



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


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?


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


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


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


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


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


it's a pain though 😉


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


but thanks 🙂


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


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


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


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


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


so prefer to just shift paradigm a little xD


You can transact the whole thing as a nested map:

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


ooh - even without being a component?


and if you do it twice, it just works?


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


also - is that infinitely nestable?


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


there are a couple of caveats ^


hehe, thanks - I'll have a read 🙂


in particular you need a unique attribute in the inside entity


or it has to be component


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.


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


:thumbsup: thank you!


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


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.


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


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


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


I took this :db.type/tuple schema example from Datomic’s On-Prem documentation.

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


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}


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

com.datomic/client-pro "0.9.57"


This is all tied to the storage not the client


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


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


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


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

Jon Walch20:08:08

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 (impl.clj:324).
Unsupported escape character: \U

Alex Miller (Clojure team)21:08:53

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

Jon Walch21:08:41

@alexmiller Different error message, but still doesnt work

Jon Walch21:08:21

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.

Alex Miller (Clojure team)21:08:54

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

Jon Walch21:08:22

Same error with that unfortunately

Alex Miller (Clojure team)21:08:07

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 Walch21:08:03

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

Alex Miller (Clojure team)21:08:23

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

👍 3

Hi @jonwalch could you try:

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

Jon Walch21:08:47

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


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

Jon Walch21:08:31

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.