Esempio n. 1
0
        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);
        }
Esempio n. 2
0
        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);
        }
Esempio n. 3
0
        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);
        }
Esempio n. 4
0
        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);
        }
Esempio n. 5
0
        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;
            }
        }
Esempio n. 6
0
        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();
        }
Esempio n. 7
0
        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);
        }
Esempio n. 8
0
        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;
            }
        }
Esempio n. 9
0
        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);
        }
Esempio n. 10
0
        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
            };
        }
Esempio n. 11
0
 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));
 }
Esempio n. 12
0
 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));
 }
Esempio n. 13
0
        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);
        }
Esempio n. 14
0
 protected bool Equals(PatchRequest other)
 {
     return(string.Equals(Script, other.Script) && Type == other.Type);
 }
Esempio n. 15
0
        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);
            }
        }
Esempio n. 16
0
 public ScriptedPatchRequestAndCustomFunctionsToken(PatchRequest request, string customFunctions)
 {
     this.request         = request;
     this.customFunctions = customFunctions;
 }
Esempio n. 17
0
        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,
            });
        }
Esempio n. 18
0
 public abstract Task <IOperationResult> ExecutePatchQuery(IndexQueryServerSide query, QueryOperationOptions options, PatchRequest patch,
                                                           BlittableJsonReaderObject patchArgs, DocumentsOperationContext context, Action <IOperationProgress> onProgress, OperationCancelToken token);
Esempio n. 19
0
        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;
            }
        }
Esempio n. 20
0
        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));
Esempio n. 21
0
        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);
        }
Esempio n. 22
0
        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);
            }
        }
Esempio n. 23
0
 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));
 }
Esempio n. 24
0
        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();
                }
            }
        }
Esempio n. 25
0
            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);
                }
            }