github.com/RevenueMonster/sqlike@v1.0.6/sqlike/delete.go (about)

     1  package sqlike
     2  
     3  import (
     4  	"context"
     5  	"errors"
     6  
     7  	"github.com/RevenueMonster/sqlike/reflext"
     8  	sqldialect "github.com/RevenueMonster/sqlike/sql/dialect"
     9  	sqldriver "github.com/RevenueMonster/sqlike/sql/driver"
    10  	"github.com/RevenueMonster/sqlike/sql/expr"
    11  	sqlstmt "github.com/RevenueMonster/sqlike/sql/stmt"
    12  	"github.com/RevenueMonster/sqlike/sqlike/actions"
    13  	"github.com/RevenueMonster/sqlike/sqlike/logs"
    14  	"github.com/RevenueMonster/sqlike/sqlike/options"
    15  )
    16  
    17  // DestroyOne : hard delete a record on the table using primary key. You should alway have primary key defined in your struct in order to use this api.
    18  func (tb *Table) DestroyOne(ctx context.Context, delete interface{}, opts ...*options.DestroyOneOptions) error {
    19  	opt := new(options.DestroyOneOptions)
    20  	if len(opts) > 0 && opts[0] != nil {
    21  		opt = opts[0]
    22  	}
    23  	return destroyOne(
    24  		ctx,
    25  		tb.dbName,
    26  		tb.name,
    27  		tb.pk,
    28  		tb.client.cache,
    29  		tb.driver,
    30  		tb.dialect,
    31  		tb.logger,
    32  		delete,
    33  		opt,
    34  	)
    35  }
    36  
    37  // DeleteOne : delete single record on the table using where clause.
    38  func (tb *Table) DeleteOne(ctx context.Context, act actions.DeleteOneStatement, opts ...*options.DeleteOneOptions) (int64, error) {
    39  	x := new(actions.DeleteOneActions)
    40  	if act != nil {
    41  		*x = *(act.(*actions.DeleteOneActions))
    42  	}
    43  	opt := new(options.DeleteOneOptions)
    44  	if len(opts) > 0 && opts[0] != nil {
    45  		opt = opts[0]
    46  	}
    47  	x.Limit(1)
    48  	return deleteMany(
    49  		ctx,
    50  		tb.dbName,
    51  		tb.name,
    52  		tb.driver,
    53  		tb.dialect,
    54  		tb.logger,
    55  		&x.DeleteActions,
    56  		&opt.DeleteOptions,
    57  	)
    58  }
    59  
    60  // Delete : delete multiple record on the table using where clause. If you didn't provided any where clause, it will throw error. For multiple record deletion without where clause, you should use `Truncate` instead.
    61  func (tb *Table) Delete(ctx context.Context, act actions.DeleteStatement, opts ...*options.DeleteOptions) (int64, error) {
    62  	x := new(actions.DeleteActions)
    63  	if act != nil {
    64  		*x = *(act.(*actions.DeleteActions))
    65  	}
    66  	opt := new(options.DeleteOptions)
    67  	if len(opts) > 0 && opts[0] != nil {
    68  		opt = opts[0]
    69  	}
    70  	return deleteMany(
    71  		ctx,
    72  		tb.dbName,
    73  		tb.name,
    74  		tb.driver,
    75  		tb.dialect,
    76  		tb.logger,
    77  		x,
    78  		opt,
    79  	)
    80  }
    81  
    82  func deleteMany(ctx context.Context, dbName, tbName string, driver sqldriver.Driver, dialect sqldialect.Dialect, logger logs.Logger, act *actions.DeleteActions, opt *options.DeleteOptions) (int64, error) {
    83  	if act.Database == "" {
    84  		act.Database = dbName
    85  	}
    86  	if act.Table == "" {
    87  		act.Table = tbName
    88  	}
    89  	if len(act.Conditions) < 1 {
    90  		return 0, errors.New("sqlike: empty condition is not allow for delete, please use truncate instead")
    91  	}
    92  
    93  	stmt := sqlstmt.AcquireStmt(dialect)
    94  	defer sqlstmt.ReleaseStmt(stmt)
    95  	if err := dialect.Delete(stmt, act); err != nil {
    96  		return 0, err
    97  	}
    98  	result, err := sqldriver.Execute(
    99  		ctx,
   100  		driver,
   101  		stmt,
   102  		getLogger(logger, opt.Debug),
   103  	)
   104  	if err != nil {
   105  		return 0, err
   106  	}
   107  	return result.RowsAffected()
   108  }
   109  
   110  func destroyOne(ctx context.Context, dbName, tbName, pk string, cache reflext.StructMapper, driver sqldriver.Driver, dialect sqldialect.Dialect, logger logs.Logger, delete interface{}, opt *options.DestroyOneOptions) error {
   111  	v := reflext.ValueOf(delete)
   112  	if !v.IsValid() {
   113  		return ErrInvalidInput
   114  	}
   115  
   116  	t := v.Type()
   117  	cdc := cache.CodecByType(t)
   118  	x := new(actions.DeleteActions)
   119  	x.Database = dbName
   120  	x.Table = tbName
   121  
   122  	var pkv = [2]interface{}{}
   123  	for _, sf := range cdc.Properties() {
   124  		fv := cache.FieldByIndexesReadOnly(v, sf.Index())
   125  		if _, ok := sf.Tag().LookUp("primary_key"); ok {
   126  			pkv[0] = sf.Name()
   127  			pkv[1] = fv.Interface()
   128  			continue
   129  		}
   130  		if sf.Name() == pk && pkv[0] == nil {
   131  			pkv[0] = sf.Name()
   132  			pkv[1] = fv.Interface()
   133  			continue
   134  		}
   135  	}
   136  
   137  	if pkv[0] == nil {
   138  		return errors.New("sqlike: missing primary key field")
   139  	}
   140  
   141  	x.Where(expr.Equal(pkv[0], pkv[1]))
   142  	x.Limit(1)
   143  
   144  	stmt := sqlstmt.AcquireStmt(dialect)
   145  	defer sqlstmt.ReleaseStmt(stmt)
   146  	if err := dialect.Delete(stmt, x); err != nil {
   147  		return err
   148  	}
   149  	result, err := sqldriver.Execute(
   150  		ctx,
   151  		driver,
   152  		stmt,
   153  		getLogger(logger, opt.Debug),
   154  	)
   155  	if err != nil {
   156  		return err
   157  	}
   158  	if affected, _ := result.RowsAffected(); affected <= 0 {
   159  		return errors.New("sqlike: unable to delete entity")
   160  	}
   161  	return err
   162  }