[#7538] set OnlyInt:true when a view column expression is loosely known to return int-only values

This commit is contained in:
Gani Georgiev
2026-02-22 11:06:08 +02:00
parent ab0edb80df
commit eb28f898d0
3 changed files with 80 additions and 3 deletions

View File

@@ -1,3 +1,8 @@
## v0.36.6 (WIP)
- Set `NumberField.OnlyInt:true` for the generated View collection schema fields when a view column expression is known to return int-only values ([#7538](https://github.com/pocketbase/pocketbase/issues/7538)).
## v0.36.5 ## v0.36.5
- Disabled collection and fields name normalization while in IME mode ([#7532](https://github.com/pocketbase/pocketbase/pull/7532); thanks @miaopan607). - Disabled collection and fields name normalization while in IME mode ([#7532](https://github.com/pocketbase/pocketbase/pull/7532); thanks @miaopan607).

View File

@@ -257,7 +257,16 @@ func parseQueryToFields(app App, selectQuery string) (map[string]*queryField, er
} }
// numeric aggregations // numeric aggregations
if strings.HasPrefix(colLower, "count(") || strings.HasPrefix(colLower, "total(") { if strings.HasPrefix(colLower, "count(") {
result[col.alias] = &queryField{
field: &NumberField{
Name: col.alias,
OnlyInt: true,
},
}
continue
}
if strings.HasPrefix(colLower, "total(") {
result[col.alias] = &queryField{ result[col.alias] = &queryField{
field: &NumberField{ field: &NumberField{
Name: col.alias, Name: col.alias,
@@ -268,16 +277,24 @@ func parseQueryToFields(app App, selectQuery string) (map[string]*queryField, er
castMatch := castRegex.FindStringSubmatch(colLower) castMatch := castRegex.FindStringSubmatch(colLower)
// numeric casts // casts
if len(castMatch) == 2 { if len(castMatch) == 2 {
switch castMatch[1] { switch castMatch[1] {
case "real", "integer", "int", "decimal", "numeric": case "real", "decimal", "numeric":
result[col.alias] = &queryField{ result[col.alias] = &queryField{
field: &NumberField{ field: &NumberField{
Name: col.alias, Name: col.alias,
}, },
} }
continue continue
case "int", "integer":
result[col.alias] = &queryField{
field: &NumberField{
Name: col.alias,
OnlyInt: true,
},
}
continue
case "text": case "text":
result[col.alias] = &queryField{ result[col.alias] = &queryField{
field: &TextField{ field: &TextField{

View File

@@ -545,6 +545,61 @@ func TestCreateViewFields(t *testing.T) {
ensureNoTempViews(app, t) ensureNoTempViews(app, t)
} }
func TestCreateViewFieldsWithNumberOnlyInt(t *testing.T) {
t.Parallel()
app, _ := tests.NewTestApp()
defer app.Cleanup()
sql := `select
a.id,
count(a.id) count,
total(a.id) total,
cast(a.id as int) cast_int,
cast(a.id as integer) cast_integer,
cast(a.id as real) cast_real,
cast(a.id as decimal) cast_decimal,
cast(a.id as numeric) cast_numeric
from demo1 a`
result, err := app.CreateViewFields(sql)
if err != nil {
t.Fatal(err)
}
onlyInts := map[string]bool{
"count": true,
"total": false,
"cast_int": true,
"cast_integer": true,
"cast_real": false,
"cast_decimal": false,
"cast_numeric": false,
}
totalExpected := len(onlyInts) + 1
if total := len(result); total != totalExpected {
t.Fatalf("Expected %d, got %d", totalExpected, total)
}
for _, f := range result {
if f.GetName() == "id" {
continue
}
t.Run(f.GetName(), func(t *testing.T) {
nf, ok := f.(*core.NumberField)
if !ok {
t.Fatalf("Expected *core.NumberField, got %v", f)
}
if nf.OnlyInt != onlyInts[nf.Name] {
t.Fatalf("Expected OnlyInt %v, got %v", onlyInts[nf.Name], nf.OnlyInt)
}
})
}
}
func TestFindRecordByViewFile(t *testing.T) { func TestFindRecordByViewFile(t *testing.T) {
t.Parallel() t.Parallel()