-
-
Notifications
You must be signed in to change notification settings - Fork 4.3k
/
attribute.ts
257 lines (238 loc) · 7.61 KB
/
attribute.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
import type { NonUndefined } from '@sequelize/utils';
import { isDataType } from '../../abstract-dialect/data-types-utils.js';
import type { DataType } from '../../abstract-dialect/data-types.js';
import type { AttributeIndexOptions, AttributeOptions } from '../../model.js';
import { columnToAttribute } from '../../utils/deprecations.js';
import { underscore } from '../../utils/string.js';
import {
createOptionalAttributeOptionsDecorator,
createRequiredAttributeOptionsDecorator,
} from './attribute-utils.js';
import type { PropertyOrGetterDescriptor } from './decorator-utils.js';
type AttributeDecoratorOption = DataType | Partial<AttributeOptions>;
/**
* The `@Attribute` decorator is used to add an attribute to a model. It is used on an instance property.
*
* @example
* The simplest way to use it is to pass a data type as the parameter:
* ```ts
* class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
* @Attribute(DataTypes.STRING)
* declare firstName: string | null;
* }
* ```
*
* @example
* `@Attribute` also accepts an option bag, {@link index~AttributeOptions}, which allows you to configure all available attribute definition options.
* ```ts
* class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
* @Attribute({
* type: DataTypes.STRING,
* allowNull: false,
* })
* declare firstName: string;
* }
* ```
*/
export const Attribute = createRequiredAttributeOptionsDecorator<AttributeDecoratorOption>(
'Attribute',
attrOptionOrDataType => {
if (isDataType(attrOptionOrDataType)) {
return {
type: attrOptionOrDataType,
};
}
return attrOptionOrDataType;
},
);
/**
* @param optionsOrDataType
* @deprecated use {@link Attribute} instead.
*/
export function Column(optionsOrDataType: DataType | AttributeOptions): PropertyOrGetterDescriptor {
columnToAttribute();
return Attribute(optionsOrDataType);
}
type UniqueOptions = NonNullable<AttributeOptions['unique']>;
/**
* The `@Unique` decorator is used to make an attribute unique, it is a shortcut for setting the `unique` option of the {@link Attribute} decorator.
* Learn more about unique constraints in our documentation.
*
* @example
* This makes "firstName" unique
* ```ts
* class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
* @Attribute(DataTypes.STRING)
* @Unique
* declare firstName: string;
* }
* ```
*
* @example
* This creates a composite unique on columns "firstName" and "lastName"
* ```ts
* class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
* @Attribute(DataTypes.STRING)
* @Unique('firstName-lastName')
* declare firstName: string;
*
* @Attribute(DataTypes.STRING)
* @Unique('firstName-lastName')
* declare lastName: string;
* }
* ```
*/
export const Unique = createOptionalAttributeOptionsDecorator<UniqueOptions>(
'Unique',
true,
(unique: UniqueOptions) => ({ unique }),
);
/**
* Makes the attribute accept null values. Opposite of {@link NotNull}.
* It is a shortcut for setting the `allowNull` option of the {@link Attribute} decorator to true.
*
* @example
* ```ts
* class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
* @Attribute(DataTypes.STRING)
* @AllowNull
* declare firstName: string | null;
* }
* ```
*/
export const AllowNull = createOptionalAttributeOptionsDecorator<boolean>(
'AllowNull',
true,
(allowNull: boolean) => ({ allowNull }),
);
/**
* Makes the attribute reject null values. Opposite of {@link AllowNull}.
* It is a shortcut for setting the `allowNull` option of the {@link Attribute} decorator to false.
*
* @example
* ```ts
* class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
* @Attribute(DataTypes.STRING)
* @NotNull
* declare firstName: string;
* }
* ```
*/
export const NotNull = createOptionalAttributeOptionsDecorator<boolean>(
'NotNull',
true,
(notNull: boolean) => ({ allowNull: !notNull }),
);
/**
* The `@PrimaryKey` decorator is used to make an attribute a primary key,
* it is a shortcut for setting the `primaryKey` option of the {@link Attribute} decorator to true.
*
* @example
* ```ts
* class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
* @Attribute(DataTypes.INTEGER)
* @PrimaryKey
* declare id: number;
* }
* ```
*/
export const PrimaryKey = createOptionalAttributeOptionsDecorator<boolean>(
'PrimaryKey',
true,
(primaryKey: boolean) => ({ primaryKey }),
);
/**
* The `@AutoIncrement` decorator is used to make an attribute auto-increment,
* it is a shortcut for setting the `autoIncrement` option of the {@link Attribute} decorator to true.
*
* Some dialects require the field to be a primary key.
*
* @example
* ```ts
* class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
* @Attribute(DataTypes.INTEGER)
* @PrimaryKey
* @AutoIncrement
* declare id: number;
* }
* ```
*/
export const AutoIncrement = createOptionalAttributeOptionsDecorator<boolean>(
'AutoIncrement',
true,
(autoIncrement: boolean) => ({ autoIncrement }),
);
/**
* The `@Comment` decorator is used to set the comment on a column, it is a shortcut for setting the `comment` option of the {@link Attribute} decorator.
*
* This is only useful if you use {@link index~Sequelize#sync} to create your tables.
*/
export const Comment = createRequiredAttributeOptionsDecorator<string>(
'Comment',
(comment: string) => ({ comment }),
);
/**
* The `@Default` decorator is used to set a default value for an attribute, it is a shortcut for setting the `defaultValue` option of the {@link Attribute} decorator.
*
* @example
* ```ts
* class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
* @Attribute(DataTypes.STRING)
* @Default('John Doe')
* declare firstName: string;
* }
* ```
*/
export const Default = createRequiredAttributeOptionsDecorator<unknown>(
'Default',
(defaultValue: unknown) => ({ defaultValue }),
);
/**
* Sets the name of the column (in the database) this attribute maps to.
* It is a shortcut for setting the `columnName` option of the {@link Attribute} decorator.
*
* With a good naming strategy configured, you rarely need to use this decorator.
* Learn about naming strategies in our documentation.
*
* @example
* ```ts
* class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
* @Attribute(DataTypes.STRING)
* @ColumnName('first_name')
* declare firstName: string;
* }
* ```
*/
export const ColumnName = createRequiredAttributeOptionsDecorator<string>(
'ColumnName',
(columnName: string) => ({ columnName }),
);
type IndexAttributeOption = NonUndefined<AttributeIndexOptions['attribute']>;
export function createIndexDecorator(
decoratorName: string,
options: Omit<AttributeIndexOptions, 'attribute'> = {},
) {
return createOptionalAttributeOptionsDecorator<IndexAttributeOption>(
decoratorName,
{},
(indexField: IndexAttributeOption): Partial<AttributeOptions> => {
const index: AttributeIndexOptions = {
...options,
// TODO: default index name should be generated using https://github.com/sequelize/sequelize/issues/15312
name: options.name || underscore(decoratorName),
attribute: indexField,
};
return { index };
},
);
}
type IndexDecoratorOptions = NonUndefined<AttributeOptions['index']>;
export const Index = createOptionalAttributeOptionsDecorator<IndexDecoratorOptions>(
'Index',
{},
(indexField: IndexDecoratorOptions): Partial<AttributeOptions> => {
return {
index: indexField,
};
},
);