Skip to content

Commit 0389d8f

Browse files
committed
fix: wrap user UPDATE in CTE so the postgres command tag doesn't show as a fake id
`UPDATE … RETURNING id` causes psql to emit both the row ids and the protocol-level command tag (`UPDATE 1`) on stdout, even under `-A -t`. The split-by-newline parser counted the command-tag line as an extra match and reported `2 users matched "you@example"` against a single-row update. Wrap the UPDATE in a CTE so the outer query is a SELECT, which `-t` does strip cleanly. The "multiple matches" warning now fires only when there really are multiple rows for that email.
1 parent dfb4860 commit 0389d8f

1 file changed

Lines changed: 6 additions & 1 deletion

File tree

packages/cli/src/commands/users.ts

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,12 @@ async function updateUserByEmail(opts: UpdateUserOptions): Promise<string[]> {
108108
throw new Error(`"${opts.email}" does not look like an email address`);
109109
}
110110
const target = await resolvePostgresTarget(opts.rootDir);
111-
const sql = `UPDATE "user" SET ${opts.setClause} WHERE email = ${quoteSqlLiteral(opts.email)} RETURNING id;`;
111+
// Wrap the UPDATE in a CTE and SELECT the returned ids in a separate step.
112+
// A bare `UPDATE … RETURNING` makes psql emit both the row ids AND the
113+
// protocol-level command tag (`UPDATE <n>`) on stdout, even under `-A -t`,
114+
// so the naive split-by-newline used to falsely report N+1 matches. The
115+
// CTE turns the final result into a SELECT, which `-t` does strip cleanly.
116+
const sql = `WITH updated AS (UPDATE "user" SET ${opts.setClause} WHERE email = ${quoteSqlLiteral(opts.email)} RETURNING id) SELECT id FROM updated;`;
112117
const stdout = await execPsql(target, sql, opts.rootDir);
113118
const ids = stdout
114119
.split("\n")

0 commit comments

Comments
 (0)