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

     1  package steampipeconfig
     2  
     3  import (
     4  	"sort"
     5  	"strings"
     6  	"time"
     7  
     8  	typehelpers "github.com/turbot/go-kit/types"
     9  	"github.com/turbot/steampipe-plugin-sdk/v5/plugin"
    10  	"github.com/turbot/steampipe/pkg/constants"
    11  	"github.com/turbot/steampipe/pkg/steampipeconfig/modconfig"
    12  )
    13  
    14  // ConnectionState is a struct containing all details for a connection
    15  // - the plugin name and checksum, the connection config and options
    16  // json tags needed as this is stored in the connection state file
    17  type ConnectionState struct {
    18  	// the connection name
    19  	ConnectionName string `json:"connection"  db:"name"`
    20  	// connection type (expected value: "aggregator")
    21  	Type *string `json:"type,omitempty"  db:"type"`
    22  	// should we create a postgres schema for the connection (expected values: "enable", "disable")
    23  	ImportSchema string `json:"import_schema"  db:"import_schema"`
    24  	// the fully qualified name of the plugin
    25  	Plugin string `json:"plugin"  db:"plugin"`
    26  	// the plugin instance
    27  	PluginInstance *string `json:"plugin_instance" db:"plugin_instance"`
    28  	// the connection state (pending, updating, deleting, error, ready)
    29  	State string `json:"state"  db:"state"`
    30  	// error (if there is one - make a pointer to support null)
    31  	ConnectionError *string `json:"error,omitempty" db:"error"`
    32  	// schema mode - static or dynamic
    33  	SchemaMode string `json:"schema_mode" db:"schema_mode"`
    34  	// the hash of the connection schema - this is used to determine if a dynamic schema has changed
    35  	SchemaHash string `json:"schema_hash,omitempty" db:"schema_hash"`
    36  	// are the comments set
    37  	CommentsSet bool `json:"comments_set" db:"comments_set"`
    38  	// the creation time of the plugin file
    39  	PluginModTime time.Time `json:"plugin_mod_time" db:"plugin_mod_time"`
    40  	// the update time of the connection
    41  	ConnectionModTime time.Time `json:"connection_mod_time" db:"connection_mod_time"`
    42  	// the matching patterns of child connections (for aggregators)
    43  	Connections     []string `json:"connections" db:"connections"`
    44  	FileName        string   `json:"file_name" db:"file_name"`
    45  	StartLineNumber int      `json:"start_line_number" db:"start_line_number"`
    46  	EndLineNumber   int      `json:"end_line_number" db:"end_line_number"`
    47  }
    48  
    49  func NewConnectionState(connection *modconfig.Connection, creationTime time.Time) *ConnectionState {
    50  	state := &ConnectionState{
    51  		Plugin:         connection.Plugin,
    52  		PluginInstance: connection.PluginInstance,
    53  		ConnectionName: connection.Name,
    54  		PluginModTime:  creationTime,
    55  		State:          constants.ConnectionStateReady,
    56  		Type:           &connection.Type,
    57  		ImportSchema:   connection.ImportSchema,
    58  		Connections:    connection.ConnectionNames,
    59  	}
    60  	state.setFilename(connection)
    61  	if connection.Error != nil {
    62  		state.SetError(connection.Error.Error())
    63  	}
    64  	return state
    65  }
    66  
    67  func (d *ConnectionState) setFilename(connection *modconfig.Connection) {
    68  	d.FileName = connection.DeclRange.Filename
    69  	d.StartLineNumber = connection.DeclRange.Start.Line
    70  	d.EndLineNumber = connection.DeclRange.End.Line
    71  }
    72  
    73  func (d *ConnectionState) Equals(other *ConnectionState) bool {
    74  	if d.Plugin != other.Plugin {
    75  		return false
    76  	}
    77  	if d.GetType() != other.GetType() {
    78  		return false
    79  	}
    80  	if d.ImportSchema != other.ImportSchema {
    81  		return false
    82  	}
    83  	if d.Error() != other.Error() {
    84  		return false
    85  	}
    86  
    87  	names := d.Connections
    88  	sort.Strings(names)
    89  	otherNames := other.Connections
    90  	sort.Strings(otherNames)
    91  	if strings.Join(names, ",") != strings.Join(otherNames, "'") {
    92  		return false
    93  	}
    94  
    95  	if d.pluginModTimeChanged(other) {
    96  		return false
    97  	}
    98  	// do not look at connection mod time as the mod time for the desired state is not relevant
    99  
   100  	return true
   101  }
   102  
   103  // allow for sub ms rounding errors when converting from PG
   104  func (d *ConnectionState) pluginModTimeChanged(other *ConnectionState) bool {
   105  	return d.PluginModTime.Sub(other.PluginModTime).Abs() > 1*time.Millisecond
   106  }
   107  
   108  func (d *ConnectionState) CanCloneSchema() bool {
   109  	return d.SchemaMode != plugin.SchemaModeDynamic &&
   110  		d.GetType() != modconfig.ConnectionTypeAggregator
   111  }
   112  
   113  func (d *ConnectionState) Error() string {
   114  	return typehelpers.SafeString(d.ConnectionError)
   115  }
   116  
   117  func (d *ConnectionState) SetError(err string) {
   118  	d.State = constants.ConnectionStateError
   119  	d.ConnectionError = &err
   120  }
   121  
   122  // Loaded returns true if the connection state is 'ready' or 'error'
   123  // Disabled connections are considered as 'loaded'
   124  func (d *ConnectionState) Loaded() bool {
   125  	return d.Disabled() || d.State == constants.ConnectionStateReady || d.State == constants.ConnectionStateError
   126  }
   127  
   128  func (d *ConnectionState) Disabled() bool {
   129  	return d.State == constants.ConnectionStateDisabled
   130  }
   131  
   132  func (d *ConnectionState) GetType() string {
   133  	return typehelpers.SafeString(d.Type)
   134  }