Skip to content

Commit 544e18d

Browse files
authored
Merge pull request #1463 from shantanuraj/shantanu/fix-json-buffer-reuse
Fix buffer reuse for types.JSON fields
2 parents b385498 + 7f8daf0 commit 544e18d

File tree

2 files changed

+61
-18
lines changed

2 files changed

+61
-18
lines changed

queries/reflect.go

Lines changed: 9 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -115,12 +115,12 @@ func (q *Query) BindGP(ctx context.Context, obj any) {
115115
// For custom objects that want to use eager loading, please see the
116116
// loadRelationships function.
117117
func Bind(rows *sql.Rows, obj any) error {
118-
structType, sliceType, singular, err := bindChecks(obj)
118+
structType, _, singular, err := bindChecks(obj)
119119
if err != nil {
120120
return err
121121
}
122122

123-
return bind(rows, obj, structType, sliceType, singular)
123+
return bind(rows, obj, structType, singular)
124124
}
125125

126126
// Bind executes the query and inserts the
@@ -133,7 +133,7 @@ func Bind(rows *sql.Rows, obj any) error {
133133
//
134134
// Also see documentation for Bind()
135135
func (q *Query) Bind(ctx context.Context, exec boil.Executor, obj any) error {
136-
structType, sliceType, bkind, err := bindChecks(obj)
136+
structType, _, bkind, err := bindChecks(obj)
137137
if err != nil {
138138
return err
139139
}
@@ -147,7 +147,7 @@ func (q *Query) Bind(ctx context.Context, exec boil.Executor, obj any) error {
147147
if err != nil {
148148
return errors.Wrap(err, "bind failed to execute query")
149149
}
150-
if err = bind(rows, obj, structType, sliceType, bkind); err != nil {
150+
if err = bind(rows, obj, structType, bkind); err != nil {
151151
if innerErr := rows.Close(); innerErr != nil {
152152
return errors.Wrapf(err, "error on rows.Close after bind error: %+v", innerErr)
153153
}
@@ -223,7 +223,7 @@ func bindChecks(obj any) (structType reflect.Type, sliceType reflect.Type, bkind
223223
}
224224
}
225225

226-
func bind(rows *sql.Rows, obj any, structType, sliceType reflect.Type, bkind bindKind) error {
226+
func bind(rows *sql.Rows, obj any, structType reflect.Type, bkind bindKind) error {
227227
cols, err := rows.Columns()
228228
if err != nil {
229229
return errors.Wrap(err, "bind failed to get column names")
@@ -240,11 +240,6 @@ func bind(rows *sql.Rows, obj any, structType, sliceType reflect.Type, bkind bin
240240
return err
241241
}
242242

243-
var oneStruct reflect.Value
244-
if bkind == kindSliceStruct {
245-
oneStruct = reflect.Indirect(reflect.New(structType))
246-
}
247-
248243
foundOne := false
249244
Rows:
250245
for rows.Next() {
@@ -256,14 +251,12 @@ Rows:
256251
case kindStruct:
257252
pointers = PtrsFromMapping(reflect.Indirect(reflect.ValueOf(obj)), mapping)
258253
case kindSliceStruct:
259-
pointers = PtrsFromMapping(oneStruct, mapping)
254+
newStruct = reflect.Indirect(reflect.New(structType))
255+
pointers = PtrsFromMapping(newStruct, mapping)
260256
case kindPtrSliceStruct:
261257
newStruct = makeStructPtr(structType)
262258
pointers = PtrsFromMapping(reflect.Indirect(newStruct), mapping)
263259
}
264-
if err != nil {
265-
return err
266-
}
267260

268261
if err := rows.Scan(pointers...); err != nil {
269262
return errors.Wrap(err, "failed to bind pointers to obj")
@@ -272,9 +265,7 @@ Rows:
272265
switch bkind {
273266
case kindStruct:
274267
break Rows
275-
case kindSliceStruct:
276-
ptrSlice.Set(reflect.Append(ptrSlice, oneStruct))
277-
case kindPtrSliceStruct:
268+
case kindSliceStruct, kindPtrSliceStruct:
278269
ptrSlice.Set(reflect.Append(ptrSlice, newStruct))
279270
}
280271
}
@@ -871,4 +862,4 @@ func unTitleCase(n string) string {
871862
ret := buf.String()
872863
strmangle.PutBuffer(buf)
873864
return ret
874-
}
865+
}

queries/reflect_test.go

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ import (
1414

1515
"github.com/aarondl/null/v8"
1616
"github.com/aarondl/sqlboiler/v4/drivers"
17+
"github.com/aarondl/sqlboiler/v4/types"
1718

1819
"github.com/DATA-DOG/go-sqlmock"
1920
)
@@ -181,6 +182,57 @@ func TestBindPtrSlice(t *testing.T) {
181182
}
182183
}
183184

185+
func TestBindJsonSlice(t *testing.T) {
186+
t.Parallel()
187+
188+
type siteInfoItem struct {
189+
ID int `boil:"id" json:"id" toml:"id" yaml:"id"`
190+
Fields types.JSON `boil:"test" json:"test" toml:"test" yaml:"test"`
191+
}
192+
193+
query := &Query{
194+
from: []string{"fun"},
195+
dialect: &drivers.Dialect{LQ: '"', RQ: '"', UseIndexPlaceholders: true},
196+
}
197+
198+
db, mock, err := sqlmock.New()
199+
if err != nil {
200+
t.Error(err)
201+
}
202+
203+
ret := sqlmock.NewRows([]string{"id", "test"})
204+
ret.AddRow(driver.Value(int64(35)), driver.Value(`{"foo": "bar"}`))
205+
ret.AddRow(driver.Value(int64(12)), driver.Value("{}"))
206+
mock.ExpectQuery(`SELECT \* FROM "fun";`).WillReturnRows(ret)
207+
208+
var testResults []siteInfoItem
209+
err = query.Bind(nil, db, &testResults)
210+
if err != nil {
211+
t.Error(err)
212+
}
213+
214+
if len(testResults) != 2 {
215+
t.Fatal("wrong number of results:", len(testResults))
216+
}
217+
if id := testResults[0].ID; id != 35 {
218+
t.Error("wrong ID:", id)
219+
}
220+
if name := testResults[0].Fields; name.String() != `{"foo": "bar"}` {
221+
t.Error("wrong name:", name)
222+
}
223+
224+
if id := testResults[1].ID; id != 12 {
225+
t.Error("wrong ID:", id)
226+
}
227+
if name := testResults[1].Fields; name.String() != "{}" {
228+
t.Error("wrong name:", name)
229+
}
230+
231+
if err := mock.ExpectationsWereMet(); err != nil {
232+
t.Error(err)
233+
}
234+
}
235+
184236
func testMakeMapping(byt ...byte) uint64 {
185237
var x uint64
186238
for i, b := range byt {

0 commit comments

Comments
 (0)