go.chromium.org/luci@v0.0.0-20240309015107-7cdc2e660f33/analysis/internal/aip/orderby_generator.go (about) 1 // Copyright 2022 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 aip 16 17 import ( 18 "fmt" 19 "strings" 20 ) 21 22 // MergeWithDefaultOrder merges the specified order with the given 23 // defaultOrder. The merge occurs as follows: 24 // - Ordering specified in `order` takes precedence. 25 // - For columns not specified in the `order` that appear in `defaultOrder`, 26 // ordering is applied in the order they apply in defaultOrder. 27 func MergeWithDefaultOrder(defaultOrder []OrderBy, order []OrderBy) []OrderBy { 28 result := make([]OrderBy, 0, len(order)+len(defaultOrder)) 29 seenColumns := make(map[string]struct{}) 30 for _, o := range order { 31 result = append(result, o) 32 seenColumns[o.FieldPath.String()] = struct{}{} 33 } 34 for _, o := range defaultOrder { 35 if _, ok := seenColumns[o.FieldPath.String()]; !ok { 36 result = append(result, o) 37 } 38 } 39 return result 40 } 41 42 // OrderByClause returns a Standard SQL Order by clause, including 43 // "ORDER BY" and trailing new line (if an order is specified). 44 // If no order is specified, returns "". 45 // 46 // The returned order clause is safe against SQL injection; only 47 // strings appearing from Table appear in the output. 48 func (t *Table) OrderByClause(order []OrderBy) (string, error) { 49 if len(order) == 0 { 50 return "", nil 51 } 52 seenColumns := make(map[string]struct{}) 53 var result strings.Builder 54 result.WriteString("ORDER BY ") 55 for i, o := range order { 56 if i > 0 { 57 result.WriteString(", ") 58 } 59 column, err := t.SortableColumnByFieldPath(o.FieldPath) 60 if err != nil { 61 return "", err 62 } 63 if _, ok := seenColumns[column.databaseName]; ok { 64 return "", fmt.Errorf("field appears in order_by multiple times: %q", o.FieldPath.String()) 65 } 66 seenColumns[column.databaseName] = struct{}{} 67 result.WriteString(column.databaseName) 68 if o.Descending { 69 result.WriteString(" DESC") 70 } 71 } 72 result.WriteString("\n") 73 return result.String(), nil 74 }