Awesome Open Source
Awesome Open Source


GoDoc Build Status Go Report Card Maintainability Test Coverage FOSSA Status

⚠️ Grimoire V2 is available as REL and Changeset package.

Grimoire is a database access layer inspired by Ecto. It features a flexible query API and built-in validation. It currently supports MySQL, PostgreSQL, and SQLite3 but a custom adapter can be implemented easily using the Adapter interface.


  • Query Builder
  • Association Preloading
  • Struct style create and update
  • Changeset Style create and update
  • Builtin validation using changeset
  • Multi adapter support
  • Logger


Common go ORM accepts struct as a value for modifying records which has a problem of unable to differentiate between an empty, nil, or undefined value. It's a tricky problem especially when you want to have an endpoint that supports partial updates. Grimoire attempts to solve that problem by integrating Changeset system inspired from Elixir's Ecto. Changeset is a form like entity which allows us to not only solve that problem but also help us with casting, validations, and constraints check.


go get

Quick Start

package main

import (


type Product struct {
	ID        int
	Name      string
	Price     int
	CreatedAt time.Time
	UpdatedAt time.Time

// ChangeProduct prepares data before database operation.
// Such as casting value to appropriate types and perform validations.
func ChangeProduct(product interface{}, params params.Params) *changeset.Changeset {
	ch := changeset.Cast(product, params, []string{"name", "price"})
	changeset.ValidateRequired(ch, []string{"name", "price"})
	changeset.ValidateMin(ch, "price", 100)
	return ch

func main() {
	// initialize mysql adapter.
	adapter, err := mysql.Open("[email protected](")
	if err != nil {
	defer adapter.Close()

	// initialize grimoire's repo.
	repo := grimoire.New(adapter)

	var product Product

	// Inserting Products.
	// Changeset is used when creating or updating your data.
	ch := ChangeProduct(product, params.Map{
		"name":  "shampoo",
		"price": 1000,

	if ch.Error() != nil {
		// handle error

	// Changeset can also be created directly from json string.
	jsonch := ChangeProduct(product, params.ParseJSON(`{
		"name":  "soap",
		"price": 2000,

	// Create products with changeset and return the result to &product,
	if err = repo.From("products").Insert(&product, ch); err != nil {
		// handle error

	// or panic when insertion pailed
	repo.From("products").MustInsert(&product, jsonch)

	// Querying Products.
	// Find a product with id 1.

	// Updating Products.
	// Update products with id=1.
	repo.From("products").Find(1).MustUpdate(&product, ch)

	// Deleting Products.
	// Delete Product with id=1.




API Documentation:


Released under the MIT License

FOSSA Status

Get A Weekly Email With Trending Projects For These Topics
No Spam. Unsubscribe easily at any time.
Go (193,761
Golang (32,088
Mysql (12,037
Database (9,307
Validation (2,394
Postgres (2,146
Orm (2,052
Sqlite3 (1,796
Related Projects