github.com/RevenueMonster/sqlike@v1.0.6/sql/dialect/mysql/builder.go (about)

     1  package mysql
     2  
     3  import (
     4  	"errors"
     5  	"reflect"
     6  	"strconv"
     7  	"strings"
     8  
     9  	"github.com/RevenueMonster/sqlike/reflext"
    10  	"github.com/RevenueMonster/sqlike/spatial"
    11  	"github.com/RevenueMonster/sqlike/sql"
    12  	"github.com/RevenueMonster/sqlike/sql/codec"
    13  	sqlstmt "github.com/RevenueMonster/sqlike/sql/stmt"
    14  	sqlutil "github.com/RevenueMonster/sqlike/sql/util"
    15  	"github.com/RevenueMonster/sqlike/sqlike/actions"
    16  	"github.com/RevenueMonster/sqlike/sqlike/primitive"
    17  )
    18  
    19  var operatorMap = map[primitive.Operator]string{
    20  	primitive.Equal:          "=",
    21  	primitive.NotEqual:       "<>",
    22  	primitive.In:             "IN",
    23  	primitive.NotIn:          "NOT IN",
    24  	primitive.Between:        "BETWEEN",
    25  	primitive.NotBetween:     "NOT BETWEEN",
    26  	primitive.IsNull:         "IS NULL",
    27  	primitive.NotNull:        "IS NOT NULL",
    28  	primitive.GreaterThan:    ">",
    29  	primitive.GreaterOrEqual: ">=",
    30  	primitive.LesserThan:     "<",
    31  	primitive.LesserOrEqual:  "<=",
    32  	primitive.Or:             "OR",
    33  	primitive.And:            "AND",
    34  }
    35  
    36  type mySQLBuilder struct {
    37  	registry codec.Codecer
    38  	builder  *sqlstmt.StatementBuilder
    39  	sqlutil.MySQLUtil
    40  }
    41  
    42  func (b mySQLBuilder) SetRegistryAndBuilders(rg codec.Codecer, blr *sqlstmt.StatementBuilder) {
    43  	if rg == nil {
    44  		panic("missing required registry")
    45  	}
    46  	if blr == nil {
    47  		panic("missing required parser")
    48  	}
    49  	blr.SetBuilder(reflect.TypeOf(primitive.CastAs{}), b.BuildCastAs)
    50  	blr.SetBuilder(reflect.TypeOf(primitive.Func{}), b.BuildFunction)
    51  	blr.SetBuilder(reflect.TypeOf(primitive.JSONFunc{}), b.BuildJSONFunction)
    52  	blr.SetBuilder(reflect.TypeOf(primitive.Field{}), b.BuildField)
    53  	blr.SetBuilder(reflect.TypeOf(primitive.Value{}), b.BuildValue)
    54  	blr.SetBuilder(reflect.TypeOf(primitive.As{}), b.BuildAs)
    55  	blr.SetBuilder(reflect.TypeOf(primitive.Nil{}), b.BuildNil)
    56  	blr.SetBuilder(reflect.TypeOf(primitive.Raw{}), b.BuildRaw)
    57  	blr.SetBuilder(reflect.TypeOf(primitive.Encoding{}), b.BuildEncoding)
    58  	blr.SetBuilder(reflect.TypeOf(primitive.Aggregate{}), b.BuildAggregate)
    59  	blr.SetBuilder(reflect.TypeOf(primitive.Column{}), b.BuildColumn)
    60  	blr.SetBuilder(reflect.TypeOf(primitive.JSONColumn{}), b.BuildJSONColumn)
    61  	blr.SetBuilder(reflect.TypeOf(primitive.C{}), b.BuildClause)
    62  	blr.SetBuilder(reflect.TypeOf(primitive.L{}), b.BuildLike)
    63  	blr.SetBuilder(reflect.TypeOf(primitive.TypeSafe{}), b.BuildTypeSafe)
    64  	blr.SetBuilder(reflect.TypeOf(primitive.Operator(0)), b.BuildOperator)
    65  	blr.SetBuilder(reflect.TypeOf(primitive.Group{}), b.BuildGroup)
    66  	blr.SetBuilder(reflect.TypeOf(primitive.R{}), b.BuildRange)
    67  	blr.SetBuilder(reflect.TypeOf(primitive.Sort{}), b.BuildSort)
    68  	blr.SetBuilder(reflect.TypeOf(primitive.KV{}), b.BuildKeyValue)
    69  	blr.SetBuilder(reflect.TypeOf(primitive.Math{}), b.BuildMath)
    70  	blr.SetBuilder(reflect.TypeOf(&primitive.Case{}), b.BuildCase)
    71  	blr.SetBuilder(reflect.TypeOf(spatial.Func{}), b.BuildSpatialFunc)
    72  	blr.SetBuilder(reflect.TypeOf(&sql.SelectStmt{}), b.BuildSelectStmt)
    73  	blr.SetBuilder(reflect.TypeOf(&sql.UpdateStmt{}), b.BuildUpdateStmt)
    74  	// blr.SetBuilder(reflect.TypeOf(&sql.DeleteStmt{}), b.BuildDeleteStmt)
    75  	blr.SetBuilder(reflect.TypeOf(&actions.FindActions{}), b.BuildFindActions)
    76  	blr.SetBuilder(reflect.TypeOf(&actions.UpdateActions{}), b.BuildUpdateActions)
    77  	blr.SetBuilder(reflect.TypeOf(&actions.DeleteActions{}), b.BuildDeleteActions)
    78  	blr.SetBuilder(reflect.String, b.BuildString)
    79  	b.registry = rg
    80  	b.builder = blr
    81  }
    82  
    83  // BuildCastAs :
    84  func (b *mySQLBuilder) BuildCastAs(stmt sqlstmt.Stmt, it interface{}) error {
    85  	x := it.(primitive.CastAs)
    86  	stmt.WriteString("CAST(")
    87  	if err := b.builder.BuildStatement(stmt, x.Value); err != nil {
    88  		return err
    89  	}
    90  	stmt.WriteString(" AS ")
    91  	switch x.DataType {
    92  	case primitive.JSON:
    93  		stmt.WriteString("JSON")
    94  	default:
    95  		return errors.New("mysql: unsupported cast as data type")
    96  	}
    97  	stmt.WriteByte(')')
    98  	return nil
    99  }
   100  
   101  // BuildFunction :
   102  func (b *mySQLBuilder) BuildFunction(stmt sqlstmt.Stmt, it interface{}) error {
   103  	x := it.(primitive.Func)
   104  	stmt.WriteString(x.Name)
   105  	stmt.WriteByte('(')
   106  	for i, args := range x.Args {
   107  		if i > 0 {
   108  			stmt.WriteByte(',')
   109  		}
   110  		if err := b.builder.BuildStatement(stmt, args); err != nil {
   111  			return err
   112  		}
   113  	}
   114  	stmt.WriteByte(')')
   115  	return nil
   116  }
   117  
   118  // BuildJSONFunction :
   119  func (b *mySQLBuilder) BuildJSONFunction(stmt sqlstmt.Stmt, it interface{}) error {
   120  	x := it.(primitive.JSONFunc)
   121  	if x.Prefix != nil {
   122  		if err := b.getValue(stmt, x.Prefix); err != nil {
   123  			return err
   124  		}
   125  		stmt.WriteString(" ")
   126  	}
   127  	stmt.WriteString(x.Type.String())
   128  	stmt.WriteByte('(')
   129  	for i, args := range x.Args {
   130  		if i > 0 {
   131  			stmt.WriteByte(',')
   132  		}
   133  		if err := b.builder.BuildStatement(stmt, args); err != nil {
   134  			return err
   135  		}
   136  	}
   137  	stmt.WriteByte(')')
   138  	return nil
   139  }
   140  
   141  // BuildString :
   142  func (b *mySQLBuilder) BuildString(stmt sqlstmt.Stmt, it interface{}) error {
   143  	v := reflect.ValueOf(it)
   144  	stmt.WriteString(b.Quote(v.String()))
   145  	return nil
   146  }
   147  
   148  // BuildLike :
   149  func (b *mySQLBuilder) BuildLike(stmt sqlstmt.Stmt, it interface{}) error {
   150  	x := it.(primitive.L)
   151  	if err := b.builder.BuildStatement(stmt, x.Field); err != nil {
   152  		return err
   153  	}
   154  
   155  	stmt.WriteByte(' ')
   156  	if x.IsNot {
   157  		stmt.WriteString("NOT LIKE")
   158  	} else {
   159  		stmt.WriteString("LIKE")
   160  	}
   161  	stmt.WriteByte(' ')
   162  	v := reflext.ValueOf(x.Value)
   163  	if !v.IsValid() {
   164  		stmt.WriteByte('?')
   165  		stmt.AppendArgs(nil)
   166  		return nil
   167  	}
   168  
   169  	t := v.Type()
   170  	if builder, ok := b.builder.LookupBuilder(t); ok {
   171  		if err := builder(stmt, x.Value); err != nil {
   172  			return err
   173  		}
   174  		return nil
   175  	}
   176  
   177  	stmt.WriteByte('?')
   178  	encoder, err := b.registry.LookupEncoder(v)
   179  	if err != nil {
   180  		return err
   181  	}
   182  	vv, err := encoder(nil, v)
   183  	if err != nil {
   184  		return err
   185  	}
   186  	switch vi := vv.(type) {
   187  	case string:
   188  		vv = escapeWildCard(vi)
   189  	case []byte:
   190  		vv = escapeWildCard(string(vi))
   191  	}
   192  	stmt.AppendArgs(vv)
   193  	return nil
   194  }
   195  
   196  // BuildField :
   197  func (b *mySQLBuilder) BuildField(stmt sqlstmt.Stmt, it interface{}) error {
   198  	x := it.(primitive.Field)
   199  	stmt.WriteString("FIELD")
   200  	stmt.WriteByte('(')
   201  	stmt.WriteString(b.Quote(x.Name))
   202  	for _, v := range x.Values {
   203  		stmt.WriteByte(',')
   204  		if err := b.getValue(stmt, v); err != nil {
   205  			return err
   206  		}
   207  	}
   208  	stmt.WriteByte(')')
   209  	return nil
   210  }
   211  
   212  // BuildValue :
   213  func (b *mySQLBuilder) BuildValue(stmt sqlstmt.Stmt, it interface{}) (err error) {
   214  	x := it.(primitive.Value)
   215  	v := reflext.ValueOf(x.Raw)
   216  	if !v.IsValid() {
   217  		stmt.WriteByte('?')
   218  		stmt.AppendArgs(nil)
   219  		return
   220  	}
   221  
   222  	encoder, err := b.registry.LookupEncoder(v)
   223  	if err != nil {
   224  		return err
   225  	}
   226  	vv, err := encoder(nil, v)
   227  	if err != nil {
   228  		return err
   229  	}
   230  	convertSpatial(stmt, vv)
   231  	// stmt.WriteRune('?')
   232  	// stmt.AppendArgs(vv)
   233  	return nil
   234  }
   235  
   236  // BuildColumn :
   237  func (b *mySQLBuilder) BuildColumn(stmt sqlstmt.Stmt, it interface{}) error {
   238  	x := it.(primitive.Column)
   239  	if x.Table != "" {
   240  		stmt.WriteString(b.Quote(x.Table))
   241  		stmt.WriteByte('.')
   242  	}
   243  	stmt.WriteString(b.Quote(x.Name))
   244  	return nil
   245  }
   246  
   247  // BuildJSONColumn :
   248  func (b *mySQLBuilder) BuildJSONColumn(stmt sqlstmt.Stmt, it interface{}) error {
   249  	/*
   250  		Expected columns ( JSON_EXTRACT )
   251  		Column : Address
   252  		Nested : [ State, City ]
   253  		UnquoteResult : false
   254  
   255  		Result
   256  		`Address`->'$.State.City'
   257  
   258  		--------------------------------------------
   259  
   260  		Expected columns ( JSON_EXTRACT(JSON_UNQUOTE) )
   261  		Column : Address
   262  		Nested : [ State, City ]
   263  		UnquoteResult : true
   264  
   265  		Result
   266  		`Address`->>'$.State.City'
   267  	*/
   268  	x := it.(primitive.JSONColumn)
   269  	nested := strings.Join(x.Nested, ".")
   270  	operator := "->"
   271  	if !strings.HasPrefix(nested, "$.") {
   272  		nested = "$." + nested
   273  	}
   274  	if x.UnquoteResult {
   275  		operator += ">"
   276  	}
   277  	stmt.WriteString(b.Quote(x.Column) + operator + b.Wrap(nested))
   278  	return nil
   279  }
   280  
   281  // BuildNil :
   282  func (b *mySQLBuilder) BuildNil(stmt sqlstmt.Stmt, it interface{}) error {
   283  	x := it.(primitive.Nil)
   284  	if err := b.builder.BuildStatement(stmt, x.Field); err != nil {
   285  		return err
   286  	}
   287  	if x.IsNot {
   288  		stmt.WriteString(" IS NULL")
   289  	} else {
   290  		stmt.WriteString(" IS NOT NULL")
   291  	}
   292  	return nil
   293  }
   294  
   295  // BuildRaw :
   296  func (b *mySQLBuilder) BuildRaw(stmt sqlstmt.Stmt, it interface{}) error {
   297  	x, ok := it.(primitive.Raw)
   298  	if ok {
   299  		stmt.WriteString(x.Value)
   300  	}
   301  	return nil
   302  }
   303  
   304  // BuildAs :
   305  func (b *mySQLBuilder) BuildAs(stmt sqlstmt.Stmt, it interface{}) error {
   306  	stmt.WriteByte('(')
   307  	x := it.(primitive.As)
   308  	if err := b.getValue(stmt, x.Field); err != nil {
   309  		return err
   310  	}
   311  	stmt.WriteByte(')')
   312  	stmt.WriteString(" AS ")
   313  	stmt.WriteString(b.Quote(x.Name))
   314  	return nil
   315  }
   316  
   317  // BuildAggregate :
   318  func (b *mySQLBuilder) BuildAggregate(stmt sqlstmt.Stmt, it interface{}) error {
   319  	x := it.(primitive.Aggregate)
   320  	switch x.By {
   321  	case primitive.Sum:
   322  		stmt.WriteString("COALESCE(SUM(")
   323  		if err := b.getValue(stmt, x.Field); err != nil {
   324  			return err
   325  		}
   326  		stmt.WriteString("),0)")
   327  		return nil
   328  	case primitive.Average:
   329  		stmt.WriteString("AVG")
   330  	case primitive.Count:
   331  		stmt.WriteString("COUNT")
   332  	case primitive.Max:
   333  		stmt.WriteString("MAX")
   334  	case primitive.Min:
   335  		stmt.WriteString("MIN")
   336  	}
   337  	stmt.WriteByte('(')
   338  	if err := b.getValue(stmt, x.Field); err != nil {
   339  		return err
   340  	}
   341  	stmt.WriteByte(')')
   342  	return nil
   343  }
   344  
   345  // BuildOperator :
   346  func (b *mySQLBuilder) BuildOperator(stmt sqlstmt.Stmt, it interface{}) error {
   347  	x := it.(primitive.Operator)
   348  	stmt.WriteByte(' ')
   349  	stmt.WriteString(operatorMap[x])
   350  	stmt.WriteByte(' ')
   351  	return nil
   352  }
   353  
   354  // BuildClause :
   355  func (b *mySQLBuilder) BuildClause(stmt sqlstmt.Stmt, it interface{}) error {
   356  	x := it.(primitive.C)
   357  	if err := b.builder.BuildStatement(stmt, x.Field); err != nil {
   358  		return err
   359  	}
   360  
   361  	stmt.WriteString(" " + operatorMap[x.Operator] + " ")
   362  	switch x.Operator {
   363  	case primitive.IsNull, primitive.NotNull:
   364  		return nil
   365  	}
   366  
   367  	if err := b.getValue(stmt, x.Value); err != nil {
   368  		return err
   369  	}
   370  	return nil
   371  }
   372  
   373  // BuildSort :
   374  func (b *mySQLBuilder) BuildSort(stmt sqlstmt.Stmt, it interface{}) error {
   375  	x := it.(primitive.Sort)
   376  	if err := b.builder.BuildStatement(stmt, x.Field); err != nil {
   377  		return err
   378  	}
   379  	if x.Order == primitive.Descending {
   380  		stmt.WriteByte(' ')
   381  		stmt.WriteString("DESC")
   382  	}
   383  	return nil
   384  }
   385  
   386  // BuildKeyValue :
   387  func (b *mySQLBuilder) BuildKeyValue(stmt sqlstmt.Stmt, it interface{}) (err error) {
   388  	x := it.(primitive.KV)
   389  	stmt.WriteString(b.Quote(string(x.Field)))
   390  	stmt.WriteString(" = ")
   391  	return b.getValue(stmt, x.Value)
   392  }
   393  
   394  // BuildMath :
   395  func (b *mySQLBuilder) BuildMath(stmt sqlstmt.Stmt, it interface{}) (err error) {
   396  	x := it.(primitive.Math)
   397  	stmt.WriteString(b.Quote(string(x.Field)) + " ")
   398  	if x.Mode == primitive.Add {
   399  		stmt.WriteByte('+')
   400  	} else {
   401  		stmt.WriteByte('-')
   402  	}
   403  	stmt.WriteString(" " + strconv.Itoa(x.Value))
   404  	return
   405  }
   406  
   407  // BuildCase :
   408  func (b *mySQLBuilder) BuildCase(stmt sqlstmt.Stmt, it interface{}) error {
   409  	x := it.(*primitive.Case)
   410  	stmt.WriteByte('(')
   411  	stmt.WriteString("CASE")
   412  	for _, w := range x.WhenClauses {
   413  		stmt.WriteString(" WHEN ")
   414  		if err := b.builder.BuildStatement(stmt, w[0]); err != nil {
   415  			return err
   416  		}
   417  		stmt.WriteString(" THEN ")
   418  		if err := b.getValue(stmt, w[1]); err != nil {
   419  			return err
   420  		}
   421  	}
   422  	stmt.WriteString(" ELSE ")
   423  	if x.ElseClause != nil {
   424  		if err := b.getValue(stmt, x.ElseClause); err != nil {
   425  			return err
   426  		}
   427  	}
   428  	stmt.WriteString(" END")
   429  	stmt.WriteByte(')')
   430  	return nil
   431  }
   432  
   433  // BuildSpatialFunc :
   434  func (b *mySQLBuilder) BuildSpatialFunc(stmt sqlstmt.Stmt, it interface{}) (err error) {
   435  	x := it.(spatial.Func)
   436  	stmt.WriteString(x.Type.String())
   437  	stmt.WriteByte('(')
   438  	for i, arg := range x.Args {
   439  		if i > 0 {
   440  			stmt.WriteByte(',')
   441  		}
   442  		if err := b.builder.BuildStatement(stmt, arg); err != nil {
   443  			return err
   444  		}
   445  	}
   446  	stmt.WriteByte(')')
   447  	return
   448  }
   449  
   450  // BuildGroup :
   451  func (b *mySQLBuilder) BuildGroup(stmt sqlstmt.Stmt, it interface{}) (err error) {
   452  	x := it.(primitive.Group)
   453  	for len(x.Values) > 0 {
   454  		if err := b.getValue(stmt, x.Values[0]); err != nil {
   455  			return err
   456  		}
   457  		x.Values = x.Values[1:]
   458  	}
   459  	return
   460  }
   461  
   462  // BuildRange :
   463  func (b *mySQLBuilder) BuildRange(stmt sqlstmt.Stmt, it interface{}) (err error) {
   464  	x := it.(primitive.R)
   465  	v := reflext.ValueOf(x.From)
   466  	encoder, err := b.registry.LookupEncoder(v)
   467  	if err != nil {
   468  		return err
   469  	}
   470  	arg, err := encoder(nil, v)
   471  	if err != nil {
   472  		return err
   473  	}
   474  	stmt.AppendArgs(arg)
   475  
   476  	v = reflext.ValueOf(x.To)
   477  	encoder, err = b.registry.LookupEncoder(v)
   478  	if err != nil {
   479  		return err
   480  	}
   481  	arg, err = encoder(nil, v)
   482  	if err != nil {
   483  		return err
   484  	}
   485  	stmt.AppendArgs(arg)
   486  	stmt.WriteByte('?')
   487  	stmt.WriteString(" AND ")
   488  	stmt.WriteByte('?')
   489  	return
   490  }
   491  
   492  // BuildEncoding :
   493  func (b *mySQLBuilder) BuildEncoding(stmt sqlstmt.Stmt, it interface{}) (err error) {
   494  	x := it.(primitive.Encoding)
   495  	if x.Charset != nil {
   496  		if (*x.Charset)[0] != '_' {
   497  			stmt.WriteString("_")
   498  		}
   499  		stmt.WriteString(*x.Charset + " ")
   500  	}
   501  	err = b.builder.BuildStatement(stmt, x.Column)
   502  	if err != nil {
   503  		return
   504  	}
   505  	stmt.WriteString(" COLLATE " + x.Collate)
   506  	return
   507  }
   508  
   509  // BuildTypeSafe :
   510  func (b *mySQLBuilder) BuildTypeSafe(stmt sqlstmt.Stmt, it interface{}) (err error) {
   511  	ts := it.(primitive.TypeSafe)
   512  	switch ts.Type {
   513  	case reflect.String:
   514  		stmt.WriteString(strconv.Quote(ts.Value.(string)))
   515  	case reflect.Bool:
   516  		v := ts.Value.(bool)
   517  		if v {
   518  			stmt.WriteString("1")
   519  		} else {
   520  			stmt.WriteString("0")
   521  		}
   522  	case reflect.Int:
   523  		stmt.WriteString(strconv.FormatInt(int64(ts.Value.(int)), 10))
   524  	case reflect.Int8:
   525  		stmt.WriteString(strconv.FormatInt(int64(ts.Value.(int8)), 10))
   526  	case reflect.Int16:
   527  		stmt.WriteString(strconv.FormatInt(int64(ts.Value.(int16)), 10))
   528  	case reflect.Int32:
   529  		stmt.WriteString(strconv.FormatInt(int64(ts.Value.(int32)), 10))
   530  	case reflect.Int64:
   531  		stmt.WriteString(strconv.FormatInt(ts.Value.(int64), 10))
   532  	case reflect.Uint:
   533  		stmt.WriteString(strconv.FormatUint(uint64(ts.Value.(uint)), 10))
   534  	case reflect.Uint8:
   535  		stmt.WriteString(strconv.FormatUint(uint64(ts.Value.(uint8)), 10))
   536  	case reflect.Uint16:
   537  		stmt.WriteString(strconv.FormatUint(uint64(ts.Value.(uint16)), 10))
   538  	case reflect.Uint32:
   539  		stmt.WriteString(strconv.FormatUint(uint64(ts.Value.(uint32)), 10))
   540  	case reflect.Uint64:
   541  		stmt.WriteString(strconv.FormatUint(ts.Value.(uint64), 10))
   542  	case reflect.Float32:
   543  		stmt.WriteString(strconv.FormatFloat(float64(ts.Value.(float32)), 'e', -1, 64))
   544  	case reflect.Float64:
   545  		stmt.WriteString(strconv.FormatFloat(ts.Value.(float64), 'e', -1, 64))
   546  	}
   547  	return
   548  }
   549  
   550  // BuildSelectStmt :
   551  func (b *mySQLBuilder) BuildSelectStmt(stmt sqlstmt.Stmt, it interface{}) error {
   552  	x := it.(*sql.SelectStmt)
   553  	stmt.WriteString("SELECT ")
   554  	if x.DistinctOn {
   555  		stmt.WriteString("DISTINCT ")
   556  	}
   557  	if err := b.appendSelect(stmt, x.Projections); err != nil {
   558  		return err
   559  	}
   560  	stmt.WriteString(" FROM ")
   561  	if err := b.appendTable(stmt, x.Tables); err != nil {
   562  		return err
   563  	}
   564  	if err := b.appendWhere(stmt, x.Conditions.Values); err != nil {
   565  		return err
   566  	}
   567  	if err := b.appendGroupBy(stmt, x.Groups); err != nil {
   568  		return err
   569  	}
   570  	if err := b.appendOrderBy(stmt, x.Sorts); err != nil {
   571  		return err
   572  	}
   573  	b.appendLimitNOffset(stmt, x.Max, x.Skip)
   574  	return nil
   575  }
   576  
   577  // BuildUpdateStmt :
   578  func (b *mySQLBuilder) BuildUpdateStmt(stmt sqlstmt.Stmt, it interface{}) error {
   579  	x := it.(*sql.UpdateStmt)
   580  	stmt.WriteString("UPDATE " + b.TableName(x.Database, x.Table) + ` `)
   581  	if err := b.appendSet(stmt, x.Values); err != nil {
   582  		return err
   583  	}
   584  	if err := b.appendWhere(stmt, x.Conditions.Values); err != nil {
   585  		return err
   586  	}
   587  	if err := b.appendOrderBy(stmt, x.Sorts); err != nil {
   588  		return err
   589  	}
   590  	b.appendLimitNOffset(stmt, x.Max, 0)
   591  	return nil
   592  }
   593  
   594  // BuildFindActions :
   595  func (b *mySQLBuilder) BuildFindActions(stmt sqlstmt.Stmt, it interface{}) error {
   596  	x := it.(*actions.FindActions)
   597  	x.Table = strings.TrimSpace(x.Table)
   598  	if x.Table == "" {
   599  		return errors.New("mysql: empty table name")
   600  	}
   601  	stmt.WriteString("SELECT ")
   602  	if x.DistinctOn {
   603  		stmt.WriteString("DISTINCT ")
   604  	}
   605  	if err := b.appendSelect(stmt, x.Projections); err != nil {
   606  		return err
   607  	}
   608  	stmt.WriteString(" FROM " + b.TableName(x.Database, x.Table))
   609  	if err := b.appendWhere(stmt, x.Conditions.Values); err != nil {
   610  		return err
   611  	}
   612  	if err := b.appendGroupBy(stmt, x.GroupBys); err != nil {
   613  		return err
   614  	}
   615  	if err := b.appendOrderBy(stmt, x.Sorts); err != nil {
   616  		return err
   617  	}
   618  	b.appendLimitNOffset(stmt, x.Count, x.Skip)
   619  
   620  	return nil
   621  }
   622  
   623  // BuildUpdateActions :
   624  func (b *mySQLBuilder) BuildUpdateActions(stmt sqlstmt.Stmt, it interface{}) error {
   625  	x, ok := it.(*actions.UpdateActions)
   626  	if !ok {
   627  		return errors.New("data type not match")
   628  	}
   629  	stmt.WriteString("UPDATE " + b.TableName(x.Database, x.Table) + ` `)
   630  	if err := b.appendSet(stmt, x.Values); err != nil {
   631  		return err
   632  	}
   633  	if err := b.appendWhere(stmt, x.Conditions); err != nil {
   634  		return err
   635  	}
   636  	if err := b.appendOrderBy(stmt, x.Sorts); err != nil {
   637  		return err
   638  	}
   639  	b.appendLimitNOffset(stmt, x.Record, 0)
   640  	return nil
   641  }
   642  
   643  // BuildDeleteActions :
   644  func (b *mySQLBuilder) BuildDeleteActions(stmt sqlstmt.Stmt, it interface{}) error {
   645  	x := it.(*actions.DeleteActions)
   646  	stmt.WriteString("DELETE FROM " + b.TableName(x.Database, x.Table))
   647  	if err := b.appendWhere(stmt, x.Conditions); err != nil {
   648  		return err
   649  	}
   650  	if err := b.appendOrderBy(stmt, x.Sorts); err != nil {
   651  		return err
   652  	}
   653  	b.appendLimitNOffset(stmt, x.Record, 0)
   654  	return nil
   655  }
   656  
   657  func (b *mySQLBuilder) getValue(stmt sqlstmt.Stmt, it interface{}) (err error) {
   658  	v := reflext.ValueOf(it)
   659  	if !v.IsValid() {
   660  		stmt.WriteByte('?')
   661  		stmt.AppendArgs(nil)
   662  		return
   663  	}
   664  
   665  	t := v.Type()
   666  	if builder, ok := b.builder.LookupBuilder(t); ok {
   667  		if err := builder(stmt, it); err != nil {
   668  			return err
   669  		}
   670  		return nil
   671  	}
   672  
   673  	encoder, err := b.registry.LookupEncoder(v)
   674  	if err != nil {
   675  		return err
   676  	}
   677  	vv, err := encoder(nil, v)
   678  	if err != nil {
   679  		return err
   680  	}
   681  	// stmt.WriteByte('?')
   682  	// stmt.AppendArgs(vv)
   683  	convertSpatial(stmt, vv)
   684  	return
   685  }
   686  
   687  func (b *mySQLBuilder) appendSelect(stmt sqlstmt.Stmt, pjs []interface{}) error {
   688  	if len(pjs) > 0 {
   689  		length := len(pjs)
   690  		for i := 0; i < length; i++ {
   691  			if i > 0 {
   692  				stmt.WriteByte(',')
   693  			}
   694  			if err := b.builder.BuildStatement(stmt, pjs[i]); err != nil {
   695  				return err
   696  			}
   697  		}
   698  		return nil
   699  	}
   700  	stmt.WriteString("*")
   701  	return nil
   702  }
   703  
   704  func (b *mySQLBuilder) appendTable(stmt sqlstmt.Stmt, fields []interface{}) error {
   705  	length := len(fields)
   706  	if length > 0 {
   707  		for i := 0; i < length; i++ {
   708  			if i > 0 {
   709  				stmt.WriteByte(' ')
   710  			}
   711  			if err := b.builder.BuildStatement(stmt, fields[i]); err != nil {
   712  				return err
   713  			}
   714  		}
   715  	}
   716  	return nil
   717  }
   718  
   719  func (b *mySQLBuilder) appendWhere(stmt sqlstmt.Stmt, conds []interface{}) error {
   720  	length := len(conds)
   721  	if length > 0 {
   722  		stmt.WriteString(" WHERE ")
   723  		for i := 0; i < length; i++ {
   724  			if err := b.builder.BuildStatement(stmt, conds[i]); err != nil {
   725  				return err
   726  			}
   727  		}
   728  	}
   729  	return nil
   730  }
   731  
   732  func (b *mySQLBuilder) appendGroupBy(stmt sqlstmt.Stmt, fields []interface{}) error {
   733  	length := len(fields)
   734  	if length > 0 {
   735  		stmt.WriteString(" GROUP BY ")
   736  		for i := 0; i < length; i++ {
   737  			if i > 0 {
   738  				stmt.WriteByte(',')
   739  			}
   740  			if err := b.builder.BuildStatement(stmt, fields[i]); err != nil {
   741  				return err
   742  			}
   743  		}
   744  	}
   745  	return nil
   746  }
   747  
   748  func (b *mySQLBuilder) appendOrderBy(stmt sqlstmt.Stmt, sorts []interface{}) error {
   749  	length := len(sorts)
   750  	if length < 1 {
   751  		return nil
   752  	}
   753  	stmt.WriteString(" ORDER BY ")
   754  	for i := 0; i < length; i++ {
   755  		if i > 0 {
   756  			stmt.WriteByte(',')
   757  		}
   758  		if err := b.builder.BuildStatement(stmt, sorts[i]); err != nil {
   759  			return err
   760  		}
   761  	}
   762  	return nil
   763  }
   764  
   765  func (b *mySQLBuilder) appendLimitNOffset(stmt sqlstmt.Stmt, limit, offset uint) {
   766  	if limit > 0 {
   767  		stmt.WriteString(" LIMIT " + strconv.FormatUint(uint64(limit), 10))
   768  	}
   769  	if offset > 0 {
   770  		stmt.WriteString(" OFFSET " + strconv.FormatUint(uint64(offset), 10))
   771  	}
   772  }
   773  
   774  func (b *mySQLBuilder) appendSet(stmt sqlstmt.Stmt, values []primitive.KV) error {
   775  	length := len(values)
   776  	if length > 0 {
   777  		stmt.WriteString("SET ")
   778  		for i := 0; i < length; i++ {
   779  			if i > 0 {
   780  				stmt.WriteByte(',')
   781  			}
   782  			if err := b.builder.BuildStatement(stmt, values[i]); err != nil {
   783  				return err
   784  			}
   785  		}
   786  	}
   787  	return nil
   788  }
   789  
   790  func escapeWildCard(n string) string {
   791  	length := len(n) - 1
   792  	if length < 1 {
   793  		return n
   794  	}
   795  	blr := new(strings.Builder)
   796  	for i := 0; i < length; i++ {
   797  		switch n[i] {
   798  		case '%':
   799  			blr.WriteString(`\%`)
   800  		case '_':
   801  			blr.WriteString(`\_`)
   802  		case '\\':
   803  			blr.WriteString(`\\`)
   804  		default:
   805  			blr.WriteByte(n[i])
   806  		}
   807  	}
   808  	blr.WriteByte(n[length])
   809  	return blr.String()
   810  }
   811  
   812  func unmatchedDataType(callback string) error {
   813  	return errors.New("mysql: invalid data type")
   814  }