dsn

package
v0.0.0-...-b779cef Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 11, 2023 License: Apache-2.0 Imports: 8 Imported by: 18

Documentation

Overview

The package dsn is a toolbox of functions to fill and format structs from varying sources. It acts entirely upon struct metadata.

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func FlagSet

func FlagSet(name string, errorHandling flag.ErrorHandling, info interface{}) (*flag.FlagSet, error)

FlagSet creates a flag.FlagSet to be used with the stdlib flag package or flag-compatible third party packages.

Flags will be created for members based on their json metadata. If no json metadata is present no flag will be created. If the member has a doc metadata tag its value will be used as the usage argument for the flag.

The resulting FlagSet can be used with e.g. github.com/spf13/pflag to merge multiple FlagSets.

func FormatSimple

func FormatSimple(input interface{}) string

FormatSimple formats the passed value as a simple DSN.

Only members with a json metadata tag are added with the json metadata value used as the key.

Example:

type Example struct {
    StringA string `json:"a"`
    IntB int `json:"b"`
}

ex := new(Example)
ex.StringA = "a string"
ex.IntB = 5

fmt.Println(dsn.FormatSimple(ex))

Will print:

a="a string" b=5

func FormatURI

func FormatURI(input interface{}) (string, error)

FormatURI formats the passed values as a simple URI.

Only members with a json metadata tag are added with the json metadata value used as key. This key should reflect an URI-resource name, e.g. scheme, user, password, host, port. The associated values of these keys are passed to an URL-struct.

Additionally, the keys referring to a userstorekey or database will be added as connection property using their respective key, e.g. "KEY=<userstorekey>" or "database=<database>".

Any key that does not match such URI-resource name will be added as connection property following the scheme: "<key>=<value>". Thus, non-string struct-members that do not match any URI-resource name and default to "0" (int) or "false" (boolean) are added as connection property with their default as value. To avoid possible issues, use string-members with an empty string.

Example:

type Example struct {
    Scheme       string `json:"scheme"`
    User         string `json:"user"`
    Pass         string `json:"pass"`
    Host         string `json:"host"`
    Port         int    `json:"port"`
    Database     string `json:"database"`
    ConnectProp1 bool   `json:"connectProp1"`
    ConnectProp2 string `json:"connectProp2"`
}

ex := new(Example)
ex.Scheme       = "db"
ex.User         = "username"
ex.Pass         = "password"
ex.Host         = "hostname"
ex.Port         = 12345
ex.Database     = "db1"
ex.ConnectProp1 = false
ex.ConnectProp2 = "connectionProperty"

uri, err := dsn.FormatURI(ex)
if err != nil {
  fmt.Errorf("Something failed: %w", err)
}

fmt.Println(uri)

Will print:

db://username:password@hostname:12345/?database=db1&connectProp1=false&connectProp2=connectionProperty

For more examples see format_test.go

func FromEnv

func FromEnv(prefix string, input interface{}) error

FromEnv reads values from environment variables into the given input.

Environment variables are matched to members of the input based on the json and multiref metadata tags.

Example:

os.Setenv("MY_MEMBER", "an example")
os.Setenv("MY_SECOND_MEMBER", "5")

type Example struct {
    Member string `json:"member"`
    AnotherMember int `json:"another-member" multiref:"second-member"`
}

ex := new(Example)
if err := FromEnv("MY", ex); err != nil {
    return err
}

ex.Member will be "an example" and ex.AnotherMember will be 5.

Also see dsn/examples/from_env.

func Parse

func Parse(dsn string, target interface{}) error

Parse uses ParseURI or ParseSimple and returns the respective error. The decision is made based on the existence of "://" in the passed string.

func ParseSimple

func ParseSimple(dsn string, target interface{}) error

ParseSimple parses a simple DSN in the form of "key=value k2=v2".

Only members with a json or multiref metadata tag will be filled. Should be member have both json and multiref tags which occur multiple times in the passed string the last occurrence will take priority.

ParseSimple supports whitespaces in values, but not in keys - given that values are quoted with either double or single quotes.

Example:

type Example struct {
    // Recognized as "hostname", "host" and "remote"
    Host string `json:"hostname" multiref:"host,remote"`
    // Only recognized as "port"
    Port string `json:"port"`
    // Recognized as "database" and "db"
    Database string `json:"database" multiref:"db"`
    // Not recognized due to missing metadata
    Username string
}

ex := new(Example)
simple := `host="a.b.c.d" remote='w.x.y.z' port=ssl username="user"`
if err := dsn.ParseSimple(simple, ex); err != nil {
    return err
}

Will result in :

ex.Host being set to "w.x.y.z" as it's multiref tag 'remote' came last.
ex.Port being set to "ssl".
ex.Database not being set as no values were provided.
ex.Username not being set as it has no metadata.

func ParseURI

func ParseURI(dsn string, target interface{}) error

ParseURI uses url.Parse to parse the passed string.

Only members with json metadata tags will be filled. Additionally multiref metadata tags are recognized.

Hostname, Port, Username and Password are hardcoded to be set to "hostname", "port", "username" and "password" respectively due to technical limitations.

If the "database" tag is set its member is set to the path of the URI, sans the leading "/".

func TagToField

func TagToField(input interface{}, tagType TagType) map[string]reflect.Value

TagToField returns a mapping from json metadata tags to reflect.Values.

If TagType OnlyJSON is passed only the json tag will be mapped. If the TagType MultiRef is passed the tags from the `multiref` metadata tag will also be mapped to their field.Value.

Example:

type Example struct {
	Host `json:"host" multiref:"hostname"`
}

example := Example{Host: "host.name.tld"}
TagToField(example, OnlyJSON)
-> map[string]reflect.Value{
    "host": example.Host,
}
TagToField(example, Multiref)
-> map[string]reflect.Value{
    "host": example.Host,
    "hostname": example.Host,
}

If the TagType Doc is passed the json metadata tag value will be mapped to a reflect.Value of Kind string containing the value of the doc metadata tag..

Example:

type Example struct {
    Host `json:"hostname" doc:"Hostname to connect to"`
}

example := new(Example)
TagToField(example, Doc)
-> map[string]reflect.Value{
      "hostname": reflect.ValueOf("Hostname to connect to"),
   }

If the input is a pointer the reflect.Values will be addressable and settable - allowing to modify the fields of the passed structure.

Example:

type Example struct {
    Host `json:"host"`
}

example := Example{Host: "old.host.name"}
ttf := TagToField(&example, OnlyJSON)
ttf["host"].SetString("new.host.name")
fmt.Println(example.Host)
-> "new.host.name"

Types

type Info

type Info struct {
	Host     string `json:"host" multiref:"hostname" doc:"Hostname to connect to"`
	Port     string `json:"port" doc:"Port (Example: '443' or 'tls') to connect to"`
	Username string `json:"username" multiref:"user" doc:"Username"`
	Password string `json:"password" multiref:"passwd,pass" doc:"Password"`
	Database string `json:"database" multiref:"db" doc:"Database"`
}

Info serves as both an example and an embeddable default to use in DSN structs.

type TagType

type TagType string
const (
	OnlyJSON TagType = "json"
	Multiref TagType = "multiref"
	Doc      TagType = "doc"
)

Directories

Path Synopsis
examples

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL