(identifiers: {
slack_user_id?: string;
workos_user_id?: string;
email?: string;
prospect_org_id?: string;
display_name?: string;
})
| 72 | * Returns the person ID (UUID). |
| 73 | */ |
| 74 | export async function resolvePersonId(identifiers: { |
| 75 | slack_user_id?: string; |
| 76 | workos_user_id?: string; |
| 77 | email?: string; |
| 78 | prospect_org_id?: string; |
| 79 | display_name?: string; |
| 80 | }): Promise<string> { |
| 81 | const client = await getClient(); |
| 82 | try { |
| 83 | await client.query('BEGIN'); |
| 84 | |
| 85 | const conditions: string[] = []; |
| 86 | const params: unknown[] = []; |
| 87 | |
| 88 | if (identifiers.slack_user_id) { |
| 89 | params.push(identifiers.slack_user_id); |
| 90 | conditions.push(`slack_user_id = $${params.length}`); |
| 91 | } |
| 92 | if (identifiers.workos_user_id) { |
| 93 | params.push(identifiers.workos_user_id); |
| 94 | conditions.push(`workos_user_id = $${params.length}`); |
| 95 | } |
| 96 | if (identifiers.email) { |
| 97 | params.push(identifiers.email); |
| 98 | conditions.push(`email = $${params.length}`); |
| 99 | } |
| 100 | |
| 101 | let existing: Record<string, unknown> | undefined; |
| 102 | let mergedPersonIds: string[] = []; |
| 103 | let identityLinkedData: Record<string, string> | null = null; |
| 104 | |
| 105 | if (conditions.length > 0) { |
| 106 | const result = await client.query( |
| 107 | `SELECT * FROM person_relationships WHERE ${conditions.join(' OR ')} FOR UPDATE`, |
| 108 | params |
| 109 | ); |
| 110 | |
| 111 | if (result.rows.length > 1) { |
| 112 | // Multiple rows matched different identifiers — need to merge. |
| 113 | // Pick the oldest record as the winner (most history). |
| 114 | const sorted = result.rows.sort( |
| 115 | (a, b) => new Date(a.created_at as string).getTime() - new Date(b.created_at as string).getTime() |
| 116 | ); |
| 117 | const winner = sorted[0]; |
| 118 | const losers = sorted.slice(1); |
| 119 | |
| 120 | // Absorb loser fields the winner doesn't have |
| 121 | for (const loser of losers) { |
| 122 | const fieldUpdates: string[] = []; |
| 123 | const fieldParams: unknown[] = []; |
| 124 | let fi = 1; |
| 125 | |
| 126 | // Identity fields |
| 127 | if (!winner.slack_user_id && loser.slack_user_id) { |
| 128 | fieldUpdates.push(`slack_user_id = $${fi++}`); |
| 129 | fieldParams.push(loser.slack_user_id); |
| 130 | winner.slack_user_id = loser.slack_user_id; |
| 131 | } |
no test coverage detected