-
Notifications
You must be signed in to change notification settings - Fork 31
STITCH-1970 Optimize UPDATE and REPLACE to be $set and $unset #72
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
…into STITCH-1970
…into STITCH-1970
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.
Generally LGTM. Just a few source changes to make and some test recommendations. Nice job!
fun testUpdateDescriptionDiff() { | ||
val originalJson = """ | ||
{ | ||
"shop_name": "nkd pizza", |
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.
where did you get this from haha
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.
It's our local pizza shop in Dublin– I'll change it to not use real names 🍕
} | ||
|
||
@Test | ||
fun testUpdateDescriptionToUpdateDoc() { |
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.
[request] Can you make a more involved test that hits more than just 1 field per updated and removed? I would add some nesting as well. It's nice to have a test where we have a literal string saying exactly what the diff should be.
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.
👍
return newDocument | ||
} | ||
|
||
fun testUpdatedDocumentMatchesExpectation( |
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.
Seems like you can pull this out to a function outside of here so it can be reused. It would make it easier to see what this test is doing if it was just the tests were performing as succinctly as possible.
collection.aggregate( | ||
listOf( | ||
BsonDocument( | ||
"\$project", |
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.
[q] Why is this projecting instead of just doing a find?
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.
The projection was to eliminate the id fields in the subdocuments.
expectedDocumentAfterUpdate: BsonDocument | ||
) { | ||
// create an update description via diff'ing the two documents. | ||
val updateDescription = diff(withoutId(originalDocument), withoutId(expectedDocumentAfterUpdate)) |
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.
[test] It would be better to write an actual update and not use expectedDocumentAfterUpdate. That will prove that we can update something with whatever operators and still produce an update description.
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.
👍
event = changeEventForLocalUpdate( | ||
namespace, | ||
documentId, | ||
ChangeEvent.UpdateDescription.diff(remoteEvent.getFullDocument(), document), |
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.
[q] I think we can still use documentAfterUpdate here?
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 yes, we should be able to.
|
||
if (beforeResult != null) { | ||
emitEvent(documentId, | ||
changeEventForLocalUpdate( |
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.
[minor] When we replace from remote, it is really a replacement so you should be able to keep this code the same.
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.
👍
/** | ||
* Find the diff between two documents. | ||
* | ||
* NOTE: This does not do a full diff on [BsonArray]. If there is |
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.
[q] Why [] for [BsonArray]?
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 copied this over from the kotlin PoC code. Will replace with {@link BsonArray}
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.
👍
* @return a description of the updated fields and removed keys between | ||
* the documents | ||
*/ | ||
private static UpdateDescription diff(final BsonDocument thisDocument, |
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.
[test] I would make several more unit tests for this for various edge cases. Empty doc vs non empty doc, rray vs non array field, Deeply nested docs, etc.
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.
These were covered in the main unit test, but I should break it up into multiple tests.
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.
Broken up in the same test, but with numbering.
* @return a description of the updated fields and removed keys between | ||
* the documents | ||
*/ | ||
private static UpdateDescription diff(final BsonDocument thisDocument, |
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.
Instead of this and that, how about before and after?
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.
Could do– in the PoC, it was more general use case diffing. Since this is attached to UpdateDesc, I agree.
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.
👍
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.
looking pretty good. had some nits and q's but I think this will be LGTM once you address Eric's comments
// because they require more permissive Stitch rules. | ||
final BsonDocument update, | ||
final UpdateDescription update, | ||
final BsonDocument document, |
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.
[nit/not your code] this argument should be renamed to fullDocumentAfterUpdate
to make it clear that's what it is
} else { | ||
// ii. Otherwise, replace the local document with the resolved document locally, mark that | ||
// there are pending writes for this document, and emit a REPLACE change event. | ||
// there are pending writes for this document, and emit an UPDATE change event, or a |
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.
[nit] any changes you make to the comments with the the lettering/numbering should also be made to the spec document. we should try to keep the spec in sync with what the code is actually doing
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.
Noted.
logicalT, | ||
atVersion, | ||
event); | ||
event = changeEventForLocalUpdate( |
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.
[nit] I guess the proper name for this method would now be updateOrUpsertOneFromResolution
ctx.namespace, | ||
ctx.testDocumentId, | ||
ctx.updateDocument, | ||
ChangeEvent.UpdateDescription(BsonDocument("count", BsonInt32(2)), listOf()), |
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.
[nit] you reuse this exact update in a lot of places so maybe just set a testUpdateDescription
constant?
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.
Could, though for the purpose of test code, I think it's better to write in line. Though it's reused, it's fairly arbitrary, and throughout the test, the count can increase.
)) | ||
ctx.verifyConflictHandlerCalledForActiveDoc(1, expectedLocalEvent, | ||
ChangeEvent.changeEventForLocalUpdate(ctx.namespace, ctx.testDocumentId, ctx.updateDocument, ctx.testDocument, false)) | ||
ChangeEvent.changeEventForLocalUpdate(ctx.namespace, ctx.testDocumentId, null, ctx.testDocument, false)) |
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.
[q] what does a change event for a local update with a null UpdateDescription mean? is it a noop update? seems a little odd that this is something our code is producing
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 I see now that this is produced by our mock, but I think we should just have the mock produce a real update, because a local update change event with no actual things being updated seems like something that shouldn't actually exist
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.
Actually I think this is due to coalescence. I can add a note here that that is what this is testing.
ChangeEvent.changeEventForLocalDelete(ctx.namespace, ctx.testDocumentId, true), | ||
ChangeEvent.changeEventForLocalUpdate( | ||
ctx.namespace, ctx.testDocumentId, ctx.updateDocument, ctx.testDocument, false | ||
ctx.namespace, ctx.testDocumentId, null, ctx.testDocument, false |
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.
[ditto q] noop update
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.
See above
override fun queueConsumableRemoteUpdateEvent() { | ||
`when`(dataSynchronizer.getEventsForNamespace(any())).thenReturn( | ||
mapOf(testDocument to ChangeEvent.changeEventForLocalUpdate(namespace, testDocumentId, updateDocument, testDocument, false)), | ||
mapOf(testDocument to ChangeEvent.changeEventForLocalUpdate(namespace, testDocumentId, null, testDocument, false)), |
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.
[ditto q] noop update
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.
See above
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.
LGTM
See https://docs.google.com/document/d/1lvd02JFNI9Aa7Zely3xMJEct_N-HMn84tKIIhMq7Zes/ for more detailed information on the agreed design.