github.com/turbot/steampipe@v1.7.0-rc.0.0.20240517123944-7cef272d4458/pkg/query/queryresult/scan_metadata.go (about) 1 package queryresult 2 3 import ( 4 "github.com/turbot/steampipe-plugin-sdk/v5/grpc" 5 "github.com/turbot/steampipe-plugin-sdk/v5/grpc/proto" 6 "time" 7 ) 8 9 type ScanMetadataRow struct { 10 // the fields of this struct need to be public since these are populated by pgx using RowsToStruct 11 Connection string `db:"connection,optional" json:"connection"` 12 Table string `db:"table" json:"table"` 13 CacheHit bool `db:"cache_hit" json:"cache_hit"` 14 RowsFetched int64 `db:"rows_fetched" json:"rows_fetched"` 15 HydrateCalls int64 `db:"hydrate_calls" json:"hydrate_calls"` 16 StartTime time.Time `db:"start_time" json:"start_time"` 17 DurationMs int64 `db:"duration_ms" json:"duration_ms"` 18 Columns []string `db:"columns" json:"columns"` 19 Limit *int64 `db:"limit" json:"limit,omitempty"` 20 Quals []grpc.SerializableQual `db:"quals" json:"quals,omitempty"` 21 } 22 23 func NewScanMetadataRow(connection string, table string, columns []string, quals map[string]*proto.Quals, startTime time.Time, diration time.Duration, limit int64, m *proto.QueryMetadata) ScanMetadataRow { 24 res := ScanMetadataRow{ 25 Connection: connection, 26 Table: table, 27 StartTime: startTime, 28 DurationMs: diration.Milliseconds(), 29 Columns: columns, 30 Quals: grpc.QualMapToSerializableSlice(quals), 31 } 32 if limit == -1 { 33 res.Limit = nil 34 } else { 35 res.Limit = &limit 36 } 37 if m != nil { 38 res.CacheHit = m.CacheHit 39 res.RowsFetched = m.RowsFetched 40 res.HydrateCalls = m.HydrateCalls 41 } 42 return res 43 } 44 45 // AsResultRow returns the ScanMetadata as a map[string]interface which can be returned as a query result 46 func (m ScanMetadataRow) AsResultRow() map[string]any { 47 res := map[string]any{ 48 "connection": m.Connection, 49 "table": m.Table, 50 "cache_hit": m.CacheHit, 51 "rows_fetched": m.RowsFetched, 52 "hydrate_calls": m.HydrateCalls, 53 "start_time": m.StartTime, 54 "duration_ms": m.DurationMs, 55 "columns": m.Columns, 56 "quals": m.Quals, 57 } 58 // explicitly set limit to nil if needed (otherwise postgres returns `1`) 59 if m.Limit != nil { 60 res["limit"] = *m.Limit 61 } else { 62 res["limit"] = nil // Explicitly set nil 63 } 64 return res 65 } 66 67 type QueryRowSummary struct { 68 UncachedRowsFetched int64 `db:"uncached_rows_fetched" json:"uncached_rows_fetched"` 69 CachedRowsFetched int64 `db:"cached_rows_fetched" json:"cached_rows_fetched"` 70 HydrateCalls int64 `db:"hydrate_calls" json:"hydrate_calls"` 71 ScanCount int64 `db:"scan_count" json:"scan_count"` 72 ConnectionCount int64 `db:"connection_count" json:"connection_count"` 73 // map connections to the scans 74 connections map[string]struct{} 75 } 76 77 func NewQueryRowSummary() *QueryRowSummary { 78 return &QueryRowSummary{ 79 connections: make(map[string]struct{}), 80 } 81 } 82 func (s *QueryRowSummary) AsResultRow() map[string]any { 83 res := map[string]any{ 84 "uncached_rows_fetched": s.UncachedRowsFetched, 85 "cached_rows_fetched": s.CachedRowsFetched, 86 "hydrate_calls": s.HydrateCalls, 87 "scan_count": s.ScanCount, 88 "connection_count": s.ConnectionCount, 89 } 90 91 return res 92 } 93 94 func (s *QueryRowSummary) Update(m ScanMetadataRow) { 95 if m.CacheHit { 96 s.CachedRowsFetched += m.RowsFetched 97 } else { 98 s.UncachedRowsFetched += m.RowsFetched 99 } 100 s.HydrateCalls += m.HydrateCalls 101 s.ScanCount++ 102 s.connections[m.Connection] = struct{}{} 103 s.ConnectionCount = int64(len(s.connections)) 104 }