feat: add target deletion functionality with cascaded removal of associated jobs and tasks
This commit is contained in:
+81
-2
@@ -2,6 +2,7 @@ package db
|
||||
|
||||
import (
|
||||
"database/sql"
|
||||
"fmt"
|
||||
"math"
|
||||
"regexp"
|
||||
"strings"
|
||||
@@ -83,6 +84,86 @@ func (db *DB) UpdateTargetCrawledAt(id int64) error {
|
||||
return err
|
||||
}
|
||||
|
||||
func (db *DB) DeleteTarget(id int64) (*SearchTarget, int64, error) {
|
||||
tx, err := db.Begin()
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer func() { _ = tx.Rollback() }()
|
||||
|
||||
// 1. Get target info before deleting
|
||||
var target SearchTarget
|
||||
var lastCrawled sql.NullTime
|
||||
err = tx.QueryRow(`SELECT id, name, target_url, platform, is_active, last_crawled_at FROM search_targets WHERE id = ?`, id).Scan(
|
||||
&target.ID, &target.Name, &target.TargetURL, &target.Platform, &target.IsActive, &lastCrawled,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
if lastCrawled.Valid {
|
||||
target.LastCrawledAt = &lastCrawled.Time
|
||||
}
|
||||
|
||||
// 2. Find all raw_jobs IDs associated with this target
|
||||
rows, err := tx.Query(`SELECT id, canonical_id FROM raw_jobs WHERE target_id = ?`, id)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
var rawJobIDs []int64
|
||||
var canonicalIDs []string
|
||||
for rows.Next() {
|
||||
var rID int64
|
||||
var cID string
|
||||
if err := rows.Scan(&rID, &cID); err != nil {
|
||||
_ = rows.Close()
|
||||
return nil, 0, err
|
||||
}
|
||||
rawJobIDs = append(rawJobIDs, rID)
|
||||
canonicalIDs = append(canonicalIDs, cID)
|
||||
}
|
||||
_ = rows.Close()
|
||||
|
||||
// 3. Delete tasks referencing this target or its discovered jobs
|
||||
targetIDPattern := fmt.Sprintf(`%%"target_id":%d%%`, id)
|
||||
targetIDPatternStr := fmt.Sprintf(`%%"target_id": %d%%`, id)
|
||||
_, _ = tx.Exec(`DELETE FROM tasks WHERE payload LIKE ? OR payload LIKE ?`, targetIDPattern, targetIDPatternStr)
|
||||
|
||||
for _, cid := range canonicalIDs {
|
||||
cPattern := fmt.Sprintf(`%%"canonical_id":"%s"%%`, cid)
|
||||
_, _ = tx.Exec(`DELETE FROM tasks WHERE payload LIKE ?`, cPattern)
|
||||
}
|
||||
for _, rID := range rawJobIDs {
|
||||
rPattern := fmt.Sprintf(`%%"raw_job_id":%d%%`, rID)
|
||||
rPatternStr := fmt.Sprintf(`%%"raw_job_id": %d%%`, rID)
|
||||
_, _ = tx.Exec(`DELETE FROM tasks WHERE payload LIKE ? OR payload LIKE ?`, rPattern, rPatternStr)
|
||||
}
|
||||
|
||||
// 4. Delete job_applications and job_analyses for these raw_jobs
|
||||
for _, rID := range rawJobIDs {
|
||||
_, _ = tx.Exec(`DELETE FROM job_applications WHERE raw_job_id = ?`, rID)
|
||||
_, _ = tx.Exec(`DELETE FROM job_analyses WHERE raw_job_id = ?`, rID)
|
||||
}
|
||||
|
||||
// 5. Delete raw_jobs for this target
|
||||
res, err := tx.Exec(`DELETE FROM raw_jobs WHERE target_id = ?`, id)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
deletedJobsCount, _ := res.RowsAffected()
|
||||
|
||||
// 6. Delete search_target
|
||||
_, err = tx.Exec(`DELETE FROM search_targets WHERE id = ?`, id)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
if err := tx.Commit(); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
return &target, deletedJobsCount, nil
|
||||
}
|
||||
|
||||
// Raw Jobs Queries & Vector Similarity Deduplication
|
||||
func (db *DB) InsertRawJob(canonicalID string, targetID *int64, title, company, location, applyURL, rawContent string) (*RawJob, bool, error) {
|
||||
// Deduplication Check 1 & 2: Check canonical_id exist AND vector similarity >= 99%
|
||||
@@ -207,8 +288,6 @@ func tokenizeToVector(text string) map[string]int {
|
||||
return freqMap
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Job Analyses Queries
|
||||
func (db *DB) CreateJobAnalysis(rawJobID int64, score float64, isQualified bool, status string) error {
|
||||
query := `
|
||||
|
||||
Reference in New Issue
Block a user