Skip to content
go-libfossil Artifact [23e21c79eb]
Login

Artifact [23e21c79eb]

Artifact 23e21c79ebd9f8965769c8a7f73a76620f926acf6f9553307d65e21545c25549:


package sync

import (
	"fmt"

	"github.com/danmestas/go-libfossil/db"
	"github.com/danmestas/go-libfossil/internal/repo"
)

// applyXDeleteLocally applies an xdelete to the local repo. Calls DeleteXRowByPKHash first;
// if the row doesn't exist, inserts a tombstone from pkData. Returns nil on success.
func applyXDeleteLocally(d *db.DB, table string, def repo.TableDef, pkHash string, mtime int64, pkData []byte) error {
	deleted, err := repo.DeleteXRowByPKHash(d, table, def, pkHash, mtime)
	if err != nil {
		return fmt.Errorf("applyXDeleteLocally: delete %s/%s: %w", table, pkHash, err)
	}
	if deleted {
		return nil
	}

	// Row didn't exist or had newer mtime. Check which case.
	existingRow, _, err := repo.LookupXRow(d, table, def, pkHash)
	if err != nil {
		return fmt.Errorf("applyXDeleteLocally: lookup %s/%s: %w", table, pkHash, err)
	}
	if existingRow != nil {
		return nil // Row exists with newer mtime — no-op.
	}

	// Row doesn't exist. Insert tombstone from PKData.
	if len(pkData) == 0 {
		return nil // No PKData — can't create tombstone.
	}
	pkValues, err := decodeRowJSON(pkData, def)
	if err != nil {
		return fmt.Errorf("applyXDeleteLocally: decode PKData %s/%s: %w", table, pkHash, err)
	}

	// Verify PKData matches declared PKHash.
	var pkColDefs []repo.ColumnDef
	for _, col := range def.Columns {
		if col.PK {
			pkColDefs = append(pkColDefs, col)
		}
	}
	computedHash := repo.PKHash(pkColDefs, pkValues)
	if computedHash != pkHash {
		return fmt.Errorf("applyXDeleteLocally: PKData hash mismatch %s/%s: computed %s", table, pkHash, computedHash)
	}

	if err := repo.UpsertXRow(d, table, pkValues, mtime); err != nil {
		return fmt.Errorf("applyXDeleteLocally: insert tombstone %s/%s: %w", table, pkHash, err)
	}
	return nil
}