Fork me on GitHub

@tony.kay great to hear all the progress on RAD, one question that pops op is: do you send datomic ids to the front-end as well? Because I did that with datomic cloud a while back and ran into some weird issues that had me scratching my head for quite a bit. It turns out that the Double the browser uses can usually correctly encode the int generated by datomic, but sometimes it couldn't.. Had to do a lot of casting from and to goog.math/Long, for example at fulcro routing that uses strings (as it should).


@U09MR0T5Y i believe that’s because native datomic ids can be bigger than the usual range of supported ints for some browsers (at the very least it can cause performance problems)


Tony and I tend to use uuids with a unique identity constraint on almost all of our entities


so :order/id , :payment/id , etc are all set to a uuid


this also make data re-imports possible if we ever need to do that


and allows us to set the id in the client optimistically if we want to


and this approach works better with pathom


for our project, db/ids are just an internal implementation detail, that we rarely deal with by using look-up refs instead


Okay, thanks for the approach info. And yes, it's just the floating point double can only represent so many integers accurately. I understand lookup refs with uuid are the solution here. Just wondered about Datomic native IDs: the ability to map pathom/RADs concept of an id attribute (i.e. :account/id ) to Datomic's :db/id so that you don't have to use UUIDs.


yeah i believe that’s just so it’s possible, for example with a legacy project


or a different database that has some other constraints


just a generalization IMO


FWIW, I do the same thing - Datomic ids are just an implementation detail, and lookup refs are used for all entities. This approach has a couple of nice features when working with Fulcro. First, resolvers are easier to write since a plain :db/id doesn’t have any context whereas something like :person/id does. Second, I rarely have to deal with tempid resolution because in most cases the uuid can be generated on the client and used from the start.


I just added native ID support to the native datomic RAD adapter. Had not considered long overflows…I should make sure that isn’t a problem.


Otherwise, what they said…the RAD adapter actually morphs :db/id to/from :account/id etc.


Interestingly, transit should already handle integers that overflow and make them goog.math.Long . Assuming that those js-objects in Fulcro state don’t get accidentally transformed into something else, I think they should “just work”, so I’m wondering where you ran into problems with the cloud @U09MR0T5Y. Were you using transit?


Oh, in routing…I overlooked that


Yes, I was using transit, and that conversion happened, but for example at routing, where you parse ids.


Yes! 🙂


yes, when using strings, that is a problem


Thanks for saying that…RAD has that bug, then


cognitect.transit had a nice int-value function that takes care of it, and goog.math.Longs cast to string nicely.


What is the role of the RAD database adapters? Are they needed necessarily, and what does that impose on the database schema?


RAD is intended to any one or combination of the following: • Centralize the declaration of everything you’d like to say about a “fact” of your application in one place. From how it should appear on a form, to validation and storage in a database; however, RAD proper need not actually provide the implementation of any of those “definitions” • Database adapters: Support generating database schema from those declarations, should also support optionally generating resolvers for pathom to make network query API for entity/table/row things. • Form data: Manage the lifecycle, state, loading, and saving of generic forms. • Basic Reporting: Collecting parameters and running queries for generating reports. • Rendering plugins: Support rendering forms/reports automatically. Imagine declaring the above and being able to say “ok, use the react native plugin for rendering”. Right now, I’m only writing a web-based rendering for things using Semantic UI, but that is very easy to expand upon. The overall goal is in the name: Rapid Application Development. Make it possible for you to say the absolute minimum about your appplication and have everything from the schema to the UI created for you. However, one very strong requirement is that RAD not lock you into anything. So every one of the features above (aside from simple concentrated declaration of facts) is meant to have an easy “escape hatch”. You do not have to use the database adapter. You don’t have to use the renderers, etc.


In terms of the other part of your question: what does a db adapter impose on the schema: well, that is up to the db adapter. For the most part the pathom parser and save middleware makes it quite easy for you to adapt RAD (and any of its current or future db adapters) to any schema. I’m currently porting a prod app to use RAD (many admin/setting screens) and am seeing 300+ lines of code disappear for every pre-existing CRUD screen in the old app. As I go I do run into specific things that I had yet to design into RAD, but have yet to have the Datomic adapter “get in the way” because of this intentional design. Not to say it “does everything”…it is not meant to…It is designed to be easy to escape from and customize.


So, if you want it to generate some specific schema for you, that will be a natural limitation. It will only be able to generate what the db adapter author wanted to handle…but that doesn’t mean you can’t put that schema in the db by hand and use it.


Okay thank you for that extensive reply 🙂 Will definitely look more closely into it now.


According to RAD design, many-to-many relations, such as :author/books and :book/authors, are modelled as independent attributes at the level of :com.fulcrologic.rad.attributes/* keywords, but their join table will be configured via underlying adapter, right?


correct. how such relations are resolved will be a task either for the db adapter, or a hand-written resolver.


If it possible to use StringBufferedInput to display a custom input instead of dom/input, like the semantic ui input?


don’t remember…use the source 🙂