public Task Patch() { var returnContextToPool = ContextPool.AllocateOperationContext(out DocumentsOperationContext context); // we don't dispose this as operation is async var reader = context.Read(RequestBodyStream(), "queries/patch"); if (reader == null) { throw new BadRequestException("Missing JSON content."); } if (reader.TryGet("Query", out BlittableJsonReaderObject queryJson) == false || queryJson == null) { throw new BadRequestException("Missing 'Query' property."); } var query = IndexQueryServerSide.Create(queryJson, context, Database.QueryMetadataCache, QueryType.Update); var patch = new PatchRequest(query.Metadata.GetUpdateBody(query.QueryParameters), PatchRequestType.Patch); ExecuteQueryOperation(query, (runner, options, onProgress, token) => runner.ExecutePatchQuery( query, options, patch, query.QueryParameters, context, onProgress, token), context, returnContextToPool, Operations.Operations.OperationType.UpdateByIndex); return(Task.CompletedTask); }
public static PatchRequest Parse(BlittableJsonReaderObject input, out BlittableJsonReaderObject args) { if (input.TryGet("Script", out string script) == false || script == null) { throw new InvalidDataException("Missing 'Script' property on 'Patch'"); } // todo: maybe support receiving functions here? not sure, because this function is for single-document patches, which is not in RQL notation in the first place var patch = new PatchRequest(script, PatchRequestType.Patch); input.TryGet("Values", out args); return(patch); }
public Engine GetEngine(Func <PatchRequest, Engine> createEngine, PatchRequest request, string customFunctions) { CachedResult value; var patchRequestAndCustomFunctionsTuple = new ScriptedPatchRequestAndCustomFunctionsToken(request, customFunctions); if (_cache.TryGetValue(patchRequestAndCustomFunctionsTuple, out value)) { value.Usage++; return(value.Engine); } var result = createEngine(request); if (string.IsNullOrWhiteSpace(customFunctions) == false) { result.Execute(string.Format(@"var customFunctions = function() {{ var exports = {{ }}; {0}; return exports; }}(); for(var customFunction in customFunctions) {{ this[customFunction] = customFunctions[customFunction]; }};", customFunctions), new ParserOptions { Source = "customFunctions.js" }); } var cachedResult = new CachedResult { Usage = 1, Timestamp = SystemTime.UtcNow, Engine = result }; if (_cache.Count > CacheMaxSize) { foreach (var item in _cache.OrderBy(x => x.Value?.Usage) .ThenByDescending(x => x.Value?.Timestamp) .Take(CacheMaxSize / 10) .Select(source => source.Key) .ToList()) { _cache.Remove(item); } } _cache[patchRequestAndCustomFunctionsTuple] = cachedResult; return(result); }
public static PatchRequest Parse(BlittableJsonReaderObject input) { var patch = new PatchRequest(); if (input.TryGet("Script", out patch.Script) == false) { throw new InvalidDataException("Missing 'Script' property on 'Patch'"); } BlittableJsonReaderObject values; if (input.TryGet("Values", out values)) { patch.Values = values; } return(patch); }
public bool TryResolveConflict(DocumentsOperationContext context, PatchRequest patch, out BlittableJsonReaderObject resolved) { var run = new SingleScriptRun(this, context, patch, false); try { run.Prepare(_docsSize); SetupInputs(run.Scope, run.JintEngine); run.Execute(); return(TryParse(context, run.Scope, out resolved)); } catch (Exception errorEx) { run.HandleError(errorEx); throw; } }
private void PrepareEngine(PatchRequest patch, PatcherOperationScope scope, Engine jintEngine, int documentSize) { int totalScriptSteps = 0; if (documentSize != 0) { totalScriptSteps = maxSteps + (documentSize * additionalStepsPerSize); jintEngine.Options.MaxStatements(totalScriptSteps); } jintEngine.Global.Delete("LoadDocument", false); jintEngine.Global.Delete("IncreaseNumberOfAllowedStepsBy", false); CustomizeEngine(jintEngine, scope); jintEngine.SetValue("LoadDocument", (Func <string, JsValue>)(key => scope.LoadDocument(key, jintEngine, ref totalScriptSteps))); jintEngine.SetValue("IncreaseNumberOfAllowedStepsBy", (Action <int>)(number => { if (allowScriptsToAdjustNumberOfSteps == false) { throw new InvalidOperationException("Cannot use 'IncreaseNumberOfAllowedStepsBy' method, because `Raven/AllowScriptsToAdjustNumberOfSteps` is set to false."); } scope.MaxSteps += number; totalScriptSteps += number; jintEngine.Options.MaxStatements(totalScriptSteps); })); if (patch.Values != null) { var prop = new BlittableJsonReaderObject.PropertyDetails(); for (int i = 0; i < patch.Values.Count; i++) { patch.Values.GetPropertyByIndex(i, ref prop); jintEngine.SetValue(prop.Name, scope.ToJsValue(jintEngine, prop.Value, prop.Token)); } } jintEngine.ResetStatementsCount(); }
protected bool Equals(PatchRequest other) { if ((string.Equals(Script, other.Script) && Type == other.Type) == false) { return(false); } if (_functions != null) { foreach (var function in _functions) { if (other._functions.TryGetValue(function.Key, out var otherVal) == false || function.Value.FunctionText != otherVal.FunctionText) { return(false); } } } return(true); }
public async Task Patch() { var queryContext = QueryOperationContext.Allocate(Database); // we don't dispose this as operation is async try { var reader = await queryContext.Documents.ReadForMemoryAsync(RequestBodyStream(), "queries/patch"); if (reader == null) { throw new BadRequestException("Missing JSON content."); } if (reader.TryGet("Query", out BlittableJsonReaderObject queryJson) == false || queryJson == null) { throw new BadRequestException("Missing 'Query' property."); } var query = IndexQueryServerSide.Create(HttpContext, queryJson, Database.QueryMetadataCache, null, queryType: QueryType.Update); query.DisableAutoIndexCreation = GetBoolValueQueryString("disableAutoIndexCreation", false) ?? false; if (TrafficWatchManager.HasRegisteredClients) { TrafficWatchQuery(query); } var patch = new PatchRequest(query.Metadata.GetUpdateBody(query.QueryParameters), PatchRequestType.Patch, query.Metadata.DeclaredFunctions); await ExecuteQueryOperation(query, (runner, options, onProgress, token) => runner.ExecutePatchQuery( query, options, patch, query.QueryParameters, queryContext, onProgress, token), queryContext, Operations.Operations.OperationType.UpdateByQuery); } catch { queryContext.Dispose(); throw; } }
public async Task <ImportResult> Import(DocumentsOperationContext context, Stream stream, Action <IOperationProgress> onProgress = null) { var result = new ImportResult(); var progress = new IndeterminateProgress(); var state = new JsonParserState(); JsonOperationContext.ManagedPinnedBuffer buffer; using (context.GetManagedBuffer(out buffer)) using (var parser = new UnmanagedJsonParser(context, state, "fileName")) { var operateOnType = "__top_start_object"; var buildVersion = 0L; var identities = new Dictionary <string, long>(); VersioningStorage versioningStorage = null; while (true) { if (parser.Read() == false) { var read = await stream.ReadAsync(buffer.Buffer.Array, buffer.Buffer.Offset, buffer.Length); if (read == 0) { if (state.CurrentTokenType != JsonParserToken.EndObject) { throw new EndOfStreamException("Stream ended without reaching end of json content"); } break; } parser.SetBuffer(buffer, read); continue; } switch (state.CurrentTokenType) { case JsonParserToken.String: unsafe { operateOnType = new LazyStringValue(null, state.StringBuffer, state.StringSize, context).ToString(); } break; case JsonParserToken.Integer: switch (operateOnType) { case "BuildVersion": buildVersion = state.Long; break; } break; case JsonParserToken.StartObject: if (operateOnType == "__top_start_object") { operateOnType = null; break; } context.CachedProperties.NewDocument(); var builder = new BlittableJsonDocumentBuilder(_batchPutCommand.Context, BlittableJsonDocumentBuilder.UsageMode.ToDisk, "ImportObject", parser, state); builder.ReadNestedObject(); while (builder.Read() == false) { var read = await stream.ReadAsync(buffer.Buffer.Array, buffer.Buffer.Offset, buffer.Length); if (read == 0) { throw new EndOfStreamException("Stream ended without reaching end of json content"); } parser.SetBuffer(buffer, read); } builder.FinalizeDocument(); if (operateOnType == "Docs" && Options.OperateOnTypes.HasFlag(DatabaseItemType.Documents)) { progress.Progress = "Importing Documents"; onProgress?.Invoke(progress); PatchDocument patch = null; PatchRequest patchRequest = null; if (string.IsNullOrWhiteSpace(Options.TransformScript) == false) { patch = new PatchDocument(context.DocumentDatabase); patchRequest = new PatchRequest { Script = Options.TransformScript }; } result.DocumentsCount++; var reader = builder.CreateReader(); var document = new Document { Data = reader, }; if (Options.IncludeExpired == false && document.Expired(_database.Time.GetUtcNow())) { continue; } TransformScriptOrDisableVersioningIfNeeded(context, patch, reader, document, patchRequest); _batchPutCommand.Add(document.Data); if (result.DocumentsCount % 1000 == 0) { progress.Progress = $"Imported {result.DocumentsCount} documents"; onProgress?.Invoke(progress); } await HandleBatchOfDocuments(context, parser, buildVersion).ConfigureAwait(false); } else if (operateOnType == "RevisionDocuments" && Options.OperateOnTypes.HasFlag(DatabaseItemType.RevisionDocuments)) { if (versioningStorage == null) { break; } result.RevisionDocumentsCount++; var reader = builder.CreateReader(); _batchPutCommand.Add(reader); await HandleBatchOfDocuments(context, parser, buildVersion).ConfigureAwait(false);; } else { using (builder) { switch (operateOnType) { case "Attachments": result.Warnings.Add("Attachments are not supported anymore. Use RavenFS isntead. Skipping."); break; case "Indexes": if (Options.OperateOnTypes.HasFlag(DatabaseItemType.Indexes) == false) { continue; } result.IndexesCount++; progress.Progress = "importing Indexes"; onProgress?.Invoke(progress); try { IndexProcessor.Import(builder, _database, buildVersion, Options.RemoveAnalyzers); } catch (Exception e) { result.Warnings.Add($"Could not import index. Message: {e.Message}"); } break; case "Transformers": if (Options.OperateOnTypes.HasFlag(DatabaseItemType.Transformers) == false) { continue; } result.TransformersCount++; progress.Progress = "Importing Transformers"; onProgress?.Invoke(progress); try { TransformerProcessor.Import(builder, _database, buildVersion); } catch (Exception e) { result.Warnings.Add($"Could not import transformer. Message: {e.Message}"); } break; case "Identities": if (Options.OperateOnTypes.HasFlag(DatabaseItemType.Identities)) { result.IdentitiesCount++; progress.Progress = "Importing Identities"; onProgress?.Invoke(progress); using (var reader = builder.CreateReader()) { try { string identityKey, identityValueString; long identityValue; if (reader.TryGet("Key", out identityKey) == false || reader.TryGet("Value", out identityValueString) == false || long.TryParse(identityValueString, out identityValue) == false) { result.Warnings.Add($"Cannot import the following identity: '{reader}'. Skipping."); } else { identities[identityKey] = identityValue; } } catch (Exception e) { result.Warnings.Add($"Cannot import the following identity: '{reader}'. Error: {e}. Skipping."); } } } break; default: result.Warnings.Add( $"The following type is not recognized: '{operateOnType}'. Skipping."); break; } } } break; case JsonParserToken.StartArray: switch (operateOnType) { case "RevisionDocuments": // We are taking a reference here since the documents import can activate or disable the versioning. // We hold a local copy because the user can disable the bundle during the import process, exteranly. // In this case we want to continue to import the revisions documents. versioningStorage = _database.BundleLoader.VersioningStorage; _batchPutCommand.IsRevision = true; break; } break; case JsonParserToken.EndArray: switch (operateOnType) { case "Docs": await FinishBatchOfDocuments(); _batchPutCommand = new MergedBatchPutCommand(_database, buildVersion); break; case "RevisionDocuments": await FinishBatchOfDocuments(); break; case "Identities": if (identities.Count > 0) { using (var tx = context.OpenWriteTransaction()) { _database.DocumentsStorage.UpdateIdentities(context, identities); tx.Commit(); } } identities = null; break; } break; } } } return(result); }
private void TransformScriptOrDisableVersioningIfNeeded(DocumentsOperationContext context, PatchDocument patch, BlittableJsonReaderObject reader, Document document, PatchRequest patchRequest) { if (patch == null && Options.DisableVersioningBundle == false) { return; } BlittableJsonReaderObject newMetadata; reader.TryGet(Constants.Metadata.Key, out newMetadata); if (patch != null) { LazyStringValue key; if (newMetadata != null) { if (newMetadata.TryGet(Constants.Metadata.Id, out key)) { document.Key = key; } } var patchResult = patch.Apply(context, document, patchRequest); if (patchResult != null && patchResult.ModifiedDocument.Equals(document.Data) == false) { document.Data = patchResult.ModifiedDocument; } } if (Options.DisableVersioningBundle == false || newMetadata == null) { return; } newMetadata.Modifications = new DynamicJsonValue(newMetadata) { [Constants.Versioning.RavenDisableVersioning] = false }; }
public Task <IOperationResult> ExecutePatch(string collectionName, long start, long take, CollectionOperationOptions options, PatchRequest patch, BlittableJsonReaderObject patchArgs, Action <IOperationProgress> onProgress, OperationCancelToken token) { return(ExecuteOperation(collectionName, start, take, options, Context, onProgress, key => new PatchDocumentCommand(Context, key, expectedChangeVector: null, skipPatchIfChangeVectorMismatch: false, patch: (patch, patchArgs), patchIfMissing: (null, null), createIfMissing: null, Database, isTest: false, debugMode: false, collectResultsNeeded: false, returnDocument: false), token)); }
public Task <IOperationResult> ExecutePatch(string collectionName, CollectionOperationOptions options, PatchRequest patch, BlittableJsonReaderObject patchArgs, Action <IOperationProgress> onProgress, OperationCancelToken token) { return(ExecuteOperation(collectionName, options, Context, onProgress, key => new PatchDocumentCommand(Context, key, null, false, (patch, patchArgs), (null, null), Database, false, false), token)); }
public ExportResult Export(DocumentsOperationContext context, Stream destinationStream, Action <IOperationProgress> onProgress = null) { var result = new ExportResult(); var progress = new IndeterminateProgress(); using (var gZipStream = new GZipStream(destinationStream, CompressionMode.Compress, leaveOpen: true)) using (var writer = new BlittableJsonTextWriter(context, gZipStream)) { writer.WriteStartObject(); writer.WritePropertyName(("BuildVersion")); writer.WriteInteger(40000); if (Options.OperateOnTypes.HasFlag(DatabaseItemType.Documents)) { progress.Progress = "Exporting Documents"; onProgress?.Invoke(progress); writer.WriteComma(); writer.WritePropertyName(("Docs")); IEnumerable <Document> documents = Options.CollectionsToExport.Count != 0 ? _database.DocumentsStorage.GetDocumentsFrom(context, Options.CollectionsToExport, StartDocsEtag ?? 0, int.MaxValue) : _database.DocumentsStorage.GetDocumentsFrom(context, StartDocsEtag ?? 0, 0, int.MaxValue); writer.WriteStartArray(); PatchDocument patch = null; PatchRequest patchRequest = null; if (string.IsNullOrWhiteSpace(Options.TransformScript) == false) { patch = new PatchDocument(context.DocumentDatabase); patchRequest = new PatchRequest { Script = Options.TransformScript }; } bool first = true; foreach (var document in documents) { if (document == null) { continue; } if (Options.IncludeExpired == false && document.Expired(_database.Time.GetUtcNow())) { continue; } var patchResult = patch?.Apply(context, document, patchRequest); if (patchResult != null && patchResult.ModifiedDocument.Equals(document.Data) == false) { document.Data = patchResult.ModifiedDocument; } using (document.Data) { if (first == false) { writer.WriteComma(); } first = false; document.EnsureMetadata(); context.Write(writer, document.Data); result.LastDocsEtag = document.Etag; } result.ExportedDocuments++; } writer.WriteEndArray(); } if (Options.OperateOnTypes.HasFlag(DatabaseItemType.RevisionDocuments)) { var versioningStorage = _database.BundleLoader.VersioningStorage; if (versioningStorage != null) { writer.WriteComma(); writer.WritePropertyName("RevisionDocuments"); writer.WriteStartArray(); var first = true; var revisionDocuments = Options.RevisionDocumentsLimit.HasValue ? versioningStorage.GetRevisionsAfter(context, StartRevisionDocumentsEtag ?? 0, Options.RevisionDocumentsLimit.Value) : versioningStorage.GetRevisionsAfter(context, StartRevisionDocumentsEtag ?? 0); foreach (var revisionDocument in revisionDocuments) { if (revisionDocument == null) { continue; } using (revisionDocument.Data) { if (first == false) { writer.WriteComma(); } first = false; revisionDocument.EnsureMetadata(); context.Write(writer, revisionDocument.Data); result.LastRevisionDocumentsEtag = revisionDocument.Etag; } } writer.WriteEndArray(); } } if (Options.OperateOnTypes.HasFlag(DatabaseItemType.Indexes)) { progress.Progress = "Exporting Indexes"; onProgress?.Invoke(progress); writer.WriteComma(); writer.WritePropertyName("Indexes"); writer.WriteStartArray(); var isFirst = true; foreach (var index in _database.IndexStore.GetIndexes()) { if (isFirst == false) { writer.WriteComma(); } isFirst = false; IndexProcessor.Export(writer, index, context, Options.RemoveAnalyzers); } writer.WriteEndArray(); } if (Options.OperateOnTypes.HasFlag(DatabaseItemType.Transformers)) { progress.Progress = "Exporting Transformers"; onProgress?.Invoke(progress); writer.WriteComma(); writer.WritePropertyName(("Transformers")); writer.WriteStartArray(); var isFirst = true; foreach (var transformer in _database.TransformerStore.GetTransformers()) { if (isFirst == false) { writer.WriteComma(); } isFirst = false; TransformerProcessor.Export(writer, transformer, context); } writer.WriteEndArray(); } if (Options.OperateOnTypes.HasFlag(DatabaseItemType.Identities)) { progress.Progress = "Exporting Identities"; onProgress?.Invoke(progress); writer.WriteComma(); writer.WritePropertyName(("Identities")); writer.WriteStartArray(); var identities = _database.DocumentsStorage.GetIdentities(context); var first = true; foreach (var identity in identities) { if (first == false) { writer.WriteComma(); } first = false; writer.WriteStartObject(); writer.WritePropertyName(("Key")); writer.WriteString((identity.Key)); writer.WriteComma(); writer.WritePropertyName(("Value")); writer.WriteString((identity.Value.ToString())); writer.WriteEndObject(); } writer.WriteEndArray(); } writer.WriteEndObject(); progress.Progress = $"Finish Exported database to {Options.FileName}. Exported {result.ExportedDocuments}"; onProgress?.Invoke(progress); } return(result); }
protected bool Equals(PatchRequest other) { return(string.Equals(Script, other.Script) && Type == other.Type); }
public Task PatchTest() { using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context)) { var reader = context.Read(RequestBodyStream(), "queries/patch"); if (reader == null) { throw new BadRequestException("Missing JSON content."); } if (reader.TryGet("Query", out BlittableJsonReaderObject queryJson) == false || queryJson == null) { throw new BadRequestException("Missing 'Query' property."); } var query = IndexQueryServerSide.Create(queryJson, context, Database.QueryMetadataCache, QueryType.Update); var patch = new PatchRequest(query.Metadata.GetUpdateBody(), PatchRequestType.Patch); var whereValueToken = (query.Metadata?.Query?.Where?.Arguments[0] as QueryExpression)?.Value; if (whereValueToken == null) { HttpContext.Response.StatusCode = (int)HttpStatusCode.BadRequest; return(Task.CompletedTask); } var docId = QueryExpression.Extract(query.Metadata.QueryText, whereValueToken, stripQuotes: true); PatchDocumentCommand command; if (query.Metadata.IsDynamic == false) { command = new PatchDocumentCommand(context, docId, expectedChangeVector: null, skipPatchIfChangeVectorMismatch: false, patch: (patch, query.QueryParameters), patchIfMissing: (null, null), database: context.DocumentDatabase, debugMode: true, isTest: true); } else { command = new PatchDocumentCommand(context, docId, null, false, (patch, query.QueryParameters), (null, null), Database, true, true); } using (context.OpenWriteTransaction()) { command.Execute(context); } switch (command.PatchResult.Status) { case PatchStatus.DocumentDoesNotExist: HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; return(Task.CompletedTask); case PatchStatus.Created: HttpContext.Response.StatusCode = (int)HttpStatusCode.Created; break; case PatchStatus.Skipped: HttpContext.Response.StatusCode = (int)HttpStatusCode.NotModified; return(Task.CompletedTask); case PatchStatus.Patched: case PatchStatus.NotModified: HttpContext.Response.StatusCode = (int)HttpStatusCode.OK; break; default: throw new ArgumentOutOfRangeException(); } WritePatchResultToResponse(context, command); return(Task.CompletedTask); } }
public ScriptedPatchRequestAndCustomFunctionsToken(PatchRequest request, string customFunctions) { this.request = request; this.customFunctions = customFunctions; }
public virtual PatchResultData Apply(DocumentsOperationContext context, Document document, PatchRequest patch) { if (document == null) { return(null); } if (string.IsNullOrEmpty(patch.Script)) { throw new InvalidOperationException("Patch script must be non-null and not empty"); } var scope = ApplySingleScript(context, document, false, patch); var modifiedDocument = context.ReadObject(scope.ToBlittable(scope.PatchObject.AsObject()), document.Key); /* TODO: Should not use BlittableJsonDocumentBuilder.UsageMode.ToDisk? */ return(new PatchResultData { ModifiedDocument = modifiedDocument ?? document.Data, DebugInfo = scope.DebugInfo, }); }
public abstract Task <IOperationResult> ExecutePatchQuery(IndexQueryServerSide query, QueryOperationOptions options, PatchRequest patch, BlittableJsonReaderObject patchArgs, DocumentsOperationContext context, Action <IOperationProgress> onProgress, OperationCancelToken token);
protected PatcherOperationScope ApplySingleScript(DocumentsOperationContext context, Document document, bool isTestOnly, PatchRequest patch) { var run = new SingleScriptRun(this, context, patch, isTestOnly); try { run.Prepare(document?.Data?.Size ?? 0); SetupInputs(document, run.Scope, run.JintEngine); run.Execute(); return(run.Scope); } catch (Exception errorEx) { run.HandleError(errorEx); throw; } }
protected Task <IOperationResult> ExecutePatch(IndexQueryServerSide query, Index index, QueryOperationOptions options, PatchRequest patch, BlittableJsonReaderObject patchArgs, DocumentsOperationContext context, Action <DeterminateProgress> onProgress, OperationCancelToken token) { return(ExecuteOperation(query, index, options, context, onProgress, (key, retrieveDetails) => { var command = new PatchDocumentCommand(context, key, expectedChangeVector: null, skipPatchIfChangeVectorMismatch: false, patch: (patch, patchArgs), patchIfMissing: (null, null), database: Database, debugMode: false, isTest: false, collectResultsNeeded: true); return new BulkOperationCommand <PatchDocumentCommand>(command, retrieveDetails, x => new BulkOperationResult.PatchDetails { Id = key, ChangeVector = x.PatchResult.ChangeVector, Status = x.PatchResult.Status }); }, token));
public unsafe PatchResultData Apply(DocumentsOperationContext context, string documentKey, long?etag, PatchRequest patch, PatchRequest patchIfMissing, bool isTestOnly = false, bool skipPatchIfEtagMismatch = false) { var document = _database.DocumentsStorage.Get(context, documentKey); if (_logger.IsInfoEnabled) { _logger.Info(string.Format("Preparing to apply patch on ({0}). Document found?: {1}.", documentKey, document != null)); } if (etag.HasValue && document != null && document.Etag != etag.Value) { System.Diagnostics.Debug.Assert(document.Etag > 0); if (skipPatchIfEtagMismatch) { return(new PatchResultData { PatchResult = PatchResult.Skipped }); } if (_logger.IsInfoEnabled) { _logger.Info($"Got concurrent exception while tried to patch the following document: {documentKey}"); } throw new ConcurrencyException($"Could not patch document '{documentKey}' because non current etag was used") { ActualETag = document.Etag, ExpectedETag = etag.Value, }; } var patchRequest = patch; if (document == null) { if (patchIfMissing == null) { if (_logger.IsInfoEnabled) { _logger.Info("Tried to patch a not exists document and patchIfMissing is null"); } return(new PatchResultData { PatchResult = PatchResult.DocumentDoesNotExists }); } patchRequest = patchIfMissing; } var scope = ApplySingleScript(context, document, isTestOnly, patchRequest); var modifiedDocument = context.ReadObject(scope.ToBlittable(scope.PatchObject.AsObject()), documentKey, BlittableJsonDocumentBuilder.UsageMode.ToDisk); var result = new PatchResultData { PatchResult = PatchResult.NotModified, OriginalDocument = document?.Data, DebugInfo = scope.DebugInfo, }; if (modifiedDocument == null) { if (_logger.IsInfoEnabled) { _logger.Info($"After applying patch, modifiedDocument is null and document is null? {document == null}"); } result.PatchResult = PatchResult.Skipped; return(result); } if (isTestOnly) { return(new PatchResultData { PatchResult = PatchResult.Tested, OriginalDocument = document?.Data, ModifiedDocument = modifiedDocument, DebugActions = scope.DebugActions.GetDebugActions(), DebugInfo = scope.DebugInfo, }); } var putResult = new DocumentsStorage.PutOperationResults(); if (document == null) { putResult = _database.DocumentsStorage.Put(context, documentKey, null, modifiedDocument); } else { var isModified = document.Data.Size != modifiedDocument.Size; if (isModified == false) // optimization, if size different, no need to compute hash to check { var originHash = Hashing.XXHash64.Calculate(document.Data.BasePointer, (ulong)document.Data.Size); var modifiedHash = Hashing.XXHash64.Calculate(modifiedDocument.BasePointer, (ulong)modifiedDocument.Size); isModified = originHash != modifiedHash; } if (isModified) { putResult = _database.DocumentsStorage.Put(context, document.Key, document.Etag, modifiedDocument); result.PatchResult = PatchResult.Patched; } } if (putResult.Etag != 0) { result.Etag = putResult.Etag; result.Collection = putResult.Collection; } return(result); }
public Task PatchTest() { using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context)) { var reader = context.Read(RequestBodyStream(), "queries/patch"); if (reader == null) { throw new BadRequestException("Missing JSON content."); } if (reader.TryGet("Query", out BlittableJsonReaderObject queryJson) == false || queryJson == null) { throw new BadRequestException("Missing 'Query' property."); } var query = IndexQueryServerSide.Create(HttpContext, queryJson, Database.QueryMetadataCache, null, QueryType.Update); if (TrafficWatchManager.HasRegisteredClients) { TrafficWatchQuery(query); } var patch = new PatchRequest(query.Metadata.GetUpdateBody(query.QueryParameters), PatchRequestType.Patch, query.Metadata.DeclaredFunctions); var docId = GetQueryStringValueAndAssertIfSingleAndNotEmpty("id"); var command = new PatchDocumentCommand(context, docId, expectedChangeVector: null, skipPatchIfChangeVectorMismatch: false, patch: (patch, query.QueryParameters), patchIfMissing: (null, null), database: context.DocumentDatabase, debugMode: true, isTest: true, collectResultsNeeded: true, returnDocument: false); using (context.OpenWriteTransaction()) { command.Execute(context, null); } switch (command.PatchResult.Status) { case PatchStatus.DocumentDoesNotExist: HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; return(Task.CompletedTask); case PatchStatus.Created: HttpContext.Response.StatusCode = (int)HttpStatusCode.Created; break; case PatchStatus.Skipped: HttpContext.Response.StatusCode = (int)HttpStatusCode.NotModified; return(Task.CompletedTask); case PatchStatus.Patched: case PatchStatus.NotModified: HttpContext.Response.StatusCode = (int)HttpStatusCode.OK; break; default: throw new ArgumentOutOfRangeException(); } WritePatchResultToResponse(context, command); return(Task.CompletedTask); } }
public override Task <IOperationResult> ExecutePatchQuery(IndexQueryServerSide query, QueryOperationOptions options, PatchRequest patch, BlittableJsonReaderObject patchArgs, DocumentsOperationContext context, Action <IOperationProgress> onProgress, OperationCancelToken token) { return(GetRunner(query).ExecutePatchQuery(query, options, patch, patchArgs, context, onProgress, token)); }
public async Task Patch() { var id = GetQueryStringValueAndAssertIfSingleAndNotEmpty("id"); var isTest = GetBoolValueQueryString("test", required: false) ?? false; var debugMode = GetBoolValueQueryString("debug", required: false) ?? isTest; var skipPatchIfChangeVectorMismatch = GetBoolValueQueryString("skipPatchIfChangeVectorMismatch", required: false) ?? false; using (ContextPool.AllocateOperationContext(out DocumentsOperationContext context)) { var request = context.Read(RequestBodyStream(), "ScriptedPatchRequest"); if (request.TryGet("Patch", out BlittableJsonReaderObject patchCmd) == false || patchCmd == null) { throw new ArgumentException("The 'Patch' field in the body request is mandatory"); } var patch = PatchRequest.Parse(patchCmd, out var patchArgs); PatchRequest patchIfMissing = null; BlittableJsonReaderObject patchIfMissingArgs = null; if (request.TryGet("PatchIfMissing", out BlittableJsonReaderObject patchIfMissingCmd) && patchIfMissingCmd != null) { patchIfMissing = PatchRequest.Parse(patchIfMissingCmd, out patchIfMissingArgs); } var changeVector = context.GetLazyString(GetStringFromHeaders("If-Match")); var command = new PatchDocumentCommand(context, id, changeVector, skipPatchIfChangeVectorMismatch, (patch, patchArgs), (patchIfMissing, patchIfMissingArgs), Database, isTest, debugMode, true, returnDocument: false ); if (isTest == false) { await Database.TxMerger.Enqueue(command); } else { // PutDocument requires the write access to the docs storage // testing patching is rare enough not to optimize it using (context.OpenWriteTransaction()) { command.Execute(context, null); } } switch (command.PatchResult.Status) { case PatchStatus.DocumentDoesNotExist: HttpContext.Response.StatusCode = (int)HttpStatusCode.NotFound; return; case PatchStatus.Created: HttpContext.Response.StatusCode = (int)HttpStatusCode.Created; break; case PatchStatus.Skipped: HttpContext.Response.StatusCode = (int)HttpStatusCode.NotModified; return; case PatchStatus.Patched: case PatchStatus.NotModified: HttpContext.Response.StatusCode = (int)HttpStatusCode.OK; break; default: throw new ArgumentOutOfRangeException(); } using (var writer = new BlittableJsonTextWriter(context, ResponseBodyStream())) { writer.WriteStartObject(); writer.WritePropertyName(nameof(command.PatchResult.Status)); writer.WriteString(command.PatchResult.Status.ToString()); writer.WriteComma(); writer.WritePropertyName(nameof(command.PatchResult.ModifiedDocument)); writer.WriteObject(command.PatchResult.ModifiedDocument); if (debugMode) { writer.WriteComma(); writer.WritePropertyName(nameof(command.PatchResult.OriginalDocument)); if (isTest) { writer.WriteObject(command.PatchResult.OriginalDocument); } else { writer.WriteNull(); } writer.WriteComma(); writer.WritePropertyName(nameof(command.PatchResult.Debug)); context.Write(writer, new DynamicJsonValue { ["Info"] = new DynamicJsonArray(command.DebugOutput), ["Actions"] = command.DebugActions }); } switch (command.PatchResult.Status) { case PatchStatus.Created: case PatchStatus.Patched: writer.WriteComma(); writer.WritePropertyName(nameof(command.PatchResult.LastModified)); writer.WriteString(command.PatchResult.LastModified.GetDefaultRavenFormat(isUtc: command.PatchResult.LastModified.Kind == DateTimeKind.Utc)); writer.WriteComma(); writer.WritePropertyName(nameof(command.PatchResult.ChangeVector)); writer.WriteString(command.PatchResult.ChangeVector); writer.WriteComma(); writer.WritePropertyName(nameof(command.PatchResult.Collection)); writer.WriteString(command.PatchResult.Collection); break; } writer.WriteEndObject(); } } }
public SingleScriptRun(PatchDocument parent, DocumentsOperationContext context, PatchRequest patch, bool isTestOnly) { _parent = parent; _patch = patch; Scope = new PatcherOperationScope(parent._database, context, isTestOnly) { AdditionalStepsPerSize = parent.additionalStepsPerSize, MaxSteps = parent.maxSteps, }; try { JintEngine = ScriptsCache.GetEngine(parent.CreateEngine, patch, Scope.CustomFunctions); } catch (NotSupportedException e) { throw new ParseException("Could not parse script", e); } catch (JavaScriptException e) { throw new ParseException("Could not parse script", e); } catch (Exception e) { throw new ParseException("Could not parse: " + Environment.NewLine + patch.Script, e); } }