Skip to content

Commit 49b3c43

Browse files
committed
Fix script representation for bulk updates
Parameters related to an update script should be serialized as properties of an object assigned to a script property. Closes #2357
1 parent 2147972 commit 49b3c43

File tree

3 files changed

+218
-60
lines changed

3 files changed

+218
-60
lines changed

src/Nest/Document/Multiple/Bulk/BulkOperation/BulkUpdate.cs

Lines changed: 179 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,51 +8,83 @@ public interface IBulkUpdateOperation<TDocument, TPartialDocument> : IBulkOperat
88
where TDocument : class
99
where TPartialDocument : class
1010
{
11+
/// <summary>
12+
/// Infers the id of the object to update from the provided <param name="object">object</param>.
13+
/// See <see cref="Doc"/> to apply a partial object merge.
14+
/// </summary>
1115
TDocument InferFrom { get; set; }
1216

17+
/// <summary>
18+
/// A document to upsert when the specified document to be updated is not found
19+
/// </summary>
1320
TDocument Upsert { get; set; }
14-
21+
22+
/// <summary>
23+
/// The partial update document to be merged on to the existing object.
24+
/// </summary>
1525
TPartialDocument Doc { get; set; }
16-
26+
27+
/// <summary>
28+
/// Instead of sending a partial doc with <see cref="Doc"/> plus an upsert doc
29+
/// with <see cref="Upsert"/>, setting <see cref="DocAsUpsert"/> to <c>true</c> will
30+
/// use the contents of doc as the upsert value.
31+
/// </summary>
1732
bool? DocAsUpsert { get; set; }
18-
33+
34+
/// <summary>
35+
/// The script language to use
36+
/// </summary>
1937
string Lang { get; set; }
20-
38+
39+
/// <summary>
40+
/// An inline script to specify the update
41+
/// </summary>
2142
string Script { get; set; }
2243

44+
/// <summary>
45+
/// The id of an indexed script to specify the update
46+
/// </summary>
2347
string ScriptId { get; set; }
2448

49+
/// <summary>
50+
/// The file of a script to specify the update
51+
/// </summary>
2552
string ScriptFile { get; set; }
26-
53+
54+
/// <summary>
55+
/// The parameters for the script
56+
/// </summary>
2757
Dictionary<string, object> Params { get; set; }
2858
}
2959

3060
public class BulkUpdateOperation<TDocument, TPartialDocument> : BulkOperationBase, IBulkUpdateOperation<TDocument, TPartialDocument>
3161
where TDocument : class
3262
where TPartialDocument : class
3363
{
34-
64+
/// <summary>
65+
/// Create a new bulk update operation
66+
/// </summary>
3567
public BulkUpdateOperation(Id id) { this.Id = id; }
3668

3769
/// <summary>
38-
/// Create a new bulk operation
70+
/// Create a new bulk update operation
3971
/// </summary>
4072
/// <param name="idFrom">Use this document to infer the id from</param>
4173
/// <param name="useIdFromAsUpsert">Use the document to infer on as the upsert document in this update operation</param>
42-
public BulkUpdateOperation(TDocument idFrom, bool useIdFromAsUpsert = false)
74+
public BulkUpdateOperation(TDocument idFrom, bool useIdFromAsUpsert = false)
4375
{
4476
this.InferFrom = idFrom;
4577
if (useIdFromAsUpsert)
4678
this.Upsert = idFrom;
4779
}
48-
80+
4981
/// <summary>
50-
/// Create a new Bulk Operation
82+
/// Create a new bulk update operation
5183
/// </summary>
5284
/// <param name="idFrom">Use this document to infer the id from</param>
5385
/// <param name="update">The partial update document (doc) to send as update</param>
5486
/// <param name="useIdFromAsUpsert">Use the document to infer on as the upsert document in this update operation</param>
55-
public BulkUpdateOperation(TDocument idFrom, TPartialDocument update, bool useIdFromAsUpsert = false)
87+
public BulkUpdateOperation(TDocument idFrom, TPartialDocument update, bool useIdFromAsUpsert = false)
5688
{
5789
this.InferFrom = idFrom;
5890
if (useIdFromAsUpsert)
@@ -66,28 +98,94 @@ public BulkUpdateOperation(TDocument idFrom, TPartialDocument update, bool useId
6698

6799
protected override Id GetIdForOperation(Inferrer inferrer) => this.Id ?? new Id(new[] { this.InferFrom, this.Upsert }.FirstOrDefault(o=>o != null));
68100

69-
protected override object GetBody() =>
101+
protected override object GetBody() =>
70102
new BulkUpdateBody<TDocument, TPartialDocument>
71-
{
72-
_PartialUpdate = this.Doc,
73-
_Script = this.Script,
74-
_ScriptId = this.ScriptId,
75-
_ScriptFile = this.ScriptFile,
76-
_Lang = this.Lang,
77-
_Params = this.Params,
78-
_Upsert = this.Upsert,
79-
_DocAsUpsert = this.DocAsUpsert
80-
};
103+
{
104+
_PartialUpdate = this.Doc,
105+
_Script = CreateScriptFromProperties(),
106+
_Upsert = this.Upsert,
107+
_DocAsUpsert = this.DocAsUpsert
108+
};
81109

110+
/// <summary>
111+
/// Infers the id of the object to update from the provided <param name="object">object</param>.
112+
/// See <see cref="Doc"/> to apply a partial object merge.
113+
/// </summary>
82114
public TDocument InferFrom { get; set; }
115+
116+
/// <summary>
117+
/// A document to upsert when the specified document to be updated is not found
118+
/// </summary>
83119
public TDocument Upsert { get; set; }
120+
121+
/// <summary>
122+
/// The partial update document to be merged on to the existing object.
123+
/// </summary>
84124
public TPartialDocument Doc { get; set; }
125+
126+
/// <summary>
127+
/// Instead of sending a partial doc with <see cref="Doc"/> plus an upsert doc
128+
/// with <see cref="Upsert"/>, setting <see cref="DocAsUpsert"/> to <c>true</c> will
129+
/// use the contents of doc as the upsert value.
130+
/// </summary>
85131
public bool? DocAsUpsert { get; set; }
132+
133+
/// <summary>
134+
/// The script language to use
135+
/// </summary>
86136
public string Lang { get; set; }
137+
138+
/// <summary>
139+
/// An inline script to specify the update
140+
/// </summary>
87141
public string Script { get; set; }
142+
143+
/// <summary>
144+
/// The id of an indexed script to specify the update
145+
/// </summary>
88146
public string ScriptId { get; set; }
147+
148+
/// <summary>
149+
/// The file of a script to specify the update
150+
/// </summary>
89151
public string ScriptFile { get; set; }
152+
153+
/// <summary>
154+
/// The parameters for the script
155+
/// </summary>
90156
public Dictionary<string, object> Params { get; set; }
157+
158+
private IScript CreateScriptFromProperties()
159+
{
160+
IScript script = null;
161+
162+
if (!this.Script.IsNullOrEmpty())
163+
{
164+
script = new InlineScript(this.Script)
165+
{
166+
Lang = this.Lang,
167+
Params = this.Params
168+
};
169+
}
170+
else if (!this.ScriptFile.IsNullOrEmpty())
171+
{
172+
script = new FileScript(this.ScriptFile)
173+
{
174+
Lang = this.Lang,
175+
Params = this.Params
176+
};
177+
}
178+
else if (!this.ScriptId.IsNullOrEmpty())
179+
{
180+
script = new IndexedScript(this.ScriptId)
181+
{
182+
Lang = this.Lang,
183+
Params = this.Params
184+
};
185+
}
186+
187+
return script;
188+
}
91189
}
92190

93191
public class BulkUpdateDescriptor<TDocument, TPartialDocument>
@@ -100,19 +198,12 @@ public class BulkUpdateDescriptor<TDocument, TPartialDocument>
100198
protected override Type BulkOperationClrType => typeof(TDocument);
101199

102200
TDocument IBulkUpdateOperation<TDocument, TPartialDocument>.InferFrom { get; set; }
103-
104201
TDocument IBulkUpdateOperation<TDocument, TPartialDocument>.Upsert { get; set; }
105-
106202
TPartialDocument IBulkUpdateOperation<TDocument, TPartialDocument>.Doc { get; set; }
107-
108203
bool? IBulkUpdateOperation<TDocument, TPartialDocument>.DocAsUpsert { get; set; }
109-
110204
string IBulkUpdateOperation<TDocument, TPartialDocument>.Lang { get; set; }
111-
112205
string IBulkUpdateOperation<TDocument, TPartialDocument>.Script { get; set; }
113-
114206
string IBulkUpdateOperation<TDocument, TPartialDocument>.ScriptId { get; set; }
115-
116207
string IBulkUpdateOperation<TDocument, TPartialDocument>.ScriptFile { get; set; }
117208

118209
Dictionary<string, object> IBulkUpdateOperation<TDocument, TPartialDocument>.Params { get; set; }
@@ -121,20 +212,16 @@ protected override object GetBulkOperationBody() =>
121212
new BulkUpdateBody<TDocument, TPartialDocument>
122213
{
123214
_PartialUpdate = Self.Doc,
124-
_Script = Self.Script,
125-
_ScriptId = Self.ScriptId,
126-
_ScriptFile = Self.ScriptFile,
127-
_Lang = Self.Lang,
128-
_Params = Self.Params,
215+
_Script = CreateScriptFromProperties(),
129216
_Upsert = Self.Upsert,
130217
_DocAsUpsert = Self.DocAsUpsert
131218
};
132219

133220
protected override Id GetIdForOperation(Inferrer inferrer) => Self.Id ?? new Id(new[] { Self.InferFrom, Self.Upsert }.FirstOrDefault(o=>o != null));
134221

135222
/// <summary>
136-
/// The object to update, if id is not manually set it will be inferred from the object.
137-
/// Used ONLY to infer the ID see Document() to apply a partial object merge.
223+
/// Infers the id of the object to update from the provided <param name="object">object</param>.
224+
/// See <see cref="Doc(TPartialDocument)"/> to apply a partial object merge.
138225
/// </summary>
139226
public BulkUpdateDescriptor<TDocument, TPartialDocument> IdFrom(TDocument @object, bool useAsUpsert = false)
140227
{
@@ -152,19 +239,74 @@ public BulkUpdateDescriptor<TDocument, TPartialDocument> IdFrom(TDocument @objec
152239
/// </summary>
153240
public BulkUpdateDescriptor<TDocument, TPartialDocument> Doc(TPartialDocument @object) => Assign(a => a.Doc = @object);
154241

242+
/// <summary>
243+
/// Instead of sending a partial doc with <see cref="Doc(TPartialDocument)"/> plus an upsert doc
244+
/// with <see cref="Upsert(TDocument)"/>, setting <see cref="DocAsUpsert"/> to <c>true</c> will
245+
/// use the contents of doc as the upsert value.
246+
/// </summary>
155247
public BulkUpdateDescriptor<TDocument, TPartialDocument> DocAsUpsert(bool partialDocumentAsUpsert = true) => Assign(a => a.DocAsUpsert = partialDocumentAsUpsert);
156248

249+
/// <summary>
250+
/// The script language to use
251+
/// </summary>
157252
public BulkUpdateDescriptor<TDocument, TPartialDocument> Lang(string lang) => Assign(a => a.Lang = lang);
158253

254+
/// <summary>
255+
/// An inline script to specify the update
256+
/// </summary>
159257
public BulkUpdateDescriptor<TDocument, TPartialDocument> Script(string script) => Assign(a => a.Script = script);
160258

259+
/// <summary>
260+
/// The id of an indexed script to specify the update
261+
/// </summary>
161262
public BulkUpdateDescriptor<TDocument, TPartialDocument> ScriptId(string scriptId) => Assign(a => a.ScriptId = scriptId);
162263

264+
/// <summary>
265+
/// The file of a script to specify the update
266+
/// </summary>
163267
public BulkUpdateDescriptor<TDocument, TPartialDocument> ScriptFile(string scriptFile) => Assign(a => a.ScriptFile = scriptFile);
164268

269+
/// <summary>
270+
/// The parameters for the script
271+
/// </summary>
165272
public BulkUpdateDescriptor<TDocument, TPartialDocument> Params(Func<FluentDictionary<string, object>, FluentDictionary<string, object>> paramDictionary) =>
166273
Assign(a => a.Params = paramDictionary(new FluentDictionary<string, object>()));
167274

275+
/// <summary>
276+
/// How many times an update should be retried in the case of a version conflict.
277+
/// </summary>
168278
public BulkUpdateDescriptor<TDocument, TPartialDocument> RetriesOnConflict(int? retriesOnConflict) => Assign(a => a.RetriesOnConflict = retriesOnConflict);
279+
280+
private IScript CreateScriptFromProperties()
281+
{
282+
IScript script = null;
283+
284+
if (!Self.Script.IsNullOrEmpty())
285+
{
286+
script = new InlineScript(Self.Script)
287+
{
288+
Lang = Self.Lang,
289+
Params = Self.Params
290+
};
291+
}
292+
else if (!Self.ScriptFile.IsNullOrEmpty())
293+
{
294+
script = new FileScript(Self.ScriptFile)
295+
{
296+
Lang = Self.Lang,
297+
Params = Self.Params
298+
};
299+
}
300+
else if (!Self.ScriptId.IsNullOrEmpty())
301+
{
302+
script = new IndexedScript(Self.ScriptId)
303+
{
304+
Lang = Self.Lang,
305+
Params = Self.Params
306+
};
307+
}
308+
309+
return script;
310+
}
169311
}
170-
}
312+
}

src/Nest/Document/Multiple/Bulk/BulkOperation/BulkUpdateBody.cs

Lines changed: 7 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -3,33 +3,20 @@
33

44
namespace Nest
55
{
6-
internal class BulkUpdateBody<TDocument, TPartialUpdate>
6+
internal class BulkUpdateBody<TDocument, TPartialUpdate>
77
where TDocument : class
88
where TPartialUpdate : class
99
{
10-
[JsonProperty(PropertyName = "doc")]
10+
[JsonProperty("doc")]
1111
internal TPartialUpdate _PartialUpdate { get; set; }
1212

13-
[JsonProperty(PropertyName = "upsert")]
13+
[JsonProperty("upsert")]
1414
internal TDocument _Upsert { get; set; }
1515

16-
[JsonProperty(PropertyName = "doc_as_upsert")]
16+
[JsonProperty("doc_as_upsert")]
1717
public bool? _DocAsUpsert { get; set; }
1818

19-
[JsonProperty(PropertyName = "script")]
20-
internal string _Script { get; set; }
21-
22-
[JsonProperty("script_id")]
23-
internal string _ScriptId { get; set; }
24-
25-
[JsonProperty("script_file")]
26-
internal string _ScriptFile { get; set; }
27-
28-
[JsonProperty(PropertyName = "params")]
29-
[JsonConverter(typeof(VerbatimDictionaryKeysJsonConverter))]
30-
internal Dictionary<string, object> _Params { get; set; }
31-
32-
[JsonProperty(PropertyName = "lang")]
33-
public string _Lang { get; set; }
19+
[JsonProperty("script")]
20+
internal IScript _Script { get; set; }
3421
}
35-
}
22+
}

0 commit comments

Comments
 (0)