Skip to content

Commit

Permalink
feat(core, build): implement getConstraints for all built-in validator
Browse files Browse the repository at this point in the history
  • Loading branch information
oscar60310 committed Oct 6, 2022
1 parent 8864af6 commit be6f6c5
Show file tree
Hide file tree
Showing 13 changed files with 241 additions and 40 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ import {
VulcanInternalExtension,
DocumentSpec,
ConfigurationError,
TypeConstraint,
} from '@vulcan-sql/core';
import { isEmpty } from 'lodash';

Expand Down Expand Up @@ -121,8 +122,10 @@ export class OAS3SpecGenerator extends SpecGenerator<oas3.OpenAPIObject> {
for (const constraint of parameter.constraints) {
if (constraint instanceof MinValueConstraint) {
schema.minimum = constraint.getMinValue();
schema.exclusiveMinimum = constraint.isExclusive();
} else if (constraint instanceof MaxValueConstraint) {
schema.maximum = constraint.getMaxValue();
schema.exclusiveMaximum = constraint.isExclusive();
} else if (constraint instanceof MinLengthConstraint) {
schema.minLength = constraint.getMinLength();
} else if (constraint instanceof MaxLengthConstraint) {
Expand All @@ -131,6 +134,8 @@ export class OAS3SpecGenerator extends SpecGenerator<oas3.OpenAPIObject> {
schema.pattern = constraint.getRegex();
} else if (constraint instanceof EnumConstraint) {
schema.enum = constraint.getList();
} else if (constraint instanceof TypeConstraint) {
schema.type = constraint.getType();
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
VulcanInternalExtension,
} from '@vulcan-sql/core/models';
import { ConfigurationError, UserError } from '../../utils/errors';
import { Constraint } from '../constraints';

// Support custom date format -> dayjs.format(...)
dayjs.extend(customParseFormat);
Expand Down Expand Up @@ -49,4 +50,9 @@ export class DateTypeValidator extends InputValidator {
'The input parameter is invalid, it should be date type'
);
}

public override getConstraints() {
const constraints: Constraint[] = [Constraint.Type('string')];
return constraints;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import * as Joi from 'joi';
import { isUndefined } from 'lodash';
import { ConfigurationError, UserError } from '../../utils/errors';
import { Constraint } from '../constraints';

export interface IntInputArgs {
// The integer minimum value
Expand Down Expand Up @@ -62,4 +63,13 @@ export class IntegerTypeValidator extends InputValidator {
);
}
}

public override getConstraints(args: IntInputArgs) {
const constraints: Constraint[] = [Constraint.Type('integer')];
if (args.min) constraints.push(Constraint.MinValue(args.min, false));
if (args.max) constraints.push(Constraint.MaxValue(args.max, false));
if (args.greater) constraints.push(Constraint.MinValue(args.greater, true));
if (args.less) constraints.push(Constraint.MaxValue(args.less, true));
return constraints;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import {
} from '@vulcan-sql/core/models';
import * as Joi from 'joi';
import { ConfigurationError, UserError } from '../../utils/errors';
import { Constraint } from '../constraints';

export interface RequiredInputArgs {
/**
Expand Down Expand Up @@ -52,4 +53,8 @@ export class RequiredValidator extends InputValidator {
);
}
}

public override getConstraints() {
return [Constraint.Required()];
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import {
import * as Joi from 'joi';
import { isUndefined } from 'lodash';
import { ConfigurationError, UserError } from '../../utils/errors';
import { Constraint } from '../constraints';
export interface StringInputArgs {
// The string regex format pattern
format?: string;
Expand Down Expand Up @@ -61,4 +62,16 @@ export class StringTypeValidator extends InputValidator {
);
}
}

public override getConstraints(args: StringInputArgs) {
const constraints: Constraint[] = [Constraint.Type('string')];
if (args.min) constraints.push(Constraint.MinLength(args.min));
if (args.max) constraints.push(Constraint.MaxLength(args.max));
if (args.length) {
constraints.push(Constraint.MinLength(args.length));
constraints.push(Constraint.MaxLength(args.length));
}
if (args.format) constraints.push(Constraint.Regex(args.format));
return constraints;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import * as Joi from 'joi';
import { GuidVersions } from 'joi';
import { isUndefined } from 'lodash';
import { ConfigurationError, UserError } from '../../utils/errors';
import { Constraint } from '../constraints';

type UUIDVersion = 'uuid_v1' | 'uuid_v4' | 'uuid_v5';

Expand Down Expand Up @@ -57,4 +58,9 @@ export class UUIDTypeValidator extends InputValidator {
);
}
}

public override getConstraints() {
const constraints: Constraint[] = [Constraint.Type('string')];
return constraints;
}
}
76 changes: 63 additions & 13 deletions packages/core/src/lib/validators/constraints.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,12 @@ export abstract class Constraint {
return new RequiredConstraint();
}

static MinValue(minValue: number) {
return new MinValueConstraint(minValue);
static MinValue(minValue: number, exclusive?: boolean) {
return new MinValueConstraint(minValue, exclusive);
}

static MaxValue(maxValue: number) {
return new MaxValueConstraint(maxValue);
static MaxValue(maxValue: number, exclusive?: boolean) {
return new MaxValueConstraint(maxValue, exclusive);
}

static MinLength(minLength: number) {
Expand All @@ -30,6 +30,10 @@ export abstract class Constraint {
return new EnumConstraint(list);
}

static Type(type: TypeConstraintType) {
return new TypeConstraint(type);
}

abstract compose(constraint: Constraint): Constraint;
}

Expand All @@ -41,34 +45,56 @@ export class RequiredConstraint extends Constraint {
}

export class MinValueConstraint extends Constraint {
constructor(private minValue: number) {
constructor(private minValue: number, private exclusive = false) {
super();
}

public getMinValue() {
return this.minValue;
}

public isExclusive() {
return this.exclusive;
}

public compose(constraint: MinValueConstraint): MinValueConstraint {
return new MinValueConstraint(
Math.max(this.minValue, constraint.getMinValue())
);
if (constraint.getMinValue() === this.getMinValue()) {
return new MinValueConstraint(
this.getMinValue(),
constraint.isExclusive() || this.isExclusive()
);
}
if (constraint.getMinValue() > this.getMinValue()) {
return constraint;
}
return this;
}
}

export class MaxValueConstraint extends Constraint {
constructor(private maxValue: number) {
constructor(private maxValue: number, private exclusive = false) {
super();
}

public getMaxValue() {
return this.maxValue;
}

public isExclusive() {
return this.exclusive;
}

public compose(constraint: MaxValueConstraint): MaxValueConstraint {
return new MaxValueConstraint(
Math.min(this.maxValue, constraint.getMaxValue())
);
if (constraint.getMaxValue() === this.getMaxValue()) {
return new MaxValueConstraint(
this.getMaxValue(),
constraint.isExclusive() || this.isExclusive()
);
}
if (constraint.getMaxValue() < this.getMaxValue()) {
return constraint;
}
return this;
}
}

Expand Down Expand Up @@ -115,7 +141,7 @@ export class RegexConstraint extends Constraint {

public compose(): RegexConstraint {
throw new InternalError(
`Can use multiple RegexConstraint at the same time.`
`Cannot use multiple RegexConstraint at the same time.`
);
}
}
Expand All @@ -135,3 +161,27 @@ export class EnumConstraint<T = string> extends Constraint {
);
}
}

export type TypeConstraintType =
| 'string'
| 'number'
| 'integer'
| 'boolean'
| 'array'
| 'object';

export class TypeConstraint extends Constraint {
constructor(private type: TypeConstraintType) {
super();
}

public getType() {
return this.type;
}

public compose(): TypeConstraint {
throw new InternalError(
`Cannot use multiple TypeConstraint at the same time.`
);
}
}
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { DateTypeValidator } from '@vulcan-sql/core/validators';
import { Constraint, DateTypeValidator } from '@vulcan-sql/core/validators';

describe('Test "date" type validator', () => {
it.each([
Expand Down Expand Up @@ -74,4 +74,13 @@ describe('Test "date" type validator', () => {
expect(() => validator.validateData(data, args)).toThrow();
}
);

it('Should return TypeConstraint', async () => {
// Arrange
const validator = new DateTypeValidator({}, '');
// Act
const constraints = validator.getConstraints();
// Assert
expect(constraints).toEqual([Constraint.Type('string')]);
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { IntegerTypeValidator } from '@vulcan-sql/core/validators';
import { Constraint, IntegerTypeValidator } from '@vulcan-sql/core/validators';

describe('Test "integer" type validator', () => {
it.each([
Expand Down Expand Up @@ -95,4 +95,23 @@ describe('Test "integer" type validator', () => {
expect(() => validator.validateData(data, args)).toThrow();
}
);

it('Should return TypeConstraint, MaxConstraint, and MinConstraint', async () => {
// Arrange
const validator = new IntegerTypeValidator({}, '');
// Act
const constraints = validator.getConstraints({
min: 3,
max: 5,
greater: 10,
less: 20,
});
// Assert
expect(constraints.length).toBe(5);
expect(constraints).toContainEqual(Constraint.Type('integer'));
expect(constraints).toContainEqual(Constraint.MinValue(3, false));
expect(constraints).toContainEqual(Constraint.MaxValue(5, false));
expect(constraints).toContainEqual(Constraint.MinValue(10, true));
expect(constraints).toContainEqual(Constraint.MaxValue(20, true));
});
});
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { RequiredValidator } from '@vulcan-sql/core/validators';
import { Constraint, RequiredValidator } from '@vulcan-sql/core/validators';

describe('Test "required" type validator', () => {
it.each([
Expand Down Expand Up @@ -85,4 +85,14 @@ describe('Test "required" type validator', () => {
expect(() => validator.validateData(data, args)).toThrow();
}
);

it('Should return RequiredConstraint', async () => {
// Arrange
const validator = new RequiredValidator({}, '');
// Act
const constraints = validator.getConstraints();
// Assert
expect(constraints.length).toBe(1);
expect(constraints).toContainEqual(Constraint.Required());
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import faker from '@faker-js/faker';
import { StringTypeValidator } from '@vulcan-sql/core/validators';
import { Constraint, StringTypeValidator } from '@vulcan-sql/core/validators';

describe('Test "string" type validator', () => {
it.each([
Expand Down Expand Up @@ -78,4 +78,24 @@ describe('Test "string" type validator', () => {
expect(() => validator.validateData(data, args)).toThrow();
}
);

it('Should return TypeConstraint, MaxLengthConstraint, and MinLengthConstraint', async () => {
// Arrange
const validator = new StringTypeValidator({}, '');
// Act
const constraints = validator.getConstraints({
min: 3,
max: 5,
length: 10,
format: '.+',
});
// Assert
expect(constraints.length).toBe(6);
expect(constraints).toContainEqual(Constraint.Type('string'));
expect(constraints).toContainEqual(Constraint.MinLength(3));
expect(constraints).toContainEqual(Constraint.MaxLength(5));
expect(constraints).toContainEqual(Constraint.MaxLength(10));
expect(constraints).toContainEqual(Constraint.MinLength(10));
expect(constraints).toContainEqual(Constraint.Regex('.+'));
});
});
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import * as uuid from 'uuid';
import { UUIDTypeValidator } from '@vulcan-sql/core/validators';
import { Constraint, UUIDTypeValidator } from '@vulcan-sql/core/validators';

describe('Test "uuid" type validator ', () => {
it.each([
Expand Down Expand Up @@ -78,4 +78,14 @@ describe('Test "uuid" type validator ', () => {
expect(() => validator.validateData(data, args)).toThrow();
}
);

it('Should return TypeConstraint', async () => {
// Arrange
const validator = new UUIDTypeValidator({}, '');
// Act
const constraints = validator.getConstraints();
// Assert
expect(constraints.length).toBe(1);
expect(constraints).toContainEqual(Constraint.Type('string'));
});
});
Loading

0 comments on commit be6f6c5

Please sign in to comment.