github.com/google/syzkaller@v0.0.0-20251211124644-a066d2bc4b02/syz-cluster/pkg/db/report_reply_repo.go (about) 1 // Copyright 2025 syzkaller project authors. All rights reserved. 2 // Use of this source code is governed by Apache 2 LICENSE that can be found in the LICENSE file. 3 4 package db 5 6 import ( 7 "context" 8 "errors" 9 10 "cloud.google.com/go/spanner" 11 ) 12 13 type ReportReplyRepository struct { 14 client *spanner.Client 15 } 16 17 func NewReportReplyRepository(client *spanner.Client) *ReportReplyRepository { 18 return &ReportReplyRepository{ 19 client: client, 20 } 21 } 22 23 func (repo *ReportReplyRepository) FindParentReportID(ctx context.Context, reporter, messageID string) (string, error) { 24 type result struct { 25 ReportID string `spanner:"ReportID"` 26 } 27 ret, err := readEntity[result](ctx, repo.client.Single(), spanner.Statement{ 28 SQL: "SELECT `ReportReplies`.ReportID FROM `ReportReplies` " + 29 "JOIN `SessionReports` ON `SessionReports`.ID = `ReportReplies`.ReportID " + 30 "WHERE `ReportReplies`.MessageID = @messageID " + 31 "AND `SessionReports`.Reporter = @reporter LIMIT 1", 32 Params: map[string]interface{}{ 33 "reporter": reporter, 34 "messageID": messageID, 35 }, 36 }) 37 if err != nil { 38 return "", err 39 } else if ret != nil { 40 return ret.ReportID, nil 41 } 42 return "", nil 43 } 44 45 var ErrReportReplyExists = errors.New("the reply has already been recorded") 46 47 func (repo *ReportReplyRepository) Insert(ctx context.Context, reply *ReportReply) error { 48 _, err := repo.client.ReadWriteTransaction(ctx, 49 func(ctx context.Context, txn *spanner.ReadWriteTransaction) error { 50 entity, err := readEntity[ReportReply](ctx, txn, spanner.Statement{ 51 SQL: "SELECT * from `ReportReplies` " + 52 "WHERE `ReportID`=@reportID AND `MessageID`=@messageID", 53 Params: map[string]interface{}{ 54 "reportID": reply.ReportID, 55 "messageID": reply.MessageID, 56 }, 57 }) 58 if err != nil { 59 return err 60 } else if entity != nil { 61 return ErrReportReplyExists 62 } 63 insert, err := spanner.InsertStruct("ReportReplies", reply) 64 if err != nil { 65 return err 66 } 67 return txn.BufferWrite([]*spanner.Mutation{insert}) 68 }) 69 return err 70 } 71 72 func (repo *ReportReplyRepository) LastForReporter(ctx context.Context, reporter string) (*ReportReply, error) { 73 return readEntity[ReportReply](ctx, repo.client.Single(), spanner.Statement{ 74 SQL: "SELECT `ReportReplies`.* FROM `ReportReplies` " + 75 "JOIN `SessionReports` ON `SessionReports`.ID=`ReportReplies`.ReportID " + 76 "WHERE `SessionReports`.Reporter=@reporter " + 77 "ORDER BY `Time` DESC LIMIT 1", 78 Params: map[string]interface{}{ 79 "reporter": reporter, 80 }, 81 }) 82 }