From 88b3f406da81f2097979a9c62c8b6a75452910be Mon Sep 17 00:00:00 2001 From: Karanjot Singh Date: Tue, 3 Sep 2024 15:49:12 +0530 Subject: [PATCH 1/3] Add support for Creating Tables Signed-off-by: Karanjot Singh --- atlan/assets/table_client.go | 144 +++++++++++++++++++++++++++++++++++ main.go | 47 ++++++++---- 2 files changed, 178 insertions(+), 13 deletions(-) create mode 100644 atlan/assets/table_client.go diff --git a/atlan/assets/table_client.go b/atlan/assets/table_client.go new file mode 100644 index 0000000..5d1c716 --- /dev/null +++ b/atlan/assets/table_client.go @@ -0,0 +1,144 @@ +package assets + +import ( + "encoding/json" + "errors" + "github.com/atlanhq/atlan-go/atlan" + "github.com/atlanhq/atlan-go/atlan/model/structs" + "strings" +) + +type Table structs.Table + +// Creator is used to create a new table asset. +func (t *Table) Creator(name, schemaQualifiedName string, schemaName, databaseName, databaseQualifiedName, connectionQualifiedName *string) error { + if name == "" || schemaQualifiedName == "" { + return errors.New("name and schemaQualifiedName are required fields") + } + + // Extract the connector type from the schemaQualifiedName + connectorType, err := atlan.GetConnectorTypeFromQualifiedName(schemaQualifiedName) + if err != nil { + return err + } + + // Split the schemaQualifiedName to extract fields + fields := strings.Split(schemaQualifiedName, "/") + if len(fields) < 5 { + return errors.New("schemaQualifiedName must have at least 5 parts separated by '/'") + } + + // Construct connectionQualifiedName if not provided + if connectionQualifiedName == nil { + connectionQn := fields[0] + "/" + connectorType.Value + connectionQualifiedName = &connectionQn + } + + // Construct qualified name + qualifiedName := schemaQualifiedName + "/" + name + + // Set the optional fields if not provided + if databaseName == nil { + databaseName = &fields[3] + } + + if schemaName == nil { + schemaName = &fields[4] + } + + if databaseQualifiedName == nil { + dbQualifiedName := *connectionQualifiedName + "/" + *databaseName + databaseQualifiedName = &dbQualifiedName + } + + // Assign the constructed and provided values to the Table + t.TypeName = structs.StringPtr("Table") + t.Name = structs.StringPtr(name) + t.QualifiedName = structs.StringPtr(qualifiedName) + t.SchemaQualifiedName = structs.StringPtr(schemaQualifiedName) + t.SchemaName = schemaName + t.DatabaseName = databaseName + t.DatabaseQualifiedName = databaseQualifiedName + t.ConnectionQualifiedName = connectionQualifiedName + + return nil +} + +// UnmarshalJSON implements the JSON unmarshal interface for the Table struct. +func (t *Table) UnmarshalJSON(data []byte) error { + // Define a temporary structure with the expected JSON structure. + var temp struct { + Entity struct { + TypeName string `json:"typeName"` + Name string `json:"name"` + SchemaQualifiedName string `json:"schemaQualifiedName"` + SchemaName string `json:"schemaName"` + DatabaseName string `json:"databaseName"` + DatabaseQualifiedName string `json:"databaseQualifiedName"` + ConnectionQualifiedName string `json:"connectionQualifiedName"` + Guid string `json:"guid"` + } `json:"entity"` + } + + // Unmarshal the JSON into the temporary structure + if err := json.Unmarshal(data, &temp); err != nil { + return err + } + + // Map the fields from the temporary structure to the Table struct + t.TypeName = &temp.Entity.TypeName + t.Name = &temp.Entity.Name + t.SchemaQualifiedName = &temp.Entity.SchemaQualifiedName + t.SchemaName = &temp.Entity.SchemaName + t.DatabaseName = &temp.Entity.DatabaseName + t.DatabaseQualifiedName = &temp.Entity.DatabaseQualifiedName + t.ConnectionQualifiedName = &temp.Entity.ConnectionQualifiedName + t.Guid = &temp.Entity.Guid + + return nil +} + +// MarshalJSON filters out entities to only include those with non-empty attributes. +func (t *Table) MarshalJSON() ([]byte, error) { + // Construct the custom JSON structure + customJSON := map[string]interface{}{ + "typeName": t.TypeName, + "attributes": map[string]interface{}{ + "name": t.Name, + "schemaQualifiedName": t.SchemaQualifiedName, + "qualifiedName": t.QualifiedName, + // Add other attributes as necessary. + }, + } + + if t.Guid != nil && *t.Guid != "" { + customJSON["guid"] = *t.Guid + } + + if t.SchemaName != nil && *t.SchemaName != "" { + customJSON["attributes"].(map[string]interface{})["schemaName"] = *t.SchemaName + } + + if t.DatabaseName != nil && *t.DatabaseName != "" { + customJSON["attributes"].(map[string]interface{})["databaseName"] = *t.DatabaseName + } + + if t.DatabaseQualifiedName != nil && *t.DatabaseQualifiedName != "" { + customJSON["attributes"].(map[string]interface{})["databaseQualifiedName"] = *t.DatabaseQualifiedName + } + + if t.ConnectionQualifiedName != nil && *t.ConnectionQualifiedName != "" { + customJSON["attributes"].(map[string]interface{})["connectionQualifiedName"] = *t.ConnectionQualifiedName + } + + // Marshal the custom JSON + return json.MarshalIndent(customJSON, "", " ") +} + +func (ag *Table) ToJSON() ([]byte, error) { + return json.MarshalIndent(ag, "", " ") +} + +func (ag *Table) FromJSON(data []byte) error { + return json.Unmarshal(data, ag) +} diff --git a/main.go b/main.go index eb0e656..0c001ae 100644 --- a/main.go +++ b/main.go @@ -13,22 +13,43 @@ func main() { ctx.SetLogger(true, "debug") - qualifiedname := "default/snowflake/1715371897/RAW/WIDEWORLDIMPORTERS_SALESFORCE/FIVETRAN_API_CALL" - - response, atlanErr := assets.NewFluentSearch(). - PageSizes(10). - ActiveAssets(). - Where(ctx.Table.SUPERTYPE_NAMES.Eq("SQL")). - Where(ctx.Table.QUALIFIED_NAME.Eq(qualifiedname)). - IncludeOnResults("userDescription", "ownerUsers", "ownerGroups", "certificateStatus", "tags"). - Execute() - - if atlanErr != nil { - fmt.Println(atlanErr) + t := &assets.Table{} // create a new Glossary instance + + //schemaName := "WIDEWORLDIMPORTERS_PURCHASING" + //dataBaseName := "RAW" + //dataBaseQualifiedName := "default/snowflake/1723642516/RAW" + //connectionQualifiedName := "default/snowflake/1723642516" + + t.Creator("TestTable3", "default/snowflake/1723642516/RAW/WIDEWORLDIMPORTERS_PURCHASING", nil, nil, nil, nil) + + response, err := assets.Save(t) // save the table + if err != nil { + fmt.Println("Error:", err) + } else { + for _, entity := range response.MutatedEntities.CREATE { + //fmt.Println("Response:", entity) + fmt.Printf("Entity ID: %s, Display Text: %s\n", entity.Guid, entity.DisplayText) + } } + /* + qualifiedname := "default/snowflake/1715371897/RAW/WIDEWORLDIMPORTERS_SALESFORCE/FIVETRAN_API_CALL" - fmt.Println(response[0].Entities[0].SearchMeanings[0].Guid) + response, atlanErr := assets.NewFluentSearch(). + PageSizes(10). + ActiveAssets(). + Where(ctx.Table.SUPERTYPE_NAMES.Eq("SQL")). + Where(ctx.Table.QUALIFIED_NAME.Eq(qualifiedname)). + IncludeOnResults("userDescription", "ownerUsers", "ownerGroups", "certificateStatus", "tags"). + Execute() + + if atlanErr != nil { + fmt.Println(atlanErr) + } + + fmt.Println(response[0].Entities[0].SearchMeanings[0].Guid) + + */ /* structs.GetAll() From 04063ec91b263373a045fe810a5f55d8ed79f85c Mon Sep 17 00:00:00 2001 From: Karanjot Singh Date: Thu, 5 Sep 2024 17:11:02 +0530 Subject: [PATCH 2/3] feat: Added CreatorWithParams method while for creating a table Signed-off-by: Karanjot Singh --- atlan/assets/table_client.go | 47 +++++++++++++++++++++++++++++++++++- 1 file changed, 46 insertions(+), 1 deletion(-) diff --git a/atlan/assets/table_client.go b/atlan/assets/table_client.go index 5d1c716..7bfcbdf 100644 --- a/atlan/assets/table_client.go +++ b/atlan/assets/table_client.go @@ -11,7 +11,52 @@ import ( type Table structs.Table // Creator is used to create a new table asset. -func (t *Table) Creator(name, schemaQualifiedName string, schemaName, databaseName, databaseQualifiedName, connectionQualifiedName *string) error { +func (t *Table) Creator(name, schemaQualifiedName string) error { + if name == "" || schemaQualifiedName == "" { + return errors.New("name and schemaQualifiedName are required fields") + } + + // Extract the connector type from the schemaQualifiedName + connectorType, err := atlan.GetConnectorTypeFromQualifiedName(schemaQualifiedName) + if err != nil { + return err + } + + // Split the schemaQualifiedName to extract fields + fields := strings.Split(schemaQualifiedName, "/") + if len(fields) < 5 { + return errors.New("schemaQualifiedName must have at least 5 parts separated by '/'") + } + + // Construct connectionQualifiedName if not provided + connectionQn := fields[0] + "/" + connectorType.Value + connectionQualifiedName := &connectionQn + + // Construct qualified name + qualifiedName := schemaQualifiedName + "/" + name + + // Set the optional fields if not provided + databaseName := &fields[3] + + schemaName := &fields[4] + + dbQualifiedName := *connectionQualifiedName + "/" + *databaseName + databaseQualifiedName := &dbQualifiedName + + // Assign the constructed and provided values to the Table + t.TypeName = structs.StringPtr("Table") + t.Name = structs.StringPtr(name) + t.QualifiedName = structs.StringPtr(qualifiedName) + t.SchemaQualifiedName = structs.StringPtr(schemaQualifiedName) + t.SchemaName = schemaName + t.DatabaseName = databaseName + t.DatabaseQualifiedName = databaseQualifiedName + t.ConnectionQualifiedName = connectionQualifiedName + + return nil +} + +func (t *Table) CreatorWithParams(name, schemaQualifiedName string, schemaName, databaseName, databaseQualifiedName, connectionQualifiedName *string) error { if name == "" || schemaQualifiedName == "" { return errors.New("name and schemaQualifiedName are required fields") } From 5a3169cc72c7bc55c4eb3b4dc231558f83dd03a7 Mon Sep 17 00:00:00 2001 From: Karanjot Singh Date: Thu, 5 Sep 2024 17:29:36 +0530 Subject: [PATCH 3/3] Add updater method for table Signed-off-by: Karanjot Singh --- atlan/assets/table_client.go | 13 +++++++++++++ main.go | 19 ++++++++++++++++--- 2 files changed, 29 insertions(+), 3 deletions(-) diff --git a/atlan/assets/table_client.go b/atlan/assets/table_client.go index 7bfcbdf..5e4a6c7 100644 --- a/atlan/assets/table_client.go +++ b/atlan/assets/table_client.go @@ -143,6 +143,19 @@ func (t *Table) UnmarshalJSON(data []byte) error { return nil } +// Updater is used to modify a glossary asset in memory. +func (t *Table) Updater(name string, qualifiedName string) error { + if name == "" || qualifiedName == "" { + return errors.New("name, qualified_name are required fields") + } + + t.TypeName = structs.StringPtr("Table") + t.Name = structs.StringPtr(name) + t.QualifiedName = structs.StringPtr(qualifiedName) + + return nil +} + // MarshalJSON filters out entities to only include those with non-empty attributes. func (t *Table) MarshalJSON() ([]byte, error) { // Construct the custom JSON structure diff --git a/main.go b/main.go index 0c001ae..95ba340 100644 --- a/main.go +++ b/main.go @@ -13,15 +13,14 @@ func main() { ctx.SetLogger(true, "debug") - t := &assets.Table{} // create a new Glossary instance + t := &assets.Table{} // create a new Table instance //schemaName := "WIDEWORLDIMPORTERS_PURCHASING" //dataBaseName := "RAW" //dataBaseQualifiedName := "default/snowflake/1723642516/RAW" //connectionQualifiedName := "default/snowflake/1723642516" - t.Creator("TestTable3", "default/snowflake/1723642516/RAW/WIDEWORLDIMPORTERS_PURCHASING", nil, nil, nil, nil) - + t.Creator("TestTable6", "default/snowflake/1723642516/RAW/WIDEWORLDIMPORTERS_PURCHASING") response, err := assets.Save(t) // save the table if err != nil { fmt.Println("Error:", err) @@ -31,6 +30,20 @@ func main() { fmt.Printf("Entity ID: %s, Display Text: %s\n", entity.Guid, entity.DisplayText) } } + + t1 := &assets.Table{} // create a new Table instance + + t1.Updater("TestTable7", "default/snowflake/1723642516/RAW/WIDEWORLDIMPORTERS_PURCHASING/TestTable4") + DisplayName := "TestTableModified" + t1.Name = &DisplayName + response2, err := assets.Save(t1) + if err != nil { + } else { + for _, entity := range response2.MutatedEntities.UPDATE { + println("Response:", entity) + println("Entity ID:", entity.Guid, "Display Text:", entity.DisplayText) + } + } /* qualifiedname := "default/snowflake/1715371897/RAW/WIDEWORLDIMPORTERS_SALESFORCE/FIVETRAN_API_CALL"