Skip to content

Commit

Permalink
Added CreateIfNotExists DeleteIfExists for blobs (#7881)
Browse files Browse the repository at this point in the history
  • Loading branch information
amnguye authored Oct 4, 2019
1 parent 08afd05 commit 69d8d63
Show file tree
Hide file tree
Showing 39 changed files with 4,892 additions and 11 deletions.
145 changes: 143 additions & 2 deletions sdk/storage/Azure.Storage.Blobs/src/AppendBlobClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,143 @@ await CreateInternal(
cancellationToken)
.ConfigureAwait(false);

/// <summary>
/// The <see cref="CreateIfNotExists"/> operation creates a new 0-length
/// append blob. If the append blob already exists, the content of
/// the existing append blob will remain unchanged. To add content to the append
/// blob, call the <see cref="AppendBlockAsync"/> operation.
///
/// For more information, see <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob" />.
/// </summary>
/// <param name="httpHeaders">
/// Optional standard HTTP header properties that can be set for the
/// new append blob.
/// </param>
/// <param name="metadata">
/// Optional custom metadata to set for this append blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{BlobContentInfo}"/> describing the
/// newly created append blob.
/// </returns>
/// <remarks>
/// A <see cref="StorageRequestFailedException"/> will be thrown if
/// a failure occurs.
/// </remarks>
public virtual Response<BlobContentInfo> CreateIfNotExists(
BlobHttpHeaders? httpHeaders = default,
Metadata metadata = default,
CancellationToken cancellationToken = default) =>
CreateIfNotExistsInternal(
httpHeaders,
metadata,
false, // async
cancellationToken)
.EnsureCompleted();

/// <summary>
/// The <see cref="CreateIfNotExistsAsync"/> operation creates a new 0-length
/// append blob. If the append blob already exists, the content of
/// the existing append blob will remain unchanged. To add content to the append
/// blob, call the <see cref="AppendBlockAsync"/> operation.
///
/// For more information, see <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob" />.
/// </summary>
/// <param name="httpHeaders">
/// Optional standard HTTP header properties that can be set for the
/// new append blob.
/// </param>
/// <param name="metadata">
/// Optional custom metadata to set for this append blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{BlobContentInfo}"/> describing the
/// newly created append blob.
/// </returns>
/// <remarks>
/// A <see cref="StorageRequestFailedException"/> will be thrown if
/// a failure occurs.
/// </remarks>
public virtual async Task<Response<BlobContentInfo>> CreateIfNotExistsAsync(
BlobHttpHeaders? httpHeaders = default,
Metadata metadata = default,
CancellationToken cancellationToken = default) =>
await CreateIfNotExistsInternal(
httpHeaders,
metadata,
true, // async
cancellationToken)
.ConfigureAwait(false);

/// <summary>
/// The <see cref="CreateIfNotExistsInternal"/> operation creates a new 0-length
/// append blob. If the append blob already exists, the content of
/// the existing append blob will remain unchanged. To add content to the append
/// blob, call the <see cref="AppendBlockAsync"/> operation.
///
/// For more information, see <see href="https://docs.microsoft.com/rest/api/storageservices/put-blob" />.
/// </summary>
/// <param name="httpHeaders">
/// Optional standard HTTP header properties that can be set for the
/// new append blob.
/// </param>
/// <param name="metadata">
/// Optional custom metadata to set for this append blob.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response{BlobContentInfo}"/> describing the
/// newly created append blob.
/// </returns>
/// <remarks>
/// A <see cref="StorageRequestFailedException"/> will be thrown if
/// a failure occurs.
/// </remarks>
private async Task<Response<BlobContentInfo>> CreateIfNotExistsInternal(
BlobHttpHeaders? httpHeaders,
Metadata metadata,
bool async,
CancellationToken cancellationToken)
{
AppendBlobAccessConditions accessConditions = new AppendBlobAccessConditions
{
HttpAccessConditions = new HttpAccessConditions
{
IfNoneMatch = new ETag(Constants.Wildcard)
}
};
try
{
return await CreateInternal(
httpHeaders,
metadata,
accessConditions,
async,
cancellationToken,
Constants.Blob.Append.CreateIfNotExistsOperationName)
.ConfigureAwait(false);
}
catch (StorageRequestFailedException storageRequestFailedException)
when (storageRequestFailedException.ErrorCode == Constants.Blob.AlreadyExists)
{
return default;
}
}

/// <summary>
/// The <see cref="CreateInternal"/> operation creates a new 0-length
/// append blob. The content of any existing blob is overwritten with
Expand All @@ -356,6 +493,9 @@ await CreateInternal(
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <param name="operationName">
/// Optional. To indicate if the name of the operation.
/// </param>
/// <returns>
/// A <see cref="Response{BlobContentInfo}"/> describing the
/// newly created append blob.
Expand All @@ -369,7 +509,8 @@ private async Task<Response<BlobContentInfo>> CreateInternal(
Metadata metadata,
AppendBlobAccessConditions? accessConditions,
bool async,
CancellationToken cancellationToken)
CancellationToken cancellationToken,
string operationName = Constants.Blob.Append.CreateOperationName)
{
using (Pipeline.BeginLoggingScope(nameof(AppendBlobClient)))
{
Expand Down Expand Up @@ -403,7 +544,7 @@ private async Task<Response<BlobContentInfo>> CreateInternal(
ifMatch: accessConditions?.HttpAccessConditions?.IfMatch,
ifNoneMatch: accessConditions?.HttpAccessConditions?.IfNoneMatch,
async: async,
operationName: "Azure.Storage.Blobs.Specialized.AppendBlobClient.Create",
operationName: operationName,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
Expand Down
144 changes: 142 additions & 2 deletions sdk/storage/Azure.Storage.Blobs/src/BlobBaseClient.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1894,6 +1894,142 @@ await DeleteInternal(
cancellationToken)
.ConfigureAwait(false);

/// <summary>
/// The <see cref="DeleteIfExists"/> operation marks the specified blob
/// or snapshot for deletion, if the blob exists. The blob is later deleted
/// during garbage collection.
///
/// Note that in order to delete a blob, you must delete all of its
/// snapshots. You can delete both at the same time using
/// <see cref="DeleteSnapshotsOption.Include"/>.
///
/// For more information, see <see href="https://docs.microsoft.com/rest/api/storageservices/delete-blob" />.
/// </summary>
/// <param name="deleteOptions">
/// Specifies options for deleting blob snapshots.
/// </param>
/// <param name="accessConditions">
/// Optional <see cref="BlobAccessConditions"/> to add conditions on
/// deleting this blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response"/> on successfully deleting.
/// </returns>
/// <remarks>
/// A <see cref="StorageRequestFailedException"/> will be thrown if
/// a failure occurs.
/// </remarks>
public virtual Response<bool> DeleteIfExists(
DeleteSnapshotsOption? deleteOptions = default,
BlobAccessConditions? accessConditions = default,
CancellationToken cancellationToken = default) =>
DeleteIfExistsInternal(
deleteOptions,
accessConditions ?? default,
false, // async
cancellationToken)
.EnsureCompleted();

/// <summary>
/// The <see cref="DeleteIfExistsAsync"/> operation marks the specified blob
/// or snapshot for deletion, if the blob exists. The blob is later deleted
/// during garbage collection.
///
/// Note that in order to delete a blob, you must delete all of its
/// snapshots. You can delete both at the same time using
/// <see cref="DeleteSnapshotsOption.Include"/>.
///
/// For more information, see <see href="https://docs.microsoft.com/rest/api/storageservices/delete-blob" />.
/// </summary>
/// <param name="deleteOptions">
/// Specifies options for deleting blob snapshots.
/// </param>
/// <param name="accessConditions">
/// Optional <see cref="BlobAccessConditions"/> to add conditions on
/// deleting this blob.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response"/> on successfully deleting.
/// </returns>
/// <remarks>
/// A <see cref="StorageRequestFailedException"/> will be thrown if
/// a failure occurs.
/// </remarks>
public virtual async Task<Response<bool>> DeleteIfExistsAsync(
DeleteSnapshotsOption? deleteOptions = default,
BlobAccessConditions? accessConditions = default,
CancellationToken cancellationToken = default) =>
await DeleteIfExistsInternal(
deleteOptions,
accessConditions ?? default,
true, // async
cancellationToken)
.ConfigureAwait(false);

/// <summary>
/// The <see cref="DeleteIfExistsInternal"/> operation marks the specified blob
/// or snapshot for deletion, if the blob exists. The blob is later deleted
/// during garbage collection.
///
/// Note that in order to delete a blob, you must delete all of its
/// snapshots. You can delete both at the same time using
/// <see cref="DeleteSnapshotsOption.Include"/>.
///
/// For more information, see <see href="https://docs.microsoft.com/rest/api/storageservices/delete-blob" />.
/// </summary>
/// <param name="deleteOptions">
/// Specifies options for deleting blob snapshots.
/// </param>
/// <param name="accessConditions">
/// Optional <see cref="BlobAccessConditions"/> to add conditions on
/// deleting this blob.
/// </param>
/// <param name="async">
/// Whether to invoke the operation asynchronously.
/// </param>
/// <param name="cancellationToken">
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <returns>
/// A <see cref="Response"/> on successfully deleting.
/// </returns>
/// <remarks>
/// A <see cref="StorageRequestFailedException"/> will be thrown if
/// a failure occurs.
/// </remarks>
private async Task<Response<bool>> DeleteIfExistsInternal(
DeleteSnapshotsOption? deleteOptions,
BlobAccessConditions accessConditions,
bool async,
CancellationToken cancellationToken)
{
try
{
Response response = await DeleteInternal(
deleteOptions,
accessConditions,
async,
cancellationToken,
Constants.Blob.Base.DeleteIfExists)
.ConfigureAwait(false);
return Response.FromValue(response, true);
}
catch (StorageRequestFailedException storageRequestFailedException)
when (storageRequestFailedException.ErrorCode == Constants.Blob.NotFound)
{
return Response.FromValue(default, false);
}
}

/// <summary>
/// The <see cref="DeleteInternal"/> operation marks the specified blob
/// or snapshot for deletion. The blob is later deleted during
Expand All @@ -1919,6 +2055,9 @@ await DeleteInternal(
/// Optional <see cref="CancellationToken"/> to propagate
/// notifications that the operation should be cancelled.
/// </param>
/// <param name="operationName">
/// Optional. To indicate if the name of the operation.
/// </param>
/// <returns>
/// A <see cref="Response"/> on successfully deleting.
/// </returns>
Expand All @@ -1930,7 +2069,8 @@ private async Task<Response> DeleteInternal(
DeleteSnapshotsOption? deleteOptions,
BlobAccessConditions? accessConditions,
bool async,
CancellationToken cancellationToken)
CancellationToken cancellationToken,
string operationName = Constants.Blob.Base.Delete)
{
using (Pipeline.BeginLoggingScope(nameof(BlobBaseClient)))
{
Expand All @@ -1952,7 +2092,7 @@ private async Task<Response> DeleteInternal(
ifMatch: accessConditions?.HttpAccessConditions?.IfMatch,
ifNoneMatch: accessConditions?.HttpAccessConditions?.IfNoneMatch,
async: async,
operationName: "Azure.Storage.Blobs.Specialized.BlobBaseClient.Delete",
operationName: operationName,
cancellationToken: cancellationToken)
.ConfigureAwait(false);
}
Expand Down
Loading

0 comments on commit 69d8d63

Please sign in to comment.