Skip to content

Commit

Permalink
feat: Add task to SDK (#2099)
Browse files Browse the repository at this point in the history
* Add initial create task definition

* Add generated create task files

* Add validate field validation to generator

* Define alter for task

* Add WIP defs for drop, show and desc

* Add custom operation to generator and use it in task def

* Add ShowByID operation to generator and use it in task def

* Add better template for ShowByID

* Finish show definition

* Finish describe definition

* Remove comment

* Generation ended here

* Update READMEs

* Add mappings and fix methods

* Add create validation tests

* Add tests to create

* Use builder in create task test

* Pass alter task validation tests

* Implement task alter tests (WIP)

* Fix def and generation

* Pass all alter tests for task

* Pass all unit tests for task

* Prepare common resources for integration tests

* List all the integration tests for tasks

* Pass the first integration test for task

* Pass almost complete integration test for create task

* Pass drop tests for task

* Pass some alter tests for task

* Pass suspend and resume for task

* Pass modifying as and when for task

* Rename copy-paste errors

* Pass show and describe tests for task

* Pass execute test for task

* Adjust assert task defaults

* Adjust assert task with optionals

* Adjust assert task with terse

* Pass create task with after

* Add test for copy grants

* Add create task with tag test

* Add remove and add after alter task test

* Update generator README possible improvements

* Fix formatting

* Use create method for task

* Fix suspend and resume test

* Refactor parameter builders

* Use WarehouseSize

* Add tests for initial warehouse size

* Fix unit tests

* Fix after review
  • Loading branch information
sfc-gh-asawicki authored Oct 9, 2023
1 parent 2380e33 commit d52f334
Show file tree
Hide file tree
Showing 21 changed files with 2,155 additions and 78 deletions.
14 changes: 7 additions & 7 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -80,22 +80,22 @@ Integration status - indicates if given resource / datasource is using new SDK.
| Notification Integration || snowflake_notification_integration | snowflake_integrations ||
| Security Integration || snowflake_security_integration | snowflake_integrations ||
| Storage Integration || snowflake_storage_integration | snowflake_integrations ||
| Network Policy | | snowflake_network_policy | snowflake_network_policy ||
| Network Policy | | snowflake_network_policy | snowflake_network_policy ||
| Password Policy || snowflake_password_policy | snowflake_password_policy ||
| Session Policy | | snowflake_session_policy | snowflake_session_policy ||
| Session Policy | | snowflake_session_policy | snowflake_session_policy ||
| Replication Group || snowflake_replication_group | snowflake_replication_group ||
| Failover Group || snowflake_failover_group | snowflake_failover_group ||
| Connection || snowflake_connection | snowflake_connection ||
| Account Parameters | 🟨 | snowflake_account_parameter | snowflake_parameters ||
| Session Parameters | 🟨 | snowflake_session_parameter | snowflake_parameters ||
| Object Parameters | 🟨 | snowflake_object_parameter | snowflake_parameters ||
| Account Parameters | | snowflake_account_parameter | snowflake_parameters ||
| Session Parameters | | snowflake_session_parameter | snowflake_parameters ||
| Object Parameters | | snowflake_object_parameter | snowflake_parameters ||
| Warehouse || snowflake_warehouse | snowflake_warehouse | 🟨 |
| Resource Monitor || snowflake_resource_monitor | snowflake_resource_monitor ||
| Database || snowflake_database | snowflake_database ||
| Schema || snowflake_schema | snowflake_schema ||
| Share || snowflake_share | snowflake_share ||
| Table | 👨‍💻 | snowflake_table | snowflake_table ||
| Dynamic Table | | snowflake_dynamic_table | snowflake_dynamic_table ||
| Dynamic Table | | snowflake_dynamic_table | snowflake_dynamic_table ||
| External Table || snowflake_external_table | snowflake_external_table ||
| Event Table || snowflake_event_table | snowflake_event_table ||
| View || snowflake_view | snowflake_view ||
Expand All @@ -105,7 +105,7 @@ Integration status - indicates if given resource / datasource is using new SDK.
| External Function || snowflake_external_function | snowflake_external_function ||
| Stored Procedure || snowflake_stored_procedure | snowflake_stored_procedure ||
| Stream || snowflake_stream | snowflake_stream ||
| Task | | snowflake_task | snowflake_task ||
| Task | | snowflake_task | snowflake_task ||
| Masking Policy || snowflake_masking_policy | snowflake_masking_policy ||
| Row Access Policy || snowflake_row_access_policy | snowflake_row_access_policy ||
| Tag || snowflake_tag | snowflake_tag ||
Expand Down
2 changes: 2 additions & 0 deletions pkg/sdk/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ type Client struct {
SessionPolicies SessionPolicies
Sessions Sessions
Shares Shares
Tasks Tasks
Users Users
Schemas Schemas
Warehouses Warehouses
Expand Down Expand Up @@ -149,6 +150,7 @@ func (c *Client) initialize() {
c.Shares = &shares{client: c}
c.Schemas = &schemas{client: c}
c.SystemFunctions = &systemFunctions{client: c}
c.Tasks = &tasks{client: c}
c.Users = &users{client: c}
c.Warehouses = &warehouses{client: c}
}
Expand Down
13 changes: 13 additions & 0 deletions pkg/sdk/poc/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -33,8 +33,16 @@ To invoke example generation (with first cleaning all the generated files) run:
make clean-generator-poc run-generator-poc
```

To invoke generation inside SDK package (with cleaning), e.g. for `session_policies` run (mind the `_`(underscore)):
```shell
make clean-generator-session_policies run-generator-session_policies
```

### Next steps
##### Essentials
- fix builder generation (`With`s for optional fields should have required param, optional fields should not be exported in `Request` structs)
- generate each branch of alter in tests (instead of basic and all options)
- clean up predefined operations in generator (now casting to string)
- (?) add mapping from db to plain struct (for now only "// TODO: Mapping" comment is generated)
- add arguments to the generator, so we'll be able to specify which files should be generated / re-generated,
because after we fill things that need our input we don't want to re-generate those files and override the changes,
Expand Down Expand Up @@ -85,8 +93,13 @@ find a better solution to solve the issue (add more logic to the templates ?)
- when calling .SelfIdentifier we can implicitly also add validateObjectIdentifier validation rule
- enforce user to use KindOf... functions with interface
- example implementation - StringTyper implements Typer and all the KindOf... functions use StringTyper to return Typer easily - https://go.dev/play/p/TZZgSkkHw_M
- `queryStruct` should be spilled into `Operation` interface file, because the idea was to have model which is unaware of DSL used to create it.
- generate full tests for common types (e.g. setting/unsetting tags)
- generate common resources for integration tests
- cleanup the design of builders in DSL (e.g. why transformer has to be always added?)

##### Known issues
- generating two converts when Show and Desc use the same data structure
- wrong generated validations for validIdentifierIfSet for cases like
```go
A := QueryStruct("A").
Expand Down
36 changes: 36 additions & 0 deletions pkg/sdk/poc/generator/field_transformers.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,11 @@ func (v *KeywordTransformer) SQL(sqlPrefix string) *KeywordTransformer {
return v
}

func (v *KeywordTransformer) NoQuotes() *KeywordTransformer {
v.quotes = "no_quotes"
return v
}

func (v *KeywordTransformer) SingleQuotes() *KeywordTransformer {
v.quotes = "single_quotes"
return v
Expand All @@ -51,6 +56,7 @@ type ParameterTransformer struct {
sqlPrefix string
quotes string
parentheses string
equals string
}

func ParameterOptions() *ParameterTransformer {
Expand All @@ -72,6 +78,11 @@ func (v *ParameterTransformer) NoQuotes() *ParameterTransformer {
return v
}

func (v *ParameterTransformer) NoEquals() *ParameterTransformer {
v.equals = "no_equals"
return v
}

func (v *ParameterTransformer) SingleQuotes() *ParameterTransformer {
v.quotes = "single_quotes"
return v
Expand All @@ -82,6 +93,11 @@ func (v *ParameterTransformer) DoubleQuotes() *ParameterTransformer {
return v
}

func (v *ParameterTransformer) NoParentheses() *ParameterTransformer {
v.quotes = "no_parentheses"
return v
}

func (v *ParameterTransformer) Parentheses() *ParameterTransformer {
v.quotes = "parentheses"
return v
Expand All @@ -95,13 +111,15 @@ func (v *ParameterTransformer) Transform(f *Field) *Field {
addTagIfMissing(f.Tags, "sql", v.sqlPrefix)
addTagIfMissing(f.Tags, "ddl", v.quotes)
addTagIfMissing(f.Tags, "ddl", v.parentheses)
addTagIfMissing(f.Tags, "ddl", v.equals)
return f
}

type ListTransformer struct {
required bool
sqlPrefix string
parentheses string
equals string
}

func ListOptions() *ListTransformer {
Expand All @@ -118,6 +136,11 @@ func (v *ListTransformer) NoParens() *ListTransformer {
return v
}

func (v *ListTransformer) NoEquals() *ListTransformer {
v.equals = "no_equals"
return v
}

func (v *ListTransformer) SQL(sqlPrefix string) *ListTransformer {
v.sqlPrefix = sqlPrefix
return v
Expand All @@ -130,13 +153,15 @@ func (v *ListTransformer) Transform(f *Field) *Field {
}
addTagIfMissing(f.Tags, "sql", v.sqlPrefix)
addTagIfMissing(f.Tags, "ddl", v.parentheses)
addTagIfMissing(f.Tags, "ddl", v.equals)
return f
}

type IdentifierTransformer struct {
required bool
sqlPrefix string
quotes string
equals string
}

func IdentifierOptions() *IdentifierTransformer {
Expand All @@ -163,13 +188,24 @@ func (v *IdentifierTransformer) Required() *IdentifierTransformer {
return v
}

func (v *IdentifierTransformer) NoEquals() *IdentifierTransformer {
v.equals = "no_equals"
return v
}

func (v *IdentifierTransformer) Equals() *IdentifierTransformer {
v.equals = "equals"
return v
}

func (v *IdentifierTransformer) Transform(f *Field) *Field {
addTagIfMissing(f.Tags, "ddl", "identifier")
if v.required {
f.Required = true
}
addTagIfMissing(f.Tags, "sql", v.sqlPrefix)
addTagIfMissing(f.Tags, "ddl", v.quotes)
addTagIfMissing(f.Tags, "ddl", v.equals)
return f
}

Expand Down
45 changes: 45 additions & 0 deletions pkg/sdk/poc/generator/keyword_builders.go
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,10 @@ func (v *queryStruct) IfExists() *queryStruct {
return v.OptionalSQL("IF EXISTS")
}

func (v *queryStruct) Terse() *queryStruct {
return v.OptionalSQL("TERSE")
}

func (v *queryStruct) Text(name string, transformer *KeywordTransformer) *queryStruct {
v.fields = append(v.fields, NewField(name, "string", Tags().Keyword(), transformer))
return v
Expand All @@ -27,6 +31,27 @@ func (v *queryStruct) OptionalText(name string, transformer *KeywordTransformer)
return v
}

// SessionParameters *SessionParameters `ddl:"list,no_parentheses"`
func (v *queryStruct) SessionParameters() *queryStruct {
v.fields = append(v.fields, NewField("SessionParameters", "*SessionParameters", Tags().List().NoParentheses(), nil).withValidations(NewValidation(ValidateValue, "SessionParameters")))
return v
}

func (v *queryStruct) OptionalSessionParameters() *queryStruct {
v.fields = append(v.fields, NewField("SessionParameters", "*SessionParameters", Tags().List().NoParentheses(), nil).withValidations(NewValidation(ValidateValue, "SessionParameters")))
return v
}

func (v *queryStruct) OptionalSessionParametersUnset() *queryStruct {
v.fields = append(v.fields, NewField("SessionParametersUnset", "*SessionParametersUnset", Tags().List().NoParentheses(), nil).withValidations(NewValidation(ValidateValue, "SessionParametersUnset")))
return v
}

func (v *queryStruct) WithTags() *queryStruct {
v.fields = append(v.fields, NewField("Tag", "[]TagAssociation", Tags().Keyword().Parentheses().SQL("TAG"), nil))
return v
}

func (v *queryStruct) SetTags() *queryStruct {
v.fields = append(v.fields, NewField("SetTags", "[]TagAssociation", Tags().Keyword().SQL("SET TAG"), nil))
return v
Expand All @@ -36,3 +61,23 @@ func (v *queryStruct) UnsetTags() *queryStruct {
v.fields = append(v.fields, NewField("UnsetTags", "[]ObjectIdentifier", Tags().Keyword().SQL("UNSET TAG"), nil))
return v
}

func (v *queryStruct) OptionalLike() *queryStruct {
v.fields = append(v.fields, NewField("Like", "*Like", Tags().Keyword().SQL("LIKE"), nil))
return v
}

func (v *queryStruct) OptionalIn() *queryStruct {
v.fields = append(v.fields, NewField("In", "*In", Tags().Keyword().SQL("IN"), nil))
return v
}

func (v *queryStruct) OptionalStartsWith() *queryStruct {
v.fields = append(v.fields, NewField("StartsWith", "*string", Tags().Parameter().NoEquals().SingleQuotes().SQL("STARTS WITH"), nil))
return v
}

func (v *queryStruct) OptionalLimit() *queryStruct {
v.fields = append(v.fields, NewField("Limit", "*LimitFrom", Tags().Keyword().SQL("LIMIT"), nil))
return v
}
33 changes: 24 additions & 9 deletions pkg/sdk/poc/generator/operation.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ const (
// Operation defines a single operation for given object or objects family (e.g. CREATE DATABASE ROLE)
type Operation struct {
// Name is the operation's name, e.g. "Create"
Name OperationKind
Name string
// ObjectInterface points to the containing interface
ObjectInterface *Interface
// Doc is the URL for the doc used to create given operation, e.g. https://docs.snowflake.com/en/sql-reference/sql/create-database-role
Expand All @@ -44,7 +44,7 @@ type Mapping struct {
To *Field
}

func newOperation(kind OperationKind, doc string) *Operation {
func newOperation(kind string, doc string) *Operation {
return &Operation{
Name: kind,
Doc: doc,
Expand Down Expand Up @@ -83,7 +83,14 @@ func addDescriptionMapping(op *Operation, from, to *Field) {
op.DescribeMapping = newMapping("convert", from, to)
}

func (i *Interface) newSimpleOperation(kind OperationKind, doc string, queryStruct *queryStruct, helperStructs ...IntoField) *Interface {
func (i *Interface) newNoSqlOperation(kind string) *Interface {
operation := newOperation(kind, "placeholder").
withOptionsStruct(nil)
i.Operations = append(i.Operations, operation)
return i
}

func (i *Interface) newSimpleOperation(kind string, doc string, queryStruct *queryStruct, helperStructs ...IntoField) *Interface {
if queryStruct.identifierField != nil {
queryStruct.identifierField.Kind = i.IdentifierKind
}
Expand All @@ -101,7 +108,7 @@ func (i *Interface) newSimpleOperation(kind OperationKind, doc string, queryStru
}

func (i *Interface) newOperationWithDBMapping(
kind OperationKind,
kind string,
doc string,
dbRepresentation *dbStruct,
resourceRepresentation *plainStruct,
Expand All @@ -127,24 +134,32 @@ type IntoField interface {
}

func (i *Interface) CreateOperation(doc string, queryStruct *queryStruct, helperStructs ...IntoField) *Interface {
return i.newSimpleOperation(OperationKindCreate, doc, queryStruct, helperStructs...)
return i.newSimpleOperation(string(OperationKindCreate), doc, queryStruct, helperStructs...)
}

func (i *Interface) AlterOperation(doc string, queryStruct *queryStruct) *Interface {
return i.newSimpleOperation(OperationKindAlter, doc, queryStruct)
return i.newSimpleOperation(string(OperationKindAlter), doc, queryStruct)
}

func (i *Interface) DropOperation(doc string, queryStruct *queryStruct) *Interface {
return i.newSimpleOperation(OperationKindDrop, doc, queryStruct)
return i.newSimpleOperation(string(OperationKindDrop), doc, queryStruct)
}

func (i *Interface) ShowOperation(doc string, dbRepresentation *dbStruct, resourceRepresentation *plainStruct, queryStruct *queryStruct) *Interface {
i.newOperationWithDBMapping(OperationKindShow, doc, dbRepresentation, resourceRepresentation, queryStruct, addShowMapping)
i.newOperationWithDBMapping(string(OperationKindShow), doc, dbRepresentation, resourceRepresentation, queryStruct, addShowMapping)
return i
}

func (i *Interface) ShowByIdOperation() *Interface {
return i.newNoSqlOperation(string(OperationKindShowByID))
}

func (i *Interface) DescribeOperation(describeKind DescriptionMappingKind, doc string, dbRepresentation *dbStruct, resourceRepresentation *plainStruct, queryStruct *queryStruct) *Interface {
op := i.newOperationWithDBMapping(OperationKindDescribe, doc, dbRepresentation, resourceRepresentation, queryStruct, addDescriptionMapping)
op := i.newOperationWithDBMapping(string(OperationKindDescribe), doc, dbRepresentation, resourceRepresentation, queryStruct, addDescriptionMapping)
op.DescribeKind = &describeKind
return i
}

func (i *Interface) CustomOperation(kind string, doc string, queryStruct *queryStruct) *Interface {
return i.newSimpleOperation(kind, doc, queryStruct)
}
Loading

0 comments on commit d52f334

Please sign in to comment.