1// compile 2 3// Copyright 2021 The Go Authors. All rights reserved. 4// Use of this source code is governed by a BSD-style 5// license that can be found in the LICENSE file. 6 7package main 8 9import ( 10 "database/sql" 11) 12 13// Collection generic interface which things can be added to. 14type Collection[T any] interface { 15 Add(T) 16} 17 18// Slice generic slice implementation of a Collection 19type Slice[T any] []*T 20 21func (s *Slice[T]) Add(t *T) { 22 *s = append(*s, t) 23} 24 25type Scanner interface { 26 Scan(...interface{}) error 27} 28 29type Mapper[T any] func(s Scanner, t T) error 30 31type Repository[T any] struct { 32 db *sql.DB 33} 34 35func (r *Repository[T]) scan(rows *sql.Rows, m Mapper[*T], c Collection[*T]) error { 36 for rows.Next() { 37 t := new(T) 38 if err := m(rows, t); err != nil { 39 return err 40 } 41 c.Add(t) 42 } 43 return rows.Err() 44} 45 46func (r *Repository[T]) query(query string, m Mapper[*T], c Collection[*T]) error { 47 rows, err := r.db.Query(query) 48 if err != nil { 49 return err 50 } 51 if err := r.scan(rows, m, c); err != nil { 52 rows.Close() 53 return err 54 } 55 return rows.Close() 56} 57 58type Actor struct { 59 ActorID uint16 60 FirstName string 61 LastName string 62} 63 64type ActorRepository struct { 65 r Repository[Actor] 66} 67 68func (ActorRepository) scan(s Scanner, a *Actor) error { 69 return s.Scan(&a.ActorID, &a.FirstName, &a.LastName) 70} 71 72func (r *ActorRepository) SelectAll(c Collection[*Actor]) error { 73 return r.r.query("SELECT `actor_id`, `first_name`, `last_name` FROM `actor` LIMIT 10", r.scan, c) 74} 75