* Rollback a property to a previous revision.
(
domain: string,
toRevisionNumber: number,
editor: { user_id: string; email?: string; name?: string }
)
| 695 | * Rollback a property to a previous revision. |
| 696 | */ |
| 697 | async rollbackProperty( |
| 698 | domain: string, |
| 699 | toRevisionNumber: number, |
| 700 | editor: { user_id: string; email?: string; name?: string } |
| 701 | ): Promise<{ property: HostedProperty; revision_number: number }> { |
| 702 | const client = await getClient(); |
| 703 | try { |
| 704 | await client.query('BEGIN'); |
| 705 | |
| 706 | // Get target revision |
| 707 | const targetResult = await client.query<{ snapshot: string }>( |
| 708 | 'SELECT snapshot FROM property_revisions WHERE publisher_domain = $1 AND revision_number = $2', |
| 709 | [domain.toLowerCase(), toRevisionNumber] |
| 710 | ); |
| 711 | if (targetResult.rows.length === 0) { |
| 712 | throw new Error(`Revision ${toRevisionNumber} not found for ${domain}`); |
| 713 | } |
| 714 | |
| 715 | const snapshot = typeof targetResult.rows[0].snapshot === 'string' |
| 716 | ? JSON.parse(targetResult.rows[0].snapshot) |
| 717 | : targetResult.rows[0].snapshot; |
| 718 | |
| 719 | // Lock current row |
| 720 | const currentResult = await client.query<HostedProperty>( |
| 721 | 'SELECT * FROM hosted_properties WHERE publisher_domain = $1 FOR UPDATE', |
| 722 | [domain.toLowerCase()] |
| 723 | ); |
| 724 | if (currentResult.rows.length === 0) { |
| 725 | throw new Error(`Property not found: ${domain}`); |
| 726 | } |
| 727 | |
| 728 | // Get next revision number |
| 729 | const revResult = await client.query<{ next_rev: number }>( |
| 730 | 'SELECT COALESCE(MAX(revision_number), 0) + 1 as next_rev FROM property_revisions WHERE publisher_domain = $1', |
| 731 | [domain.toLowerCase()] |
| 732 | ); |
| 733 | const revisionNumber = revResult.rows[0].next_rev; |
| 734 | |
| 735 | // Create rollback revision |
| 736 | await client.query( |
| 737 | `INSERT INTO property_revisions ( |
| 738 | publisher_domain, revision_number, snapshot, |
| 739 | editor_user_id, editor_email, editor_name, |
| 740 | edit_summary, is_rollback, rolled_back_to |
| 741 | ) VALUES ($1, $2, $3, $4, $5, $6, $7, true, $8)`, |
| 742 | [ |
| 743 | domain.toLowerCase(), |
| 744 | revisionNumber, |
| 745 | JSON.stringify(currentResult.rows[0]), |
| 746 | editor.user_id, |
| 747 | editor.email || null, |
| 748 | editor.name || null, |
| 749 | `Rollback to revision ${toRevisionNumber}`, |
| 750 | toRevisionNumber, |
| 751 | ] |
| 752 | ); |
| 753 | |
| 754 | // Restore from snapshot |
no test coverage detected