import { all, chunks, placeholders } from "./db";
export type WithAuthorAccount<T> = T & { authorAccount: string | null };
/**
* Lowercased commit email to account name, through verified addresses only (primary or added), so a
* commit is shown as someone's only once they have proven they own the address it was made with.
*/
export async function accountsForEmails(emails: string[]): Promise<Map<string, string>> {
const unique = [...new Set(emails.map((email) => email.trim().toLowerCase()).filter(Boolean))];
const out = new Map<string, string>();
for (const group of chunks(unique, 45)) {
const rows = await all<{ email: string; name: string }>(
`SELECT LOWER(u.email) AS email, a.name FROM users u JOIN accounts a ON a.id = u.account_id
WHERE u.email_verified_at IS NOT NULL AND LOWER(u.email) IN (${placeholders(group.length)})
UNION SELECT LOWER(e.email) AS email, a.name FROM user_emails e JOIN accounts a ON a.id = e.user_id
WHERE e.verified_at IS NOT NULL AND LOWER(e.email) IN (${placeholders(group.length)})`,
...group,
...group,
);
for (const row of rows) out.set(row.email, row.name);
}
return out;
}
/** Adds the account (if any) that owns each commit's author email. */
export async function withAuthorAccounts<T extends { authorEmail?: string }>(
commits: T[],
): Promise<Array<WithAuthorAccount<T>>> {
const accounts = await accountsForEmails(commits.map((commit) => commit.authorEmail ?? ""));
return commits.map((commit) => ({
...commit,
authorAccount: accounts.get((commit.authorEmail ?? "").trim().toLowerCase()) ?? null,
}));
}
export async function withAuthorAccount<T extends { authorEmail?: string }>(commit: T): Promise<WithAuthorAccount<T>> {
const [enriched] = await withAuthorAccounts([commit]);
return enriched;
}