You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Follow-up to #5015 (ETag / If-None-Match support). To be done before the 9.18 release.
Problem
StreamOne<T> currently computes its ETag by, after the document JSON is already fetched and buffered:
deserializing the buffered JSON back into a T (session.Serializer.FromJson<T>(stream)), then
issuing a second DB round trip — IQuerySession.MetadataForAsync<T>(entity) — purely to read mt_version.
So with EmitETag = true (the default), every StreamOne request does two DB round trips instead of one, and a 304 saves only bandwidth — the document was already fetched. (This is unlike StreamAggregate, where FetchStreamStateAsync reads the version cheaply before the expensive fold, so a 304 skips real work.)
This second call is also the reason StreamOne<T>/WriteSingle<T> had to tighten to where T : notnull (because MetadataForAsync<T> is constrained notnull).
Goal
Fetch mt_versioninline with the document in the original single round trip — same idea as the count(*) OVER() as total_rows stats-column trick that #5014 uses — so:
StreamOne stays at one DB round trip with EmitETag = true on by default (which the maintainer has OK'd once this lands), and
the second MetadataForAsync call is removed entirely.
Sketch
Have the StreamOne streaming path select mt_version alongside the data column (extend the Marten core streaming query used by WriteSingle, analogous to how StatsSelectClause appends count(*) OVER()), and read the version off the same DbDataReader before/while streaming the body — no re-deserialization, no metadata query.
Guard the mt_version-disabled case: if the doc type has version metadata turned off, skip emitting an ETag rather than emitting a constant "00000000-…" (which would risk false 304s). Confirm what the inline read returns in that config.
Acceptance
StreamOne with EmitETag = true executes exactly one DB command (assert via command counting / query logging).
Version-metadata-disabled doc types emit no ETag (documented).
Also in scope for this follow-up (folded in from #5015 review)
Reverse the breaking constraint tightening.#5015 shipped where T : notnull on the public StreamOne<T> and WriteSingle<T> signatures — a source-compatibility break — solely because IQuerySession.MetadataForAsync<T> is constrained where T : notnull. Once this issue removes the MetadataForAsync call in favor of the inline mt_version read, that constraint is no longer needed and must be dropped from both StreamOne<T> and WriteSingle<T> to restore the pre-9.18 signature. (Loosening a constraint is non-breaking, and this ships before the 9.18 release, so the tightened form never reaches a release.)
Add the ETag test cases identified in review (additive; can land with this work or separately, but before release):
ETagHelpers unit coverage for the logic branches: * wildcard, W/ weak validator stripping, and multi-value comma-separated If-None-Match lists.
The 404 path (missing document for StreamOne, missing stream for StreamAggregate).
The version-metadata-disabled / no-version-column case → assert no ETag header is emitted (guards against a constant "00000000-…" ETag causing false 304s).
Follow-up to #5015 (ETag / If-None-Match support). To be done before the 9.18 release.
Problem
StreamOne<T>currently computes its ETag by, after the document JSON is already fetched and buffered:T(session.Serializer.FromJson<T>(stream)), thenIQuerySession.MetadataForAsync<T>(entity)— purely to readmt_version.So with
EmitETag = true(the default), everyStreamOnerequest does two DB round trips instead of one, and a304saves only bandwidth — the document was already fetched. (This is unlikeStreamAggregate, whereFetchStreamStateAsyncreads the version cheaply before the expensive fold, so a304skips real work.)This second call is also the reason
StreamOne<T>/WriteSingle<T>had to tighten towhere T : notnull(becauseMetadataForAsync<T>is constrainednotnull).Goal
Fetch
mt_versioninline with the document in the original single round trip — same idea as thecount(*) OVER() as total_rowsstats-column trick that #5014 uses — so:StreamOnestays at one DB round trip withEmitETag = trueon by default (which the maintainer has OK'd once this lands), andMetadataForAsynccall is removed entirely.Sketch
StreamOnestreaming path selectmt_versionalongside thedatacolumn (extend the Marten core streaming query used byWriteSingle, analogous to howStatsSelectClauseappendscount(*) OVER()), and read the version off the sameDbDataReaderbefore/while streaming the body — no re-deserialization, no metadata query.MetadataForAsync<T>, thewhere T : notnullconstraint on the publicStreamOne<T>/WriteSingle<T>signatures can be dropped cleanly (see the separate constraint-reversal that ships in feat: ETag / If-None-Match (304) support on StreamOne and StreamAggregate (fixes #5010) #5015 itself).mt_version-disabled case: if the doc type has version metadata turned off, skip emitting an ETag rather than emitting a constant"00000000-…"(which would risk false304s). Confirm what the inline read returns in that config.Acceptance
StreamOnewithEmitETag = trueexecutes exactly one DB command (assert via command counting / query logging).304/200semantics vs feat: ETag / If-None-Match (304) support on StreamOne and StreamAggregate (fixes #5010) #5015's tests.Also in scope for this follow-up (folded in from #5015 review)
Reverse the breaking constraint tightening. #5015 shipped
where T : notnullon the publicStreamOne<T>andWriteSingle<T>signatures — a source-compatibility break — solely becauseIQuerySession.MetadataForAsync<T>is constrainedwhere T : notnull. Once this issue removes theMetadataForAsynccall in favor of the inlinemt_versionread, that constraint is no longer needed and must be dropped from bothStreamOne<T>andWriteSingle<T>to restore the pre-9.18 signature. (Loosening a constraint is non-breaking, and this ships before the 9.18 release, so the tightened form never reaches a release.)Add the ETag test cases identified in review (additive; can land with this work or separately, but before release):
ETagHelpersunit coverage for the logic branches:*wildcard,W/weak validator stripping, and multi-value comma-separatedIf-None-Matchlists.404path (missing document forStreamOne, missing stream forStreamAggregate)."00000000-…"ETag causing false304s).