Skip to content

Commit b79c5fa

Browse files
authored
feat(mysql): Add :execlastid implementation for mysql (#13)
* add execlastid implementation for mysql * pg and postgress driver should throw on unsupported execlastid command * only import ResultSetHeader if execlastid query exists * add throwing execlastidDecl to better-sqlite3 driver * update examples
1 parent 0134a95 commit b79c5fa

File tree

9 files changed

+215
-12
lines changed

9 files changed

+215
-12
lines changed

Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,4 @@ out.js: src/app.ts $(wildcard src/drivers/*.ts) src/gen/plugin/codegen_pb.ts
1212
npx esbuild --bundle src/app.ts --tree-shaking=true --format=esm --target=es2020 --outfile=out.js
1313

1414
src/gen/plugin/codegen_pb.ts: buf.gen.yaml
15-
buf generate --template buf.gen.yaml buf.build/sqlc/sqlc --path plugin/
15+
buf generate --template buf.gen.yaml buf.build/sqlc/sqlc --path plugin/

examples/authors/mysql/query.sql

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,14 @@ ORDER BY name;
1010
INSERT INTO authors (
1111
name, bio
1212
) VALUES (
13-
?, ?
13+
?, ?
14+
);
15+
16+
/* name: CreateAuthorReturnId :execlastid */
17+
INSERT INTO authors (
18+
name, bio
19+
) VALUES (
20+
?, ?
1421
);
1522

1623
/* name: DeleteAuthor :exec */
@@ -19,4 +26,4 @@ WHERE id = ?;
1926

2027
/* name: Test :one */
2128
SELECT * FROM node_mysql_types
22-
LIMIT 1;
29+
LIMIT 1;

examples/bun-mysql2/src/db/query_sql.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Code generated by sqlc. DO NOT EDIT.
22

3-
import mysql, { RowDataPacket } from "mysql2/promise";
3+
import mysql, { RowDataPacket, ResultSetHeader } from "mysql2/promise";
44

55
type Client = mysql.Connection | mysql.Pool;
66

@@ -64,7 +64,7 @@ export const createAuthorQuery = `-- name: CreateAuthor :exec
6464
INSERT INTO authors (
6565
name, bio
6666
) VALUES (
67-
?, ?
67+
?, ?
6868
)`;
6969

7070
export interface CreateAuthorArgs {
@@ -79,6 +79,26 @@ export async function createAuthor(client: Client, args: CreateAuthorArgs): Prom
7979
});
8080
}
8181

82+
export const createAuthorReturnIdQuery = `-- name: CreateAuthorReturnId :execlastid
83+
INSERT INTO authors (
84+
name, bio
85+
) VALUES (
86+
?, ?
87+
)`;
88+
89+
export interface CreateAuthorReturnIdArgs {
90+
name: string;
91+
bio: string | null;
92+
}
93+
94+
export async function createAuthorReturnId(client: Client, args: CreateAuthorReturnIdArgs): Promise<number> {
95+
const [result] = await client.query<ResultSetHeader>({
96+
sql: createAuthorReturnIdQuery,
97+
values: [args.name, args.bio]
98+
});
99+
return result?.insertId ?? 0;
100+
}
101+
82102
export const deleteAuthorQuery = `-- name: DeleteAuthor :exec
83103
DELETE FROM authors
84104
WHERE id = ?`;

examples/node-mysql2/src/db/query_sql.ts

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
// Code generated by sqlc. DO NOT EDIT.
22

3-
import mysql, { RowDataPacket } from "mysql2/promise";
3+
import mysql, { RowDataPacket, ResultSetHeader } from "mysql2/promise";
44

55
type Client = mysql.Connection | mysql.Pool;
66

@@ -64,7 +64,7 @@ export const createAuthorQuery = `-- name: CreateAuthor :exec
6464
INSERT INTO authors (
6565
name, bio
6666
) VALUES (
67-
?, ?
67+
?, ?
6868
)`;
6969

7070
export interface CreateAuthorArgs {
@@ -79,6 +79,26 @@ export async function createAuthor(client: Client, args: CreateAuthorArgs): Prom
7979
});
8080
}
8181

82+
export const createAuthorReturnIdQuery = `-- name: CreateAuthorReturnId :execlastid
83+
INSERT INTO authors (
84+
name, bio
85+
) VALUES (
86+
?, ?
87+
)`;
88+
89+
export interface CreateAuthorReturnIdArgs {
90+
name: string;
91+
bio: string | null;
92+
}
93+
94+
export async function createAuthorReturnId(client: Client, args: CreateAuthorReturnIdArgs): Promise<number> {
95+
const [result] = await client.query<ResultSetHeader>({
96+
sql: createAuthorReturnIdQuery,
97+
values: [args.name, args.bio]
98+
});
99+
return result?.insertId ?? 0;
100+
}
101+
82102
export const deleteAuthorQuery = `-- name: DeleteAuthor :exec
83103
DELETE FROM authors
84104
WHERE id = ?`;

src/app.ts

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,12 @@ interface Driver {
5454
iface: string | undefined,
5555
params: Parameter[]
5656
) => Node;
57+
execlastidDecl: (
58+
name: string,
59+
text: string,
60+
iface: string | undefined,
61+
params: Parameter[]
62+
) => Node;
5763
manyDecl: (
5864
name: string,
5965
text: string,
@@ -160,6 +166,12 @@ ${query.text}`
160166
);
161167
break;
162168
}
169+
case ":execlastid": {
170+
nodes.push(
171+
driver.execlastidDecl(lowerName, textName, argIface, query.params)
172+
)
173+
break;
174+
}
163175
case ":one": {
164176
nodes.push(
165177
driver.oneDecl(

src/drivers/better-sqlite3.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SyntaxKind, NodeFlags, Node, TypeNode, factory } from "typescript";
1+
import { SyntaxKind, NodeFlags, Node, TypeNode, factory, FunctionDeclaration } from "typescript";
22

33
import { Parameter, Column, Query } from "../gen/plugin/codegen_pb";
44
import { argName } from "./utlis";
@@ -427,10 +427,20 @@ export function manyDecl(
427427
);
428428
}
429429

430+
export function execlastidDecl(
431+
funcName: string,
432+
queryName: string,
433+
argIface: string | undefined,
434+
params: Parameter[]
435+
): FunctionDeclaration {
436+
throw new Error('better-sqlite3 driver currently does not support :execlastid')
437+
}
438+
430439
export default {
431440
columnType,
432441
execDecl,
433442
manyDecl,
434443
oneDecl,
435444
preamble,
445+
execlastidDecl,
436446
};

src/drivers/mysql2.ts

Lines changed: 116 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ import { SyntaxKind, NodeFlags, TypeNode, factory } from "typescript";
22

33
// import { writeFileSync, STDIO } from "javy/fs";
44

5-
import { Parameter, Column } from "../gen/plugin/codegen_pb";
5+
import { Parameter, Column, Query } from "../gen/plugin/codegen_pb";
66
import { argName, colName } from "./utlis";
77

88
export function columnType(column?: Column): TypeNode {
@@ -165,7 +165,8 @@ export function columnType(column?: Column): TypeNode {
165165
]);
166166
}
167167

168-
export function preamble(queries: unknown) {
168+
export function preamble(queries: Query[]) {
169+
const hasExecLastIdCmd = queries.some((query) => query.cmd === ":execlastid");
169170
return [
170171
factory.createImportDeclaration(
171172
undefined,
@@ -178,6 +179,15 @@ export function preamble(queries: unknown) {
178179
undefined,
179180
factory.createIdentifier("RowDataPacket")
180181
),
182+
...(hasExecLastIdCmd
183+
? [
184+
factory.createImportSpecifier(
185+
false,
186+
undefined,
187+
factory.createIdentifier("ResultSetHeader")
188+
),
189+
]
190+
: []),
181191
])
182192
),
183193
factory.createStringLiteral("mysql2/promise"),
@@ -611,10 +621,114 @@ export function oneDecl(
611621
);
612622
}
613623

624+
export function execlastidDecl(
625+
funcName: string,
626+
queryName: string,
627+
argIface: string | undefined,
628+
params: Parameter[]
629+
) {
630+
const funcParams = funcParamsDecl(argIface, params);
631+
632+
return factory.createFunctionDeclaration(
633+
[
634+
factory.createToken(SyntaxKind.ExportKeyword),
635+
factory.createToken(SyntaxKind.AsyncKeyword),
636+
],
637+
undefined,
638+
factory.createIdentifier(funcName),
639+
undefined,
640+
funcParams,
641+
factory.createTypeReferenceNode(factory.createIdentifier("Promise"), [
642+
factory.createTypeReferenceNode("number", undefined),
643+
]),
644+
factory.createBlock(
645+
[
646+
factory.createVariableStatement(
647+
undefined,
648+
factory.createVariableDeclarationList(
649+
[
650+
factory.createVariableDeclaration(
651+
factory.createArrayBindingPattern([
652+
factory.createBindingElement(
653+
undefined,
654+
undefined,
655+
factory.createIdentifier("result"),
656+
undefined
657+
),
658+
]),
659+
undefined,
660+
undefined,
661+
factory.createAwaitExpression(
662+
factory.createCallExpression(
663+
factory.createPropertyAccessExpression(
664+
factory.createIdentifier("client"),
665+
factory.createIdentifier("query")
666+
),
667+
[
668+
factory.createTypeReferenceNode(
669+
factory.createIdentifier("ResultSetHeader"),
670+
undefined
671+
),
672+
],
673+
[
674+
factory.createObjectLiteralExpression(
675+
[
676+
factory.createPropertyAssignment(
677+
factory.createIdentifier("sql"),
678+
factory.createIdentifier(queryName)
679+
),
680+
factory.createPropertyAssignment(
681+
factory.createIdentifier("values"),
682+
factory.createArrayLiteralExpression(
683+
params.map((param, i) =>
684+
factory.createPropertyAccessExpression(
685+
factory.createIdentifier("args"),
686+
factory.createIdentifier(
687+
argName(i, param.column)
688+
)
689+
)
690+
),
691+
false
692+
)
693+
),
694+
],
695+
true
696+
),
697+
]
698+
)
699+
)
700+
),
701+
],
702+
NodeFlags.Const |
703+
// NodeFlags.Constant |
704+
NodeFlags.AwaitContext |
705+
// NodeFlags.Constant |
706+
NodeFlags.ContextFlags |
707+
NodeFlags.TypeExcludesFlags
708+
)
709+
),
710+
factory.createReturnStatement(
711+
factory.createBinaryExpression(
712+
factory.createPropertyAccessChain(
713+
factory.createIdentifier("result"),
714+
factory.createToken(SyntaxKind.QuestionDotToken),
715+
factory.createIdentifier("insertId")
716+
),
717+
factory.createToken(SyntaxKind.QuestionQuestionToken),
718+
factory.createNumericLiteral(0)
719+
)
720+
),
721+
],
722+
true
723+
)
724+
);
725+
}
726+
614727
export default {
615728
columnType,
616729
preamble,
617730
execDecl,
618731
manyDecl,
619732
oneDecl,
733+
execlastidDecl,
620734
};

src/drivers/pg.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SyntaxKind, NodeFlags, Node, TypeNode, factory } from "typescript";
1+
import { SyntaxKind, NodeFlags, Node, TypeNode, factory, FunctionDeclaration } from "typescript";
22

33
import { Parameter, Column, Query } from "../gen/plugin/codegen_pb";
44
import { argName, colName } from "./utlis";
@@ -778,10 +778,20 @@ export function manyDecl(
778778
);
779779
}
780780

781+
export function execlastidDecl(
782+
funcName: string,
783+
queryName: string,
784+
argIface: string | undefined,
785+
params: Parameter[]
786+
): FunctionDeclaration {
787+
throw new Error('pg driver currently does not support :execlastid')
788+
}
789+
781790
export default {
782791
columnType,
783792
execDecl,
784793
manyDecl,
785794
oneDecl,
786795
preamble,
796+
execlastidDecl,
787797
};

src/drivers/postgres.ts

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import { SyntaxKind, NodeFlags, TypeNode, factory } from "typescript";
1+
import { SyntaxKind, NodeFlags, TypeNode, factory, FunctionDeclaration } from "typescript";
22

33
import { Parameter, Column } from "../gen/plugin/codegen_pb";
44
import { argName, colName } from "./utlis";
@@ -602,10 +602,20 @@ export function oneDecl(
602602
);
603603
}
604604

605+
export function execlastidDecl(
606+
funcName: string,
607+
queryName: string,
608+
argIface: string | undefined,
609+
params: Parameter[]
610+
): FunctionDeclaration {
611+
throw new Error('postgres driver currently does not support :execlastid')
612+
}
613+
605614
export default {
606615
columnType,
607616
preamble,
608617
execDecl,
609618
manyDecl,
610619
oneDecl,
620+
execlastidDecl
611621
};

0 commit comments

Comments
 (0)