Skip to content

Commit

Permalink
Add dialect to spanner database (#5799) (#11363)
Browse files Browse the repository at this point in the history
Signed-off-by: Modular Magician <magic-modules@google.com>
  • Loading branch information
modular-magician authored Mar 28, 2022
1 parent 2c3be0c commit adb6e10
Show file tree
Hide file tree
Showing 4 changed files with 132 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .changelog/5799.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
```release-note:enhancement
spanner: added support for setting database_dialect on `google_spanner_database`
```
32 changes: 32 additions & 0 deletions google/resource_spanner_database.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,18 @@ func resourceSpannerDatabase() *schema.Resource {
ValidateFunc: validateRegexp(`^[a-z][a-z0-9_\-]*[a-z0-9]$`),
Description: `A unique identifier for the database, which cannot be changed after
the instance is created. Values are of the form [a-z][-a-z0-9]*[a-z0-9].`,
},
"database_dialect": {
Type: schema.TypeString,
Computed: true,
Optional: true,
ForceNew: true,
ValidateFunc: validateEnum([]string{"GOOGLE_STANDARD_SQL", "POSTGRESQL", ""}),
Description: `The dialect of the Cloud Spanner Database.
If it is not provided, "GOOGLE_STANDARD_SQL" will be used.
Note: Databases that are created with POSTGRESQL dialect do not support
extra DDL statements in the 'CreateDatabase' call. You must therefore re-apply
terraform with ddl on the same database after creation. Possible values: ["GOOGLE_STANDARD_SQL", "POSTGRESQL"]`,
},
"ddl": {
Type: schema.TypeList,
Expand Down Expand Up @@ -167,6 +179,12 @@ func resourceSpannerDatabaseCreate(d *schema.ResourceData, meta interface{}) err
} else if v, ok := d.GetOkExists("encryption_config"); !isEmptyValue(reflect.ValueOf(encryptionConfigProp)) && (ok || !reflect.DeepEqual(v, encryptionConfigProp)) {
obj["encryptionConfig"] = encryptionConfigProp
}
databaseDialectProp, err := expandSpannerDatabaseDatabaseDialect(d.Get("database_dialect"), d, config)
if err != nil {
return err
} else if v, ok := d.GetOkExists("database_dialect"); !isEmptyValue(reflect.ValueOf(databaseDialectProp)) && (ok || !reflect.DeepEqual(v, databaseDialectProp)) {
obj["databaseDialect"] = databaseDialectProp
}
instanceProp, err := expandSpannerDatabaseInstance(d.Get("instance"), d, config)
if err != nil {
return err
Expand Down Expand Up @@ -307,6 +325,9 @@ func resourceSpannerDatabaseRead(d *schema.ResourceData, meta interface{}) error
if err := d.Set("encryption_config", flattenSpannerDatabaseEncryptionConfig(res["encryptionConfig"], d, config)); err != nil {
return fmt.Errorf("Error reading Database: %s", err)
}
if err := d.Set("database_dialect", flattenSpannerDatabaseDatabaseDialect(res["databaseDialect"], d, config)); err != nil {
return fmt.Errorf("Error reading Database: %s", err)
}
if err := d.Set("instance", flattenSpannerDatabaseInstance(res["instance"], d, config)); err != nil {
return fmt.Errorf("Error reading Database: %s", err)
}
Expand Down Expand Up @@ -478,6 +499,10 @@ func flattenSpannerDatabaseEncryptionConfigKmsKeyName(v interface{}, d *schema.R
return v
}

func flattenSpannerDatabaseDatabaseDialect(v interface{}, d *schema.ResourceData, config *Config) interface{} {
return v
}

func flattenSpannerDatabaseInstance(v interface{}, d *schema.ResourceData, config *Config) interface{} {
if v == nil {
return v
Expand Down Expand Up @@ -516,6 +541,10 @@ func expandSpannerDatabaseEncryptionConfigKmsKeyName(v interface{}, d TerraformR
return v, nil
}

func expandSpannerDatabaseDatabaseDialect(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
return v, nil
}

func expandSpannerDatabaseInstance(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
f, err := parseGlobalFieldValue("instances", v.(string), "project", d, config, true)
if err != nil {
Expand All @@ -526,6 +555,9 @@ func expandSpannerDatabaseInstance(v interface{}, d TerraformResourceData, confi

func resourceSpannerDatabaseEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
obj["createStatement"] = fmt.Sprintf("CREATE DATABASE `%s`", obj["name"])
if dialect, ok := obj["databaseDialect"]; ok && dialect == "POSTGRESQL" {
obj["createStatement"] = fmt.Sprintf("CREATE DATABASE %s", obj["name"])
}
delete(obj, "name")
delete(obj, "instance")
return obj, nil
Expand Down
84 changes: 84 additions & 0 deletions google/resource_spanner_database_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,90 @@ resource "google_spanner_database" "basic" {
`, instanceName, instanceName, databaseName)
}

func TestAccSpannerDatabase_postgres(t *testing.T) {
t.Parallel()

rnd := randString(t, 10)
instanceName := fmt.Sprintf("tf-test-%s", rnd)
databaseName := fmt.Sprintf("tfgen_%s", rnd)

vcrTest(t, resource.TestCase{
PreCheck: func() { testAccPreCheck(t) },
Providers: testAccProviders,
CheckDestroy: testAccCheckSpannerDatabaseDestroyProducer(t),
Steps: []resource.TestStep{
{
Config: testAccSpannerDatabase_postgres(instanceName, databaseName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("google_spanner_database.basic_spangres", "state"),
),
},
{
// Test import with default Terraform ID
ResourceName: "google_spanner_database.basic_spangres",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"ddl", "deletion_protection"},
},
{
Config: testAccSpannerDatabase_postgresUpdate(instanceName, databaseName),
Check: resource.ComposeTestCheckFunc(
resource.TestCheckResourceAttrSet("google_spanner_database.basic_spangres", "state"),
),
},
{
// Test import with default Terraform ID
ResourceName: "google_spanner_database.basic_spangres",
ImportState: true,
ImportStateVerify: true,
ImportStateVerifyIgnore: []string{"ddl", "deletion_protection"},
},
},
})
}

func testAccSpannerDatabase_postgres(instanceName, databaseName string) string {
return fmt.Sprintf(`
resource "google_spanner_instance" "basic" {
name = "%s"
config = "regional-us-central1"
display_name = "%s-display"
num_nodes = 1
}
resource "google_spanner_database" "basic_spangres" {
instance = google_spanner_instance.basic.name
name = "%s_spangres"
database_dialect = "POSTGRESQL"
deletion_protection = false
}
`, instanceName, instanceName, databaseName)
}

func testAccSpannerDatabase_postgresUpdate(instanceName, databaseName string) string {
return fmt.Sprintf(`
resource "google_spanner_instance" "basic" {
name = "%s"
config = "regional-us-central1"
display_name = "%s-display"
num_nodes = 1
}
resource "google_spanner_database" "basic_spangres" {
instance = google_spanner_instance.basic.name
name = "%s_spangres"
database_dialect = "POSTGRESQL"
ddl = [
"CREATE TABLE t1 (t1 bigint NOT NULL PRIMARY KEY)",
"CREATE TABLE t2 (t2 bigint NOT NULL PRIMARY KEY)",
"CREATE TABLE t3 (t3 bigint NOT NULL PRIMARY KEY)",
"CREATE TABLE t4 (t4 bigint NOT NULL PRIMARY KEY)",
]
deletion_protection = false
}
`, instanceName, instanceName, databaseName)
}

// Unit Tests for type spannerDatabaseId
func TestDatabaseNameForApi(t *testing.T) {
id := spannerDatabaseId{
Expand Down
13 changes: 13 additions & 0 deletions website/docs/r/spanner_database.html.markdown
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ On older versions, it is strongly recommended to set `lifecycle { prevent_destro
on databases in order to prevent accidental data loss. See [Terraform docs](https://www.terraform.io/docs/configuration/resources.html#prevent_destroy)
for more information on lifecycle parameters.

Note: Databases that are created with POSTGRESQL dialect do not support
extra DDL statements in the `CreateDatabase` call. You must therefore re-apply
terraform with ddl on the same database after creation.

<div class = "oics-button" style="float: right; margin: 0 0 -15px">
<a href="https://console.cloud.google.com/cloudshell/open?cloudshell_git_repo=https%3A%2F%2Fgit.luolix.top%2Fterraform-google-modules%2Fdocs-examples.git&cloudshell_working_dir=spanner_database_basic&cloudshell_image=gcr.io%2Fgraphite-cloud-shell-images%2Fterraform%3Alatest&open_in_editor=main.tf&cloudshell_print=.%2Fmotd&cloudshell_tutorial=.%2Ftutorial.md" target="_blank">
<img alt="Open in Cloud Shell" src="//gstatic.com/cloudssh/images/open-btn.svg" style="max-height: 44px; margin: 32px auto; max-width: 100%;">
Expand Down Expand Up @@ -94,6 +98,15 @@ The following arguments are supported:
Encryption configuration for the database
Structure is [documented below](#nested_encryption_config).

* `database_dialect` -
(Optional)
The dialect of the Cloud Spanner Database.
If it is not provided, "GOOGLE_STANDARD_SQL" will be used.
Note: Databases that are created with POSTGRESQL dialect do not support
extra DDL statements in the `CreateDatabase` call. You must therefore re-apply
terraform with ddl on the same database after creation.
Possible values are `GOOGLE_STANDARD_SQL` and `POSTGRESQL`.

* `project` - (Optional) The ID of the project in which the resource belongs.
If it is not provided, the provider project is used.

Expand Down

0 comments on commit adb6e10

Please sign in to comment.