1package pgproto3
2
3import (
4	"bytes"
5	"encoding/json"
6	"errors"
7
8	"github.com/jackc/pgio"
9)
10
11type Close struct {
12	ObjectType byte // 'S' = prepared statement, 'P' = portal
13	Name       string
14}
15
16// Frontend identifies this message as sendable by a PostgreSQL frontend.
17func (*Close) Frontend() {}
18
19// Decode decodes src into dst. src must contain the complete message with the exception of the initial 1 byte message
20// type identifier and 4 byte message length.
21func (dst *Close) Decode(src []byte) error {
22	if len(src) < 2 {
23		return &invalidMessageFormatErr{messageType: "Close"}
24	}
25
26	dst.ObjectType = src[0]
27	rp := 1
28
29	idx := bytes.IndexByte(src[rp:], 0)
30	if idx != len(src[rp:])-1 {
31		return &invalidMessageFormatErr{messageType: "Close"}
32	}
33
34	dst.Name = string(src[rp : len(src)-1])
35
36	return nil
37}
38
39// Encode encodes src into dst. dst will include the 1 byte message type identifier and the 4 byte message length.
40func (src *Close) Encode(dst []byte) []byte {
41	dst = append(dst, 'C')
42	sp := len(dst)
43	dst = pgio.AppendInt32(dst, -1)
44
45	dst = append(dst, src.ObjectType)
46	dst = append(dst, src.Name...)
47	dst = append(dst, 0)
48
49	pgio.SetInt32(dst[sp:], int32(len(dst[sp:])))
50
51	return dst
52}
53
54// MarshalJSON implements encoding/json.Marshaler.
55func (src Close) MarshalJSON() ([]byte, error) {
56	return json.Marshal(struct {
57		Type       string
58		ObjectType string
59		Name       string
60	}{
61		Type:       "Close",
62		ObjectType: string(src.ObjectType),
63		Name:       src.Name,
64	})
65}
66
67// UnmarshalJSON implements encoding/json.Unmarshaler.
68func (dst *Close) UnmarshalJSON(data []byte) error {
69	// Ignore null, like in the main JSON package.
70	if string(data) == "null" {
71		return nil
72	}
73
74	var msg struct {
75		ObjectType string
76		Name       string
77	}
78	if err := json.Unmarshal(data, &msg); err != nil {
79		return err
80	}
81
82	if len(msg.ObjectType) != 1 {
83		return errors.New("invalid length for Close.ObjectType")
84	}
85
86	dst.ObjectType = byte(msg.ObjectType[0])
87	dst.Name = msg.Name
88	return nil
89}
90