Skip to content

Commit 67ddd92

Browse files
committed
updated uuid generator
1 parent 161be21 commit 67ddd92

File tree

10 files changed

+249
-45
lines changed

10 files changed

+249
-45
lines changed
Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
## Bug fixes
2+
3+
- https://github.com/drizzle-team/drizzle-orm/issues/4551
4+
5+
## Breaking changes
6+
7+
### `uuid` generator was changed and upgraded to v4
8+
9+
```ts
10+
await seed(db, { table }).refine((f) => ({
11+
table: {
12+
columns: {
13+
// AA97B177-9383-4934-8543-0F91A7A02836
14+
// ^
15+
// 1
16+
// the digit at position 1 is always one of '8', '9', 'A' or 'B'
17+
column1: f.uuid(),
18+
}
19+
}
20+
}))
21+
```
22+
23+
**Reason for upgrade**
24+
25+
UUID values generated by the old version of the `uuid` generator fail Zod’s v4 UUID validation.
26+
27+
example
28+
```ts
29+
import { createSelectSchema } from 'drizzle-zod';
30+
import { seed } from 'drizzle-seed';
31+
32+
await seed(db, { uuidTest: schema.uuidTest }, { count: 1 }).refine((funcs) => ({
33+
uuidTest: {
34+
columns: {
35+
col1: funcs.uuid()
36+
}
37+
}
38+
})
39+
);
40+
41+
const uuidSelectSchema = createSelectSchema(schema.uuidTest);
42+
const res = await db.select().from(schema.uuidTest);
43+
// the line below will throw an error when using old version of uuid generator
44+
uuidSelectSchema.parse(res[0]);
45+
```
46+
47+
**Usage**
48+
```ts
49+
await seed(db, schema);
50+
// or explicit
51+
await seed(db, schema, { version: '4' });
52+
```
53+
54+
**Switch to the old version**
55+
56+
The previous version of `uuid` generator is v1.
57+
```ts
58+
await seed(db, schema, { version: '1' });
59+
```
60+
To use the v2 generators while maintaining the v1 `uuid` generator:
61+
```ts
62+
await seed(db, schema, { version: '2' });
63+
```
64+
To use the v3 generators while maintaining the v1 `uuid` generator:
65+
```ts
66+
await seed(db, schema, { version: '3' });
67+
```

drizzle-seed/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,7 @@
9393
"dotenv": "^16.4.5",
9494
"drizzle-kit": "workspace:./drizzle-kit/dist",
9595
"drizzle-orm": "workspace:./drizzle-orm/dist",
96+
"drizzle-zod": "workspace:./drizzle-zod/dist",
9697
"get-port": "^7.1.0",
9798
"mssql": "^11.0.1",
9899
"mysql2": "^3.14.1",
@@ -102,6 +103,7 @@
102103
"tslib": "^2.7.0",
103104
"tsx": "^4.19.0",
104105
"uuid": "^10.0.0",
106+
"zod": "^4.0.0",
105107
"zx": "^8.1.5"
106108
},
107109
"dependencies": {

drizzle-seed/src/SeedService.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,7 @@ export class SeedService {
226226
}
227227

228228
// Generating undefined as a value for a column and then inserting it via drizzle-orm
229-
// will result in the value not being inserted into that column.
229+
// will result in null of default value being inserted into that column.
230230
columnPossibleGenerator.generator = new generatorsMap.GenerateDefault[0]({ defaultValue: undefined });
231231
columnPossibleGenerator.wasRefined = true;
232232

drizzle-seed/src/generators/GeneratorFuncs.ts

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -63,6 +63,7 @@ import {
6363
} from './Generators.ts';
6464
import { GenerateStringV2, GenerateUniqueIntervalV2, GenerateUniqueStringV2 } from './versioning/v2.ts';
6565
import { GenerateHashFromStringV3 } from './versioning/v3.ts';
66+
import { GenerateUUIDV4 } from './versioning/v4.ts';
6667

6768
function createGenerator<GeneratorType extends AbstractGenerator<T>, T>(
6869
generatorConstructor: new(params?: T) => GeneratorType,
@@ -910,6 +911,10 @@ export const generatorsFuncsV3 = {
910911
...generatorsFuncs,
911912
};
912913

914+
export const generatorsFuncsV4 = {
915+
...generatorsFuncs,
916+
};
917+
913918
export const generatorsMap = {
914919
GenerateHashFromString: [
915920
GenerateHashFromString,
@@ -983,6 +988,7 @@ export const generatorsMap = {
983988
],
984989
GenerateUUID: [
985990
GenerateUUID,
991+
GenerateUUIDV4,
986992
],
987993
GenerateFirstName: [
988994
GenerateFirstName,
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
export const latestVersion = 3;
1+
export const latestVersion = 4;
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
import prand from 'pure-rand';
2+
import { AbstractGenerator } from '../Generators.ts';
3+
4+
/* eslint-disable drizzle-internal/require-entity-kind */
5+
export class GenerateUUIDV4 extends AbstractGenerator<{
6+
arraySize?: number;
7+
}> {
8+
static override readonly entityKind: string = 'GenerateUUID';
9+
static override readonly version: number = 4;
10+
11+
public override isGeneratorUnique = true;
12+
public override maxUniqueCount: number = Number.POSITIVE_INFINITY;
13+
14+
private state: { rng: prand.RandomGenerator } | undefined;
15+
16+
override getMaxUniqueCount(): number {
17+
return Number.POSITIVE_INFINITY;
18+
}
19+
20+
override init({ count, seed }: { count: number; seed: number }) {
21+
super.init({ count, seed });
22+
23+
const rng = prand.xoroshiro128plus(seed);
24+
this.state = { rng };
25+
}
26+
27+
generate() {
28+
if (this.state === undefined) {
29+
throw new Error('state is not defined.');
30+
}
31+
// TODO generate uuid using string generator
32+
const stringChars = '1234567890abcdef';
33+
let idx: number,
34+
currStr: string;
35+
const strLength = 36;
36+
37+
// uuid v4
38+
const uuidTemplate = '########-####-4###-N###-############';
39+
currStr = '';
40+
for (let i = 0; i < strLength; i++) {
41+
[idx, this.state.rng] = prand.uniformIntDistribution(
42+
0,
43+
stringChars.length - 1,
44+
this.state.rng,
45+
);
46+
47+
if (uuidTemplate[i] === '#') {
48+
currStr += stringChars[idx];
49+
continue;
50+
}
51+
52+
// used this pr -> https://github.com/drizzle-team/drizzle-orm/pull/4503
53+
if (uuidTemplate[i] === 'N') {
54+
currStr += '89ab'[idx % 4];
55+
continue;
56+
}
57+
58+
currStr += uuidTemplate[i];
59+
}
60+
return currStr;
61+
}
62+
}

drizzle-seed/src/index.ts

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,12 @@ import type { SingleStoreColumn, SingleStoreSchema, SingleStoreTable } from 'dri
2121
import { SingleStoreDatabase } from 'drizzle-orm/singlestore-core';
2222

2323
import { filterCockroachSchema, resetCockroach, seedCockroach } from './cockroach-core/index.ts';
24-
import { generatorsFuncs, generatorsFuncsV2, type generatorsFuncsV3 } from './generators/GeneratorFuncs.ts';
24+
import {
25+
generatorsFuncs,
26+
generatorsFuncsV2,
27+
type generatorsFuncsV3,
28+
type generatorsFuncsV4,
29+
} from './generators/GeneratorFuncs.ts';
2530
import type { AbstractGenerator } from './generators/Generators.ts';
2631
import { filterMsSqlTables, resetMsSql, seedMsSql } from './mssql-core/index.ts';
2732
import { filterMysqlTables, resetMySql, seedMySql } from './mysql-core/index.ts';
@@ -161,7 +166,8 @@ export type FunctionsVersioning<VERSION extends string | undefined = undefined>
161166
? typeof generatorsFuncs
162167
: VERSION extends `2` ? typeof generatorsFuncsV2
163168
: VERSION extends `3` ? typeof generatorsFuncsV3
164-
: typeof generatorsFuncsV3;
169+
: VERSION extends `4` ? typeof generatorsFuncsV4
170+
: typeof generatorsFuncsV4;
165171

166172
export function getGeneratorsFunctions() {
167173
return generatorsFuncs;
@@ -319,7 +325,7 @@ export function seed<
319325
SCHEMA extends {
320326
[key: string]: SchemaValuesType;
321327
},
322-
VERSION extends '3' | '2' | '1' | undefined,
328+
VERSION extends '4' | '3' | '2' | '1' | undefined,
323329
>(db: DB, schema: SCHEMA, options?: { count?: number; seed?: number; version?: VERSION }) {
324330
return new SeedPromise<typeof db, typeof schema, VERSION>(db, schema, options);
325331
}

drizzle-seed/tests/pg/pg.test.ts

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { relations } from 'drizzle-orm/_relations';
44
import type { PgliteDatabase } from 'drizzle-orm/pglite';
55
import { drizzle } from 'drizzle-orm/pglite';
66
import { afterAll, afterEach, beforeAll, expect, test, vi } from 'vitest';
7+
import { createSelectSchema } from '../../../drizzle-zod/dist';
78
import { reset, seed } from '../../src/index.ts';
89
import * as schema from './pgSchema.ts';
910

@@ -236,6 +237,15 @@ beforeAll(async () => {
236237
);
237238
`,
238239
);
240+
241+
await db.execute(
242+
sql`
243+
create table "seeder_lib_pg"."uuid_test"
244+
(
245+
col1 uuid
246+
);
247+
`,
248+
);
239249
});
240250

241251
afterEach(async () => {
@@ -501,3 +511,28 @@ test('seeding table with sequences', async () => {
501511
col8: 11,
502512
});
503513
});
514+
515+
test('uuid with drizzle-zod check', async () => {
516+
await seed(db, { uuidTest: schema.uuidTest }, { count: 1 }).refine((funcs) => ({
517+
uuidTest: {
518+
columns: {
519+
col1: funcs.uuid(),
520+
},
521+
},
522+
}));
523+
524+
const uuidSelectSchema = createSelectSchema(schema.uuidTest);
525+
const res = await db.select().from(schema.uuidTest);
526+
uuidSelectSchema.parse(res[0]);
527+
528+
expect(res).toStrictEqual([{ col1: 'caf44ec1-e98c-4d92-8ed5-beb2074f1460' }]);
529+
const possibleUuids = [
530+
'caf44ec1-e98c-4d92-8ed5-beb2074f1460',
531+
'caf44ec1-e98c-4d92-9ed5-beb2074f1460',
532+
'caf44ec1-e98c-4d92-aed5-beb2074f1460',
533+
'caf44ec1-e98c-4d92-bed5-beb2074f1460',
534+
];
535+
for (const uuid of possibleUuids) {
536+
uuidSelectSchema.parse({ col1: uuid });
537+
}
538+
});

drizzle-seed/tests/pg/pgSchema.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
smallserial,
1111
text,
1212
timestamp,
13+
uuid,
1314
varchar,
1415
} from 'drizzle-orm/pg-core';
1516

@@ -153,3 +154,7 @@ export const testSequences = schema.table(
153154
col8: smallserial(),
154155
},
155156
);
157+
158+
export const uuidTest = schema.table('uuid_test', {
159+
col1: uuid(),
160+
});

0 commit comments

Comments
 (0)