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 }