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