Skip to content
This repository has been archived by the owner on Dec 23, 2021. It is now read-only.

Commit

Permalink
feat: #68 enhance
Browse files Browse the repository at this point in the history
  • Loading branch information
Soontao committed Sep 25, 2020
1 parent c4efed5 commit e3f52da
Show file tree
Hide file tree
Showing 8 changed files with 383 additions and 172 deletions.
57 changes: 17 additions & 40 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -43,20 +43,20 @@
"@odata/metadata": "^0.1.14",
"@odata/parser": "^0.2.3",
"body-parser": "^1.19.0",
"class-validator": "^0.12.2",
"colors": "^1.4.0",
"cors": "^2.8.5",
"debug": "^4.2.0",
"deepmerge": "^4.2.2",
"express": "^4.17.1",
"get-function-location": "^2.0.0",
"node-cache": "^5.1.2",
"odata2openapi": "^1.3.2",
"qs": "^6.9.4",
"reflect-metadata": "^0.1.13",
"swagger-ui-express": "^4.1.4",
"tslib": "^2.0.1",
"typeorm": "^0.2.25",
"uuid": "^8.3.0"
"uuid": "^8.3.0",
"validate.js": "^0.13.1"
},
"devDependencies": {
"@odata/client": "^2.10.2",
Expand Down
222 changes: 180 additions & 42 deletions src/type/decorators/assert.ts
Original file line number Diff line number Diff line change
@@ -1,49 +1,187 @@
import { buildMessage, Contains, IsBoolean, IsDate, IsDateString, isDateString, IsDefined, IsEmail, IsEmpty, IsEnum, IsInt, IsNumber, IsNumberString, IsOptional, IsPhoneNumber, IsString, IsUrl, IsUUID, MaxLength, MinLength, ValidateBy, ValidationOptions } from 'class-validator';
import { isClass } from '@newdash/inject/lib/utils';
import { ODataMethod } from '@odata/parser';
import 'reflect-metadata';
import { EColumnOptions } from './odata';

const KEY_PROP_CONSTRAINT = 'entity:constraint_information';

/**
* Checks if value is defined (!== undefined, !== null).
*/
export function isDefined(value: any): boolean {
return value !== undefined && value !== null;
export interface ConstraintOption {
presence?: { allowEmpty?: boolean, message?: string };
type?: 'array' | 'integer' | 'number' | 'string' | 'date' | 'boolean';
/**
* The inclusion validator is useful for validating input from a dropdown for example.
* It checks that the given value exists in the list given by the `within` option.
*/
inclusion?: any[];
/**
* The exclusion validator is useful for restriction certain values.
* It checks that the given value is not in the list given by the within option.
*/
exclusion?: any[];
/**
* The format validator will validate a value against a regular expression of your chosing.
*/
format?: {
pattern?: RegExp;
message?: string;
};
length?: {
minimum?: number;
maximum?: number;
is?: number;

notValid?: string;
wrongLength?: string;
tooLong?: string;
tooShort?: string;
};
numericality?: {
greaterThan?: number;
greaterThanOrEqualTo?: number;
lessThan?: number;
divisibleBy?: number;
onlyInteger?: boolean;
strict?: boolean;
odd?: boolean;
even?: boolean;

notValid?: string;
notInteger?: string;
notGreaterThan?: string;
notGreaterThanOrEqualTo?: string;
notEqualTo?: string;
notLessThan?: string;
notLessThanOrEqualTo?: string;
notDivisibleBy?: string;
notOdd?: string;
notEven?: string;
},
email?: { message?: string },
/**
* This datetime validator can be used to validate dates and times.
* Since date parsing in javascript is very poor some additional work is required to make this work.
*/
datetime?: {
/**
* The date cannot be before this time.
* This argument will be parsed using the parse function, just like the value.
* The default error must be no earlier than %{date}
*/
earliest?: string;
latest?: string;
/**
* If true, only dates (not datetimes) will be allowed.
* The default error is must be a valid date
*/
dateOnly?: boolean;
}
}

export function IsDateOrDateString(validationOptions?: ValidationOptions): PropertyDecorator {
return ValidateBy(
{
name: 'IS_DATE_OR_DATE_STRING',
validator: {
validate: (value): boolean => isDateString(value) || value instanceof Date,
defaultMessage: buildMessage(
(eachPrefix) => `${eachPrefix}$property should be date object or ISO date string`,
validationOptions
)
}
},
validationOptions
);
export function Validate(validateOptions: ConstraintOption): PropertyDecorator {
return function (target, propertyKey) {
Reflect.defineMetadata(KEY_PROP_CONSTRAINT, validateOptions, target, propertyKey);
};
}

export function getValidateOptions(target, propertyKey): ConstraintOption {
if (isClass(target)) {
return Reflect.getMetadata(KEY_PROP_CONSTRAINT, target.prototype, propertyKey);
}
return Reflect.getMetadata(KEY_PROP_CONSTRAINT, target, propertyKey);
}

export const Assert = {
IsDefined,
NotNull: IsDefined,
IsString,
IsNumber,
IsInt,
IsEnum,
IsPhoneNumber,
IsUrl,
IsOptional,
IsDate,
IsDateString,
IsBoolean,
IsNumberString,
IsDateOrDateString,
IsEmail,
IsEmpty,
Contains,
IsUUID,
MaxLength,
MinLength
};
const UUID_REGEX = /^[0-9A-F]{8}-[0-9A-F]{4}-4[0-9A-F]{3}-[89AB][0-9A-F]{3}-[0-9A-F]{12}$/i;
const ISO_DATE_FORMAT = /\d{4}-[01]\d-[0-3]\dT[0-2]\d:[0-5]\d:[0-5]\d\.\d+([+-][0-2]\d:[0-5]\d|Z)/;

export function columnToValidateRule(
options: EColumnOptions,
method: ODataMethod
): ConstraintOption {

const cOption: ConstraintOption = {};

if (options?.nullable == true || options?.default !== undefined || options?.generated) {
// no required
}
else if (ODataMethod.POST == method) {
cOption.presence = {}; // mandatory
}

switch (options.type) {
case 'decimal': case 'dec': case 'float': case 'float4': case 'float8':
cOption.type = 'string';
cOption.format = {
pattern: /^\d*\.?\d*$/,
message: 'invalid numeric string.'
};
break;
case 'date':
case 'nvarchar':
case 'nvarchar2':
case 'varchar':
case 'varchar2':
case 'char':
case 'text':
case String:
cOption.type = 'string';
if (options?.length) {
cOption.length = { maximum: options.length as number };
}
if (options.generated === 'uuid') {
cOption.type = 'string';
cOption.format = {
pattern: UUID_REGEX,
message: 'invalid uuid string.'
};
}
break;
case 'uuid':
cOption.type = 'string';
cOption.format = {
pattern: UUID_REGEX,
message: 'invalid uuid string.'
};
break;
case 'datetime': case 'datetime2': case 'datetimeoffset': case Date:
cOption.type = 'string';
cOption.format = {
pattern: ISO_DATE_FORMAT,
message: 'invalid datetime string, only support ISO format.'
};
break;
case 'int':
case 'integer':
case 'int2':
case 'int4':
case 'int8':
case 'int64':
case 'bigint':
case Number:
if (options.reflectType == Date) {
cOption.type = 'string';
cOption.format = {
pattern: ISO_DATE_FORMAT,
message: 'invalid datetime string, only support ISO format.'
};
}
else {
cOption.type = 'number';
if (options?.length) {
cOption.length = { maximum: options.length as number };
}
cOption.numericality = {
onlyInteger: true
};
}

break;
case 'bool': case 'boolean':
cOption.type = 'boolean';
break;
default:
break;
}


return cOption;
}

0 comments on commit e3f52da

Please sign in to comment.