This page is not created by, affiliated with, or supported by Slack Technologies, Inc.
- # adventofcode (100)
- # announcements (7)
- # architecture (1)
- # aws (14)
- # beginners (209)
- # calva (30)
- # cider (5)
- # cljdoc (2)
- # cljs-dev (37)
- # cljsrn (2)
- # clojure (133)
- # clojure-dev (20)
- # clojure-finland (1)
- # clojure-italy (10)
- # clojure-nl (19)
- # clojure-spec (56)
- # clojure-uk (49)
- # clojurescript (57)
- # clojurex (8)
- # core-async (2)
- # core-logic (1)
- # cursive (38)
- # data-science (19)
- # datomic (28)
- # devcards (3)
- # duct (8)
- # emacs (28)
- # figwheel (1)
- # figwheel-main (31)
- # fulcro (2)
- # jobs (1)
- # kaocha (1)
- # klipse (2)
- # mount (6)
- # nrepl (43)
- # off-topic (20)
- # pathom (3)
- # pedestal (1)
- # re-frame (15)
- # ring-swagger (1)
- # shadow-cljs (47)
- # spacemacs (19)
- # sql (20)
- # tools-deps (58)
- # unrepl (13)
- # vim (5)
Am I thinking to boldly about Datomic, or is it possible to have a entirely purely functional non-trivial buisiness logic, similar to how one could do it with a plain closure map? That is, passing in the state (database) at the top, then adding, updating, retracting, getting etc. in any combination, and lastly do something similar to a "swap!" or "reset!"? Preferably I'd like to get a "new" database instance back after every step, so that I can continue to query and alter the database state until I'm happy. Also, if something goes wrong in the middle I obviously don't want anything committed to the actual database. I imagine transactor functions as in Datomic ions ought to make this possible?
That's not exactly how it works, but you can essentially achieve the same power. Datomic Connections and Database values essentially correspond respectively to Clojure Agents and values. However, unlike regular Clojure values, you don't update a Database value by calling
assoc etc. - you do it by emitting Datoms. Transaction functions enable you to accept a 'present' Database value, optional additional arguments, and to emit an arbitrary set of Datoms which will be added to form the next Database value.
So the model is not that you fabricate intermediary database values and 'commit' to the last one. However, you can use speculative writes (aka db.with()) to 'preview' what Database value will be yielded by adding the Datoms you're considering.
Thank you @U06GS6P1N for the reply! It remains then to figure out a reasonable architecture that lets me output the datoms in a sensible way. :) Also, regarding unit testing, is there any way to get an in-memory equivalent to an datomic cloud/ions database value that supports the same query/pull API? The idea is to transact (plain) datoms to a clear database, and then query it using the function I'm presumably testing. Would either the datomic Free database or an in-memory peer with a wrapper like https://github.com/ComputeSoftware/datomic-client-memdb/blob/master/README.md do the trick? By the way, I found your awesome blog the other day, I have yet not managed to digest all the datomic-specific parts yet, but I have still learned a lot, especially the post about event sourcing was enlightening! 👏
At my job we are using ‘on-prem’ Datomic run on AWS EC2 because we considerably pre-date the advent of Cloud and Ions, so we haven’t had a need to wrap the in-memory peer, but otherwise we do exactly as you describe for unit tests and CI. We have a manageable amount of test data that just lives in source control as datoms in EDN, and before a test run we stand up an in-mem DB, transact our schema to it, and transact in the test data.
A nice knock-on effect is that we also have a
server-dev Boot task which stands up that same “test” in-mem DB and also starts up our backend services locally, pointed to it. One fully-operational but local backend stack, ready to attach to a REPL, please! 😄
That's awesome! 😄 I hope that I'll be able to construct something similar.
@UEJ28A9PH I think you can attempt that by using d/with-db and d/with, although the bookkeeping of what data is tx-data would be your responsibility.
Thanks for the suggestion @U0CJ19XAM ! However, the scenario I asked for in the first post does not seem to be very idiomatic, so I believe I'd be better off just doing it "the right way" instead. I guess the d/with and d/with-db could be helpful in some situations though, especially in tests maybe?
In our SPA we do a lot of local ui-bookkeeping resulting in a couple of keys that won't be accepted by Datomic for transact. What is a good way to dissoc them? Or selecting relevant keys. We have a spec for what a complete entity should be.
I suppose the only way would be with some spec magic, but I think it is frowned upon
Maybe take a look at https://github.com/metosin/spec-tools - it has tools for coercion, transformations and walking nested specs (including stripping out extra keys)
having worked with datomic cloud for the last 3 weeks i’m ruined to postgres. i want to thank and shame everyone responsible for this. /rant
now i have to go find a way to reify transactions, write triggers into an audit table, and compose some horrific transactions and queries
When using the Datomic cloud client,
(d/db ,,,) returns a
:database-id value as well as the
:database-id value isn’t returned by
(d/db ,,,) when running in the cloud AFAICT. Can someone confirm this? I’m looking to get a globally unique, consistent value for the database across connections. Alternative ideas welcome.
I've used db values themselves as keys, although there could be two equivalent databases.
And just in case, since I'm trying to get my company to open source this library, what are you doing?
Nope, making sure I’m connected to the same database I thought I was before. We churn through databases (and Datomic Cloud stacks, for that matter) and I want to be able to confirm I’m connected to the same database I was before.
@andreas862 we namespace all the ui artifact keys with
:ui/, and then we just use
clojure.walk to remove all the keys that
(= "ui" (namespace k))