github.com/e154/smart-home@v0.17.2-0.20240311175135-e530a6e5cd45/db/tag.go (about)

     1  // This file is part of the Smart Home
     2  // Program complex distribution https://github.com/e154/smart-home
     3  // Copyright (C) 2016-2023, Filippov Alex
     4  //
     5  // This library is free software: you can redistribute it and/or
     6  // modify it under the terms of the GNU Lesser General Public
     7  // License as published by the Free Software Foundation; either
     8  // version 3 of the License, or (at your option) any later version.
     9  //
    10  // This library is distributed in the hope that it will be useful,
    11  // but WITHOUT ANY WARRANTY; without even the implied warranty of
    12  // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    13  // Library General Public License for more details.
    14  //
    15  // You should have received a copy of the GNU Lesser General Public
    16  // License along with this library.  If not, see
    17  // <https://www.gnu.org/licenses/>.
    18  
    19  package db
    20  
    21  import (
    22  	"context"
    23  	"fmt"
    24  	"github.com/jackc/pgerrcode"
    25  	"github.com/jackc/pgx/v5/pgconn"
    26  	"github.com/pkg/errors"
    27  	"gorm.io/gorm"
    28  	"strings"
    29  
    30  	"github.com/e154/smart-home/common/apperr"
    31  )
    32  
    33  // Tags ...
    34  type Tags struct {
    35  	Db *gorm.DB
    36  }
    37  
    38  // Tag ...
    39  type Tag struct {
    40  	Id   int64 `gorm:"primary_key"`
    41  	Name string
    42  }
    43  
    44  // TableName ...
    45  func (d *Tag) TableName() string {
    46  	return "tags"
    47  }
    48  
    49  // Add ...
    50  func (n Tags) Add(ctx context.Context, tag *Tag) (id int64, err error) {
    51  	if err = n.Db.WithContext(ctx).Create(tag).Error; err != nil {
    52  		err = errors.Wrap(apperr.ErrTagAdd, err.Error())
    53  		return
    54  	}
    55  	id = tag.Id
    56  	return
    57  }
    58  
    59  // List ...
    60  func (n *Tags) List(ctx context.Context, limit, offset int, orderBy, sort string, query *string, names *[]string) (list []*Tag, total int64, err error) {
    61  
    62  	list = make([]*Tag, 0)
    63  	q := n.Db.WithContext(ctx).Model(Tag{})
    64  	if query != nil {
    65  		q = q.Where("name LIKE ? or source LIKE ?", "%"+*query+"%", "%"+*query+"%")
    66  	}
    67  	if names != nil {
    68  		q = q.Where("name IN (?)", *names)
    69  	}
    70  	if err = q.Count(&total).Error; err != nil {
    71  		err = errors.Wrap(apperr.ErrTagList, err.Error())
    72  		return
    73  	}
    74  	err = q.
    75  		Limit(limit).
    76  		Offset(offset).
    77  		//Order(fmt.Sprintf("%s %s", sort, orderBy)).
    78  		Find(&list).
    79  		Error
    80  	if err != nil {
    81  		err = errors.Wrap(apperr.ErrTagList, err.Error())
    82  	}
    83  	return
    84  }
    85  
    86  // GetByName ...
    87  func (n *Tags) GetByName(ctx context.Context, name string) (tag *Tag, err error) {
    88  	tag = &Tag{}
    89  	err = n.Db.WithContext(ctx).Model(tag).
    90  		Where("name = ?", name).
    91  		First(&tag).Error
    92  
    93  	if err != nil {
    94  		if errors.Is(err, gorm.ErrRecordNotFound) {
    95  			err = errors.Wrap(apperr.ErrTagNotFound, fmt.Sprintf("name \"%s\"", name))
    96  			return
    97  		}
    98  		err = errors.Wrap(apperr.ErrTagGet, err.Error())
    99  	}
   100  
   101  	return
   102  }
   103  
   104  // GetById ...
   105  func (n *Tags) GetById(ctx context.Context, id int64) (tag *Tag, err error) {
   106  	tag = &Tag{}
   107  	err = n.Db.WithContext(ctx).Model(tag).
   108  		Where("id = ?", id).
   109  		First(&tag).Error
   110  
   111  	if err != nil {
   112  		if errors.Is(err, gorm.ErrRecordNotFound) {
   113  			err = errors.Wrap(apperr.ErrTagNotFound, fmt.Sprintf("id \"%d\"", id))
   114  			return
   115  		}
   116  		err = errors.Wrap(apperr.ErrTagGet, err.Error())
   117  	}
   118  
   119  	return
   120  }
   121  
   122  // Delete ...
   123  func (n *Tags) Delete(ctx context.Context, name string) (err error) {
   124  	if err = n.Db.WithContext(ctx).Delete(&Tag{Name: name}).Error; err != nil {
   125  		err = errors.Wrap(apperr.ErrTagDelete, err.Error())
   126  	}
   127  	return
   128  }
   129  
   130  // Update ...
   131  func (n *Tags) Update(ctx context.Context, tag *Tag) (err error) {
   132  	err = n.Db.WithContext(ctx).Model(&Tag{Id: tag.Id}).Updates(map[string]interface{}{
   133  		"name": tag.Name,
   134  	}).Error
   135  	if err != nil {
   136  		var pgErr *pgconn.PgError
   137  		if errors.As(err, &pgErr) {
   138  			switch pgErr.Code {
   139  			case pgerrcode.UniqueViolation:
   140  				if strings.Contains(pgErr.Message, "tag_name_unq") {
   141  					err = errors.Wrap(apperr.ErrTagUpdate, fmt.Sprintf("tag name \"%s\" not unique", tag.Name))
   142  					return
   143  				}
   144  			default:
   145  				fmt.Printf("unknown code \"%s\"\n", pgErr.Code)
   146  			}
   147  		}
   148  		err = errors.Wrap(apperr.ErrTagUpdate, err.Error())
   149  		return
   150  	}
   151  
   152  	return
   153  }
   154  
   155  // Search ...
   156  func (n *Tags) Search(ctx context.Context, query string, limit, offset int) (list []*Tag, total int64, err error) {
   157  
   158  	q := n.Db.WithContext(ctx).Model(&Tag{}).
   159  		Where("name LIKE ?", "%"+query+"%")
   160  
   161  	if err = q.Count(&total).Error; err != nil {
   162  		err = errors.Wrap(apperr.ErrTagSearch, err.Error())
   163  		return
   164  	}
   165  
   166  	q = q.
   167  		Limit(limit).
   168  		Offset(offset).
   169  		Order("name ASC")
   170  
   171  	list = make([]*Tag, 0)
   172  	if err = q.Find(&list).Error; err != nil {
   173  		err = errors.Wrap(apperr.ErrTagSearch, err.Error())
   174  	}
   175  	return
   176  }