Description
Currently, all multi-lookup operations pass through the transcoder to deserialize. However, multi-mutate operations skip the transcoder and go directly to the serializer. This is fine for JSON content, but means that content such as a byte array meant to be written raw is serialized by the JSON serializer. It will then fail to read when performing a multi-lookup "GetFull" operation because that does pass through the transcoder's Decode<T> method.
When working with true sub-document operations, this is probably fine. You are clearly working with JSON if you're setting a property on a JSON document. However, sub-doc operations are also used for getting/settings XATTRs. This bug means that there is no way to set a byte-array document with XATTRs as a single operation, it would require one traditional SET operation followed by a separate operation to set the XATTRs.
Additionally, the handling is also inconsistent on nested properties. In this case, the multi-mutate operation is correctly assuming that everything should be serialized as JSON, but the multi-lookup is out of sync because it always uses the Transcoder not just the JSON serializer.
Repro:
var transcoder = new LegacyTranscoder(new DefaultSerializer()); |
|
var mutateInSpecs = new List<MutateInSpec>(2) |
{
|
MutateInSpec.SetDoc(new byte[] { 1, 2, 3, 4 }); |
MutateInSpec.Upsert("test_attr", "foo", isXattr: true); |
};
|
|
var mutateInOptions = new MutateInOptions() |
.Transcoder(transcoder)
|
.StoreSemantics(StoreSemantics.Upsert);
|
|
await collection.MutateInAsync("key", mutateInSpecs , mutateInOptions); |
|
var lookupInSpecs = new List<LookupInSpecs>(2) |
{
|
builder.GetFull();
|
LookupInSpec.Get("test_attr", isXattr: true); |
};
|
|
var lookupInOptions = new LookupInOptions() |
.Transcoder(transcoder);
|
|
var result = await collection.LookupInAsync("key", lookupInSpecs, lookupInOptions); |
|
// Fails with an exception because the JSON serializer encoded as a Base64 string,
|
// but we're decoding as a byte array currently
|
var bytes = result.ContentAs<byte[]>(0); |
|
// Fails because "foo" was serialized as a JSON string, with wrapping quotes, but
|
// the deserializer is passing through the LegacyTranscoder which expects raw strings
|
// It seems like gets with a path shouldn't pass through the transcoder.
|
Assert.Equal("foo", result.ContentAs<string>(1)); |
Attachments
Gerrit Reviews
For Gerrit Dashboard: NCBC-3590 | ||||||
---|---|---|---|---|---|---|
# | Subject | Branch | Project | Status | CR | V |
202712,4 | NCBC-3590: Ensure consistent transcoding of sub-doc operations | master | couchbase-net-client | Status: MERGED | +2 | +1 |