Skip to content

Instantly share code, notes, and snippets.

@lorenzorapetti
Created February 18, 2018 16:57
Show Gist options
  • Star 4 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save lorenzorapetti/38cab778eef588c3128c05a18a65e789 to your computer and use it in GitHub Desktop.
Save lorenzorapetti/38cab778eef588c3128c05a18a65e789 to your computer and use it in GitHub Desktop.
Custom validation in objection.js
const { Model, AjvValidator } = require('objection');
const pluralize = require('pluralize');
class BaseModel extends Model {
/**
* Always use timestamps as default
*/
static get timestamps() {
return true;
}
/**
* Use the lower case, plural model class name
* as the table name
*/
static get tableName() {
return pluralize(this.name.toLowerCase());
}
/**
* Set this directory as the model path so
* they can get automatically imported in
* `relationMappings` without circular dependencies
*/
static get modelPaths() {
return [__dirname];
}
/**
* Override this to true whenever you want to
* use `$customValidate` over `$validate`
*
* @returns {Boolean}
*/
static get hasToCustomValidate() {
return false;
}
/**
* Return an array of the required fields to validate.
*
* @param {object} queryContext The context of the query. See http://vincit.github.io/objection.js/#context
* @param {object} opts Options. Can be accessed to check if the query that is being
* executed is an insert or an update query
*/
// eslint-disable-next-line no-unused-vars
static requiredFields(queryContext, opts) {
return [];
}
/**
* Create a custom validator, because we need
* the $data feature, see https://github.com/epoberezkin/ajv#data-reference
*/
static createValidator() {
return new AjvValidator({
onCreateAjv: () => {},
options: {
$data: true,
allErrors: true,
validateSchema: false,
ownProperties: true,
v5: true,
coerceTypes: true,
removeAdditional: true,
},
});
}
/**
* Validates the model with a custom schema.
* This is used over `$validate` whenever we want to
* validate different attributes based on whether the model
* is being created or updated
*/
$customValidate(queryContext, opts) {
const { jsonSchema } = this.constructor;
jsonSchema.required = this.constructor.requiredFields(queryContext, opts);
const validator = this.constructor.getValidator();
const args = {
json: this.$toJson(),
model: this,
options: { mutable: true },
ctx: { jsonSchema },
};
validator.validate(args);
}
/**
* Override with the ability to perform custom validation on
* an insert operation
*/
$beforeInsert(queryContext) {
if (this.constructor.hasToCustomValidate) {
this.$customValidate(queryContext, {
isInsert: true,
});
}
}
/**
* Override with the ability to perform custom validation on
* an update operation
*/
$beforeUpdate(opts, queryContext) {
if (this.constructor.hasToCustomValidate && !opts.skipValidation) {
this.$customValidate(queryContext, {
isUpdate: true,
});
}
}
}
module.exports = BaseModel;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment