From daaf779effa198a4fedc3a8c678afae15f718393 Mon Sep 17 00:00:00 2001 From: Tommy Romano Date: Fri, 19 Jan 2024 13:10:47 -0800 Subject: [PATCH] Basic support for views --- internal/hammer/diff.go | 48 ++++++++++++++++++++++++++- internal/hammer/diff_test.go | 64 ++++++++++++++++++++++++++++++++++++ 2 files changed, 111 insertions(+), 1 deletion(-) diff --git a/internal/hammer/diff.go b/internal/hammer/diff.go index 9a55f71..500d343 100644 --- a/internal/hammer/diff.go +++ b/internal/hammer/diff.go @@ -32,6 +32,7 @@ func NewDatabase(ddl DDL) (*Database, error) { var ( tables []*Table changeStreams []*ChangeStream + views []*View alterDatabaseOptions *spansql.AlterDatabase options spansql.SetDatabaseOptions ) @@ -78,6 +79,9 @@ func NewDatabase(ddl DDL) (*Database, error) { } else { changeStreams = append(changeStreams, &ChangeStream{CreateChangeStream: stmt}) } + case *spansql.CreateView: + v := &View{CreateView: stmt} + views = append(views, v) default: return nil, fmt.Errorf("unexpected ddl statement: %v", stmt) } @@ -92,12 +96,13 @@ func NewDatabase(ddl DDL) (*Database, error) { } } - return &Database{tables: tables, changeStreams: changeStreams, alterDatabaseOptions: alterDatabaseOptions, options: options}, nil + return &Database{tables: tables, changeStreams: changeStreams, views: views, alterDatabaseOptions: alterDatabaseOptions, options: options}, nil } type Database struct { tables []*Table changeStreams []*ChangeStream + views []*View alterDatabaseOptions *spansql.AlterDatabase options spansql.SetDatabaseOptions @@ -111,6 +116,10 @@ type Table struct { changeStreams []*ChangeStream } +type View struct { + *spansql.CreateView +} + type ChangeStream struct { *spansql.CreateChangeStream } @@ -201,6 +210,20 @@ func (g *Generator) GenerateDDL() DDL { ddl.AppendDDL(g.generateDDLForAlterChangeStream(fromChangeStream, cs)) } + // for views + for _, toView := range g.to.views { + _, exists := g.findViewByName(g.from.views, toView.Name) + if !exists { + ddl.Append(toView) + continue + } + ddl.AppendDDL(g.generateDDLForReplaceView(toView)) + } + for _, fromView := range g.from.views { + if _, exists := g.findViewByName(g.to.views, fromView.Name); !exists { + ddl.AppendDDL(g.generateDDLForDropView(fromView)) + } + } return ddl } @@ -815,3 +838,26 @@ func (g *Generator) generateDDLForDropChangeStream(changeStream *ChangeStream) D ddl.Append(spansql.DropChangeStream{Name: changeStream.Name}) return ddl } + +func (g *Generator) findViewByName(views []*View, name spansql.ID) (view *View, exists bool) { + for _, v := range views { + if v.Name == name { + view = v + exists = true + break + } + } + return +} + +func (g *Generator) generateDDLForReplaceView(view *View) DDL { + ddl := DDL{} + ddl.Append(spansql.CreateView{Name: view.Name, Position: view.Position, Query: view.Query, OrReplace: true}) + return ddl +} + +func (g *Generator) generateDDLForDropView(view *View) DDL { + ddl := DDL{} + ddl.Append(spansql.DropView{Name: view.Name}) + return ddl +} diff --git a/internal/hammer/diff_test.go b/internal/hammer/diff_test.go index f36a9f5..618773f 100644 --- a/internal/hammer/diff_test.go +++ b/internal/hammer/diff_test.go @@ -1380,6 +1380,70 @@ CREATE TABLE Nonces ( `ALTER TABLE Nonces ALTER COLUMN expires TIMESTAMP NOT NULL DEFAULT (TIMESTAMP '2000-01-01 12:00:00.000000+00:00')`, }, }, + { + name: "drop view", + from: ` +CREATE TABLE t1 ( + t1_1 INT64 NOT NULL, +) PRIMARY KEY(t1_1); + +CREATE VIEW v1 +SQL SECURITY INVOKER +AS SELECT * FROM t1; +`, + to: ` +CREATE TABLE t1 ( + t1_1 INT64 NOT NULL, +) PRIMARY KEY(t1_1); +`, + expected: []string{ + `DROP VIEW v1`, + }, + }, + { + name: "create view", + from: ` +CREATE TABLE t1 ( + t1_1 INT64 NOT NULL, +) PRIMARY KEY(t1_1); +`, + to: ` +CREATE TABLE t1 ( + t1_1 INT64 NOT NULL, +) PRIMARY KEY(t1_1); + +CREATE VIEW v1 +SQL SECURITY INVOKER +AS SELECT * FROM t1; +`, + expected: []string{ + `CREATE VIEW v1 SQL SECURITY INVOKER AS SELECT * FROM t1`, + }, + }, + { + name: "replace view", + from: ` +CREATE TABLE t1 ( + t1_1 INT64 NOT NULL, +) PRIMARY KEY(t1_1); + +CREATE VIEW v1 +SQL SECURITY INVOKER +AS SELECT * FROM t1 WHERE t1_1 > 0; +`, + to: ` +CREATE TABLE t1 ( + t1_1 INT64 NOT NULL, +) PRIMARY KEY(t1_1); + +CREATE VIEW v1 +SQL SECURITY INVOKER +AS SELECT * FROM t1; +`, + expected: []string{ + `CREATE OR REPLACE VIEW v1 SQL SECURITY INVOKER AS SELECT * FROM t1`, + }, + }, } for _, v := range values { t.Run(v.name, func(t *testing.T) {