Fork me on GitHub
#datomic
<
2018-02-02
>
frankiesardo14:02:37

So let's say I have some code that uses the datomic cloud infrastructure and I want to test it locally

frankiesardo14:02:57

Is there a way to use the in-memory datomic db to test the code that uses datomic.client.api?

stuarthalloway14:02:50

@frankie I would encourage you to try testing against Solo (possibly plus with-db)

frankiesardo14:02:18

What about unit tests?

stuarthalloway14:02:37

people mean a lot of different things when they say “unit”

stuarthalloway14:02:10

A test for assembling a transaction doesn’t need to touch the db at all — it is a value prop of Datomic that you can “stay in data”

stuarthalloway14:02:16

once you are careful about that separation, I rarely find the need for mocks/stubs or in-memory dbs

stuarthalloway14:02:18

(note to self: blog post about how I would test a Datomic app)

frankiesardo14:02:29

That would be an interesting read

frankiesardo14:02:32

Let's say I want to test some code that transact some data into the db and then queries it to retrieve part of it based on some user input

frankiesardo14:02:43

I can check that the transaction data structure is correct and the query is correct based on my understanding of datomic, but I would like to have the confidence that a successful round trip gives me

frankiesardo14:02:16

Particularly testing :offset and :limit which are client only

stuarthalloway14:02:12

that sounds fine (to a point), but what are you saving by avoiding the db?

frankiesardo14:02:17

Do you mean 'avoiding the cloud db'? The fact that I can run many tests on my machine without needing a connection to aws

stuarthalloway14:02:35

because you don’t have internet connection?

frankiesardo14:02:03

Possibly. Possibly because I want to do some crazy stuff with autogenerated data and run many many tests without impacting the bill. Possibly because we want to all run tests in our team without having to spin a aws db for each one of us

frankiesardo14:02:27

I got used to the convenience of having a fully functional in memory db for testing and not having it feels like a step back

stuarthalloway14:02:48

it is a tradeoff for sure

stuarthalloway14:02:21

I think it is valuable to break these cases apart as much as possible

stuarthalloway14:02:19

re: running up the bill — if you are testing intensively enough to do that you are probably doing perf testing and so I think you want to run against your planned topology

stuarthalloway14:02:53

re: spinning a db for each. Fair point, OTOH we have worked hard to make that easy

stuarthalloway14:02:05

Here’s how the Datomic team does it:

stuarthalloway14:02:29

(1) we have a solo topology system for department information (dogfooding, not perf sensitive)

stuarthalloway14:02:28

(2) we have a solo for devs to dev against (create and delete dbs as needed, named with prefixes so we don’t get in each other’s way)

stuarthalloway14:02:15

(3) CI uses another solo (db names have UUID components so tests have isolation)

robert-stuttaford14:02:19

@frankie, you can stand up a free transactor and a peer server locally and use client api with that

stuarthalloway14:02:45

(4) app staging on prod topology

stuarthalloway14:02:01

(5) pop-up additional prod topology systems when we want isolation for perf testing

robert-stuttaford14:02:42

loving reading about your testing setup, Stu!

stuarthalloway14:02:51

@frankie and you can totally do what @robert-stuttaford said too 🙂 I am just laying out the future we are trying to make

frankiesardo14:02:23

@robert-stuttaford Yes I was thinking about that, it's just a little awkward to shell out to the datomic starter edition (I guess the way to do it is this one https://docs.datomic.com/on-prem/first-db.html)

robert-stuttaford14:02:26

it’s honestly not that tough, @frankie - it’s a once off investment, take you a couple hours to get set up to your liking, and then you have it. we have a zsh-plugin with everything in it 🙂 (we’re Peer based, but i’m dabbling with Client right now)

frankiesardo14:02:34

Thanks for taking the time to explain how the datomic team does it @stuarthalloway

robert-stuttaford14:02:48

i have 2 letter shell aliases to start txor and peer server

stuarthalloway14:02:17

@robert-stuttaford and similar aliases for launch missiles and ejector seat I hope 🙂

robert-stuttaford14:02:31

yeah, those are the capitalised ones!

frankiesardo14:02:33

@stuarthalloway would you consider in the future the ability to include the peer server as a jar dependency you can start within your test process?

frankiesardo14:02:50

Or there is some kind of technical/licence limitation here

stuarthalloway14:02:58

@frankie feature suggestions always welcome! I think it more likely that we would build a dedicated test-local feature a la DDB local mode

stuarthalloway14:02:21

but before we do I am going to continue advocating “think differently” about testing 🙂

frankiesardo14:02:55

Ah, fair point 🙂 We're definitely going to try out the Datomic Team approach

frankiesardo14:02:57

But something tells me I'm not the only one who's going to miss the in memory convenience of peer datomic

stuarthalloway14:02:39

no doubt, and code-local-with-nodes features are an active area of consideration for Cloud

val_waeselynck15:02:55

@stuarthalloway sounds interesting, can you clarify what you mean by 'code-local-with-nodes'?

sleepyfox14:02:44

What are the differences between the peer and client apis with respect to swapping out client for peer to be able to test locally with a :mem db?

frankiesardo14:02:08

@sleepyfox :offset and :limit , for one

robert-stuttaford14:02:18

you need a peer-server to connect to with Client, @sleepyfox, and the api is substantially simpler https://docs.datomic.com/client-api/datomic.client.api.html

sleepyfox14:02:59

I have already run up against the fact that pull doesn't seem to work with the client API

stuarthalloway14:02:13

@sleepyfox pull works with the client API

sleepyfox14:02:15

(we're using Cloud)

robert-stuttaford14:02:38

@sleepyfox if you’re curious, i converted my blog code from peer to client recently, to begin learning about this https://github.com/robert-stuttaford/stuttaford.me/commit/ae31ad1899b7977adc74064227c0a126c1d39662 - it’s a toy app and so therefore a toy migration, but some noticeable changes there

Hendrik Poernama16:02:29

Curious about your architecture here. Seems like you are passing datoms to cljs and perform query using datascript?

robert-stuttaford21:02:20

yes; because the dataset is small, i wanted to have an instant-search experience on the client. check it out: http://www.stuttaford.me/codex/

Hendrik Poernama19:02:04

looks like something is broken in the current build. Getting this in my browser Uncaught Error: ... is not ISeqable

Hendrik Poernama19:02:22

interesting titles on the blog posts though, I'm gonna read 🙂

robert-stuttaford20:02:59

Thanks - pr-str print length issue. resolved, @U7Q9VAXPT!

stuarthalloway14:02:41

but more than one person has said that, wonder where the confusion comes from

sleepyfox14:02:47

Really? OK, then it's our fault, we'll have to investigate that further

sleepyfox14:02:20

Thanks @robert-stuttaford - I'll take a look at that

sleepyfox14:02:20

We tried pull with the client API fronting Cloud, and got an exception which led us to believe that that feature wasn't supported by the Client API

sleepyfox14:02:39

something to do with the API not implementing a protocol

stuarthalloway14:02:05

@sleepyfox keep in mind that pull-many is not (and never has been) needed as a separate API, as it is basically a shim on query+pull

sleepyfox14:02:29

we were just trying pull, not pull-many

stuarthalloway14:02:19

@sleepyfox let me know if you have a repro, I would want to jump on that

sleepyfox14:02:52

If I get time next week I'll set up something reproducible.

sleepyfox15:02:20

Is it possible to subscribe to the tx report queue from the client API (i.e. using Cloud)?

sleepyfox15:02:42

(context: thinking of event-driven systems)

robert-stuttaford15:02:46

not according to the api docs

sleepyfox15:02:01

^^that's what I suspected

sleepyfox15:02:19

and we can't use the peer API with Cloud?

robert-stuttaford15:02:05

tx-report-queue exists because it basically exposes something Peer does for its own needs; receive pushes of live index from the transactor. clients don’t receive such, and so wouldn’t be able to expose it

sleepyfox15:02:18

thanks, thought so

robert-stuttaford15:02:25

no Peer + Cloud availability yet, but i believe the possibility exists

timgilbert15:02:10

Say, random question here. I'm using the newish datomic feature where you can add schema without explicitly specifying the :db.install/_attribute attribute, by transacting some data like this:

{:db/ident       :artist/id
   :db/valueType   :db.type/long
   :db/cardinality :db.cardinality/one
   :db/unique      :db.unique/identity}
That works fine, but then I'm also working on some code to do some introspective analysis on the db, so I'm trying to find every defined attribute. That code looks like this:
(defn- attr-list [db]
  (d/q '[:find ?ns ?attr ?doc
         :where
         [_ :db.install/attribute ?a]
         [?a :db/ident ?ident]
         [?a :db/doc ?doc]
         [(namespace ?ident) ?ns]
         [(datomic.api/attribute $ ?a) ?attr]
         (not [(re-find #"deprecated" ?ns)])
         (not [(re-find #"fressian" ?ns)])
         (not [(re-find #"^db" ?ns)])]
       db))

timgilbert15:02:52

What I've found is that I can find older attributes via [_ :db.install/attribute ?a], but when I add them to the schema in the new-school way, they don't seem to come back in the query. Looking here I see that datomic is supposed to automatically add them: https://docs.datomic.com/on-prem/schema.html#explicit-schema

timgilbert15:02:27

Is there a better way I should be scanning for user-defined attributes that will handle both cases?

stuarthalloway15:02:29

@timgilbert the presence of any of the other attributes-of-attributes would work

stuarthalloway15:02:47

e.g. :db/cardinality or :db/valueType

timgilbert16:02:27

Ah, good idea. Thanks!

dbernal16:02:07

Is there a particular order to how entities come back from a query? My question being how does Datomic decide in what order to return entities

favila16:02:50

There is no guaranteed order. It's an accident of implementation (hashing, order of operations done in parallel, etc)

favila16:02:14

but I think it's stable, so if you repeat a query on the same db you will get them in the same order

dbernal19:02:22

gotcha. thank you!

alexk18:02:09

I’d appreciate some guidance for (or tales of) modelling time in Datomic. Should be the easiest thing, right? But there’s a problem because time comes in at least two flavours, real time (i.e. monotonically increasing) and business logic time (i.e. when did something have an effect). The former is absolute, the latter is fluid and can be retroactively changed. Question: Should the time-value of a datom be used for business logic? If yes, then time-travel becomes easier, but doesn’t rewriting history also become hard/impossible? How would you then store a fact that somebody retroactively applied a discount to a user’s invoice??

favila18:02:18

Generally no. Think of datomic's time as "git time"

favila18:02:37

it's for debugging, auditing, etc, not business logic

favila19:02:51

in Git you wouldn't rewrite history to make a bug never get committed, you'd make a new commit (= transaction)

favila19:02:25

however this technique may sometimes be useful: have a source-of-truth db which models business time explicitly; then occasionally you can construct a derived datomic db where business time = tx time

favila19:02:32

This is useful if you have some time-series application that would benefit from the nicer time indexing and api of db-as-of or db-since

favila19:02:04

but every time you "change the past" you would have to regenerate the db, so it's an offline batch-type workflow only (e.g. for analysis)

alexk20:02:16

Hmm right, that’s a neat compromise

joelsanchez21:02:17

I think this article is related

joelsanchez21:02:29

event time vs recording time

dadair21:02:20

In the Datomic pricing model for Pro, it says $5000/yr for a “system”. I assume “system” relates to number of transactors; where 1 system = 1 transactor?

dominicm22:02:20

Having a failover is okay too

dadair22:02:11

So one “system” is a primary transactor and one fail-over transactor + any number of peers/clients?

timgilbert22:02:23

That's my understanding, yes. It was changed last year to include unlimited peers, IIRC. I'm sure someone from Cognitect can confirm though

favila22:02:05

A "system" is easier to discern by storage

favila22:02:41

"system" = peers and transactors used in production which share a storage

favila22:02:16

(a transactor can only manage one storage)

dadair22:02:34

awesome thank you!

dadair21:02:40

Sorry if there are docs on this, couldn’t see anything obvious in the docs.