diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java
index a566fbeb8421..9eb6b92d2325 100644
--- a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java
+++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQuery.java
@@ -151,6 +151,39 @@ public String getSelector() {
}
}
+ /**
+ * Fields of a BigQuery Routine resource.
+ *
+ * @see Routine
+ * Resource
+ */
+ enum RoutineField implements FieldSelector {
+ ARGUMENTS("arguments"),
+ CREATION_TIME("creationTime"),
+ DEFINITION_BODY("definitionBody"),
+ ETAG("etag"),
+ IMPORTED_LIBRARIES("importedLibraries"),
+ LANGUAGE("language"),
+ LAST_MODIFIED_TIME("lastModifiedTime"),
+ RETURN_TYPE("returnType"),
+ ROUTINE_REFERENCE("routineReference"),
+ ROUTINE_TYPE("routineType");
+
+ static final List extends FieldSelector> REQUIRED_FIELDS =
+ ImmutableList.of(ROUTINE_REFERENCE);
+
+ private final String selector;
+
+ RoutineField(String selector) {
+ this.selector = selector;
+ }
+
+ @Override
+ public String getSelector() {
+ return selector;
+ }
+ }
+
/**
* Fields of a BigQuery Job resource.
*
@@ -267,6 +300,27 @@ public static ModelListOption pageToken(String pageToken) {
}
}
+ /** Class for specifying routine list options. */
+ class RoutineListOption extends Option {
+
+ private static final long serialVersionUID = 8660294969063312498L;
+
+ private RoutineListOption(BigQueryRpc.Option option, Object value) {
+ super(option, value);
+ }
+
+ /** Returns an option to specify the maximum number of routines returned per page. */
+ public static RoutineListOption pageSize(long pageSize) {
+ checkArgument(pageSize >= 0);
+ return new RoutineListOption(BigQueryRpc.Option.MAX_RESULTS, pageSize);
+ }
+
+ /** Returns an option to specify the page token from which to start listing routines. */
+ public static RoutineListOption pageToken(String pageToken) {
+ return new RoutineListOption(BigQueryRpc.Option.PAGE_TOKEN, pageToken);
+ }
+ }
+
/** Class for specifying table list options. */
class TableListOption extends Option {
@@ -309,7 +363,7 @@ public static TableOption fields(TableField... fields) {
}
}
- /** Class for specifying table get, create and update options. */
+ /** Class for specifying model get, create and update options. */
class ModelOption extends Option {
private static final long serialVersionUID = -1723870134095226772L;
@@ -329,6 +383,26 @@ public static ModelOption fields(ModelField... fields) {
}
}
+ /** Class for specifying table get, create and update options. */
+ class RoutineOption extends Option {
+
+ private static final long serialVersionUID = -1723870122095226772L;
+
+ private RoutineOption(BigQueryRpc.Option option, Object value) {
+ super(option, value);
+ }
+
+ /**
+ * Returns an option to specify the routines's fields to be returned by the RPC call. If this
+ * option is not provided all model's fields are returned. {@code RoutineOption.fields} can be
+ * used to specify only the fields of interest.
+ */
+ public static RoutineOption fields(RoutineField... fields) {
+ return new RoutineOption(
+ BigQueryRpc.Option.FIELDS, Helper.selector(RoutineField.REQUIRED_FIELDS, fields));
+ }
+ }
+
/** Class for specifying table data list options. */
class TableDataListOption extends Option {
@@ -583,6 +657,13 @@ public int hashCode() {
*/
Table create(TableInfo tableInfo, TableOption... options);
+ /**
+ * Creates a new routine.
+ *
+ * @throws BigQueryException upon failure
+ */
+ Routine create(RoutineInfo routineInfo, RoutineOption... options);
+
/**
* Creates a new job.
*
@@ -804,6 +885,29 @@ public int hashCode() {
*/
boolean delete(ModelId modelId);
+ /**
+ * Deletes the requested routine.
+ *
+ *
Example of deleting a routine.
+ *
+ *
{@code
+ * String projectId = "my_project_id";
+ * String datasetId = "my_dataset_id";
+ * String routineId = "my_routine_id";
+ * RoutineId routineId = RoutineId.of(projectId, datasetId, routineId);
+ * boolean deleted = bigquery.delete(routineId);
+ * if (deleted) {
+ * // the routine was deleted
+ * } else {
+ * // the routine was not found
+ * }
+ *
+ *
+ * @return {@code true} if routine was deleted, {@code false} if it was not found
+ * @throws BigQueryException upon failure
+ */
+ boolean delete(RoutineId routineId);
+
/**
* Updates dataset information.
*
@@ -899,6 +1003,13 @@ public int hashCode() {
*/
Model update(ModelInfo modelInfo, ModelOption... options);
+ /**
+ * Updates routine information.
+ *
+ * @throws BigQueryException upon failure
+ */
+ Routine update(RoutineInfo routineInfo, RoutineOption... options);
+
/**
* Returns the requested table or {@code null} if not found.
*
@@ -955,6 +1066,26 @@ public int hashCode() {
*/
Model getModel(ModelId tableId, ModelOption... options);
+ /**
+ * Returns the requested routine or {@code null} if not found.
+ *
+ * @throws BigQueryException upon failure
+ */
+ Routine getRoutine(String datasetId, String routineId, RoutineOption... options);
+
+ /**
+ * Returns the requested routine or {@code null} if not found.
+ *
+ * @throws BigQueryException upon failure
+ */
+ Routine getRoutine(RoutineId routineId, RoutineOption... options);
+
+ /** Lists the routines in the specified dataset. */
+ Page listRoutines(String datasetId, RoutineListOption... options);
+
+ /** Lists the routines in the specified dataset. */
+ Page listRoutines(DatasetId datasetId, RoutineListOption... options);
+
/**
* Lists the tables in the dataset. This method returns partial information on each table: ({@link
* Table#getTableId()}, {@link Table#getFriendlyName()}, {@link Table#getGeneratedId()} and type,
diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java
index 06b3f150b580..85fcadfdec14 100644
--- a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java
+++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/BigQueryImpl.java
@@ -125,6 +125,30 @@ public Page getNextPage() {
}
}
+ private static class RoutinePageFetcher implements NextPageFetcher {
+
+ private static final long serialVersionUID = 8611242311504201187L;
+ private final Map requestOptions;
+ private final BigQueryOptions serviceOptions;
+ private final DatasetId datasetId;
+
+ RoutinePageFetcher(
+ DatasetId datasetId,
+ BigQueryOptions serviceOptions,
+ String cursor,
+ Map optionMap) {
+ this.requestOptions =
+ PageImpl.nextRequestOptions(BigQueryRpc.Option.PAGE_TOKEN, cursor, optionMap);
+ this.serviceOptions = serviceOptions;
+ this.datasetId = datasetId;
+ }
+
+ @Override
+ public Page getNextPage() {
+ return listRoutines(datasetId, serviceOptions, requestOptions);
+ }
+ }
+
private static class JobPageFetcher implements NextPageFetcher {
private static final long serialVersionUID = 8536533282558245472L;
@@ -226,6 +250,34 @@ public com.google.api.services.bigquery.model.Table call() {
}
}
+ @Override
+ public Routine create(RoutineInfo routineInfo, RoutineOption... options) {
+ final com.google.api.services.bigquery.model.Routine routinePb =
+ routineInfo
+ .setProjectId(
+ Strings.isNullOrEmpty(routineInfo.getRoutineId().getProject())
+ ? getOptions().getProjectId()
+ : routineInfo.getRoutineId().getProject())
+ .toPb();
+ final Map optionsMap = optionMap(options);
+ try {
+ return Routine.fromPb(
+ this,
+ runWithRetries(
+ new Callable() {
+ @Override
+ public com.google.api.services.bigquery.model.Routine call() {
+ return bigQueryRpc.create(routinePb, optionsMap);
+ }
+ },
+ getOptions().getRetrySettings(),
+ EXCEPTION_HANDLER,
+ getOptions().getClock()));
+ } catch (RetryHelper.RetryHelperException e) {
+ throw BigQueryException.translateAndThrow(e);
+ }
+ }
+
@Override
public Job create(JobInfo jobInfo, JobOption... options) {
Supplier idProvider =
@@ -456,6 +508,32 @@ public Boolean call() {
}
}
+ @Override
+ public boolean delete(RoutineId routineId) {
+ final RoutineId completeRoutineId =
+ routineId.setProjectId(
+ Strings.isNullOrEmpty(routineId.getProject())
+ ? getOptions().getProjectId()
+ : routineId.getProject());
+ try {
+ return runWithRetries(
+ new Callable() {
+ @Override
+ public Boolean call() {
+ return bigQueryRpc.deleteRoutine(
+ completeRoutineId.getProject(),
+ completeRoutineId.getDataset(),
+ completeRoutineId.getRoutine());
+ }
+ },
+ getOptions().getRetrySettings(),
+ EXCEPTION_HANDLER,
+ getOptions().getClock());
+ } catch (RetryHelper.RetryHelperException e) {
+ throw BigQueryException.translateAndThrow(e);
+ }
+ }
+
@Override
public Dataset update(DatasetInfo datasetInfo, DatasetOption... options) {
final com.google.api.services.bigquery.model.Dataset datasetPb =
@@ -535,6 +613,34 @@ public com.google.api.services.bigquery.model.Model call() {
}
}
+ @Override
+ public Routine update(RoutineInfo routineInfo, RoutineOption... options) {
+ final com.google.api.services.bigquery.model.Routine routinePb =
+ routineInfo
+ .setProjectId(
+ Strings.isNullOrEmpty(routineInfo.getRoutineId().getProject())
+ ? getOptions().getProjectId()
+ : routineInfo.getRoutineId().getProject())
+ .toPb();
+ final Map optionsMap = optionMap(options);
+ try {
+ return Routine.fromPb(
+ this,
+ runWithRetries(
+ new Callable() {
+ @Override
+ public com.google.api.services.bigquery.model.Routine call() {
+ return bigQueryRpc.update(routinePb, optionsMap);
+ }
+ },
+ getOptions().getRetrySettings(),
+ EXCEPTION_HANDLER,
+ getOptions().getClock()));
+ } catch (RetryHelper.RetryHelperException e) {
+ throw BigQueryException.translateAndThrow(e);
+ }
+ }
+
@Override
public Table getTable(final String datasetId, final String tableId, TableOption... options) {
return getTable(TableId.of(datasetId, tableId), options);
@@ -612,6 +718,44 @@ public com.google.api.services.bigquery.model.Model call() {
}
}
+ @Override
+ public Routine getRoutine(String datasetId, String routineId, RoutineOption... options) {
+ return getRoutine(RoutineId.of(datasetId, routineId), options);
+ }
+
+ @Override
+ public Routine getRoutine(RoutineId routineId, RoutineOption... options) {
+ final RoutineId completeRoutineId =
+ routineId.setProjectId(
+ Strings.isNullOrEmpty(routineId.getProject())
+ ? getOptions().getProjectId()
+ : routineId.getProject());
+ final Map optionsMap = optionMap(options);
+ try {
+ com.google.api.services.bigquery.model.Routine answer =
+ runWithRetries(
+ new Callable() {
+ @Override
+ public com.google.api.services.bigquery.model.Routine call() {
+ return bigQueryRpc.getRoutine(
+ completeRoutineId.getProject(),
+ completeRoutineId.getDataset(),
+ completeRoutineId.getRoutine(),
+ optionsMap);
+ }
+ },
+ getOptions().getRetrySettings(),
+ EXCEPTION_HANDLER,
+ getOptions().getClock());
+ if (getOptions().getThrowNotFound() && answer == null) {
+ throw new BigQueryException(HTTP_NOT_FOUND, "Model not found");
+ }
+ return answer == null ? null : Routine.fromPb(this, answer);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw BigQueryException.translateAndThrow(e);
+ }
+ }
+
@Override
public Page
listTables(String datasetId, TableListOption... options) {
return listTables(
@@ -636,6 +780,18 @@ public Page listModels(DatasetId datasetId, ModelListOption... options) {
return listModels(completeDatasetId, getOptions(), optionMap(options));
}
+ @Override
+ public Page listRoutines(String datasetId, RoutineListOption... options) {
+ return listRoutines(
+ DatasetId.of(getOptions().getProjectId(), datasetId), getOptions(), optionMap(options));
+ }
+
+ @Override
+ public Page listRoutines(DatasetId datasetId, RoutineListOption... options) {
+ DatasetId completeDatasetId = datasetId.setProjectId(getOptions().getProjectId());
+ return listRoutines(completeDatasetId, getOptions(), optionMap(options));
+ }
+
@Override
public List listPartitions(TableId tableId) {
List partitions = new ArrayList();
@@ -730,6 +886,43 @@ public Model apply(com.google.api.services.bigquery.model.Model model) {
}
}
+ private static Page listRoutines(
+ final DatasetId datasetId,
+ final BigQueryOptions serviceOptions,
+ final Map optionsMap) {
+ try {
+ Tuple> result =
+ runWithRetries(
+ new Callable<
+ Tuple>>() {
+ @Override
+ public Tuple>
+ call() {
+ return serviceOptions
+ .getBigQueryRpcV2()
+ .listRoutines(datasetId.getProject(), datasetId.getDataset(), optionsMap);
+ }
+ },
+ serviceOptions.getRetrySettings(),
+ EXCEPTION_HANDLER,
+ serviceOptions.getClock());
+ String cursor = result.x();
+ Iterable routines =
+ Iterables.transform(
+ result.y(),
+ new Function() {
+ @Override
+ public Routine apply(com.google.api.services.bigquery.model.Routine routinePb) {
+ return Routine.fromPb(serviceOptions.getService(), routinePb);
+ }
+ });
+ return new PageImpl<>(
+ new RoutinePageFetcher(datasetId, serviceOptions, cursor, optionsMap), cursor, routines);
+ } catch (RetryHelper.RetryHelperException e) {
+ throw BigQueryException.translateAndThrow(e);
+ }
+ }
+
@Override
public InsertAllResponse insertAll(InsertAllRequest request) {
final TableId tableId =
diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/JobStatistics.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/JobStatistics.java
index ac6e4a85750a..388284c04aa3 100644
--- a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/JobStatistics.java
+++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/JobStatistics.java
@@ -317,6 +317,7 @@ public static class QueryStatistics extends JobStatistics {
private final Boolean cacheHit;
private final String ddlOperationPerformed;
private final TableId ddlTargetTable;
+ private final RoutineId ddlTargetRoutine;
private final Long estimatedBytesProcessed;
private final Long numDmlAffectedRows;
private final List referencedTables;
@@ -355,8 +356,16 @@ public StatementType apply(String constant) {
public static final StatementType CREATE_TABLE_AS_SELECT =
type.createAndRegister("CREATE_TABLE_AS_SELECT");
public static final StatementType CREATE_VIEW = type.createAndRegister("CREATE_VIEW");
+ public static final StatementType CREATE_MODEL = type.createAndRegister("CREATE_MODEL");
+ public static final StatementType CREATE_FUNCTION = type.createAndRegister("CREATE_FUNCTION");
+ public static final StatementType CREATE_PROCEDURE =
+ type.createAndRegister("CREATE_PROCEDURE");
+ public static final StatementType ALTER_TABLE = type.createAndRegister("ALTER_TABLE");
+ public static final StatementType ALTER_VIEW = type.createAndRegister("ALTER_VIEW");
public static final StatementType DROP_TABLE = type.createAndRegister("DROP_TABLE");
public static final StatementType DROP_VIEW = type.createAndRegister("DROP_VIEW");
+ public static final StatementType DROP_FUNCTION = type.createAndRegister("DROP_FUNCTION");
+ public static final StatementType DROP_PROCEDURE = type.createAndRegister("DROP_PROCEDURE");
public static final StatementType MERGE = type.createAndRegister("MERGE");
private StatementType(String constant) {
@@ -388,6 +397,7 @@ static final class Builder extends JobStatistics.Builder referencedTables;
@@ -411,6 +421,9 @@ private Builder(com.google.api.services.bigquery.model.JobStatistics statisticsP
if (statisticsPb.getQuery().getDdlTargetTable() != null) {
this.ddlTargetTable = TableId.fromPb(statisticsPb.getQuery().getDdlTargetTable());
}
+ if (statisticsPb.getQuery().getDdlTargetRoutine() != null) {
+ this.ddlTargetRoutine = RoutineId.fromPb(statisticsPb.getQuery().getDdlTargetRoutine());
+ }
this.estimatedBytesProcessed = statisticsPb.getQuery().getEstimatedBytesProcessed();
this.numDmlAffectedRows = statisticsPb.getQuery().getNumDmlAffectedRows();
this.totalBytesBilled = statisticsPb.getQuery().getTotalBytesBilled();
@@ -462,6 +475,11 @@ Builder setDDLTargetTable(TableId ddlTargetTable) {
return self();
}
+ Builder setDDLTargetRoutine(RoutineId ddlTargetRoutine) {
+ this.ddlTargetRoutine = ddlTargetRoutine;
+ return self();
+ }
+
Builder setEstimatedBytesProcessed(Long estimatedBytesProcessed) {
this.estimatedBytesProcessed = estimatedBytesProcessed;
return self();
@@ -534,6 +552,7 @@ private QueryStatistics(Builder builder) {
this.cacheHit = builder.cacheHit;
this.ddlOperationPerformed = builder.ddlOperationPerformed;
this.ddlTargetTable = builder.ddlTargetTable;
+ this.ddlTargetRoutine = builder.ddlTargetRoutine;
this.estimatedBytesProcessed = builder.estimatedBytesProcessed;
this.numDmlAffectedRows = builder.numDmlAffectedRows;
this.referencedTables = builder.referencedTables;
@@ -571,6 +590,11 @@ public TableId getDdlTargetTable() {
return ddlTargetTable;
}
+ /** [BETA] For DDL queries, returns the RoutineId of the targeted routine. */
+ public RoutineId getDdlTargetRoutine() {
+ return ddlTargetRoutine;
+ }
+
/** The original estimate of bytes processed for the job. */
public Long getEstimatedBytesProcessed() {
return estimatedBytesProcessed;
@@ -696,6 +720,9 @@ com.google.api.services.bigquery.model.JobStatistics toPb() {
if (ddlTargetTable != null) {
queryStatisticsPb.setDdlTargetTable(ddlTargetTable.toPb());
}
+ if (ddlTargetRoutine != null) {
+ queryStatisticsPb.setDdlTargetRoutine(ddlTargetRoutine.toPb());
+ }
if (referencedTables != null) {
queryStatisticsPb.setReferencedTables(
diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Routine.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Routine.java
new file mode 100644
index 000000000000..61c8848fb188
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Routine.java
@@ -0,0 +1,191 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigquery;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.cloud.bigquery.BigQuery.RoutineOption;
+import java.io.IOException;
+import java.io.ObjectInputStream;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * A Google BigQuery Routine.
+ *
+ *
Objects of this class are immutable. Operations that modify the routine like {@link #update}
+ * return a new object. To get a {@code routine} object with the most recent information use {@link
+ * #reload}.
+ */
+public class Routine extends RoutineInfo {
+
+ private final BigQueryOptions options;
+ private transient BigQuery bigquery;
+
+ public static class Builder extends RoutineInfo.Builder {
+
+ private final BigQuery bigquery;
+ private final RoutineInfo.BuilderImpl infoBuilder;
+
+ Builder(BigQuery bigquery, RoutineId routineId) {
+ this.bigquery = bigquery;
+ this.infoBuilder = new RoutineInfo.BuilderImpl();
+ this.infoBuilder.setRoutineId(routineId);
+ }
+
+ Builder(Routine routine) {
+ this.bigquery = routine.bigquery;
+ this.infoBuilder = new RoutineInfo.BuilderImpl(routine);
+ }
+
+ @Override
+ Builder setRoutineId(RoutineId id) {
+ infoBuilder.setRoutineId(id);
+ return this;
+ }
+
+ @Override
+ Builder setEtag(String etag) {
+ infoBuilder.setEtag(etag);
+ return this;
+ }
+
+ @Override
+ public Builder setRoutineType(String routineType) {
+ infoBuilder.setRoutineType(routineType);
+ return this;
+ }
+
+ @Override
+ Builder setCreationTime(Long creationMillis) {
+ infoBuilder.setCreationTime(creationMillis);
+ return this;
+ }
+
+ @Override
+ Builder setLastModifiedTime(Long lastModifiedMillis) {
+ infoBuilder.setLastModifiedTime(lastModifiedMillis);
+ return this;
+ }
+
+ @Override
+ public Builder setLanguage(String language) {
+ infoBuilder.setLanguage(language);
+ return this;
+ }
+
+ @Override
+ public Builder setArguments(List arguments) {
+ infoBuilder.setArguments(arguments);
+ return this;
+ }
+
+ @Override
+ public Builder setReturnType(StandardSQLDataType returnType) {
+ infoBuilder.setReturnType(returnType);
+ return this;
+ }
+
+ @Override
+ public Builder setImportedLibraries(List libraries) {
+ infoBuilder.setImportedLibraries(libraries);
+ return this;
+ }
+
+ @Override
+ public Builder setBody(String body) {
+ infoBuilder.setBody(body);
+ return this;
+ }
+
+ @Override
+ public Routine build() {
+ return new Routine(bigquery, infoBuilder);
+ }
+ }
+
+ Routine(BigQuery bigquery, RoutineInfo.BuilderImpl infoBuilder) {
+ super(infoBuilder);
+ this.bigquery = checkNotNull(bigquery);
+ this.options = bigquery.getOptions();
+ }
+
+ /** Checks if this routine exists. */
+ public boolean exists() {
+ return bigquery.getRoutine(getRoutineId(), RoutineOption.fields()) != null;
+ }
+
+ /**
+ * Fetches this routine's latest information. Returns {@code null} if the routine does not exist.
+ */
+ public Routine reload(RoutineOption... options) {
+ return bigquery.getRoutine(getRoutineId(), options);
+ }
+
+ /**
+ * Update's the routine's information with this Routine's information. This method does not allow
+ * changing the RoutineId identifier of the routine. A new {@code Routine} is returned.
+ */
+ public Routine update(RoutineOption... options) {
+ return bigquery.update(this, options);
+ }
+
+ /**
+ * Deletes this routine.
+ *
+ * @return {@code true} if routine was deleted, {@code false} if it was not found
+ * @throws BigQueryException upon failure
+ */
+ public boolean delete() {
+ return bigquery.delete(getRoutineId());
+ }
+
+ /** Returns the routine's {@code BigQuery} object used to issue requests. */
+ public BigQuery getBigQuery() {
+ return bigquery;
+ }
+
+ @Override
+ public Builder toBuilder() {
+ return new Builder(this);
+ }
+
+ @Override
+ public final boolean equals(Object obj) {
+ if (obj == this) {
+ return true;
+ }
+ if (obj == null || !obj.getClass().equals(Routine.class)) {
+ return false;
+ }
+ Routine other = (Routine) obj;
+ return Objects.equals(toPb(), other.toPb()) && Objects.equals(options, other.options);
+ }
+
+ public final int hashCode() {
+ return Objects.hash(super.hashCode(), options);
+ }
+
+ public void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {
+ in.defaultReadObject();
+ this.bigquery = options.getService();
+ }
+
+ static Routine fromPb(
+ BigQuery bigquery, com.google.api.services.bigquery.model.Routine routinePb) {
+ return new Routine(bigquery, new RoutineInfo.BuilderImpl(routinePb));
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineArgument.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineArgument.java
new file mode 100644
index 000000000000..d36d1f229517
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineArgument.java
@@ -0,0 +1,117 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigquery;
+
+import com.google.api.services.bigquery.model.Argument;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Function;
+import javax.annotation.Nullable;
+
+/** An argument for a BigQuery Routine. */
+@AutoValue
+public abstract class RoutineArgument {
+
+ static final Function FROM_PB_FUNCTION =
+ new Function() {
+ @Override
+ public RoutineArgument apply(Argument pb) {
+ return RoutineArgument.fromPb(pb);
+ }
+ };
+ static final Function TO_PB_FUNCTION =
+ new Function() {
+ @Override
+ public Argument apply(RoutineArgument argument) {
+ return argument.toPb();
+ }
+ };
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+ /** Sets the argument name. */
+ public abstract Builder setName(String name);
+
+ /**
+ * Sets the kind of argument.
+ *
+ *
A FIXED_TYPE argument is a fully specified type. It can be a struct or an array, but not a
+ * table.
+ *
+ *
An ANY_TYPE argument is any type. It can be a struct or an array, but not a table.
+ */
+ public abstract Builder setKind(String kind);
+
+ /**
+ * Optionally specifies the input/output mode of the argument.
+ *
+ *
An IN mode argument is input-only. An OUT mode argument is output-only. An INOUT mode
+ * argument is both an input and output.
+ */
+ public abstract Builder setMode(String mode);
+
+ /**
+ * Sets the data type specification for the argument. It is required except for ANY_TYPE
+ * argument kinds.
+ */
+ public abstract Builder setDataType(StandardSQLDataType dataType);
+
+ /** Creates a {@code RoutineArgument} object. */
+ public abstract RoutineArgument build();
+ }
+
+ /** Returns the name of the argument. */
+ @Nullable
+ public abstract String getName();
+
+ /** Returns the kind of the argument. */
+ @Nullable
+ public abstract String getKind();
+
+ /** Returns the mode of the argument. */
+ @Nullable
+ public abstract String getMode();
+
+ @Nullable
+ public abstract StandardSQLDataType getDataType();
+
+ /** Returns a builder pre-populated using the current values of this {@code RoutineArgument}. */
+ public abstract Builder toBuilder();
+
+ /** Returns a builder for a {@Code RoutineArgument} object. */
+ public static Builder newBuilder() {
+ return new AutoValue_RoutineArgument.Builder();
+ }
+
+ Argument toPb() {
+ Argument argumentPb =
+ new Argument().setName(getName()).setArgumentKind(getKind()).setMode(getMode());
+ if (getDataType() != null) {
+ argumentPb.setDataType(getDataType().toPb());
+ }
+ return argumentPb;
+ }
+
+ static RoutineArgument fromPb(Argument argumentPb) {
+ Builder builder = newBuilder();
+ builder.setName(argumentPb.getName());
+ builder.setKind(argumentPb.getArgumentKind());
+ builder.setMode(argumentPb.getMode());
+ if (argumentPb.getDataType() != null) {
+ builder.setDataType(StandardSQLDataType.fromPb(argumentPb.getDataType()));
+ }
+ return builder.build();
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineId.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineId.java
new file mode 100644
index 000000000000..d5d3c5bfe982
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineId.java
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.bigquery;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.api.services.bigquery.model.RoutineReference;
+import com.google.common.base.Function;
+import com.google.common.base.Preconditions;
+import com.google.common.base.Strings;
+import java.io.Serializable;
+import java.util.Objects;
+
+/** RoutineId represents the identifier for a given Routine. */
+public final class RoutineId implements Serializable {
+
+ static final Function FROM_PB_FUNCTION =
+ new Function() {
+ @Override
+ public RoutineId apply(RoutineReference pb) {
+ return RoutineId.fromPb(pb);
+ }
+ };
+ static final Function TO_PB_FUNCTION =
+ new Function() {
+ @Override
+ public RoutineReference apply(RoutineId routineId) {
+ return routineId.toPb();
+ }
+ };
+
+ private final String project;
+ private final String dataset;
+ private final String routine;
+
+ /** Return corresponding project ID for this routine. * */
+ public String getProject() {
+ return project;
+ }
+
+ /** Return corresponding dataset ID for this routine. * */
+ public String getDataset() {
+ return dataset;
+ }
+
+ /** Return corresponding routine ID for this routine. * */
+ public String getRoutine() {
+ return routine;
+ }
+
+ private RoutineId(String project, String dataset, String routine) {
+ this.project = project;
+ this.dataset = dataset;
+ this.routine = routine;
+ }
+
+ /** Creates a routine identity given project, dataset, and routine identifiers. * */
+ public static RoutineId of(String project, String dataset, String routine) {
+ return new RoutineId(checkNotNull(project), checkNotNull(dataset), checkNotNull(routine));
+ }
+
+ /** Creates a routine identity given dataset and routine identifiers. * */
+ public static RoutineId of(String dataset, String routine) {
+ return new RoutineId(null, checkNotNull(dataset), checkNotNull(routine));
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this
+ || obj instanceof RoutineId && Objects.equals(toPb(), ((RoutineId) obj).toPb());
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(project, dataset, routine);
+ }
+
+ @Override
+ public String toString() {
+ return toPb().toString();
+ }
+
+ RoutineId setProjectId(String projectId) {
+ Preconditions.checkArgument(
+ !Strings.isNullOrEmpty(projectId), "Provided projectId is null or empty");
+ return RoutineId.of(projectId, getDataset(), getRoutine());
+ }
+
+ RoutineReference toPb() {
+ return new RoutineReference().setProjectId(project).setDatasetId(dataset).setRoutineId(routine);
+ }
+
+ static RoutineId fromPb(RoutineReference routineRef) {
+ return new RoutineId(
+ routineRef.getProjectId(), routineRef.getDatasetId(), routineRef.getRoutineId());
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineInfo.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineInfo.java
new file mode 100644
index 000000000000..1474b1994c9e
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/RoutineInfo.java
@@ -0,0 +1,405 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigquery;
+
+import static com.google.common.base.Preconditions.checkNotNull;
+
+import com.google.api.services.bigquery.model.Routine;
+import com.google.common.base.Function;
+import com.google.common.base.MoreObjects;
+import com.google.common.base.Strings;
+import com.google.common.collect.Lists;
+import java.io.Serializable;
+import java.util.Collections;
+import java.util.List;
+import java.util.Objects;
+
+/**
+ * Google BigQuery routine information. A Routine is an API abstraction that encapsulates several
+ * related concepts inside the BigQuery service, including scalar user defined functions (UDFS) and
+ * stored procedures.
+ *
+ *
For more information about the REST representation of routines, see:
+ * https://cloud.google.com/bigquery/docs/reference/rest/v2/routines
+ *
+ *
For more information about working with scalar functions, see:
+ * https://cloud.google.com/bigquery/docs/reference/standard-sql/user-defined-functions
+ */
+public class RoutineInfo implements Serializable {
+
+ static final Function FROM_PB_FUNCTION =
+ new Function() {
+ @Override
+ public RoutineInfo apply(Routine pb) {
+ return RoutineInfo.fromPb(pb);
+ }
+ };
+ static final Function TO_PB_FUNCTION =
+ new Function() {
+ @Override
+ public Routine apply(RoutineInfo routineInfo) {
+ return routineInfo.toPb();
+ }
+ };
+
+ private final RoutineId routineId;
+ private final String etag;
+ private final String routineType;
+ private final Long creationTime;
+ private final Long lastModifiedTime;
+ private final String language;
+ private final List argumentList;
+ private final StandardSQLDataType returnType;
+ private final List importedLibrariesList;
+ private final String body;
+
+ public abstract static class Builder {
+
+ abstract Builder setRoutineId(RoutineId id);
+
+ abstract Builder setEtag(String etag);
+
+ /**
+ * Sets the routine type for the Builder (e.g. SCALAR_FUNCTION).
+ *
+ *
See https://cloud.google.com/bigquery/docs/reference/rest/v2/routines
+ */
+ public abstract Builder setRoutineType(String routineType);
+
+ abstract Builder setCreationTime(Long creationMillis);
+
+ abstract Builder setLastModifiedTime(Long lastModifiedMillis);
+
+ /** Sets the language for the routine (e.g. SQL or JAVASCRIPT) */
+ public abstract Builder setLanguage(String language);
+
+ /** Specifies the list of input/output arguments for the routine. */
+ public abstract Builder setArguments(List argumentList);
+
+ /**
+ * Sets the return type of the routine.
+ *
+ *
Optional if language = "SQL"; required otherwise.
+ *
+ *
If absent, the return type is inferred from definitionBody at query time in each query
+ * that references this routine. If present, then the evaluated result will be cast to the
+ * specified returned type at query time.
+ */
+ public abstract Builder setReturnType(StandardSQLDataType returnType);
+
+ /**
+ * Optional. If language = "JAVASCRIPT", this field stores the path of the imported JAVASCRIPT
+ * libraries as a list of gs:// URLs.
+ */
+ public abstract Builder setImportedLibraries(List importedLibrariesList);
+
+ /**
+ * Required. The body of the routine.
+ *
+ *
For functions, this is the expression in the AS clause.
+ *
+ *
If language=SQL, it is the substring inside (but excluding) the parentheses. For example,
+ * for the function created with the following statement:
+ *
+ *
CREATE FUNCTION JoinLines(x string, y string) as (concat(x, "\n", y))
+ *
+ *
The definitionBody is concat(x, "\n", y) (\n is not replaced with linebreak).
+ *
+ *
If language=JAVASCRIPT, it is the evaluated string in the AS clause. For example, for the
+ * function created with the following statement:
+ *
+ *
CREATE FUNCTION f() RETURNS STRING LANGUAGE js AS 'return "\n";\n'
+ *
+ *
The definitionBody is
+ *
+ *
return "\n";\n
+ *
+ *
Note that both \n are replaced with linebreaks.
+ */
+ public abstract Builder setBody(String body);
+
+ /** Creates a {@code RoutineInfo} object. */
+ public abstract RoutineInfo build();
+ }
+
+ static class BuilderImpl extends Builder {
+ private RoutineId routineId;
+ private String etag;
+ private String routineType;
+ private Long creationTime;
+ private Long lastModifiedTime;
+ private String language;
+ private List argumentList;
+ private StandardSQLDataType returnType;
+ private List importedLibrariesList;
+ private String body;
+
+ BuilderImpl() {}
+
+ BuilderImpl(RoutineInfo routineInfo) {
+ this.routineId = routineInfo.routineId;
+ this.etag = routineInfo.etag;
+ this.routineType = routineInfo.routineType;
+ this.creationTime = routineInfo.creationTime;
+ this.lastModifiedTime = routineInfo.lastModifiedTime;
+ this.language = routineInfo.language;
+ this.argumentList = routineInfo.argumentList;
+ this.returnType = routineInfo.returnType;
+ this.importedLibrariesList = routineInfo.importedLibrariesList;
+ this.body = routineInfo.body;
+ }
+
+ BuilderImpl(Routine routinePb) {
+ this.routineId = RoutineId.fromPb(routinePb.getRoutineReference());
+ this.etag = routinePb.getEtag();
+ this.routineType = routinePb.getRoutineType();
+ this.creationTime = routinePb.getCreationTime();
+ this.lastModifiedTime = routinePb.getLastModifiedTime();
+ this.language = routinePb.getLanguage();
+ if (routinePb.getArguments() != null) {
+ this.argumentList =
+ Lists.transform(routinePb.getArguments(), RoutineArgument.FROM_PB_FUNCTION);
+ }
+ if (routinePb.getReturnType() != null) {
+ this.returnType = StandardSQLDataType.fromPb(routinePb.getReturnType());
+ }
+ if (routinePb.getImportedLibraries() == null) {
+ this.importedLibrariesList = Collections.emptyList();
+ } else {
+ this.importedLibrariesList = routinePb.getImportedLibraries();
+ }
+ this.body = routinePb.getDefinitionBody();
+ }
+
+ @Override
+ Builder setRoutineId(RoutineId id) {
+ this.routineId = id;
+ return this;
+ }
+
+ @Override
+ Builder setEtag(String etag) {
+ this.etag = etag;
+ return this;
+ }
+
+ @Override
+ public Builder setRoutineType(String routineType) {
+ this.routineType = routineType;
+ return this;
+ }
+
+ @Override
+ Builder setCreationTime(Long creationMillis) {
+ this.creationTime = creationMillis;
+ return this;
+ }
+
+ @Override
+ Builder setLastModifiedTime(Long lastModifiedMillis) {
+ this.lastModifiedTime = lastModifiedMillis;
+ return this;
+ }
+
+ @Override
+ public Builder setLanguage(String language) {
+ this.language = language;
+ return this;
+ }
+
+ @Override
+ public Builder setArguments(List argumentList) {
+ this.argumentList = argumentList;
+ return this;
+ }
+
+ @Override
+ public Builder setReturnType(StandardSQLDataType returnType) {
+ this.returnType = returnType;
+ return this;
+ }
+
+ @Override
+ public Builder setImportedLibraries(List importedLibrariesList) {
+ this.importedLibrariesList = importedLibrariesList;
+ return this;
+ }
+
+ @Override
+ public Builder setBody(String body) {
+ this.body = body;
+ return this;
+ }
+
+ @Override
+ public RoutineInfo build() {
+ return new RoutineInfo(this);
+ }
+ }
+
+ RoutineInfo(BuilderImpl builder) {
+ this.routineId = checkNotNull(builder.routineId);
+ this.etag = builder.etag;
+ this.routineType = builder.routineType;
+ this.creationTime = builder.creationTime;
+ this.lastModifiedTime = builder.lastModifiedTime;
+ this.language = builder.language;
+ this.argumentList = builder.argumentList;
+ this.returnType = builder.returnType;
+ this.importedLibrariesList = builder.importedLibrariesList;
+ this.body = builder.body;
+ }
+
+ /** Returns the RoutineId identified for the routine resource. * */
+ public RoutineId getRoutineId() {
+ return routineId;
+ }
+
+ /** Returns the hash of the routine resource. */
+ public String getEtag() {
+ return etag;
+ }
+
+ /** Returns the type of the routine, e.g. SCALAR_FUNCTION. */
+ public String getRoutineType() {
+ return routineType;
+ }
+
+ /** Returns the creation time of the routine, represented as milliseconds since the epoch. */
+ public Long getCreationTime() {
+ return creationTime;
+ }
+
+ /**
+ * Returns the last modification time of the routine, represented as milliseconds since the epoch.
+ */
+ public Long getLastModifiedTime() {
+ return lastModifiedTime;
+ }
+
+ /**
+ * Returns the language of the routine. Currently supported languages include SQL and JAVASCRIPT.
+ */
+ public String getLanguage() {
+ return language;
+ }
+
+ /** Returns the list of arguments for the routine. */
+ public List getArguments() {
+ return argumentList;
+ }
+
+ /** If specified, returns the data type returned from the routine. */
+ public StandardSQLDataType getReturnType() {
+ return returnType;
+ }
+
+ /**
+ * Returns the list of imported libraries for the routine. Only relevant for routines implemented
+ * using the JAVASCRIPT language.
+ */
+ public List getImportedLibraries() {
+ return importedLibrariesList;
+ }
+
+ /** Returns the definition body of the routine. */
+ public String getBody() {
+ return body;
+ }
+
+ /** Returns a builder pre-populated using the current values of this routine. */
+ public Builder toBuilder() {
+ return new BuilderImpl(this);
+ }
+
+ @Override
+ public String toString() {
+ return MoreObjects.toStringHelper(this)
+ .add("routineId", routineId)
+ .add("etag", etag)
+ .add("routineType", routineType)
+ .add("creationTime", creationTime)
+ .add("lastModifiedTime", lastModifiedTime)
+ .add("language", language)
+ .add("arguments", argumentList)
+ .add("returnType", returnType)
+ .add("importedLibrariesList", importedLibrariesList)
+ .add("body", body)
+ .toString();
+ }
+
+ @Override
+ public int hashCode() {
+ return Objects.hash(
+ routineId,
+ etag,
+ routineType,
+ creationTime,
+ lastModifiedTime,
+ language,
+ argumentList,
+ returnType,
+ importedLibrariesList,
+ body);
+ }
+
+ @Override
+ public boolean equals(Object obj) {
+ return obj == this
+ || obj != null
+ && obj.getClass().equals(RoutineInfo.class)
+ && Objects.equals(toPb(), ((RoutineInfo) obj).toPb());
+ }
+
+ /** Returns a builder for a {@code RoutineInfo} object given routine identity. */
+ public static Builder newBuilder(RoutineId routineId) {
+ return new BuilderImpl().setRoutineId(routineId);
+ }
+
+ /** Returns a {@code RoutineInfo} object given routine identity. */
+ public static RoutineInfo of(RoutineId routineId) {
+ return newBuilder(routineId).build();
+ }
+
+ RoutineInfo setProjectId(String projectId) {
+ if (Strings.isNullOrEmpty(getRoutineId().getProject())) {
+ return toBuilder().setRoutineId(getRoutineId().setProjectId(projectId)).build();
+ }
+ return this;
+ }
+
+ Routine toPb() {
+ Routine routinePb =
+ new Routine()
+ .setEtag(getEtag())
+ .setRoutineType(getRoutineType())
+ .setDefinitionBody(getBody())
+ .setCreationTime(getCreationTime())
+ .setLastModifiedTime(getLastModifiedTime())
+ .setLanguage(getLanguage());
+ if (getRoutineId() != null) {
+ routinePb.setRoutineReference(getRoutineId().toPb());
+ }
+ if (getArguments() != null) {
+ routinePb.setArguments(Lists.transform(getArguments(), RoutineArgument.TO_PB_FUNCTION));
+ }
+ return routinePb;
+ }
+
+ static RoutineInfo fromPb(Routine routinePb) {
+ return new BuilderImpl(routinePb).build();
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLDataType.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLDataType.java
new file mode 100644
index 000000000000..99ed10af1461
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLDataType.java
@@ -0,0 +1,100 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigquery;
+
+import com.google.api.services.bigquery.model.StandardSqlDataType;
+import com.google.auto.value.AutoValue;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+
+/** Represents Standard SQL data type information. */
+@AutoValue
+public abstract class StandardSQLDataType implements Serializable {
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+ /** Sets the type of an array's elements, when the TypeKind is ARRAY. */
+ public abstract Builder setArrayElementType(StandardSQLDataType arrayElementType);
+
+ /** Sets the struct type definition (list of fields) when the TypeKind is STRUCT. */
+ public abstract Builder setStructType(StandardSQLStructType structType);
+
+ /**
+ * Sets the top-level type of this data type. Can be any standard SQL data type. For more
+ * information, see https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types
+ */
+ public abstract Builder setTypeKind(String typeKind);
+
+ /** Creates a {@code StandardSQLDataType} object. */
+ public abstract StandardSQLDataType build();
+ }
+
+ /**
+ * Returns the type kind of the data type.
+ *
+ *
Can be any standard SQL data type. For more information, see
+ * https://cloud.google.com/bigquery/docs/reference/standard-sql/data-types
+ */
+ public abstract String getTypeKind();
+
+ /** Returns the type of an ARRAY's elements. */
+ @Nullable
+ public abstract StandardSQLDataType getArrayElementType();
+
+ /** Returns the struct definition's list of fields for a STRUCT type. */
+ @Nullable
+ public abstract StandardSQLStructType getStructType();
+
+ public abstract Builder toBuilder();
+
+ public static Builder newBuilder() {
+ return new AutoValue_StandardSQLDataType.Builder();
+ }
+
+ /** Returns a new builder initialized with the type kind. */
+ public static Builder newBuilder(String typeKind) {
+ return newBuilder().setTypeKind(typeKind);
+ }
+
+ /** Returns a new builder initialized with a StandardSQLTypeName as the type kind. */
+ public static Builder newBuilder(StandardSQLTypeName typeName) {
+ return newBuilder().setTypeKind(typeName.toString());
+ }
+
+ StandardSqlDataType toPb() {
+ StandardSqlDataType dataTypePb = new StandardSqlDataType();
+ dataTypePb.setTypeKind(getTypeKind());
+ if (getArrayElementType() != null) {
+ dataTypePb.setArrayElementType(getArrayElementType().toPb());
+ }
+ if (getStructType() != null) {
+ dataTypePb.setStructType(getStructType().toPb());
+ }
+ return dataTypePb;
+ }
+
+ static StandardSQLDataType fromPb(StandardSqlDataType dataTypePb) {
+ Builder builder = newBuilder();
+ builder.setTypeKind(dataTypePb.getTypeKind());
+ if (dataTypePb.getArrayElementType() != null) {
+ builder.setArrayElementType(StandardSQLDataType.fromPb(dataTypePb.getArrayElementType()));
+ }
+ if (dataTypePb.getStructType() != null) {
+ builder.setStructType(StandardSQLStructType.fromPb(dataTypePb.getStructType()));
+ }
+ return builder.build();
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLField.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLField.java
new file mode 100644
index 000000000000..013742548720
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLField.java
@@ -0,0 +1,101 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package com.google.cloud.bigquery;
+
+import com.google.api.services.bigquery.model.StandardSqlField;
+import com.google.auto.value.AutoValue;
+import com.google.common.base.Function;
+import java.io.Serializable;
+import javax.annotation.Nullable;
+
+/** A Google BigQuery SQL Field. */
+@AutoValue
+public abstract class StandardSQLField implements Serializable {
+
+ static final Function FROM_PB_FUNCTION =
+ new Function() {
+ @Override
+ public StandardSQLField apply(StandardSqlField pb) {
+ return StandardSQLField.fromPb(pb);
+ }
+ };
+ static final Function TO_PB_FUNCTION =
+ new Function() {
+ @Override
+ public StandardSqlField apply(StandardSQLField field) {
+ return field.toPb();
+ }
+ };
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ /** Sets the name of the field. */
+ public abstract Builder setName(String name);
+
+ /** Sets the data type of the field. */
+ public abstract Builder setDataType(StandardSQLDataType dataType);
+
+ /** Creates a {@code StandardSQLField} object. */
+ public abstract StandardSQLField build();
+ }
+
+ /** Returns the field name. */
+ @Nullable
+ public abstract String getName();
+
+ /** Returns the field's data type. */
+ public abstract StandardSQLDataType getDataType();
+
+ /** Returns a builder pre-populated using the current values of this field. */
+ public abstract Builder toBuilder();
+
+ /** Returns a builder for a {@code StandardSQLField} object. */
+ public static Builder newBuilder() {
+ return new AutoValue_StandardSQLField.Builder();
+ }
+
+ /** Returns a builder for a {@code StandardSQLField} object with the specified data type. */
+ public static Builder newBuilder(StandardSQLDataType dataType) {
+ return newBuilder().setDataType(dataType);
+ }
+
+ /**
+ * Returns a builder for a {@code StandardSQLField} object with the specified field name and data
+ * type.
+ */
+ public static Builder newBuilder(String name, StandardSQLDataType dataType) {
+ return newBuilder().setName(name).setDataType(dataType);
+ }
+
+ StandardSqlField toPb() {
+ StandardSqlField fieldPb = new StandardSqlField();
+ fieldPb.setName(getName());
+ if (getDataType() != null) {
+ fieldPb.setType(getDataType().toPb());
+ }
+ return fieldPb;
+ }
+
+ static StandardSQLField fromPb(StandardSqlField fieldPb) {
+ Builder builder = newBuilder();
+ builder.setName(fieldPb.getName());
+ if (fieldPb.getType() != null) {
+ builder.setDataType(StandardSQLDataType.fromPb(fieldPb.getType()));
+ }
+ return builder.build();
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLStructType.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLStructType.java
new file mode 100644
index 000000000000..43844916ec12
--- /dev/null
+++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardSQLStructType.java
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2019 Google LLC
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.google.cloud.bigquery;
+
+import com.google.api.services.bigquery.model.StandardSqlStructType;
+import com.google.auto.value.AutoValue;
+import com.google.common.collect.Lists;
+import java.io.Serializable;
+import java.util.List;
+
+/** A set of fields contained within a SQL STRUCT in Google BigQuery. */
+@AutoValue
+public abstract class StandardSQLStructType implements Serializable {
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ /** Sets the fields of the struct type. */
+ public abstract Builder setFields(List fields);
+
+ /** Creates a {@code StandardSQLStructType} object. */
+ public abstract StandardSQLStructType build();
+ }
+
+ /** Returns the list of fields within a struct type. */
+ public abstract List getFields();
+
+ /** Returns a builder pre-populated using the current values of this field. */
+ public abstract Builder toBuilder();
+
+ /** Returns a builder for a {@code StandardSQLStructType} object. */
+ public static Builder newBuilder() {
+ return new AutoValue_StandardSQLStructType.Builder();
+ }
+
+ /** Returns a builder for a {@code StandardSQLStructType} object with the specified fields. */
+ public static Builder newBuilder(List fieldList) {
+ return newBuilder().setFields(fieldList);
+ }
+
+ static StandardSQLStructType fromPb(
+ com.google.api.services.bigquery.model.StandardSqlStructType structTypePb) {
+ Builder builder = newBuilder();
+ if (structTypePb.getFields() != null) {
+ builder.setFields(
+ Lists.transform(structTypePb.getFields(), StandardSQLField.FROM_PB_FUNCTION));
+ }
+ return builder.build();
+ }
+
+ StandardSqlStructType toPb() {
+ StandardSqlStructType structTypePb = new StandardSqlStructType();
+ if (getFields() != null) {
+ structTypePb.setFields(Lists.transform(getFields(), StandardSQLField.TO_PB_FUNCTION));
+ }
+ return structTypePb;
+ }
+}
diff --git a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/BigQueryRpc.java b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/BigQueryRpc.java
index 8255bcfd5a56..a0dde557d259 100644
--- a/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/BigQueryRpc.java
+++ b/google-cloud-clients/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/spi/v2/BigQueryRpc.java
@@ -21,6 +21,7 @@
import com.google.api.services.bigquery.model.GetQueryResultsResponse;
import com.google.api.services.bigquery.model.Job;
import com.google.api.services.bigquery.model.Model;
+import com.google.api.services.bigquery.model.Routine;
import com.google.api.services.bigquery.model.Table;
import com.google.api.services.bigquery.model.TableDataInsertAllRequest;
import com.google.api.services.bigquery.model.TableDataInsertAllResponse;
@@ -158,7 +159,7 @@ Tuple> listTables(
boolean deleteTable(String projectId, String datasetId, String tableId);
/**
- * Updates table information.
+ * Updates model information.
*
* @throws BigQueryException upon failure
*/
@@ -187,6 +188,37 @@ Tuple> listModels(
*/
boolean deleteModel(String projectId, String datasetId, String modelId);
+ /**
+ * Creates the requested routine.
+ *
+ * @throws BigQueryException upon failure
+ */
+ Routine create(Routine routine, Map