github.com/icyphox/x@v0.0.355-0.20220311094250-029bd783e8b8/sqlcon/parse_opts.go (about)

     1  package sqlcon
     2  
     3  import (
     4  	"fmt"
     5  	"net/url"
     6  	"strconv"
     7  	"strings"
     8  	"time"
     9  
    10  	"github.com/ory/x/logrusx"
    11  )
    12  
    13  // ParseConnectionOptions parses values for max_conns, max_idle_conns, max_conn_lifetime from DSNs.
    14  // It also returns the URI without those query parameters.
    15  func ParseConnectionOptions(l *logrusx.Logger, dsn string) (maxConns int, maxIdleConns int, maxConnLifetime, maxIdleConnTime time.Duration, cleanedDSN string) {
    16  	maxConns = maxParallelism() * 2
    17  	maxIdleConns = maxParallelism()
    18  	maxConnLifetime = time.Duration(0)
    19  	maxIdleConnTime = time.Duration(0)
    20  	cleanedDSN = dsn
    21  
    22  	parts := strings.Split(dsn, "?")
    23  	if len(parts) != 2 {
    24  		l.
    25  			WithField("sql_max_connections", maxConns).
    26  			WithField("sql_max_idle_connections", maxIdleConns).
    27  			WithField("sql_max_connection_lifetime", maxConnLifetime).
    28  			WithField("sql_max_idle_connection_time", maxIdleConnTime).
    29  			Debugf("No SQL connection options have been defined, falling back to default connection options.")
    30  		return
    31  	}
    32  
    33  	query, err := url.ParseQuery(parts[1])
    34  	if err != nil {
    35  		l.
    36  			WithField("sql_max_connections", maxConns).
    37  			WithField("sql_max_idle_connections", maxIdleConns).
    38  			WithField("sql_max_connection_lifetime", maxConnLifetime).
    39  			WithField("sql_max_idle_connection_time", maxIdleConnTime).
    40  			WithError(err).
    41  			Warnf("Unable to parse SQL DSN query, falling back to default connection options.")
    42  		return
    43  	}
    44  
    45  	if v := query.Get("max_conns"); v != "" {
    46  		s, err := strconv.ParseInt(v, 10, 64)
    47  		if err != nil {
    48  			l.WithError(err).Warnf(`SQL DSN query parameter "max_conns" value %v could not be parsed to int, falling back to default value %d`, v, maxConns)
    49  		} else {
    50  			maxConns = int(s)
    51  		}
    52  		query.Del("max_conns")
    53  	}
    54  
    55  	if v := query.Get("max_idle_conns"); v != "" {
    56  		s, err := strconv.ParseInt(v, 10, 64)
    57  		if err != nil {
    58  			l.WithError(err).Warnf(`SQL DSN query parameter "max_idle_conns" value %v could not be parsed to int, falling back to default value %d`, v, maxIdleConns)
    59  		} else {
    60  			maxIdleConns = int(s)
    61  		}
    62  		query.Del("max_idle_conns")
    63  	}
    64  
    65  	if v := query.Get("max_conn_lifetime"); v != "" {
    66  		s, err := time.ParseDuration(v)
    67  		if err != nil {
    68  			l.WithError(err).Warnf(`SQL DSN query parameter "max_conn_lifetime" value %v could not be parsed to duration, falling back to default value %d`, v, maxConnLifetime)
    69  		} else {
    70  			maxConnLifetime = s
    71  		}
    72  		query.Del("max_conn_lifetime")
    73  	}
    74  
    75  	if v := query.Get("max_conn_idle_time"); v != "" {
    76  		s, err := time.ParseDuration(v)
    77  		if err != nil {
    78  			l.WithError(err).Warnf(`SQL DSN query parameter "max_conn_idle_time" value %v could not be parsed to duration, falling back to default value %d`, v, maxIdleConnTime)
    79  		} else {
    80  			maxIdleConnTime = s
    81  		}
    82  		query.Del("max_conn_idle_time")
    83  	}
    84  	cleanedDSN = fmt.Sprintf("%s?%s", parts[0], query.Encode())
    85  
    86  	return
    87  }
    88  
    89  // FinalizeDSN will return a finalized DSN URI.
    90  func FinalizeDSN(l *logrusx.Logger, dsn string) string {
    91  	if strings.HasPrefix(dsn, "mysql://") {
    92  		var q url.Values
    93  		parts := strings.SplitN(dsn, "?", 2)
    94  
    95  		if len(parts) == 1 {
    96  			q = make(url.Values)
    97  		} else {
    98  			var err error
    99  			q, err = url.ParseQuery(parts[1])
   100  			if err != nil {
   101  				l.WithError(err).Warnf("Unable to parse SQL DSN query, could not finalize the DSN URI.")
   102  				return dsn
   103  			}
   104  		}
   105  
   106  		q.Set("multiStatements", "true")
   107  		q.Set("parseTime", "true")
   108  
   109  		return fmt.Sprintf("%s?%s", parts[0], q.Encode())
   110  	}
   111  
   112  	return dsn
   113  }