glebarez/sqlite

repository·master·Indexed 21 days ago

https://github.com/glebarez/sqlite

A pure-Go (CGO-free) SQLite driver for GORM. It enables the use of SQLite in Go applications without requiring C compilers, facilitating easier cross-compilation and deployment in minimal container environments like golang-alpine or restricted cloud platforms. The driver includes a Migrator for schema operations, support for in-memory databases, and mapping of Go types to SQLite-compatible types.

Tokens
2.5K
Snippets
12
Records
16
Agent score
75%

What's inside glebarez/sqlite

  1. Compare glebarez/sqlite with the standard GORM SQLite driver

    master

    The primary difference is that the standard go-gorm/sqlite driver relies on go-sqlite3, which requires CGO. This imposes several constraints that glebarez/sqlite avoids:

    • No C Compiler Required: You don't need gcc installed to build or run your code.
    • Easier Containerization: You can build in tiny, stripped-down containers like golang-alpine without installing build tools.
    • Cloud Compatibility: Works on platforms like Google Cloud Platform (GCP) that may restrict gcc execution.
    • Simplified Feature Management: You don't need to manage complex build tags for SQLite features like JSON support.

    Note on Performance: Because this is a pure-Go implementation, it is generally slower than the CGO-based implementation, though the performance gap is not considered extreme.

  2. Use the glebarez/sqlite driver with GORM

    master

    To use this driver, import github.com/glebarez/sqlite and pass sqlite.Open(filename) to gorm.Open. This driver is a pure-Go implementation, meaning it does not require CGO or a C compiler to build or run, making it ideal for cross-compilation and minimal container environments (like golang-alpine).

    import (
      "github.com/glebarez/sqlite"
      "gorm.io/gorm"
    )
    
    db, err := gorm.Open(sqlite.Open("sqlite.db"), &gorm.Config{})
  3. Activate Foreign-key constraints

    master

    Foreign-key constraints are disabled by default in SQLite. To enable them, append the _pragma=foreign_keys(1) parameter to your connection string via the connection URL.

    db, err := gorm.Open(sqlite.Open(":memory:?_pragma=foreign_keys(1)"), &gorm.Config{})
  4. Error translation for SQLite constraints

    master

    The driver translates specific gosqlite error codes into standard GORM errors. This allows you to handle database constraints using GORM's error constants:

    • sqlite3.SQLITE_CONSTRAINT_UNIQUE $\rightarrow$ gorm.ErrDuplicatedKey
    • sqlite3.SQLITE_CONSTRAINT_PRIMARYKEY $\rightarrow$ gorm.ErrDuplicatedKey
    • sqlite3.SQLITE_CONSTRAINT_FOREIGNKEY $\rightarrow$ gorm.ErrForeignKeyViolated
    • sqlite3.SQLITE_CONSTRAINT_CHECK $\rightarrow$ gorm.ErrCheckConstraintViolated
  5. Use Generated Columns in SQLite

    master

    The driver supports SQLite generated columns via the GENERATED tag on model fields. If the tag contains an expression (and is not the identity keyword), the driver renders the column as GENERATED ALWAYS AS (<expression>) STORED.

    type User struct {
    	ID   uint
    	Name string
    	// Example of a generated column
    	UpperName string `gorm:"GENERATED:upper(name)"`
    }
  6. Use the SQLite Migrator for schema operations

    master

    The Migrator type in the sqlite package extends the standard GORM migrator.Migrator to provide SQLite-specific schema management. Because SQLite has limited support for ALTER TABLE (e.g., it cannot easily drop columns or change constraints), this implementation often uses a 'recreate table' pattern: creating a temporary table with the new schema, migrating data, dropping the old table, and renaming the new one.

    Key capabilities include:

    • Table Management: HasTable, GetTables, DropTable (handles foreign key constraints automatically).
    • Column Management: HasColumn, AlterColumn, DropColumn (uses the recreation pattern).
    • Constraint Management: CreateConstraint, DropConstraint, HasConstraint (uses the recreation pattern).
    • Index Management: CreateIndex, DropIndex, HasIndex, GetIndexes, RenameIndex.
    • Database Inspection: CurrentDatabase, ColumnTypes.
  7. Manage indexes in SQLite

    master

    The Migrator provides full lifecycle management for indexes:

    • CreateIndex: Creates a new index based on the model's index tags.
    • DropIndex: Removes an index by name.
    • HasIndex: Checks if an index exists.
    • GetIndexes: Retrieves a list of gorm.Index objects for a model, excluding indexes created by UNIQUE constraints (which are handled as constraints).
    • RenameIndex: Renames an existing index by dropping and recreating it.
    // Create an index
    err := m.CreateIndex(&User{})
    
    // Check if an index exists
    exists := m.HasIndex(&User{}, "idx_user_email")
    
    // Get all indexes
    indexes, err := m.GetIndexes(&User{})
  8. Initialize the SQLite driver with New() and Config

    master

    Use New(config Config) when you need more control over the initialization, such as providing a custom DriverName or an existing gorm.ConnPool (e.g., a *sql.DB instance you have already configured).

    import (
    	"database/sql"
    	"gorm.io/gorm"
    	sqlite "github.com/glebarez/glebarez/sqlite"
    )
    
    // Using a pre-existing sql.DB connection
    sqlDB, _ := sql.Open("sqlite", "gorm.db")
    
    dialector := sqlite.New(sqlite.Config{
    	DriverName: "sqlite",
    	DSN:        "gorm.db",
    	Conn:       sqlDB,
    })
    
    db, err := gorm.Open(dialector, &gorm.Config{})
  9. Get column types for a model

    master

    The ColumnTypes method returns a slice of gorm.ColumnType objects for a given model. It works by parsing the sqlite_master DDL and combining it with the actual column information from the database to provide a complete view of the schema.

    columnTypes, err := m.ColumnTypes(&User{})
    if err != nil {
        // handle error
    }
    for _, ct := range columnTypes {
        fmt.Printf("Column: %s, Type: %s\n", ct.Name(), ct.DatabaseTypeName())
    }
  10. Drop a table safely with foreign keys

    master

    The DropTable method is enhanced to handle foreign key constraints. It uses RunWithoutForeignKey to disable constraints during the operation and reorders models to ensure tables are dropped in an order that minimizes constraint violations.

    // Drops multiple tables safely
    err := m.DropTable(&User{}, &Profile{})
  11. Alter a column in SQLite

    master

    The AlterColumn method allows you to change the definition of an existing column. Since SQLite does not support direct column alteration for many types of changes, this method performs a table recreation under the hood. It attempts to preserve existing UNIQUE constraints if they are detected in the original DDL.

    // Example: Altering a column named 'Email' on the User model
    err := m.AlterColumn(&User{}, "Email")