Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: foreign key on delete cascade #2340

Merged
merged 17 commits into from
Jul 18, 2023
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/*
* Copyright 2020 Google LLC
arpan14 marked this conversation as resolved.
Show resolved Hide resolved
*
* 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.spanner;

// [START spanner_alter_table_with_foreign_key_delete_cascade]
import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.Instance;
import com.google.cloud.spanner.InstanceAdminClient;
import com.google.cloud.spanner.InstanceConfigId;
import com.google.cloud.spanner.InstanceId;
import com.google.cloud.spanner.InstanceInfo;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import com.google.common.collect.ImmutableList;
import com.google.spanner.admin.database.v1.UpdateDatabaseDdlMetadata;
import com.google.spanner.admin.instance.v1.CreateInstanceMetadata;
import java.util.concurrent.ExecutionException;

class AlterTableWithForeignKeyDeleteCascadeSample {

static void alterForeignKeyDeleteCascadeConstraint() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String databaseId = "my-database";

try (Spanner spanner =
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
alterForeignKeyDeleteCascadeConstraint(adminClient, instanceId, databaseId);
}
}

static void alterForeignKeyDeleteCascadeConstraint(
DatabaseAdminClient adminClient, String instanceId, String databaseId) {
adminClient.updateDatabaseDdl(
instanceId,
databaseId,
ImmutableList.of("ALTER TABLE ShoppingCarts\n"
+ " ADD CONSTRAINT FKShoppingCartsCustomerName\n"
+ " FOREIGN KEY (CustomerName)\n"
+ " REFERENCES Customers(CustomerName)\n"
olavloite marked this conversation as resolved.
Show resolved Hide resolved
+ " ON DELETE CASCADE\n"),
null);

System.out.printf(String.format("Altered ShoppingCarts table with FKShoppingCartsCustomerName\n"
+ "foreign key constraint on database %s on instance %s", databaseId, instanceId));

arpan14 marked this conversation as resolved.
Show resolved Hide resolved
}
}
// [END spanner_alter_table_with_foreign_key_delete_cascade]
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
/*
* Copyright 2020 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.spanner;

// [START spanner_create_table_with_foreign_key_delete_cascade]
import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.Instance;
import com.google.cloud.spanner.InstanceAdminClient;
import com.google.cloud.spanner.InstanceConfigId;
import com.google.cloud.spanner.InstanceId;
import com.google.cloud.spanner.InstanceInfo;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import com.google.common.collect.ImmutableList;
import com.google.spanner.admin.instance.v1.CreateInstanceMetadata;
import java.util.concurrent.ExecutionException;

class CreateTableWithForeignKeyDeleteCascadeSample {

static void createForeignKeyDeleteCascadeConstraint() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String databaseId = "my-database";

try (Spanner spanner =
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
createForeignKeyDeleteCascadeConstraint(adminClient, instanceId, databaseId);
}
}

static void createForeignKeyDeleteCascadeConstraint(
DatabaseAdminClient adminClient, String instanceId, String databaseId) {
adminClient.updateDatabaseDdl(
instanceId,
databaseId,
ImmutableList.of("CREATE TABLE Customers (\n"
+ " CustomerId INT64 NOT NULL,\n"
+ " CustomerName STRING(62) NOT NULL,\n"
+ " ) PRIMARY KEY (CustomerId)",
"CREATE TABLE ShoppingCarts (\n"
+ " CartId INT64 NOT NULL,\n"
+ " CustomerId INT64 NOT NULL,\n"
+ " CustomerName STRING(62) NOT NULL,\n"
+ " CONSTRAINT FKShoppingCartsCustomerId FOREIGN KEY (CustomerId)\n"
+ " REFERENCES Customers (CustomerId) ON DELETE CASCADE\n"
+ " ) PRIMARY KEY (CartId)\n"),
null);

System.out.printf(String.format("Created Customers and ShoppingCarts table with FKShoppingCartsCustomerId\n"
+ "foreign key constraint on database %s on instance %s\n", databaseId, instanceId));
}
}
// [END spanner_create_table_with_foreign_key_delete_cascade]
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
/*
* Copyright 2020 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.spanner;

// [START spanner_drop_foreign_key_constraint_delete_cascade]
import com.google.api.gax.longrunning.OperationFuture;
import com.google.cloud.spanner.DatabaseAdminClient;
import com.google.cloud.spanner.Instance;
import com.google.cloud.spanner.InstanceAdminClient;
import com.google.cloud.spanner.InstanceConfigId;
import com.google.cloud.spanner.InstanceId;
import com.google.cloud.spanner.InstanceInfo;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import com.google.common.collect.ImmutableList;
import com.google.spanner.admin.instance.v1.CreateInstanceMetadata;
import java.util.concurrent.ExecutionException;

class DropForeignKeyConstraintDeleteCascadeSample {
arpan14 marked this conversation as resolved.
Show resolved Hide resolved

static void deleteForeignKeyDeleteCascadeConstraint() {
// TODO(developer): Replace these variables before running the sample.
String projectId = "my-project";
String instanceId = "my-instance";
String databaseId = "my-database";

try (Spanner spanner =
SpannerOptions.newBuilder().setProjectId(projectId).build().getService()) {
DatabaseAdminClient adminClient = spanner.getDatabaseAdminClient();
deleteForeignKeyDeleteCascadeConstraint(adminClient, instanceId, databaseId);
}
}

static void deleteForeignKeyDeleteCascadeConstraint(
DatabaseAdminClient adminClient, String instanceId, String databaseId) {
adminClient.updateDatabaseDdl(
instanceId,
databaseId,
ImmutableList.of("ALTER TABLE ShoppingCarts\n"
+ " DROP CONSTRAINT FKShoppingCartsCustomerName\n"),
null);

System.out.printf(String.format("Altered ShoppingCarts table to drop FKShoppingCartsCustomerName\n"
+ "foreign key constraint on database %s on instance %s\n", databaseId, instanceId));

arpan14 marked this conversation as resolved.
Show resolved Hide resolved
}
}
// [END spanner_drop_foreign_key_constraint_delete_cascade]
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
package com.example.spanner;
arpan14 marked this conversation as resolved.
Show resolved Hide resolved

import static org.junit.Assert.assertTrue;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.junit.Test;

public class AlterTableWithForeignKeyDeleteCascadeSampleIT extends SampleTestBase {

@Test
public void testAlterTableWithForeignKeyDeleteCascade() throws Exception {

// Creates database
final String databaseId = idGenerator.generateDatabaseId();
databaseAdminClient.createDatabase(instanceId, databaseId, Arrays.asList("CREATE TABLE Customers (\n"
+ " CustomerId INT64 NOT NULL,\n"
+ " CustomerName STRING(62) NOT NULL,\n"
+ " ) PRIMARY KEY (CustomerId)",
"CREATE TABLE ShoppingCarts (\n"
+ " CartId INT64 NOT NULL,\n"
+ " CustomerId INT64 NOT NULL,\n"
+ " CustomerName STRING(62) NOT NULL,\n"
+ " CONSTRAINT FKShoppingCartsCustomerId FOREIGN KEY (CustomerId)\n"
+ " REFERENCES Customers (CustomerId) ON DELETE CASCADE\n"
+ " ) PRIMARY KEY (CartId)\n")
).get(5, TimeUnit.MINUTES);

// Runs sample
final String out = SampleRunner.runSample(() -> AlterTableWithForeignKeyDeleteCascadeSample
.alterForeignKeyDeleteCascadeConstraint(databaseAdminClient, instanceId, databaseId)
);

assertTrue(
"Expected to have created database " + databaseId + " with tables containing "
+ "foreign key constraints.", out.contains("Altered ShoppingCarts table "
+ "with FKShoppingCartsCustomerName"
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package com.example.spanner;
arpan14 marked this conversation as resolved.
Show resolved Hide resolved

import static org.junit.Assert.assertTrue;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.junit.Test;

public class CreateTableWithForeignKeyDeleteCascadeSampleIT extends SampleTestBase {

@Test
public void testCreateTableWithForeignKeyDeleteCascade() throws Exception {

// Creates database
final String databaseId = idGenerator.generateDatabaseId();
databaseAdminClient.createDatabase(instanceId, databaseId, Arrays.asList()
).get(5, TimeUnit.MINUTES);

// Runs sample
final String out = SampleRunner.runSample(() -> CreateTableWithForeignKeyDeleteCascadeSample
.createForeignKeyDeleteCascadeConstraint(databaseAdminClient, instanceId, databaseId)
);

assertTrue(
"Expected to have created database " + databaseId + " with tables containing "
+ "foreign key constraints.", out.contains("Created Customers and ShoppingCarts table "
+ "with FKShoppingCartsCustomerId"
)
);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
package com.example.spanner;
arpan14 marked this conversation as resolved.
Show resolved Hide resolved

import static org.junit.Assert.assertTrue;

import java.util.Arrays;
import java.util.concurrent.TimeUnit;
import org.junit.Test;

public class DropForeignKeyConstraintDeleteCascadeSampleIT extends SampleTestBase {

@Test
public void testDropForeignKeyConstraintDeleteCascade() throws Exception {

// Creates database
final String databaseId = idGenerator.generateDatabaseId();
databaseAdminClient.createDatabase(instanceId, databaseId, Arrays.asList("CREATE TABLE Customers (\n"
+ " CustomerId INT64 NOT NULL,\n"
+ " CustomerName STRING(62) NOT NULL,\n"
+ " ) PRIMARY KEY (CustomerId)",
"CREATE TABLE ShoppingCarts (\n"
+ " CartId INT64 NOT NULL,\n"
+ " CustomerId INT64 NOT NULL,\n"
+ " CustomerName STRING(62) NOT NULL,\n"
+ " CONSTRAINT FKShoppingCartsCustomerName FOREIGN KEY (CustomerName)\n"
+ " REFERENCES Customers (CustomerName) ON DELETE CASCADE\n"
+ " ) PRIMARY KEY (CartId)\n")
).get(5, TimeUnit.MINUTES);

// Runs sample
final String out = SampleRunner.runSample(() -> DropForeignKeyConstraintDeleteCascadeSample
.deleteForeignKeyDeleteCascadeConstraint(databaseAdminClient, instanceId, databaseId)
);

assertTrue(
"Expected to have dropped foreign-key constraints from tables in created database "
arpan14 marked this conversation as resolved.
Show resolved Hide resolved
+ databaseId , out.contains("Altered ShoppingCarts table to drop FKShoppingCartsCustomerName"
)
);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,14 @@ public class SampleTestBase {

@BeforeClass
public static void beforeClass() {
final SpannerOptions options = SpannerOptions
final String serverUrl = "";
final SpannerOptions.Builder optionsBuilder = SpannerOptions
.newBuilder()
.setAutoThrottleAdministrativeRequests()
.build();
.setAutoThrottleAdministrativeRequests();
if (!serverUrl.isEmpty()) {
optionsBuilder.setHost(serverUrl);
}
final SpannerOptions options = optionsBuilder.build();
projectId = options.getProjectId();
spanner = options.getService();
databaseAdminClient = spanner.getDatabaseAdminClient();
Expand Down