go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/resultdb/internal/testmetadata/test_metadata.go (about) 1 // Copyright 2023 The LUCI Authors. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 // Package testmetadata implements methods to query from TestMetadata spanner table. 16 package testmetadata 17 18 import ( 19 "context" 20 "time" 21 22 "cloud.google.com/go/spanner" 23 "go.chromium.org/luci/resultdb/internal/spanutil" 24 "go.chromium.org/luci/resultdb/pbutil" 25 pb "go.chromium.org/luci/resultdb/proto/v1" 26 "google.golang.org/protobuf/proto" 27 ) 28 29 // TestMetadataRow represents a row in the TestMetadata table. 30 type TestMetadataRow struct { 31 Project string 32 TestID string 33 RefHash []byte 34 SubRealm string 35 LastUpdated time.Time 36 TestMetadata *pb.TestMetadata 37 SourceRef *pb.SourceRef 38 Position int64 39 } 40 41 // ReadTestMetadataOptions is the input for the ReadTestMetadata function. 42 type ReadTestMetadataOptions struct { 43 Project string 44 SubRealm string 45 TestIDs []string 46 SourceRef *pb.SourceRef 47 } 48 49 // ReadTestMetadata read rows from TestMetadata table. 50 func ReadTestMetadata(ctx context.Context, opts ReadTestMetadataOptions, f func(*TestMetadataRow) error) error { 51 st := spanner.NewStatement(` 52 SELECT 53 tm.Project, 54 tm.TestId, 55 tm.RefHash, 56 tm.SubRealm, 57 tm.LastUpdated, 58 tm.SourceRef, 59 tm.TestMetadata, 60 tm.Position, 61 FROM TestMetadata tm 62 WHERE tm.Project = @project 63 AND tm.TestId in UNNEST(@testIDs) 64 AND tm.RefHash = @refHash 65 AND tm.SubRealm = @subRealm`) 66 st.Params = spanutil.ToSpannerMap(map[string]any{ 67 "project": opts.Project, 68 "testIDs": opts.TestIDs, 69 "refHash": pbutil.SourceRefHash(opts.SourceRef), 70 "subRealm": opts.SubRealm, 71 }) 72 var b spanutil.Buffer 73 return spanutil.Query(ctx, st, func(row *spanner.Row) error { 74 tmd := &TestMetadataRow{} 75 var compressedTestMetadata spanutil.Compressed 76 var compressedSourceRef spanutil.Compressed 77 if err := b.FromSpanner(row, 78 &tmd.Project, 79 &tmd.TestID, 80 &tmd.RefHash, 81 &tmd.SubRealm, 82 &tmd.LastUpdated, 83 &compressedSourceRef, 84 &compressedTestMetadata, 85 &tmd.Position); err != nil { 86 return err 87 } 88 tmd.TestMetadata = &pb.TestMetadata{} 89 if err := proto.Unmarshal(compressedTestMetadata, tmd.TestMetadata); err != nil { 90 return err 91 } 92 tmd.SourceRef = &pb.SourceRef{} 93 if err := proto.Unmarshal(compressedSourceRef, tmd.SourceRef); err != nil { 94 return err 95 } 96 return f(tmd) 97 }) 98 }