Skip to content
forked from mattatcha/scaneo

Generate Go code to convert database rows into arbitrary structs.

License

Notifications You must be signed in to change notification settings

thisissoon/scaneo

 
 

Folders and files

NameName
Last commit message
Last commit date

Latest commit

 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

scaneo

Build Status Coverage Status

Generate Go code to convert database rows into arbitrary structs. Works with any database driver. Don't have to worry about database columns and struct names matching or tagging structs. No ORM magic.

Installation

Install or upgrade Scaneo with this command.

go get -u github.com/variadico/scaneo

Otherwise, check out the releases page.

Usage

scaneo [options] paths...

Options

-o, -output
    Set the name of the generated file. Default is scans.go.

-p, -package
    Set the package name for the generated file. Default is current
    directory name.

-u, -unexport
    Generate unexported functions. Default is export all.

-w, -whitelist
    Only include structs specified in case-sensitive, comma-delimited
    string.

-f, -funcs
    Generate SQL helper functions. Default is false.

-i, -import
    Override package to import type from.

-v, -version
    Print version and exit.

-h, -help
    Print help and exit.

3-Step Tutorial

First, we start with a file that looks like this, called tables.go.

package models

import (
	"time"

	"github.com/lib/pq"
)

type Post struct {
	ID        int
	Created   time.Time
	Published pq.NullTime
	Draft     bool
	Title     string
	Body      string
}

Second, run scaneo tables.go. This will create a new file called scans.go, which looks like this.

// DON'T EDIT *** generated by scaneo *** DON'T EDIT //

package models

import "database/sql"

func ScanPost(r *sql.Row) (Post, error) {
	var s Post
	if err := r.Scan(
		&s.ID,
		&s.Created,
		&s.Published,
		&s.Draft,
		&s.Title,
		&s.Body,
	); err != nil {
		return Post{}, err
	}
	return s, nil
}
func ScanPosts(rs *sql.Rows) ([]Post, error) {
	structs := make([]Post, 0, 16)
	var err error
	for rs.Next() {
		var s Post
		if err = rs.Scan(
			&s.ID,
			&s.Created,
			&s.Published,
			&s.Draft,
			&s.Title,
			&s.Body,
		); err != nil {
			return nil, err
		}
		structs = append(structs, s)
	}
	return structs, nil
}

Third, call those functions from other parts of your code, like this.

func serveHome(resp http.ResponseWriter, req *http.Request) {
	rows, err := db.Query("select * from post")
	if err != nil {
		log.Println(err)
		return
	}

	posts, err := models.ScanPosts(rows) // ScanPosts was auto-generated!
	if err != nil {
		log.Println(err)
	}

	// ... send posts to template or whatever...
}

Go Generate

If you want to use scaneo with go generate, then just add this comment to the top of tables.go.

//go:generate scaneo $GOFILE

package models
// ... rest of code...

Now you can call go generate in package models and scans.go will be created.

FAQ

Why did you write this instead of using sqlx, modl, gorm, gorp, etc?

  1. Didn't know which one I should learn. Already knew database/sql.
  2. All I wanted was structs from the database.
  3. I can write SQL.

In addition, I wasn't entirely sure how much more convenient an ORM would be in contrast to writing the SQL myself. After reading some usage examples, it kind of felt like I was writing SQL anyway.

// github.com/go-gorp/gorp
dbMap.Select(&users, "SELECT * FROM users WHERE last_name = ? OR age < ? ORDER BY age DESC LIMIT 2", "Doe", 12)

// github.com/eaigner/hood
hd.Where("last_name", "=", "Doe").Or("age", "<", 12).OrderBy("age").Limit(2).Find(&users)

// github.com/jmoiron/sqlx
db.Select(&people, "SELECT * FROM person ORDER BY first_name ASC")

// github.com/astaxie/beedb
orm.Where("last_name = ? OR age < ?", "Doe", 12).Limit(2).OrderBy("age").FindAll(&users)

Do my table columns have to match my struct field names?

Nope. The names don't actually matter at all. However, what does matter is the order in which you declare the types in your struct. That has to match the database table. So if your table looks like this:

 user_id | first_name | last_name
---------+------------+-----------
       1 | Silvio     | Rodríguez

then, your struct field names must follow the same order, like this.

type User struct {
	ID        int
	FirstName string
	LastName  string
}

About

Generate Go code to convert database rows into arbitrary structs.

Resources

License

Stars

Watchers

Forks

Packages

No packages published

Languages

  • Go 100.0%