database(feat) add logging

This commit is contained in:
Theo Technicguy 2023-08-22 17:47:10 +02:00
parent 2eb52068f6
commit 3820bd3aa8
Signed by: theo.technicguy
GPG Key ID: 3BC661201BCA53D9
4 changed files with 123 additions and 30 deletions

View File

@ -13,14 +13,17 @@ import (
"errors"
"os"
hlogger "git.licolas.net/hoffman/server/logger"
_ "github.com/mattn/go-sqlite3"
"github.com/rs/zerolog"
)
var (
/* *** Errors *** */
ErrInvalidOperator = errors.New("invalid sql constraint joining operator - must be AND/OR")
sqlSelectLastId = "SELECT last_insert_rowid();"
sqlSelectLastId = "SELECT last_insert_rowid();"
logger zerolog.Logger = hlogger.GetLogger("database")
)
// Database Repository structure
@ -29,6 +32,7 @@ type R struct {
}
func Connect(path string) (*R, error) {
logger.Info().Str("path", path).Msg("connecting to database")
_, errStat := os.Stat(path)
db, errSql := sql.Open("sqlite3", path)
@ -39,6 +43,7 @@ func Connect(path string) (*R, error) {
r := &R{db}
if os.IsNotExist(errStat) {
logger.Debug().Err(errStat).Msg("creating hoffman database")
if err := r.CreateHoffmanDatabase(); err != nil {
return nil, err
}
@ -46,6 +51,7 @@ func Connect(path string) (*R, error) {
return nil, errStat
}
logger.Debug().Str("path", path).Msg("done connecting to database")
return r, nil
}
@ -54,6 +60,7 @@ func Use(db *sql.DB) *R {
}
func (r *R) Disconnect() error {
logger.Info().Msg("disconnecting from database")
return r.db.Close()
}

View File

@ -58,48 +58,57 @@ func convertEANtoSQL(ean uint) *uint {
// convert uint EAN from SQL number
// NULL SQL EANs are mapped to 0 to allow multiple EANless products
// other uints stay the same
func convertEANfromSQL(ean any) (uint, error) {
func convertEANfromSQL(ean any) (e uint, err error) {
logger.Trace().Any("ean", ean).Msg("converting ean from sql equivalent")
switch v := ean.(type) {
case nil:
return 0, nil
e, err = 0, nil
case int:
if v < 0 {
return 0, ErrNegativeEAN
e, err = 0, ErrNegativeEAN
} else {
e, err = uint(v), nil
}
return uint(v), nil
case int8:
if v < 0 {
return 0, ErrNegativeEAN
e, err = 0, ErrNegativeEAN
} else {
e, err = uint(v), nil
}
return uint(v), nil
case int16:
if v < 0 {
return 0, ErrNegativeEAN
e, err = 0, ErrNegativeEAN
} else {
e, err = uint(v), nil
}
return uint(v), nil
case int32:
if v < 0 {
return 0, ErrNegativeEAN
e, err = 0, ErrNegativeEAN
} else {
e, err = uint(v), nil
}
return uint(v), nil
case int64:
if v < 0 {
return 0, ErrNegativeEAN
e, err = 0, ErrNegativeEAN
} else {
e, err = uint(v), nil
}
return uint(v), nil
case uint:
return uint(v), nil
e, err = uint(v), nil
case uint8:
return uint(v), nil
e, err = uint(v), nil
case uint16:
return uint(v), nil
e, err = uint(v), nil
case uint32:
return uint(v), nil
e, err = uint(v), nil
case uint64:
return uint(v), nil
e, err = uint(v), nil
default:
return 0, ErrInvalidEANType
e, err = 0, ErrInvalidEANType
}
logger.Trace().Uint("ean", e).Msg("done converting ean")
return
}
// Scan products from SQL rows into product structures
@ -107,6 +116,7 @@ func convertEANfromSQL(ean any) (uint, error) {
// The first argument is a SQL Transaction pointer. If none (nil) is passed,
// then one is created. The other two arguments are directly passed to tx.Query
func (r *R) scanProducts(tx *sql.Tx, query string, args ...any) ([]*types.Product, error) {
logger.Trace().Bool("transaction", tx != nil).Str("query", query).Any("args", args).Msg("excuting query and scanning products")
if tx == nil {
var err error
tx, err = r.db.Begin()
@ -142,50 +152,61 @@ func (r *R) scanProducts(tx *sql.Tx, query string, args ...any) ([]*types.Produc
return nil, err
}
logger.Trace().Any("ean", ean).Msg("converting ean")
if product.EAN, err = convertEANfromSQL(ean); err != nil {
return nil, err
}
logger.Trace().Uint("product-id", product.Id).Msg("adding tags")
if product.Tags, err = r.SelectProductTaggingByPid(product.Id); err != nil {
return nil, err
}
logger.Trace().Any("product", product).Msg("adding found product")
products = append(products, &product)
}
// This is only a query, no data is modified so there is no need to commit.
logger.Trace().Int("products", len(products)).Msg("done querying and scanning products")
return products, nil
}
// Scan products and assert uniqueness
func (r *R) scanUniqueProduct(tx *sql.Tx, query string, args ...any) (*types.Product, error) {
products, err := r.scanProducts(tx, query, args...)
func (r *R) scanUniqueProduct(tx *sql.Tx, query string, args ...any) (product *types.Product, err error) {
logger.Trace().Bool("transaction", tx != nil).Str("query", query).Any("args", args).Msg("excuting query and scanning one product")
products, err := r.scanProducts(tx, query, args...)
if err != nil {
return nil, err
}
switch len(products) {
case 0:
return new(types.Product), nil
product, err = new(types.Product), nil
case 1:
return products[0], nil
product, err = products[0], nil
default:
return nil, ErrNonUniqueIdentifier
product, err = nil, ErrNonUniqueIdentifier
}
logger.Trace().Any("product", product).Msg("found product")
return
}
func (r *R) CreateProductTable() error {
logger.Debug().Msg("creating product table")
_, err := r.db.Exec(sqlCreateProducts)
return err
}
func (r *R) SelectAllProducts() ([]*types.Product, error) {
logger.Trace().Msg("selecting all products")
return r.scanProducts(nil, sqlSelectAllProducts)
}
func (r *R) SelectProductById(id uint) (*types.Product, error) {
logger.Trace().Uint("id", id).Msg("selecting product by id")
return r.scanUniqueProduct(nil, sqlSelectProductById, id)
}
@ -194,6 +215,7 @@ func (r *R) SelectProductByEAN(ean uint) (*types.Product, error) {
}
func (r *R) SelectProductsLike(ps *types.ProductSearch) ([]*types.Product, error) {
logger.Trace().Any("search", ps).Msg("selecting product like search")
if !ps.Valid() {
return nil, types.ErrInvalidSearch
}
@ -202,6 +224,7 @@ func (r *R) SelectProductsLike(ps *types.ProductSearch) ([]*types.Product, error
}
func (r *R) InsertProduct(product *types.Product) error {
logger.Trace().Any("product", product).Msg("inserting new product")
tx, err := r.db.Begin()
if err != nil {
return err
@ -225,24 +248,29 @@ func (r *R) InsertProduct(product *types.Product) error {
return err
}
product.Id = uint(id)
logger.Trace().Any("product", product).Int64("new-id", id).Msg("new product id")
for _, tag := range product.Tags {
logger.Trace().Any("product", product).Int64("new-id", id).Uint("tag", tag.Id).Msg("adding tag")
if _, err := tx.Exec(sqlInsertProductTagging, id, tag.Id); err != nil {
return err
}
}
logger.Trace().Any("product", product).Int64("new-id", id).Msg("selecting insertion")
newProduct, err := r.scanUniqueProduct(tx, sqlSelectProductById, id)
if err != nil {
return err
}
logger.Trace().Any("product", product).Int64("new-id", id).Msg("updating product")
product.Tags = newProduct.Tags
return tx.Commit()
}
func (r *R) UpdateProduct(product *types.Product) (*types.Product, error) {
logger.Trace().Any("product", product).Msg("updating product")
tx, err := r.db.Begin()
if err != nil {
return nil, err
@ -261,6 +289,7 @@ func (r *R) UpdateProduct(product *types.Product) (*types.Product, error) {
return nil, err
}
logger.Trace().Any("product", product).Msg("deleting taggings")
if _, err := tx.Exec(sqlDeleteProductProductTagging, product.Id); err != nil {
return nil, err
}
@ -271,6 +300,7 @@ func (r *R) UpdateProduct(product *types.Product) (*types.Product, error) {
}
for _, tag := range product.Tags {
logger.Trace().Any("product", product).Uint("tag-id", tag.Id).Msg("inserting tagging")
if _, err := stmt.Exec(product.Id, tag.Id); err != nil {
return nil, err
}
@ -280,25 +310,31 @@ func (r *R) UpdateProduct(product *types.Product) (*types.Product, error) {
return nil, err
}
logger.Trace().Any("product", product).Msg("returning selection")
return r.scanUniqueProduct(nil, sqlSelectProductById, product.Id)
}
func (r *R) DeleteProduct(id uint) (*types.Product, error) {
logger := logger.With().Uint("product-id", id).Logger()
logger.Trace().Msg("deleting product")
tx, err := r.db.Begin()
if err != nil {
return nil, err
}
defer tx.Rollback()
logger.Trace().Msg("selecting product")
product, err := r.scanUniqueProduct(tx, sqlSelectProductById, id)
if err != nil {
return nil, err
}
logger.Trace().Msg("deleting taggings")
if _, err := tx.Exec(sqlDeleteProductProductTagging, id); err != nil {
return nil, err
}
logger.Trace().Msg("deleting product")
if _, err := tx.Exec(sqlDeleteProduct, id); err != nil {
return nil, err
}
@ -307,6 +343,7 @@ func (r *R) DeleteProduct(id uint) (*types.Product, error) {
}
func (r *R) DropProductTable() error {
logger.Info().Msg("dropping product table")
_, err := r.db.Exec(sqlDropProducts)
return err
}

View File

@ -31,6 +31,7 @@ const (
)
func (r *R) scanProductTags(tx *sql.Tx, query string, args ...any) ([]*types.Tag, error) {
logger.Trace().Bool("transaction", tx != nil).Str("query", query).Any("args", args).Msg("excuting query and scanning tags")
if tx == nil {
var err error
tx, err = r.db.Begin()
@ -45,6 +46,7 @@ func (r *R) scanProductTags(tx *sql.Tx, query string, args ...any) ([]*types.Tag
if err != nil {
return nil, err
}
defer rows.Close()
var tags []*types.Tag = []*types.Tag{}
for rows.Next() {
@ -54,13 +56,17 @@ func (r *R) scanProductTags(tx *sql.Tx, query string, args ...any) ([]*types.Tag
return nil, err
}
logger.Trace().Any("tag", tag).Msg("adding found tag")
tags = append(tags, &tag)
}
logger.Trace().Int("tags", len(tags)).Msg("done querying and scanning tags")
return tags, nil
}
func (r *R) scanUniqueProductTag(tx *sql.Tx, query string, args ...any) (*types.Tag, error) {
func (r *R) scanUniqueProductTag(tx *sql.Tx, query string, args ...any) (tag *types.Tag, err error) {
logger.Trace().Bool("transaction", tx != nil).Str("query", query).Any("args", args).Msg("excuting query and scanning one tag")
tags, err := r.scanProductTags(tx, query, args...)
if err != nil {
return nil, err
@ -68,41 +74,51 @@ func (r *R) scanUniqueProductTag(tx *sql.Tx, query string, args ...any) (*types.
switch len(tags) {
case 0:
return new(types.Tag), nil
tag, err = new(types.Tag), nil
case 1:
return tags[0], nil
tag, err = tags[0], nil
default:
return nil, ErrNonUniqueIdentifier
tag, err = nil, ErrNonUniqueIdentifier
}
logger.Trace().Any("tag", tag).Msg("found tag")
return
}
func (r *R) DropProductTagTable() error {
logger.Info().Msg("dropping product tag table")
_, err := r.db.Exec(sqlDropProductTags)
return err
}
func (r *R) CreateProductTagTable() error {
logger.Info().Msg("creating product tag table")
_, err := r.db.Exec(sqlCreateProductTags)
return err
}
func (r *R) SelectAllProductTags() ([]*types.Tag, error) {
logger.Trace().Msg("selecting all tags")
return r.scanProductTags(nil, sqlSelectAllProductTags)
}
func (r *R) SelectProductTagById(id uint) (*types.Tag, error) {
logger.Trace().Uint("id", id).Msg("selecting tag by id")
return r.scanUniqueProductTag(nil, sqlSelectProductTagById, id)
}
func (r *R) SelectProductTagByName(name string) (*types.Tag, error) {
logger.Trace().Str("name", name).Msg("selecting tag by name")
return r.scanUniqueProductTag(nil, sqlSelectProductTagByName, name)
}
func (r *R) SelectProductTagsLikeName(name string) ([]*types.Tag, error) {
logger.Trace().Str("name", name).Msg("selecting tag like name")
return r.scanProductTags(nil, sqlSelectProductTagsLikeName, name)
}
func (r *R) InsertProductTag(tag *types.Tag) error {
logger.Trace().Any("tag", tag).Msg("inserting new tag")
result, err := r.db.Exec(sqlInsertProductTag, tag.Name, tag.Color)
if err != nil {
return err
@ -112,13 +128,14 @@ func (r *R) InsertProductTag(tag *types.Tag) error {
if err != nil {
return err
}
tag.Id = uint(id)
logger.Trace().Uint("new-id", tag.Id).Msg("new tag id")
return nil
}
func (r *R) UpdateProductTag(tag *types.Tag) (*types.Tag, error) {
logger.Trace().Any("tag", tag).Msg("updating tag")
if _, err := r.db.Exec(sqlUpdateProductTag, tag.Name, tag.Color, tag.Id); err != nil {
return nil, err
}
@ -127,21 +144,26 @@ func (r *R) UpdateProductTag(tag *types.Tag) (*types.Tag, error) {
}
func (r *R) DeleteProductTag(id uint) (*types.Tag, error) {
logger := logger.With().Uint("tag-id", id).Logger()
logger.Trace().Msg("deleting tag")
tx, err := r.db.Begin()
if err != nil {
return nil, err
}
defer tx.Rollback()
logger.Trace().Msg("selecting tag")
tags, err := r.scanProductTags(tx, sqlSelectProductTagById, id)
if err != nil {
return nil, err
}
logger.Trace().Msg("deleting taggings")
if _, err := tx.Exec(sqlDeleteTagProductTagging, id); err != nil {
return nil, err
}
logger.Trace().Msg("deleting tag")
if _, err := tx.Exec(sqlDeleteProductTag, id); err != nil {
return nil, err
}

View File

@ -45,16 +45,22 @@ const (
)
func (r *R) DropProductTaggingTable() error {
logger.Info().Msg("dropping product tagging table")
_, err := r.db.Exec(sqlDropProductTagging)
return err
}
func (r *R) CreateProductTaggingTable() error {
logger.Info().Msg("creating product tagging table")
_, err := r.db.Exec(sqlCreateProductTagging)
return err
}
func (r *R) SelectProductTaggingByPid(pid uint) ([]types.Tag, error) {
logger.
Trace().
Uint("product-id", pid).
Msg("querying taggings by product and scanning tags")
rows, err := r.db.Query(sqlSelectProductTaggingByPid, pid)
if err != nil {
@ -67,13 +73,22 @@ func (r *R) SelectProductTaggingByPid(pid uint) ([]types.Tag, error) {
if err := rows.Scan(&tag.Id, &tag.Name, &tag.Color); err != nil {
return nil, err
}
logger.Trace().Any("tag", tag).Msg("adding tag")
tags = append(tags, tag)
}
logger.
Trace().
Int("tags", len(tags)).
Msg("done querying taggings by product and scanning tags")
return tags, nil
}
func (r *R) SelectProductTaggingByTid(tid uint) ([]*types.Product, error) {
logger := logger.With().Uint("tag-id", tid).Logger()
logger.
Trace().
Msg("querying taggings by tag and scanning products")
rows, err := r.db.Query(sqlSelectProductTaggingByTid, tid)
if err != nil {
@ -88,18 +103,23 @@ func (r *R) SelectProductTaggingByTid(tid uint) ([]*types.Product, error) {
return nil, err
}
logger.Trace().Uint("product-id", pid).Msg("selecting product")
product, err := r.SelectProductById(pid)
if err != nil {
return nil, err
}
logger.Trace().Any("product", pid).Msg("adding found product")
products = append(products, product)
}
logger.Trace().Int("products", len(products)).Msg("found products")
return products, nil
}
func (r *R) SelectProductTaggingLikeTagName(name string) ([]*types.Product, error) {
logger := logger.With().Str("name", name).Logger()
logger.Trace().Msg("selecting product taggings like tag name")
rows, err := r.db.Query(sqlSelectProductTaggingLikeTagName, name)
if err != nil {
@ -114,33 +134,40 @@ func (r *R) SelectProductTaggingLikeTagName(name string) ([]*types.Product, erro
return nil, err
}
logger.Trace().Uint("product-id", pid).Msg("selecting product")
product, err := r.SelectProductById(pid)
if err != nil {
return nil, err
}
logger.Trace().Any("product", pid).Msg("adding found product")
products = append(products, product)
}
logger.Trace().Int("products", len(products)).Msg("found products")
return products, nil
}
func (r *R) InsertProductTagging(pid, tid uint) error {
logger.Trace().Uint("product-id", pid).Uint("tag-id", tid).Msg("inserting tagging")
_, err := r.db.Exec(sqlInsertProductTagging, pid, tid)
return err
}
func (r *R) DeleteOneProductTagging(pid, tid uint) error {
logger.Trace().Uint("product-id", pid).Uint("tag-id", tid).Msg("deleting tagging")
_, err := r.db.Exec(sqlDeleteOneProductTagging, pid, tid)
return err
}
func (r *R) DeleteProductProductTagging(pid uint) error {
logger.Trace().Uint("product-id", pid).Msg("deleting tagging by product")
_, err := r.db.Exec(sqlDeleteProductProductTagging, pid)
return err
}
func (r *R) DeleteTagProductTagging(tid uint) error {
logger.Trace().Uint("tag-id", tid).Msg("deleting tagging by tag")
_, err := r.db.Exec(sqlDeleteTagProductTagging, tid)
return err
}