Skip to content

Commit ab4e159

Browse files
Add dialect to spanner database (#5799) (#4158)
Signed-off-by: Modular Magician <[email protected]>
1 parent 1addc4c commit ab4e159

File tree

4 files changed

+132
-0
lines changed

4 files changed

+132
-0
lines changed

.changelog/5799.txt

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
```release-note:enhancement
2+
spanner: added support for setting database_dialect on `google_spanner_database`
3+
```

google-beta/resource_spanner_database.go

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,18 @@ func resourceSpannerDatabase() *schema.Resource {
9090
ValidateFunc: validateRegexp(`^[a-z][a-z0-9_\-]*[a-z0-9]$`),
9191
Description: `A unique identifier for the database, which cannot be changed after
9292
the instance is created. Values are of the form [a-z][-a-z0-9]*[a-z0-9].`,
93+
},
94+
"database_dialect": {
95+
Type: schema.TypeString,
96+
Computed: true,
97+
Optional: true,
98+
ForceNew: true,
99+
ValidateFunc: validateEnum([]string{"GOOGLE_STANDARD_SQL", "POSTGRESQL", ""}),
100+
Description: `The dialect of the Cloud Spanner Database.
101+
If it is not provided, "GOOGLE_STANDARD_SQL" will be used.
102+
Note: Databases that are created with POSTGRESQL dialect do not support
103+
extra DDL statements in the 'CreateDatabase' call. You must therefore re-apply
104+
terraform with ddl on the same database after creation. Possible values: ["GOOGLE_STANDARD_SQL", "POSTGRESQL"]`,
93105
},
94106
"ddl": {
95107
Type: schema.TypeList,
@@ -167,6 +179,12 @@ func resourceSpannerDatabaseCreate(d *schema.ResourceData, meta interface{}) err
167179
} else if v, ok := d.GetOkExists("encryption_config"); !isEmptyValue(reflect.ValueOf(encryptionConfigProp)) && (ok || !reflect.DeepEqual(v, encryptionConfigProp)) {
168180
obj["encryptionConfig"] = encryptionConfigProp
169181
}
182+
databaseDialectProp, err := expandSpannerDatabaseDatabaseDialect(d.Get("database_dialect"), d, config)
183+
if err != nil {
184+
return err
185+
} else if v, ok := d.GetOkExists("database_dialect"); !isEmptyValue(reflect.ValueOf(databaseDialectProp)) && (ok || !reflect.DeepEqual(v, databaseDialectProp)) {
186+
obj["databaseDialect"] = databaseDialectProp
187+
}
170188
instanceProp, err := expandSpannerDatabaseInstance(d.Get("instance"), d, config)
171189
if err != nil {
172190
return err
@@ -307,6 +325,9 @@ func resourceSpannerDatabaseRead(d *schema.ResourceData, meta interface{}) error
307325
if err := d.Set("encryption_config", flattenSpannerDatabaseEncryptionConfig(res["encryptionConfig"], d, config)); err != nil {
308326
return fmt.Errorf("Error reading Database: %s", err)
309327
}
328+
if err := d.Set("database_dialect", flattenSpannerDatabaseDatabaseDialect(res["databaseDialect"], d, config)); err != nil {
329+
return fmt.Errorf("Error reading Database: %s", err)
330+
}
310331
if err := d.Set("instance", flattenSpannerDatabaseInstance(res["instance"], d, config)); err != nil {
311332
return fmt.Errorf("Error reading Database: %s", err)
312333
}
@@ -478,6 +499,10 @@ func flattenSpannerDatabaseEncryptionConfigKmsKeyName(v interface{}, d *schema.R
478499
return v
479500
}
480501

502+
func flattenSpannerDatabaseDatabaseDialect(v interface{}, d *schema.ResourceData, config *Config) interface{} {
503+
return v
504+
}
505+
481506
func flattenSpannerDatabaseInstance(v interface{}, d *schema.ResourceData, config *Config) interface{} {
482507
if v == nil {
483508
return v
@@ -516,6 +541,10 @@ func expandSpannerDatabaseEncryptionConfigKmsKeyName(v interface{}, d TerraformR
516541
return v, nil
517542
}
518543

544+
func expandSpannerDatabaseDatabaseDialect(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
545+
return v, nil
546+
}
547+
519548
func expandSpannerDatabaseInstance(v interface{}, d TerraformResourceData, config *Config) (interface{}, error) {
520549
f, err := parseGlobalFieldValue("instances", v.(string), "project", d, config, true)
521550
if err != nil {
@@ -526,6 +555,9 @@ func expandSpannerDatabaseInstance(v interface{}, d TerraformResourceData, confi
526555

527556
func resourceSpannerDatabaseEncoder(d *schema.ResourceData, meta interface{}, obj map[string]interface{}) (map[string]interface{}, error) {
528557
obj["createStatement"] = fmt.Sprintf("CREATE DATABASE `%s`", obj["name"])
558+
if dialect, ok := obj["databaseDialect"]; ok && dialect == "POSTGRESQL" {
559+
obj["createStatement"] = fmt.Sprintf("CREATE DATABASE %s", obj["name"])
560+
}
529561
delete(obj, "name")
530562
delete(obj, "instance")
531563
return obj, nil

google-beta/resource_spanner_database_test.go

Lines changed: 84 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,90 @@ resource "google_spanner_database" "basic" {
116116
`, instanceName, instanceName, databaseName)
117117
}
118118

119+
func TestAccSpannerDatabase_postgres(t *testing.T) {
120+
t.Parallel()
121+
122+
rnd := randString(t, 10)
123+
instanceName := fmt.Sprintf("tf-test-%s", rnd)
124+
databaseName := fmt.Sprintf("tfgen_%s", rnd)
125+
126+
vcrTest(t, resource.TestCase{
127+
PreCheck: func() { testAccPreCheck(t) },
128+
Providers: testAccProviders,
129+
CheckDestroy: testAccCheckSpannerDatabaseDestroyProducer(t),
130+
Steps: []resource.TestStep{
131+
{
132+
Config: testAccSpannerDatabase_postgres(instanceName, databaseName),
133+
Check: resource.ComposeTestCheckFunc(
134+
resource.TestCheckResourceAttrSet("google_spanner_database.basic_spangres", "state"),
135+
),
136+
},
137+
{
138+
// Test import with default Terraform ID
139+
ResourceName: "google_spanner_database.basic_spangres",
140+
ImportState: true,
141+
ImportStateVerify: true,
142+
ImportStateVerifyIgnore: []string{"ddl", "deletion_protection"},
143+
},
144+
{
145+
Config: testAccSpannerDatabase_postgresUpdate(instanceName, databaseName),
146+
Check: resource.ComposeTestCheckFunc(
147+
resource.TestCheckResourceAttrSet("google_spanner_database.basic_spangres", "state"),
148+
),
149+
},
150+
{
151+
// Test import with default Terraform ID
152+
ResourceName: "google_spanner_database.basic_spangres",
153+
ImportState: true,
154+
ImportStateVerify: true,
155+
ImportStateVerifyIgnore: []string{"ddl", "deletion_protection"},
156+
},
157+
},
158+
})
159+
}
160+
161+
func testAccSpannerDatabase_postgres(instanceName, databaseName string) string {
162+
return fmt.Sprintf(`
163+
resource "google_spanner_instance" "basic" {
164+
name = "%s"
165+
config = "regional-us-central1"
166+
display_name = "%s-display"
167+
num_nodes = 1
168+
}
169+
170+
resource "google_spanner_database" "basic_spangres" {
171+
instance = google_spanner_instance.basic.name
172+
name = "%s_spangres"
173+
database_dialect = "POSTGRESQL"
174+
deletion_protection = false
175+
}
176+
`, instanceName, instanceName, databaseName)
177+
}
178+
179+
func testAccSpannerDatabase_postgresUpdate(instanceName, databaseName string) string {
180+
return fmt.Sprintf(`
181+
resource "google_spanner_instance" "basic" {
182+
name = "%s"
183+
config = "regional-us-central1"
184+
display_name = "%s-display"
185+
num_nodes = 1
186+
}
187+
188+
resource "google_spanner_database" "basic_spangres" {
189+
instance = google_spanner_instance.basic.name
190+
name = "%s_spangres"
191+
database_dialect = "POSTGRESQL"
192+
ddl = [
193+
"CREATE TABLE t1 (t1 bigint NOT NULL PRIMARY KEY)",
194+
"CREATE TABLE t2 (t2 bigint NOT NULL PRIMARY KEY)",
195+
"CREATE TABLE t3 (t3 bigint NOT NULL PRIMARY KEY)",
196+
"CREATE TABLE t4 (t4 bigint NOT NULL PRIMARY KEY)",
197+
]
198+
deletion_protection = false
199+
}
200+
`, instanceName, instanceName, databaseName)
201+
}
202+
119203
// Unit Tests for type spannerDatabaseId
120204
func TestDatabaseNameForApi(t *testing.T) {
121205
id := spannerDatabaseId{

website/docs/r/spanner_database.html.markdown

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ On older versions, it is strongly recommended to set `lifecycle { prevent_destro
3838
on databases in order to prevent accidental data loss. See [Terraform docs](https://www.terraform.io/docs/configuration/resources.html#prevent_destroy)
3939
for more information on lifecycle parameters.
4040

41+
Note: Databases that are created with POSTGRESQL dialect do not support
42+
extra DDL statements in the `CreateDatabase` call. You must therefore re-apply
43+
terraform with ddl on the same database after creation.
44+
4145
<div class = "oics-button" style="float: right; margin: 0 0 -15px">
4246
<a href="https://console.cloud.google.com/cloudshell/open?cloudshell_git_repo=https%3A%2F%2Fgithub.com%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">
4347
<img alt="Open in Cloud Shell" src="//gstatic.com/cloudssh/images/open-btn.svg" style="max-height: 44px; margin: 32px auto; max-width: 100%;">
@@ -94,6 +98,15 @@ The following arguments are supported:
9498
Encryption configuration for the database
9599
Structure is [documented below](#nested_encryption_config).
96100

101+
* `database_dialect` -
102+
(Optional)
103+
The dialect of the Cloud Spanner Database.
104+
If it is not provided, "GOOGLE_STANDARD_SQL" will be used.
105+
Note: Databases that are created with POSTGRESQL dialect do not support
106+
extra DDL statements in the `CreateDatabase` call. You must therefore re-apply
107+
terraform with ddl on the same database after creation.
108+
Possible values are `GOOGLE_STANDARD_SQL` and `POSTGRESQL`.
109+
97110
* `project` - (Optional) The ID of the project in which the resource belongs.
98111
If it is not provided, the provider project is used.
99112

0 commit comments

Comments
 (0)