Skip to content

Commit

Permalink
feat: add dynamic tables to sdk (#2074)
Browse files Browse the repository at this point in the history
* add dynamic tables to sdk

* update dynamic tables

* minor fixes

* update

* fix int error

* update validations

* go fmt
  • Loading branch information
sfc-gh-swinkler authored Oct 3, 2023
1 parent 9b0825d commit d1dfb05
Show file tree
Hide file tree
Showing 12 changed files with 1,039 additions and 2 deletions.
7 changes: 7 additions & 0 deletions .vscode/launch.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
{
// Use IntelliSense to learn about possible attributes.
// Hover to view descriptions of existing attributes.
// For more information, visit: https://go.microsoft.com/fwlink/?linkid=830387
"version": "0.2.0",
"configurations": []
}
2 changes: 2 additions & 0 deletions pkg/sdk/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ type Client struct {
Comments Comments
Databases Databases
DatabaseRoles DatabaseRoles
DynamicTables DynamicTables
ExternalTables ExternalTables
FailoverGroups FailoverGroups
FileFormats FileFormats
Expand Down Expand Up @@ -130,6 +131,7 @@ func (c *Client) initialize() {
c.ConversionFunctions = &conversionFunctions{client: c}
c.Databases = &databases{client: c}
c.DatabaseRoles = &databaseRoles{client: c}
c.DynamicTables = &dynamicTables{client: c}
c.ExternalTables = &externalTables{client: c}
c.FailoverGroups = &failoverGroups{client: c}
c.FileFormats = &fileFormats{client: c}
Expand Down
2 changes: 1 addition & 1 deletion pkg/sdk/database_role_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ func TestDatabaseRolesShow(t *testing.T) {
}

t.Run("validation: nil options", func(t *testing.T) {
var opts *ShowPipeOptions = nil
var opts *showDatabaseRoleOptions = nil
assertOptsInvalidJoinedErrors(t, opts, errNilOptions)
})

Expand Down
227 changes: 227 additions & 0 deletions pkg/sdk/dynamic_table.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,227 @@
package sdk

import (
"context"
"database/sql"
"time"
)

type DynamicTables interface {
Create(ctx context.Context, request *CreateDynamicTableRequest) error
Alter(ctx context.Context, request *AlterDynamicTableRequest) error
Describe(ctx context.Context, request *DescribeDynamicTableRequest) (*DynamicTableDetails, error)
Drop(ctx context.Context, request *DropDynamicTableRequest) error
Show(ctx context.Context, opts *ShowDynamicTableRequest) ([]DynamicTable, error)
ShowByID(ctx context.Context, id AccountObjectIdentifier) (*DynamicTable, error)
}

// createDynamicTableOptions is based on https://docs.snowflake.com/en/sql-reference/sql/create-dynamic-table
type createDynamicTableOptions struct {
create bool `ddl:"static" sql:"CREATE"`
OrReplace *bool `ddl:"keyword" sql:"OR REPLACE"`
dynamicTable bool `ddl:"static" sql:"DYNAMIC TABLE"`
name SchemaObjectIdentifier `ddl:"identifier"`
targetLag TargetLag `ddl:"parameter,no_quotes" sql:"TARGET_LAG"`
warehouse AccountObjectIdentifier `ddl:"identifier,equals" sql:"WAREHOUSE"`
Comment *string `ddl:"parameter,single_quotes" sql:"COMMENT"`
query string `ddl:"parameter,no_equals,no_quotes" sql:"AS"`
}

type TargetLag struct {
Lagtime *string `ddl:"keyword,single_quotes"`
Downstream *bool `ddl:"keyword" sql:"DOWNSTREAM"`
}

type DynamicTableSet struct {
TargetLag *TargetLag `ddl:"parameter,no_quotes" sql:"TARGET_LAG"`
Warehouse *AccountObjectIdentifier `ddl:"identifier,equals" sql:"WAREHOUSE"`
}

// alterDynamicTableOptions is based on https://docs.snowflake.com/en/sql-reference/sql/alter-dynamic-table
type alterDynamicTableOptions struct {
alter bool `ddl:"static" sql:"ALTER"`
dynamicTable bool `ddl:"static" sql:"DYNAMIC TABLE"`
name SchemaObjectIdentifier `ddl:"identifier"`

Suspend *bool `ddl:"keyword" sql:"SUSPEND"`
Resume *bool `ddl:"keyword" sql:"RESUME"`
Refresh *bool `ddl:"keyword" sql:"REFRESH"`
Set *DynamicTableSet `ddl:"keyword" sql:"SET"`
}

// dropDynamicTableOptions is based on https://docs.snowflake.com/en/sql-reference/sql/drop-dynamic-table
type dropDynamicTableOptions struct {
drop bool `ddl:"static" sql:"DROP"`
dynamicTable bool `ddl:"static" sql:"DYNAMIC TABLE"`
name SchemaObjectIdentifier `ddl:"identifier"`
}

// showDynamicTableOptions is based on https://docs.snowflake.com/en/sql-reference/sql/show-dynamic-tables
type showDynamicTableOptions struct {
show bool `ddl:"static" sql:"SHOW"`
dynamicTable bool `ddl:"static" sql:"DYNAMIC TABLES"`
Like *Like `ddl:"keyword" sql:"LIKE"`
In *In `ddl:"keyword" sql:"IN"`
StartsWith *string `ddl:"parameter,single_quotes,no_equals" sql:"STARTS WITH"`
Limit *LimitFrom `ddl:"keyword" sql:"LIMIT"`
}

type DynamicTableRefreshMode string

const (
DynamicTableRefreshModeIncremental DynamicTableRefreshMode = "INCREMENTAL"
DynamicTableRefreshModeFull DynamicTableRefreshMode = "FULL"
)

type DynamicTableSchedulingState string

const (
DynamicTableSchedulingStateRunning DynamicTableSchedulingState = "RUNNING"
DynamicTableSchedulingStateSuspended DynamicTableSchedulingState = "SUSPENDED"
)

type DynamicTable struct {
CreatedOn time.Time
Name string
Reserved string
DatabaseName string
SchemaName string
ClusterBy string
Rows int
Bytes int
Owner string
TargetLag string
RefreshMode DynamicTableRefreshMode
RefreshModeReason string
Warehouse string
Comment string
Text string
AutomaticClustering bool
SchedulingState DynamicTableSchedulingState
LastSuspendedOn time.Time
IsClone bool
IsReplica bool
DataTimestamp time.Time
}

func (dt *DynamicTable) ID() SchemaObjectIdentifier {
return NewSchemaObjectIdentifier(dt.DatabaseName, dt.SchemaName, dt.Name)
}

type dynamicTableRow struct {
CreatedOn time.Time `db:"created_on"`
Name string `db:"name"`
Reserved string `db:"reserved"`
DatabaseName string `db:"database_name"`
SchemaName string `db:"schema_name"`
ClusterBy string `db:"cluster_by"`
Rows int `db:"rows"`
Bytes int `db:"bytes"`
Owner string `db:"owner"`
TargetLag string `db:"target_lag"`
RefreshMode string `db:"refresh_mode"`
RefreshModeReason sql.NullString `db:"refresh_mode_reason"`
Warehouse string `db:"warehouse"`
Comment string `db:"comment"`
Text string `db:"text"`
AutomaticClustering string `db:"automatic_clustering"`
SchedulingState string `db:"scheduling_state"`
LastSuspendedOn sql.NullTime `db:"last_suspended_on"`
IsClone bool `db:"is_clone"`
IsReplica bool `db:"is_replica"`
DataTimestamp time.Time `db:"data_timestamp"`
}

func (dtr dynamicTableRow) convert() *DynamicTable {
dt := &DynamicTable{
CreatedOn: dtr.CreatedOn,
Name: dtr.Name,
Reserved: dtr.Reserved,
DatabaseName: dtr.DatabaseName,
SchemaName: dtr.SchemaName,
ClusterBy: dtr.ClusterBy,
Rows: dtr.Rows,
Bytes: dtr.Bytes,
Owner: dtr.Owner,
TargetLag: dtr.TargetLag,
RefreshMode: DynamicTableRefreshMode(dtr.RefreshMode),
Warehouse: dtr.Warehouse,
Comment: dtr.Comment,
Text: dtr.Text,
AutomaticClustering: dtr.AutomaticClustering == "ON", // "ON" or "OFF
SchedulingState: DynamicTableSchedulingState(dtr.SchedulingState),
IsClone: dtr.IsClone,
IsReplica: dtr.IsReplica,
DataTimestamp: dtr.DataTimestamp,
}
if dtr.RefreshModeReason.Valid {
dt.RefreshModeReason = dtr.RefreshModeReason.String
}
if dtr.LastSuspendedOn.Valid {
dt.LastSuspendedOn = dtr.LastSuspendedOn.Time
}
return dt
}

// describeDynamicTableOptions is based on https://docs.snowflake.com/en/sql-reference/sql/desc-dynamic-table
type describeDynamicTableOptions struct {
describe bool `ddl:"static" sql:"DESCRIBE"`
dynamicTable bool `ddl:"static" sql:"DYNAMIC TABLE"`
name SchemaObjectIdentifier `ddl:"identifier"`
}

type DynamicTableDetails struct {
Name string
Type DataType
Kind string
IsNull bool
Default string
PrimaryKey string
UniqueKey string
Check string
Expression string
Comment string
PolicyName string
}

type dynamicTableDetailsRow struct {
Name string `db:"name"`
Type string `db:"type"`
Kind string `db:"kind"`
IsNull string `db:"null?"`
Default sql.NullString `db:"default"`
PrimaryKey string `db:"primary key"`
UniqueKey string `db:"unique key"`
Check sql.NullString `db:"check"`
Expression sql.NullString `db:"expression"`
Comment sql.NullString `db:"comment"`
PolicyName sql.NullString `db:"policy name"`
}

func (row dynamicTableDetailsRow) convert() *DynamicTableDetails {
typ, _ := ToDataType(row.Type)
dtd := &DynamicTableDetails{
Name: row.Name,
Type: typ,
Kind: row.Kind,
IsNull: row.IsNull == "Y",
PrimaryKey: row.PrimaryKey,
UniqueKey: row.UniqueKey,
}
if row.Default.Valid {
dtd.Default = row.Default.String
}
if row.Check.Valid {
dtd.Check = row.Check.String
}
if row.Expression.Valid {
dtd.Expression = row.Expression.String
}
if row.Comment.Valid {
dtd.Comment = row.Comment.String
}
if row.PolicyName.Valid {
dtd.PolicyName = row.PolicyName.String
}
return dtd
}
51 changes: 51 additions & 0 deletions pkg/sdk/dynamic_table_dto.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
package sdk

//go:generate go run ./dto-builder-generator/main.go

var (
_ optionsProvider[createDynamicTableOptions] = new(CreateDynamicTableRequest)
_ optionsProvider[alterDynamicTableOptions] = new(AlterDynamicTableRequest)
_ optionsProvider[dropDynamicTableOptions] = new(DropDynamicTableRequest)
_ optionsProvider[showDynamicTableOptions] = new(ShowDynamicTableRequest)
)

type CreateDynamicTableRequest struct {
orReplace bool

name SchemaObjectIdentifier // required
warehouse AccountObjectIdentifier // required
targetLag TargetLag // required
query string // required

comment *string
}

type AlterDynamicTableRequest struct {
name SchemaObjectIdentifier // required

// One of
suspend *bool
resume *bool
refresh *bool
set *DynamicTableSetRequest
}

type DynamicTableSetRequest struct {
targetLag *TargetLag
warehourse *AccountObjectIdentifier
}

type DropDynamicTableRequest struct {
name SchemaObjectIdentifier // required
}

type DescribeDynamicTableRequest struct {
name SchemaObjectIdentifier // required
}

type ShowDynamicTableRequest struct {
like *Like
in *In
startsWith *string
limit *LimitFrom
}
Loading

0 comments on commit d1dfb05

Please sign in to comment.