Go tool for generating sql scanners, sql statements and other helper functions

sqlgen generates SQL statements and database helper functions from your Go structs. It can be used in place of a simple ORM or hand-written SQL. See the demo directory for examples.

Install

Install or upgrade with this command:

go get -u github.com/drone/sqlgen

Usage

Usage of sqlgen:
  -type string
    	type to generate; required
  -file string
    	input file name; required
  -o string
    	output file name
  -pkg string
    	output package name
  -db string
    	sql dialect; sqlite, postgres, mysql
  -schema
    	generate sql schema and queries; default true
  -funcs
    	generate sql helper functions; default true

Tutorial

First, let's start with a simple User struct in user.go:

type User struct {
	ID     int64
	Login  string
	Email  string
}

We can run the following command:

sqlgen -file user.go -type User -pkg demo

The tool outputs the following generated code:

func ScanUser(row *sql.Row) (*User, error) {
	var v0 int64
	var v1 string
	var v2 string

	err := row.Scan(
		&v0,
		&v1,
		&v2,
	)
	if err != nil {
		return nil, err
	}

	v := &User{}
	v.ID = v0
	v.Login = v1
	v.Email = v2

	return v, nil
}

const CreateUserStmt = `
CREATE TABLE IF NOT EXISTS users (
 user_id     INTEGER
,user_login  TEXT
,user_email  TEXT
);
`

const SelectUserStmt = `
SELECT 
 user_id
,user_login
,user_email
FROM users 
`

const SelectUserRangeStmt = `
SELECT 
 user_id
,user_login
,user_email
FROM users 
LIMIT ? OFFSET ?
`


// more functions and sql statements not displayed

This is a great start, but what if we want to specify primary keys, column sizes and more? This may be acheived by annotating your code using Go tags. For example, we can tag the ID field to indicate it is a primary key and will auto increment:

type User struct {
-   ID      int64
+   ID      int64  `sql:"pk: true, auto: true"`
    Login   string
    Email   string
}

This information allows the tool to generate smarter SQL statements:

CREATE TABLE IF NOT EXISTS users (
-user_id     INTEGER
+user_id     INTEGER PRIMARY KEY AUTOINCREMENT
,user_login  TEXT
,user_email  TEXT
);

Including SQL statements to select, insert, update and delete data using the primary key:

const SelectUserPkeyStmt = `
SELECT 
 user_id
,user_login
,user_email
WHERE user_id=?
`

const UpdateUserPkeyStmt = `
UPDATE users SET 
 user_id=?
,user_login=?
,user_email=?
WHERE user_id=?
`

const DeleteUserPkeyStmt = `
DELETE FROM users 
WHERE user_id=?
`

We can take this one step further and annotate indexes. In our example, we probably want to make sure the user_login field has a unique index:

type User struct {
    ID      int64  `sql:"pk: true, auto: true"`
-   Login   string
+   Login   string `sql:"unique: user_login"`
    Email   string
}

This information instructs the tool to generate the following:

const CreateUserLogin = `
CREATE UNIQUE INDEX IF NOT EXISTS user_login ON users (user_login)

The tool also assumes that we probably intend to fetch data from the database using this index. The tool will therefore automatically generate the following queries:

const SelectUserLoginStmt = `
SELECT 
 user_id
,user_login
,user_email
WHERE user_login=?
`

const UpdateUserLoginStmt = `
UPDATE users SET 
 user_id=?
,user_login=?
,user_email=?
WHERE user_login=?
`

const DeleteUserLoginStmt = `
DELETE FROM users 
WHERE user_login=?
`

Nesting

Nested Go structures can be flattened into a single database table. As an example, we have a User and Address with a one-to-one relationship. In some cases, we may prefer to de-normalize our data and store in a single table, avoiding un-necessary joins.

type User struct {
    ID     int64  `sql:"pk: true"`
    Login  string
    Email  string
+   Addr   *Address
}

type Address struct {
    City   string
    State  string
    Zip    string `sql:"index: user_zip"`
}

The above relationship is flattened into a single table (see below). When the data is retrieved from the database the nested structure is restored.

CREATE TALBE IF NOT EXISTS users (
 user_id         INTEGER PRIMARY KEY AUTO_INCREMENT
,user_login      TEXT
,user_email      TEXT
,user_addr_city  TEXT
,user_addr_state TEXT
,user_addr_zip   TEXT
);

JSON Encoding

Some types in your struct may not have native equivalents in your database such as []string. These values can be marshaled and stored as JSON in the database.

type User struct {
    ID     int64  `sql:"pk: true"`
    Login  string
    Email  string
+   Label  []string `sql:"encode: json"
}

Dialects

You may specify one of the following SQL dialects when generating your code: postgres, mysql and sqlite. The default value is sqlite.

sqlgen -file user.go -type User -pkg demo -db postgres

Go Generate

Example use with go:generate:

package demo

//go:generate sqlgen -file user.go -type User -pkg demo -o user_sql.go

type User struct {
    ID     int64  `sql:"pk: true, auto: true"`
    Login  string `sql:"unique: user_login"`
    Email  string `sql:"size: 1024"`
    Avatar string
}

Benchmarks

This tool demonstrates performance gains, albeit small, over light-weight ORM packages such as sqlx and meddler. Over time I plan to expand the benchmarks to include additional ORM packages.

To run the project benchmarks:

go get ./...
go generate ./...
go build
cd bench
go test -bench=Bench

Example selecing a single row:

BenchmarkMeddlerRow-4      30000        42773 ns/op
BenchmarkSqlxRow-4         30000        41554 ns/op
BenchmarkSqlgenRow-4       50000        39664 ns/op

Selecting multiple rows:

BenchmarkMeddlerRows-4      2000      1025218 ns/op
BenchmarkSqlxRows-4         2000       807213 ns/op
BenchmarkSqlgenRows-4       2000       700673 ns/op

Credits

This tool was inspired by scaneo.

Similar Resources

A better ORM for Go, based on non-empty interfaces and code generation.

reform A better ORM for Go and database/sql. It uses non-empty interfaces, code generation (go generate), and initialization-time reflection as oppose

Dec 31, 2022

A better ORM for Go, based on non-empty interfaces and code generation.

A better ORM for Go, based on non-empty interfaces and code generation.

A better ORM for Go and database/sql. It uses non-empty interfaces, code generation (go generate), and initialization-time reflection as opposed to interface{}, type system sidestepping, and runtime reflection. It will be kept simple.

Dec 29, 2022

Golang ORM with focus on PostgreSQL features and performance

go-pg is in a maintenance mode and only critical issues are addressed. New development happens in Bun repo which offers similar functionality but works with PostgreSQL, MySQL, and SQLite.

Jan 8, 2023

Converts a database into gorm structs and RESTful api

gen The gen tool produces a CRUD (Create, read, update and delete) REST api project template from a given database. The gen tool will connect to the d

Dec 28, 2022

Simple project in Go to play around with some CRUD operations using a PostgreSQL database and pgx

Record Store November 2021 I started learning Go a few weeks ago and this is my first proper project using Go. I wanted to use it to get to grips with

Nov 26, 2021

Examples of using various popular database libraries and ORM in Go.

Introduction Examples of using various popular database libraries and ORM in Go. sqlx sqlc Gorm sqlboiler ent The aim is to demonstrate and compare us

Dec 12, 2021

Examples of using various popular database libraries and ORM in Go.

Introduction Examples of using various popular database libraries and ORM in Go. sqlx sqlc Gorm sqlboiler ent The aim is to demonstrate and compare us

Dec 28, 2022

Code that will query the meta data of an instance within AWS and provide a json formatted output on Go

EC2 meta-data, output JSON Code that will query the meta data of an instance wit

Dec 16, 2021

A example of a join table using liquibase and gorm

A example of a join table using liquibase and gorm. Additionally the join table's composite key is used as a composite foreign key for another table.

Feb 4, 2022
Comments
  • Adds CRUD methods based on new flags.

    Adds CRUD methods based on new flags.

    I wanted to generate the CRUD functions as methods on a type. This allows me to define a CRUD interface in my application. That then allows me to inject the interface as a dependency into my handlers. This allows me to mock the interface easily when testing those handler functions.

    The mechanism is the addition of two flags.

    • doDI adds a receiver to the CRUD functions
    • diName defaults to *sql.DB and is the name of the receiver.
  • set primary key, continued

    set primary key, continued

    the code

    v.ID, err = res.LastInsertId()
    

    will fail with string ID fields. This PR includes that block of code if and only if ID is int64.

    Alternatively func Insert%s() could return res.LastInsertID() and give the client a choice to use it.

  • Implement the ability to rename the tables without contriving your type names, and more!

    Implement the ability to rename the tables without contriving your type names, and more!

    This short-circuits the type parsing so that when it hits an element named "SQLName" it will automatically tack the tags parsed for that onto the parent type. This allows us to apply tags to the struct.

    Additionally, this implements the following behaviour on the schema gen:

    • if skip: true is in the tag, it will skip that field for name concatation. ( To allow fully-naming the fields of a column in the struct.)

    An example / test case of this has been retrofitted into the demo/users.go file.

Related tags
Crud - A mysql crud code generate tool from table DDL sql file

crud is a mysql crud code generate tool 中文文档 Getting Started Overview Crud is a

Oct 13, 2022
100% type-safe ORM for Go (Golang) with code generation and MySQL, PostgreSQL, Sqlite3, SQL Server support. GORM under the hood.

go-queryset 100% type-safe ORM for Go (Golang) with code generation and MySQL, PostgreSQL, Sqlite3, SQL Server support. GORM under the hood. Contents

Dec 30, 2022
Simple and performant ORM for sql.DB

Simple and performant ORM for sql.DB Main features are: Works with PostgreSQL, MySQL, SQLite. Selecting into a map, struct, slice of maps/structs/vars

Jan 4, 2023
beedb is a go ORM,support database/sql interface,pq/mysql/sqlite

Beedb ❗ IMPORTANT: Beedb is being deprecated in favor of Beego.orm ❗ Beedb is an ORM for Go. It lets you map Go structs to tables in a database. It's

Nov 25, 2022
A simple wrapper around sql.DB to help with structs. Not quite an ORM.

go-modeldb A simple wrapper around sql.DB to help with structs. Not quite an ORM. Philosophy: Don't make an ORM Example: // Setup require "modeldb" db

Nov 16, 2019
A pure golang SQL database for learning database theory

Go SQL DB 中文 "Go SQL DB" is a relational database that supports SQL queries for research purposes. The main goal is to show the basic principles and k

Dec 29, 2022
SQL mapper ORM framework for Golang
 SQL mapper ORM framework for Golang

SQL mapper ORM framework for Golang English 中文 Please read the documentation website carefully when using the tutorial. DOC Powerful Features High Per

Dec 8, 2021
Mybatis for golang - SQL mapper ORM framework

SQL mapper ORM framework for Golang English 中文 Please read the documentation website carefully when using the tutorial. DOC Powerful Features High Per

Nov 10, 2022
A simple and fast Redis backed key-value store library for Go

store store is a data-store library for Go that provides a set of platform-independent interfaces to persist and retrieve data. Its primary goal is to

Sep 27, 2022
Simple and Powerful ORM for Go, support mysql,postgres,tidb,sqlite3,mssql,oracle, Moved to https://gitea.com/xorm/xorm

xorm HAS BEEN MOVED TO https://gitea.com/xorm/xorm . THIS REPOSITORY WILL NOT BE UPDATED ANY MORE. 中文 Xorm is a simple and powerful ORM for Go. Featur

Jan 3, 2023