src

Go monorepo.
git clone git://code.dwrz.net/src
Log | Files | Refs

encoder.go (1942B)


      1 package query
      2 
      3 import (
      4 	"io"
      5 	"net/url"
      6 	"sort"
      7 )
      8 
      9 // Encoder is a Query encoder that supports construction of Query body
     10 // values using methods.
     11 type Encoder struct {
     12 	// The query values that will be built up to manage encoding.
     13 	values url.Values
     14 	// The writer that the encoded body will be written to.
     15 	writer io.Writer
     16 	Value
     17 }
     18 
     19 // NewEncoder returns a new Query body encoder
     20 func NewEncoder(writer io.Writer) *Encoder {
     21 	values := url.Values{}
     22 	return &Encoder{
     23 		values: values,
     24 		writer: writer,
     25 		Value:  newBaseValue(values),
     26 	}
     27 }
     28 
     29 // Encode returns the []byte slice representing the current
     30 // state of the Query encoder.
     31 func (e Encoder) Encode() error {
     32 	ws, ok := e.writer.(interface{ WriteString(string) (int, error) })
     33 	if !ok {
     34 		// Fall back to less optimal byte slice casting if WriteString isn't available.
     35 		ws = &wrapWriteString{writer: e.writer}
     36 	}
     37 
     38 	// Get the keys and sort them to have a stable output
     39 	keys := make([]string, 0, len(e.values))
     40 	for k := range e.values {
     41 		keys = append(keys, k)
     42 	}
     43 	sort.Strings(keys)
     44 	isFirstEntry := true
     45 	for _, key := range keys {
     46 		queryValues := e.values[key]
     47 		escapedKey := url.QueryEscape(key)
     48 		for _, value := range queryValues {
     49 			if !isFirstEntry {
     50 				if _, err := ws.WriteString(`&`); err != nil {
     51 					return err
     52 				}
     53 			} else {
     54 				isFirstEntry = false
     55 			}
     56 			if _, err := ws.WriteString(escapedKey); err != nil {
     57 				return err
     58 			}
     59 			if _, err := ws.WriteString(`=`); err != nil {
     60 				return err
     61 			}
     62 			if _, err := ws.WriteString(url.QueryEscape(value)); err != nil {
     63 				return err
     64 			}
     65 		}
     66 	}
     67 	return nil
     68 }
     69 
     70 // wrapWriteString wraps an io.Writer to provide a WriteString method
     71 // where one is not available.
     72 type wrapWriteString struct {
     73 	writer io.Writer
     74 }
     75 
     76 // WriteString writes a string to the wrapped writer by casting it to
     77 // a byte array first.
     78 func (w wrapWriteString) WriteString(v string) (int, error) {
     79 	return w.writer.Write([]byte(v))
     80 }