// 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) }