diff --git a/README.md b/README.md
index b7a5c463fc..371a1f93ea 100644
--- a/README.md
+++ b/README.md
@@ -53,20 +53,20 @@ If you are using Maven without the BOM, add this to your dependencies:
If you are using Gradle 5.x or later, add this to your dependencies:
```Groovy
-implementation platform('com.google.cloud:libraries-bom:26.16.0')
+implementation platform('com.google.cloud:libraries-bom:26.17.0')
implementation 'com.google.cloud:google-cloud-bigquery'
```
If you are using Gradle without BOM, add this to your dependencies:
```Groovy
-implementation 'com.google.cloud:google-cloud-bigquery:2.27.0'
+implementation 'com.google.cloud:google-cloud-bigquery:2.27.1'
```
If you are using SBT, add this to your dependencies:
```Scala
-libraryDependencies += "com.google.cloud" % "google-cloud-bigquery" % "2.27.0"
+libraryDependencies += "com.google.cloud" % "google-cloud-bigquery" % "2.27.1"
```
@@ -145,6 +145,7 @@ Samples are in the [`samples/`](https://github.com/googleapis/java-bigquery/tree
| Create Table Cmek | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/CreateTableCmek.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/CreateTableCmek.java) |
| Create Table External Hive Partitioned | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/CreateTableExternalHivePartitioned.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/CreateTableExternalHivePartitioned.java) |
| Create Table Without Schema | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/CreateTableWithoutSchema.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/CreateTableWithoutSchema.java) |
+| Create Tables With Primary And Foreign Keys | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/CreateTablesWithPrimaryAndForeignKeys.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/CreateTablesWithPrimaryAndForeignKeys.java) |
| Create View | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/CreateView.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/CreateView.java) |
| Dataset Exists | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/DatasetExists.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/DatasetExists.java) |
| Ddl Create View | [source code](https://github.com/googleapis/java-bigquery/blob/main/samples/snippets/src/main/java/com/example/bigquery/DdlCreateView.java) | [![Open in Cloud Shell][shell_img]](https://console.cloud.google.com/cloudshell/open?git_repo=https://github.com/googleapis/java-bigquery&page=editor&open_in_editor=samples/snippets/src/main/java/com/example/bigquery/DdlCreateView.java) |
@@ -350,7 +351,7 @@ Java is a registered trademark of Oracle and/or its affiliates.
[kokoro-badge-link-5]: http://storage.googleapis.com/cloud-devrel-public/java/badges/java-bigquery/java11.html
[stability-image]: https://img.shields.io/badge/stability-stable-green
[maven-version-image]: https://img.shields.io/maven-central/v/com.google.cloud/google-cloud-bigquery.svg
-[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-bigquery/2.27.0
+[maven-version-link]: https://central.sonatype.com/artifact/com.google.cloud/google-cloud-bigquery/2.27.1
[authentication]: https://github.com/googleapis/google-cloud-java#authentication
[auth-scopes]: https://developers.google.com/identity/protocols/oauth2/scopes
[predefined-iam-roles]: https://cloud.google.com/iam/docs/understanding-roles#predefined_roles
diff --git a/google-cloud-bigquery/clirr-ignored-differences.xml b/google-cloud-bigquery/clirr-ignored-differences.xml
index 5fe634cca7..784a3c9626 100644
--- a/google-cloud-bigquery/clirr-ignored-differences.xml
+++ b/google-cloud-bigquery/clirr-ignored-differences.xml
@@ -44,10 +44,19 @@
com/google/cloud/bigquery/TableInfo*
*DefaultCollation(*)
-
7013
com/google/cloud/bigquery/TableInfo*
*CloneDefinition(*)
+
+ 7013
+ com/google/cloud/bigquery/StandardTableDefinition*
+ *TableConstraints(*)
+
+
+ 7013
+ com/google/cloud/bigquery/TableInfo*
+ *TableConstraints(*)
+
\ No newline at end of file
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ColumnReference.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ColumnReference.java
new file mode 100644
index 0000000000..3dc688be5f
--- /dev/null
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ColumnReference.java
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2023 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.auto.value.AutoValue;
+import com.google.common.annotations.VisibleForTesting;
+import javax.annotation.Nullable;
+
+@AutoValue
+public abstract class ColumnReference {
+ public static ColumnReference.Builder newBuilder() {
+ return new AutoValue_ColumnReference.Builder();
+ }
+
+ static ColumnReference fromPb(
+ com.google.api.services.bigquery.model.TableConstraints.ForeignKeys.ColumnReferences
+ columnReference) {
+ ColumnReference.Builder builder = newBuilder();
+
+ if (columnReference.getReferencedColumn() != null) {
+ builder.setReferencedColumn(columnReference.getReferencedColumn());
+ }
+
+ if (columnReference.getReferencingColumn() != null) {
+ builder.setReferencingColumn(columnReference.getReferencingColumn());
+ }
+
+ return builder.build();
+ }
+
+ com.google.api.services.bigquery.model.TableConstraints.ForeignKeys.ColumnReferences toPb() {
+
+ com.google.api.services.bigquery.model.TableConstraints.ForeignKeys.ColumnReferences
+ columnReference =
+ new com.google.api.services.bigquery.model.TableConstraints.ForeignKeys
+ .ColumnReferences();
+ columnReference.setReferencedColumn(getReferencedColumn());
+ columnReference.setReferencingColumn(getReferencingColumn());
+
+ return columnReference;
+ }
+
+ @Nullable
+ public abstract String getReferencedColumn();
+
+ @Nullable
+ public abstract String getReferencingColumn();
+
+ /** Returns a builder for column reference. */
+ @VisibleForTesting
+ public abstract ColumnReference.Builder toBuilder();
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ /** The target column of this reference. * */
+ public abstract ColumnReference.Builder setReferencedColumn(String referencedColumn);
+
+ /** The source column of this reference. * */
+ public abstract ColumnReference.Builder setReferencingColumn(String referencingColumn);
+
+ /** Creates a {@code ColumnReference} object. */
+ public abstract ColumnReference build();
+ }
+}
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ForeignKey.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ForeignKey.java
new file mode 100644
index 0000000000..69c2f74346
--- /dev/null
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/ForeignKey.java
@@ -0,0 +1,110 @@
+/*
+ * Copyright 2023 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.auto.value.AutoValue;
+import com.google.common.annotations.VisibleForTesting;
+import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+@AutoValue
+public abstract class ForeignKey implements Serializable {
+ public static ForeignKey.Builder newBuilder() {
+ return new AutoValue_ForeignKey.Builder();
+ }
+
+ static ForeignKey fromPb(
+ com.google.api.services.bigquery.model.TableConstraints.ForeignKeys foreignKey) {
+ ForeignKey.Builder builder = newBuilder();
+
+ if (foreignKey.getName() != null) {
+ builder.setName(foreignKey.getName());
+ }
+
+ if (foreignKey.getReferencedTable() != null) {
+ com.google.api.services.bigquery.model.TableConstraints.ForeignKeys.ReferencedTable
+ referencedTable = foreignKey.getReferencedTable();
+ builder.setReferencedTable(
+ TableId.of(
+ referencedTable.getProjectId(),
+ referencedTable.getDatasetId(),
+ referencedTable.getTableId()));
+ }
+
+ if (foreignKey.getColumnReferences() != null) {
+ builder.setColumnReferences(
+ foreignKey.getColumnReferences().stream()
+ .map(ColumnReference::fromPb)
+ .collect(Collectors.toList()));
+ }
+
+ return builder.build();
+ }
+
+ com.google.api.services.bigquery.model.TableConstraints.ForeignKeys toPb() {
+
+ com.google.api.services.bigquery.model.TableConstraints.ForeignKeys foreignKey =
+ new com.google.api.services.bigquery.model.TableConstraints.ForeignKeys();
+ if (getName() != null) {
+ foreignKey.setName(getName());
+ }
+ if (getReferencedTable() != null) {
+ TableId referencedTableId = getReferencedTable();
+ foreignKey.setReferencedTable(
+ new com.google.api.services.bigquery.model.TableConstraints.ForeignKeys.ReferencedTable()
+ .setTableId(referencedTableId.getTable())
+ .setDatasetId(referencedTableId.getDataset())
+ .setProjectId(referencedTableId.getProject()));
+ }
+ if (getColumnReferences() != null) {
+ foreignKey.setColumnReferences(
+ getColumnReferences().stream().map(ColumnReference::toPb).collect(Collectors.toList()));
+ }
+ return foreignKey;
+ }
+
+ @Nullable
+ public abstract String getName();
+
+ @Nullable
+ public abstract TableId getReferencedTable();
+
+ @Nullable
+ public abstract List getColumnReferences();
+
+ /** Returns a builder for foreign key. */
+ @VisibleForTesting
+ public abstract ForeignKey.Builder toBuilder();
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ /** The name of the foreign key. * */
+ public abstract ForeignKey.Builder setName(String name);
+
+ /** The table referenced by this foreign key. * */
+ public abstract ForeignKey.Builder setReferencedTable(TableId referencedTable);
+
+ /** The set of column references for this foreign key. * */
+ public abstract ForeignKey.Builder setColumnReferences(List columnReferences);
+
+ /** Creates a {@code ForignKey} object. */
+ public abstract ForeignKey build();
+ }
+}
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/PrimaryKey.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/PrimaryKey.java
new file mode 100644
index 0000000000..a8474cf0fb
--- /dev/null
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/PrimaryKey.java
@@ -0,0 +1,68 @@
+/*
+ * Copyright 2023 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.auto.value.AutoValue;
+import com.google.common.annotations.VisibleForTesting;
+import java.io.Serializable;
+import java.util.List;
+import javax.annotation.Nullable;
+
+@AutoValue
+public abstract class PrimaryKey implements Serializable {
+ public static PrimaryKey.Builder newBuilder() {
+ return new AutoValue_PrimaryKey.Builder();
+ }
+
+ static PrimaryKey fromPb(
+ com.google.api.services.bigquery.model.TableConstraints.PrimaryKey primaryKey) {
+ PrimaryKey.Builder builder = newBuilder();
+
+ if (primaryKey.getColumns() != null) {
+ builder.setColumns(primaryKey.getColumns());
+ }
+
+ return builder.build();
+ }
+
+ com.google.api.services.bigquery.model.TableConstraints.PrimaryKey toPb() {
+
+ com.google.api.services.bigquery.model.TableConstraints.PrimaryKey primaryKey =
+ new com.google.api.services.bigquery.model.TableConstraints.PrimaryKey();
+ if (getColumns() != null) {
+ primaryKey.setColumns(getColumns());
+ }
+ return primaryKey;
+ }
+
+ @Nullable
+ public abstract List getColumns();
+
+ /** Returns a builder for primary key. */
+ @VisibleForTesting
+ public abstract PrimaryKey.Builder toBuilder();
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ /** The column names that are primary keys. * */
+ public abstract PrimaryKey.Builder setColumns(List columns);
+
+ /** Creates a {@code PrimaryKey} object. */
+ public abstract PrimaryKey build();
+ }
+}
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardTableDefinition.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardTableDefinition.java
index 4b09fe3c40..8242147df3 100644
--- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardTableDefinition.java
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/StandardTableDefinition.java
@@ -161,6 +161,8 @@ public abstract static class Builder
*/
public abstract Builder setClustering(Clustering clustering);
+ public abstract Builder setTableConstraints(TableConstraints tableConstraints);
+
/** Creates a {@code StandardTableDefinition} object. */
public abstract StandardTableDefinition build();
}
@@ -221,6 +223,13 @@ public abstract static class Builder
@Nullable
public abstract Clustering getClustering();
+ /**
+ * Returns the table constraints for this table. Returns {@code null} if no table constraints are
+ * set for this table.
+ */
+ @Nullable
+ public abstract TableConstraints getTableConstraints();
+
/** Returns a builder for a BigQuery standard table definition. */
public static Builder newBuilder() {
return new AutoValue_StandardTableDefinition.Builder().setType(Type.TABLE);
@@ -259,6 +268,9 @@ Table toPb() {
if (getClustering() != null) {
tablePb.setClustering(getClustering().toPb());
}
+ if (getTableConstraints() != null) {
+ tablePb.setTableConstraints(getTableConstraints().toPb());
+ }
return tablePb;
}
@@ -296,6 +308,9 @@ static StandardTableDefinition fromPb(Table tablePb) {
if (tablePb.getNumLongTermBytes() != null) {
builder.setNumLongTermBytes(tablePb.getNumLongTermBytes());
}
+ if (tablePb.getTableConstraints() != null) {
+ builder.setTableConstraints(TableConstraints.fromPb(tablePb.getTableConstraints()));
+ }
return builder.setNumBytes(tablePb.getNumBytes()).setLocation(tablePb.getLocation()).build();
}
}
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Table.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Table.java
index 3e67e8d750..cf1dfb4f7f 100644
--- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Table.java
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/Table.java
@@ -168,6 +168,12 @@ public TableInfo.Builder setCloneDefinition(CloneDefinition cloneDefinition) {
return this;
}
+ @Override
+ public Builder setTableConstraints(TableConstraints tableConstraints) {
+ infoBuilder.setTableConstraints(tableConstraints);
+ return this;
+ }
+
@Override
public Table build() {
return new Table(bigquery, infoBuilder);
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/TableConstraints.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/TableConstraints.java
new file mode 100644
index 0000000000..ad30eafcc2
--- /dev/null
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/TableConstraints.java
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2023 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.auto.value.AutoValue;
+import com.google.common.annotations.VisibleForTesting;
+import java.io.Serializable;
+import java.util.List;
+import java.util.stream.Collectors;
+import javax.annotation.Nullable;
+
+@AutoValue
+public abstract class TableConstraints implements Serializable {
+ public static TableConstraints.Builder newBuilder() {
+ return new AutoValue_TableConstraints.Builder();
+ }
+
+ static TableConstraints fromPb(
+ com.google.api.services.bigquery.model.TableConstraints tableConstraints) {
+ TableConstraints.Builder builder = newBuilder();
+
+ if (tableConstraints.getForeignKeys() != null) {
+ builder.setForeignKeys(
+ tableConstraints.getForeignKeys().stream()
+ .map(ForeignKey::fromPb)
+ .collect(Collectors.toList()));
+ }
+ if (tableConstraints.getPrimaryKey() != null) {
+ builder.setPrimaryKey(PrimaryKey.fromPb(tableConstraints.getPrimaryKey()));
+ }
+
+ return builder.build();
+ }
+
+ com.google.api.services.bigquery.model.TableConstraints toPb() {
+
+ com.google.api.services.bigquery.model.TableConstraints tableConstraints =
+ new com.google.api.services.bigquery.model.TableConstraints();
+ if (getForeignKeys() != null) {
+ tableConstraints.setForeignKeys(
+ getForeignKeys().stream().map(ForeignKey::toPb).collect(Collectors.toList()));
+ }
+ if (getPrimaryKey() != null) {
+ tableConstraints.setPrimaryKey(getPrimaryKey().toPb());
+ }
+
+ return tableConstraints;
+ }
+
+ @Nullable
+ public abstract List getForeignKeys();
+
+ @Nullable
+ public abstract PrimaryKey getPrimaryKey();
+
+ /** Returns a builder for table constraints. */
+ @VisibleForTesting
+ public abstract TableConstraints.Builder toBuilder();
+
+ @AutoValue.Builder
+ public abstract static class Builder {
+
+ /** The list of foreign keys for the table constraints. * */
+ public abstract TableConstraints.Builder setForeignKeys(List foreignKeys);
+
+ /** The primary key for the table constraints. * */
+ public abstract TableConstraints.Builder setPrimaryKey(PrimaryKey primaryKey);
+
+ /** Creates a {@code TableConstraints} object. */
+ public abstract TableConstraints build();
+ }
+}
diff --git a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/TableInfo.java b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/TableInfo.java
index 19e9de2b79..abfe21ec46 100644
--- a/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/TableInfo.java
+++ b/google-cloud-bigquery/src/main/java/com/google/cloud/bigquery/TableInfo.java
@@ -75,6 +75,7 @@ public Table apply(TableInfo tableInfo) {
private final String defaultCollation;
private final CloneDefinition cloneDefinition;
+ private final TableConstraints tableConstraints;
/** A builder for {@code TableInfo} objects. */
public abstract static class Builder {
@@ -142,6 +143,8 @@ public Builder setRequirePartitionFilter(Boolean requirePartitionFilter) {
public abstract Builder setDefaultCollation(String defaultCollation);
public abstract Builder setCloneDefinition(CloneDefinition cloneDefinition);
+
+ public abstract Builder setTableConstraints(TableConstraints tableConstraints);
}
static class BuilderImpl extends Builder {
@@ -164,6 +167,7 @@ static class BuilderImpl extends Builder {
private Boolean requirePartitionFilter;
private String defaultCollation;
private CloneDefinition cloneDefinition;
+ private TableConstraints tableConstraints;
BuilderImpl() {}
@@ -186,6 +190,7 @@ static class BuilderImpl extends Builder {
this.requirePartitionFilter = tableInfo.requirePartitionFilter;
this.defaultCollation = tableInfo.defaultCollation;
this.cloneDefinition = tableInfo.cloneDefinition;
+ this.tableConstraints = tableInfo.tableConstraints;
}
BuilderImpl(Table tablePb) {
@@ -214,6 +219,9 @@ static class BuilderImpl extends Builder {
if (tablePb.getCloneDefinition() != null) {
this.cloneDefinition = CloneDefinition.fromPb(tablePb.getCloneDefinition());
}
+ if (tablePb.getTableConstraints() != null) {
+ this.tableConstraints = TableConstraints.fromPb(tablePb.getTableConstraints());
+ }
}
@Override
@@ -323,6 +331,11 @@ public Builder setCloneDefinition(CloneDefinition cloneDefinition) {
return this;
}
+ public Builder setTableConstraints(TableConstraints tableConstraints) {
+ this.tableConstraints = tableConstraints;
+ return this;
+ }
+
@Override
public TableInfo build() {
return new TableInfo(this);
@@ -348,6 +361,7 @@ public TableInfo build() {
this.requirePartitionFilter = builder.requirePartitionFilter;
this.defaultCollation = builder.defaultCollation;
this.cloneDefinition = builder.cloneDefinition;
+ this.tableConstraints = builder.tableConstraints;
}
/** Returns the hash of the table resource. */
@@ -458,6 +472,10 @@ public CloneDefinition getCloneDefinition() {
return cloneDefinition;
}
+ public TableConstraints getTableConstraints() {
+ return tableConstraints;
+ }
+
/** Returns a builder for the table object. */
public Builder toBuilder() {
return new BuilderImpl(this);
@@ -484,6 +502,7 @@ public String toString() {
.add("requirePartitionFilter", requirePartitionFilter)
.add("defaultCollation", defaultCollation)
.add("cloneDefinition", cloneDefinition)
+ .add("tableConstraints", tableConstraints)
.toString();
}
@@ -551,6 +570,9 @@ Table toPb() {
if (cloneDefinition != null) {
tablePb.setCloneDefinition(cloneDefinition.toPb());
}
+ if (tableConstraints != null) {
+ tablePb.setTableConstraints(tableConstraints.toPb());
+ }
return tablePb;
}
diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ColumnReferenceTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ColumnReferenceTest.java
new file mode 100644
index 0000000000..7a6cac30f6
--- /dev/null
+++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ColumnReferenceTest.java
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2023 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import org.junit.Test;
+
+public class ColumnReferenceTest {
+ private static final ColumnReference COLUMN_REFERENCE =
+ ColumnReference.newBuilder()
+ .setReferencingColumn("column1")
+ .setReferencedColumn("column2")
+ .build();
+
+ @Test
+ public void testToBuilder() {
+ compareColumnReferenceDefinition(COLUMN_REFERENCE, COLUMN_REFERENCE.toBuilder().build());
+ ColumnReference columnReference =
+ COLUMN_REFERENCE
+ .toBuilder()
+ .setReferencingColumn("col1")
+ .setReferencedColumn("col2")
+ .build();
+ assertEquals("col1", columnReference.getReferencingColumn());
+ assertEquals("col2", columnReference.getReferencedColumn());
+ }
+
+ @Test
+ public void testBuilder() {
+ assertEquals("column1", COLUMN_REFERENCE.getReferencingColumn());
+ assertEquals("column2", COLUMN_REFERENCE.getReferencedColumn());
+ ColumnReference columnReference =
+ COLUMN_REFERENCE
+ .newBuilder()
+ .setReferencingColumn("column1")
+ .setReferencedColumn("column2")
+ .build();
+ assertEquals(COLUMN_REFERENCE, columnReference);
+ }
+
+ @Test
+ public void testToAndFromPb() {
+ ColumnReference columnReference = COLUMN_REFERENCE.toBuilder().build();
+ assertTrue(ColumnReference.fromPb(columnReference.toPb()) instanceof ColumnReference);
+ compareColumnReferenceDefinition(
+ columnReference, ColumnReference.fromPb(columnReference.toPb()));
+ }
+
+ private void compareColumnReferenceDefinition(ColumnReference expected, ColumnReference value) {
+ assertEquals(expected.getReferencingColumn(), value.getReferencingColumn());
+ assertEquals(expected.getReferencedColumn(), value.getReferencedColumn());
+ }
+}
diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ForeignKeyTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ForeignKeyTest.java
new file mode 100644
index 0000000000..5cb2b418f2
--- /dev/null
+++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/ForeignKeyTest.java
@@ -0,0 +1,95 @@
+/*
+ * Copyright 2023 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Collections;
+import org.junit.Test;
+
+public class ForeignKeyTest {
+ private static final TableId TABLE_ID = TableId.of("project", "dataset", "table");
+
+ private static final ColumnReference COLUMN_REFERENCE =
+ ColumnReference.newBuilder()
+ .setReferencingColumn("column1")
+ .setReferencedColumn("column2")
+ .build();
+ private static final ForeignKey FOREIGN_KEY =
+ ForeignKey.newBuilder()
+ .setName("foreign_key")
+ .setReferencedTable(TABLE_ID)
+ .setColumnReferences(Collections.singletonList(COLUMN_REFERENCE))
+ .build();
+
+ @Test
+ public void testToBuilder() {
+ compareForeignKeyDefinition(FOREIGN_KEY, FOREIGN_KEY.toBuilder().build());
+ TableId referencedTable = TableId.of("project1", "dataset1", "table1");
+ ArrayList columnReferences = new ArrayList<>();
+ columnReferences.add(
+ ColumnReference.newBuilder()
+ .setReferencingColumn("from")
+ .setReferencedColumn("to")
+ .build());
+ columnReferences.add(
+ ColumnReference.newBuilder()
+ .setReferencingColumn("from2")
+ .setReferencedColumn("to2")
+ .build());
+ ForeignKey foreignKey =
+ FOREIGN_KEY
+ .toBuilder()
+ .setName("test")
+ .setReferencedTable(referencedTable)
+ .setColumnReferences(columnReferences)
+ .build();
+ assertEquals("test", foreignKey.getName());
+ assertEquals(referencedTable, foreignKey.getReferencedTable());
+ assertEquals(columnReferences, foreignKey.getColumnReferences());
+ }
+
+ @Test
+ public void testBuilder() {
+ assertEquals("foreign_key", FOREIGN_KEY.getName());
+ assertEquals(TABLE_ID, FOREIGN_KEY.getReferencedTable());
+ assertEquals(Collections.singletonList(COLUMN_REFERENCE), FOREIGN_KEY.getColumnReferences());
+ ForeignKey foreignKey =
+ FOREIGN_KEY
+ .newBuilder()
+ .setName("foreign_key")
+ .setReferencedTable(TABLE_ID)
+ .setColumnReferences(Collections.singletonList(COLUMN_REFERENCE))
+ .build();
+ assertEquals(FOREIGN_KEY, foreignKey);
+ }
+
+ @Test
+ public void testToAndFromPb() {
+ ForeignKey foreignKey = FOREIGN_KEY.toBuilder().build();
+ assertTrue(ForeignKey.fromPb(foreignKey.toPb()) instanceof ForeignKey);
+ compareForeignKeyDefinition(foreignKey, ForeignKey.fromPb(foreignKey.toPb()));
+ }
+
+ private void compareForeignKeyDefinition(ForeignKey expected, ForeignKey value) {
+ assertEquals(expected.getName(), value.getName());
+ assertEquals(expected.getReferencedTable(), value.getReferencedTable());
+ assertEquals(expected.getColumnReferences(), value.getColumnReferences());
+ }
+}
diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/PrimaryKeyTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/PrimaryKeyTest.java
new file mode 100644
index 0000000000..2de87a0258
--- /dev/null
+++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/PrimaryKeyTest.java
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2023 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.Arrays;
+import java.util.List;
+import org.junit.Test;
+
+public class PrimaryKeyTest {
+ private static final List COLUMNS = Arrays.asList("column1", "column2");
+ private static final PrimaryKey PRIMARY_KEY = PrimaryKey.newBuilder().setColumns(COLUMNS).build();
+
+ @Test
+ public void testToBuilder() {
+ comparePrimaryKeyDefinition(PRIMARY_KEY, PRIMARY_KEY.toBuilder().build());
+ PrimaryKey primaryKey =
+ PRIMARY_KEY.toBuilder().setColumns(Arrays.asList("col1", "col2", "col3")).build();
+ assertEquals(Arrays.asList("col1", "col2", "col3"), primaryKey.getColumns());
+ }
+
+ @Test
+ public void testBuilder() {
+ assertEquals(COLUMNS, PRIMARY_KEY.getColumns());
+ PrimaryKey primaryKey = PRIMARY_KEY.newBuilder().setColumns(COLUMNS).build();
+ assertEquals(PRIMARY_KEY, primaryKey);
+ }
+
+ @Test
+ public void testToAndFromPb() {
+ PrimaryKey primaryKey = PRIMARY_KEY.toBuilder().build();
+ assertTrue(PrimaryKey.fromPb(primaryKey.toPb()) instanceof PrimaryKey);
+ comparePrimaryKeyDefinition(primaryKey, PrimaryKey.fromPb(primaryKey.toPb()));
+ }
+
+ private void comparePrimaryKeyDefinition(PrimaryKey expected, PrimaryKey value) {
+ assertEquals(expected.getColumns(), value.getColumns());
+ }
+}
diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/TableConstraintsTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/TableConstraintsTest.java
new file mode 100644
index 0000000000..05f3bbf41c
--- /dev/null
+++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/TableConstraintsTest.java
@@ -0,0 +1,119 @@
+/*
+ * Copyright 2023 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 org.junit.Assert.assertEquals;
+import static org.junit.Assert.assertTrue;
+
+import java.util.ArrayList;
+import java.util.Arrays;
+import java.util.Collections;
+import java.util.List;
+import org.junit.Test;
+
+public class TableConstraintsTest {
+ private static final List COLUMNS_PK = Arrays.asList("column1", "column2");
+ private static final PrimaryKey PRIMARY_KEY =
+ PrimaryKey.newBuilder().setColumns(COLUMNS_PK).build();
+ private static final TableId TABLE_ID_PK = TableId.of("project", "dataset", "table");
+
+ private static final ColumnReference COLUMN_REFERENCE =
+ ColumnReference.newBuilder()
+ .setReferencingColumn("column1")
+ .setReferencedColumn("column2")
+ .build();
+ private static final ForeignKey FOREIGN_KEY =
+ ForeignKey.newBuilder()
+ .setName("foreign_key")
+ .setReferencedTable(TABLE_ID_PK)
+ .setColumnReferences(Collections.singletonList(COLUMN_REFERENCE))
+ .build();
+
+ private static final TableConstraints TABLE_CONSTRAINTS =
+ TableConstraints.newBuilder()
+ .setPrimaryKey(PRIMARY_KEY)
+ .setForeignKeys(Collections.singletonList(FOREIGN_KEY))
+ .build();
+
+ @Test
+ public void testToBuilder() {
+ compareTableConstraintsDefinition(TABLE_CONSTRAINTS, TABLE_CONSTRAINTS.toBuilder().build());
+ List columnsPk = Arrays.asList("col1", "col2", "col3");
+ PrimaryKey primaryKey = PrimaryKey.newBuilder().setColumns(columnsPk).build();
+ TableId referencedTable = TableId.of("project1", "dataset1", "table1");
+ TableId referencedTable2 = TableId.of("project2", "dataset2", "table2");
+ ArrayList columnReferences = new ArrayList<>();
+ columnReferences.add(
+ ColumnReference.newBuilder()
+ .setReferencingColumn("from")
+ .setReferencedColumn("to")
+ .build());
+ columnReferences.add(
+ ColumnReference.newBuilder()
+ .setReferencingColumn("from2")
+ .setReferencedColumn("to2")
+ .build());
+ ForeignKey foreignKey1 =
+ ForeignKey.newBuilder()
+ .setName("test")
+ .setReferencedTable(referencedTable)
+ .setColumnReferences(columnReferences)
+ .build();
+ ForeignKey foreignKey2 =
+ ForeignKey.newBuilder()
+ .setName("test")
+ .setReferencedTable(referencedTable2)
+ .setColumnReferences(columnReferences)
+ .build();
+
+ TableConstraints tableConstraints =
+ TABLE_CONSTRAINTS
+ .toBuilder()
+ .setForeignKeys(Arrays.asList(foreignKey1, foreignKey2))
+ .setPrimaryKey(primaryKey)
+ .build();
+ assertEquals(Arrays.asList(foreignKey1, foreignKey2), tableConstraints.getForeignKeys());
+ assertEquals(primaryKey, tableConstraints.getPrimaryKey());
+ }
+
+ @Test
+ public void testBuilder() {
+ assertEquals(Collections.singletonList(FOREIGN_KEY), TABLE_CONSTRAINTS.getForeignKeys());
+ assertEquals(PRIMARY_KEY, TABLE_CONSTRAINTS.getPrimaryKey());
+ TableConstraints tableConstraints =
+ TABLE_CONSTRAINTS
+ .newBuilder()
+ .setForeignKeys(Collections.singletonList(FOREIGN_KEY))
+ .setPrimaryKey(PRIMARY_KEY)
+ .build();
+ assertEquals(TABLE_CONSTRAINTS, tableConstraints);
+ }
+
+ @Test
+ public void testToAndFromPb() {
+ TableConstraints tableConstraints = TABLE_CONSTRAINTS.toBuilder().build();
+ assertTrue(TableConstraints.fromPb(tableConstraints.toPb()) instanceof TableConstraints);
+ compareTableConstraintsDefinition(
+ tableConstraints, TableConstraints.fromPb(tableConstraints.toPb()));
+ }
+
+ private void compareTableConstraintsDefinition(
+ TableConstraints expected, TableConstraints value) {
+ assertEquals(expected.getForeignKeys(), value.getForeignKeys());
+ assertEquals(expected.getPrimaryKey(), value.getPrimaryKey());
+ }
+}
diff --git a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java
index cdfcb80033..dbab63709f 100644
--- a/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java
+++ b/google-cloud-bigquery/src/test/java/com/google/cloud/bigquery/it/ITBigQueryTest.java
@@ -57,6 +57,7 @@
import com.google.cloud.bigquery.BigQuerySQLException;
import com.google.cloud.bigquery.CloneDefinition;
import com.google.cloud.bigquery.Clustering;
+import com.google.cloud.bigquery.ColumnReference;
import com.google.cloud.bigquery.Connection;
import com.google.cloud.bigquery.ConnectionProperty;
import com.google.cloud.bigquery.ConnectionSettings;
@@ -74,6 +75,7 @@
import com.google.cloud.bigquery.FieldValue;
import com.google.cloud.bigquery.FieldValue.Attribute;
import com.google.cloud.bigquery.FieldValueList;
+import com.google.cloud.bigquery.ForeignKey;
import com.google.cloud.bigquery.FormatOptions;
import com.google.cloud.bigquery.HivePartitioningOptions;
import com.google.cloud.bigquery.InsertAllRequest;
@@ -97,6 +99,7 @@
import com.google.cloud.bigquery.Parameter;
import com.google.cloud.bigquery.ParquetOptions;
import com.google.cloud.bigquery.PolicyTags;
+import com.google.cloud.bigquery.PrimaryKey;
import com.google.cloud.bigquery.QueryJobConfiguration;
import com.google.cloud.bigquery.QueryParameterValue;
import com.google.cloud.bigquery.RangePartitioning;
@@ -112,6 +115,7 @@
import com.google.cloud.bigquery.StandardSQLTypeName;
import com.google.cloud.bigquery.StandardTableDefinition;
import com.google.cloud.bigquery.Table;
+import com.google.cloud.bigquery.TableConstraints;
import com.google.cloud.bigquery.TableDataWriteChannel;
import com.google.cloud.bigquery.TableDefinition;
import com.google.cloud.bigquery.TableId;
@@ -157,6 +161,7 @@
import java.time.LocalTime;
import java.time.Period;
import java.util.ArrayList;
+import java.util.Arrays;
import java.util.Collection;
import java.util.Collections;
import java.util.HashMap;
@@ -744,6 +749,16 @@ public class ITBigQueryTest {
.build();
private static final Schema SESSION_TABLE_SCHEMA =
Schema.of(ID_SCHEMA, FIRST_NAME_SCHEMA, LAST_NAME_SCHEMA, EMAIL_SCHEMA, PROFESSION_SCHEMA);
+
+ private static final Schema CONSTRAINTS_TABLE_SCHEMA =
+ Schema.of(
+ Field.newBuilder("ID", LegacySQLTypeName.STRING).setMode(Mode.REQUIRED).build(),
+ Field.newBuilder("FirstName", LegacySQLTypeName.STRING)
+ .setMode(Field.Mode.NULLABLE)
+ .build(),
+ Field.newBuilder("LastName", LegacySQLTypeName.STRING)
+ .setMode(Field.Mode.NULLABLE)
+ .build());
private static final Path csvPath =
FileSystems.getDefault().getPath("src/test/resources", "sessionTest.csv").toAbsolutePath();
@@ -5672,4 +5687,206 @@ public void testHivePartitioningOptionsFieldsFieldExistence() throws Interrupted
assertTrue(table.delete());
assertTrue(storage.delete(blobInfo.getBlobId()));
}
+
+ @Test
+ public void testPrimaryKey() {
+ String tableName = "test_primary_key";
+ TableId tableId = TableId.of(DATASET, tableName);
+ PrimaryKey primaryKey = PrimaryKey.newBuilder().setColumns(Arrays.asList("ID")).build();
+ TableConstraints tableConstraintsPk =
+ TableConstraints.newBuilder().setPrimaryKey(primaryKey).build();
+
+ try {
+ StandardTableDefinition tableDefinition =
+ StandardTableDefinition.newBuilder()
+ .setSchema(CONSTRAINTS_TABLE_SCHEMA)
+ .setTableConstraints(tableConstraintsPk)
+ .build();
+ Table createdTable = bigquery.create(TableInfo.of(tableId, tableDefinition));
+ assertNotNull(createdTable);
+ Table remoteTable = bigquery.getTable(DATASET, tableName);
+ assertEquals(
+ tableConstraintsPk,
+ remoteTable.getDefinition().getTableConstraints());
+ } finally {
+ bigquery.delete(tableId);
+ }
+ }
+
+ @Test
+ public void testPrimaryKeyUpdate() {
+ String tableName = "test_primary_key_update";
+ TableId tableId = TableId.of(DATASET, tableName);
+ PrimaryKey primaryKey =
+ PrimaryKey.newBuilder().setColumns(Arrays.asList("FirstName", "LastName")).build();
+ TableConstraints tableConstraintsPk =
+ TableConstraints.newBuilder().setPrimaryKey(primaryKey).build();
+
+ try {
+ StandardTableDefinition tableDefinition =
+ StandardTableDefinition.newBuilder().setSchema(CONSTRAINTS_TABLE_SCHEMA).build();
+ Table createdTable = bigquery.create(TableInfo.of(tableId, tableDefinition));
+ assertNotNull(createdTable);
+ Table remoteTable = bigquery.getTable(DATASET, tableName);
+ assertNull(remoteTable.getDefinition().getTableConstraints());
+
+ Table updatedTable =
+ remoteTable.toBuilder().setTableConstraints(tableConstraintsPk).build().update();
+ assertNotNull(updatedTable);
+ Table remoteUpdatedTable = bigquery.getTable(DATASET, tableName);
+ assertEquals(
+ tableConstraintsPk,
+ remoteUpdatedTable.getDefinition().getTableConstraints());
+ } finally {
+ bigquery.delete(tableId);
+ }
+ }
+
+ @Test
+ public void testForeignKeys() {
+ String tableNamePk = "test_foreign_key";
+ String tableNameFk = "test_foreign_key2";
+ // TableIds referenced by foreign keys need project id to be specified
+ TableId tableIdPk = TableId.of(PROJECT_ID, DATASET, tableNamePk);
+ TableId tableIdFk = TableId.of(DATASET, tableNameFk);
+ ColumnReference columnReference =
+ ColumnReference.newBuilder().setReferencingColumn("ID").setReferencedColumn("ID").build();
+
+ PrimaryKey primaryKey =
+ PrimaryKey.newBuilder().setColumns(Collections.singletonList("ID")).build();
+ TableConstraints tableConstraintsPk =
+ TableConstraints.newBuilder().setPrimaryKey(primaryKey).build();
+
+ ForeignKey foreignKey =
+ ForeignKey.newBuilder()
+ .setName("foreign_key")
+ .setReferencedTable(tableIdPk)
+ .setColumnReferences(Collections.singletonList(columnReference))
+ .build();
+ TableConstraints tableConstraintsFk =
+ TableConstraints.newBuilder().setForeignKeys(Collections.singletonList(foreignKey)).build();
+
+ try {
+ StandardTableDefinition tableDefinitionPk =
+ StandardTableDefinition.newBuilder()
+ .setSchema(CONSTRAINTS_TABLE_SCHEMA)
+ .setTableConstraints(tableConstraintsPk)
+ .build();
+ Table createdTablePk = bigquery.create(TableInfo.of(tableIdPk, tableDefinitionPk));
+ assertNotNull(createdTablePk);
+
+ StandardTableDefinition tableDefinitionFk =
+ StandardTableDefinition.newBuilder()
+ .setSchema(CONSTRAINTS_TABLE_SCHEMA)
+ .setTableConstraints(tableConstraintsFk)
+ .build();
+ Table createdTableFk = bigquery.create(TableInfo.of(tableIdFk, tableDefinitionFk));
+ assertNotNull(createdTableFk);
+ Table remoteTable = bigquery.getTable(DATASET, tableNameFk);
+ assertEquals(
+ tableConstraintsFk,
+ remoteTable.getDefinition().getTableConstraints());
+ } finally {
+ bigquery.delete(tableIdPk);
+ bigquery.delete(tableIdFk);
+ }
+ }
+
+ @Test
+ public void testForeignKeysUpdate() {
+ String tableNameFk = "test_foreign_key";
+ String tableNamePk1 = "test_foreign_key2";
+ String tableNamePk2 = "test_foreign_key3";
+ TableId tableIdFk = TableId.of(DATASET, tableNameFk);
+ // TableIds referenced by foreign keys need project id to be specified
+ TableId tableIdPk1 = TableId.of(PROJECT_ID, DATASET, tableNamePk1);
+ TableId tableIdPk2 = TableId.of(PROJECT_ID, DATASET, tableNamePk2);
+
+ ArrayList foreignKeys = new ArrayList<>();
+
+ // set up ID in tableFk as a foreign key to tablePk1
+ ColumnReference columnReferencePk1 =
+ ColumnReference.newBuilder().setReferencingColumn("ID").setReferencedColumn("ID").build();
+ PrimaryKey primaryKey1 =
+ PrimaryKey.newBuilder().setColumns(Collections.singletonList("ID")).build();
+ TableConstraints tableConstraintsPk1 =
+ TableConstraints.newBuilder().setPrimaryKey(primaryKey1).build();
+
+ ForeignKey foreignKey1 =
+ ForeignKey.newBuilder()
+ .setName("foreign_key1")
+ .setReferencedTable(tableIdPk1)
+ .setColumnReferences(Collections.singletonList(columnReferencePk1))
+ .build();
+ foreignKeys.add(foreignKey1);
+
+ // set up First and last names in tableFk as foreign keys to TablePk2
+ ArrayList columnReferencesPk2 = new ArrayList<>();
+ columnReferencesPk2.add(
+ ColumnReference.newBuilder()
+ .setReferencingColumn("FirstName")
+ .setReferencedColumn("FirstName")
+ .build());
+ columnReferencesPk2.add(
+ ColumnReference.newBuilder()
+ .setReferencingColumn("LastName")
+ .setReferencedColumn("LastName")
+ .build());
+
+ ArrayList primaryKey2Columns = new ArrayList<>();
+ primaryKey2Columns.add("FirstName");
+ primaryKey2Columns.add("LastName");
+
+ PrimaryKey primaryKey2 = PrimaryKey.newBuilder().setColumns(primaryKey2Columns).build();
+ TableConstraints tableConstraintsPk2 =
+ TableConstraints.newBuilder().setPrimaryKey(primaryKey2).build();
+ ForeignKey foreignKey2 =
+ ForeignKey.newBuilder()
+ .setName("foreign_key2")
+ .setReferencedTable(tableIdPk2)
+ .setColumnReferences(columnReferencesPk2)
+ .build();
+ foreignKeys.add(foreignKey2);
+ TableConstraints tableConstraintsFk =
+ TableConstraints.newBuilder().setForeignKeys(foreignKeys).build();
+
+ try {
+ StandardTableDefinition tableDefinitionFk =
+ StandardTableDefinition.newBuilder().setSchema(CONSTRAINTS_TABLE_SCHEMA).build();
+ Table createdTableFk = bigquery.create(TableInfo.of(tableIdFk, tableDefinitionFk));
+ assertNotNull(createdTableFk);
+
+ StandardTableDefinition tableDefinitionPk1 =
+ StandardTableDefinition.newBuilder()
+ .setSchema(CONSTRAINTS_TABLE_SCHEMA)
+ .setTableConstraints(tableConstraintsPk1)
+ .build();
+ Table createdTablePk1 = bigquery.create(TableInfo.of(tableIdPk1, tableDefinitionPk1));
+ assertNotNull(createdTablePk1);
+
+ StandardTableDefinition tableDefinitionPk2 =
+ StandardTableDefinition.newBuilder()
+ .setSchema(CONSTRAINTS_TABLE_SCHEMA)
+ .setTableConstraints(tableConstraintsPk2)
+ .build();
+ Table createdTablePk2 = bigquery.create(TableInfo.of(tableIdPk2, tableDefinitionPk2));
+ assertNotNull(createdTablePk2);
+
+ Table remoteTable = bigquery.getTable(DATASET, tableNameFk);
+ assertNull(remoteTable.getDefinition().getTableConstraints());
+
+ Table updatedTable =
+ remoteTable.toBuilder().setTableConstraints(tableConstraintsFk).build().update();
+
+ assertNotNull(updatedTable);
+ Table remoteUpdatedTable = bigquery.getTable(DATASET, tableNameFk);
+ assertEquals(
+ tableConstraintsFk,
+ remoteUpdatedTable.getDefinition().getTableConstraints());
+ } finally {
+ bigquery.delete(tableIdFk);
+ bigquery.delete(tableIdPk1);
+ bigquery.delete(tableIdPk2);
+ }
+ }
}
diff --git a/samples/snippets/src/main/java/com/example/bigquery/CreateTablesWithPrimaryAndForeignKeys.java b/samples/snippets/src/main/java/com/example/bigquery/CreateTablesWithPrimaryAndForeignKeys.java
new file mode 100644
index 0000000000..36e32bc216
--- /dev/null
+++ b/samples/snippets/src/main/java/com/example/bigquery/CreateTablesWithPrimaryAndForeignKeys.java
@@ -0,0 +1,109 @@
+/*
+ * Copyright 2023 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.example.bigquery;
+
+// [START bigquery_create_tables_with_primary_and_foreign_keys]
+import com.google.cloud.bigquery.BigQuery;
+import com.google.cloud.bigquery.BigQueryException;
+import com.google.cloud.bigquery.BigQueryOptions;
+import com.google.cloud.bigquery.ColumnReference;
+import com.google.cloud.bigquery.Field;
+import com.google.cloud.bigquery.ForeignKey;
+import com.google.cloud.bigquery.LegacySQLTypeName;
+import com.google.cloud.bigquery.PrimaryKey;
+import com.google.cloud.bigquery.Schema;
+import com.google.cloud.bigquery.StandardTableDefinition;
+import com.google.cloud.bigquery.TableConstraints;
+import com.google.cloud.bigquery.TableId;
+import com.google.cloud.bigquery.TableInfo;
+import java.util.Arrays;
+import java.util.Collections;
+
+// Create tables with primary/foreign key columns
+public class CreateTablesWithPrimaryAndForeignKeys {
+
+ private static final Schema PK_FK_SCHEMA =
+ Schema.of(
+ Field.newBuilder("ID", LegacySQLTypeName.STRING).setMode(Field.Mode.NULLABLE).build(),
+ Field.newBuilder("FirstName", LegacySQLTypeName.STRING)
+ .setMode(Field.Mode.NULLABLE)
+ .build(),
+ Field.newBuilder("LastName", LegacySQLTypeName.STRING)
+ .setMode(Field.Mode.NULLABLE)
+ .build());
+
+ public static void main(String[] args) {
+ // TODO(developer): Replace these variables before running the sample.
+ String datasetName = "MY_DATASET_NAME";
+ String tableNamePk = "PK_TABLE";
+ String tableNameFk = "FK_TABLE";
+ createTablesWithPrimaryAndForeignKeys(datasetName, tableNamePk, tableNameFk);
+ }
+
+ public static void createTablesWithPrimaryAndForeignKeys(
+ String datasetName, String tableNamePk, String tableNameFk) {
+ try {
+ // Initialize client that will be used to send requests. This client only needs to be created
+ // once, and can be reused for multiple requests.
+ BigQuery bigquery = BigQueryOptions.getDefaultInstance().getService();
+
+ // TableIds referenced by foreign keys need project id to be set
+ TableId tableIdPk =
+ TableId.of(bigquery.getOptions().getProjectId(), datasetName, tableNamePk);
+ TableId tableIdFk = TableId.of(datasetName, tableNameFk);
+
+ PrimaryKey primaryKey =
+ PrimaryKey.newBuilder().setColumns(Collections.singletonList("ID")).build();
+ TableConstraints tableConstraintsPk =
+ TableConstraints.newBuilder().setPrimaryKey(primaryKey).build();
+
+ ColumnReference columnReference =
+ ColumnReference.newBuilder().setReferencingColumn("ID").setReferencedColumn("ID").build();
+ ForeignKey foreignKey =
+ ForeignKey.newBuilder()
+ .setName("foreign_key")
+ .setColumnReferences(Collections.singletonList(columnReference))
+ .setReferencedTable(tableIdPk)
+ .build();
+ TableConstraints tableConstraintsFk =
+ TableConstraints.newBuilder().setForeignKeys(Arrays.asList(foreignKey)).build();
+
+ // Create a table with a primary key
+ StandardTableDefinition tableDefinitionPk =
+ StandardTableDefinition.newBuilder()
+ .setSchema(PK_FK_SCHEMA)
+ .setTableConstraints(tableConstraintsPk)
+ .build();
+ TableInfo tableInfoPk = TableInfo.of(tableIdPk, tableDefinitionPk);
+ bigquery.create(tableInfoPk);
+
+ // Create a table with a foreign key
+ StandardTableDefinition tableDefinitionFk =
+ StandardTableDefinition.newBuilder()
+ .setSchema(PK_FK_SCHEMA)
+ .setTableConstraints(tableConstraintsFk)
+ .build();
+ TableInfo tableInfoFk = TableInfo.of(tableIdFk, tableDefinitionFk);
+ bigquery.create(tableInfoFk);
+
+ System.out.println("Tables with primary and foreign keys created successfully.");
+ } catch (BigQueryException e) {
+ System.out.println("Tables not created \n" + e.toString());
+ }
+ }
+}
+// [END bigquery_create_tables_with_primary_and_foreign_keys]
diff --git a/samples/snippets/src/test/java/com/example/bigquery/CreateTablesWithPrimaryAndForeignKeysIT.java b/samples/snippets/src/test/java/com/example/bigquery/CreateTablesWithPrimaryAndForeignKeysIT.java
new file mode 100644
index 0000000000..00ba8fa441
--- /dev/null
+++ b/samples/snippets/src/test/java/com/example/bigquery/CreateTablesWithPrimaryAndForeignKeysIT.java
@@ -0,0 +1,82 @@
+/*
+ * Copyright 2023 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.example.bigquery;
+
+import static com.google.common.truth.Truth.assertThat;
+import static junit.framework.TestCase.assertNotNull;
+
+import java.io.ByteArrayOutputStream;
+import java.io.PrintStream;
+import java.util.UUID;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+import org.junit.After;
+import org.junit.Before;
+import org.junit.BeforeClass;
+import org.junit.Test;
+
+public class CreateTablesWithPrimaryAndForeignKeysIT {
+
+ private final Logger log = Logger.getLogger(this.getClass().getName());
+ private String tableNamePk;
+ private String tableNameFk;
+ private ByteArrayOutputStream bout;
+ private PrintStream out;
+ private PrintStream originalPrintStream;
+
+ private static final String BIGQUERY_DATASET_NAME = System.getenv("BIGQUERY_DATASET_NAME");
+
+ private static void requireEnvVar(String varName) {
+ assertNotNull(
+ "Environment variable " + varName + " is required to perform these tests.",
+ System.getenv(varName));
+ }
+
+ @BeforeClass
+ public static void checkRequirements() {
+ requireEnvVar("BIGQUERY_DATASET_NAME");
+ }
+
+ @Before
+ public void setUp() {
+ bout = new ByteArrayOutputStream();
+ out = new PrintStream(bout);
+ originalPrintStream = System.out;
+ System.setOut(out);
+ tableNamePk = "MY_TABLE_NAME_" + UUID.randomUUID().toString().replace("-", "_");
+ tableNameFk = "MY_TABLE_NAME_" + UUID.randomUUID().toString().replace("-", "_");
+ }
+
+ @After
+ public void tearDown() {
+ // Clean up
+ DeleteTable.deleteTable(BIGQUERY_DATASET_NAME, tableNamePk);
+ DeleteTable.deleteTable(BIGQUERY_DATASET_NAME, tableNameFk);
+ // restores print statements in the original method
+ System.out.flush();
+ System.setOut(originalPrintStream);
+ log.log(Level.INFO, "\n" + bout.toString());
+ }
+
+ @Test
+ public void testCreateAndQueryRepeatedRecordField() {
+ CreateTablesWithPrimaryAndForeignKeys.createTablesWithPrimaryAndForeignKeys(
+ BIGQUERY_DATASET_NAME, tableNamePk, tableNameFk);
+ assertThat(bout.toString())
+ .contains("Tables with primary and foreign keys created successfully.");
+ }
+}