Skip to content

Commit 6e4eb0c

Browse files
authored
Merge pull request #60 from Recidiviz/dankurtz/delete-views-created-via-query
Allow deletion of views created by `CREATE VIEW` queries
2 parents 794cf4d + 3bebadf commit 6e4eb0c

File tree

2 files changed

+71
-26
lines changed

2 files changed

+71
-26
lines changed

server/handler.go

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2110,7 +2110,12 @@ func (h *jobsInsertHandler) Handle(ctx context.Context, r *jobsInsertRequest) (*
21102110
job.Configuration.Query.QueryParameters,
21112111
)
21122112
endTime := time.Now()
2113-
if job.JobReference.JobId == "" {
2113+
if job.JobReference == nil {
2114+
job.JobReference = &bigqueryv2.JobReference{
2115+
ProjectId: r.project.ID,
2116+
JobId: randomID(),
2117+
}
2118+
} else if job.JobReference.JobId == "" {
21142119
job.JobReference.JobId = randomID() // generate job id
21152120
}
21162121
if jobErr == nil {
@@ -2256,14 +2261,20 @@ func addTableMetadata(ctx context.Context, server *Server, spec *zetasqlite.Tabl
22562261
return err
22572262
}
22582263
defer tx.RollbackIfNotCommitted()
2259-
if _, err := createTableMetadata(ctx, tx, server, project, dataset, &bigqueryv2.Table{
2264+
table := &bigqueryv2.Table{
22602265
TableReference: &bigqueryv2.TableReference{
22612266
ProjectId: projectID,
22622267
DatasetId: datasetID,
22632268
TableId: tableID,
22642269
},
22652270
Schema: &bigqueryv2.TableSchema{Fields: fields},
2266-
}); err != nil {
2271+
}
2272+
if spec.IsView {
2273+
table.View = &bigqueryv2.ViewDefinition{
2274+
Query: spec.Query,
2275+
}
2276+
}
2277+
if _, err := createTableMetadata(ctx, tx, server, project, dataset, table); err != nil {
22672278
return err
22682279
}
22692280
if err := tx.Commit(); err != nil {

test/python/emulator_test.py

Lines changed: 57 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -671,7 +671,7 @@ def test_invalid_data_load_fails(self) -> None:
671671
],
672672
)
673673
with self.assertRaisesRegex(
674-
RuntimeError, "failed to convert 202-06-06 to time.Time type"
674+
RuntimeError, "failed to convert 202-06-06 to time.Time type"
675675
):
676676
self.load_rows_into_table(address, data=[{"a": "202-06-06"}])
677677

@@ -703,7 +703,7 @@ def test_array_agg_with_nulls(self) -> None:
703703
GROUP BY b;
704704
"""
705705
with self.assertRaisesRegex(
706-
Exception, r"ARRAY_AGG: input value must be not null"
706+
Exception, r"ARRAY_AGG: input value must be not null"
707707
):
708708
self.run_query_test(
709709
query,
@@ -783,6 +783,39 @@ def test_drop_view(self) -> None:
783783
example_view = client.create_table(_view_definition)
784784
client.delete_table(example_view)
785785

786+
def test_drop_view_created_via_sql(self) -> None:
787+
"""Ensures we can delete views created via CREATE VIEW SQL statements."""
788+
client = self.client
789+
# Create dataset and source table
790+
client.create_dataset("sql_view_dataset")
791+
client.create_table(
792+
bigquery.Table(
793+
f"{BQ_EMULATOR_PROJECT_ID}.sql_view_dataset.source_table",
794+
[
795+
bigquery.SchemaField("id", "INTEGER"),
796+
bigquery.SchemaField("name", "STRING"),
797+
],
798+
)
799+
)
800+
801+
# Create view using CREATE VIEW SQL statement
802+
create_view_query = f"""
803+
CREATE VIEW `{BQ_EMULATOR_PROJECT_ID}.sql_view_dataset.sql_view`
804+
AS SELECT id, name FROM `{BQ_EMULATOR_PROJECT_ID}.sql_view_dataset.source_table`
805+
"""
806+
self.query(create_view_query)
807+
808+
# Verify the view was created and has correct type
809+
view = client.get_table(f"{BQ_EMULATOR_PROJECT_ID}.sql_view_dataset.sql_view")
810+
self.assertEqual(view.table_type, "VIEW")
811+
812+
# Delete the view using delete_table - this should succeed
813+
client.delete_table(view)
814+
815+
# Verify the view is gone
816+
with self.assertRaises(Exception):
817+
client.get_table(f"{BQ_EMULATOR_PROJECT_ID}.sql_view_dataset.sql_view")
818+
786819
# TODO(#39819) Update this test when the emulator quotes date values here
787820
def test_json_string_column(self) -> None:
788821
query = """
@@ -877,8 +910,8 @@ def test_query_from_pandas_call(self) -> None:
877910

878911
# A similar mocking approach didn't quite work. More work to be done.
879912
with self.assertRaisesRegex(
880-
RuntimeError,
881-
"Writing to the emulator from pandas is not currently supported.",
913+
RuntimeError,
914+
"Writing to the emulator from pandas is not currently supported.",
882915
):
883916
more_data = pd.DataFrame(
884917
[{"a": 42, "b": "bar"}, {"a": 43, "b": "baz"}],
@@ -919,7 +952,9 @@ def test_read_bigquery_storage(self) -> None:
919952
),
920953
]
921954

922-
dataset_ref = DatasetReference(project=self.project_id, dataset_id="test_dataset")
955+
dataset_ref = DatasetReference(
956+
project=self.project_id, dataset_id="test_dataset"
957+
)
923958
self.client.create_dataset(dataset_ref.dataset_id, exists_ok=True)
924959
table_ref = TableReference(dataset_ref, f"test_table_{format_.lower()}")
925960
table = bigquery.Table(table_ref, schema=schema)
@@ -933,7 +968,7 @@ def test_read_bigquery_storage(self) -> None:
933968
"int_col": 42,
934969
"float_col": 3.14,
935970
"bool_col": True,
936-
"bytes_col": base64.b64encode(b"abc").decode('utf-8'),
971+
"bytes_col": base64.b64encode(b"abc").decode("utf-8"),
937972
"date_col": "2024-01-01",
938973
"datetime_col": "2024-01-01T12:00:00",
939974
"timestamp_col": "2024-01-01T12:00:00Z",
@@ -1027,7 +1062,6 @@ def test_read_bigquery_storage(self) -> None:
10271062
else:
10281063
assert False, "Unsupported format"
10291064

1030-
10311065
def test_timestamp_min_max(self) -> None:
10321066
"""Tests resolution of https://github.com/goccy/go-zetasqlite/issues/132
10331067
and https://github.com/goccy/bigquery-emulator/issues/262"""
@@ -1066,8 +1100,8 @@ def test_numeric_min_max(self) -> None:
10661100
""",
10671101
expected_result=[
10681102
{
1069-
"min_numeric": Decimal('-99999999999999999999999999999.999999999'),
1070-
"max_numeric": Decimal('99999999999999999999999999999.999999999'),
1103+
"min_numeric": Decimal("-99999999999999999999999999999.999999999"),
1104+
"max_numeric": Decimal("99999999999999999999999999999.999999999"),
10711105
}
10721106
],
10731107
)
@@ -1081,8 +1115,12 @@ def test_bignumeric_min_max(self) -> None:
10811115
""",
10821116
expected_result=[
10831117
{
1084-
"min_bignumeric": Decimal('-578960446186580977117854925043439539266.34992332820282019728792003956564819968'),
1085-
"max_bignumeric": Decimal('578960446186580977117854925043439539266.34992332820282019728792003956564819967'),
1118+
"min_bignumeric": Decimal(
1119+
"-578960446186580977117854925043439539266.34992332820282019728792003956564819968"
1120+
),
1121+
"max_bignumeric": Decimal(
1122+
"578960446186580977117854925043439539266.34992332820282019728792003956564819967"
1123+
),
10861124
}
10871125
],
10881126
)
@@ -1196,17 +1234,17 @@ def test_bytes_field_base64_encoding(self) -> None:
11961234
# Test case 1: Simple ASCII string "Hello"
11971235
# Original bytes: b'Hello'
11981236
# Expected base64: 'SGVsbG8='
1199-
hello_bytes = b'Hello'
1200-
hello_base64 = base64.b64encode(hello_bytes).decode('utf-8')
1201-
self.assertEqual(hello_base64, 'SGVsbG8=')
1237+
hello_bytes = b"Hello"
1238+
hello_base64 = base64.b64encode(hello_bytes).decode("utf-8")
1239+
self.assertEqual(hello_base64, "SGVsbG8=")
12021240

12031241
# Test case 2: Binary data with various byte values
1204-
binary_bytes = bytes([0x48, 0x65, 0x6c, 0x6c, 0x6f, 0x00, 0xFF, 0xAB])
1205-
binary_base64 = base64.b64encode(binary_bytes).decode('utf-8')
1242+
binary_bytes = bytes([0x48, 0x65, 0x6C, 0x6C, 0x6F, 0x00, 0xFF, 0xAB])
1243+
binary_base64 = base64.b64encode(binary_bytes).decode("utf-8")
12061244

12071245
# Test case 3: Empty bytes
1208-
empty_bytes = b''
1209-
empty_base64 = base64.b64encode(empty_bytes).decode('utf-8')
1246+
empty_bytes = b""
1247+
empty_base64 = base64.b64encode(empty_bytes).decode("utf-8")
12101248

12111249
# Load data into table
12121250
# The BigQuery Python client expects base64-encoded strings for BYTES fields
@@ -1247,11 +1285,7 @@ def test_bytes_field_base64_encoding(self) -> None:
12471285
self.run_query_test(
12481286
query_with_to_base64,
12491287
expected_result=[
1250-
{
1251-
"id": 1,
1252-
"binary_data": hello_bytes,
1253-
"explicit_base64": hello_base64
1254-
},
1288+
{"id": 1, "binary_data": hello_bytes, "explicit_base64": hello_base64},
12551289
{
12561290
"id": 2,
12571291
"binary_data": binary_bytes,

0 commit comments

Comments
 (0)