github.com/blend/go-sdk@v1.20220411.3/db/parse_url.go (about)

     1  /*
     2  
     3  Copyright (c) 2022 - Present. Blend Labs, Inc. All rights reserved
     4  Use of this source code is governed by a MIT license that can be found in the LICENSE file.
     5  
     6  */
     7  
     8  package db
     9  
    10  import (
    11  	"fmt"
    12  	"net"
    13  	"net/url"
    14  	"sort"
    15  	"strings"
    16  )
    17  
    18  // ParseURL no longer needs to be used by clients of this library since supplying a URL as a
    19  // connection string to sql.Open() is now supported:
    20  //
    21  //	sql.Open("postgres", "postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full")
    22  //
    23  // It remains exported here for backwards-compatibility.
    24  //
    25  // ParseURL converts a url to a connection string for driver.Open.
    26  // Example:
    27  //
    28  //	"postgres://bob:secret@1.2.3.4:5432/mydb?sslmode=verify-full"
    29  //
    30  // converts to:
    31  //
    32  //	"user=bob password=secret host=1.2.3.4 port=5432 dbname=mydb sslmode=verify-full"
    33  //
    34  // A minimal example:
    35  //
    36  //	"postgres://"
    37  //
    38  // This will be blank, causing driver.Open to use all of the defaults
    39  func ParseURL(databaseURL string) (string, error) {
    40  	u, err := url.Parse(databaseURL)
    41  	if err != nil {
    42  		return "", err
    43  	}
    44  
    45  	if u.Scheme != "postgres" && u.Scheme != "postgresql" {
    46  		return "", fmt.Errorf("invalid connection protocol: %s", u.Scheme)
    47  	}
    48  
    49  	var kvs []string
    50  	escaper := strings.NewReplacer(` `, `\ `, `'`, `\'`, `\`, `\\`)
    51  	accrue := func(k, v string) {
    52  		if v != "" {
    53  			kvs = append(kvs, k+"="+escaper.Replace(v))
    54  		}
    55  	}
    56  
    57  	if u.User != nil {
    58  		v := u.User.Username()
    59  		accrue("user", v)
    60  
    61  		v, _ = u.User.Password()
    62  		accrue("password", v)
    63  	}
    64  
    65  	if host, port, err := net.SplitHostPort(u.Host); err != nil {
    66  		accrue("host", u.Host)
    67  	} else {
    68  		accrue("host", host)
    69  		accrue("port", port)
    70  	}
    71  
    72  	if u.Path != "" {
    73  		accrue("dbname", u.Path[1:])
    74  	}
    75  
    76  	q := u.Query()
    77  	for k := range q {
    78  		accrue(k, q.Get(k))
    79  	}
    80  
    81  	sort.Strings(kvs) // Makes testing easier (not a performance concern)
    82  	return strings.Join(kvs, " "), nil
    83  }