summary history files

internal/store/metric.go
package store

import (
	"context"
	"database/sql"
)

// MetricStorer manages metrics.
type MetricStorer interface {
	Create(context.Context, string) (*Metric, error)
	SelectOne(context.Context, string) (*Metric, error)
	SelectLimit(context.Context, int64) ([]Metric, error)
	Delete(context.Context, int64) error
}

// MetricStore manages metrics.
type MetricStore struct {
	DB *sql.DB
}

// Delete deletes a metric by id.
func (s MetricStore) Delete(ctx context.Context, metricID int64) error {
	tx, err := s.DB.BeginTx(ctx, nil)
	if err != nil {
		return err
	}
	defer tx.Rollback()

	stmt, err := tx.PrepareContext(ctx, "DELETE FROM metric WHERE id = ?")
	if err != nil {
		return err
	}

	_, err = stmt.ExecContext(ctx, metricID)
	if err != nil {
		return err
	}

	return tx.Commit()
}

// Create creates a new metric.
func (s MetricStore) Create(ctx context.Context, metricName string) (*Metric, error) {
	tx, err := s.DB.BeginTx(ctx, nil)
	if err != nil {
		return nil, err
	}
	defer tx.Rollback()

	stmt, err := tx.PrepareContext(ctx, "INSERT INTO metric (id, name) VALUES (NULL, ?)")
	if err != nil {
		return nil, err
	}

	res, err := stmt.ExecContext(ctx, metricName)
	if err != nil {
		return nil, err
	}

	if err = tx.Commit(); err != nil {
		return nil, err
	}

	metric := &Metric{Name: metricName}

	metric.MetricID, err = res.LastInsertId()
	if err != nil {
		return nil, err
	}

	return metric, nil
}

// SelectLimit returns all metric rows up to limit. A limit of 0 is no limit.
func (s MetricStore) SelectLimit(ctx context.Context, limit int64) ([]Metric, error) {

	tx, err := s.DB.BeginTx(ctx, nil)
	if err != nil {
		return nil, err
	}
	defer tx.Rollback()

	var ret []Metric
	var rows *sql.Rows

	if limit == 0 {
		rows, err = tx.QueryContext(ctx, "SELECT id, name FROM metric ORDER BY name")
		if err != nil {
			return nil, err
		}
	} else {
		rows, err = tx.QueryContext(ctx, "SELECT id, name FROM metric ORDER BY name LIMIT ?", limit)
		if err != nil {
			return nil, err
		}
	}
	defer rows.Close()

	for rows.Next() {
		var o Metric
		if err = rows.Scan(&o.MetricID, &o.Name); err != nil {
			return nil, err
		}
		ret = append(ret, o)
	}

	if err := rows.Err(); err != nil {
		return nil, err
	}

	return ret, tx.Commit()
}

// SelectOne returns a single metric.
func (s MetricStore) SelectOne(ctx context.Context, metricName string) (*Metric, error) {
	tx, err := s.DB.BeginTx(ctx, nil)
	if err != nil {
		return nil, err
	}
	defer tx.Rollback()

	var ret Metric
	err = tx.QueryRowContext(ctx, "SELECT id, name FROM metric WHERE name = ?", metricName).Scan(&ret.MetricID, &ret.Name)
	if err != nil && err != sql.ErrNoRows {
		return nil, err
	}
	if err != nil && err == sql.ErrNoRows {
		return nil, ErrNotFound
	}

	return &ret, tx.Commit()
}