-
Notifications
You must be signed in to change notification settings - Fork 160
Create Mutation #7
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
oskarhane
left a comment
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.
First of all, thank you for a superb PR description.
It's very useful to read about your reasoning and the path you got to to get to this solution.
As for the changes, I think the separation into separate files are useful and makes it easy to read, so 👍 on that!
The code looks good, I just had some minor comment.
And love the tests, thanks for writing good tests.
I found a bug when using float numbers when using query variables (unrelated to this PR), but something to think about in the future is to include most datatypes in each higher level tests (tck + integration).
One thing I wonder though is if the non-transactional behavior is expected.
The case when you want to create X and connect it Y and Y doesn't exist. In the database world that might live in a transaction that will be rolled back when it fails.
I think we should discuss the last point with PM/Will before I approve this PR.
| const outStr = relationField.direction === "OUT" ? "->" : "-"; | ||
| const relTypeStr = `[:${relationField.type}]`; | ||
|
|
||
| res.connect += `\nWITH ${withVars.join(", ")}`; |
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.
wdyt about using arrays to store the strings and joining them with line-break at the end (as you do in other areas of the code) instead?
I find the \nString everywhere a bit dirty.
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.
Yeah, I agree, in most use cases an array is fine. This was me being inconsistent & a good spot. Ill tackle this with the next few commits.
| ## Cypher Create Pringles | ||
|
|
||
| Tests operations for Pringles base case. see @ https://paper.dropbox.com/doc/Nested-mutations--A9l6qeiLzvYSxcyrii1ru0MNAg-LbUKLCTNN1nMO3Ka4VBoV |
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 love these tests. Very useful and easy to read!
@oskarhane Thanks for your feedback. Interesting thoughts on the transaction & I guess your specific point highlighted here touches on the usage of Currently, as it stands, if one was to "Create a product & connect to a not found photo"; mutation {
createProduct(input: [
{
name: "Pringles",
connect: {
photo: [{ where { name: "not found" }}]
}
}
])
}this ^ mutation would pass. Just to clarify your question here... are you asking if either this should or should not succeed? |
Yes, correct. Personally, I'm not sure. Something to discuss internally. |
Interesting point, if we went for the "all or nothing" approach we would need an explicit way of throwing an exception. Something like; |
One could use |
oskarhane
left a comment
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 good to go, it sounds like we want the behavior to "connect and ignore if there's nothing to connect to" rather than "all or nothing".
🤖
This PR covers this card. It's tested and fully functional and here I will explain a few points and gotchas.
Conditional Cypher
The nature of
connectmeans that we are matching nodes that could or could not exist. Say we have aproductand we want to connect it to aphoto. We know that theproductwill exist, as we are creating it, but thephotois an unknown. One could go ahead and write the following;But quickly this becomes a problem when
photois not found... The query will 'break' and not return the createdproductor execute any lines under the "not found"photo. To combat this unwanted behavior one would think to use sub subquerys such as;Unfortunately, the above cypher will not work and there is currently an investigation into the discussed and reported bug here. Due to the issue discussed we need to fall back to using the FOREACH technique explained in conditional-cypher-execution;
It's worth pointing out that FOREACH will be removed at some point. We should keep its deprecation in mind & continue liaising with the cypher team as to when the issue will be fixed.
Projections
One can create many
productwith one mutation;Although the ability to create many
productusers only has the ability to specify one projection. In this PR, we have some 'magic' to reuse the same projection for each createdproducthere. This logic saves us from creating O(n) projections and params.Usefull Tests
All tests are useful although you will find the following; here & here extremely handy in the context of this PR.
Cypher Generation
You may have noticed the 'ugly' cypher generation. Efforts have been made to keep this as readable as possible however, it's unrealistic to generate pretty patterns with cypher. One who is creating a node and creating relationships may write something like;
Seeming we expose the ability to generate complex cypher this PR sticks to using a more 'procedural' style such as;
The usage of procedural cypher becomes apparent when one is connecting large subgraphs such as the one here. It means the code is simpler as we only ever 'concatenate' a connection between 2 nodes plus it leaves room for further operations such as; update & disconnect.