code/client/model.go (105 lines of code) (raw):
package main
import (
"context"
"fmt"
"go.mongodb.org/mongo-driver/bson"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
)
type trainer struct {
Name string `json:"name"`
Age int `json:"age"`
City string `json:"city"`
}
type trainerCRUDer interface {
load(context.Context, []trainer) error
list(context.Context) ([]*trainer, error)
create(context.Context, trainer) error
delete(context.Context, trainer) error
update(context.Context, trainer, trainer) error
}
type trainerCollection interface {
InsertMany(context.Context, []interface{}, ...*options.InsertManyOptions) (*mongo.InsertManyResult, error)
InsertOne(context.Context, interface{}, ...*options.InsertOneOptions) (*mongo.InsertOneResult, error)
DeleteOne(context.Context, interface{}, ...*options.DeleteOptions) (*mongo.DeleteResult, error)
ReplaceOne(context.Context, interface{}, interface{}, ...*options.ReplaceOptions) (*mongo.UpdateResult, error)
Find(context.Context, interface{}, ...*options.FindOptions) (cur *mongo.Cursor, err error)
}
type trainerService struct {
collection trainerCollection
}
// newTrainerService spins up a new TrainerManager for interacting with MongoDB.
func newTrainerService(ctx context.Context, host, port string) (*trainerService, error) {
uri := fmt.Sprintf("mongodb://%s:%s", host, port)
clientOptions := options.Client().ApplyURI(uri)
client, err := mongo.Connect(ctx, clientOptions)
if err != nil {
return nil, fmt.Errorf("error connecting to mongo: %w", err)
}
collection := client.Database("test").Collection("trainers")
svc := &trainerService{
collection: collection,
}
if err := initData(ctx, svc); err != nil {
return nil, fmt.Errorf("error initializing data: %w", err)
}
return svc, nil
}
func initData(ctx context.Context, svc trainerCRUDer) error {
trainers := []trainer{
{Name: "Ash", Age: 20, City: "Pallet Town"},
{Name: "Misty", Age: 22, City: "Cerulean City"},
{Name: "Brock", Age: 35, City: "Pewter City"},
}
return svc.load(ctx, trainers)
}
// load pushes a collection of trainers into a mongoDB instance
func (svc *trainerService) load(ctx context.Context, trainers []trainer) error {
t := make([]interface{}, len(trainers))
for i, tdata := range trainers {
t[i] = tdata
}
list, err := svc.list(ctx)
if err != nil {
return fmt.Errorf("error checking before loading to mongo: %w", err)
}
if len(list) > 0 {
return nil
}
if _, err := svc.collection.InsertMany(ctx, t); err != nil {
return fmt.Errorf("error inserting records to mongo: %w", err)
}
return nil
}
func (svc *trainerService) create(ctx context.Context, trainer trainer) error {
if _, err := svc.collection.InsertOne(ctx, trainer); err != nil {
return fmt.Errorf("error inserting record to mongo: %w", err)
}
return nil
}
func (svc *trainerService) delete(ctx context.Context, trainer trainer) error {
if _, err := svc.collection.DeleteOne(ctx, trainer); err != nil {
return fmt.Errorf("error inserting record to mongo: %w", err)
}
return nil
}
func (svc *trainerService) update(ctx context.Context, original, replacement trainer) error {
if _, err := svc.collection.ReplaceOne(ctx, original, replacement); err != nil {
return fmt.Errorf("error replacing record in mongo: %w", err)
}
return nil
}
// list retrieves the total collection of trainers from a mongoDB instance
func (svc *trainerService) list(ctx context.Context) ([]*trainer, error) {
var results []*trainer
cur, err := svc.collection.Find(ctx, bson.D{{}}, options.Find())
if err != nil {
return nil, err
}
defer cur.Close(ctx)
for cur.Next(ctx) {
var elem trainer
if err := cur.Decode(&elem); err != nil {
return nil, err
}
results = append(results, &elem)
}
return results, cur.Err()
}