github.com/mdaxf/iac@v0.0.0-20240519030858-58a061660378/databases/orm/db_sqllit.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  	"database/sql"
    23  	"fmt"
    24  	"reflect"
    25  	"strings"
    26  	"time"
    27  
    28  	"github.com/mdaxf/iac/databases/orm/hints"
    29  )
    30  
    31  // sqlite operators.
    32  var sqliteOperators = map[string]string{
    33  	"exact":       "= ?",
    34  	"iexact":      "LIKE ? ESCAPE '\\'",
    35  	"contains":    "LIKE ? ESCAPE '\\'",
    36  	"icontains":   "LIKE ? ESCAPE '\\'",
    37  	"gt":          "> ?",
    38  	"gte":         ">= ?",
    39  	"lt":          "< ?",
    40  	"lte":         "<= ?",
    41  	"eq":          "= ?",
    42  	"ne":          "!= ?",
    43  	"startswith":  "LIKE ? ESCAPE '\\'",
    44  	"endswith":    "LIKE ? ESCAPE '\\'",
    45  	"istartswith": "LIKE ? ESCAPE '\\'",
    46  	"iendswith":   "LIKE ? ESCAPE '\\'",
    47  }
    48  
    49  // sqlite column types.
    50  var sqliteTypes = map[string]string{
    51  	"auto":                "integer NOT NULL PRIMARY KEY AUTOINCREMENT",
    52  	"pk":                  "NOT NULL PRIMARY KEY",
    53  	"bool":                "bool",
    54  	"string":              "varchar(%d)",
    55  	"string-char":         "character(%d)",
    56  	"string-text":         "text",
    57  	"time.Time-date":      "date",
    58  	"time.Time":           "datetime",
    59  	"time.Time-precision": "datetime(%d)",
    60  	"int8":                "tinyint",
    61  	"int16":               "smallint",
    62  	"int32":               "integer",
    63  	"int64":               "bigint",
    64  	"uint8":               "tinyint unsigned",
    65  	"uint16":              "smallint unsigned",
    66  	"uint32":              "integer unsigned",
    67  	"uint64":              "bigint unsigned",
    68  	"float64":             "real",
    69  	"float64-decimal":     "decimal",
    70  }
    71  
    72  // sqlite dbBaser.
    73  type dbBaseSqlite struct {
    74  	dbBase
    75  }
    76  
    77  var _ dbBaser = new(dbBaseSqlite)
    78  
    79  // override base db read for update behavior as SQlite does not support syntax
    80  func (d *dbBaseSqlite) Read(ctx context.Context, q dbQuerier, mi *modelInfo, ind reflect.Value, tz *time.Location, cols []string, isForUpdate bool) error {
    81  	if isForUpdate {
    82  		DebugLog.Println("[WARN] SQLite does not support SELECT FOR UPDATE query, isForUpdate param is ignored and always as false to do the work")
    83  	}
    84  	return d.dbBase.Read(ctx, q, mi, ind, tz, cols, false)
    85  }
    86  
    87  // get sqlite operator.
    88  func (d *dbBaseSqlite) OperatorSQL(operator string) string {
    89  	return sqliteOperators[operator]
    90  }
    91  
    92  // generate functioned sql for sqlite.
    93  // only support DATE(text).
    94  func (d *dbBaseSqlite) GenerateOperatorLeftCol(fi *fieldInfo, operator string, leftCol *string) {
    95  	if fi.fieldType == TypeDateField {
    96  		*leftCol = fmt.Sprintf("DATE(%s)", *leftCol)
    97  	}
    98  }
    99  
   100  // unable updating joined record in sqlite.
   101  func (d *dbBaseSqlite) SupportUpdateJoin() bool {
   102  	return false
   103  }
   104  
   105  // max int in sqlite.
   106  func (d *dbBaseSqlite) MaxLimit() uint64 {
   107  	return 9223372036854775807
   108  }
   109  
   110  // get column types in sqlite.
   111  func (d *dbBaseSqlite) DbTypes() map[string]string {
   112  	return sqliteTypes
   113  }
   114  
   115  // get show tables sql in sqlite.
   116  func (d *dbBaseSqlite) ShowTablesQuery() string {
   117  	return "SELECT name FROM sqlite_master WHERE type = 'table'"
   118  }
   119  
   120  // get columns in sqlite.
   121  func (d *dbBaseSqlite) GetColumns(ctx context.Context, db dbQuerier, table string) (map[string][3]string, error) {
   122  	query := d.ins.ShowColumnsQuery(table)
   123  	rows, err := db.QueryContext(ctx, query)
   124  	if err != nil {
   125  		return nil, err
   126  	}
   127  
   128  	columns := make(map[string][3]string)
   129  	for rows.Next() {
   130  		var tmp, name, typ, null sql.NullString
   131  		err := rows.Scan(&tmp, &name, &typ, &null, &tmp, &tmp)
   132  		if err != nil {
   133  			return nil, err
   134  		}
   135  		columns[name.String] = [3]string{name.String, typ.String, null.String}
   136  	}
   137  
   138  	return columns, nil
   139  }
   140  
   141  // get show columns sql in sqlite.
   142  func (d *dbBaseSqlite) ShowColumnsQuery(table string) string {
   143  	return fmt.Sprintf("pragma table_info('%s')", table)
   144  }
   145  
   146  // check index exist in sqlite.
   147  func (d *dbBaseSqlite) IndexExists(ctx context.Context, db dbQuerier, table string, name string) bool {
   148  	query := fmt.Sprintf("PRAGMA index_list('%s')", table)
   149  	rows, err := db.QueryContext(ctx, query)
   150  	if err != nil {
   151  		panic(err)
   152  	}
   153  	defer rows.Close()
   154  	for rows.Next() {
   155  		var tmp, index sql.NullString
   156  		rows.Scan(&tmp, &index, &tmp, &tmp, &tmp)
   157  		if name == index.String {
   158  			return true
   159  		}
   160  	}
   161  	return false
   162  }
   163  
   164  // GenerateSpecifyIndex return a specifying index clause
   165  func (d *dbBaseSqlite) GenerateSpecifyIndex(tableName string, useIndex int, indexes []string) string {
   166  	var s []string
   167  	Q := d.TableQuote()
   168  	for _, index := range indexes {
   169  		tmp := fmt.Sprintf(`%s%s%s`, Q, index, Q)
   170  		s = append(s, tmp)
   171  	}
   172  
   173  	switch useIndex {
   174  	case hints.KeyUseIndex, hints.KeyForceIndex:
   175  		return fmt.Sprintf(` INDEXED BY %s `, strings.Join(s, `,`))
   176  	default:
   177  		DebugLog.Println("[WARN] Not a valid specifying action, so that action is ignored")
   178  		return ``
   179  	}
   180  }
   181  
   182  // create new sqlite dbBaser.
   183  func newdbBaseSqlite() dbBaser {
   184  	b := new(dbBaseSqlite)
   185  	b.ins = b
   186  	return b
   187  }