A website inspired by Last.fm that will keep track of your listening statistics
lastfm music statistics
at main 95 lines 2.5 kB view raw
1package database 2 3import ( 4 "context" 5 "database/sql" 6 "strings" 7) 8 9func AppendMany[T any](args []any, values []T) []any { 10 for _, value := range values { 11 args = append(args, value) 12 } 13 return args 14} 15 16// QueryMany executes a query and returns a slice of results. It is a small helper function reducing 17// the boilerplate code needed to execute a query and scan the results. The scanFunc is used to scan 18// each row into a result. 19func QueryMany[T any]( 20 ctx context.Context, db *sql.DB, query string, args []any, scanFunc func(*sql.Rows) (T, error), 21) ([]T, error) { 22 rows, err := db.QueryContext(ctx, query, args...) 23 if err != nil { 24 return nil, err 25 } 26 defer rows.Close() 27 28 var results []T 29 for rows.Next() { 30 result, err := scanFunc(rows) 31 if err != nil { 32 return nil, err 33 } 34 results = append(results, result) 35 } 36 return results, nil 37} 38 39// QueryOne executes a query and returns a single result. It is a small helper function reducing the 40// boilerplate code needed to execute a query and scan the results. The scanFunc is used to scan 41// the row into a result. 42func QueryOne[T any]( 43 ctx context.Context, db *sql.DB, query string, args []any, scanFunc func(*sql.Rows) (T, error), 44) (T, error) { 45 rows, err := db.QueryContext(ctx, query, args...) 46 if err != nil { 47 return *new(T), err 48 } 49 defer rows.Close() 50 51 if !rows.Next() { 52 return *new(T), nil 53 } 54 55 return scanFunc(rows) 56} 57 58// Generates a string of placeholders for a SQL query. For example, if count is 3, the result will 59// be "?, ?, ?". 60func Placeholders(count int) string { 61 placeholders := make([]string, count) 62 for i := range placeholders { 63 placeholders[i] = "?" 64 } 65 return strings.Join(placeholders, ", ") 66} 67 68type Condition struct { 69 SQL string 70 Value any 71 Ok bool 72} 73 74// Takes a list of where strings and argument values together with a list of conditions. Those 75// conditions that are Ok will be added to the list of where strings and argument values. Useful 76// when having optional conditionals that used to filter a query. 77func Where(wheres []string, args []any, conditions ...Condition) ([]string, []any) { 78 for _, v := range conditions { 79 if v.Ok { 80 wheres = append(wheres, v.SQL) 81 args = append(args, v.Value) 82 } 83 } 84 return wheres, args 85} 86 87// Takes a list of SQL condition snippets and joins them with AND. If the list is empty, returns 88// TRUE. 89func WhereSQL(wheres []string) string { 90 where := "TRUE" 91 if len(wheres) > 0 { 92 where = strings.Join(wheres, " AND ") 93 } 94 return where 95}