package pilgrim_conf import ( "fmt" "log" "regexp" "slices" "strings" ) const EmptyString = "" type DbDriver string const ( DbDriver_MySQL DbDriver = "mysql" DbDriver_MSSQL DbDriver = "mssql" DbDriver_Postgres DbDriver = "postgres" DbDriver_Oracle DbDriver = "oracle" DbDriver_SQLite DbDriver = "sqlite" DbDriver_MariaDB DbDriver = "mariadb" ) var AvailableDbDrivers []DbDriver = []DbDriver{ DbDriver_MySQL, DbDriver_MSSQL, DbDriver_Postgres, DbDriver_Oracle, DbDriver_SQLite, DbDriver_MariaDB, } type UrlParts struct { Host, Port, Username, Password string Driver DbDriver Segments []string Arguments map[string]string } const DbUrlRegex = `^(?:([^:\/?#\s]+):\/{2})?(?:([^@\/?#\s]+)@)?([^\/?#\s]+)?(?:\/([^?#\s]*))?(?:[?]([^#\s]+))?\S*$` func ParseDatabaseUrl(url string) UrlParts { urlRegex, err := regexp.Compile(DbUrlRegex) if err != nil { log.Fatalf("Regex %s could not be compiled", DbUrlRegex) // The developer wrote the regex wrong. } parsed := urlRegex.FindAllStringSubmatch(url, -1) if parsed == nil || parsed[0] == nil { return UrlParts{} } parsedUrl := parsed[0] driver := DbDriver(parsedUrl[1]) username := "" password := "" host := "" port := "" var segments []string var arguments map[string]string = make(map[string]string) // Parse username and password ( username:password ) if parsedUrl[2] != EmptyString && strings.Contains(parsedUrl[2], ":") { splitUserAndPass := strings.Split(parsedUrl[2], ":") username = splitUserAndPass[0] password = splitUserAndPass[1] } // Parse host and port ( host:port ) if parsedUrl[3] != EmptyString && strings.Contains(parsedUrl[3], ":") { splitHostAndPort := strings.Split(parsedUrl[3], ":") host = splitHostAndPort[0] port = splitHostAndPort[1] } // Parse segments ( segment1/segment2 ) if parsedUrl[4] != EmptyString { segments = ParseSegments(parsedUrl[4]) } // Parse arguments ( arg1=value1&arg2=value2 ) if parsedUrl[5] != EmptyString { arguments = ParseArguments(parsedUrl[5]) } return UrlParts{ Driver: driver, Username: username, Password: password, Host: host, Port: port, Segments: segments, Arguments: arguments, } } func ParseSegments(segments string) []string { if segments == EmptyString { return []string{} } return strings.Split(segments, "/") } func ParseArguments(arguments string) map[string]string { if arguments == EmptyString { return make(map[string]string) } var argsMap map[string]string = make(map[string]string) splitArguments := strings.Split(arguments, "&") for _, arg := range splitArguments { if !strings.Contains(arg, "=") { continue } splitArgAndValue := strings.Split(arg, "=") argsMap[splitArgAndValue[0]] = splitArgAndValue[1] } return argsMap } // Returns true if valid, with nil error, or false if invalid, with the validation error func (urlParts *UrlParts) Validate() (bool, error) { if !slices.Contains(AvailableDbDrivers, DbDriver(urlParts.Driver)) { return false, PilgrimInvalidError(fmt.Sprintf("URLParts invalid: Provided driver %v is not currently supported ( must be one of %v )", urlParts.Driver, AvailableDbDrivers)) } return true, nil }