Skip to content

Commit e4fdf05

Browse files
Make batch requests no longer require manual encoding.
Now leverages the existing 'ParseCommand' class instead of constructing improperly typed dictionaries. TODO: Split this into its own class.
1 parent d64b538 commit e4fdf05

File tree

3 files changed

+49
-24
lines changed

3 files changed

+49
-24
lines changed

Parse/Internal/Command/ParseCommand.cs

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,20 @@ namespace Parse.Internal {
1313
internal class ParseCommand : HttpRequest {
1414
private const string revocableSessionTokenTrueValue = "1";
1515

16+
public IDictionary<string, object> DataObject { get; private set; }
17+
public override Stream Data {
18+
get {
19+
if (base.Data != null) {
20+
return base.Data;
21+
}
22+
23+
return base.Data = DataObject != null
24+
? new MemoryStream(Encoding.UTF8.GetBytes(Json.Encode(DataObject)))
25+
: null;
26+
}
27+
internal set { base.Data = value; }
28+
}
29+
1630
public ParseCommand(string relativeUri,
1731
string method,
1832
string sessionToken = null,
@@ -21,8 +35,9 @@ public ParseCommand(string relativeUri,
2135
method: method,
2236
sessionToken: sessionToken,
2337
headers: headers,
24-
stream: data != null ? new MemoryStream(UTF8Encoding.UTF8.GetBytes(Json.Encode(data))) : null,
38+
stream: null,
2539
contentType: data != null ? "application/json" : null) {
40+
DataObject = data;
2641
}
2742

2843
public ParseCommand(string relativeUri,

Parse/Internal/HttpRequest.cs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,9 +3,6 @@
33
using System;
44
using System.Collections.Generic;
55
using System.IO;
6-
using System.Net;
7-
using System.Threading;
8-
using System.Threading.Tasks;
96

107
namespace Parse.Internal {
118
/// <summary>
@@ -18,7 +15,7 @@ internal class HttpRequest {
1815
/// <summary>
1916
/// Data stream to be uploaded.
2017
/// </summary>
21-
public Stream Data { get; internal set; }
18+
public virtual Stream Data { get; internal set; }
2219

2320
/// <summary>
2421
/// HTTP method. One of <c>DELETE</c>, <c>GET</c>, <c>HEAD</c>, <c>POST</c> or <c>PUT</c>

Parse/Internal/Object/Controller/ParseObjectController.cs

Lines changed: 32 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -55,14 +55,15 @@ public IList<Task<IObjectState>> SaveAllAsync(IList<IObjectState> states,
5555
IList<IDictionary<string, IParseFieldOperation>> operationsList,
5656
string sessionToken,
5757
CancellationToken cancellationToken) {
58-
var requests = states.Zip(operationsList, (item, ops) => new Dictionary<string, object> {
59-
{ "method", (item.ObjectId == null ? "POST" : "PUT") },
60-
{ "path", (item.ObjectId == null ?
61-
string.Format("/1/classes/{0}", Uri.EscapeDataString(item.ClassName)) :
62-
string.Format("/1/classes/{0}/{1}", Uri.EscapeDataString(item.ClassName),
63-
Uri.EscapeDataString(item.ObjectId))) },
64-
{ "body", ParseObject.ToJSONObjectForSaving(ops) }
65-
}).Cast<object>().ToList();
58+
59+
var requests = states
60+
.Zip(operationsList, (item, ops) => new ParseCommand(
61+
item.ObjectId == null
62+
? string.Format("classes/{0}", Uri.EscapeDataString(item.ClassName))
63+
: string.Format("classes/{0}/{1}", Uri.EscapeDataString(item.ClassName), Uri.EscapeDataString(item.ObjectId)),
64+
method: item.ObjectId == null ? "POST" : "PUT",
65+
data: ParseObject.ToJSONObjectForSaving(ops)))
66+
.ToList();
6667

6768
var batchTasks = ExecuteBatchRequests(requests, sessionToken, cancellationToken);
6869
var stateTasks = new List<Task<IObjectState>>();
@@ -90,24 +91,25 @@ public Task DeleteAsync(IObjectState state,
9091
public IList<Task> DeleteAllAsync(IList<IObjectState> states,
9192
string sessionToken,
9293
CancellationToken cancellationToken) {
93-
var requests = states.Where(item => item.ObjectId != null).Select(item => new Dictionary<string, object> {
94-
{ "method", "DELETE" },
95-
{ "path", string.Format("/1/classes/{0}/{1}", Uri.EscapeDataString(item.ClassName),
96-
Uri.EscapeDataString(item.ObjectId)) }
97-
}).Cast<object>().ToList();
98-
94+
var requests = states
95+
.Where(item => item.ObjectId != null)
96+
.Select(item => new ParseCommand(
97+
string.Format("classes/{0}/{1}", Uri.EscapeDataString(item.ClassName), Uri.EscapeDataString(item.ObjectId)),
98+
method: "DELETE",
99+
data: null))
100+
.ToList();
99101
return ExecuteBatchRequests(requests, sessionToken, cancellationToken).Cast<Task>().ToList();
100102
}
101103

102104
// TODO (hallucinogen): move this out to a class to be used by Analytics
103105
private const int MaximumBatchSize = 50;
104-
internal IList<Task<IDictionary<string, object>>> ExecuteBatchRequests(IList<object> requests,
106+
internal IList<Task<IDictionary<string, object>>> ExecuteBatchRequests(IList<ParseCommand> requests,
105107
string sessionToken,
106108
CancellationToken cancellationToken) {
107109
var tasks = new List<Task<IDictionary<string, object>>>();
108110
int batchSize = requests.Count;
109111

110-
IEnumerable<object> remaining = requests;
112+
IEnumerable<ParseCommand> remaining = requests;
111113
while (batchSize > MaximumBatchSize) {
112114
var process = remaining.Take(MaximumBatchSize).ToList();
113115
remaining = remaining.Skip(MaximumBatchSize);
@@ -121,7 +123,7 @@ internal IList<Task<IDictionary<string, object>>> ExecuteBatchRequests(IList<obj
121123
return tasks;
122124
}
123125

124-
private IList<Task<IDictionary<string, object>>> ExecuteBatchRequest(IList<object> requests,
126+
private IList<Task<IDictionary<string, object>>> ExecuteBatchRequest(IList<ParseCommand> requests,
125127
string sessionToken,
126128
CancellationToken cancellationToken) {
127129
var tasks = new List<Task<IDictionary<string, object>>>();
@@ -133,10 +135,21 @@ private IList<Task<IDictionary<string, object>>> ExecuteBatchRequest(IList<objec
133135
tasks.Add(tcs.Task);
134136
}
135137

136-
var command = new ParseCommand("/1/batch",
138+
var encodedRequests = requests.Select(r => {
139+
var results = new Dictionary<string, object> {
140+
{ "method", r.Method },
141+
{ "path", r.Uri.AbsolutePath },
142+
};
143+
144+
if (r.DataObject != null) {
145+
results["body"] = r.DataObject;
146+
}
147+
return results;
148+
}).Cast<object>().ToList();
149+
var command = new ParseCommand("batch",
137150
method: "POST",
138151
sessionToken: sessionToken,
139-
data: new Dictionary<string, object> { { "requests", requests } });
152+
data: new Dictionary<string, object> { { "requests", encodedRequests } });
140153

141154
commandRunner.RunCommandAsync(command, cancellationToken: cancellationToken).ContinueWith(t => {
142155
if (t.IsFaulted || t.IsCanceled) {

0 commit comments

Comments
 (0)