Skip to content

Commit

Permalink
Merge pull request #2759 from veloii/main
Browse files Browse the repository at this point in the history
Fix placeholders being mapped to it's driver value instead of the value
  • Loading branch information
AndriiSherman authored Aug 7, 2024
2 parents cd71182 + bfc0cf6 commit d486e9b
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 16 deletions.
15 changes: 14 additions & 1 deletion drizzle-orm/src/sql/sql.ts
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,11 @@ export class SQL<T = unknown> implements SQLWrapper {
}

if (is(chunk, Param)) {
const mappedValue = (chunk.value === null) ? null : chunk.encoder.mapToDriverValue(chunk.value);
if (is(chunk.value, Placeholder)) {
return { sql: escapeParam(paramStartIndex.value++, chunk), params: [chunk], typings: ['none'] };
}

const mappedValue = chunk.value === null ? null : chunk.encoder.mapToDriverValue(chunk.value);

if (is(mappedValue, SQL)) {
return this.buildQueryFromSourceParams([mappedValue], config);
Expand Down Expand Up @@ -583,9 +587,18 @@ export function fillPlaceholders(params: unknown[], values: Record<string, unkno
if (!(p.name in values)) {
throw new Error(`No value for placeholder "${p.name}" was provided`);
}

return values[p.name];
}

if (is(p, Param) && is(p.value, Placeholder)) {
if (!(p.value.name in values)) {
throw new Error(`No value for placeholder "${p.value.name}" was provided`);
}

return p.encoder.mapToDriverValue(values[p.value.name]);
}

return p;
});
}
Expand Down
24 changes: 24 additions & 0 deletions integration-tests/tests/mysql/mysql-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1155,6 +1155,30 @@ export function tests(driver?: string) {
expect(result).toEqual([{ id: 1, name: 'John' }]);
});

test('insert: placeholders on columns with encoder', async (ctx) => {
const { db } = ctx.mysql;

const date = new Date('2024-08-07T15:30:00Z');

const statement = db.insert(usersTable).values({
name: 'John',
createdAt: sql.placeholder('createdAt'),
}).prepare();

await statement.execute({ createdAt: date });

const result = await db
.select({
id: usersTable.id,
createdAt: usersTable.createdAt,
})
.from(usersTable);

expect(result).toEqual([
{ id: 1, createdAt: date },
]);
});

test('prepared statement reuse', async (ctx) => {
const { db } = ctx.mysql;

Expand Down
24 changes: 23 additions & 1 deletion integration-tests/tests/pg/pg-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -253,7 +253,7 @@ export function tests() {
create table users (
id serial primary key,
name text not null,
verified boolean not null default false,
verified boolean not null default false,
jsonb jsonb,
created_at timestamptz not null default now()
)
Expand Down Expand Up @@ -1133,6 +1133,28 @@ export function tests() {
expect(result).toEqual([{ id: 1, name: 'John' }]);
});

test('insert: placeholders on columns with encoder', async (ctx) => {
const { db } = ctx.pg;

const statement = db.insert(usersTable).values({
name: 'John',
jsonb: sql.placeholder('jsonb'),
}).prepare('encoder_statement');

await statement.execute({ jsonb: ['foo', 'bar'] });

const result = await db
.select({
id: usersTable.id,
jsonb: usersTable.jsonb,
})
.from(usersTable);

expect(result).toEqual([
{ id: 1, jsonb: ['foo', 'bar'] },
]);
});

test('prepared statement reuse', async (ctx) => {
const { db } = ctx.pg;

Expand Down
46 changes: 32 additions & 14 deletions integration-tests/tests/sqlite/sqlite-common.ts
Original file line number Diff line number Diff line change
Expand Up @@ -844,10 +844,7 @@ export function tests() {
test('prepared statement reuse', async (ctx) => {
const { db } = ctx.sqlite;

const stmt = db.insert(usersTable).values({
verified: true,
name: sql.placeholder('name'),
}).prepare();
const stmt = db.insert(usersTable).values({ name: sql.placeholder('name') }).prepare();

for (let i = 0; i < 10; i++) {
await stmt.run({ name: `John ${i}` });
Expand All @@ -856,20 +853,41 @@ export function tests() {
const result = await db.select({
id: usersTable.id,
name: usersTable.name,
}).from(usersTable).all();

expect(result).toEqual([
{ id: 1, name: 'John 0' },
{ id: 2, name: 'John 1' },
{ id: 3, name: 'John 2' },
{ id: 4, name: 'John 3' },
{ id: 5, name: 'John 4' },
{ id: 6, name: 'John 5' },
{ id: 7, name: 'John 6' },
{ id: 8, name: 'John 7' },
{ id: 9, name: 'John 8' },
{ id: 10, name: 'John 9' },
]);
});

test('insert: placeholders on columns with encoder', async (ctx) => {
const { db } = ctx.sqlite;

const stmt = db.insert(usersTable).values({
name: 'John',
verified: sql.placeholder('verified'),
}).prepare();

await stmt.run({ verified: true });
await stmt.run({ verified: false });

const result = await db.select({
id: usersTable.id,
verified: usersTable.verified,
}).from(usersTable).all();

expect(result).toEqual([
{ id: 1, name: 'John 0', verified: true },
{ id: 2, name: 'John 1', verified: true },
{ id: 3, name: 'John 2', verified: true },
{ id: 4, name: 'John 3', verified: true },
{ id: 5, name: 'John 4', verified: true },
{ id: 6, name: 'John 5', verified: true },
{ id: 7, name: 'John 6', verified: true },
{ id: 8, name: 'John 7', verified: true },
{ id: 9, name: 'John 8', verified: true },
{ id: 10, name: 'John 9', verified: true },
{ id: 1, verified: true },
{ id: 2, verified: false },
]);
});

Expand Down

0 comments on commit d486e9b

Please sign in to comment.