diff --git a/Makefile b/Makefile index 45c89dc..8ab6195 100644 --- a/Makefile +++ b/Makefile @@ -12,4 +12,4 @@ out.js: src/app.ts $(wildcard src/drivers/*.ts) src/gen/plugin/codegen_pb.ts npx esbuild --bundle src/app.ts --tree-shaking=true --format=esm --target=es2020 --outfile=out.js src/gen/plugin/codegen_pb.ts: buf.gen.yaml - buf generate --template buf.gen.yaml buf.build/sqlc/sqlc --path plugin/ \ No newline at end of file + buf generate --template buf.gen.yaml buf.build/sqlc/sqlc --path plugin/ diff --git a/examples/authors/mysql/query.sql b/examples/authors/mysql/query.sql index 158c8e5..94c51b9 100644 --- a/examples/authors/mysql/query.sql +++ b/examples/authors/mysql/query.sql @@ -10,7 +10,14 @@ ORDER BY name; INSERT INTO authors ( name, bio ) VALUES ( - ?, ? + ?, ? +); + +/* name: CreateAuthorReturnId :execlastid */ +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? ); /* name: DeleteAuthor :exec */ @@ -19,4 +26,4 @@ WHERE id = ?; /* name: Test :one */ SELECT * FROM node_mysql_types -LIMIT 1; \ No newline at end of file +LIMIT 1; diff --git a/examples/bun-mysql2/src/db/query_sql.ts b/examples/bun-mysql2/src/db/query_sql.ts index 475f7bf..1673007 100644 --- a/examples/bun-mysql2/src/db/query_sql.ts +++ b/examples/bun-mysql2/src/db/query_sql.ts @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. -import mysql, { RowDataPacket } from "mysql2/promise"; +import mysql, { RowDataPacket, ResultSetHeader } from "mysql2/promise"; type Client = mysql.Connection | mysql.Pool; @@ -64,7 +64,7 @@ export const createAuthorQuery = `-- name: CreateAuthor :exec INSERT INTO authors ( name, bio ) VALUES ( - ?, ? + ?, ? )`; export interface CreateAuthorArgs { @@ -79,6 +79,26 @@ export async function createAuthor(client: Client, args: CreateAuthorArgs): Prom }); } +export const createAuthorReturnIdQuery = `-- name: CreateAuthorReturnId :execlastid +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +)`; + +export interface CreateAuthorReturnIdArgs { + name: string; + bio: string | null; +} + +export async function createAuthorReturnId(client: Client, args: CreateAuthorReturnIdArgs): Promise { + const [result] = await client.query({ + sql: createAuthorReturnIdQuery, + values: [args.name, args.bio] + }); + return result?.insertId ?? 0; +} + export const deleteAuthorQuery = `-- name: DeleteAuthor :exec DELETE FROM authors WHERE id = ?`; diff --git a/examples/node-mysql2/src/db/query_sql.ts b/examples/node-mysql2/src/db/query_sql.ts index 475f7bf..1673007 100644 --- a/examples/node-mysql2/src/db/query_sql.ts +++ b/examples/node-mysql2/src/db/query_sql.ts @@ -1,6 +1,6 @@ // Code generated by sqlc. DO NOT EDIT. -import mysql, { RowDataPacket } from "mysql2/promise"; +import mysql, { RowDataPacket, ResultSetHeader } from "mysql2/promise"; type Client = mysql.Connection | mysql.Pool; @@ -64,7 +64,7 @@ export const createAuthorQuery = `-- name: CreateAuthor :exec INSERT INTO authors ( name, bio ) VALUES ( - ?, ? + ?, ? )`; export interface CreateAuthorArgs { @@ -79,6 +79,26 @@ export async function createAuthor(client: Client, args: CreateAuthorArgs): Prom }); } +export const createAuthorReturnIdQuery = `-- name: CreateAuthorReturnId :execlastid +INSERT INTO authors ( + name, bio +) VALUES ( + ?, ? +)`; + +export interface CreateAuthorReturnIdArgs { + name: string; + bio: string | null; +} + +export async function createAuthorReturnId(client: Client, args: CreateAuthorReturnIdArgs): Promise { + const [result] = await client.query({ + sql: createAuthorReturnIdQuery, + values: [args.name, args.bio] + }); + return result?.insertId ?? 0; +} + export const deleteAuthorQuery = `-- name: DeleteAuthor :exec DELETE FROM authors WHERE id = ?`; diff --git a/src/app.ts b/src/app.ts index 7f8a9e6..36e1ddd 100644 --- a/src/app.ts +++ b/src/app.ts @@ -54,6 +54,12 @@ interface Driver { iface: string | undefined, params: Parameter[] ) => Node; + execlastidDecl: ( + name: string, + text: string, + iface: string | undefined, + params: Parameter[] + ) => Node; manyDecl: ( name: string, text: string, @@ -160,6 +166,12 @@ ${query.text}` ); break; } + case ":execlastid": { + nodes.push( + driver.execlastidDecl(lowerName, textName, argIface, query.params) + ) + break; + } case ":one": { nodes.push( driver.oneDecl( diff --git a/src/drivers/better-sqlite3.ts b/src/drivers/better-sqlite3.ts index 7e2f9c3..8665b91 100644 --- a/src/drivers/better-sqlite3.ts +++ b/src/drivers/better-sqlite3.ts @@ -1,4 +1,4 @@ -import { SyntaxKind, NodeFlags, Node, TypeNode, factory } from "typescript"; +import { SyntaxKind, NodeFlags, Node, TypeNode, factory, FunctionDeclaration } from "typescript"; import { Parameter, Column, Query } from "../gen/plugin/codegen_pb"; import { argName } from "./utlis"; @@ -427,10 +427,20 @@ export function manyDecl( ); } +export function execlastidDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + params: Parameter[] +): FunctionDeclaration { + throw new Error('better-sqlite3 driver currently does not support :execlastid') +} + export default { columnType, execDecl, manyDecl, oneDecl, preamble, + execlastidDecl, }; diff --git a/src/drivers/mysql2.ts b/src/drivers/mysql2.ts index d6f943b..bc052bb 100644 --- a/src/drivers/mysql2.ts +++ b/src/drivers/mysql2.ts @@ -2,7 +2,7 @@ import { SyntaxKind, NodeFlags, TypeNode, factory } from "typescript"; // import { writeFileSync, STDIO } from "javy/fs"; -import { Parameter, Column } from "../gen/plugin/codegen_pb"; +import { Parameter, Column, Query } from "../gen/plugin/codegen_pb"; import { argName, colName } from "./utlis"; export function columnType(column?: Column): TypeNode { @@ -165,7 +165,8 @@ export function columnType(column?: Column): TypeNode { ]); } -export function preamble(queries: unknown) { +export function preamble(queries: Query[]) { + const hasExecLastIdCmd = queries.some((query) => query.cmd === ":execlastid"); return [ factory.createImportDeclaration( undefined, @@ -178,6 +179,15 @@ export function preamble(queries: unknown) { undefined, factory.createIdentifier("RowDataPacket") ), + ...(hasExecLastIdCmd + ? [ + factory.createImportSpecifier( + false, + undefined, + factory.createIdentifier("ResultSetHeader") + ), + ] + : []), ]) ), factory.createStringLiteral("mysql2/promise"), @@ -611,10 +621,114 @@ export function oneDecl( ); } +export function execlastidDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + params: Parameter[] +) { + const funcParams = funcParamsDecl(argIface, params); + + return factory.createFunctionDeclaration( + [ + factory.createToken(SyntaxKind.ExportKeyword), + factory.createToken(SyntaxKind.AsyncKeyword), + ], + undefined, + factory.createIdentifier(funcName), + undefined, + funcParams, + factory.createTypeReferenceNode(factory.createIdentifier("Promise"), [ + factory.createTypeReferenceNode("number", undefined), + ]), + factory.createBlock( + [ + factory.createVariableStatement( + undefined, + factory.createVariableDeclarationList( + [ + factory.createVariableDeclaration( + factory.createArrayBindingPattern([ + factory.createBindingElement( + undefined, + undefined, + factory.createIdentifier("result"), + undefined + ), + ]), + undefined, + undefined, + factory.createAwaitExpression( + factory.createCallExpression( + factory.createPropertyAccessExpression( + factory.createIdentifier("client"), + factory.createIdentifier("query") + ), + [ + factory.createTypeReferenceNode( + factory.createIdentifier("ResultSetHeader"), + undefined + ), + ], + [ + factory.createObjectLiteralExpression( + [ + factory.createPropertyAssignment( + factory.createIdentifier("sql"), + factory.createIdentifier(queryName) + ), + factory.createPropertyAssignment( + factory.createIdentifier("values"), + factory.createArrayLiteralExpression( + params.map((param, i) => + factory.createPropertyAccessExpression( + factory.createIdentifier("args"), + factory.createIdentifier( + argName(i, param.column) + ) + ) + ), + false + ) + ), + ], + true + ), + ] + ) + ) + ), + ], + NodeFlags.Const | + // NodeFlags.Constant | + NodeFlags.AwaitContext | + // NodeFlags.Constant | + NodeFlags.ContextFlags | + NodeFlags.TypeExcludesFlags + ) + ), + factory.createReturnStatement( + factory.createBinaryExpression( + factory.createPropertyAccessChain( + factory.createIdentifier("result"), + factory.createToken(SyntaxKind.QuestionDotToken), + factory.createIdentifier("insertId") + ), + factory.createToken(SyntaxKind.QuestionQuestionToken), + factory.createNumericLiteral(0) + ) + ), + ], + true + ) + ); +} + export default { columnType, preamble, execDecl, manyDecl, oneDecl, + execlastidDecl, }; diff --git a/src/drivers/pg.ts b/src/drivers/pg.ts index db6936d..9272035 100644 --- a/src/drivers/pg.ts +++ b/src/drivers/pg.ts @@ -1,4 +1,4 @@ -import { SyntaxKind, NodeFlags, Node, TypeNode, factory } from "typescript"; +import { SyntaxKind, NodeFlags, Node, TypeNode, factory, FunctionDeclaration } from "typescript"; import { Parameter, Column, Query } from "../gen/plugin/codegen_pb"; import { argName, colName } from "./utlis"; @@ -778,10 +778,20 @@ export function manyDecl( ); } +export function execlastidDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + params: Parameter[] +): FunctionDeclaration { + throw new Error('pg driver currently does not support :execlastid') +} + export default { columnType, execDecl, manyDecl, oneDecl, preamble, + execlastidDecl, }; diff --git a/src/drivers/postgres.ts b/src/drivers/postgres.ts index 1a2b575..f9d7bc8 100644 --- a/src/drivers/postgres.ts +++ b/src/drivers/postgres.ts @@ -1,4 +1,4 @@ -import { SyntaxKind, NodeFlags, TypeNode, factory } from "typescript"; +import { SyntaxKind, NodeFlags, TypeNode, factory, FunctionDeclaration } from "typescript"; import { Parameter, Column } from "../gen/plugin/codegen_pb"; import { argName, colName } from "./utlis"; @@ -602,10 +602,20 @@ export function oneDecl( ); } +export function execlastidDecl( + funcName: string, + queryName: string, + argIface: string | undefined, + params: Parameter[] +): FunctionDeclaration { + throw new Error('postgres driver currently does not support :execlastid') +} + export default { columnType, preamble, execDecl, manyDecl, oneDecl, + execlastidDecl };