gtsocial-umbx

Unnamed repository; edit this file 'description' to name the repository.
Log | Files | Refs | README | LICENSE

append.go (8569B)


      1 package pgdialect
      2 
      3 import (
      4 	"database/sql/driver"
      5 	"encoding/hex"
      6 	"fmt"
      7 	"reflect"
      8 	"strconv"
      9 	"time"
     10 	"unicode/utf8"
     11 
     12 	"github.com/uptrace/bun/dialect"
     13 	"github.com/uptrace/bun/schema"
     14 )
     15 
     16 var (
     17 	driverValuerType = reflect.TypeOf((*driver.Valuer)(nil)).Elem()
     18 
     19 	stringType      = reflect.TypeOf((*string)(nil)).Elem()
     20 	sliceStringType = reflect.TypeOf([]string(nil))
     21 
     22 	intType      = reflect.TypeOf((*int)(nil)).Elem()
     23 	sliceIntType = reflect.TypeOf([]int(nil))
     24 
     25 	int64Type      = reflect.TypeOf((*int64)(nil)).Elem()
     26 	sliceInt64Type = reflect.TypeOf([]int64(nil))
     27 
     28 	float64Type      = reflect.TypeOf((*float64)(nil)).Elem()
     29 	sliceFloat64Type = reflect.TypeOf([]float64(nil))
     30 
     31 	timeType      = reflect.TypeOf((*time.Time)(nil)).Elem()
     32 	sliceTimeType = reflect.TypeOf([]time.Time(nil))
     33 )
     34 
     35 func arrayAppend(fmter schema.Formatter, b []byte, v interface{}) []byte {
     36 	switch v := v.(type) {
     37 	case int64:
     38 		return strconv.AppendInt(b, v, 10)
     39 	case float64:
     40 		return dialect.AppendFloat64(b, v)
     41 	case bool:
     42 		return dialect.AppendBool(b, v)
     43 	case []byte:
     44 		return arrayAppendBytes(b, v)
     45 	case string:
     46 		return arrayAppendString(b, v)
     47 	case time.Time:
     48 		return fmter.Dialect().AppendTime(b, v)
     49 	default:
     50 		err := fmt.Errorf("pgdialect: can't append %T", v)
     51 		return dialect.AppendError(b, err)
     52 	}
     53 }
     54 
     55 func arrayAppendStringValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
     56 	return arrayAppendString(b, v.String())
     57 }
     58 
     59 func arrayAppendBytesValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
     60 	return arrayAppendBytes(b, v.Bytes())
     61 }
     62 
     63 func arrayAppendDriverValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
     64 	iface, err := v.Interface().(driver.Valuer).Value()
     65 	if err != nil {
     66 		return dialect.AppendError(b, err)
     67 	}
     68 	return arrayAppend(fmter, b, iface)
     69 }
     70 
     71 //------------------------------------------------------------------------------
     72 
     73 func (d *Dialect) arrayAppender(typ reflect.Type) schema.AppenderFunc {
     74 	kind := typ.Kind()
     75 
     76 	switch kind {
     77 	case reflect.Ptr:
     78 		if fn := d.arrayAppender(typ.Elem()); fn != nil {
     79 			return schema.PtrAppender(fn)
     80 		}
     81 	case reflect.Slice, reflect.Array:
     82 		// ok:
     83 	default:
     84 		return nil
     85 	}
     86 
     87 	elemType := typ.Elem()
     88 
     89 	if kind == reflect.Slice {
     90 		switch elemType {
     91 		case stringType:
     92 			return appendStringSliceValue
     93 		case intType:
     94 			return appendIntSliceValue
     95 		case int64Type:
     96 			return appendInt64SliceValue
     97 		case float64Type:
     98 			return appendFloat64SliceValue
     99 		case timeType:
    100 			return appendTimeSliceValue
    101 		}
    102 	}
    103 
    104 	appendElem := d.arrayElemAppender(elemType)
    105 	if appendElem == nil {
    106 		panic(fmt.Errorf("pgdialect: %s is not supported", typ))
    107 	}
    108 
    109 	return func(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
    110 		kind := v.Kind()
    111 		switch kind {
    112 		case reflect.Ptr, reflect.Slice:
    113 			if v.IsNil() {
    114 				return dialect.AppendNull(b)
    115 			}
    116 		}
    117 
    118 		if kind == reflect.Ptr {
    119 			v = v.Elem()
    120 		}
    121 
    122 		b = append(b, '\'')
    123 
    124 		b = append(b, '{')
    125 		ln := v.Len()
    126 		for i := 0; i < ln; i++ {
    127 			elem := v.Index(i)
    128 			b = appendElem(fmter, b, elem)
    129 			b = append(b, ',')
    130 		}
    131 		if v.Len() > 0 {
    132 			b[len(b)-1] = '}' // Replace trailing comma.
    133 		} else {
    134 			b = append(b, '}')
    135 		}
    136 
    137 		b = append(b, '\'')
    138 
    139 		return b
    140 	}
    141 }
    142 
    143 func (d *Dialect) arrayElemAppender(typ reflect.Type) schema.AppenderFunc {
    144 	if typ.Implements(driverValuerType) {
    145 		return arrayAppendDriverValue
    146 	}
    147 	switch typ.Kind() {
    148 	case reflect.String:
    149 		return arrayAppendStringValue
    150 	case reflect.Slice:
    151 		if typ.Elem().Kind() == reflect.Uint8 {
    152 			return arrayAppendBytesValue
    153 		}
    154 	}
    155 	return schema.Appender(d, typ)
    156 }
    157 
    158 func appendStringSliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
    159 	ss := v.Convert(sliceStringType).Interface().([]string)
    160 	return appendStringSlice(b, ss)
    161 }
    162 
    163 func appendStringSlice(b []byte, ss []string) []byte {
    164 	if ss == nil {
    165 		return dialect.AppendNull(b)
    166 	}
    167 
    168 	b = append(b, '\'')
    169 
    170 	b = append(b, '{')
    171 	for _, s := range ss {
    172 		b = arrayAppendString(b, s)
    173 		b = append(b, ',')
    174 	}
    175 	if len(ss) > 0 {
    176 		b[len(b)-1] = '}' // Replace trailing comma.
    177 	} else {
    178 		b = append(b, '}')
    179 	}
    180 
    181 	b = append(b, '\'')
    182 
    183 	return b
    184 }
    185 
    186 func appendIntSliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
    187 	ints := v.Convert(sliceIntType).Interface().([]int)
    188 	return appendIntSlice(b, ints)
    189 }
    190 
    191 func appendIntSlice(b []byte, ints []int) []byte {
    192 	if ints == nil {
    193 		return dialect.AppendNull(b)
    194 	}
    195 
    196 	b = append(b, '\'')
    197 
    198 	b = append(b, '{')
    199 	for _, n := range ints {
    200 		b = strconv.AppendInt(b, int64(n), 10)
    201 		b = append(b, ',')
    202 	}
    203 	if len(ints) > 0 {
    204 		b[len(b)-1] = '}' // Replace trailing comma.
    205 	} else {
    206 		b = append(b, '}')
    207 	}
    208 
    209 	b = append(b, '\'')
    210 
    211 	return b
    212 }
    213 
    214 func appendInt64SliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
    215 	ints := v.Convert(sliceInt64Type).Interface().([]int64)
    216 	return appendInt64Slice(b, ints)
    217 }
    218 
    219 func appendInt64Slice(b []byte, ints []int64) []byte {
    220 	if ints == nil {
    221 		return dialect.AppendNull(b)
    222 	}
    223 
    224 	b = append(b, '\'')
    225 
    226 	b = append(b, '{')
    227 	for _, n := range ints {
    228 		b = strconv.AppendInt(b, n, 10)
    229 		b = append(b, ',')
    230 	}
    231 	if len(ints) > 0 {
    232 		b[len(b)-1] = '}' // Replace trailing comma.
    233 	} else {
    234 		b = append(b, '}')
    235 	}
    236 
    237 	b = append(b, '\'')
    238 
    239 	return b
    240 }
    241 
    242 func appendFloat64SliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
    243 	floats := v.Convert(sliceFloat64Type).Interface().([]float64)
    244 	return appendFloat64Slice(b, floats)
    245 }
    246 
    247 func appendFloat64Slice(b []byte, floats []float64) []byte {
    248 	if floats == nil {
    249 		return dialect.AppendNull(b)
    250 	}
    251 
    252 	b = append(b, '\'')
    253 
    254 	b = append(b, '{')
    255 	for _, n := range floats {
    256 		b = dialect.AppendFloat64(b, n)
    257 		b = append(b, ',')
    258 	}
    259 	if len(floats) > 0 {
    260 		b[len(b)-1] = '}' // Replace trailing comma.
    261 	} else {
    262 		b = append(b, '}')
    263 	}
    264 
    265 	b = append(b, '\'')
    266 
    267 	return b
    268 }
    269 
    270 //------------------------------------------------------------------------------
    271 
    272 func arrayAppendBytes(b []byte, bs []byte) []byte {
    273 	if bs == nil {
    274 		return dialect.AppendNull(b)
    275 	}
    276 
    277 	b = append(b, `"\\x`...)
    278 
    279 	s := len(b)
    280 	b = append(b, make([]byte, hex.EncodedLen(len(bs)))...)
    281 	hex.Encode(b[s:], bs)
    282 
    283 	b = append(b, '"')
    284 
    285 	return b
    286 }
    287 
    288 func arrayAppendString(b []byte, s string) []byte {
    289 	b = append(b, '"')
    290 	for _, r := range s {
    291 		switch r {
    292 		case 0:
    293 			// ignore
    294 		case '\'':
    295 			b = append(b, "''"...)
    296 		case '"':
    297 			b = append(b, '\\', '"')
    298 		case '\\':
    299 			b = append(b, '\\', '\\')
    300 		default:
    301 			if r < utf8.RuneSelf {
    302 				b = append(b, byte(r))
    303 				break
    304 			}
    305 			l := len(b)
    306 			if cap(b)-l < utf8.UTFMax {
    307 				b = append(b, make([]byte, utf8.UTFMax)...)
    308 			}
    309 			n := utf8.EncodeRune(b[l:l+utf8.UTFMax], r)
    310 			b = b[:l+n]
    311 		}
    312 	}
    313 	b = append(b, '"')
    314 	return b
    315 }
    316 
    317 func appendTimeSliceValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
    318 	ts := v.Convert(sliceTimeType).Interface().([]time.Time)
    319 	return appendTimeSlice(fmter, b, ts)
    320 }
    321 
    322 func appendTimeSlice(fmter schema.Formatter, b []byte, ts []time.Time) []byte {
    323 	if ts == nil {
    324 		return dialect.AppendNull(b)
    325 	}
    326 	b = append(b, '\'')
    327 	b = append(b, '{')
    328 	for _, t := range ts {
    329 		b = append(b, '"')
    330 		b = t.UTC().AppendFormat(b, "2006-01-02 15:04:05.999999-07:00")
    331 		b = append(b, '"')
    332 		b = append(b, ',')
    333 	}
    334 	if len(ts) > 0 {
    335 		b[len(b)-1] = '}' // Replace trailing comma.
    336 	} else {
    337 		b = append(b, '}')
    338 	}
    339 	b = append(b, '\'')
    340 	return b
    341 }
    342 
    343 //------------------------------------------------------------------------------
    344 
    345 var mapStringStringType = reflect.TypeOf(map[string]string(nil))
    346 
    347 func (d *Dialect) hstoreAppender(typ reflect.Type) schema.AppenderFunc {
    348 	kind := typ.Kind()
    349 
    350 	switch kind {
    351 	case reflect.Ptr:
    352 		if fn := d.hstoreAppender(typ.Elem()); fn != nil {
    353 			return schema.PtrAppender(fn)
    354 		}
    355 	case reflect.Map:
    356 		// ok:
    357 	default:
    358 		return nil
    359 	}
    360 
    361 	if typ.Key() == stringType && typ.Elem() == stringType {
    362 		return appendMapStringStringValue
    363 	}
    364 
    365 	return func(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
    366 		err := fmt.Errorf("bun: Hstore(unsupported %s)", v.Type())
    367 		return dialect.AppendError(b, err)
    368 	}
    369 }
    370 
    371 func appendMapStringString(b []byte, m map[string]string) []byte {
    372 	if m == nil {
    373 		return dialect.AppendNull(b)
    374 	}
    375 
    376 	b = append(b, '\'')
    377 
    378 	for key, value := range m {
    379 		b = arrayAppendString(b, key)
    380 		b = append(b, '=', '>')
    381 		b = arrayAppendString(b, value)
    382 		b = append(b, ',')
    383 	}
    384 	if len(m) > 0 {
    385 		b = b[:len(b)-1] // Strip trailing comma.
    386 	}
    387 
    388 	b = append(b, '\'')
    389 
    390 	return b
    391 }
    392 
    393 func appendMapStringStringValue(fmter schema.Formatter, b []byte, v reflect.Value) []byte {
    394 	m := v.Convert(mapStringStringType).Interface().(map[string]string)
    395 	return appendMapStringString(b, m)
    396 }