fragmenta / query

An SQL query builder for golang
MIT License
41 stars 10 forks source link

Query GoDoc Go Report Card

Query lets you build SQL queries with chainable methods, and defer execution of SQL until you wish to extract a count or array of models. It will probably remain limited in scope - it is not intended to be a full ORM with strict mapping between db tables and structs, but a tool for querying the database with minimum friction, and performing CRUD operations linked to models; simplifying your use of SQL to store model data without getting in the way. Full or partial SQL queries are of course also available, and full control over sql. Model creation and column are delegated to the model, to avoid dictating any particular model structure or interface, however a suggested interface is given (see below and in tests), which makes usage painless in your handlers without any boilerplate.

Supported databases: PostgreSQL, SQLite, MySQL. Bug fixes, suggestions and contributions welcome.

Usage


// In your app - open a database with options
options := map[string]string{"adapter":"postgres","db":"query_test"}
err := query.OpenDatabase(options)
defer query.CloseDatabase()

...

// In your model
type Page struct {
    ID          int64
    CreatedAt   time.Time
    UpdatedAt   time.Time
    MyField     myStruct
    ...
    // Models can have any structure, any PK, here an int is used
}

// Normally you'd define helpers on your model class to load rows from the database
// Query does not attempt to read data into columns with reflection or tags - 
// that is left to your model so you can read as little or as much as you want from queries

func Find(ID int64) (*Page, error) {
    result, err := PagesQuery().Where("id=?", ID).FirstResult()
    if err != nil {
        return nil, err
    }
    return NewWithColumns(result), nil
}

func FindAll(q *Query) ([]*Page, error) {
    results, err := q.Results()
    if err != nil {
        return nil, err
    }

    var models []*Page
    for _, r := range results {
        m := NewWithColumns(r)
        models = append(models, m)
    }

    return models, nil
}

...

// In your handlers, construct queries and ask your models for the data

// Find a simple model by id
page, err := pages.Find(1)

// Start querying the database using chained finders
q := page.Query().Where("id IN (?,?)",4,5).Order("id desc").Limit(30)

// Build up chains depending on other app logic, still no db requests
if shouldRestrict {
    q.Where("id > ?",3).OrWhere("keywords ~* ?","Page")
}

// Pass the relation around, until you are ready to retrieve models from the db
results, err := pages.FindAll(q)

What it does

What it doesn't do

Tests

All 3 databases supported have a test suite - to run the tests, create a database called query_test in mysql and psql then run go test at the root of the package. The sqlite tests are disabled by default because enabling them prohibits cross compilation, which is useful if you don't want to install go on your server but just upload a binary compiled locally.

go test

Versions