Last active
May 22, 2020 09:10
-
-
Save ayende/41327791cd1d09d56eca13d2f935a4e5 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
public static class SessionExtensions | |
{ | |
public static async Task<(T Entity, string ChangeVector)?> ConditionalLoadAsync<T>(this IAsyncDocumentSession session, | |
string id, string changeVector, CancellationToken token = default) | |
{ | |
if (session.Advanced.IsLoaded(id)) | |
{ | |
var e = await session.LoadAsync<T>(id, token); | |
var cv = session.Advanced.GetChangeVectorFor(e); | |
return (e, cv); | |
} | |
var cmd = new ConditionalGetDocumentCommand(id, changeVector); | |
await session.Advanced.RequestExecutor.ExecuteAsync(cmd, session.Advanced.Context, null, token); | |
switch (cmd.StatusCode) | |
{ | |
case HttpStatusCode.NotModified: | |
return default; // value not changed | |
case HttpStatusCode.NotFound: | |
return (default, default); // value is missing | |
} | |
if (cmd.Result.Results.Length == 0) | |
return (default, cmd.Result.ChangeVector); | |
var documentInfo = DocumentInfo.GetNewDocumentInfo((BlittableJsonReaderObject)cmd.Result.Results[0]); | |
var r = ((InMemoryDocumentSessionOperations)session).TrackEntity<T>(documentInfo); | |
return (r, cmd.Result.ChangeVector); | |
} | |
public class ConditionalGetResult | |
{ | |
public BlittableJsonReaderArray Results { get; set; } | |
public string ChangeVector; | |
} | |
public class ConditionalGetDocumentCommand : RavenCommand<ConditionalGetResult> | |
{ | |
private readonly string _changeVector; | |
private readonly string _id; | |
/// <summary> | |
/// Here we explicitly do _NOT_ want to have caching | |
/// by the Request Executer, we want to manage it ourselves | |
/// </summary> | |
public override bool IsReadRequest => false; | |
public ConditionalGetDocumentCommand(string id, string changeVector) | |
{ | |
_changeVector = changeVector; | |
_id = id; | |
} | |
public override async Task<ResponseDisposeHandling> ProcessResponse(JsonOperationContext context, HttpCache cache, HttpResponseMessage response, string url) | |
{ | |
if(response.StatusCode== HttpStatusCode.NotModified) | |
return ResponseDisposeHandling.Automatic; | |
var result = await base.ProcessResponse(context, cache, response, url); | |
Result.ChangeVector = response.Headers.ETag.Tag; | |
return result; | |
} | |
public class Deserialize : JsonDeserializationBase | |
{ | |
public static Func<BlittableJsonReaderObject, ConditionalGetResult> ConditionalGet = GenerateJsonDeserializationRoutine<ConditionalGetResult>(); | |
} | |
public override void SetResponse(JsonOperationContext context, BlittableJsonReaderObject response, bool fromCache) | |
{ | |
if (response == null) | |
{ | |
Result = null; | |
return; | |
} | |
if (fromCache) | |
{ | |
// we have to clone the response here because otherwise the cached item might be freed while | |
// we are still looking at this result, so we clone it to the side | |
response = response.Clone(context); | |
} | |
Result = Deserialize.ConditionalGet(response); | |
} | |
public override HttpRequestMessage CreateRequest(JsonOperationContext ctx, ServerNode node, out string url) | |
{ | |
var pathBuilder = new StringBuilder(node.Url); | |
pathBuilder.Append("/databases/") | |
.Append(node.Database) | |
.Append("/docs?") | |
.Append("&id=").Append(Uri.EscapeDataString(_id)); | |
var request = new HttpRequestMessage | |
{ | |
Method = HttpMethod.Get | |
}; | |
request.Headers.Add("If-None-Match", '"' + _changeVector + '"'); | |
url = pathBuilder.ToString(); | |
return request; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
FYI,
This will throw a NRE if there is no document found. I'd suggest a case to handle
HttpStatusCode.NotFound
around line 17, although a different return value may be needed so the client code can distinguish between 304 and 404.Also line 95 needs to escape the change vector otherwise a
FormatException
will occur.Should be something like: