1602 / 1602/jugglingdb

Streamline validations

Offen
#362 10 Kommentare 0 Reaktionen 0 zugewiesene Personen Auf GitHub ansehen
in progress
Vorherrschende Sprache
JavaScript
Sterne
2k
Forks
238
PR-Merge-Kennzahlen
Keine gemergten PRs in 30 T.

Beschreibung

### 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

Beitragsleitfaden

Für dieses Repository ist kein Beitragsleitfaden indexiert

Rechercherichtung

Das Issue schlägt eine umfassende Überarbeitung des Validierungssystems in jugglingdb vor. Beginnen Sie mit der Untersuchung der bestehenden Validierungsmethoden im Codebase, wahrscheinlich in Dateien wie lib/validations.js oder ähnlichen. Verstehen Sie, wie aktuelle Validatoren wie validatesPresenceOf implementiert sind. Das Ziel ist es, eine neue Validierungs-API zu entwerfen, die ein deklaratives Format, benutzerdefinierte Validatoren und Internationalisierung unterstützt. Dies erfordert tiefgehende Kenntnisse der Architektur des ORM und beinhaltet wahrscheinlich Änderungen in mehreren Dateien.

Vom Indexierungsmodell aus dem Issue-Text verfasst.

Bewertung

Tech-Stack
javascript, nodejs
Bereich
api, backend, databases
Issue-Typ
Feature
Schwierigkeit
5/5
Geschätzter Aufwand
Über eine Woche
Aktivitätsstatus
Veraltet
Klarheit
Größtenteils klar
Anfängerfreundlichkeit
25/100

Neue Issues direkt in Ihr Postfach

Eine kurze Übersicht über anfängerfreundliche GitHub-Issues.