-
Notifications
You must be signed in to change notification settings - Fork 324
Implement toString connectors method #7888
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
✅ Docs preview has no changesThe preview was not built because there were no changes. Build ID: 59397bcbd3f5548f2a67810e |
|
@andrewmcgivery, please consider creating a changeset entry in |
| /// $(42)->toString() results in "42" | ||
| /// $("hello")->toString() results in "hello" | ||
| /// $(true)->toString() results in "true" | ||
| /// $(null)->toString() results in "null" |
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.
I think this should be empty string, actually, to match how our string templates (URL & headers) work. Ideally "{thing}" in a string template would be identical to thing->toString() in the rest of code. Then if we add in the ability to do template strings in body/selection/whatever as a way of formatting, that would also be consistent.
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.
I think this is a good case for us to have a single function which converts a JSON value to string and use that in all the places that need to be consistent. So call the same function from here and
router/apollo-federation/src/connectors/json_selection/methods/public/join_not_null.rs
Line 74 in f834eba
| fn to_string(value: &JSON, method_name: &str) -> Result<Option<String>, String> { |
| pub(crate) fn write_value<Output: Write>( |
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.
Done!
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.
| /// $(null)->toString() results in "null" | |
| /// $(null)->toString() results in "" |
So this is accurate now?
| /// $("hello")->toString() results in "hello" | ||
| /// $(true)->toString() results in "true" | ||
| /// $(null)->toString() results in "null" | ||
| /// $([1,2,3])->toString() results in "[1,2,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.
This should be an error, for the same reason above. ->jsonStringify will give the json representation, and ->joinNotNull will give CSV, so whichever format they wanted, they can explicitly ask for.
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.
Yea, forgot to update this! 😩
apollo-federation/src/connectors/json_selection/methods/public/to_string.rs
Show resolved
Hide resolved
| JSON::Array(_) | JSON::Object(_) => { | ||
| return ( | ||
| None, | ||
| vec![ApplyToError::new( | ||
| format!( | ||
| "Method ->{} cannot convert arrays or objects to strings. Use ->jsonStringify instead", | ||
| method_name.as_ref() | ||
| ), | ||
| input_path.to_vec(), | ||
| method_name.range(), | ||
| )], | ||
| ); | ||
| } |
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.
Ah, the docstring up top was just wrong about arrays, so we'll want to correct that.
| fn to_string_shape( | ||
| method_name: &WithRange<String>, | ||
| method_args: Option<&MethodArgs>, | ||
| _input_shape: Shape, |
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.
| _input_shape: Shape, | |
| input_shape: Shape, |
| } | ||
|
|
||
| #[test] | ||
| fn to_string_shape_should_return_string_for_any_input() { |
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.
| fn to_string_shape_should_return_string_for_any_input() { | |
| fn to_string_shape_should_return_string_for_int_input() { |
apollo-federation/src/connectors/json_selection/methods/public/to_string.rs
Show resolved
Hide resolved
| assert_eq!( | ||
| get_shape(vec![], Shape::tuple([], [])), | ||
| Shape::error_with_partial( | ||
| "Method ->toString cannot convert arrays or objects to strings. Use ->jsonStringify instead" |
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.
| "Method ->toString cannot convert arrays or objects to strings. Use ->jsonStringify instead" | |
| "Method ->toString cannot convert arrays or objects to strings. Use ->jsonStringify or ->joinNotNull instead" |
I think in some cases, joining to like a,b,c is what the user might be looking for.
Complete side note, we should probably start including docs links somehow for some of these errors 🤔. Something to investigate at some point.
…re converting a JSON to a string, null returns blank instead of "null"
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.
Added a few more suggestions, other than those this LGTM
| pub(crate) fn json_to_string(json: &JSON) -> Result<Option<String>, String> { | ||
| match json { | ||
| JSON::Null => Ok(None), | ||
| JSON::Bool(b) => Ok(Some(b.to_string())), | ||
| JSON::Number(n) => Ok(Some(n.to_string())), | ||
| JSON::String(s) => Ok(Some(s.as_str().to_string())), | ||
| JSON::Array(_) | JSON::Object(_) => { | ||
| Err("cannot convert arrays or objects to strings.".to_string()) | ||
| } | ||
| } | ||
| } | ||
|
|
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.
| pub(crate) fn json_to_string(json: &JSON) -> Result<Option<String>, String> { | |
| match json { | |
| JSON::Null => Ok(None), | |
| JSON::Bool(b) => Ok(Some(b.to_string())), | |
| JSON::Number(n) => Ok(Some(n.to_string())), | |
| JSON::String(s) => Ok(Some(s.as_str().to_string())), | |
| JSON::Array(_) | JSON::Object(_) => { | |
| Err("cannot convert arrays or objects to strings.".to_string()) | |
| } | |
| } | |
| } | |
| pub(crate) fn json_to_string(json: &JSON) -> Result<Option<String>, &'static str> { | |
| match json { | |
| JSON::Null => Ok(None), | |
| JSON::Bool(b) => Ok(Some(b.to_string())), | |
| JSON::Number(n) => Ok(Some(n.to_string())), | |
| JSON::String(s) => Ok(Some(s.as_str().to_string())), | |
| JSON::Array(_) | JSON::Object(_) => Err("cannot convert arrays or objects to strings."), | |
| } | |
| } |
The callers don't even need a String it looks like, so might as well skip the allocation here.
| } | ||
| } | ||
|
|
||
| pub(crate) fn json_to_string(json: &JSON) -> Result<Option<String>, String> { |
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 you add a doc comment /// about what this function is for & why?
| /// $(42)->toString() results in "42" | ||
| /// $("hello")->toString() results in "hello" | ||
| /// $(true)->toString() results in "true" | ||
| /// $(null)->toString() results in "null" |
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.
| /// $(null)->toString() results in "null" | |
| /// $(null)->toString() results in "" |
So this is accurate now?
| return Err("Expression is not allowed to evaluate to arrays or objects.".into()); | ||
| } | ||
| match json_to_string(value) { | ||
| Ok(result) => write!(output, "{}", result.unwrap_or_default()), |
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 write! stuff is actually a bit silly now... the whole reason I made it this way was to avoid allocating the extra String for each value, but json_to_string is doing that anyway now....
Maybe not worth refactoring all the code, though, to deal with it.
The "right" way is probably to have our own Value type with impl Display on it (which would either write to buffer (efficient) or allocate a new string (🤢) as needed. I'm still assuming we want that some day, but not today.
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.
Perhaps could be refactored in a future PR as needed? :D
| "Method ->{} requires an array of scalar values as input", | ||
| method_name |
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.
| "Method ->{} requires an array of scalar values as input", | |
| method_name | |
| "Method ->{method_name} requires an array of scalar values as input", |
Since you're here 😁
Checklist
Complete the checklist (and note appropriate exceptions) before the PR is marked ready-for-review.
Exceptions
Note any exceptions here
Notes
Footnotes
It may be appropriate to bring upcoming changes to the attention of other (impacted) groups. Please endeavour to do this before seeking PR approval. The mechanism for doing this will vary considerably, so use your judgement as to how and when to do this. ↩
Configuration is an important part of many changes. Where applicable please try to document configuration examples. ↩
A lot of (if not most) features benefit from built-in observability and
debug-level logs. Please read this guidance on metrics best-practices. ↩Tick whichever testing boxes are applicable. If you are adding Manual Tests, please document the manual testing (extensively) in the Exceptions. ↩