From d45400dceaae2a075a2fc59167b1710e32e588fb Mon Sep 17 00:00:00 2001 From: Yasuhiro SHIMIZU Date: Sat, 17 Feb 2024 11:41:53 +0900 Subject: [PATCH 1/5] add execlastid implementation for mysql --- Makefile | 2 +- examples/authors/mysql/query.sql | 11 ++- examples/bun-mysql2/src/db/query_sql.ts | 22 ++++- examples/node-mysql2/src/db/query_sql.ts | 22 ++++- src/app.ts | 16 +++- src/drivers/mysql2.ts | 109 +++++++++++++++++++++++ 6 files changed, 175 insertions(+), 7 deletions(-) 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..c6708f5 100644 --- a/examples/bun-mysql2/src/db/query_sql.ts +++ b/examples/bun-mysql2/src/db/query_sql.ts @@ -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..c6708f5 100644 --- a/examples/node-mysql2/src/db/query_sql.ts +++ b/examples/node-mysql2/src/db/query_sql.ts @@ -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..cd029f8 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, @@ -78,10 +84,10 @@ function createNodeGenerator(driver?: string): Driver { return mysql2; } case "pg": { - return pg; + return pg as any; } case "postgres": { - return postgres; + return postgres as any; } case "better-sqlite3": { return betterSQLite3; @@ -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/mysql2.ts b/src/drivers/mysql2.ts index d6f943b..7e399dd 100644 --- a/src/drivers/mysql2.ts +++ b/src/drivers/mysql2.ts @@ -178,6 +178,11 @@ export function preamble(queries: unknown) { undefined, factory.createIdentifier("RowDataPacket") ), + factory.createImportSpecifier( + false, + undefined, + factory.createIdentifier("ResultSetHeader") + ), ]) ), factory.createStringLiteral("mysql2/promise"), @@ -611,10 +616,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, }; From de5bc8650f6d3dc42a8e74b9e0cdac2053b0f2de Mon Sep 17 00:00:00 2001 From: yshrsmz Date: Sun, 3 Mar 2024 12:45:18 +0900 Subject: [PATCH 2/5] pg and postgress driver should throw on unsupported execlastid command --- src/app.ts | 4 ++-- src/drivers/pg.ts | 12 +++++++++++- src/drivers/postgres.ts | 12 +++++++++++- 3 files changed, 24 insertions(+), 4 deletions(-) diff --git a/src/app.ts b/src/app.ts index cd029f8..36e1ddd 100644 --- a/src/app.ts +++ b/src/app.ts @@ -84,10 +84,10 @@ function createNodeGenerator(driver?: string): Driver { return mysql2; } case "pg": { - return pg as any; + return pg; } case "postgres": { - return postgres as any; + return postgres; } case "better-sqlite3": { return betterSQLite3; diff --git a/src/drivers/pg.ts b/src/drivers/pg.ts index db6936d..5239995 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 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..8ecd974 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 does not support :execlastid') +} + export default { columnType, preamble, execDecl, manyDecl, oneDecl, + execlastidDecl }; From 3bd92d26312d915421492ee23c864bc7bac72806 Mon Sep 17 00:00:00 2001 From: yshrsmz Date: Sun, 3 Mar 2024 12:45:39 +0900 Subject: [PATCH 3/5] only import ResultSetHeader if execlastid query exists --- src/drivers/mysql2.ts | 27 ++++++++++++++++----------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/src/drivers/mysql2.ts b/src/drivers/mysql2.ts index 7e399dd..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,11 +179,15 @@ export function preamble(queries: unknown) { undefined, factory.createIdentifier("RowDataPacket") ), - factory.createImportSpecifier( - false, - undefined, - factory.createIdentifier("ResultSetHeader") - ), + ...(hasExecLastIdCmd + ? [ + factory.createImportSpecifier( + false, + undefined, + factory.createIdentifier("ResultSetHeader") + ), + ] + : []), ]) ), factory.createStringLiteral("mysql2/promise"), @@ -634,7 +639,7 @@ export function execlastidDecl( undefined, funcParams, factory.createTypeReferenceNode(factory.createIdentifier("Promise"), [ - factory.createTypeReferenceNode('number', undefined), + factory.createTypeReferenceNode("number", undefined), ]), factory.createBlock( [ @@ -663,7 +668,7 @@ export function execlastidDecl( factory.createTypeReferenceNode( factory.createIdentifier("ResultSetHeader"), undefined - ) + ), ], [ factory.createObjectLiteralExpression( @@ -692,7 +697,7 @@ export function execlastidDecl( ] ) ) - ) + ), ], NodeFlags.Const | // NodeFlags.Constant | @@ -716,7 +721,7 @@ export function execlastidDecl( ], true ) - ) + ); } export default { From 08e4b7a1f2217daf1bd451138882f9fe20bf27fa Mon Sep 17 00:00:00 2001 From: yshrsmz Date: Sun, 3 Mar 2024 13:27:16 +0900 Subject: [PATCH 4/5] add throwing execlastidDecl to better-sqlite3 driver --- src/drivers/better-sqlite3.ts | 12 +++++++++++- src/drivers/pg.ts | 2 +- src/drivers/postgres.ts | 2 +- 3 files changed, 13 insertions(+), 3 deletions(-) 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/pg.ts b/src/drivers/pg.ts index 5239995..9272035 100644 --- a/src/drivers/pg.ts +++ b/src/drivers/pg.ts @@ -784,7 +784,7 @@ export function execlastidDecl( argIface: string | undefined, params: Parameter[] ): FunctionDeclaration { - throw new Error('pg driver does not support :execlastid') + throw new Error('pg driver currently does not support :execlastid') } export default { diff --git a/src/drivers/postgres.ts b/src/drivers/postgres.ts index 8ecd974..f9d7bc8 100644 --- a/src/drivers/postgres.ts +++ b/src/drivers/postgres.ts @@ -608,7 +608,7 @@ export function execlastidDecl( argIface: string | undefined, params: Parameter[] ): FunctionDeclaration { - throw new Error('postgres driver does not support :execlastid') + throw new Error('postgres driver currently does not support :execlastid') } export default { From c2dee38a6a82fefac1d9a860d5b68ec34a136d58 Mon Sep 17 00:00:00 2001 From: yshrsmz Date: Sun, 3 Mar 2024 13:25:29 +0900 Subject: [PATCH 5/5] update examples --- examples/bun-mysql2/src/db/query_sql.ts | 2 +- examples/node-mysql2/src/db/query_sql.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/bun-mysql2/src/db/query_sql.ts b/examples/bun-mysql2/src/db/query_sql.ts index c6708f5..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; diff --git a/examples/node-mysql2/src/db/query_sql.ts b/examples/node-mysql2/src/db/query_sql.ts index c6708f5..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;