Skip to content

Commit

Permalink
feat: add new dedup utility method to Option classes (#2063)
Browse files Browse the repository at this point in the history
When providing options duplicates are not allowed, however there are times when you might end up providing two options which would collide. These new utility methods encapsulate the logic necessary to deduplicate any overlap wil returing an array which can be passed directly to the respective operation method.

`dedupe` utility methods added to each of the following Option classes:
* Storage.BlobGetOption.dedupe();
* Storage.BlobListOption.dedupe();
* Storage.BlobSourceOption.dedupe();
* Storage.BlobTargetOption.dedupe();
* Storage.BlobWriteOption.dedupe();
* Storage.BucketGetOption.dedupe();
* Storage.BucketListOption.dedupe();
* Storage.BucketSourceOption.dedupe();
* Storage.BucketTargetOption.dedupe();
* Storage.CreateHmacKeyOption.dedupe();
* Storage.DeleteHmacKeyOption.dedupe();
* Storage.GetHmacKeyOption.dedupe();
* Storage.ListHmacKeysOption.dedupe();
* Storage.UpdateHmacKeyOption.dedupe();
* Bucket.BlobTargetOption.dedupe();
* Bucket.BlobWriteOption.dedupe();
* Bucket.BucketSourceOption.dedupe();
* Blob.BlobSourceOption.dedupe();

There are overloads which accept a collection or array in addition to varargs.
  • Loading branch information
BenWhitehead authored Jun 16, 2023
1 parent e48862a commit 2ad196c
Show file tree
Hide file tree
Showing 5 changed files with 818 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@
import java.security.Key;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -163,6 +164,40 @@ public static BlobSourceOption shouldReturnRawInputStream(boolean shouldReturnRa
return new BlobSourceOption(UnifiedOpts.returnRawInputStream(shouldReturnRawInputStream));
}

/**
* Deduplicate any options which are the same parameter. The value which comes last in {@code
* os} will be the value included in the return.
*/
@BetaApi
public static BlobSourceOption[] dedupe(BlobSourceOption... os) {
return Option.dedupe(BlobSourceOption[]::new, os);
}

/**
* Deduplicate any options which are the same parameter.
*
* <p>The value which comes last in {@code collection} and {@code os} will be the value included
* in the return. All options from {@code os} will override their counterparts in {@code
* collection}.
*/
@BetaApi
public static BlobSourceOption[] dedupe(
Collection<BlobSourceOption> collection, BlobSourceOption... os) {
return Option.dedupe(BlobSourceOption[]::new, collection, os);
}

/**
* Deduplicate any options which are the same parameter.
*
* <p>The value which comes last in {@code collection} and {@code os} will be the value included
* in the return. All options from {@code os} will override their counterparts in {@code
* collection}.
*/
@BetaApi
public static BlobSourceOption[] dedupe(BlobSourceOption[] array, BlobSourceOption... os) {
return Option.dedupe(BlobSourceOption[]::new, array, os);
}

static Storage.BlobSourceOption[] toSourceOptions(
BlobInfo blobInfo, BlobSourceOption... options) {
Storage.BlobSourceOption[] convertedOptions = new Storage.BlobSourceOption[options.length];
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,6 @@
import com.google.cloud.storage.UnifiedOpts.BucketSourceOpt;
import com.google.cloud.storage.UnifiedOpts.ObjectOptExtractor;
import com.google.cloud.storage.UnifiedOpts.ObjectTargetOpt;
import com.google.cloud.storage.UnifiedOpts.OptionShim;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.Lists;
import java.io.IOException;
Expand All @@ -41,6 +40,7 @@
import java.time.Duration;
import java.time.OffsetDateTime;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;
import java.util.Map;
import java.util.Objects;
Expand Down Expand Up @@ -99,6 +99,41 @@ public static BucketSourceOption userProject(@NonNull String userProject) {
return new BucketSourceOption(UnifiedOpts.userProject(userProject));
}

/**
* Deduplicate any options which are the same parameter. The value which comes last in {@code
* os} will be the value included in the return.
*/
@BetaApi
public static BucketSourceOption[] dedupe(BucketSourceOption... os) {
return Option.dedupe(BucketSourceOption[]::new, os);
}

/**
* Deduplicate any options which are the same parameter.
*
* <p>The value which comes last in {@code collection} and {@code os} will be the value included
* in the return. All options from {@code os} will override their counterparts in {@code
* collection}.
*/
@BetaApi
public static BucketSourceOption[] dedupe(
Collection<BucketSourceOption> collection, BucketSourceOption... os) {
return Option.dedupe(BucketSourceOption[]::new, collection, os);
}

/**
* Deduplicate any options which are the same parameter.
*
* <p>The value which comes last in {@code collection} and {@code os} will be the value included
* in the return. All options from {@code os} will override their counterparts in {@code
* collection}.
*/
@BetaApi
public static BucketSourceOption[] dedupe(
BucketSourceOption[] array, BucketSourceOption... os) {
return Option.dedupe(BucketSourceOption[]::new, array, os);
}

static Storage.BucketSourceOption[] toSourceOptions(
BucketInfo bucketInfo, BucketSourceOption... options) {
Storage.BucketSourceOption[] convertedOptions =
Expand Down Expand Up @@ -237,6 +272,40 @@ public static BlobTargetOption userProject(@NonNull String userProject) {
return new BlobTargetOption(UnifiedOpts.userProject(userProject));
}

/**
* Deduplicate any options which are the same parameter. The value which comes last in {@code
* os} will be the value included in the return.
*/
@BetaApi
public static BlobTargetOption[] dedupe(BlobTargetOption... os) {
return Option.dedupe(BlobTargetOption[]::new, os);
}

/**
* Deduplicate any options which are the same parameter.
*
* <p>The value which comes last in {@code collection} and {@code os} will be the value included
* in the return. All options from {@code os} will override their counterparts in {@code
* collection}.
*/
@BetaApi
public static BlobTargetOption[] dedupe(
Collection<BlobTargetOption> collection, BlobTargetOption... os) {
return Option.dedupe(BlobTargetOption[]::new, collection, os);
}

/**
* Deduplicate any options which are the same parameter.
*
* <p>The value which comes last in {@code collection} and {@code os} will be the value included
* in the return. All options from {@code os} will override their counterparts in {@code
* collection}.
*/
@BetaApi
public static BlobTargetOption[] dedupe(BlobTargetOption[] array, BlobTargetOption... os) {
return Option.dedupe(BlobTargetOption[]::new, array, os);
}

static Storage.BlobTargetOption[] toTargetOptions(
BlobInfo blobInfo, BlobTargetOption... options) {
Storage.BlobTargetOption[] targetOptions = new Storage.BlobTargetOption[options.length];
Expand All @@ -255,7 +324,7 @@ static Storage.BlobTargetOption[] toTargetOptions(
}

/** Class for specifying blob write options when {@code Bucket} methods are used. */
public static class BlobWriteOption extends OptionShim<ObjectTargetOpt> implements Serializable {
public static class BlobWriteOption extends Option<ObjectTargetOpt> implements Serializable {

private static final long serialVersionUID = 59762268190041584L;

Expand Down Expand Up @@ -366,6 +435,40 @@ public static BlobWriteOption userProject(@NonNull String userProject) {
return new BlobWriteOption(UnifiedOpts.userProject(userProject));
}

/**
* Deduplicate any options which are the same parameter. The value which comes last in {@code
* os} will be the value included in the return.
*/
@BetaApi
public static BlobWriteOption[] dedupe(BlobWriteOption... os) {
return Option.dedupe(BlobWriteOption[]::new, os);
}

/**
* Deduplicate any options which are the same parameter.
*
* <p>The value which comes last in {@code collection} and {@code os} will be the value included
* in the return. All options from {@code os} will override their counterparts in {@code
* collection}.
*/
@BetaApi
public static BlobWriteOption[] dedupe(
Collection<BlobWriteOption> collection, BlobWriteOption... os) {
return Option.dedupe(BlobWriteOption[]::new, collection, os);
}

/**
* Deduplicate any options which are the same parameter.
*
* <p>The value which comes last in {@code collection} and {@code os} will be the value included
* in the return. All options from {@code os} will override their counterparts in {@code
* collection}.
*/
@BetaApi
public static BlobWriteOption[] dedupe(BlobWriteOption[] array, BlobWriteOption... os) {
return Option.dedupe(BlobWriteOption[]::new, array, os);
}

static Storage.BlobWriteOption[] toWriteOptions(BlobInfo blobInfo, BlobWriteOption... options) {
Storage.BlobWriteOption[] convertedOptions = new Storage.BlobWriteOption[options.length];
for (int i = 0; i < options.length; i++) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,11 @@

import com.google.cloud.storage.UnifiedOpts.Opt;
import java.io.Serializable;
import java.util.Arrays;
import java.util.Collection;
import java.util.function.IntFunction;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/** Base class for Storage operation option. */
@Deprecated
Expand All @@ -29,4 +34,32 @@ public abstract class Option<O extends Opt> extends UnifiedOpts.OptionShim<O>
Option(O opt) {
super(opt);
}

@SafeVarargs
static <O extends Option<?>> O[] dedupe(IntFunction<O[]> gen, O... os) {
return dedupe(gen, Arrays.stream(os));
}

@SafeVarargs
static <O extends Option<?>> O[] dedupe(IntFunction<O[]> gen, Collection<O> collection, O... os) {
return dedupe(gen, Stream.of(collection.stream(), Arrays.stream(os)).flatMap(s -> s));
}

@SafeVarargs
static <O extends Option<?>> O[] dedupe(IntFunction<O[]> gen, O[] array, O... os) {
return dedupe(gen, Stream.of(Arrays.stream(array), Arrays.stream(os)).flatMap(s -> s));
}

/**
* All Options contain an {@link Opt}, {@code Opt}s are distinct classes allowing us to group
* based on those classes. Once grouped, we select the last element to provide last wins behavior.
*
* <p>Each of these helpers is an internal implementation detail, primarily due to the fact that
* generic arrays can not be instantiated in Java and requires a factory to be passed in.
*/
private static <O extends Option<?>> O[] dedupe(IntFunction<O[]> gen, Stream<O> s) {
return s.collect(Collectors.groupingBy(o -> o.getOpt().getClass())).values().stream()
.map(l -> l.get(l.size() - 1))
.toArray(gen);
}
}
Loading

0 comments on commit 2ad196c

Please sign in to comment.