Skip to content

Commit ad72b8a

Browse files
authored
Merge pull request #488 from drizzle-team/bugfixes
2 parents 442aac3 + 034bdcd commit ad72b8a

28 files changed

+728
-329
lines changed

changelogs/drizzle-orm/0.24.4.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
- 🐛 Added verbose error when .values() is called without values (#441)
2+
- 🐛 Fixed nested PG arrays mapping (#460)
3+
- ❗ Removed spread syntax in .values() (#269)
4+
- 🐛 Fixed passing undefined as field value to insert/update (#375)

drizzle-orm/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "drizzle-orm",
3-
"version": "0.24.3",
3+
"version": "0.24.4",
44
"description": "Drizzle ORM package for SQL databases",
55
"scripts": {
66
"build": "tsc && resolve-tspaths && cp ../README.md package.json dist/",

drizzle-orm/src/mysql-core/dialect.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { AnyColumn } from '~/column';
22
import { Column } from '~/column';
33
import type { MigrationConfig, MigrationMeta } from '~/migrator';
4-
import { name, type Query, SQL, sql, type SQLChunk } from '~/sql';
4+
import { name, Param, type Query, SQL, sql, type SQLChunk } from '~/sql';
55
import { Subquery, SubqueryConfig } from '~/subquery';
66
import { getTableName, Table } from '~/table';
77
import { orderSelectedFields, type UpdateSet } from '~/utils';
@@ -324,7 +324,7 @@ export class MySqlDialect {
324324
const valueList: (SQLChunk | SQL)[] = [];
325325
for (const [fieldName] of colEntries) {
326326
const colValue = value[fieldName];
327-
if (colValue === undefined) {
327+
if (colValue === undefined || (colValue instanceof Param && colValue.value === undefined)) {
328328
valueList.push(sql`default`);
329329
} else {
330330
valueList.push(colValue);

drizzle-orm/src/mysql-core/query-builders/insert.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -51,15 +51,12 @@ export class MySqlInsertBuilder<
5151

5252
values(value: MySqlInsertValue<TTable>): MySqlInsert<TTable, TQueryResult, TPreparedQueryHKT>;
5353
values(values: MySqlInsertValue<TTable>[]): MySqlInsert<TTable, TQueryResult, TPreparedQueryHKT>;
54-
/**
55-
* @deprecated Pass the array of values without spreading it.
56-
*/
57-
values(...values: MySqlInsertValue<TTable>[]): MySqlInsert<TTable, TQueryResult, TPreparedQueryHKT>;
5854
values(
59-
...values: MySqlInsertValue<TTable>[] | [MySqlInsertValue<TTable>] | [MySqlInsertValue<TTable>[]]
55+
values: MySqlInsertValue<TTable> | MySqlInsertValue<TTable>[],
6056
): MySqlInsert<TTable, TQueryResult, TPreparedQueryHKT> {
61-
if (values.length === 1) {
62-
values = Array.isArray(values[0]) ? values[0] : [values[0]];
57+
values = Array.isArray(values) ? values : [values];
58+
if (values.length === 0) {
59+
throw new Error('values() must be called with at least one value');
6360
}
6461
const mappedValues = values.map((entry) => {
6562
const result: Record<string, Param | SQL> = {};

drizzle-orm/src/pg-core/columns/array.ts

Lines changed: 11 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@ export class PgArrayBuilder<T extends ColumnBuilderBaseConfig> extends PgColumnB
3131
notNull: T['notNull'];
3232
hasDefault: T['hasDefault'];
3333
data: Assume<T['data'], unknown[]>[number];
34-
driverParam: Assume<T['driverParam'], unknown[]>[number];
34+
driverParam: string | Assume<T['driverParam'], unknown[]>[number];
3535
}
3636
>;
3737
size: number | undefined;
@@ -67,7 +67,7 @@ export class PgArray<T extends ColumnBaseConfig> extends PgColumn<PgArrayHKT, T,
6767
notNull: T['notNull'];
6868
hasDefault: T['hasDefault'];
6969
data: Assume<T['data'], unknown[]>[number];
70-
driverParam: Assume<T['driverParam'], unknown[]>[number];
70+
driverParam: string | Assume<T['driverParam'], unknown[]>[number];
7171
}
7272
>,
7373
AnyColumnBuilder
@@ -100,8 +100,15 @@ export class PgArray<T extends ColumnBaseConfig> extends PgColumn<PgArrayHKT, T,
100100
return value.map((v) => this.baseColumn.mapFromDriverValue(v));
101101
}
102102

103-
override mapToDriverValue(value: unknown[]): string {
104-
const a = value.map((v) => v === null ? null : this.baseColumn.mapToDriverValue(v));
103+
override mapToDriverValue(value: unknown[], isNestedArray = false): unknown[] | string {
104+
const a = value.map((v) =>
105+
v === null
106+
? null
107+
: this.baseColumn instanceof PgArray
108+
? this.baseColumn.mapToDriverValue(v as unknown[], true)
109+
: this.baseColumn.mapToDriverValue(v)
110+
);
111+
if (isNestedArray) return a;
105112
return makePgArray(a);
106113
}
107114
}

drizzle-orm/src/pg-core/dialect.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,16 @@ import type { PgDeleteConfig, PgInsertConfig, PgUpdateConfig } from '~/pg-core/q
77
import type { PgSelectConfig, SelectedFieldsOrdered } from '~/pg-core/query-builders/select.types';
88
import type { AnyPgTable } from '~/pg-core/table';
99
import { PgTable } from '~/pg-core/table';
10-
import { type DriverValueEncoder, name, type Query, type QueryTypingsValue, SQL, sql, type SQLChunk } from '~/sql';
10+
import {
11+
type DriverValueEncoder,
12+
name,
13+
Param,
14+
type Query,
15+
type QueryTypingsValue,
16+
SQL,
17+
sql,
18+
type SQLChunk,
19+
} from '~/sql';
1120
import { Subquery, SubqueryConfig } from '~/subquery';
1221
import { getTableName, Table } from '~/table';
1322
import { orderSelectedFields, type UpdateSet } from '~/utils';
@@ -303,7 +312,7 @@ export class PgDialect {
303312
const valueList: (SQLChunk | SQL)[] = [];
304313
for (const [fieldName] of colEntries) {
305314
const colValue = value[fieldName];
306-
if (colValue === undefined) {
315+
if (colValue === undefined || (colValue instanceof Param && colValue.value === undefined)) {
307316
valueList.push(sql`default`);
308317
} else {
309318
valueList.push(colValue);

drizzle-orm/src/pg-core/query-builders/insert.ts

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -34,15 +34,10 @@ export class PgInsertBuilder<TTable extends AnyPgTable, TQueryResult extends Que
3434

3535
values(value: PgInsertValue<TTable>): PgInsert<TTable, TQueryResult>;
3636
values(values: PgInsertValue<TTable>[]): PgInsert<TTable, TQueryResult>;
37-
/**
38-
* @deprecated Pass the array of values without spreading it.
39-
*/
40-
values(...values: PgInsertValue<TTable>[]): PgInsert<TTable, TQueryResult>;
41-
values(
42-
...values: PgInsertValue<TTable>[] | [PgInsertValue<TTable>] | [PgInsertValue<TTable>[]]
43-
): PgInsert<TTable, TQueryResult> {
44-
if (values.length === 1) {
45-
values = Array.isArray(values[0]) ? values[0] : [values[0]];
37+
values(values: PgInsertValue<TTable> | PgInsertValue<TTable>[]): PgInsert<TTable, TQueryResult> {
38+
values = Array.isArray(values) ? values : [values];
39+
if (values.length === 0) {
40+
throw new Error('values() must be called with at least one value');
4641
}
4742
const mappedValues = values.map((entry) => {
4843
const result: Record<string, Param | SQL> = {};

drizzle-orm/src/sqlite-core/dialect.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
import type { AnyColumn } from '~/column';
22
import { Column } from '~/column';
33
import type { MigrationMeta } from '~/migrator';
4-
import { name, param, type Query, SQL, sql, type SQLChunk } from '~/sql';
4+
import { name, Param, param, type Query, SQL, sql, type SQLChunk } from '~/sql';
55
import type { AnySQLiteColumn } from '~/sqlite-core/columns';
66
import type { SQLiteDeleteConfig, SQLiteInsertConfig, SQLiteUpdateConfig } from '~/sqlite-core/query-builders';
77
import type { AnySQLiteTable } from '~/sqlite-core/table';
@@ -257,7 +257,7 @@ export abstract class SQLiteDialect {
257257
const valueList: (SQLChunk | SQL)[] = [];
258258
for (const [fieldName, col] of colEntries) {
259259
const colValue = value[fieldName];
260-
if (colValue === undefined) {
260+
if (colValue === undefined || (colValue instanceof Param && colValue.value === undefined)) {
261261
let defaultValue;
262262
if (col.default !== null && col.default !== undefined) {
263263
defaultValue = col.default instanceof SQL ? col.default : param(col.default, col);

drizzle-orm/src/sqlite-core/query-builders/insert.ts

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -38,15 +38,12 @@ export class SQLiteInsertBuilder<
3838

3939
values(value: SQLiteInsertValue<TTable>): SQLiteInsert<TTable, TResultType, TRunResult>;
4040
values(values: SQLiteInsertValue<TTable>[]): SQLiteInsert<TTable, TResultType, TRunResult>;
41-
/**
42-
* @deprecated Pass the array of values without spreading it.
43-
*/
44-
values(...values: SQLiteInsertValue<TTable>[]): SQLiteInsert<TTable, TResultType, TRunResult>;
4541
values(
46-
...values: SQLiteInsertValue<TTable>[] | [SQLiteInsertValue<TTable>] | [SQLiteInsertValue<TTable>[]]
42+
values: SQLiteInsertValue<TTable> | SQLiteInsertValue<TTable>[],
4743
): SQLiteInsert<TTable, TResultType, TRunResult> {
48-
if (values.length === 1) {
49-
values = Array.isArray(values[0]) ? values[0] : [values[0]];
44+
values = Array.isArray(values) ? values : [values];
45+
if (values.length === 0) {
46+
throw new Error('values() must be called with at least one value');
5047
}
5148
const mappedValues = values.map((entry) => {
5249
const result: Record<string, Param | SQL> = {};

drizzle-orm/src/utils.ts

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -92,16 +92,22 @@ export function orderSelectedFields<TColumn extends AnyColumn>(
9292

9393
/** @internal */
9494
export function mapUpdateSet(table: Table, values: Record<string, unknown>): UpdateSet {
95-
return Object.fromEntries<UpdateSet[string]>(
96-
Object.entries(values).map(([key, value]) => {
95+
const entries: [string, UpdateSet[string]][] = Object.entries(values)
96+
.filter(([, value]) => value !== undefined)
97+
.map(([key, value]) => {
9798
// eslint-disable-next-line unicorn/prefer-ternary
98-
if (value instanceof SQL || value === null || value === undefined) {
99+
if (value instanceof SQL) {
99100
return [key, value];
100101
} else {
101102
return [key, new Param(value, table[Table.Symbol.Columns][key])];
102103
}
103-
}),
104-
);
104+
});
105+
106+
if (entries.length === 0) {
107+
throw new Error('No values to set');
108+
}
109+
110+
return Object.fromEntries(entries);
105111
}
106112

107113
export type UpdateSet = Record<string, SQL | Param | null | undefined>;

drizzle-orm/tests/makePgArray.test.ts

Lines changed: 26 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,21 @@
11
import { describe, it } from 'vitest';
2-
import { makePgArray } from '~/pg-core/utils';
2+
import { customType, pgTable } from '~/pg-core';
3+
4+
const anyColumn = customType<{ data: any }>({
5+
dataType() {
6+
return 'any';
7+
},
8+
});
9+
10+
const table = pgTable('test', {
11+
a: anyColumn('a').array(),
12+
b: anyColumn('a').array().array(),
13+
});
314

415
describe.concurrent('makePgArray', () => {
516
it('parses simple 1D array', ({ expect }) => {
617
const input = ['1', '2', '3'];
7-
const output = makePgArray(input);
18+
const output = table.a.mapToDriverValue(input);
819
expect(output).toEqual('{1,2,3}');
920
});
1021

@@ -14,13 +25,13 @@ describe.concurrent('makePgArray', () => {
1425
['4', '5', '6'],
1526
['7', '8', '9'],
1627
];
17-
const output = makePgArray(input);
28+
const output = table.b.mapToDriverValue(input);
1829
expect(output).toEqual('{{1,2,3},{4,5,6},{7,8,9}}');
1930
});
2031

2132
it('parses array with quoted values', ({ expect }) => {
2233
const input = ['1', '2,3', '4'];
23-
const output = makePgArray(input);
34+
const output = table.a.mapToDriverValue(input);
2435
expect(output).toEqual('{1,"2,3",4}');
2536
});
2637

@@ -29,13 +40,13 @@ describe.concurrent('makePgArray', () => {
2940
['1', '2,3', '4'],
3041
['5', '6,7', '8'],
3142
];
32-
const output = makePgArray(input);
43+
const output = table.b.mapToDriverValue(input);
3344
expect(output).toEqual('{{1,"2,3",4},{5,"6,7",8}}');
3445
});
3546

3647
it('parses array with empty values', ({ expect }) => {
3748
const input = ['1', '', '3'];
38-
const output = makePgArray(input);
49+
const output = table.a.mapToDriverValue(input);
3950
expect(output).toEqual('{1,,3}');
4051
});
4152

@@ -45,43 +56,43 @@ describe.concurrent('makePgArray', () => {
4556
['', '5', '6'],
4657
['7', '8', '9'],
4758
];
48-
const output = makePgArray(input);
59+
const output = table.b.mapToDriverValue(input);
4960
expect(output).toEqual('{{1,2,3},{,5,6},{7,8,9}}');
5061
});
5162

5263
it('parses empty array', ({ expect }) => {
5364
const input: string[] = [];
54-
const output = makePgArray(input);
65+
const output = table.a.mapToDriverValue(input);
5566
expect(output).toEqual('{}');
5667
});
5768

5869
it('parses empty nested array', ({ expect }) => {
5970
const input = [[]];
60-
const output = makePgArray(input);
71+
const output = table.b.mapToDriverValue(input);
6172
expect(output).toEqual('{{}}');
6273
});
6374

6475
it('parses single-level array with strings', ({ expect }) => {
6576
const input = ['one', 'two', 'three'];
66-
const output = makePgArray(input);
77+
const output = table.a.mapToDriverValue(input);
6778
expect(output).toEqual('{one,two,three}');
6879
});
6980

7081
it('parses single-level array with mixed values', ({ expect }) => {
7182
const input = ['1', 'two', '3'];
72-
const output = makePgArray(input);
83+
const output = table.a.mapToDriverValue(input);
7384
expect(output).toEqual('{1,two,3}');
7485
});
7586

7687
it('parses single-level array with commas inside quotes', ({ expect }) => {
7788
const input = ['1', 'two, three', '4'];
78-
const output = makePgArray(input);
89+
const output = table.a.mapToDriverValue(input);
7990
expect(output).toEqual('{1,"two, three",4}');
8091
});
8192

8293
it('parses single-level array with escaped quotes inside quotes', ({ expect }) => {
8394
const input = ['1', 'two "three", four', '5'];
84-
const output = makePgArray(input);
95+
const output = table.a.mapToDriverValue(input);
8596
expect(output).toEqual('{1,"two \\"three\\", four",5}');
8697
});
8798

@@ -91,7 +102,7 @@ describe.concurrent('makePgArray', () => {
91102
['four', 'five', 'six'],
92103
['seven', 'eight', 'nine'],
93104
];
94-
const output = makePgArray(input);
105+
const output = table.b.mapToDriverValue(input);
95106
expect(output).toEqual('{{one,two,three},{four,five,six},{seven,eight,nine}}');
96107
});
97108

@@ -101,7 +112,7 @@ describe.concurrent('makePgArray', () => {
101112
['four', 'five "and a half", six', '6'],
102113
['seven', 'eight', 'nine'],
103114
];
104-
const output = makePgArray(input);
115+
const output = table.b.mapToDriverValue(input);
105116
expect(output).toEqual(
106117
'{{1,"two \\"and a half\\", three",3},{four,"five \\"and a half\\", six",6},{seven,eight,nine}}',
107118
);

0 commit comments

Comments
 (0)