1602 / 1602/jugglingdb

Streamline validations

Aperta
#362 10 commenti 0 reazioni 0 assegnatari Vedi su GitHub
in progress
Lingua principale
JavaScript
Stelle
2k
Fork
238
Metriche di merge delle PR
Nessuna PR unita negli ultimi 30g

Descrizione

### Rationale

The first thing I noticed when reading the documentation (I'm actually evaluating this project as a suitable ORM for our own project) was the hard-coded base validators and it's lack of flexibility. Reading the issues, I see many tickets on the subject.

Having a non-negligible Zend Framework background, the way validators are handled has inspired many other projects, as it allows effortless flexibility and extensibility. An other such project is [Backbone.Validation](https://github.com/thedersen/backbone.validation).
### Suggestion

So, instead of

```
// Setup validations
User.validatesPresenceOf('name', 'email')
User.validatesLengthOf('password', {min: 5, message: {min: 'Password is too short'}});
User.validatesInclusionOf('gender', {in: ['male', 'female']});
User.validatesExclusionOf('domain', {in: ['www', 'billing', 'admin']});
User.validatesNumericalityOf('age', {int: true});
User.validatesUniquenessOf('email', {message: 'email is not unique'});
```

I would have something like

```
User.validation({
name: {
required: true // true or string, ex: "Name is not specified!"
},
email: {
required: "Email is not specified!" // or true
, unique: "Email is not unique!"
},
password: {
minLength: { min: 5, message: "Password must contain between 5 and 16 caracters" }
, maxLength: { max: 16, message: "Password must contain between 5 and 16 caracters" }
},
gender: {
in: { values: ["male", "femaile"], ignoreCase: true /*, message: .... */ }
},
domaine: {
notIn: ['www', 'billing', 'admin']
},
age: {
integer: true
, min: { value: 18, message: "You must be of legal age!" }
}
});
```

Then, adding new validators could be done like

```
var Schema = require('jugglingdb').Schema;

// signature : add(name, callback, async)
// - name String the validator's name
// - callback Function the validation function :
// - model Object the model instance
// - fieldName String the model field to validate
// - options Object the options configuration
// - callback Function the async callback (optional)
// returns true for success
// returns false or a string (error message) on failure
// - async Boolean if the validation function is async or not (optional) (default false)
Schema.Validation.add("foo", function (model, fieldName, options) {
/* ... */
return true;
});

// async validation must pass a fourth parameter 'cb'
Schema.Validation.add("bar", function (model, fieldName, options, cb) {
setTimeout(function() {
cb(true);
}, 1000);
}, true);

// to use generators, simply provide the async flag and omit the fourth parameter 'cb'
Schema.Validation.add("buz", function * (model, fieldName, options) {
var asyncResult = yield someAsyncCall(model[fieldName], options);
/* ... */
return true;
}, true);

// using each custom validators (the third parameter 'options' will be "true")
User.validation({
name: {
foo: true,
bar: true,
buz: true
}
};
```
### Internationalisation

All error messages should support a `sprintf`-like syntax. With Node, this is supported via the [`util.format`](http://nodejs.org/docs/latest/api/util.html#util_util_format_format) function. The default fallback message on failed validation (if the validation function returns `false`) could be `"'%s' validation failed!"`, which will be formatted with the validated `fieldName`.

To enable translation of these messages, simply provide a function to

```
Schema.Validation.translator(function(message) {
return message; // translated
});
```

Obviously, since all (failed) validation messages are formatted inside the validator functions, before being returned, the translations should also be performed before formatting the message. Therefore, and since we already have a reference to `Schema.Validation`, I would propose

```
var format = require('util').format;
Schema.Validation.add("foo", function (model, fieldName, options) {
return format(Schema.Validation.translate("Foo failed for '%s'!"), fieldName);
});
```
### Integration and Backward compatibility

To support existing projects, all current implementations could remain unchanged and simply proxying to the new validation system, to be deprecated at the next minor release (version 0.3). Thus, the built-in current validators could still be shipped with the ORM, along with new ones provided by the community.
#### `validatesPresenceOf` becomes `required`
##### Options

```
{
message: (defaults to "Field %s is required.")
}
```

The model field must be specified, with any given value.
#### `validatesLengthOf` becomes `minLength` and `maxLength`
##### Options

```
{
min: (defaults to 3)
, max: (defaults to 255)
, message: (defaults to "Field '%s' must contain more|less than %d character(s)")
}
```

For strings, check it's `length` property. Ignored for any other type.
#### `validatesInclusionOf` becomes `in`
##### Options

```
{
values:
, strictCompare: (defaults true)
, ignoreCase: (defaults false)
, message: (defaults to "Invalid field value '%s'")
}
```

The `values` array items' type should be compatible with the model's field type.
#### `validatesExclusionOf` becomes `notIn`
##### Options

```
{
values:
, strictCompare:
, ignoreCase: (defaults false)
, message: (defaults to "Invalid field value '%s'")
}
```

The `values` array items' type should be compatible with the model's field type.
#### `validatesNumericalityOf` becomes `number`, `integer`, `decimal`, or `finite`
##### Options

```
{
message: (defaults to "Invalid numeric value '%s'")
}
```

For `number`, the value must be _any_ numeric value.
For `integer`, the value must be an integer value.
For `decimal`, the value must _not_ be an integer value.
For `finite`, the value must be _finite_.
#### `validatesUniquenessOf` becomes `unique`
##### Options

```
{
message: (defaults to "%s must be unique.")
}
```

This validator checks in all the set for another model with the same field value. This validator is asynchronous.
### Other proposed validations

From the [sails.js](http://sailsjs.org/#!documentation/models) framework.
- empty
- notEmpty
- undefined
- string
- alpha
- alphanumeric
- email
- url
- urlish
- ip
- ipv4
- ipv6
- creditcard
- uuid
- uuidv3
- uuidv4
- falsey
- truthy
- null
- notNull
- boolean
- array
- date
- hexadecimal
- hexColor
- lowercase
- uppercase
- after
- before
- is
- regex
- not
- notRegex
- equals
- contains
- notContains
- len
- max
- min

Guida per i contributori

Nessuna guida per i contributori indicizzata per questo repository

Direzione di ricerca

L'issue propone una revisione importante del sistema di validazione in jugglingdb. Inizia esaminando i metodi di validazione esistenti nella codebase, probabilmente in file come lib/validations.js o simili. Comprendi come sono implementati i validatori attuali come validatesPresenceOf. L'obiettivo è progettare una nuova API di validazione che supporti un formato dichiarativo, validatori personalizzati e l'internazionalizzazione. Ciò richiede una profonda familiarità con l'architettura dell'ORM e probabilmente comporta modifiche in più file.

Scritto dal modello di indicizzazione a partire dal testo della issue.

Valutazione

Stack tecnologico
javascript, nodejs
Ambito
api, backend, databases
Tipo di issue
Funzionalità
Difficoltà
5/5
Tempo stimato
Più di una settimana
Stato di attività
Ferma
Chiarezza
Abbastanza chiara
Idoneità per principianti
25/100

Ricevi le nuove issue nella tua casella

Un breve riepilogo di issue GitHub adatte ai principianti.