Welcome! Please see the About page for a little more info on how this works.

+1 vote
in Libs by
edited by

ClojureScript will represent numeric values like {:person/weight 200.0} using Javascript's only numeric type, Number. When such a record is serialized with transit, transit sees Number: 200 and packs that as an integer, and then other platforms e.g. JVM will unpack that as an integer, not a float, and now systems like Datomic will crash on the unexpected type unless I preprocess the values according to a schema that says :person/weight is in fact :db.type/float.

Is this a design flaw in transit? Should transit be changed to allow me to specify the type and/or integrate with a schema provider (spec) to choose the right type?

1 Answer

+1 vote

Just trying to restate your question a bit, I believe you are asking, is there some way for transit-cljs (or really transit-js) to forcibly encode the Javascript number 200.0 as transit ground type "floating point decimal"? (This isn't really a transit-format question, as transit itself does have the capability to represent both fixed and arbitrary precision integers and floats. So, this is really a language specific encoder question.)

I think the answer is no (but I am not an expert in the js side of this world). transit-js/transit-cljs only encode as transit ground types i (integer, signed 64 bit) or f (arbitrary precision decimal). I don't know, but I would guess this is because it's difficult to tell whether a number is representable as a floating point decimal.

Presumably it's possible to allow you to force such a thing, but I think the best place to have that discussion is probably in either https://github.com/cognitect/transit-js/issues or https://github.com/cognitect/transit-cljs/issues.

I'm questioning at the philosophical level that Transit cannot possibly do its job correctly [cross platform value interchange] unless it is integrated with a schema provider like spec or Datomic?
The whole point of transit is to be a schemaless means of transmitting values by providing a means to encode (and extend types). Per the rationale, "Transit processes elements in terms of semantic types, but it is not a type system, and has no schemas. " https://github.com/cognitect/transit-format#rationale Can transit transmit floating point values? Yes, it has a ground type for that.

Questions about per-language encoding or decoding of transit types is a question for those language-specific encoders or decoders (as the language-specific capabilities vary). Does transit-cljs/transit-js have a means to encode Javascript numbers as floating point decimals? No, not currently.

These questions have nothing to do with either schemas or Datomic afaict.
After thought, I think Transit's stated goal of being schemaless is about decoding and interpreting. You don't need a schema to read it. However in this particular case, the schema is essential complexity in helping a quirky platform on the write side. IMO
In this case, you've lost the information when deserializing to JS, because its type system can't model the distinction. So that number is effectively an integer now.

(Number/isInteger 200.0)
;> true

So from the serialization perspective, it seems correct.

What seems to he happening is your database has a strict schema. So I'd simply implement coercing at that level.