Picolab / pico-engine

An implementation of the pico-engine hosted on node.js
http://picolabs.io/
MIT License
43 stars 8 forks source link

Testing tab converts digit strings to a number #627

Open b1conrad opened 1 year ago

b1conrad commented 1 year ago

Phil reported:

I have a rule that accepts an event attribute that is an identifier but looks like an 18-digit number. Like this: 830010923977419046. When I look in the logging, it comes through like this:

2023-03-23T21:56:58.348Z - EVENT clflixuzs03hf7ooicuyqgarl sensor:configuration {"iotplotter_feed_id":830010923977419000,"iotplotter_api_key":""}

Note that the last two digits are different. What I suspect is that somewhere along the line (in between the testing tab form and the event being seen by the pico, it's being treated as a number rather than a string and losing precision. For example, if I enter 830010923977419046a (note the a) then it comes through accurately.

More evidence, if I send the event using Postman, the feed ID is correctly sent and interpreted as a string.

Sure enough, a string of digits comes in as a number (not a quoted string).

it should just treat everything as a string since that's how the HTTP post will treat them.

b1conrad commented 1 year ago

This appears to be the place where the conversion to number occurs: https://github.com/Picolab/pico-engine/blob/master/packages/pico-engine-ui/src/components/PicoTabs/Testing.tsx#L21-L25

b1conrad commented 1 year ago

Yes, that does it.

$ node
Welcome to Node.js v16.15.0.
Type ".help" for more information.
> n="830010923977419046"
'830010923977419046'
> JSON.parse(n)
830010923977419000
> [Ctrl-D]
$ 
b1conrad commented 1 year ago

A workaround would be to enter the number into the Testing tab as "830010923977419046" which JSON.parse will convert into a string.

b1conrad commented 1 year ago

I'm lobbying for changing this behavior, removing the JSON.parse. A KRL developer can easily apply the .decode() operator to event attributes and function arguments, if they want incoming strings to be interpreted as Maps, Arrays, etc. The nice thing about .decode() is that if it operates on something that already isn't a String, it just returns it unchanged.

When HTTP is used as the transport, everything is passed as a String anyway, so it make sense to let the KRL programmer .decode() if they want to. In the case of a String of digits that is not intended as a Number, but just an identifier, the KRL programmer would not choose to .decode() it.

b1conrad commented 1 year ago

When an event is raised to another pico hosted by the same pico engine, attributes are passed internally as Maps, Arrays, etc. But if the pico is on a different pico engine, http:post is used behind the scenes so that attributes are given as Strings and will need to be decoded in that case. It's easiest to just always decode them and then it doesn't matter where the pico is hosted.