|  | //  compile | 
|  |  | 
|  | // Copyright 2021 The Go Authors. All rights reserved. | 
|  | // Use of this source code is governed by a BSD-style | 
|  | // license that can be found in the LICENSE file. | 
|  |  | 
|  | package main | 
|  |  | 
|  | import ( | 
|  | "database/sql" | 
|  | ) | 
|  |  | 
|  | // Collection generic interface which things can be added to. | 
|  | type Collection[T any] interface { | 
|  | Add(T) | 
|  | } | 
|  |  | 
|  | // Slice generic slice implementation of a Collection | 
|  | type Slice[T any] []*T | 
|  |  | 
|  | func (s *Slice[T]) Add(t *T) { | 
|  | *s = append(*s, t) | 
|  | } | 
|  |  | 
|  | type Scanner interface { | 
|  | Scan(...interface{}) error | 
|  | } | 
|  |  | 
|  | type Mapper[T any] func(s Scanner, t T) error | 
|  |  | 
|  | type Repository[T any] struct { | 
|  | db *sql.DB | 
|  | } | 
|  |  | 
|  | func (r *Repository[T]) scan(rows *sql.Rows, m Mapper[*T], c Collection[*T]) error { | 
|  | for rows.Next() { | 
|  | t := new(T) | 
|  | if err := m(rows, t); err != nil { | 
|  | return err | 
|  | } | 
|  | c.Add(t) | 
|  | } | 
|  | return rows.Err() | 
|  | } | 
|  |  | 
|  | func (r *Repository[T]) query(query string, m Mapper[*T], c Collection[*T]) error { | 
|  | rows, err := r.db.Query(query) | 
|  | if err != nil { | 
|  | return err | 
|  | } | 
|  | if err := r.scan(rows, m, c); err != nil { | 
|  | rows.Close() | 
|  | return err | 
|  | } | 
|  | return rows.Close() | 
|  | } | 
|  |  | 
|  | type Actor struct { | 
|  | ActorID   uint16 | 
|  | FirstName string | 
|  | LastName  string | 
|  | } | 
|  |  | 
|  | type ActorRepository struct { | 
|  | r Repository[Actor] | 
|  | } | 
|  |  | 
|  | func (ActorRepository) scan(s Scanner, a *Actor) error { | 
|  | return s.Scan(&a.ActorID, &a.FirstName, &a.LastName) | 
|  | } | 
|  |  | 
|  | func (r *ActorRepository) SelectAll(c Collection[*Actor]) error { | 
|  | return r.r.query("SELECT `actor_id`, `first_name`, `last_name` FROM `actor` LIMIT 10", r.scan, c) | 
|  | } |