Source File
composite_type.go
Belonging Package
github.com/jackc/pgtype
package pgtype
import (
)
type CompositeTypeField struct {
Name string
OID uint32
}
type CompositeType struct {
status Status
typeName string
fields []CompositeTypeField
valueTranscoders []ValueTranscoder
}
func ( string, []CompositeTypeField, *ConnInfo) (*CompositeType, error) {
:= make([]ValueTranscoder, len())
for := range {
, := .DataTypeForOID([].OID)
if ! {
return nil, fmt.Errorf("no data type registered for oid: %d", [].OID)
}
:= NewValue(.Value)
, := .(ValueTranscoder)
if ! {
return nil, fmt.Errorf("data type for oid does not implement ValueTranscoder: %d", [].OID)
}
[] =
}
return &CompositeType{typeName: , fields: , valueTranscoders: }, nil
}
func ( string, []CompositeTypeField, []ValueTranscoder) (*CompositeType, error) {
if len() != len() {
return nil, errors.New("fields and valueTranscoders must have same length")
}
return &CompositeType{typeName: , fields: , valueTranscoders: }, nil
}
func ( CompositeType) () interface{} {
switch .status {
case Present:
:= make(map[string]interface{}, len(.valueTranscoders))
for := range .valueTranscoders {
[.fields[].Name] = .valueTranscoders[].Get()
}
return
case Null:
return nil
default:
return .status
}
}
func ( *CompositeType) () Value {
:= &CompositeType{
typeName: .typeName,
fields: .fields,
valueTranscoders: make([]ValueTranscoder, len(.valueTranscoders)),
}
for := range .valueTranscoders {
.valueTranscoders[] = NewValue(.valueTranscoders[]).(ValueTranscoder)
}
return
}
func ( *CompositeType) () string {
return .typeName
}
func ( *CompositeType) () []CompositeTypeField {
return .fields
}
func ( *CompositeType) ( interface{}) error {
if == nil {
.status = Null
return nil
}
switch value := .(type) {
case []interface{}:
if len() != len(.valueTranscoders) {
return fmt.Errorf("Number of fields don't match. CompositeType has %d fields", len(.valueTranscoders))
}
for , := range {
if := .valueTranscoders[].Set(); != nil {
return
}
}
.status = Present
case *[]interface{}:
if == nil {
.status = Null
return nil
}
return .(*)
default:
return fmt.Errorf("Can not convert %v to Composite", )
}
return nil
}
func ( CompositeType) ( interface{}) error {
switch .status {
case Present:
switch v := .(type) {
case []interface{}:
if len() != len(.valueTranscoders) {
return fmt.Errorf("Number of fields don't match. CompositeType has %d fields", len(.valueTranscoders))
}
for := range .valueTranscoders {
if [] == nil {
continue
}
:= assignToOrSet(.valueTranscoders[], [])
if != nil {
return fmt.Errorf("unable to assign to dst[%d]: %v", , )
}
}
return nil
case *[]interface{}:
return .(*)
default:
if , := .assignToPtrStruct(); {
return
}
if , := GetAssignToDstType(); {
return .()
}
return fmt.Errorf("unable to assign to %T", )
}
case Null:
return NullAssignTo()
}
return fmt.Errorf("cannot decode %#v into %T", , )
}
func ( Value, interface{}) error {
:= .AssignTo()
:= false
if , := .(Value); {
:= .Set(.Get())
= == nil
}
if ! {
return
}
}
return nil
}
func ( CompositeType) ( interface{}) (bool, error) {
:= reflect.ValueOf()
if .Kind() != reflect.Ptr {
return false, nil
}
if .IsNil() {
return false, nil
}
:= .Elem()
:= .Type()
if .Kind() != reflect.Struct {
return false, nil
}
:= make([]int, 0, .NumField())
for := 0; < .NumField(); ++ {
:= .Field()
if .PkgPath == "" {
= append(, )
}
}
if len() != len(.valueTranscoders) {
return false, nil
}
for := range {
:= assignToOrSet(.valueTranscoders[], .Field([]).Addr().Interface())
if != nil {
return true, fmt.Errorf("unable to assign to field %s: %v", .Field([]).Name, )
}
}
return true, nil
}
func ( CompositeType) ( *ConnInfo, []byte) ( []byte, error) {
switch .status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
:= NewCompositeBinaryBuilder(, )
for := range .valueTranscoders {
.AppendEncoder(.fields[].OID, .valueTranscoders[])
}
return .Finish()
}
func ( *CompositeType) ( *ConnInfo, []byte) error {
if == nil {
.status = Null
return nil
}
:= NewCompositeBinaryScanner(, )
for , := range .valueTranscoders {
.ScanDecoder()
}
if .Err() != nil {
return .Err()
}
.status = Present
return nil
}
func ( *CompositeType) ( *ConnInfo, []byte) error {
if == nil {
.status = Null
return nil
}
:= NewCompositeTextScanner(, )
for , := range .valueTranscoders {
.ScanDecoder()
}
if .Err() != nil {
return .Err()
}
.status = Present
return nil
}
func ( CompositeType) ( *ConnInfo, []byte) ( []byte, error) {
switch .status {
case Null:
return nil, nil
case Undefined:
return nil, errUndefined
}
:= NewCompositeTextBuilder(, )
for , := range .valueTranscoders {
.AppendEncoder()
}
return .Finish()
}
type CompositeBinaryScanner struct {
ci *ConnInfo
rp int
src []byte
fieldCount int32
fieldBytes []byte
fieldOID uint32
err error
}
func ( *ConnInfo, []byte) *CompositeBinaryScanner {
:= 0
if len([:]) < 4 {
return &CompositeBinaryScanner{err: fmt.Errorf("Record incomplete %v", )}
}
:= int32(binary.BigEndian.Uint32([:]))
+= 4
return &CompositeBinaryScanner{
ci: ,
rp: ,
src: ,
fieldCount: ,
}
}
func ( *CompositeBinaryScanner) ( BinaryDecoder) {
if .err != nil {
return
}
if .Next() {
.err = .DecodeBinary(.ci, .fieldBytes)
} else {
.err = errors.New("read past end of composite")
}
}
func ( *CompositeBinaryScanner) () bool {
if .err != nil {
return false
}
if .rp == len(.src) {
return false
}
if len(.src[.rp:]) < 8 {
.err = fmt.Errorf("Record incomplete %v", .src)
return false
}
.fieldOID = binary.BigEndian.Uint32(.src[.rp:])
.rp += 4
:= int(int32(binary.BigEndian.Uint32(.src[.rp:])))
.rp += 4
if >= 0 {
if len(.src[.rp:]) < {
.err = fmt.Errorf("Record incomplete rp=%d src=%v", .rp, .src)
return false
}
.fieldBytes = .src[.rp : .rp+]
.rp +=
} else {
.fieldBytes = nil
}
return true
}
func ( *CompositeBinaryScanner) () int {
return int(.fieldCount)
}
func ( *CompositeBinaryScanner) () []byte {
return .fieldBytes
}
func ( *CompositeBinaryScanner) () uint32 {
return .fieldOID
}
func ( *CompositeBinaryScanner) () error {
return .err
}
type CompositeTextScanner struct {
ci *ConnInfo
rp int
src []byte
fieldBytes []byte
err error
}
func ( *ConnInfo, []byte) *CompositeTextScanner {
if len() < 2 {
return &CompositeTextScanner{err: fmt.Errorf("Record incomplete %v", )}
}
if [0] != '(' {
return &CompositeTextScanner{err: fmt.Errorf("composite text format must start with '('")}
}
if [len()-1] != ')' {
return &CompositeTextScanner{err: fmt.Errorf("composite text format must end with ')'")}
}
return &CompositeTextScanner{
ci: ,
rp: 1,
src: ,
}
}
func ( *CompositeTextScanner) ( TextDecoder) {
if .err != nil {
return
}
if .Next() {
.err = .DecodeText(.ci, .fieldBytes)
} else {
.err = errors.New("read past end of composite")
}
}
func ( *CompositeTextScanner) () bool {
if .err != nil {
return false
}
if .rp == len(.src) {
return false
}
switch .src[.rp] {
case ',', ')': // null
.rp++
.fieldBytes = nil
return true
case '"': // quoted value
.rp++
.fieldBytes = make([]byte, 0, 16)
for {
:= .src[.rp]
if == '"' {
.rp++
if .src[.rp] == '"' {
.fieldBytes = append(.fieldBytes, '"')
.rp++
} else {
break
}
} else {
.fieldBytes = append(.fieldBytes, )
.rp++
}
}
.rp++
return true
default: // unquoted value
:= .rp
for {
:= .src[.rp]
if == ',' || == ')' {
break
}
.rp++
}
.fieldBytes = .src[:.rp]
.rp++
return true
}
}
func ( *CompositeTextScanner) () []byte {
return .fieldBytes
}
func ( *CompositeTextScanner) () error {
return .err
}
type CompositeBinaryBuilder struct {
ci *ConnInfo
buf []byte
startIdx int
fieldCount uint32
err error
}
func ( *ConnInfo, []byte) *CompositeBinaryBuilder {
:= len()
= append(, 0, 0, 0, 0) // allocate room for number of fields
return &CompositeBinaryBuilder{ci: , buf: , startIdx: }
}
func ( *CompositeBinaryBuilder) ( uint32, interface{}) {
if .err != nil {
return
}
, := .ci.DataTypeForOID()
if ! {
.err = fmt.Errorf("unknown data type for OID: %d", )
return
}
:= .Value.Set()
if != nil {
.err =
return
}
, := .Value.(BinaryEncoder)
if ! {
.err = fmt.Errorf("unable to encode binary for OID: %d", )
return
}
.AppendEncoder(, )
}
func ( *CompositeBinaryBuilder) ( uint32, BinaryEncoder) {
if .err != nil {
return
}
.buf = pgio.AppendUint32(.buf, )
:= len(.buf)
.buf = pgio.AppendInt32(.buf, -1)
, := .EncodeBinary(.ci, .buf)
if != nil {
.err =
return
}
if != nil {
binary.BigEndian.PutUint32([:], uint32(len()-len(.buf)))
.buf =
}
.fieldCount++
}
func ( *CompositeBinaryBuilder) () ([]byte, error) {
if .err != nil {
return nil, .err
}
binary.BigEndian.PutUint32(.buf[.startIdx:], .fieldCount)
return .buf, nil
}
type CompositeTextBuilder struct {
ci *ConnInfo
buf []byte
startIdx int
fieldCount uint32
err error
fieldBuf [32]byte
}
func ( *ConnInfo, []byte) *CompositeTextBuilder {
= append(, '(') // allocate room for number of fields
return &CompositeTextBuilder{ci: , buf: }
}
func ( *CompositeTextBuilder) ( interface{}) {
if .err != nil {
return
}
if == nil {
.buf = append(.buf, ',')
return
}
, := .ci.DataTypeForValue()
if ! {
.err = fmt.Errorf("unknown data type for field: %v", )
return
}
:= .Value.Set()
if != nil {
.err =
return
}
, := .Value.(TextEncoder)
if ! {
.err = fmt.Errorf("unable to encode text for value: %v", )
return
}
.AppendEncoder()
}
func ( *CompositeTextBuilder) ( TextEncoder) {
if .err != nil {
return
}
, := .EncodeText(.ci, .fieldBuf[0:0])
if != nil {
.err =
return
}
if != nil {
.buf = append(.buf, quoteCompositeFieldIfNeeded(string())...)
}
.buf = append(.buf, ',')
}
func ( *CompositeTextBuilder) () ([]byte, error) {
if .err != nil {
return nil, .err
}
.buf[len(.buf)-1] = ')'
return .buf, nil
}
var quoteCompositeReplacer = strings.NewReplacer(`\`, `\\`, `"`, `\"`)
func ( string) string {
return `"` + quoteCompositeReplacer.Replace() + `"`
}
func ( string) string {
if == "" || [0] == ' ' || [len()-1] == ' ' || strings.ContainsAny(, `(),"\`) {
return quoteCompositeField()
}
return
![]() |
The pages are generated with Golds v0.3.2-preview. (GOOS=darwin GOARCH=amd64) Golds is a Go 101 project developed by Tapir Liu. PR and bug reports are welcome and can be submitted to the issue list. Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds. |