/* SPDX-License-Identifier: Apache-2.0 * * The OpenSearch Contributors require contributions made to * this file be licensed under the Apache-2.0 license or a * compatible open source license. */ /* * Modifications Copyright OpenSearch Contributors. See * GitHub history for details. * * Licensed to Elasticsearch B.V. under one or more contributor * license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright * ownership. Elasticsearch B.V. licenses this file to you under * the Apache License, Version 2.0 (the "License"); you may * not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, * software distributed under the License is distributed on an * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY * KIND, either express or implied. See the License for the * specific language governing permissions and limitations * under the License. */ using System; using System.Linq; using System.Runtime.Serialization; using OpenSearch.Net.Utf8Json; namespace OpenSearch.Client { [InterfaceDataContract] public interface IBulkUpdateOperation : IBulkOperation where TDocument : class where TPartialDocument : class { /// /// The partial update document to be merged on to the existing object. /// TPartialDocument Doc { get; set; } /// /// Instead of sending a partial doc with plus an upsert doc /// with , setting to true will /// use the contents of doc as the upsert value. /// bool? DocAsUpsert { get; set; } /// /// Infers the id of the object to update from the provided object. /// See to apply a partial object merge. /// TDocument IdFrom { get; set; } /// /// A script to specify the update. /// IScript Script { get; set; } /// /// If you would like your script to run regardless of whether the document exists or not — i.e. the script handles /// initializing the document instead of the upsert element — then set scripted_upsert to true /// bool? ScriptedUpsert { get; set; } /// /// A document to upsert when the specified document to be updated is not found /// TDocument Upsert { get; set; } long? IfSequenceNumber { get; set; } long? IfPrimaryTerm { get; set; } /// /// True or false to return the _source field or not, or a list of fields to return. /// [DataMember(Name = "_source")] Union Source { get; set; } } [DataContract] public class BulkUpdateOperation : BulkOperationBase, IBulkUpdateOperation where TDocument : class where TPartialDocument : class { public BulkUpdateOperation(Id id) => Id = id; /// /// Create a new bulk operation /// /// Use this document to infer the id from /// Use the document to infer on as the upsert document in this update operation public BulkUpdateOperation(TDocument idFrom, bool useIdFromAsUpsert = false) { IdFrom = idFrom; if (useIdFromAsUpsert) Upsert = idFrom; } /// /// Create a new Bulk Operation /// /// Use this document to infer the id from /// The partial update document (doc) to send as update /// Use the document to infer on as the upsert document in this update operation public BulkUpdateOperation(TDocument idFrom, TPartialDocument update, bool useIdFromAsUpsert = false) { IdFrom = idFrom; if (useIdFromAsUpsert) Upsert = idFrom; Doc = update; } /// /// The partial update document to be merged on to the existing object. /// public TPartialDocument Doc { get; set; } /// /// Instead of sending a partial doc with plus an upsert doc /// with , setting to true will /// use the contents of doc as the upsert value. /// public bool? DocAsUpsert { get; set; } /// /// Infers the id of the object to update from the provided object. /// See to apply a partial object merge. /// public TDocument IdFrom { get; set; } /// /// A script to specify the update. /// public IScript Script { get; set; } /// /// If you would like your script to run regardless of whether the document exists or not — i.e. the script handles /// initializing the document instead of the upsert element — then set scripted_upsert to true /// public bool? ScriptedUpsert { get; set; } /// /// A document to upsert when the specified document to be updated is not found /// public TDocument Upsert { get; set; } public long? IfSequenceNumber { get; set; } public long? IfPrimaryTerm { get; set; } /// /// True or false to return the _source field or not, or a list of fields to return. /// public Union Source { get; set; } protected override Type ClrType => typeof(TDocument); protected override string Operation => "update"; protected override Id GetIdForOperation(Inferrer inferrer) => Id ?? new Id(new[] { IdFrom, Upsert }.FirstOrDefault(o => o != null)); protected override Routing GetRoutingForOperation(Inferrer inferrer) { if (Routing != null) return Routing; if (IdFrom != null) return new Routing(IdFrom); if (Upsert != null) return new Routing(Upsert); return null; } protected override object GetBody() => new BulkUpdateBody { PartialUpdate = Doc, Script = Script, Upsert = Upsert, DocAsUpsert = DocAsUpsert, ScriptedUpsert = ScriptedUpsert, IfPrimaryTerm = IfPrimaryTerm, IfSequenceNumber = IfSequenceNumber, Source = Source }; } [DataContract] public class BulkUpdateDescriptor : BulkOperationDescriptorBase, IBulkUpdateOperation> , IBulkUpdateOperation where TDocument : class where TPartialDocument : class { protected override Type BulkOperationClrType => typeof(TDocument); protected override string BulkOperationType => "update"; TPartialDocument IBulkUpdateOperation.Doc { get; set; } bool? IBulkUpdateOperation.DocAsUpsert { get; set; } TDocument IBulkUpdateOperation.IdFrom { get; set; } IScript IBulkUpdateOperation.Script { get; set; } bool? IBulkUpdateOperation.ScriptedUpsert { get; set; } TDocument IBulkUpdateOperation.Upsert { get; set; } long? IBulkUpdateOperation.IfSequenceNumber { get; set; } long? IBulkUpdateOperation.IfPrimaryTerm { get; set; } Union IBulkUpdateOperation.Source { get; set; } protected override object GetBulkOperationBody() => new BulkUpdateBody { PartialUpdate = Self.Doc, Script = Self.Script, Upsert = Self.Upsert, DocAsUpsert = Self.DocAsUpsert, ScriptedUpsert = Self.ScriptedUpsert, IfPrimaryTerm = Self.IfPrimaryTerm, IfSequenceNumber = Self.IfSequenceNumber, Source = Self.Source }; protected override Id GetIdForOperation(Inferrer inferrer) => Self.Id ?? new Id(new[] { Self.IdFrom, Self.Upsert }.FirstOrDefault(o => o != null)); protected override Routing GetRoutingForOperation(Inferrer inferrer) { if (Self.Routing != null) return Self.Routing; if (Self.IdFrom != null) return new Routing(Self.IdFrom); if (Self.Upsert != null) return new Routing(Self.Upsert); return null; } /// /// Infers the id of the object to update from the provided /// object /// . /// See to apply a partial object merge. /// public BulkUpdateDescriptor IdFrom(TDocument @object, bool useAsUpsert = false) { Self.IdFrom = @object; return useAsUpsert ? Upsert(@object) : this; } /// /// A document to upsert when the specified document to be updated is not found /// public BulkUpdateDescriptor Upsert(TDocument @object) => Assign(@object, (a, v) => a.Upsert = v); /// /// The partial update document to be merged on to the existing object. /// public BulkUpdateDescriptor Doc(TPartialDocument @object) => Assign(@object, (a, v) => a.Doc = v); /// /// Instead of sending a partial doc with plus an upsert doc /// with , setting to true will /// use the contents of doc as the upsert value. /// public BulkUpdateDescriptor DocAsUpsert(bool? partialDocumentAsUpsert = true) => Assign(partialDocumentAsUpsert, (a, v) => a.DocAsUpsert = v); /// /// If you would like your script to run regardless of whether the document exists or not — i.e. the script handles /// initializing the document instead of the upsert element — then set scripted_upsert to true /// public BulkUpdateDescriptor ScriptedUpsert(bool? scriptedUpsert = true) => Assign(scriptedUpsert, (a, v) => a.ScriptedUpsert = v); /// /// A script to specify the update. /// public BulkUpdateDescriptor Script(Func scriptSelector) => Assign(scriptSelector, (a, v) => a.Script = v?.Invoke(new ScriptDescriptor())); /// /// How many times an update should be retried in the case of a version conflict. /// public BulkUpdateDescriptor RetriesOnConflict(int? retriesOnConflict) => Assign(retriesOnConflict, (a, v) => a.RetriesOnConflict = v); /// /// Operations can be made conditional and only be performed if the last modification to the document was assigned the sequence number. /// public BulkUpdateDescriptor IfSequenceNumber(long? seqNo) => Assign(seqNo, (a, v) => a.IfSequenceNumber = v); /// /// Operations can be made conditional and only be performed if the last modification to the document was assigned the primary term. /// public BulkUpdateDescriptor IfPrimaryTerm(long? primaryTerm) => Assign(primaryTerm, (a, v) => a.IfPrimaryTerm = v); /// /// True or false to return the _source field or not, or a list of fields to return. /// public BulkUpdateDescriptor Source(Union source) => Assign(source, (a, v) => a.Source = v); } }