Skip to content

Commit 7416998

Browse files
jiacfanvinjiang
authored andcommitted
[Storage](Blob) Add overloads to blob batch addSubRequest methods which accept BlobURL as parameter.
1 parent 21a9b66 commit 7416998

File tree

4 files changed

+180
-38
lines changed

4 files changed

+180
-38
lines changed

sdk/storage/storage-blob/src/BatchRequest.ts

Lines changed: 107 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@ export abstract class BatchRequest {
7474
return this.batchRequest.getSubRequests();
7575
}
7676

77-
protected async addSubRequest(subRequest: BatchSubRequest, assembleSubRequestFunc: ()=>Promise<void>): Promise<void> {
77+
protected async addSubRequestInternal(subRequest: BatchSubRequest, assembleSubRequestFunc: ()=>Promise<void>): Promise<void> {
7878
await Mutex.lock(this.batch);
7979

8080
try {
@@ -108,16 +108,59 @@ export class BatchDeleteRequest extends BatchRequest {
108108
*
109109
* @param {string} url The url of the blob resource to delete.
110110
* @param {Credential} credential The credential to be used for authentication and authorization.
111-
* @param {IBlobDeleteOptions} [options={}]
111+
* @param {IBlobDeleteOptions} [options]
112112
* @returns {Promise<void>}
113113
* @memberof BatchDeleteRequest
114114
*/
115-
public async addDeleteOperation(
115+
public async addSubRequest(
116116
url: string,
117117
credential: Credential,
118-
options: IBlobDeleteOptions = {}
119-
): Promise<void> {
120-
await super.addSubRequest(
118+
options?: IBlobDeleteOptions
119+
): Promise<void>;
120+
121+
/**
122+
* Add a delete operation(subrequest) to mark the specified blob or snapshot for deletion.
123+
* Note that in order to delete a blob, you must delete all of its snapshots.
124+
* You can delete both at the same time. See [delete operation details](https://docs.microsoft.com/en-us/rest/api/storageservices/delete-blob).
125+
* The operation(subrequest) will be authenticated and authorized with specified credential.
126+
* See [blob batch authorization details](https://docs.microsoft.com/en-us/rest/api/storageservices/blob-batch#authorization).
127+
*
128+
* @param {blobUrl} BlobURL The BlobURL.
129+
* @param {IBlobDeleteOptions} [options]
130+
* @returns {Promise<void>}
131+
* @memberof BatchDeleteRequest
132+
*/
133+
public async addSubRequest(
134+
blobURL: BlobURL,
135+
options?: IBlobDeleteOptions
136+
): Promise<void>;
137+
138+
public async addSubRequest(
139+
urlOrBlobURL: string | BlobURL,
140+
credentialOrOptions: Credential | IBlobDeleteOptions | undefined,
141+
options?: IBlobDeleteOptions
142+
): Promise<void>{
143+
let url: string;
144+
let credential: Credential;
145+
146+
if (typeof urlOrBlobURL === 'string' && credentialOrOptions instanceof Credential) {
147+
// First overload
148+
url = urlOrBlobURL;
149+
credential = credentialOrOptions;
150+
} else if (urlOrBlobURL instanceof BlobURL) {
151+
// Second overload
152+
url = urlOrBlobURL.url;
153+
credential = urlOrBlobURL.credential;
154+
options = credentialOrOptions as IBlobDeleteOptions;
155+
} else {
156+
throw new RangeError("Invalid arguments. Either url and credential, or BlobURL need be provided.")
157+
}
158+
159+
if (!options) {
160+
options = {};
161+
}
162+
163+
await super.addSubRequestInternal(
121164
{
122165
url: url,
123166
credential: credential
@@ -158,17 +201,70 @@ export class BatchSetTierRequest extends BatchRequest {
158201
* @param {string} url The url of the blob resource to delete.
159202
* @param {Credential} credential The credential to be used for authentication and authorization.
160203
* @param {Models.AccessTier} tier
161-
* @param {IBlobSetTierOptions} [options={}]
204+
* @param {IBlobSetTierOptions} [options]
162205
* @returns {Promise<void>}
163206
* @memberof BatchSetTierRequest
164207
*/
165-
public async addSetTierOperation(
208+
public async addSubRequest(
166209
url: string,
167210
credential: Credential,
168211
tier: Models.AccessTier,
169-
options: IBlobSetTierOptions = {}
170-
): Promise<void> {
171-
await super.addSubRequest(
212+
options?: IBlobSetTierOptions
213+
): Promise<void>;
214+
215+
/**
216+
* Add a set tier operation(subrequest) to set the tier on a blob.
217+
* The operation is allowed on a page blob in a premium
218+
* storage account and on a block blob in a blob storage account (locally redundant
219+
* storage only). A premium page blob's tier determines the allowed size, IOPS,
220+
* and bandwidth of the blob. A block blob's tier determines Hot/Cool/Archive
221+
* storage type. This operation does not update the blob's ETag.
222+
* See [set blob tier details](https://docs.microsoft.com/en-us/rest/api/storageservices/set-blob-tier).
223+
* The operation(subrequest) will be authenticated and authorized
224+
* with specified credential.See [blob batch authorization details](https://docs.microsoft.com/en-us/rest/api/storageservices/blob-batch#authorization).
225+
*
226+
* @param {blobUrl} BlobURL The BlobURL.
227+
* @param {Models.AccessTier} tier
228+
* @param {IBlobSetTierOptions} [options]
229+
* @returns {Promise<void>}
230+
* @memberof BatchSetTierRequest
231+
*/
232+
public async addSubRequest(
233+
blobURL: BlobURL,
234+
tier: Models.AccessTier,
235+
options?: IBlobSetTierOptions
236+
): Promise<void>;
237+
238+
public async addSubRequest(
239+
urlOrBlobURL: string | BlobURL,
240+
credentialOrTier: Credential | Models.AccessTier,
241+
tierOrOptions?: Models.AccessTier | IBlobSetTierOptions,
242+
options?: IBlobSetTierOptions
243+
): Promise<void>{
244+
let url: string;
245+
let credential: Credential;
246+
let tier: Models.AccessTier;
247+
248+
if (typeof urlOrBlobURL === 'string' && credentialOrTier instanceof Credential) {
249+
// First overload
250+
url = urlOrBlobURL;
251+
credential = credentialOrTier as Credential;
252+
tier = tierOrOptions as Models.AccessTier;
253+
} else if (urlOrBlobURL instanceof BlobURL) {
254+
// Second overload
255+
url = urlOrBlobURL.url;
256+
credential = urlOrBlobURL.credential;
257+
tier = credentialOrTier as Models.AccessTier;
258+
options = tierOrOptions as IBlobSetTierOptions;
259+
} else {
260+
throw new RangeError("Invalid arguments. Either url and credential, or BlobURL need be provided.")
261+
}
262+
263+
if (!options) {
264+
options = {};
265+
}
266+
267+
await super.addSubRequestInternal(
172268
{
173269
url: url,
174270
credential: credential

sdk/storage/storage-blob/src/ServiceURL.ts

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -327,17 +327,17 @@ export class ServiceURL extends StorageURL {
327327
*
328328
* @example
329329
* let batchDeleteRequest = new BatchDeleteRequest();
330-
* await batchDeleteRequest.addDeleteOperation(blockBlobURL0, credential);
331-
* await batchDeleteRequest.addDeleteOperation(blockBlobURL1, credential, {
330+
* await batchDeleteRequest.addSubRequest(urlInString0, credential0);
331+
* await batchDeleteRequest.addSubRequest(urlInString1, credential1, {
332332
* deleteSnapshots: "include"
333333
* });
334334
* const deleteBatchResp = await serviceURL.submitBatch(Aborter.none, batchDeleteRequest);
335335
* console.log(deleteBatchResp.subResponsesSucceededCount);
336336
*
337337
* @example
338338
* let batchSetTierRequest = new BatchSetTierRequest();
339-
* await batchSetTierRequest.addSetTierOperation(blockBlobURL0, credential0, "Cool");
340-
* await batchSetTierRequest.addSetTierOperation(blockBlobURL1, credential1, "Cool", {
339+
* await batchSetTierRequest.addSubRequest(blockBlobURL0, "Cool");
340+
* await batchSetTierRequest.addSubRequest(blockBlobURL1, "Cool", {
341341
* leaseAccessConditions: { leaseId: leaseId }
342342
* });
343343
* const setTierBatchResp = await serviceURL.submitBatch(Aborter.none, batchSetTierRequest);

sdk/storage/storage-blob/src/StorageURL.ts

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import { IRetryOptions, RetryPolicyFactory } from "./RetryPolicyFactory";
1010
import { ITelemetryOptions, TelemetryPolicyFactory } from "./TelemetryPolicyFactory";
1111
import { UniqueRequestIDPolicyFactory } from "./UniqueRequestIDPolicyFactory";
1212
import { escapeURLPath, getURLScheme, iEqual } from "./utils/utils.common";
13+
import { AnonymousCredential } from './credentials/AnonymousCredential';
1314

1415
export { deserializationPolicy };
1516

@@ -105,6 +106,14 @@ export abstract class StorageURL {
105106
*/
106107
public readonly url: string;
107108

109+
/**
110+
* Credential used for authentication and authorization.
111+
*
112+
* @type {string}
113+
* @memberof StorageURL
114+
*/
115+
public readonly credential: Credential;
116+
108117
/**
109118
* StorageClient is a reference to protocol layer operations entry, which is
110119
* generated by AutoRest generator.
@@ -139,6 +148,13 @@ export abstract class StorageURL {
139148

140149
this.isHttps = iEqual(getURLScheme(this.url) || "", "https");
141150

151+
this.credential = new AnonymousCredential();
152+
for (const factory of this.pipeline.factories) {
153+
if (factory instanceof Credential) {
154+
this.credential = factory;
155+
}
156+
}
157+
142158
// Override protocol layer's default content-type
143159
const storageClientContext = this.storageClientContext as any;
144160
storageClientContext.requestContentType = undefined;

sdk/storage/storage-blob/test/blobbatch.spec.ts

Lines changed: 53 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -57,7 +57,7 @@ describe("BlobURL", () => {
5757
// Assemble batch delete request.
5858
let batchDeleteRequest = new BatchDeleteRequest();
5959
for (let i = 0; i < blockBlobCount; i++) {
60-
await batchDeleteRequest.addDeleteOperation(blockBlobURLs[i].url, credential, {});
60+
await batchDeleteRequest.addSubRequest(blockBlobURLs[i].url, credential, {});
6161
}
6262

6363
// Submit batch request and verify response.
@@ -91,12 +91,12 @@ describe("BlobURL", () => {
9191

9292
// Assemble batch delete request which delete blob with its snapshot.
9393
let batchDeleteRequest = new BatchDeleteRequest();
94-
await batchDeleteRequest.addDeleteOperation(blockBlobURLs[0].url, credential, {
94+
await batchDeleteRequest.addSubRequest(blockBlobURLs[0].url, credential, {
9595
deleteSnapshots: "include"
9696
});
9797

9898
// Ensure blobs ready.
99-
const respList1 = await containerURL.listBlobFlatSegment(Aborter.none, undefined, {
99+
let respList1 = await containerURL.listBlobFlatSegment(Aborter.none, undefined, {
100100
include: ["snapshots"]
101101
});
102102
assert.equal(respList1.segment.blobItems.length, 2);
@@ -108,13 +108,13 @@ describe("BlobURL", () => {
108108
assert.equal(respSubmitBatch1.subResponsesFailedCount, 0);
109109

110110
// Validate that blob and its snapshot all get deleted.
111-
const respList2 = await containerURL.listBlobFlatSegment(Aborter.none, undefined, {
111+
respList1 = await containerURL.listBlobFlatSegment(Aborter.none, undefined, {
112112
include: ["snapshots"]
113113
});
114-
assert.equal(respList2.segment.blobItems.length, 0);
114+
assert.equal(respList1.segment.blobItems.length, 0);
115115

116116
//
117-
// Test delete snapshot only with snapshot's url
117+
// Test delete snapshot only with snapshot's url and Credential.
118118
//
119119
// Upload blob.
120120
await blockBlobURLs[1].upload(Aborter.none, content, content.length);
@@ -123,25 +123,55 @@ describe("BlobURL", () => {
123123

124124
// Assemble batch delete request.
125125
let batchDeleteRequest2 = new BatchDeleteRequest();
126-
await batchDeleteRequest2.addDeleteOperation(snapshotURL.url, credential);
126+
await batchDeleteRequest2.addSubRequest(snapshotURL.url, credential);
127127

128128
// Ensure blobs ready.
129-
const respList3 = await containerURL.listBlobFlatSegment(Aborter.none, undefined, {
129+
let respList2 = await containerURL.listBlobFlatSegment(Aborter.none, undefined, {
130130
include: ["snapshots"]
131131
});
132-
assert.equal(respList3.segment.blobItems.length, 2);
132+
assert.equal(respList2.segment.blobItems.length, 2);
133133

134134
// Submit batch request and verify response.
135135
const respSubmitBatch2 = await serviceURL.submitBatch(Aborter.none, batchDeleteRequest2, {});
136136
assert.equal(respSubmitBatch2.subResponses.length, 1);
137137
assert.equal(respSubmitBatch2.subResponsesSucceededCount, 1);
138138
assert.equal(respSubmitBatch2.subResponsesFailedCount, 0);
139139

140-
// Validate that blob and its snapshot all get deleted.
141-
const respList4 = await containerURL.listBlobFlatSegment(Aborter.none, undefined, {
140+
// Validate that snapshot get deleted.
141+
respList2 = await containerURL.listBlobFlatSegment(Aborter.none, undefined, {
142+
include: ["snapshots"]
143+
});
144+
assert.equal(respList2.segment.blobItems.length, 1);
145+
146+
//
147+
// Test delete snapshot only with snapshot's url using snapshot's BlobURL.
148+
//
149+
// Upload blob.
150+
await blockBlobURLs[2].upload(Aborter.none, content, content.length);
151+
const createSnapshotResp2 = await blockBlobURLs[2].createSnapshot(Aborter.none);
152+
const snapshotURL2 = blockBlobURLs[2].withSnapshot(createSnapshotResp2.snapshot!);
153+
154+
// Assemble batch delete request.
155+
let batchDeleteRequest3 = new BatchDeleteRequest();
156+
await batchDeleteRequest3.addSubRequest(snapshotURL2);
157+
158+
// Ensure blobs ready.
159+
let respList3 = await containerURL.listBlobFlatSegment(Aborter.none, undefined, {
142160
include: ["snapshots"]
143161
});
144-
assert.equal(respList4.segment.blobItems.length, 1);
162+
assert.equal(respList3.segment.blobItems.length, 3);
163+
164+
// Submit batch request and verify response.
165+
const respSubmitBatch3 = await serviceURL.submitBatch(Aborter.none, batchDeleteRequest3, {});
166+
assert.equal(respSubmitBatch3.subResponses.length, 1);
167+
assert.equal(respSubmitBatch3.subResponsesSucceededCount, 1);
168+
assert.equal(respSubmitBatch3.subResponsesFailedCount, 0);
169+
170+
// Validate that snapshot get deleted.
171+
respList3 = await containerURL.listBlobFlatSegment(Aborter.none, undefined, {
172+
include: ["snapshots"]
173+
});
174+
assert.equal(respList3.segment.blobItems.length, 2);
145175
});
146176

147177
it("submitBatch should work for batch delete with access condition and partial succeed", async () => {
@@ -151,14 +181,14 @@ describe("BlobURL", () => {
151181

152182
// Assemble batch delete request.
153183
let batchDeleteRequest = new BatchDeleteRequest();
154-
await batchDeleteRequest.addDeleteOperation(blockBlobURLs[0].url, credential, {
184+
await batchDeleteRequest.addSubRequest(blockBlobURLs[0], {
155185
blobAccessConditions: {
156186
modifiedAccessConditions: {
157187
ifMatch: b0.eTag
158188
}
159189
}
160190
});
161-
await batchDeleteRequest.addDeleteOperation(blockBlobURLs[1].url, credential, {
191+
await batchDeleteRequest.addSubRequest(blockBlobURLs[1], {
162192
blobAccessConditions: {
163193
modifiedAccessConditions: {
164194
ifNoneMatch: b1.eTag
@@ -194,7 +224,7 @@ describe("BlobURL", () => {
194224
// Assemble batch set tier request.
195225
let batchSetTierRequest = new BatchSetTierRequest();
196226
for (let i = 0; i < blockBlobCount; i++) {
197-
await batchSetTierRequest.addSetTierOperation(blockBlobURLs[i].url, credential, "Cool", {});
227+
await batchSetTierRequest.addSubRequest(blockBlobURLs[i].url, credential, "Cool", {});
198228
}
199229

200230
// Submit batch request and verify response.
@@ -229,8 +259,8 @@ describe("BlobURL", () => {
229259

230260
// Assemble batch set tier request.
231261
let batchSetTierRequest = new BatchSetTierRequest();
232-
await batchSetTierRequest.addSetTierOperation(blockBlobURLs[0].url, credential, "Cool");
233-
await batchSetTierRequest.addSetTierOperation(blockBlobURLs[1].url, credential, "Cool", {
262+
await batchSetTierRequest.addSubRequest(blockBlobURLs[0], "Cool");
263+
await batchSetTierRequest.addSubRequest(blockBlobURLs[1], "Cool", {
234264
leaseAccessConditions: { leaseId: leaseResp.leaseId! }
235265
});
236266

@@ -260,13 +290,13 @@ describe("BlobURL", () => {
260290

261291
// Assemble batch set tier request.
262292
let batchSetTierRequest = new BatchSetTierRequest();
263-
await batchSetTierRequest.addSetTierOperation(blockBlobURLs[0].url, credential, "Cool");
293+
await batchSetTierRequest.addSubRequest(blockBlobURLs[0].url, credential, "Cool");
264294
// When it's using token credential be sure it's not with SAS (browser testing case)
265295
let blockBlobURL1WithoutSAS = blockBlobURLs[1].url;
266296
if (blockBlobURL1WithoutSAS.indexOf("?") != -1) { // remove query part for this testing for ease
267297
blockBlobURL1WithoutSAS = blockBlobURLs[1].url.substring(0, blockBlobURLs[1].url.indexOf("?"));
268298
}
269-
await batchSetTierRequest.addSetTierOperation(blockBlobURL1WithoutSAS, getTokenCredential(), "Cool");
299+
await batchSetTierRequest.addSubRequest(blockBlobURL1WithoutSAS, getTokenCredential(), "Cool");
270300

271301
// Submit batch request and verify response.
272302
const resp = await serviceURL.submitBatch(Aborter.none, batchSetTierRequest, {});
@@ -295,14 +325,14 @@ describe("BlobURL", () => {
295325
for (let i = 0; i < 256; i++) {
296326
let tmpBlobURL = BlobURL.fromContainerURL(containerURL, `blob${i}`);
297327

298-
await batchSetTierRequest.addSetTierOperation(tmpBlobURL.url, credential, "Cool");
328+
await batchSetTierRequest.addSubRequest(tmpBlobURL.url, credential, "Cool");
299329
}
300330

301331
let exceptionCaught = false;
302332

303333
try {
304334
let tmpBlobURL = BlobURL.fromContainerURL(containerURL, `blobexceed`);
305-
await batchSetTierRequest.addSetTierOperation(tmpBlobURL.url, credential, "Cool");
335+
await batchSetTierRequest.addSubRequest(tmpBlobURL.url, credential, "Cool");
306336
} catch (err) {
307337
if (
308338
err instanceof RangeError &&
@@ -320,7 +350,7 @@ describe("BlobURL", () => {
320350
let exceptionCaught = false;
321351

322352
try {
323-
await batchSetTierRequest.addSetTierOperation("invalidurl", credential, "Cool");
353+
await batchSetTierRequest.addSubRequest("invalidurl", credential, "Cool");
324354
} catch (err) {
325355
if (
326356
err instanceof RangeError &&
@@ -355,7 +385,7 @@ describe("BlobURL", () => {
355385

356386
// Assemble batch set tier request.
357387
let batchSetTierRequest = new BatchSetTierRequest();
358-
await batchSetTierRequest.addSetTierOperation(blockBlobURLs[0].url, credential, "Cool");
388+
await batchSetTierRequest.addSubRequest(blockBlobURLs[0].url, credential, "Cool");
359389

360390
const invalidCredServiceURL = serviceURL.withPipeline(StorageURL.newPipeline(new TokenCredential("invalidtoken")))
361391

0 commit comments

Comments
 (0)