模型字段类型
在上一节中,字段的配置是这样的。S
则是引入的Sequelize
,为了编写方便,重命名了一下。
{
email: S.STRING,
name: S.STRING
}
在 define 函数的声明里面,需要传入的字段配置项其实是 DefineAttributes
类型。
[name: string]: string | DataTypeAbstract | DefineAttributeColumnOptions;
定义如上,这表示这对象里面的 key 必须是一个 string,而 value 则是 string 、DataTypeAbstract 、DefineAttributeColumnOptions 三者其一即可。
1.DataTypeAbstract
DataTypeAbstract
只是一个父接口,而 DataTypeString 、DataTypeBigInt 、DataTypeFloat 则都是继承了这个父接口,也就是说我们传入 DataTypeString 类型也是可以的,因为在面向对象的继承中,子类是可以赋值给父类的。
而我们的 DataTypes 的定义是这样的,也就是我们所有支持的类型,但是数据库之间是存在差异的,像 MYSQL 就不支持 JSON 类、Array 类等。
interface DataTypes {
ABSTRACT: DataTypeAbstract;
STRING: DataTypeString;
CHAR: DataTypeChar;
TEXT: DataTypeText;
NUMBER: DataTypeNumber;
INTEGER: DataTypeInteger;
BIGINT: DataTypeBigInt;
FLOAT: DataTypeFloat;
TIME: DataTypeTime;
DATE: DataTypeDate;
DATEONLY: DataTypeDateOnly;
BOOLEAN: DataTypeBoolean;
NOW: DataTypeNow;
BLOB: DataTypeBlob;
DECIMAL: DataTypeDecimal;
NUMERIC: DataTypeDecimal;
UUID: DataTypeUUID;
UUIDV1: DataTypeUUIDv1;
UUIDV4: DataTypeUUIDv4;
HSTORE: DataTypeHStore;
JSON: DataTypeJSONType;
JSONB: DataTypeJSONB;
VIRTUAL: DataTypeVirtual;
ARRAY: DataTypeArray;
NONE: DataTypeVirtual;
ENUM: DataTypeEnum;
RANGE: DataTypeRange;
REAL: DataTypeReal;
DOUBLE: DataTypeDouble;
"DOUBLE PRECISION": DataTypeDouble;
GEOMETRY: DataTypeGeometry;
}
并且 interface SequelizeStatic extends SequelizeStaticAndInstance, DataTypes
,也就是说 SequelizeStatic
是继承了 DataTypes 的,所以我么可以通过 Sequelize.INTEGER
来访问 DataTypes 的一些变量。
2.DefineAttributeColumnOptions
首先继承了 ColumnOptions
接口,都是一些可选属性,了解数据库知识的同学,对大部分配置项应该都能猜到是干什么用的。
interface ColumnOptions {
allowNull?: boolean;
field?: string;
defaultValue?: any;
}
interface DefineAttributeColumnOptions extends ColumnOptions {
type: string | DataTypeAbstract;
unique?: boolean | string | { name: string, msg: string };
primaryKey?: boolean;
autoIncrement?: boolean;
comment?: string;
references?: DefineAttributeColumnReferencesOptions;
onUpdate?: string;
onDelete?: string;
get?: () => any;
set?: (val: any) => void;
validate?: DefineValidateOptions;
values?: string[];
}
同时有这个validate
这个选项,其实是支持验证的。也就是用了一个validator
的库。它所支持的配置项如下。
interface DefineValidateOptions {
is?: string | Array<string | RegExp> | RegExp | { msg: string, args: string | Array<string | RegExp> | RegExp };
not?: string | Array<string | RegExp> | RegExp | { msg: string, args: string | Array<string | RegExp> | RegExp };
isEmail?: boolean | { msg: string };
isUrl?: boolean | { msg: string };
isIP?: boolean | { msg: string };
isIPv4?: boolean | { msg: string };
isIPv6?: boolean | { msg: string };
isAlpha?: boolean | { msg: string };
isAlphanumeric?: boolean | { msg: string };
isNumeric?: boolean | { msg: string };
isInt?: boolean | { msg: string };
isFloat?: boolean | { msg: string };
isDecimal?: boolean | { msg: string };
isLowercase?: boolean | { msg: string };
isUppercase?: boolean | { msg: string };
notNull?: boolean | { msg: string };
isNull?: boolean | { msg: string };
notEmpty?: boolean | { msg: string };
equals?: string | { msg: string };
contains?: string | { msg: string };
notIn?: string[][] | { msg: string, args: string[][] };
isIn?: string[][] | { msg: string, args: string[][] };
notContains?: string[] | string | { msg: string, args: string[] | string };
len?: [number, number] | { msg: string, args: [number, number] };
isUUID?: number | { msg: string, args: number };
isDate?: boolean | { msg: string, args: boolean };
isAfter?: string | { msg: string, args: string };
isBefore?: string | { msg: string, args: string };
max?: number | { msg: string, args: number };
min?: number | { msg: string, args: number };
isArray?: boolean | { msg: string, args: boolean };
isCreditCard?: boolean | { msg: string, args: boolean };
[name: string]: any;
}
小荔枝
interface BookAttributes {
// status: "inSale" | "noSale";
status: any;
description: string;
title: string;
author: string;
}
interface BookInstance extends Sequelize.Instance<BookAttributes> {
id: number;
createdAt: Date;
updatedAt: Date;
// status: "inSale" | "noSale";
status: any;
description: string;
title: string;
author: string;
}
const Book = sequelize.define<BookInstance, BookAttributes>('Book', {
id: {
type: S.INTEGER,
autoIncrement: true,
primaryKey: true,
unique: true
},
description: S.TEXT,
status: {
type: S.ENUM,
values: ['inSale', 'noSale'],
validate: {
isIn: {
args: [['inSale', 'noSale']],
msg: "status field must be inSale or noSale"
}
}
},
title:{
type: S.STRING,
allowNull: false,
get(this: BookInstance) {
return this.getDataValue('author') + ' - ' + this.getDataValue('title');
}
},
author: {
type: S.STRING,
allowNull: false,
set(val: string){
this.setDataValue('author', val.toLowerCase());
}
},
userId:{ // User 表的外键
type: S.INTEGER,
references: {
model: User
}
}
},{
comment: "图书表", // 表注释
indexes: [ // 表索引
{
fields: ['id']
}
]
})
// status: "inSale" | "noSale";
注释掉这个的原因是为了避免ts 编译时报错,我们先给它一个 any 类型,来验证一下 validate 方法是否真正的起了验证作用。
main 方法
async function main() {
try {
// await Book.sync();
// await User.sync();
Book.beforeValidate(() => {
console.log("验证之前");
});
const book = Book.build({ status: "onSale", author: "yugo", description: "lean ts", title: "typescript" });
await book.validate()
}catch(e){
// console.log(e)
if (e instanceof Sequelize.ValidationError) {
console.log(e.message);
}
}
process.exit(0)
}
运行可得到如下结果,说明验证错误是被 catch 捕获到了的,而且也打印了出来。
# Yugo @ Tractor in ~/Desktop/nl-sequelize/code/chapter2 on git:master x [13:19:00]
$ ts-node index.ts
验证之前
Validation error: status field must be inSale or noSale
当把book.validate
改成book.save
同样也会自动调用验证方法。接下来,把前面的接口改回来,再来试一试正确的。
const book = Book.build({ status: "inSale", author: "yugo", description: "lean ts", title: "typescript" });
await book.save()
# Yugo @ Tractor in ~/Desktop/nl-sequelize/code/chapter2 on git:master x [13:27:55]
$ ts-node index.ts
验证之前
Executing (default): INSERT INTO `Books` (`id`,`description`,`status`,`title`,`author`,`createdAt`,`updatedAt`) VALUES (DEFAULT,'lean ts','inSale','typescript','yugo','2017-06-19 05:29:35','2017-06-19 05:29:35');
小提示: 有的时候可能提示并没有告诉你可以调用哪些方法,大多数是因为代码编辑器的问题,直接去查看d.ts,自己找一下即可。