-
Notifications
You must be signed in to change notification settings - Fork 3
feat: segment data model #153
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Conversation
…legates to std::optional<T> overloads
|
This pull request has been linked to Shortcut Story #207649: Segment data model. |
| status_manager); | ||
|
|
||
| auto res = stream_handler.HandleMessage("put", "{\"potato\": {}}"); | ||
| auto res = stream_handler.HandleMessage("put", "{\"potato\": 3}"); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can I get an explainer on this one?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Reverted.
This was due to some confusion on my part - I intended to make {} be a valid message (viewing it as an implicit value of 0 for version, and null for value.)
But I implemented that logic incorrectly and made it a valid deserialization because I was treating it as empty/omitted.
That's a backwards way of thinking about it: "it's an empty object, therefore treat it as empty/omitted" vs "it's omitted/omitted, therefore treat it as an empty object" - the former is wrong, the latter is what I'm doing in the later Flag Model PR.
| struct SDKDataSet { | ||
| using FlagKey = std::string; | ||
| using SegmentKey = std::string; | ||
| // std::unordered_map<FlagKey, ItemDescriptor<Flag>> flags; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Commented out code.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
(This one is added in the next (flag model) PR)
This PR builds on #153, extending the deserialization to flag data. I've added to the `PARSE_FIELD` macro to handle the following cases: 1. Parse a field where the zero-value is a valid part of the domain: `PARSE_FIELD`. In other words, if the field is omitted or null, it will be filled in with a default value. Most common scenario. 2. Like (1), but supply a default value in case the field is null or omitted: `PARSE_FIELD_DEFAULT`. 3. Parse a field that doesn't have a valid default value, and so is represented as an `optional`: `PARSE_CONDITIONAL_FIELD`. For example, the value `""` wouldn't be a valid default for a unique key. 4. Parse a field that must be present in the JSON data: `PARSE_REQUIRED_FIELD`. Usage of this should be rare; the test would be if the SDK is totally unable to function without this. To achieve this, I've made the `tag_invoke`s operate on `expected<optional<T>, JsonError`'s, instead of `expected<T, JsonError`. We could potentially revert that (and instead add a new enum case to `JsonError`), but I figure `optional` is a good representation of null/omitted. I think I need to actually try removing it to determine if it results in a better API. One thing lacking is better error messages - we use kSchemaFailure everywhere but we now have the ability to report exactly what was missing/wrong type, etc.
This PR extends our existing deserialization/serialization technique from the client-side SDK to the server-side SDK data model.
Specifically, it adds deserialization for the segment structure. I've also introduced some helpers to make the logic less repetitive, and centralize some decisions (like what to do if a JSON field isn't present, or is null.)
As background, the
tag_invokefunctions present in this PR are what allows theboost::jsonlibrary to recursively deserialize complex structures.Here, I've added a couple new
tag_invokesfor bool, string, vector, etc. The special part is that they deserialize intoexpected<type, error>rather than the primitive directly; this allows us to return an error if the deserialization failed.