0

I have a class of validations that I have created in JS:

let test = new Validator(req.body);

Now I want to test something, maybe that a specific key in this object is 2-5 char length, I would do it like this:

let myBoolean = test.selector("firstName").minLength(2).maxLength(5);
// firstName is like: req.body.firstName

And how this could be done in the class?

EDIT

I made something like this:

audit.isLength({selector: "from", gte: 2, lte: 35})

class Validator {

  constructor(obj) {
    this.obj = obj;
    this.isValid = true;
  }

  isExists(sel) {
    if (typeof this.obj[sel] === "undefined") return false;
    return true;
  }

  isLength(info) {
    let sel = this.obj[info.selector];
    if (typeof sel === "undefined") return false;
    if (info.gte) {
      if (sel.length<info.gte) return false;
    }
    if (info.lte) {
      if (sel.length>info.lte) return false;
    }
    if (info.gt) {
      if (sel.length<=info.gt) return false;
    }
    if (info.lt) {
      if (sel.length>=info.lt) return false;
    }
    return true;
  }
}
Raz Buchnik
  • 7,753
  • 14
  • 53
  • 96
  • 2
    Your `selector` method needs to return *something* that has a `minLength` method that in turn returns *something* that has a `maxLength` method. It doesn't matter at all whether `selector` is part of a `class` or not. – Bergi Jul 31 '18 at 20:14
  • 2
    Note that your proposed api won’t work - presumably, minlength should also return boolean? But it can’t since it should also return sth on which you can call maxlength. You will need a terminating call that returns the final result. Befor you reinvent the wheel, you may want to look at something like https://github.com/rjperes/FluentValidationJS if only to get some inspiration – flq Jul 31 '18 at 20:20

3 Answers3

2

Create a class with fluent methods/chainable methods, that return this, which is an instance of the class itself and when you finally run validation according to the rules, call .validate(), which will act as a final method to return the result:

class Validator {
  constructor (body) {
    this._body = body;
  }
  
  selector(str) {
    this._selector = str;
    return this;
  }
  
  minLength(num) {
    this._minLength = num;
    return this;
  }
  
  maxLength(num) {
    this._maxLength = num;
    return this;
  }
  
  validate() {
    // run your validation logic here and return true or false accordingly
    return true
  }
}

const req = { body: 'body' };
const test = new Validator(req.body);
const myBoolean = test
  .selector('firstName')
  .minLength(2)
  .maxLength(5)
  .validate();
  
console.log('rules:');
console.log(test);
console.log(`result: ${myBoolean}`);
Rick
  • 4,030
  • 9
  • 24
  • 35
2

Try something like this - assign the object to validate to a property on the instantiation, return this from each validating call, and when validating, assign to an isValid property on the object (if it isn't already false). Note that you need to access the isValid property finally in order to retrieve the boolean.

class Validator {
  constructor(obj) {
    this.obj = obj;
    this.isValid = true;
  }
  selector(sel) {
    this.sel = sel;
    return this;
  }
  minLength(min) {
    if (this.isValid) this.isValid = this.obj[this.sel].length >= min;
    return this;
  }
  maxLength(max) {
    if (this.isValid) this.isValid = this.obj[this.sel].length <= max;
    return this;
  }
}

const test = new Validator({firstName: 'foobar'}); // 6 chars: invalid
console.log(test.selector("firstName").minLength(2).maxLength(5).isValid);
const test2 = new Validator({firstName: 'fooba'}); // 5 chars: valid
console.log(test2.selector("firstName").minLength(2).maxLength(5).isValid);
const test3 = new Validator({firstName: 'f'}); // 1 char: invalid
console.log(test3.selector("firstName").minLength(2).maxLength(5).isValid);
CertainPerformance
  • 356,069
  • 52
  • 309
  • 320
  • 1
    I guess this is one of the few cases where `this.isValid = this.isValid && …;` could be cleaner than `if (this.isValid) this.isValid = …;` :-) – Bergi Jul 31 '18 at 20:38
  • What about undefined in the selector? – Raz Buchnik Jul 31 '18 at 21:00
  • 1
    @Raz You might set the `isValid` property to `false` in the constructor if the `obj` doesn't exist, or when `selector` is called and `this.obj[sel]` doesn't exist (or isn't a string, whatever you need) – CertainPerformance Jul 31 '18 at 21:17
  • And what happen if the selector is: "when.date.start" ? The this.obj[this.sel] will be undefined anyway, isnt it? – Raz Buchnik Aug 01 '18 at 06:03
  • See [this question](https://stackoverflow.com/questions/2631001/test-for-existence-of-nested-javascript-object-key) if you're worried about the That (usually) wouldn't be a sane property name to exist on an object, because it's very confusing given the dot operator. But, like I said, you can test for the existence of a key when `selector` is called, and set `isValid` appropriately. – CertainPerformance Aug 01 '18 at 06:19
0

This is the builder pattern (sort of). You'll probably want to define a separate class that has a minLength and maxLength function. Those functions will set some state on the builder, and return either this (the builder its self), or a new builder that's a copy of this. Then you'd have some finalize function on the builder, which looks at the state, handles all the logic based on the min/max, and returns a boolean.

Sava B.
  • 1,007
  • 1
  • 10
  • 21