Skip to content

Commit 63738f3

Browse files
feat: Add support for more PostgreSQL data types (#19)
This commit adds support for several new PostgreSQL data types to the pgtalk library. The following data types are now supported: - money - xml - real - smallint - time without time zone - character - line - lseg - box - path - polygon - circle - cidr - inet - macaddr - bit - bit varying This change includes: - New mappings in `cmd/pgtalk-gen/mapping.go`. - A new accessor for `smallint` in `access_int16.go`. - New conversion functions in `convert/convert.go`. - A new test table `new_types` in `test/main_test.go` to test the new data types. - The generated code for the new test table. - Removal of an obsolete `mapping.json` file from the test directory. Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
1 parent 443c52d commit 63738f3

File tree

6 files changed

+375
-8
lines changed

6 files changed

+375
-8
lines changed

access_int16.go

Lines changed: 99 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
package pgtalk
2+
3+
import (
4+
"fmt"
5+
"strings"
6+
7+
"github.com/jackc/pgx/v5/pgtype"
8+
)
9+
10+
// int16Access can Read a column value (int2) and Write a column value and Set a struct field (int16).
11+
type int16Access struct {
12+
unimplementedBooleanExpression
13+
ColumnInfo
14+
fieldWriter fieldAccessFunc
15+
valueToInsert int16
16+
}
17+
18+
func NewInt16Access(
19+
info ColumnInfo,
20+
valueWriter func(dest any) any) int16Access {
21+
return int16Access{
22+
ColumnInfo: info,
23+
fieldWriter: valueWriter}
24+
}
25+
26+
func (a int16Access) BetweenAnd(begin int16, end int16) betweenAnd {
27+
return makeBetweenAnd(a, valuePrinter{v: begin}, valuePrinter{v: end})
28+
}
29+
30+
func (a int16Access) FieldValueToScan(entity any) any {
31+
return a.fieldWriter(entity)
32+
}
33+
34+
func (a int16Access) ValueToInsert() any {
35+
return a.valueToInsert
36+
}
37+
38+
func (a int16Access) Set(v int16) int16Access {
39+
a.valueToInsert = v
40+
return a
41+
}
42+
43+
func (a int16Access) In(values ...int16) SQLExpression {
44+
if len(values) == 0 {
45+
return makeConstantExpression(false)
46+
}
47+
vs := make([]any, len(values))
48+
for i := 0; i < len(values); i++ {
49+
vs[i] = values[i]
50+
}
51+
return makeBinaryOperator(a, "IN", valuesPrinter{vs: vs})
52+
}
53+
54+
func (a int16Access) Equals(intLike any) SQLExpression {
55+
if i, ok := intLike.(int); ok {
56+
return makeBinaryOperator(a, "=", valuePrinter{v: i})
57+
}
58+
if i, ok := intLike.(int16); ok {
59+
return makeBinaryOperator(a, "=", valuePrinter{v: i})
60+
}
61+
if ia, ok := intLike.(int16Access); ok {
62+
return makeBinaryOperator(a, "=", ia)
63+
}
64+
if p, ok := intLike.(*QueryParameter); ok {
65+
return makeBinaryOperator(a, "=", p)
66+
}
67+
if p, ok := intLike.(FieldAccess[pgtype.Int2]); ok {
68+
return makeBinaryOperator(a, "=", p)
69+
}
70+
panic(fmt.Sprintf("int, int16, Int16Access or *QueryParameter expected, got %T", intLike))
71+
}
72+
73+
func (a int16Access) Compare(op string, i int) binaryExpression {
74+
if !strings.Contains(validComparisonOperators, op) {
75+
panic("invalid comparison operator:" + op)
76+
}
77+
return makeBinaryOperator(a, op, valuePrinter{v: i})
78+
}
79+
80+
func (a int16Access) Column() ColumnInfo { return a.ColumnInfo }
81+
82+
func (a int16Access) TableAlias(alias string) int16Access {
83+
a.ColumnInfo = a.ColumnInfo.TableAlias(alias)
84+
return a
85+
}
86+
87+
// AppendScannable is part of ColumnAccessor
88+
func (a int16Access) AppendScannable(list []any) []any {
89+
return append(list, &a.valueToInsert)
90+
}
91+
92+
// Get returns the value for its columnName from a map (row).
93+
func (a int16Access) Get(values map[string]any) any {
94+
v, ok := values[a.columnName]
95+
if !ok {
96+
return int16(0)
97+
}
98+
return v
99+
}

cmd/pgtalk-gen/mapping.go

Lines changed: 86 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,59 @@ func (m mapping) validate() error {
9494

9595
// https://www.postgresql.org/docs/9.1/datatype-numeric.html
9696
var pgMappings = map[string]mapping{
97+
"money": {
98+
goFieldType: "pgtype.Money",
99+
nullableGoFieldType: "pgtype.Money",
100+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Money]",
101+
},
102+
"xml": {
103+
goFieldType: "pgtype.XML",
104+
nullableGoFieldType: "pgtype.XML",
105+
newAccessFuncCall: "p.NewFieldAccess[pgtype.XML]",
106+
},
107+
"real": {
108+
goFieldType: "float32",
109+
nullableGoFieldType: "pgtype.Float4",
110+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Float4]",
111+
},
112+
"cidr": {
113+
nullableGoFieldType: "pgtype.CIDR",
114+
newAccessFuncCall: "p.NewFieldAccess[pgtype.CIDR]",
115+
},
116+
"inet": {
117+
nullableGoFieldType: "pgtype.Inet",
118+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Inet]",
119+
},
120+
"macaddr": {
121+
nullableGoFieldType: "pgtype.Macaddr",
122+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Macaddr]",
123+
},
124+
"bit": {
125+
nullableGoFieldType: "pgtype.Bit",
126+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Bit]",
127+
},
128+
"bit varying": {
129+
nullableGoFieldType: "pgtype.Varbit",
130+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Varbit]",
131+
},
132+
"smallint": {
133+
goFieldType: "int16",
134+
newFuncCall: "p.NewInt16Access",
135+
136+
nullableValueFieldName: "Int",
137+
convertFuncName: "c.Int16ToInt2",
138+
nullableGoFieldType: "pgtype.Int2",
139+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Int2]",
140+
},
141+
"time without time zone": {
142+
goFieldType: "time.Time",
143+
newFuncCall: "p.NewTimeAccess",
144+
145+
nullableValueFieldName: "Time",
146+
convertFuncName: "c.TimeToTime",
147+
nullableGoFieldType: "pgtype.Time",
148+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Time]",
149+
},
97150
"timestamp with time zone": {
98151
goFieldType: "time.Time",
99152
newFuncCall: "p.NewTimeAccess",
@@ -130,6 +183,15 @@ var pgMappings = map[string]mapping{
130183
nullableGoFieldType: "pgtype.Text",
131184
newAccessFuncCall: "p.NewFieldAccess[pgtype.Text]",
132185
},
186+
"character": {
187+
goFieldType: "string",
188+
newFuncCall: "p.NewTextAccess",
189+
190+
nullableValueFieldName: "String",
191+
convertFuncName: "c.StringToText",
192+
nullableGoFieldType: "pgtype.Text",
193+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Text]",
194+
},
133195
"text": {
134196
goFieldType: "string",
135197
newFuncCall: "p.NewTextAccess",
@@ -229,4 +291,28 @@ var pgMappings = map[string]mapping{
229291
nullableGoFieldType: "pgtype.Interval",
230292
newAccessFuncCall: "p.NewFieldAccess[pgtype.Interval]",
231293
},
294+
"line": {
295+
nullableGoFieldType: "pgtype.Line",
296+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Line]",
297+
},
298+
"lseg": {
299+
nullableGoFieldType: "pgtype.Lseg",
300+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Lseg]",
301+
},
302+
"box": {
303+
nullableGoFieldType: "pgtype.Box",
304+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Box]",
305+
},
306+
"path": {
307+
nullableGoFieldType: "pgtype.Path",
308+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Path]",
309+
},
310+
"polygon": {
311+
nullableGoFieldType: "pgtype.Polygon",
312+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Polygon]",
313+
},
314+
"circle": {
315+
nullableGoFieldType: "pgtype.Circle",
316+
newAccessFuncCall: "p.NewFieldAccess[pgtype.Circle]",
317+
},
232318
}

convert/convert.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,14 @@ func TimeToDate(t time.Time) pgtype.Date {
7474
return pgtype.Date{Time: t, Valid: true}
7575
}
7676

77+
func TimeToTime(t time.Time) pgtype.Time {
78+
return pgtype.Time{Microseconds: t.UnixMicro(), Valid: true}
79+
}
80+
81+
func Int16ToInt2(i int16) pgtype.Int2 {
82+
return pgtype.Int2{Int16: i, Valid: true}
83+
}
84+
7785
func StringToText(s string) pgtype.Text {
7886
return pgtype.Text{String: s, Valid: true}
7987
}

test/main_test.go

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,29 @@ func ensureTables(conn *pgx.Conn) error {
7575
id serial primary key,
7676
title character varying(255),
7777
title_tokens tsvector
78-
);`)
78+
);
79+
drop table IF EXISTS new_types;
80+
create table new_types(
81+
id serial primary key,
82+
a_smallint smallint,
83+
a_real real,
84+
a_time time,
85+
a_xml xml,
86+
a_money money,
87+
a_char char(4),
88+
a_line line,
89+
a_lseg lseg,
90+
a_box box,
91+
a_path path,
92+
a_polygon polygon,
93+
a_circle circle,
94+
a_cidr cidr,
95+
a_inet inet,
96+
a_macaddr macaddr,
97+
a_bit bit(8),
98+
a_varbit bit varying(8)
99+
);
100+
`)
79101
if err != nil {
80102
tx.Rollback(ctx)
81103
return err

0 commit comments

Comments
 (0)