1
0
mirror of https://github.com/pocketbase/pocketbase.git synced 2025-03-19 14:17:48 +02:00

79 lines
1.9 KiB
Go
Raw Normal View History

2024-09-29 19:23:19 +03:00
package validators
import (
"database/sql"
"errors"
"strings"
validation "github.com/go-ozzo/ozzo-validation/v4"
"github.com/pocketbase/dbx"
)
// UniqueId checks whether a field string id already exists in the specified table.
//
// Example:
//
// validation.Field(&form.RelId, validation.By(validators.UniqueId(form.app.DB(), "tbl_example"))
func UniqueId(db dbx.Builder, tableName string) validation.RuleFunc {
return func(value any) error {
v, _ := value.(string)
if v == "" {
return nil // nothing to check
}
var foundId string
err := db.
Select("id").
From(tableName).
Where(dbx.HashExp{"id": v}).
Limit(1).
Row(&foundId)
if (err != nil && !errors.Is(err, sql.ErrNoRows)) || foundId != "" {
return validation.NewError("validation_invalid_or_existing_id", "The model id is invalid or already exists.")
}
return nil
}
}
// NormalizeUniqueIndexError attempts to convert a
// "unique constraint failed" error into a validation.Errors.
//
// The provided err is returned as it is without changes if:
// - err is nil
// - err is already validation.Errors
// - err is not "unique constraint failed" error
func NormalizeUniqueIndexError(err error, tableOrAlias string, fieldNames []string) error {
if err == nil {
return err
}
//
if _, ok := err.(validation.Errors); ok {
return err
}
msg := strings.ToLower(err.Error())
// check for unique constraint failure
if strings.Contains(msg, "unique constraint failed") {
normalizedErrs := validation.Errors{}
msg = strings.ReplaceAll(strings.TrimSpace(msg), ",", " ")
for _, name := range fieldNames {
// blank space to unify multi-columns lookup
if strings.Contains(msg+" ", strings.ToLower(tableOrAlias+"."+name)) {
normalizedErrs[name] = validation.NewError("validation_not_unique", "Value must be unique")
}
}
if len(normalizedErrs) > 0 {
return normalizedErrs
}
}
return err
}