github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/introspection/plugin_column_table_sql.go (about)

     1  package introspection
     2  
     3  import (
     4  	"encoding/json"
     5  	"fmt"
     6  	"strings"
     7  
     8  	"github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto"
     9  	"github.com/turbot/steampipe/pkg/constants"
    10  	"github.com/turbot/steampipe/pkg/db/db_common"
    11  )
    12  
    13  func GetPluginColumnTableCreateSql() db_common.QueryWithArgs {
    14  	return db_common.QueryWithArgs{
    15  		Query: fmt.Sprintf(`CREATE TABLE IF NOT EXISTS %s.%s (
    16  				plugin TEXT NOT NULL,
    17  				table_name TEXT NOT NULL,
    18  				name TEXT NOT NULL,
    19  				type TEXT NOT NULL,
    20  				description TEXT NULL,
    21  				list_config jsonb NULL,
    22  				get_config jsonb NULL,
    23  				hydrate_name TEXT NULL,
    24  				default_value jsonb NULL
    25  		);`, constants.InternalSchema, constants.PluginColumnTable),
    26  	}
    27  }
    28  
    29  func GetPluginColumnTablePopulateSqlForPlugin(pluginName string, schema map[string]*proto.TableSchema) ([]db_common.QueryWithArgs, error) {
    30  	var res []db_common.QueryWithArgs
    31  	for tableName, tableSchema := range schema {
    32  		getKeyColumns := tableSchema.GetKeyColumnMap()
    33  		listKeyColumns := tableSchema.ListKeyColumnMap()
    34  		for _, columnSchema := range tableSchema.Columns {
    35  			getKeyColumn := getKeyColumns[columnSchema.Name]
    36  			listKeyColumn := listKeyColumns[columnSchema.Name]
    37  			q, err := GetPluginColumnTablePopulateSql(pluginName, tableName, columnSchema, getKeyColumn, listKeyColumn)
    38  			if err != nil {
    39  				return nil, err
    40  			}
    41  			res = append(res, q)
    42  		}
    43  	}
    44  	return res, nil
    45  }
    46  
    47  func GetPluginColumnTablePopulateSql(
    48  	pluginName, tableName string,
    49  	columnSchema *proto.ColumnDefinition,
    50  	getKeyColumn, listKeyColumn *proto.KeyColumn) (db_common.QueryWithArgs, error) {
    51  
    52  	var description, defaultValue any
    53  	if columnSchema.Description != "" {
    54  		description = columnSchema.Description
    55  	}
    56  	if columnSchema.Default != nil {
    57  		var err error
    58  		defaultValue, err = columnSchema.Default.ValueToInterface()
    59  		if err != nil {
    60  			return db_common.QueryWithArgs{}, err
    61  		}
    62  	}
    63  
    64  	var listConfig, getConfig *keyColumn
    65  
    66  	if getKeyColumn != nil {
    67  		getConfig = newKeyColumn(getKeyColumn.Operators, getKeyColumn.Require, getKeyColumn.CacheMatch)
    68  	}
    69  	if listKeyColumn != nil {
    70  		listConfig = newKeyColumn(listKeyColumn.Operators, listKeyColumn.Require, listKeyColumn.CacheMatch)
    71  	}
    72  
    73  	// special handling for strings
    74  	if s, ok := defaultValue.(string); ok {
    75  		defaultValue = fmt.Sprintf(`"%s"`, s)
    76  	}
    77  	var hydrate any = nil
    78  	if columnSchema.Hydrate != "" {
    79  		hydrate = columnSchema.Hydrate
    80  	}
    81  
    82  	q := db_common.QueryWithArgs{
    83  		Query: fmt.Sprintf(`INSERT INTO %s.%s (
    84  				plugin,
    85  				table_name ,
    86  				name,
    87  				type,
    88  				description,
    89  				list_config,
    90  				get_config,
    91  				hydrate_name,
    92  				default_value
    93  )
    94  	VALUES($1,$2,$3,$4,$5,$6,$7,$8,$9)`, constants.InternalSchema, constants.PluginColumnTable),
    95  		Args: []any{
    96  			pluginName,
    97  			tableName,
    98  			columnSchema.Name,
    99  			proto.ColumnType_name[int32(columnSchema.Type)],
   100  			description,
   101  			listConfig,
   102  			getConfig,
   103  			hydrate,
   104  			defaultValue,
   105  		},
   106  	}
   107  
   108  	return q, nil
   109  }
   110  
   111  func GetPluginColumnTableDropSql() db_common.QueryWithArgs {
   112  	return db_common.QueryWithArgs{
   113  		Query: fmt.Sprintf(
   114  			`DROP TABLE IF EXISTS %s.%s;`,
   115  			constants.InternalSchema,
   116  			constants.PluginColumnTable,
   117  		),
   118  	}
   119  }
   120  
   121  func GetPluginColumnTableDeletePluginSql(plugin string) db_common.QueryWithArgs {
   122  	return db_common.QueryWithArgs{
   123  		Query: fmt.Sprintf(
   124  			`DELETE FROM %s.%s
   125  WHERE plugin = $1;`,
   126  			constants.InternalSchema,
   127  			constants.PluginColumnTable,
   128  		),
   129  		Args: []any{plugin},
   130  	}
   131  }
   132  
   133  func GetPluginColumnTableGrantSql() db_common.QueryWithArgs {
   134  	return db_common.QueryWithArgs{
   135  		Query: fmt.Sprintf(
   136  			`GRANT SELECT ON TABLE %s.%s to %s;`,
   137  			constants.InternalSchema,
   138  			constants.PluginColumnTable,
   139  			constants.DatabaseUsersRole,
   140  		),
   141  	}
   142  }
   143  
   144  type keyColumn struct {
   145  	Operators  []string `json:"operators,omitempty"`
   146  	Require    string   `json:"require,omitempty"`
   147  	CacheMatch string   `json:"cache_match,omitempty"`
   148  }
   149  
   150  func newKeyColumn(operators []string, require string, cacheMatch string) *keyColumn {
   151  	return &keyColumn{
   152  		Operators:  cleanOperators(operators),
   153  		Require:    require,
   154  		CacheMatch: cacheMatch,
   155  	}
   156  }
   157  
   158  // tactical - avoid html encoding operators
   159  func cleanOperators(operators []string) []string {
   160  	var res = make([]string, len(operators))
   161  	for i, operator := range operators {
   162  
   163  		switch operator {
   164  		case "<>":
   165  			operator = "!="
   166  		case ">":
   167  			operator = "gt"
   168  		case "<":
   169  			operator = "lt"
   170  		case ">=":
   171  			operator = "ge"
   172  		case "<=":
   173  			operator = "le"
   174  		}
   175  		res[i] = operator
   176  	}
   177  	return res
   178  }
   179  
   180  // MarshalJSON implements the json.Marshaler interface
   181  // This method is responsible for providing the custom JSON encoding
   182  func (s keyColumn) MarshalJSON() ([]byte, error) {
   183  	type Alias keyColumn
   184  
   185  	b := new(strings.Builder)
   186  	encoder := json.NewEncoder(b)
   187  	encoder.SetEscapeHTML(false)
   188  	err := encoder.Encode(Alias(s))
   189  	return []byte(b.String()), err
   190  }