github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/databases/orm/orm_queryset.go (about)

     1  // The original package is migrated from beego and modified, you can find orignal from following link:
     2  //    "github.com/beego/beego/"
     3  //
     4  // Copyright 2023 IAC. All Rights Reserved.
     5  //
     6  // Licensed under the Apache License, Version 2.0 (the "License");
     7  // you may not use this file except in compliance with the License.
     8  // You may obtain a copy of the License at
     9  //
    10  //      http://www.apache.org/licenses/LICENSE-2.0
    11  //
    12  // Unless required by applicable law or agreed to in writing, software
    13  // distributed under the License is distributed on an "AS IS" BASIS,
    14  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    15  // See the License for the specific language governing permissions and
    16  // limitations under the License.
    17  
    18  package orm
    19  
    20  import (
    21  	"context"
    22  	"fmt"
    23  
    24  	"github.com/mdaxf/iac/databases/orm/clauses"
    25  	"github.com/mdaxf/iac/databases/orm/hints"
    26  )
    27  
    28  type colValue struct {
    29  	value int64
    30  	opt   operator
    31  }
    32  
    33  type operator int
    34  
    35  // define Col operations
    36  const (
    37  	ColAdd operator = iota
    38  	ColMinus
    39  	ColMultiply
    40  	ColExcept
    41  	ColBitAnd
    42  	ColBitRShift
    43  	ColBitLShift
    44  	ColBitXOR
    45  	ColBitOr
    46  )
    47  
    48  // ColValue do the field raw changes. e.g Nums = Nums + 10. usage:
    49  //
    50  //	Params{
    51  //		"Nums": ColValue(Col_Add, 10),
    52  //	}
    53  func ColValue(opt operator, value interface{}) interface{} {
    54  	switch opt {
    55  	case ColAdd, ColMinus, ColMultiply, ColExcept, ColBitAnd, ColBitRShift,
    56  		ColBitLShift, ColBitXOR, ColBitOr:
    57  	default:
    58  		panic(fmt.Errorf("orm.ColValue wrong operator"))
    59  	}
    60  	v, err := StrTo(ToStr(value)).Int64()
    61  	if err != nil {
    62  		panic(fmt.Errorf("orm.ColValue doesn't support non string/numeric type, %s", err))
    63  	}
    64  	var val colValue
    65  	val.value = v
    66  	val.opt = opt
    67  	return val
    68  }
    69  
    70  // real query struct
    71  type querySet struct {
    72  	mi        *modelInfo
    73  	cond      *Condition
    74  	related   []string
    75  	relDepth  int
    76  	limit     int64
    77  	offset    int64
    78  	groups    []string
    79  	orders    []*clauses.Order
    80  	distinct  bool
    81  	forUpdate bool
    82  	useIndex  int
    83  	indexes   []string
    84  	orm       *ormBase
    85  	aggregate string
    86  }
    87  
    88  var _ QuerySeter = new(querySet)
    89  
    90  // add condition expression to QuerySeter.
    91  func (o querySet) Filter(expr string, args ...interface{}) QuerySeter {
    92  	if o.cond == nil {
    93  		o.cond = NewCondition()
    94  	}
    95  	o.cond = o.cond.And(expr, args...)
    96  	return &o
    97  }
    98  
    99  // add raw sql to querySeter.
   100  func (o querySet) FilterRaw(expr string, sql string) QuerySeter {
   101  	if o.cond == nil {
   102  		o.cond = NewCondition()
   103  	}
   104  	o.cond = o.cond.Raw(expr, sql)
   105  	return &o
   106  }
   107  
   108  // add NOT condition to querySeter.
   109  func (o querySet) Exclude(expr string, args ...interface{}) QuerySeter {
   110  	if o.cond == nil {
   111  		o.cond = NewCondition()
   112  	}
   113  	o.cond = o.cond.AndNot(expr, args...)
   114  	return &o
   115  }
   116  
   117  // set offset number
   118  func (o *querySet) setOffset(num interface{}) {
   119  	o.offset = ToInt64(num)
   120  }
   121  
   122  // add LIMIT value.
   123  // args[0] means offset, e.g. LIMIT num,offset.
   124  func (o querySet) Limit(limit interface{}, args ...interface{}) QuerySeter {
   125  	o.limit = ToInt64(limit)
   126  	if len(args) > 0 {
   127  		o.setOffset(args[0])
   128  	}
   129  	return &o
   130  }
   131  
   132  // add OFFSET value
   133  func (o querySet) Offset(offset interface{}) QuerySeter {
   134  	o.setOffset(offset)
   135  	return &o
   136  }
   137  
   138  // add GROUP expression
   139  func (o querySet) GroupBy(exprs ...string) QuerySeter {
   140  	o.groups = exprs
   141  	return &o
   142  }
   143  
   144  // add ORDER expression.
   145  // "column" means ASC, "-column" means DESC.
   146  func (o querySet) OrderBy(expressions ...string) QuerySeter {
   147  	if len(expressions) <= 0 {
   148  		return &o
   149  	}
   150  	o.orders = clauses.ParseOrder(expressions...)
   151  	return &o
   152  }
   153  
   154  // add ORDER expression.
   155  func (o querySet) OrderClauses(orders ...*clauses.Order) QuerySeter {
   156  	if len(orders) <= 0 {
   157  		return &o
   158  	}
   159  	o.orders = orders
   160  	return &o
   161  }
   162  
   163  // add DISTINCT to SELECT
   164  func (o querySet) Distinct() QuerySeter {
   165  	o.distinct = true
   166  	return &o
   167  }
   168  
   169  // add FOR UPDATE to SELECT
   170  func (o querySet) ForUpdate() QuerySeter {
   171  	o.forUpdate = true
   172  	return &o
   173  }
   174  
   175  // ForceIndex force index for query
   176  func (o querySet) ForceIndex(indexes ...string) QuerySeter {
   177  	o.useIndex = hints.KeyForceIndex
   178  	o.indexes = indexes
   179  	return &o
   180  }
   181  
   182  // UseIndex use index for query
   183  func (o querySet) UseIndex(indexes ...string) QuerySeter {
   184  	o.useIndex = hints.KeyUseIndex
   185  	o.indexes = indexes
   186  	return &o
   187  }
   188  
   189  // IgnoreIndex ignore index for query
   190  func (o querySet) IgnoreIndex(indexes ...string) QuerySeter {
   191  	o.useIndex = hints.KeyIgnoreIndex
   192  	o.indexes = indexes
   193  	return &o
   194  }
   195  
   196  // set relation model to query together.
   197  // it will query relation models and assign to parent model.
   198  func (o querySet) RelatedSel(params ...interface{}) QuerySeter {
   199  	if len(params) == 0 {
   200  		o.relDepth = DefaultRelsDepth
   201  	} else {
   202  		for _, p := range params {
   203  			switch val := p.(type) {
   204  			case string:
   205  				o.related = append(o.related, val)
   206  			case int:
   207  				o.relDepth = val
   208  			default:
   209  				panic(fmt.Errorf("<QuerySeter.RelatedSel> wrong param kind: %v", val))
   210  			}
   211  		}
   212  	}
   213  	return &o
   214  }
   215  
   216  // set condition to QuerySeter.
   217  func (o querySet) SetCond(cond *Condition) QuerySeter {
   218  	o.cond = cond
   219  	return &o
   220  }
   221  
   222  // get condition from QuerySeter
   223  func (o querySet) GetCond() *Condition {
   224  	return o.cond
   225  }
   226  
   227  // return QuerySeter execution result number
   228  func (o *querySet) Count() (int64, error) {
   229  	return o.CountWithCtx(context.Background())
   230  }
   231  
   232  func (o *querySet) CountWithCtx(ctx context.Context) (int64, error) {
   233  	return o.orm.alias.DbBaser.Count(ctx, o.orm.db, o, o.mi, o.cond, o.orm.alias.TZ)
   234  }
   235  
   236  // check result empty or not after QuerySeter executed
   237  func (o *querySet) Exist() bool {
   238  	return o.ExistWithCtx(context.Background())
   239  }
   240  
   241  func (o *querySet) ExistWithCtx(ctx context.Context) bool {
   242  	cnt, _ := o.orm.alias.DbBaser.Count(ctx, o.orm.db, o, o.mi, o.cond, o.orm.alias.TZ)
   243  	return cnt > 0
   244  }
   245  
   246  // execute update with parameters
   247  func (o *querySet) Update(values Params) (int64, error) {
   248  	return o.UpdateWithCtx(context.Background(), values)
   249  }
   250  
   251  func (o *querySet) UpdateWithCtx(ctx context.Context, values Params) (int64, error) {
   252  	return o.orm.alias.DbBaser.UpdateBatch(ctx, o.orm.db, o, o.mi, o.cond, values, o.orm.alias.TZ)
   253  }
   254  
   255  // execute delete
   256  func (o *querySet) Delete() (int64, error) {
   257  	return o.DeleteWithCtx(context.Background())
   258  }
   259  
   260  func (o *querySet) DeleteWithCtx(ctx context.Context) (int64, error) {
   261  	return o.orm.alias.DbBaser.DeleteBatch(ctx, o.orm.db, o, o.mi, o.cond, o.orm.alias.TZ)
   262  }
   263  
   264  // return an insert queryer.
   265  // it can be used in times.
   266  // example:
   267  //
   268  //	i,err := sq.PrepareInsert()
   269  //	i.Add(&user1{},&user2{})
   270  func (o *querySet) PrepareInsert() (Inserter, error) {
   271  	return o.PrepareInsertWithCtx(context.Background())
   272  }
   273  
   274  func (o *querySet) PrepareInsertWithCtx(ctx context.Context) (Inserter, error) {
   275  	return newInsertSet(ctx, o.orm, o.mi)
   276  }
   277  
   278  // query all data and map to containers.
   279  // cols means the columns when querying.
   280  func (o *querySet) All(container interface{}, cols ...string) (int64, error) {
   281  	return o.AllWithCtx(context.Background(), container, cols...)
   282  }
   283  
   284  func (o *querySet) AllWithCtx(ctx context.Context, container interface{}, cols ...string) (int64, error) {
   285  	return o.orm.alias.DbBaser.ReadBatch(ctx, o.orm.db, o, o.mi, o.cond, container, o.orm.alias.TZ, cols)
   286  }
   287  
   288  // query one row data and map to containers.
   289  // cols means the columns when querying.
   290  func (o *querySet) One(container interface{}, cols ...string) error {
   291  	return o.OneWithCtx(context.Background(), container, cols...)
   292  }
   293  
   294  func (o *querySet) OneWithCtx(ctx context.Context, container interface{}, cols ...string) error {
   295  	o.limit = 1
   296  	num, err := o.orm.alias.DbBaser.ReadBatch(ctx, o.orm.db, o, o.mi, o.cond, container, o.orm.alias.TZ, cols)
   297  	if err != nil {
   298  		return err
   299  	}
   300  	if num == 0 {
   301  		return ErrNoRows
   302  	}
   303  
   304  	if num > 1 {
   305  		return ErrMultiRows
   306  	}
   307  	return nil
   308  }
   309  
   310  // query all data and map to []map[string]interface.
   311  // expres means condition expression.
   312  // it converts data to []map[column]value.
   313  func (o *querySet) Values(results *[]Params, exprs ...string) (int64, error) {
   314  	return o.ValuesWithCtx(context.Background(), results, exprs...)
   315  }
   316  
   317  func (o *querySet) ValuesWithCtx(ctx context.Context, results *[]Params, exprs ...string) (int64, error) {
   318  	return o.orm.alias.DbBaser.ReadValues(ctx, o.orm.db, o, o.mi, o.cond, exprs, results, o.orm.alias.TZ)
   319  }
   320  
   321  // query all data and map to [][]interface
   322  // it converts data to [][column_index]value
   323  func (o *querySet) ValuesList(results *[]ParamsList, exprs ...string) (int64, error) {
   324  	return o.ValuesListWithCtx(context.Background(), results, exprs...)
   325  }
   326  
   327  func (o *querySet) ValuesListWithCtx(ctx context.Context, results *[]ParamsList, exprs ...string) (int64, error) {
   328  	return o.orm.alias.DbBaser.ReadValues(ctx, o.orm.db, o, o.mi, o.cond, exprs, results, o.orm.alias.TZ)
   329  }
   330  
   331  // query all data and map to []interface.
   332  // it's designed for one row record set, auto change to []value, not [][column]value.
   333  func (o *querySet) ValuesFlat(result *ParamsList, expr string) (int64, error) {
   334  	return o.ValuesFlatWithCtx(context.Background(), result, expr)
   335  }
   336  
   337  func (o *querySet) ValuesFlatWithCtx(ctx context.Context, result *ParamsList, expr string) (int64, error) {
   338  	return o.orm.alias.DbBaser.ReadValues(ctx, o.orm.db, o, o.mi, o.cond, []string{expr}, result, o.orm.alias.TZ)
   339  }
   340  
   341  // query all rows into map[string]interface with specify key and value column name.
   342  // keyCol = "name", valueCol = "value"
   343  // table data
   344  // name  | value
   345  // total | 100
   346  // found | 200
   347  //
   348  //	to map[string]interface{}{
   349  //		"total": 100,
   350  //		"found": 200,
   351  //	}
   352  func (o *querySet) RowsToMap(result *Params, keyCol, valueCol string) (int64, error) {
   353  	panic(ErrNotImplement)
   354  }
   355  
   356  // query all rows into struct with specify key and value column name.
   357  // keyCol = "name", valueCol = "value"
   358  // table data
   359  // name  | value
   360  // total | 100
   361  // found | 200
   362  //
   363  //	to struct {
   364  //		Total int
   365  //		Found int
   366  //	}
   367  func (o *querySet) RowsToStruct(ptrStruct interface{}, keyCol, valueCol string) (int64, error) {
   368  	panic(ErrNotImplement)
   369  }
   370  
   371  // create new QuerySeter.
   372  func newQuerySet(orm *ormBase, mi *modelInfo) QuerySeter {
   373  	o := new(querySet)
   374  	o.mi = mi
   375  	o.orm = orm
   376  	return o
   377  }
   378  
   379  // aggregate func
   380  func (o querySet) Aggregate(s string) QuerySeter {
   381  	o.aggregate = s
   382  	return &o
   383  }