diff --git a/CHANGELOG.md b/CHANGELOG.md index e5f3acbd..d9f1c0ee 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,8 +1,11 @@ -## (WIP) +## v0.23.2 (WIP) + +- Fixed `RecordQuery()` custom struct scanning ([#5958](https://github.com/pocketbase/pocketbase/discussions/5958)). - Added support for passing more than one id in the `Hook.Unbind` method for consistency with the router. + ## v0.23.1 - Added `RequestEvent.Blob(status, contentType, bytes)` response write helper ([#5940](https://github.com/pocketbase/pocketbase/discussions/5940)). diff --git a/core/record_query.go b/core/record_query.go index 9f640df3..8f20d8ee 100644 --- a/core/record_query.go +++ b/core/record_query.go @@ -102,11 +102,6 @@ func (app *BaseApp) RecordQuery(collectionModelOrIdentifier any) *dbx.SelectQuer return nil default: // expects []RecordProxy slice - records, err := resolveRecordAllHook(collection, op) - if err != nil { - return err - } - rv := reflect.ValueOf(v) if rv.Kind() != reflect.Ptr || rv.IsNil() { return errors.New("must be a pointer") @@ -118,11 +113,6 @@ func (app *BaseApp) RecordQuery(collectionModelOrIdentifier any) *dbx.SelectQuer return errors.New("must be a slice of RecordSetters") } - // create an empty slice - if rv.IsNil() { - rv.Set(reflect.MakeSlice(rv.Type(), 0, len(records))) - } - et := rv.Type().Elem() var isSliceOfPointers bool @@ -135,6 +125,16 @@ func (app *BaseApp) RecordQuery(collectionModelOrIdentifier any) *dbx.SelectQuer return op(sliceA) } + records, err := resolveRecordAllHook(collection, op) + if err != nil { + return err + } + + // create an empty slice + if rv.IsNil() { + rv.Set(reflect.MakeSlice(rv.Type(), 0, len(records))) + } + for _, record := range records { ev := reflect.New(et) diff --git a/core/record_query_test.go b/core/record_query_test.go index 85a8824d..479a79ab 100644 --- a/core/record_query_test.go +++ b/core/record_query_test.go @@ -66,7 +66,7 @@ func TestRecordQueryOne(t *testing.T) { name string collection string recordId string - model core.Model + model any }{ { "record model", @@ -82,6 +82,14 @@ func TestRecordQueryOne(t *testing.T) { core.BaseRecordProxy }{}, }, + { + "custom struct", + "demo1", + "84nmscqy84lsi1t", + &struct { + Id string `db:"id" json:"id"` + }{}, + }, } for _, s := range scenarios { @@ -98,8 +106,14 @@ func TestRecordQueryOne(t *testing.T) { t.Fatal(err) } - if s.model.PK() != s.recordId { - t.Fatalf("Expected record with id %q, got %q", s.recordId, s.model.PK()) + raw, err := json.Marshal(s.model) + if err != nil { + t.Fatal(err) + } + rawStr := string(raw) + + if !strings.Contains(rawStr, fmt.Sprintf(`"id":%q`, s.recordId)) { + t.Fatalf("Missing id %q in\n%s", s.recordId, rawStr) } }) } @@ -111,6 +125,10 @@ func TestRecordQueryAll(t *testing.T) { app, _ := tests.NewTestApp() defer app.Cleanup() + type customStructs struct { + Id string `db:"id" json:"id"` + } + type mockRecordProxy struct { core.BaseRecordProxy } @@ -145,6 +163,18 @@ func TestRecordQueryAll(t *testing.T) { []any{"84nmscqy84lsi1t", "al1h9ijdeojtsjy"}, &[]mockRecordProxy{}, }, + { + "slice of custom structs", + "demo1", + []any{"84nmscqy84lsi1t", "al1h9ijdeojtsjy"}, + &[]customStructs{}, + }, + { + "slice of pointer custom structs", + "demo1", + []any{"84nmscqy84lsi1t", "al1h9ijdeojtsjy"}, + &[]customStructs{}, + }, } for _, s := range scenarios {