diff --git a/README.md b/README.md index 7141ae6..34b0eba 100644 --- a/README.md +++ b/README.md @@ -36,7 +36,9 @@ func main() { All the rules are defined in: [RULES.md](./RULES.md) -Most laraval rules are supported except for the database related rules. +Most laraval rules are supported*. + +(*database related rules can be added using the `dbrules` package and currently only support sql databases) Rules can be set using the `validate` tag on a struct field like: @@ -65,6 +67,24 @@ type UserRequest struct { } ``` +## Database rules + +Database rules are not out of the box provided as they require a database connection. + +For sql connections they can be implemented using the `dbrules` package. + +```go +func main() { + db, err := sql.Open(driverName, dns) + // Check err + + dbrules.AddRules(db) + + // Now you can add translations! + // translations.RegisterNlTranslations() +} +``` + ## More error info ```go @@ -135,6 +155,9 @@ This can be done using the `laravalidate.GoValidate` method ```go func main() { + // If you are using the db rules, + // you should add them before registering any translations! + translations.RegisterNlTranslations() input := struct { diff --git a/RULES.md b/RULES.md index 52923c9..1e31de4 100644 --- a/RULES.md +++ b/RULES.md @@ -169,6 +169,12 @@ Flags: The field under validation must end with one of the given values. +### `exists` + +[Requires dbrules to be setup!](./README.md#database-rules) + + + ### `extensions:jpg,png,...` The file under validation must have a matching extension. diff --git a/dbrules/dbrules.go b/dbrules/dbrules.go new file mode 100644 index 0000000..6c9c9f4 --- /dev/null +++ b/dbrules/dbrules.go @@ -0,0 +1,64 @@ +package dbrules + +import ( + "database/sql" + "fmt" + + . "github.com/mjarkk/laravalidate" +) + +type DB struct{ conn *sql.DB } + +func AddRules(conn *sql.DB) { + if conn == nil { + panic("DB connection cannot be nil") + } + + db := &DB{conn} + + RegisterValidator("exists", db.Exists) + + BaseRegisterMessages(map[string]MessageResolver{ + "exists": BasicMessageResolver("The selected :attribute is invalid."), + }) + + LogValidatorsWithoutMessages() +} + +func (b *DB) Exists(ctx *ValidatorCtx) (string, bool) { + if len(ctx.Args) == 0 { + return "args", false + } + + tableName := ctx.Args[0] + if tableName == "" { + return "args", false + } + + column := "id" + if len(ctx.Args) >= 2 && ctx.Args[1] != "" { + column = ctx.Args[1] + } + + ctx.UnwrapPointer() + + if !ctx.HasValue() { + return "", true + } + + row := b.conn.QueryRow( + fmt.Sprintf("SELECT %s FROM %s WHERE %s = ? LIMIT 1", column, tableName, column), + ctx.Value.Interface(), + ) + if row.Err() != nil { + return "exists", false + } + + resp := sql.RawBytes{} + err := row.Scan(&resp) + if err != nil { + return "exists", false + } + + return "", true +} diff --git a/register.go b/register.go index f789cb6..79dd914 100644 --- a/register.go +++ b/register.go @@ -85,7 +85,7 @@ func registerMessagesForLangs(langs []string, resolvers map[string]MessageResolv for name, resolver := range resolvers { validator, ok := validators[name] if !ok { - fmt.Printf(`Laravalidate: Trying to register error message for validation rule that does not exists "%s"`+"\n", name) + // fmt.Printf(`Laravalidate: Trying to register error message for validation rule that does not exists "%s"`+"\n", name) continue } for _, lang := range langs { diff --git a/rules.go b/rules.go index 77d93f4..c1f8ca3 100644 --- a/rules.go +++ b/rules.go @@ -67,8 +67,8 @@ func init() { // Exclude Unless // Exclude With // Exclude Without - // Exists (Database) + // Provided by dbrules: Exists RegisterValidator("extensions", Extensions) // File @@ -201,7 +201,7 @@ func init() { "email": BasicMessageResolver("The :attribute field must be a valid email address."), "ends_with": BasicMessageResolver("The :attribute field must end with one of the following: :args."), // "enum": BasicMessageResolver("The selected :attribute is invalid."), - // "exists": BasicMessageResolver("The selected :attribute is invalid."), + "exists": BasicMessageResolver("The selected :attribute is invalid."), "extensions": BasicMessageResolver("The :attribute field must have one of the following extensions: :args."), // "file": BasicMessageResolver("The :attribute field must be a file."), "filled": BasicMessageResolver("The :attribute field must have a value."), diff --git a/translations/de.go b/translations/de.go index 95ebab8..cfe9982 100644 --- a/translations/de.go +++ b/translations/de.go @@ -50,7 +50,7 @@ func RegisterDeTranslations() { "email": BasicMessageResolver("Das :attribute Feld muss eine gültige E-Mail-Adresse sein."), "ends_with": BasicMessageResolver("Das :attribute Feld muss mit einem der folgenden Werte enden: :args."), // "enum": BasicMessageResolver("Der ausgewählte :attribute ist ungültig."), - // "exists": BasicMessageResolver("Der ausgewählte :attribute ist ungültig."), + "exists": BasicMessageResolver("Der ausgewählte :attribute ist ungültig."), "extensions": BasicMessageResolver("Das :attribute Feld muss eine der folgenden Erweiterungen haben: :args."), // "file": BasicMessageResolver("Das :attribute Feld muss eine Datei sein."), "filled": BasicMessageResolver("Das :attribute Feld muss einen Wert haben."), diff --git a/translations/es.go b/translations/es.go index 82cc0b4..2703ee0 100644 --- a/translations/es.go +++ b/translations/es.go @@ -50,7 +50,7 @@ func RegisterEsTranslations() { "email": BasicMessageResolver("El campo :attribute debe ser una dirección de correo electrónico válida."), "ends_with": BasicMessageResolver("El campo :attribute debe terminar con uno de los siguientes: :args."), // "enum": BasicMessageResolver("El :attribute seleccionado es inválido."), - // "exists": BasicMessageResolver("El :attribute seleccionado es inválido."), + "exists": BasicMessageResolver("El :attribute seleccionado es inválido."), "extensions": BasicMessageResolver("El campo :attribute debe tener una de las siguientes extensiones: :args."), // "file": BasicMessageResolver("El campo :attribute debe ser un archivo."), "filled": BasicMessageResolver("El campo :attribute debe tener un valor."), diff --git a/translations/fr.go b/translations/fr.go index aa85780..f2e765b 100644 --- a/translations/fr.go +++ b/translations/fr.go @@ -50,7 +50,7 @@ func RegisterFrTranslations() { "email": BasicMessageResolver("Le champ :attribute doit être une adresse e-mail valide."), "ends_with": BasicMessageResolver("Le champ :attribute doit se terminer par l'un des éléments suivants : :args."), // "enum": BasicMessageResolver("Le :attribute sélectionné est non valide."), - // "exists": BasicMessageResolver("Le :attribute sélectionné est non valide."), + "exists": BasicMessageResolver("Le :attribute sélectionné est non valide."), "extensions": BasicMessageResolver("Le champ :attribute doit avoir l'une des extensions suivantes : :args."), // "file": BasicMessageResolver("Le champ :attribute doit être un fichier."), "filled": BasicMessageResolver("Le champ :attribute doit avoir une valeur."), diff --git a/translations/nl.go b/translations/nl.go index eb6b576..38c5dfc 100644 --- a/translations/nl.go +++ b/translations/nl.go @@ -50,7 +50,7 @@ func RegisterNlTranslations() { "email": BasicMessageResolver("Het :attribute veld moet een geldig e-mailadres zijn."), "ends_with": BasicMessageResolver("Het :attribute veld moet eindigen met een van de volgende: :args."), // "enum": BasicMessageResolver("De geselecteerde :attribute is ongeldig."), - // "exists": BasicMessageResolver("De geselecteerde :attribute is ongeldig."), + "exists": BasicMessageResolver("De geselecteerde :attribute is ongeldig."), "extensions": BasicMessageResolver("Het :attribute veld moet een van de volgende extensies hebben: :args."), // "file": BasicMessageResolver("Het :attribute veld moet een bestand zijn."), "filled": BasicMessageResolver("Het :attribute veld moet een waarde hebben."),