// Package gormlite provides a GORM driver for SQLite.
package gormlite import ( ) type _Dialector struct { DSN string Conn gorm.ConnPool } // Open opens a GORM dialector from a data source name. func ( string) gorm.Dialector { return &_Dialector{DSN: } } // Open opens a GORM dialector from a database handle. func ( gorm.ConnPool) gorm.Dialector { return &_Dialector{Conn: } } func ( _Dialector) () string { return "sqlite" } func ( _Dialector) ( *gorm.DB) ( error) { if .Conn != nil { .ConnPool = .Conn } else { , := driver.Open(.DSN) if != nil { return } .ConnPool = } callbacks.RegisterDefaultCallbacks(, &callbacks.Config{ CreateClauses: []string{"INSERT", "VALUES", "ON CONFLICT", "RETURNING"}, UpdateClauses: []string{"UPDATE", "SET", "FROM", "WHERE", "RETURNING"}, DeleteClauses: []string{"DELETE", "FROM", "WHERE", "RETURNING"}, LastInsertIDReversed: true, }) for , := range .ClauseBuilders() { .ClauseBuilders[] = } return } func ( _Dialector) () map[string]clause.ClauseBuilder { return map[string]clause.ClauseBuilder{ "INSERT": func( clause.Clause, clause.Builder) { if , := .Expression.(clause.Insert); { if , := .(*gorm.Statement); { .WriteString("INSERT ") if .Modifier != "" { .WriteString(.Modifier) .WriteByte(' ') } .WriteString("INTO ") if .Table.Name == "" { .WriteQuoted(.Table) } else { .WriteQuoted(.Table) } return } } .Build() }, "LIMIT": func( clause.Clause, clause.Builder) { if , := .Expression.(clause.Limit); { var = -1 if .Limit != nil && *.Limit >= 0 { = *.Limit } if >= 0 || .Offset > 0 { .WriteString("LIMIT ") .WriteString(strconv.Itoa()) } if .Offset > 0 { .WriteString(" OFFSET ") .WriteString(strconv.Itoa(.Offset)) } } }, "FOR": func( clause.Clause, clause.Builder) { if , := .Expression.(clause.Locking); { // SQLite3 does not support row-level locking. return } .Build() }, } } func ( _Dialector) ( *schema.Field) clause.Expression { if .AutoIncrement { return clause.Expr{SQL: "NULL"} } // doesn't work, will raise error return clause.Expr{SQL: "DEFAULT"} } func ( _Dialector) ( *gorm.DB) gorm.Migrator { return _Migrator{migrator.Migrator{Config: migrator.Config{ DB: , Dialector: , CreateIndexAfterCreateTable: true, }}} } func ( _Dialector) ( clause.Writer, *gorm.Statement, interface{}) { .WriteByte('?') } func ( _Dialector) ( clause.Writer, string) { var ( , bool int8 int8 ) for , := range []byte() { switch { case '`': ++ if == 2 { .WriteString("``") = 0 } case '.': if > 0 || ! { = 0 = false = 0 .WriteString("`") } .WriteByte() continue default: if - <= 0 && ! { .WriteString("`") = true if = > 0; { -= 1 } } for ; > 0; -= 1 { .WriteString("``") } .WriteByte() } ++ } if > 0 && ! { .WriteString("``") } .WriteString("`") } func ( _Dialector) ( string, ...interface{}) string { return logger.ExplainSQL(, nil, `"`, ...) } func ( _Dialector) ( *schema.Field) string { switch .DataType { case schema.Bool: return "numeric" case schema.Int, schema.Uint: if .AutoIncrement { // doesn't check `PrimaryKey`, to keep backward compatibility // https://sqlite.org/autoinc.html return "integer PRIMARY KEY AUTOINCREMENT" } else { return "integer" } case schema.Float: return "real" case schema.String: return "text" case schema.Time: // Distinguish between schema.Time and tag time if , := .TagSettings["TYPE"]; { return } else { return "datetime" } case schema.Bytes: return "blob" } return string(.DataType) } func ( _Dialector) ( *gorm.DB, string) error { .Exec("SAVEPOINT " + ) return nil } func ( _Dialector) ( *gorm.DB, string) error { .Exec("ROLLBACK TO SAVEPOINT " + ) return nil }