The charger list sorted by a field the collection never had
Opening Home chargers answered {"status":400,"message":"Something went wrong
while processing your request."} — PocketBase's generic refusal, here for an
unknown sort field. home_chargers declares its own fields and nothing else:
PocketBase adds no created field to a collection defined through the API, which
is exactly why control_audit and organizations declare theirs. The list handler
sorted by created anyway. It was the only handler in the server that sorts by
created — every other one sorts by name, km or date, fields their collections
actually declare — so the gap had never had a chance to show.
The field is now declared, and reconcile adds it to the collection already
standing on the next boot, since home_chargers is in reconcileOrder. Import order
is the only order a charger has: it carries no date of its own, and a wallbox
bolted to a wall does not accumulate events the way a car does.
The list also stops depending on that. A rejected sort now falls back to the
unsorted query rather than failing the request: the order is a nicety, the list
is not, and an owner reading a database error about a field they cannot see is
the worst of both. It also makes the deploy order stop mattering — the page works
before the bootstrap has run, and the sorted query wins once it has.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 5
parent
06f91578da
commit
423bc2ab16
@@ -79,11 +79,25 @@ func (s *Server) listHomeChargers(w http.ResponseWriter, r *http.Request) {
|
|||||||
writeError(w, http.StatusUnauthorized, "not authenticated")
|
writeError(w, http.StatusUnauthorized, "not authenticated")
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
res, err := s.pb.List(r.Context(), colHomeChargers, url.Values{
|
query := func(sort string) url.Values {
|
||||||
"filter": {fmt.Sprintf("owner='%s'", me)},
|
q := url.Values{
|
||||||
"sort": {"created"},
|
"filter": {fmt.Sprintf("owner='%s'", me)},
|
||||||
"perPage": {"200"},
|
"perPage": {"200"},
|
||||||
})
|
}
|
||||||
|
if sort != "" {
|
||||||
|
q.Set("sort", sort)
|
||||||
|
}
|
||||||
|
return q
|
||||||
|
}
|
||||||
|
res, err := s.pb.List(r.Context(), colHomeChargers, query("created"))
|
||||||
|
if err != nil {
|
||||||
|
// A collection created before `created` was declared does not have the
|
||||||
|
// field, and PocketBase rejects the whole query over an unknown sort. The
|
||||||
|
// order is a nicety; the list is not, so ask again without it rather than
|
||||||
|
// show the owner an error about a field they cannot see. The bootstrap
|
||||||
|
// adds the field on the next boot, and the sorted query then wins.
|
||||||
|
res, err = s.pb.List(r.Context(), colHomeChargers, query(""))
|
||||||
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
writePBError(w, err)
|
writePBError(w, err)
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -219,6 +219,11 @@ var collectionsSchema = map[string][]fieldDef{
|
|||||||
// Owner. Non-cascading, like a car's: deleting a user must not silently
|
// Owner. Non-cascading, like a car's: deleting a user must not silently
|
||||||
// wipe the records they own.
|
// wipe the records they own.
|
||||||
fRelation("owner", "users", false, false),
|
fRelation("owner", "users", false, false),
|
||||||
|
// A charger carries no date of its own, so the import order is the only
|
||||||
|
// order there is to list them in. PocketBase adds no created field to a
|
||||||
|
// collection defined through the API, so it is declared here like the
|
||||||
|
// audit trail's.
|
||||||
|
fAutodate("created", true, false),
|
||||||
},
|
},
|
||||||
// Custom fields layered onto the built-in "users" auth collection.
|
// Custom fields layered onto the built-in "users" auth collection.
|
||||||
"users": {
|
"users": {
|
||||||
|
|||||||
@@ -457,6 +457,10 @@ const DESIRED = {
|
|||||||
F.text("provider_charger_id"),
|
F.text("provider_charger_id"),
|
||||||
// Owner. Non-cascading, like a car's: deleting a user must not wipe their records.
|
// Owner. Non-cascading, like a car's: deleting a user must not wipe their records.
|
||||||
F.relation("owner", "users", false, false),
|
F.relation("owner", "users", false, false),
|
||||||
|
// A charger carries no date of its own, so the import order is the only order
|
||||||
|
// there is to list them in. PocketBase adds no created field to a collection
|
||||||
|
// defined through the API, so it is declared here like the audit trail's.
|
||||||
|
F.autodate("created", true, false),
|
||||||
],
|
],
|
||||||
// Server-wide settings as a single record, keyed "global". Today it holds
|
// Server-wide settings as a single record, keyed "global". Today it holds
|
||||||
// pluginSettings: the top (L1) layer of the integration cascade — every
|
// pluginSettings: the top (L1) layer of the integration cascade — every
|
||||||
|
|||||||
Reference in New Issue
Block a user