Skip to content

Commit bb40dc4

Browse files
authored
document new uuid functions (#647)
1 parent 88e0fc3 commit bb40dc4

11 files changed

+114
-62
lines changed

docs/_fragments/_js-default-caution.mdx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
:::caution
22

3-
The generation of values for `DataTypes.UUIDV1` and `DataTypes.UUIDV4`, `DataTypes.NOW` and other JavaScript functions are not handled by the Database,
4-
but by Sequelize itself. This means that they will only be used when using Model methods. They will not be used in [raw queries](../querying/raw-queries.md),
3+
The generation of values for `DataTypes.NOW` and other JavaScript functions are not handled by the Database,
4+
but by Sequelize itself. This means that they will only be used when using Model methods. They will not be used in [raw queries](../querying/raw-queries.mdx),
55
in [migrations](../models/migrations.md), and all other places where Sequelize does not have access to the Model.
66

77
Read about SQL based alternatives in [Dynamic SQL default values](../models/defining-models.mdx#dynamic-sql-default-values).
+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
import { DialectTableFilter } from '@site/src/components/dialect-table-filter.tsx';
2+
3+
<DialectTableFilter>
4+
5+
| | PostgreSQL | MariaDB | MySQL | MSSQL | SQLite | Snowflake | db2 | ibmi |
6+
|----------|---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|-------------------------------------------|----------------------------------------------------------------------------------------------|-----------------------------------------------------------------------------------------------------------|--------|-----------|-----|------|
7+
| `uuidV1` | [`uuid_generate_v1`](https://www.postgresql.org/docs/current/uuid-ossp.html) (requires `uuid-ossp`) | [`UUID`](https://mariadb.com/kb/en/uuid/) | [`UUID`](https://dev.mysql.com/doc/refman/8.0/en/miscellaneous-functions.html#function_uuid) | N/A | N/A | N/A | N/A | N/A |
8+
| `uuidV4` | __pg >= v13__: [`gen_random_uuid`](https://www.postgresql.org/docs/current/functions-uuid.html) <br/>__pg &lt; v13__: [`uuid_generate_v4`](https://www.postgresql.org/docs/current/uuid-ossp.html) (requires `uuid-ossp`) | N/A | N/A | [`NEWID`](https://learn.microsoft.com/en-us/sql/t-sql/functions/newid-transact-sql?view=sql-server-ver16) | N/A | N/A | N/A | N/A |
9+
10+
</DialectTableFilter>

docs/models/data-types.mdx

+26-4
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ title: Data Types
66
import { DialectTableFilter } from '@site/src/components/dialect-table-filter.tsx';
77
import { Deprecated } from '@site/src/components/deprecated.tsx';
88
import JsDefaultCaution from '../_fragments/_js-default-caution.mdx';
9+
import UuidSupportTable from '../_fragments/_uuid-support-table.mdx';
910

1011
Sequelize provides [a lot of built-in data types](pathname:///api/v7/modules/_sequelize_core.index.DataTypes.html). To access a built-in data type, you must import `DataTypes`:
1112

@@ -212,6 +213,9 @@ MyModel.init({
212213

213214
For UUIDs, use `DataTypes.UUID`. It becomes the `UUID` data type for PostgreSQL and SQLite, and `CHAR(36)` for MySQL.
214215

216+
You can also use `DataTypes.UUID.V4` and `DataTypes.UUID.V1`
217+
to limit which version of UUID is accepted by the attribute to v4 or v1 respectively.
218+
215219
<DialectTableFilter>
216220

217221
| Sequelize DataType | PostgreSQL | MariaDB | MySQL | MSSQL | SQLite | Snowflake | db2 | ibmi |
@@ -222,18 +226,36 @@ For UUIDs, use `DataTypes.UUID`. It becomes the `UUID` data type for PostgreSQL
222226

223227
### Built-in Default Values for UUID
224228

225-
Sequelize can generate UUIDs automatically for these attributes, simply use `DataTypes.UUIDV1` or `DataTypes.UUIDV4` as the default value:
229+
Sequelize can generate UUIDs automatically for these attributes, simply use [`sql.uuidV1` or `sql.uuidV4`](../querying/raw-queries.mdx#sqluuidv4--sqluuidv1) as the default value:
226230

227231
```javascript
228232
MyModel.init({
229233
myUuid: {
230-
type: DataTypes.UUID,
231-
defaultValue: DataTypes.UUIDV4, // Or DataTypes.UUIDV1
234+
type: DataTypes.UUID.V4,
235+
defaultValue: sql.uuidV4, // Or sql.uuidV1
232236
},
233237
});
234238
```
235239

236-
<JsDefaultCaution />
240+
In supported dialects, Sequelize will set the default value to the appropriate function, as shown in the table below.
241+
These dialects can also use these two functions in migrations.
242+
243+
In all other dialects, Sequelize will generate the UUID value itself, in JavaScript.
244+
This means that they cannot use these two functions in migrations.
245+
246+
<UuidSupportTable />
247+
248+
The postgres dialect requires the `uuid-ossp` extension to be enabled to be able to generate v1 UUIDs.
249+
If this extension is not available, you can force Sequelize to generate the UUIDs itself by using `sql.uuidV1.asJavaScript` instead.
250+
251+
```javascript
252+
MyModel.init({
253+
myUuid: {
254+
type: DataTypes.UUID.V1,
255+
defaultValue: sql.uuidV1.asJavaScript,
256+
},
257+
});
258+
```
237259

238260
## BLOBs
239261

docs/models/defining-models.mdx

+26-26
Original file line numberDiff line numberDiff line change
@@ -235,13 +235,9 @@ class User extends Model {
235235

236236
### Dynamic JS default values
237237

238-
Instead of a static value, you can also use a JavaScript function that sequelize will call every time a new instance is created. Sequelize provides 3 built-in functions that you can use, but a custom function can be used as well:
239-
240-
- [`DataTypes.NOW`](./data-types.mdx#built-in-default-values-for-dates) for the current timestamp
241-
- [`DataTypes.UUIDV4`](./data-types.mdx#built-in-default-values-for-uuid) for a UUIDv4
242-
- [`DataTypes.UUIDV1`](./data-types.mdx#built-in-default-values-for-uuid) for a UUIDv1
243-
244-
<JsDefaultCaution />
238+
Instead of a static value, you can also use a JavaScript function that sequelize will call every time a new instance is created.
239+
Sequelize provides the built-in [`DataTypes.NOW`](./data-types.mdx#built-in-default-values-for-dates) for the current timestamp,
240+
but a custom function can be used as well:
245241

246242
<Tabs groupId="ts-js">
247243
<TabItem value="ts" label="TypeScript">
@@ -296,28 +292,27 @@ class User extends Model {
296292
</TabItem>
297293
</Tabs>
298294

295+
<JsDefaultCaution />
296+
299297
### Dynamic SQL default values
300298

301-
You can also use a SQL function as a default value using either [`fn`] or [`literal`].
302-
This has the advantage over [dynamic JS default values](#dynamic-js-default-values) that the function will always be called, since it is handled by the database, not by Sequelize.
299+
You can also use a SQL function as a default value using [raw SQL](../querying/raw-queries.mdx).
300+
This has the advantage over [dynamic JS default values](#dynamic-js-default-values) that the function will always be called,
301+
since it is handled by the database, not by Sequelize.
303302

304-
For instance, if your dialect provides a built-in SQL function to generate UUIDs, you can use [`fn`] to set a default value on the SQL layer:
303+
For instance, you could use the [`sql.fn`](../querying/raw-queries.mdx#sqlfn) function to make the database generate a random number for you:
305304

306305
<Tabs groupId="ts-js">
307306
<TabItem value="ts" label="TypeScript">
308307

309308
```ts
310309
import { DataTypes, Model, sql, InferAttributes, InferCreationAttributes, CreationOptional } from '@sequelize/core';
311-
import { Attribute, Default, PrimaryKey } from '@sequelize/core/decorators-legacy';
310+
import { Attribute, Default } from '@sequelize/core/decorators-legacy';
312311

313312
class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
314-
@PrimaryKey
315-
@Attribute(DataTypes.UUID)
316-
// 'uuid_generate_v4' is only available in postgres + uuid-ossp
317-
// other dialects may support this function under different names.
318-
// highlight-next-line
319-
@Default(sql.fn('uuid_generate_v4'))
320-
declare id: CreationOptional<string>;
313+
@Attribute(DataTypes.FLOAT)
314+
@Default(sql.fn('random'))
315+
declare randomNumber: CreationOptional<number>;
321316
}
322317
```
323318

@@ -326,22 +321,27 @@ class User extends Model<InferAttributes<User>, InferCreationAttributes<User>> {
326321

327322
```js
328323
import { DataTypes, Model, sql } from '@sequelize/core';
329-
import { Attribute, Default, PrimaryKey } from '@sequelize/core/decorators-legacy';
324+
import { Attribute, Default } from '@sequelize/core/decorators-legacy';
330325

331326
class User extends Model {
332-
@PrimaryKey
333-
@Attribute(DataTypes.UUID)
334-
// 'uuid_generate_v4' is only available in postgres + uuid-ossp
335-
// other dialects may support this function under different names.
336-
// highlight-next-line
337-
@Default(sql.fn('uuid_generate_v4'))
338-
id;
327+
@Attribute(DataTypes.FLOAT)
328+
@Default(sql.fn('random'))
329+
randomNumber;
339330
}
340331
```
341332

342333
</TabItem>
343334
</Tabs>
344335

336+
Sequelize also provides 2 built-in functions, [`sql.uuidV1` and `sql.uuidV4`](./data-types.mdx#built-in-default-values-for-uuid), that will
337+
generate a UUID in SQL if possible, and fallback to a JavaScript implementation otherwise.
338+
339+
:::info
340+
341+
In MySQL, it is only possible to use dynamic SQL default values starting with version [8.0.13](https://dev.mysql.com/doc/relnotes/mysql/8.0/en/news-8-0-13.html).
342+
343+
:::
344+
345345
## Primary Keys
346346

347347
Sequelize automatically adds an auto-incremented integer attribute called `id` as primary key if none is specified.

docs/other-topics/extending-data-types.md

+3-3
Original file line numberDiff line numberDiff line change
@@ -102,8 +102,8 @@ export class MyDateType extends DataTypes.ABSTRACT<Date> {
102102
We also have 4 methods that can be implemented to define how the Data Type serializes & deserializes values when interacting with the database:
103103

104104
- `parseDatabaseValue(value): unknown`: Transforms values retrieved from the database[^caveat-1].
105-
- `toBindableValue(value): unknown`: Transforms a value into a value accepted by the connector library when using [bind parameters](../querying/raw-queries.md#bind-parameters).
106-
- `escape(value): string`: Escapes a value for inlining inside of raw SQL, such as when using [replacements](../querying/raw-queries.md#replacements).
105+
- `toBindableValue(value): unknown`: Transforms a value into a value accepted by the connector library when using [bind parameters](../querying/raw-queries.mdx#bind-parameters).
106+
- `escape(value): string`: Escapes a value for inlining inside of raw SQL, such as when using [replacements](../querying/raw-queries.mdx#replacements).
107107
By default, if `toBindableValue` returns a string, this method will escape that string as a SQL string.
108108

109109
```typescript
@@ -171,4 +171,4 @@ When using `DataTypes.ENUM`, Sequelize will automatically create the enum type i
171171
If you need to create a custom type, you will need to create it manually in the database before you can use it in one of your models.
172172

173173
[^caveat-1]: `parseDatabaseValue` is only called if a Sequelize Data Type is specified in the query.
174-
This is the case when using model methods, but not when using [raw queries](../querying/raw-queries.md) or when not specifying the model in [`QueryInterface`](pathname:///api/v7/classes/_sequelize_core.index.AbstractQueryInterface.html) methods
174+
This is the case when using model methods, but not when using [raw queries](../querying/raw-queries.mdx) or when not specifying the model in [`QueryInterface`](pathname:///api/v7/classes/_sequelize_core.index.AbstractQueryInterface.html) methods

docs/other-topics/hooks.mdx

+11-11
Original file line numberDiff line numberDiff line change
@@ -64,9 +64,9 @@ Instance Sequelize hooks can be registered in two ways:
6464
1. Using the `hooks` property of the `Sequelize` instance:
6565
```typescript
6666
import { Sequelize } from '@sequelize/core';
67-
67+
6868
const sequelize = new Sequelize(/* options */);
69-
69+
7070
// highlight-next-line
7171
sequelize.hooks.addListener('beforeDefine', () => {
7272
console.log('A new Model is being initialized');
@@ -75,7 +75,7 @@ Instance Sequelize hooks can be registered in two ways:
7575
2. Through the `Sequelize` options:
7676
```typescript
7777
import { Sequelize } from '@sequelize/core';
78-
78+
7979
const sequelize = new Sequelize({
8080
// highlight-next-line
8181
hooks: {
@@ -115,13 +115,13 @@ Instance Sequelize hooks can be registered in three ways:
115115
1. Using the `hooks` property of the `Sequelize` instance:
116116
```typescript
117117
import { Sequelize, DataTypes } from '@sequelize/core';
118-
118+
119119
const sequelize = new Sequelize(/* options */);
120-
120+
121121
const MyModel = sequelize.define('MyModel', {
122122
name: DataTypes.STRING,
123123
});
124-
124+
125125
// highlight-next-line
126126
MyModel.hooks.addListener('beforeFind', () => {
127127
console.log('findAll has been called on MyModel');
@@ -150,7 +150,7 @@ Instance Sequelize hooks can be registered in three ways:
150150
```typescript
151151
import { Sequelize, Model, Hook } from '@sequelize/core';
152152
import { BeforeFind } from '@sequelize/core/decorators-legacy';
153-
153+
154154
export class MyModel extends Model {
155155
// highlight-next-line
156156
@BeforeFind
@@ -262,7 +262,7 @@ These include but are not limited to:
262262

263263
- Instances being deleted by the database because of an `ON DELETE CASCADE` constraint, [except if the `hooks` option is true](#hooks-for-cascade-deletes).
264264
- Instances being updated by the database because of a `SET NULL` or `SET DEFAULT` constraint.
265-
- [Raw queries](../querying/raw-queries.md).
265+
- [Raw queries](../querying/raw-queries.mdx).
266266
- All QueryInterface methods.
267267

268268
If you need to react to these events, consider using your database's native and notification system instead.
@@ -310,7 +310,7 @@ class Post extends Model {
310310

311311
const sequelize = new Sequelize({
312312
/* options */
313-
models: [User, Post],
313+
models: [User, Post],
314314
});
315315

316316
await sequelize.sync({ force: true });
@@ -351,8 +351,8 @@ await sequelize.transaction(async transaction => {
351351
});
352352
```
353353

354-
If we had not included the transaction option in our call to `User.update` in the preceding code,
355-
no change would have occurred, since our newly created user does not exist in the database until the pending transaction
354+
If we had not included the transaction option in our call to `User.update` in the preceding code,
355+
no change would have occurred, since our newly created user does not exist in the database until the pending transaction
356356
has been committed.
357357

358358
[^find-all]: **findAll**: Note that some methods, such as `Model.findOne`, `Model.findAndCountAll` and association getters will also call `Model.findAll` internally. This will cause the `beforeFind` hook to be called for these methods too.

docs/querying/json.mdx

+1-1
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ import { SupportTable } from '@site/src/components/support-table';
2727
JSON columns are a great way to opt-in to a document approach to data storage while preserving the advantages of relational databases.
2828

2929
Sequelize has first class support for querying JSON columns, including support for accessing nested properties.
30-
This is done thanks to the `.` syntax supported by [attributes](./raw-queries.md#sqlattribute):
30+
This is done thanks to the `.` syntax supported by [attributes](./raw-queries.mdx#sqlattribute):
3131

3232
```ts
3333
User.findAll({

docs/querying/operators.mdx

+2-2
Original file line numberDiff line numberDiff line change
@@ -1187,8 +1187,8 @@ Post.findAll({
11871187

11881188
## Custom Operators
11891189

1190-
Thanks to the [`sql`](./raw-queries.md) tag, it is very easy to create custom operators. We recommend reading
1191-
the chapter on [raw queries](./raw-queries.md) to learn more.
1190+
Thanks to the [`sql`](./raw-queries.mdx) tag, it is very easy to create custom operators. We recommend reading
1191+
the chapter on [raw queries](./raw-queries.mdx) to learn more.
11921192

11931193
Here is an example of a `LIKE` that supports escaping special LIKE characters:
11941194

docs/querying/raw-queries.md renamed to docs/querying/raw-queries.mdx

+24-4
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@ sidebar_position: 8
33
title: Raw SQL (literals)
44
---
55

6+
import UuidSupportTable from '../_fragments/_uuid-support-table.mdx';
7+
68
We believe that ORMs are inherently leaky abstractions. They are a compromise between the flexibility of SQL and the convenience of an object-oriented programming language.
79
As such, it does not make sense to try to provide a 100% complete abstraction over SQL (which could easily be more difficult to read than the SQL itself).
810

@@ -97,7 +99,7 @@ whereas bind parameters are sent to the database separately from the SQL query t
9799

98100
A query can have both bind parameters and replacements.
99101

100-
Each database uses a different syntax for bind parameters, but Sequelize provides its own unification layer.
102+
Each database uses a different syntax for bind parameters, but Sequelize provides its own unification layer.
101103

102104
Inconsequentially to which database you use, in Sequelize bind parameters are written following a postgres-like syntax. You can either:
103105

@@ -201,7 +203,7 @@ $$;
201203
);
202204
```
203205

204-
The above query looks like code, has syntax coloring that makes it look like code, but is really a regular dollar-quoted string
206+
The above query looks like code, has syntax coloring that makes it look like code, but is really a regular dollar-quoted string
205207
that will be interpreted as SQL by the `DO` clause (similarly to `eval` in JavaScript).
206208

207209
Dollar-quoted strings end as soon as `$$` is encountered. If the user passes `$$` as the `id` parameter, the query will end early and will
@@ -359,7 +361,7 @@ SELECT * FROM "projects" WHERE '2012-01-01' BETWEEN "createdAt" AND "publishedAt
359361

360362
### `sql.attribute`
361363

362-
The `sql.attribute` function can be used to reference the name of a Model attribute. It is similar to the [`sql.identifier`](#sqlidentifier) function,
364+
The `sql.attribute` function can be used to reference the name of a Model attribute. It is similar to the [`sql.identifier`](#sqlidentifier) function,
363365
but the name of the attribute will be mapped to the name of the column, whereas `sql.identifier` escapes its value as-is:
364366

365367
```ts
@@ -483,11 +485,29 @@ Attributes support a shorthand syntax for casting. See [Casting syntax in `sql.a
483485

484486
:::
485487

488+
### `sql.uuidV4` & `sql.uuidV1`
489+
490+
In supported dialects, using `sql.uuidV4` and `sql.uuidV1` will generate the dialect-specific function to generate a UUID.
491+
In unsupported dialects, using these functions, except as [the default value of an attribute](../models/data-types.mdx#built-in-default-values-for-uuid), will throw an error.
492+
493+
```ts
494+
sequelize.query(sql`INSERT INTO users (id) VALUES (${sql.uuidV4()})`);
495+
```
496+
497+
```sql
498+
-- postgres example
499+
INSERT INTO users (id) VALUES (gen_random_uuid())
500+
```
501+
502+
These functions are supported by the following dialects:
503+
504+
<UuidSupportTable />
505+
486506
### `sql.col`
487507

488508
:::caution
489509

490-
This function is available for backwards compatibility, and there are currently no plans to deprecate it,
510+
This function is available for backwards compatibility, and there are currently no plans to deprecate it,
491511
but it is not recommended to use in new code. Prefer instead to use [`sql.attribute`](#sqlattribute), [`sql.identifier`](#sqlidentifier),
492512
and the `sql` template tag.
493513

0 commit comments

Comments
 (0)