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 }