filesql

repository·main·Indexed 18 days ago

https://github.com/nao1215/filesql

A Go library that enables SQL querying on various file formats (CSV, TSV, LTSV, Parquet, and XLSX) by loading them into an in-memory SQLite database. It provides a pipeline for loading, cleaning (prep), and in-memory transformation (frame). filesql returns a standard *sql.DB instance, making it compatible with Go database tools and ORMs including Bun, Ent, GORM, sqlc, sqlx, and Squirrel.

Tokens
20.8K
Snippets
81
Records
102
Agent score
60%

What's inside filesql

  1. Overview of filesql

    main

    filesql is a Go library that loads various file formats into an in-memory SQLite database, allowing you to query them using standard SQL syntax. It is designed for scenarios where data is already in files and SQL is the most efficient way to process it.

    Core Capabilities:

    • Join across formats: Join data from CSV, TSV, LTSV, JSON, JSONL, Parquet, XLSX, ACH, or Fedwire.
    • Flexible Input: Read from file paths, directories, io.Reader, or embed.FS.
    • Transparent Compression: Automatically handles .gz, .bz2, .xz, .zst, .z, .snappy, .s2, and .lz4 wrappers for supported text and columnar formats.
    • Companion Packages:
      • prep: For cleaning and validating rows before they are loaded as tables.
      • frame: For performing in-memory transformations on small/medium datasets using plain Go instead of SQL.
  2. Handle concurrency with filesql

    main

    The *sql.DB returned by Open and OpenContext is safe to share across goroutines. filesql uses a shared-cache in-memory SQLite database, allowing pooled connections to see the same tables.

    Important for LoadInto: When using LoadInto, you manage the database and pool settings. If you are using sql.Open("sqlite", ":memory:"), you must set SetMaxOpenConns(1) to ensure every query hits the same in-memory database instance.

  3. Manage memory and chunked loading in filesql

    main

    filesql loads data into an in-memory SQLite database. To manage memory usage, the library uses chunked loading for certain formats.

    Memory Behavior:

    • Chunked Loading: CSV, TSV, and JSON arrays are read in chunks. This keeps the Go heap usage low (roughly the size of one chunk), but the resident memory will grow to approximately 2x the file's size because the data is stored in the in-memory SQLite database.
    • Full Loading: LTSV, non-array JSON/JSONL, Parquet, XLSX, ACH, and Fedwire are read in full before being converted to rows.

    To tune the memory/performance tradeoff for chunked formats, use SetDefaultChunkSize on the builder.

    validatedBuilder, err := filesql.NewBuilder().
    	AddPath("large.csv").
    	SetDefaultChunkSize(5000).
    	Build(ctx)
  4. Configure Bun models for filesql tables

    main

    When using Bun with filesql, you must define your Go structs to match the file's structure using Bun's struct tags:

    • Embed bun.BaseModel in your struct.
    • Use the bun:"table:xxx" tag to specify the name of the file/table.
    • Use bun:"column,pk" tags to define primary keys and map specific columns.
    type User struct {
    	bun.BaseModel `bun:"table:users"` // Maps to the users file
    
    	ID    int64  `bun:"id,pk"`      // Primary key
    	Name  string `bun:"name"`       // Column mapping
    	Email string `bun:"email"`      // Column mapping
    	Age   int    `bun:"age"`        // Column mapping
    }
  5. Experimental support for ACH and Fedwire

    main
    filesql provides experimental support for ACH (.ach) and Fedwire (.fed) files. These are useful for inspection, joins, and controlled updates, but users should note that exported files still require domain-specific knowledge to be fully valid.
  6. Configure GORM struct mapping for CSV files

    main

    When using GORM with filesql, you must explicitly map struct fields to the CSV column names using the gorm:"column:xxx" tag. Additionally, because filesql treats files as tables, you must implement the TableName() string method on your model struct to specify the filename (excluding the extension) that GORM should target.

    type User struct {
        ID    int    `gorm:"column:id"` 
        Name  string `gorm:"column:name"` 
    }
    
    func (User) TableName() string {
        return "users" // targets users.csv
    }
  7. Save in-memory changes to files

    main

    Changes made to the data live in memory until an explicit save operation is performed. You can use the following methods to persist data:

    • DumpDatabase: Writes the current database state to files (explicit export).
    • EnableAutoSave: Automatically saves changes when db.Close() is called.
    • EnableAutoSaveOnCommit: Automatically saves changes after every committed transaction.
  8. Run the Squirrel integration example

    main

    To run the standalone Squirrel integration example, ensure you have the Squirrel dependency installed, then navigate to the example directory to run the main entry point.

    go get github.com/Masterminds/squirrel
    
    cd examples/squirrel
    go mod tidy
    go run main.go