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."); + } +}