2016-02-24 11:45:09 +01:00
# SQLBoiler
2016-02-23 09:27:32 +01:00
2016-08-15 17:48:37 +02:00
[![License ](https://img.shields.io/badge/license-BSD-blue.svg )](https://github.com/vattle/sqlboiler/blob/master/LICENSE)
2016-08-23 07:32:26 +02:00
[![GoDoc ](https://godoc.org/github.com/vattle/sqlboiler?status.svg )](https://godoc.org/github.com/vattle/sqlboiler)
2016-08-09 09:59:30 +02:00
[![CircleCI ](https://circleci.com/gh/vattle/sqlboiler.svg?style=shield )](https://circleci.com/gh/vattle/sqlboiler)
2016-08-23 07:32:26 +02:00
[![Go Report Card ](https://goreportcard.com/badge/vattle/sqlboiler )](http://goreportcard.com/report/vattle/sqlboiler)
2016-08-31 23:01:59 +02:00
SQLBoiler is a tool to generate a Go ORM tailored to your database schema.
2016-08-23 07:32:26 +02:00
It is a "database-first" ORM as opposed to "code-first" (like gorm/gorp).
That means you must first create your database schema. Please use something
2016-09-01 02:35:32 +02:00
like [goose ](https://bitbucket.org/liamstask/goose ), [sql-migrate ](https://github.com/rubenv/sql-migrate )
2016-09-01 01:05:06 +02:00
or some other migration tool to manage this part of the database's life-cycle.
2016-08-23 07:32:26 +02:00
2016-08-31 16:13:39 +02:00
## Why another ORM
2016-09-01 02:35:32 +02:00
2016-09-04 09:37:48 +02:00
While attempting to migrate a legacy Rails database, we realized how much ActiveRecord benefitted us in terms of development velocity.
Coming over to the Go `database/sql` package after using ActiveRecord feels extremely repetitive, super long-winded and down-right boring.
Being Go veterans we knew the state of ORMs was shaky, and after a quick review we found what our fears confirmed. Most packages out
there are code-first, reflect-based and have a very weak story around relationships between models. So with that we set out with these goals:
* Work with existing databases: Don't be the tool to define the schema, that's better left to other tools.
* ActiveRecord-like productivity: Eliminate all sql boilerplate, have relationships as a first-class concept.
* Go-like feel: Work with normal structs, call functions, no hyper-magical struct tags, small interfaces.
2016-09-04 09:58:48 +02:00
* Go-like performance: [Benchmark ](#benchmarks ) and optimize the hot-paths, perform like hand-rolled `sql.DB` code.
2016-09-04 09:37:48 +02:00
We believe with SQLBoiler and our database-first code-generation approach we've been able to successfully meet all of these goals. On top
of that SQLBoiler also confers the following benefits:
* The models package is type safe. This means no chance of random panics due to passing in the wrong type. No need for interface{}.
2016-09-01 02:35:32 +02:00
* Our types closely correlate to your database column types. This is expanded by our extended null package which supports nearly all Go data types.
2016-09-04 09:37:48 +02:00
* A system that is easy to debug. Your ORM is tailored to your schema, the code paths should be easy to trace since it's not all buried in reflect.
* Auto-completion provides work-flow efficiency gains.
2016-08-30 12:38:29 +02:00
2016-09-02 11:32:56 +02:00
Table of Contents
=================
* [SQLBoiler ](#sqlboiler )
* [Why another ORM ](#why-another-orm )
* [About SQL Boiler ](#about-sql-boiler )
* [Features ](#features )
* [Supported Databases ](#supported-databases )
* [A Small Taste ](#a-small-taste )
* [Requirements & Pro Tips ](#requirements--pro-tips )
* [Requirements ](#requirements )
* [Pro Tips ](#pro-tips )
* [Getting started ](#getting-started )
* [Download ](#download )
* [Configuration ](#configuration )
* [Initial Generation ](#initial-generation )
* [Diagnosing Problems ](#diagnosing-problems )
* [Features & Examples ](#features--examples )
* [Automatic CreatedAt/UpdatedAt ](#automatic-createdatupdatedat )
* [Overriding Automatic Timestamps ](#overriding-automatic-timestamps )
* [Query Building ](#query-building )
* [Query Mod System ](#query-mod-system )
* [Function Variations ](#function-variations )
* [Finishers ](#finishers )
* [Raw Query ](#raw-query )
* [Binding ](#binding )
* [Relationships ](#relationships )
* [Hooks ](#hooks )
* [Transactions ](#transactions )
* [Debug Logging ](#debug-logging )
* [Select ](#select )
* [Find ](#find )
* [Insert ](#insert )
* [Update ](#update )
* [Delete ](#delete )
* [Upsert ](#upsert )
* [Reload ](#reload )
* [Exists ](#exists )
* [FAQ ](#faq )
* [Won't compiling models for a huge database be very slow? ](#wont-compiling-models-for-a-huge-database-be-very-slow )
* [Missing imports for generated package ](#missing-imports-for-generated-package )
2016-09-04 09:58:48 +02:00
* [Benchmarks ](#benchmarks )
2016-09-02 11:32:56 +02:00
2016-08-23 07:32:26 +02:00
## About SQL Boiler
2016-08-30 13:04:58 +02:00
### Features
2016-08-23 07:32:26 +02:00
- Full model generation
2016-08-30 10:54:21 +02:00
- Extremely fast code generation
2016-09-14 12:42:20 +02:00
- High performance through generation & intelligent caching
2016-08-26 17:10:25 +02:00
- Uses boil.Executor (simple interface, sql.DB, sqlx.DB etc. compatible)
2016-08-23 07:32:26 +02:00
- Easy workflow (models can always be regenerated, full auto-complete)
- Strongly typed querying (usually no converting or binding to pointers)
2016-08-30 07:55:58 +02:00
- Hooks (Before/After Create/Select/Update/Delete/Upsert)
2016-08-28 16:12:37 +02:00
- Automatic CreatedAt/UpdatedAt
2016-09-14 12:42:20 +02:00
- Table whitelist/blacklist
2016-08-23 07:32:26 +02:00
- Relationships/Associations
2016-08-30 10:54:21 +02:00
- Eager loading (recursive)
2016-09-14 12:42:20 +02:00
- Custom struct tags
- Schema support
2016-08-23 07:32:26 +02:00
- Transactions
2016-09-01 01:05:06 +02:00
- Raw SQL fallback
2016-08-23 07:32:26 +02:00
- Compatibility tests (Run against your own DB schema)
- Debug logging
2016-09-14 12:42:20 +02:00
- Postgres 1d arrays, json, hstore & more
2016-08-23 07:32:26 +02:00
2016-08-30 13:04:58 +02:00
### Supported Databases
2016-08-23 07:32:26 +02:00
- PostgreSQL
2016-09-14 12:42:20 +02:00
- MySQL
2016-08-23 07:32:26 +02:00
2016-08-30 13:04:58 +02:00
*Note: Seeking contributors for other database engines.*
2016-08-23 07:32:26 +02:00
2016-08-30 13:04:58 +02:00
### A Small Taste
2016-08-30 12:38:29 +02:00
2016-08-30 13:04:58 +02:00
For a comprehensive list of available operations and examples please see [Features & Examples ](#features--examples ).
2016-08-23 07:32:26 +02:00
```go
import (
// Import this so we don't have to use qm.Limit etc.
. "github.com/vattle/sqlboiler/boil/qm"
)
// Open handle to database like normal
db, err := sql.Open("postgres", "dbname=fun user=abc")
if err != nil {
return err
}
// Query all users
users, err := models.Users(db).All()
// Panic-able if you like to code that way
users := models.Users(db).AllP()
// More complex query
users, err := models.Users(db, Where("age > ?", 30), Limit(5), Offset(6)).All()
// Ultra complex query
users, err := models.Users(db,
Select("id", "name"),
InnerJoin("credit_cards c on c.user_id = users.id"),
Where("age > ?", 30),
AndIn("c.kind in ?", "visa", "mastercard"),
2016-09-05 09:51:34 +02:00
Or("email like ?", `%aol.com%` ),
2016-08-23 07:32:26 +02:00
GroupBy("id", "name"),
Having("count(c.id) > ?", 2),
Limit(5),
Offset(6),
).All()
// Use any "boil.Executor" implementation (*sql.DB, *sql.Tx, data-dog mock db)
// for any query.
tx, err := db.Begin()
if err != nil {
return err
}
users, err := models.Users(tx).All()
// Relationships
2016-08-23 11:52:31 +02:00
user, err := models.Users(db).One()
2016-08-23 07:32:26 +02:00
if err != nil {
return err
}
movies, err := user.FavoriteMovies(db).All()
// Eager loading
2016-08-26 17:10:25 +02:00
users, err := models.Users(db, Load("FavoriteMovies")).All()
2016-08-23 07:32:26 +02:00
if err != nil {
return err
}
2016-08-27 06:40:11 +02:00
fmt.Println(len(users.R.FavoriteMovies))
2016-08-23 07:32:26 +02:00
```
2016-02-25 01:16:02 +01:00
2016-08-30 12:38:29 +02:00
## Requirements & Pro Tips
### Requirements
2016-08-30 08:58:14 +02:00
2016-09-04 18:11:27 +02:00
* Go 1.6 minimum, and Go 1.7 for compatibility tests.
2016-08-30 08:58:14 +02:00
* Table names and column names should use `snake_case` format.
2016-08-30 12:38:29 +02:00
* At the moment we require `snake_case` table names and column names. This
is a recommended default in Postgres. We can reassess this for future database drivers.
2016-08-30 08:58:14 +02:00
* Join tables should use a *composite primary key* .
* For join tables to be used transparently for relationships your join table must have
a *composite primary key* that encompasses both foreign table foreign keys. For example, on a
join table named `user_videos` you should have: `primary key(user_id, video_id)` , with both `user_id`
and `video_id` being foreign key columns to the users and videos tables respectively.
2016-09-20 03:59:46 +02:00
* For MySQL if using the `github.com/go-sql-driver/mysql` driver, please activate
2016-09-19 07:22:32 +02:00
[time.Time parsing ](https://github.com/go-sql-driver/mysql#timetime-support ) when making your
2016-09-20 03:59:46 +02:00
MySQL database connection. SQLBoiler uses `time.Time` and `null.Time` to represent time in
2016-09-19 07:22:32 +02:00
it's models and without this enabled any models with `DATE` /`DATETIME` columns will not work.
2016-08-30 08:58:14 +02:00
2016-08-30 12:38:29 +02:00
### Pro Tips
2016-08-30 08:58:14 +02:00
* Foreign key column names should end with `_id` .
* Foreign key column names in the format `x_id` will generate clearer method names.
2016-08-30 12:38:29 +02:00
It is advisable to use this naming convention whenever it makes sense for your database schema.
2016-09-01 02:35:32 +02:00
* If you never plan on using the hooks functionality you can disable generation of this
2016-08-30 12:38:29 +02:00
feature using the `--no-hooks` flag. This will save you some binary size.
2016-08-30 07:24:09 +02:00
2016-08-30 12:38:29 +02:00
## Getting started
2016-02-24 11:45:09 +01:00
2016-08-23 07:32:26 +02:00
#### Download
2016-02-25 01:20:39 +01:00
2016-08-23 07:32:26 +02:00
```shell
2016-09-04 23:42:14 +02:00
go get -u -t github.com/vattle/sqlboiler
2016-08-23 07:32:26 +02:00
```
2016-02-25 01:20:39 +01:00
2016-08-23 07:32:26 +02:00
#### Configuration
2016-08-15 15:37:41 +02:00
2016-08-23 11:52:31 +02:00
Create a configuration file. Because the project uses [viper ](github.com/spf13/viper ), TOML, JSON and YAML
2016-08-23 07:32:26 +02:00
are all supported. Environment variables are also able to be used.
We will assume TOML for the rest of the documentation.
2016-08-15 15:37:41 +02:00
2016-08-30 12:38:29 +02:00
The configuration file should be named `sqlboiler.toml` and is searched for in the following directories in this
2016-08-23 07:32:26 +02:00
order:
2016-08-15 15:37:41 +02:00
2016-08-23 07:32:26 +02:00
- `./`
- `$XDG_CONFIG_HOME/sqlboiler/`
2016-08-23 11:52:31 +02:00
- `$HOME/.config/sqlboiler/`
2016-08-15 15:37:41 +02:00
2016-09-14 12:42:20 +02:00
We require you pass in your `postgres` and `mysql` database configuration via the configuration file rather than env vars.
There is no command line argument support for database configuration. Values given under the `postgres` and `mysql`
block are passed directly to the postgres and mysql drivers. Here is a rundown of all the different
2016-08-23 07:32:26 +02:00
values that can go in that section:
2016-08-15 15:37:41 +02:00
2016-09-14 12:42:20 +02:00
| Name | Required | Postgres Default | MySQL Default |
| --- | --- | --- | --- |
| dbname | yes | none | none |
| host | yes | none | none |
| port | no | 5432 | 3306 |
| user | yes | none | none |
| pass | no | none | none |
| sslmode | no | "require" | "true" |
2016-08-30 08:34:52 +02:00
2016-08-30 08:58:14 +02:00
You can also pass in these top level configuration values if you would prefer
2016-08-30 08:34:52 +02:00
not to pass them through the command line or environment variables:
2016-09-15 08:33:18 +02:00
| Name | Defaults |
| ------------------ | --------- |
| basedir | none |
| schema | "public" *(or dbname for mysql)* |
| pkgname | "models" |
| output | "models" |
| whitelist | [] |
| blacklist | [] |
| tag | [] |
| debug | false |
| no-hooks | false |
| no-tests | false |
| no-auto-timestamps | false |
2016-02-25 01:20:39 +01:00
2016-08-30 13:04:58 +02:00
Example:
2016-08-23 07:32:26 +02:00
```toml
[postgres]
dbname="dbname"
host="localhost"
port=5432
user="dbusername"
pass="dbpassword"
```
2016-02-24 11:45:09 +01:00
2016-08-30 12:38:29 +02:00
#### Initial Generation
After creating a configuration file that points at the database we want to
generate models for, we can invoke the sqlboiler command line utility.
```text
SQL Boiler generates a Go ORM from template files, tailored to your database schema.
Complete documentation is available at http://github.com/vattle/sqlboiler
Usage:
sqlboiler [flags] < driver >
Examples:
2016-09-14 12:42:20 +02:00
sqlboiler postgres
sqlboiler mysql
2016-08-30 12:38:29 +02:00
Flags:
2016-09-09 07:41:57 +02:00
-b, --blacklist stringSlice Do not include these tables in your generated package
2016-09-05 16:41:12 +02:00
-w, --whitelist stringSlice Only include these tables in your generated package
2016-09-08 19:43:36 +02:00
-s, --schema string The name of your database schema, for databases that support real schemas (default "public")
-p, --pkgname string The name you wish to assign to your generated package (default "models")
-o, --output string The name of the folder to output to (default "models")
-t, --tag stringSlice Struct tags to be included on your models in addition to json, yaml, toml
-d, --debug Debug mode prints stack traces on error
2016-09-09 07:41:57 +02:00
--basedir string The base directory has the templates and templates_test folders
2016-08-30 12:38:29 +02:00
--no-auto-timestamps Disable automatic timestamps for created_at/updated_at
--no-hooks Disable hooks feature for your models
2016-09-02 10:07:11 +02:00
--no-tests Disable generated go test files
2016-08-30 12:38:29 +02:00
```
2016-09-14 12:42:20 +02:00
Follow the steps below to do some basic model generation. Once you've generated
your models, you can run the compatibility tests which will exercise the entirety
of the generated code. This way you can ensure that your database is compatible
2016-09-01 02:35:32 +02:00
with SQLBoiler. If you find there are some failing tests, please check the
2016-08-30 12:38:29 +02:00
[Diagnosing Problems ](#diagnosing-problems ) section.
2016-08-30 16:04:39 +02:00
```sh
2016-08-30 12:38:29 +02:00
# Generate our models and exclude the migrations table
sqlboiler -x goose_migrations postgres
# Run the generated tests
2016-09-15 05:59:55 +02:00
go test ./models
2016-08-30 12:38:29 +02:00
```
2016-08-30 10:54:21 +02:00
## Diagnosing Problems
The most common causes of problems and panics are:
- Forgetting to exclude tables you do not want included in your generation, like migration tables.
- Tables without a primary key. All tables require one.
2016-09-02 10:07:11 +02:00
- Forgetting to put foreign key constraints on your columns that reference other tables.
2016-09-14 12:42:20 +02:00
- The compatibility tests require privileges to create a database for testing purposes, ensure the user
2016-09-02 10:07:11 +02:00
supplied in your `sqlboiler.toml` config has adequate privileges.
2016-08-30 10:54:21 +02:00
- A nil or closed database handle. Ensure your passed in `boil.Executor` is not nil.
- If you decide to use the `G` variant of functions instead, make sure you've initialized your
global database handle using `boil.SetDB()` .
For errors with other causes, it may be simple to debug yourself by looking at the generated code.
Setting `boil.DebugMode` to `true` can help with this. You can change the output using `boil.DebugWriter` (defaults to `os.Stdout` ).
If you're still stuck and/or you think you've found a bug, feel free to leave an issue and we'll do our best to help you.
2016-08-30 12:38:29 +02:00
## Features & Examples
2016-08-31 07:10:30 +02:00
Most examples in this section will be demonstrated using the following schema, structs and variables:
2016-08-30 16:04:39 +02:00
```sql
CREATE TABLE pilots (
id integer NOT NULL,
name text NOT NULL,
);
ALTER TABLE pilots ADD CONSTRAINT pilot_pkey PRIMARY KEY (id);
CREATE TABLE jets (
id integer NOT NULL,
pilot_id integer NOT NULL,
2016-08-31 14:04:39 +02:00
age integer NOT NULL,
2016-08-30 16:04:39 +02:00
name text NOT NULL,
2016-08-31 14:04:39 +02:00
color text NOT NULL,
2016-08-30 16:04:39 +02:00
);
ALTER TABLE jets ADD CONSTRAINT jet_pkey PRIMARY KEY (id);
ALTER TABLE jets ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
CREATE TABLE languages (
id integer NOT NULL,
language text NOT NULL
);
ALTER TABLE languages ADD CONSTRAINT language_pkey PRIMARY KEY (id);
-- Join table
CREATE TABLE pilot_languages (
pilot_id integer NOT NULL,
language_id integer NOT NULL
);
-- Composite primary key
ALTER TABLE pilot_languages ADD CONSTRAINT pilot_language_pkey PRIMARY KEY (pilot_id, language_id);
ALTER TABLE pilot_languages ADD CONSTRAINT pilots_fkey FOREIGN KEY (pilot_id) REFERENCES pilots(id);
ALTER TABLE pilot_languages ADD CONSTRAINT languages_fkey FOREIGN KEY (language_id) REFERENCES languages(id);
```
2016-09-14 12:42:20 +02:00
The generated model structs for this schema look like the following. Note that we've included the relationship
structs as well so you can see how it all pieces together:
2016-08-30 16:04:39 +02:00
```go
type Pilot struct {
ID int `boil:"id" json:"id" toml:"id" yaml:"id"`
Name string `boil:"name" json:"name" toml:"name" yaml:"name"`
2016-08-31 07:10:30 +02:00
R *pilotR `boil:"-" json:"-" toml:"-" yaml:"-"`
2016-09-14 12:42:20 +02:00
L pilotR `boil:"-" json:"-" toml:"-" yaml:"-"`
2016-08-30 16:04:39 +02:00
}
2016-08-31 07:10:30 +02:00
type pilotR struct {
2016-08-30 16:04:39 +02:00
Licenses LicenseSlice
Languages LanguageSlice
Jets JetSlice
}
type Jet struct {
ID int `boil:"id" json:"id" toml:"id" yaml:"id"`
PilotID int `boil:"pilot_id" json:"pilot_id" toml:"pilot_id" yaml:"pilot_id"`
2016-08-31 14:04:39 +02:00
Age int `boil:"age" json:"age" toml:"age" yaml:"age"`
2016-08-30 16:04:39 +02:00
Name string `boil:"name" json:"name" toml:"name" yaml:"name"`
2016-08-31 14:04:39 +02:00
Color string `boil:"color" json:"color" toml:"color" yaml:"color"`
2016-08-30 16:04:39 +02:00
2016-08-31 07:10:30 +02:00
R *jetR `boil:"-" json:"-" toml:"-" yaml:"-"`
2016-09-14 12:42:20 +02:00
L jetR `boil:"-" json:"-" toml:"-" yaml:"-"`
2016-08-30 16:04:39 +02:00
}
2016-08-31 07:10:30 +02:00
type jetR struct {
2016-08-30 16:04:39 +02:00
Pilot *Pilot
}
type Language struct {
ID int `boil:"id" json:"id" toml:"id" yaml:"id"`
Language string `boil:"language" json:"language" toml:"language" yaml:"language"`
2016-08-31 07:10:30 +02:00
R *languageR `boil:"-" json:"-" toml:"-" yaml:"-"`
2016-09-14 12:42:20 +02:00
L languageR `boil:"-" json:"-" toml:"-" yaml:"-"`
2016-08-30 16:04:39 +02:00
}
2016-08-31 07:10:30 +02:00
type languageR struct {
2016-08-30 16:04:39 +02:00
Pilots PilotSlice
}
```
```go
// Open handle to database like normal
db, err := sql.Open("postgres", "dbname=fun user=abc")
if err != nil {
return err
}
```
2016-08-31 11:41:00 +02:00
### Automatic CreatedAt/UpdatedAt
If your generated SQLBoiler models package can find columns with the
names `created_at` or `updated_at` it will automatically set them
to `time.Now()` in your database, and update your object appropriately.
To disable this feature use `--no-auto-timestamps` .
Note: You can set the timezone for this feature by calling `boil.SetLocation()`
#### Overriding Automatic Timestamps
* **Insert**
* Timestamps for both `updated_at` and `created_at` that are zero values will be set automatically.
* To set the timestamp to null, set `Valid` to false and `Time` to a non-zero value.
This is somewhat of a work around until we can devise a better solution in a later version.
* **Update**
* The `updated_at` column will always be set to `time.Now()` . If you need to override
2016-09-15 05:59:55 +02:00
this value you will need to fall back to another method in the meantime: `queries.Raw()` ,
2016-08-31 11:41:00 +02:00
overriding `updated_at` in all of your objects using a hook, or create your own wrapper.
* **Upsert**
* `created_at` will be set automatically if it is a zero value, otherwise your supplied value
will be used. To set `created_at` to `null` , set `Valid` to false and `Time` to a non-zero value.
* The `updated_at` column will always be set to `time.Now()` .
2016-08-30 16:04:39 +02:00
### Query Building
2016-08-31 07:10:30 +02:00
We generate "Starter" methods for you. These methods are named as the plural versions of your model,
2016-09-01 02:35:32 +02:00
for example: `models.Jets()` . Starter methods are used to build queries using our
[Query Mod System ](#query-mod-system ). They take a slice of [Query Mods ](#query-mod-system )
2016-08-31 07:10:30 +02:00
as parameters, and end with a call to a [Finisher ](#finishers ) method.
Here are a few examples:
```go
// SELECT COUNT(*) FROM pilots;
count, err := models.Pilots().Count()
// SELECT * FROM "pilots" LIMIT 5;
pilots, err := models.Pilots(qm.Limit(5)).All()
// DELETE FROM "pilots" WHERE "id"=$1;
2016-09-01 02:35:32 +02:00
err := models.Pilots(qm.Where("id=?", 1)).DeleteAll()
2016-08-31 07:10:30 +02:00
```
2016-08-31 23:01:59 +02:00
In the event that you would like to build a query and specify the table yourself, you
can do so using `models.NewQuery()` :
```go
// Select all rows from the pilots table by using the From query mod.
err := models.NewQuery(db, From("pilots")).All()
```
2016-09-01 02:35:32 +02:00
As you can see, [Query Mods ](#query-mods ) allow you to modify your queries, and [Finishers ](#finishers )
2016-08-31 07:10:30 +02:00
allow you to execute the final action.
2016-09-15 05:59:55 +02:00
We also generate query building helper methods for your relationships as well. Take a look at our
2016-09-14 11:42:07 +02:00
[Relationships Query Building ](#relationships ) section for some additional query building information.
2016-08-31 23:01:59 +02:00
2016-09-01 01:05:06 +02:00
2016-08-30 16:04:39 +02:00
### Query Mod System
2016-09-01 02:35:32 +02:00
The query mod system allows you to modify queries created with [Starter ](#query-building ) methods
2016-08-31 07:10:30 +02:00
when performing query building. Here is a list of all of your generated query mods using examples:
```go
// Dot import so we can access query mods directly instead of prefixing with "qm."
import . "github.com/vattle/sqlboiler/boil/qm"
// Use a raw query against a generated struct (Pilot in this example)
// If this query mod exists in your call, it will override the others.
// "?" placeholders are not supported here, use "$1, $2" etc.
SQL("select * from pilots where id=$1", 10)
models.Pilots(SQL("select * from pilots where id=$1", 10)).All()
Select("id", "name") // Select specific columns.
From("pilots as p") // Specify the FROM table manually, can be useful for doing complex queries.
// WHERE clause building
Where("name=?", "John")
And("age=?", 24)
Or("height=?", 183)
// WHERE IN clause building
WhereIn("name, age in ?", "John" 24, "Tim", 33) // Generates: WHERE ("name","age") IN (($1,$2),($3,$4))
AndIn("weight in ?", 84)
OrIn("height in ?", 183, 177, 204)
InnerJoin("pilots p on jets.pilot_id=?", 10)
GroupBy("name")
OrderBy("age, height")
Having("count(jets) > 2")
Limit(15)
Offset(5)
// Explicit locking
For("update nowait")
2016-09-01 02:35:32 +02:00
// Eager Loading -- Load takes the relationship name, ie the struct field name of the
2016-08-31 07:10:30 +02:00
// Relationship struct field you want to load.
Load("Languages") // If it's a ToOne relationship it's in singular form, ToMany is plural.
```
Note: We don't force you to break queries apart like this if you don't want to, the following
is also valid and supported by query mods that take a clause:
```go
Where("(name=? OR age=?) AND height=?", "John", 24, 183)
```
2016-08-30 12:38:29 +02:00
### Function Variations
2016-08-30 16:04:39 +02:00
You will find that most functions have the following variations. We've used the
```Delete``` method to demonstrate:
```go
// Set the global db handle for G method variants.
boil.SetDB(db)
2016-08-31 11:41:00 +02:00
pilot, _ := models.FindPilot(db, 1)
2016-08-30 16:04:39 +02:00
err := pilot.Delete(db) // Regular variant, takes a db handle (boil.Executor interface).
2016-09-01 02:35:32 +02:00
pilot.DeleteP(db) // Panic variant, takes a db handle and panics on error.
2016-08-30 16:04:39 +02:00
err := pilot.DeleteG() // Global variant, uses the globally set db handle (boil.SetDB()).
pilot.DeleteGP() // Global& Panic variant, combines the global db handle and panic on error.
```
2016-08-31 11:41:00 +02:00
Note that it's slightly different for query building.
2016-08-30 16:04:39 +02:00
2016-08-31 11:41:00 +02:00
### Finishers
2016-08-30 12:38:29 +02:00
2016-09-01 02:35:32 +02:00
Here are a list of all of the finishers that can be used in combination with
2016-08-31 11:41:00 +02:00
[Query Building ](#query-building ).
2016-08-30 12:38:29 +02:00
2016-08-31 14:04:39 +02:00
Finishers all have `P` (panic) [method variations ](#function-variations ). To specify
your db handle use the `G` or regular variation of the [Starter ](#query-building ) method.
2016-08-30 12:38:29 +02:00
2016-08-31 11:41:00 +02:00
```go
// These are called like the following:
models.Pilots(db).All()
One() // Retrieve one row as object (same as LIMIT(1))
All() // Retrieve all rows as objects (same as SELECT * FROM)
Count() // Number of rows (same as COUNT(*))
2016-09-01 02:35:32 +02:00
UpdateAll(models.M{"name": "John", "age": 23}) // Update all rows matching the built query.
2016-08-31 11:41:00 +02:00
DeleteAll() // Delete all rows matching the built query.
Exists() // Returns a bool indicating whether the row(s) for the built query exists.
Bind(& myObj) // Bind the results of a query to your own struct object.
2016-09-14 18:14:30 +02:00
Exec() // Execute an SQL query that does not require any rows returned.
QueryRow() // Execute an SQL query expected to return only a single row.
Query() // Execute an SQL query expected to return multiple rows.
2016-08-31 11:41:00 +02:00
```
2016-08-30 12:38:29 +02:00
2016-08-31 11:41:00 +02:00
### Raw Query
2016-08-30 12:38:29 +02:00
2016-09-15 05:59:55 +02:00
We provide `queries.Raw()` for executing raw queries. Generally you will want to use `Bind()` with
2016-08-31 11:41:00 +02:00
this, like the following:
2016-08-30 12:38:29 +02:00
2016-08-31 11:41:00 +02:00
```go
2016-09-15 05:59:55 +02:00
err := queries.Raw(db, "select * from pilots where id=$1", 5).Bind(& obj)
2016-08-31 11:41:00 +02:00
```
2016-08-30 12:38:29 +02:00
2016-08-31 11:41:00 +02:00
You can use your own structs or a generated struct as a parameter to Bind. Bind supports both
a single object for single row queries and a slice of objects for multiple row queries.
2016-08-30 12:38:29 +02:00
2016-09-15 05:59:55 +02:00
`queries.Raw()` also has a method that can execute a query without binding to an object, if required.
2016-09-14 11:42:07 +02:00
You also have `models.NewQuery()` at your disposal if you would still like to use [Query Building ](#query-building )
in combination with your own custom, non-generated model.
2016-08-31 23:01:59 +02:00
2016-08-30 12:38:29 +02:00
### Binding
2016-09-15 08:33:18 +02:00
For a comprehensive ruleset for `Bind()` you can refer to our [godoc ](https://godoc.org/github.com/vattle/sqlboiler/queries#Bind ).
2016-08-31 23:01:59 +02:00
2016-09-01 02:35:32 +02:00
The `Bind()` [Finisher ](#finisher ) allows the results of a query built with
2016-08-31 16:13:39 +02:00
the [Raw SQL ](#raw-query ) method or the [Query Builder ](#query-building ) methods to be bound
to your generated struct objects, or your own custom struct objects.
This can be useful for complex queries, queries that only require a small subset of data
and have no need for the rest of the object variables, or custom join struct objects like
the following:
```go
2016-08-31 23:01:59 +02:00
// Custom struct using two generated structs
2016-08-31 16:13:39 +02:00
type PilotAndJet struct {
models.Pilot `boil:",bind"`
models.Jet `boil:",bind"`
}
var paj PilotAndJet
2016-08-31 23:01:59 +02:00
// Use a raw query
2016-09-15 05:59:55 +02:00
err := queries.Raw(`
2016-08-31 23:01:59 +02:00
select pilots.id as "pilots.id", pilots.name as "pilots.name",
jets.id as "jets.id", jets.pilot_id as "jets.pilot_id",
jets.age as "jets.age", jets.name as "jets.name", jets.color as "jets.color"
from pilots inner join jets on jets.pilot_id=?`, 23,
).Bind(& paj)
// Use query building
err := models.NewQuery(db,
Select("pilots.id", "pilots.name", "jets.id", "jets.pilot_id", "jets.age", "jets.name", "jets.color"),
From("pilots"),
InnerJoin("jets on jets.pilot_id = pilots.id"),
).Bind(& paj)
2016-08-31 16:13:39 +02:00
```
```go
2016-08-31 23:01:59 +02:00
// Custom struct for selecting a subset of data
2016-08-31 16:13:39 +02:00
type JetInfo struct {
AgeSum int `boil:"age_sum"`
Count int `boil:"juicy_count"`
}
var info JetInfo
2016-08-31 23:01:59 +02:00
// Use query building
err := models.NewQuery(db, Select("sum(age) as age_sum", "count(*) as juicy_count", From("jets"))).Bind(& info)
// Use a raw query
2016-09-15 05:59:55 +02:00
err := queries.Raw(`select sum(age) as "age_sum", count(*) as "juicy_count" from jets`).Bind(& info)
2016-08-31 16:13:39 +02:00
```
We support the following struct tag modes for `Bind()` control:
```go
type CoolObject struct {
2016-09-01 02:35:32 +02:00
// Don't specify a name, Bind will TitleCase the column
2016-08-31 23:01:59 +02:00
// name, and try to match against this.
2016-08-31 16:13:39 +02:00
Frog int
2016-09-01 02:35:32 +02:00
// Specify an alternative name for the column, it will
2016-08-31 23:01:59 +02:00
// be titlecased for matching, can be whatever you like.
2016-08-31 16:13:39 +02:00
Cat int `boil:"kitten"`
2016-08-31 23:01:59 +02:00
// Ignore this struct field, do not attempt to bind it.
Pig int `boil:"-"`
2016-09-01 02:35:32 +02:00
// Instead of binding to this as a regular struct field
// (like other sql-able structs eg. time.Time)
2016-08-31 23:01:59 +02:00
// Recursively search inside the Dog struct for field names from the query.
Dog `boil:",bind"`
// Same as the above, except specify a different table name
Mouse `boil:"rodent,bind"`
// Ignore this struct field, do not attempt to bind it.
2016-08-31 16:13:39 +02:00
Bird `boil:"-"`
}
```
2016-09-01 02:35:32 +02:00
### Relationships
Helper methods will be generated for every to one and to many relationship structure
you have defined in your database by using foreign keys.
We attach these helpers directly to your model struct, for example:
```go
jet, _ := models.FindJet(db, 1)
// "to one" relationship helper method.
// This will retrieve the pilot for the jet.
pilot, err := jet.Pilot(db).One()
// "to many" relationship helper method.
// This will retrieve all languages for the pilot.
languages, err := pilot.Languages(db).All()
```
If your relationship involves a join table SQLBoiler will figure it out for you transparently.
It is important to note that you should use `Eager Loading` if you plan
on loading large collections of rows, to avoid N+1 performance problems.
For example, take the following:
```go
// Avoid this loop query pattern, it is slow.
jets, _ := models.Jets(db).All()
pilots := make([]models.Pilot, len(jets))
for i := 0; i < len ( jets ) ; i + + {
pilots[i] = jets[i].Pilot(db).OneP()
}
// Instead, use Eager Loading!
jets, _ := models.Jets(db, Load("Pilot")).All()
```
Eager loading can be combined with other query mods, and it can also eager load recursively.
```go
// Example of a nested load.
// Each jet will have its pilot loaded, and each pilot will have its languages loaded.
jets, _ := models.Jets(db, Load("Pilot.Languages")).All()
// Note that each level of a nested Load call will be loaded. No need to call Load() multiple times.
// A larger, random example
users, _ := models.Users(db,
Load("Pets.Vets"),
Load("Pets.Toys"),
Load("Property"),
Where("age > ?", 23),
).All()
```
We provide the following methods for managing relationships on objects:
**To One**
- `SetX()` : Set the foreign key to point to something else: jet.SetPilot(...)
- `RemoveX()` : Null out the foreign key, effectively removing the relationship between these two objects: jet.RemovePilot(...)
**To Many**
- `AddX()` : Add more relationships to the existing set of related Xs: pilot.AddLanguages(...)
- `SetX()` : Remove all existing relationships, and replace them with the provided set: pilot.SetLanguages(...)
- `RemoveX()` : Remove all provided relationships: pilot.RemoveLanguages(...)
**To One** code examples:
```go
jet, _ := models.FindJet(db, 1)
pilot, _ := models.FindPilot(db, 1)
// Set the pilot to an existing pilot
err := jet.SetPilot(db, false, & pilot)
pilot = models.Pilot{
Name: "Erlich",
}
// Insert the pilot into the database and assign it to a jet
err := jet.SetPilot(db, true, & pilot)
// Remove a relationship. This method only exists for foreign keys that can be NULL.
err := jet.RemovePilot(db, & pilot)
```
**To Many** code examples:
```go
pilots, _ := models.Pilots(db).All()
languages, _ := models.Languages(db).All()
// Set a group of language relationships
err := pilots.SetLanguages(db, false, & languages)
languages := []*models.Language{
{Language: "Strayan"},
{Language: "Yupik"},
{Language: "Pawnee"},
}
// Insert new a group of languages and assign them to a pilot
err := pilots.SetLanguages(db, true, languages...)
// Add another language relationship to the existing set of relationships
err := pilots.AddLanguages(db, false, & someOtherLanguage)
anotherLanguage := models.Language{Language: "Archi"}
// Insert and then add another language relationship
err := pilots.AddLanguages(db, true, & anotherLanguage)
// Remove a group of relationships
err := pilots.RemoveLanguages(db, languages...)
```
2016-08-31 11:41:00 +02:00
### Hooks
2016-09-01 02:35:32 +02:00
Before and After hooks are available for most operations. If you don't need them you can
2016-08-31 23:01:59 +02:00
shrink the size of the generated code by disabling them with the `--no-hooks` flag.
2016-09-01 02:35:32 +02:00
Every generated package that includes hooks has the following `HookPoints` defined:
2016-08-31 14:04:39 +02:00
```go
const (
BeforeInsertHook HookPoint = iota + 1
BeforeUpdateHook
BeforeDeleteHook
BeforeUpsertHook
AfterInsertHook
AfterSelectHook
AfterUpdateHook
AfterDeleteHook
AfterUpsertHook
)
```
To register a hook for your model you will need to create the hook function, and attach
it with the `AddModelHook` method. Here is an example of a before insert hook:
```go
// Define my hook function
func myHook(exec boil.Executor, p *Pilot) {
// Do stuff
}
// Register my before insert hook for pilots
models.AddPilotHook(boil.BeforeInsertHook, myHook)
```
Your `ModelHook` will always be defined as `func(boil.Executor, *Model)`
2016-08-30 12:38:29 +02:00
### Transactions
2016-09-01 02:35:32 +02:00
The boil.Executor interface powers all of SQLBoiler. This means anything that conforms
to the three `Exec/Query/QueryRow` methods can be used. `sql.DB` , `sql.Tx` as well as other
libraries (`sqlx`) conform to this interface, and therefore any of these things may be
2016-08-31 23:01:59 +02:00
used as an executor for any query in the system. This makes using transactions very simple:
2016-08-31 16:13:39 +02:00
```go
tx, err := db.Begin()
if err != nil {
return err
}
users, _ := models.Pilots(tx).All()
users.DeleteAll(tx)
// Rollback or commit
tx.Commit()
tx.Rollback()
```
2016-08-30 12:38:29 +02:00
### Debug Logging
2016-08-31 14:04:39 +02:00
Debug logging will print your generated SQL statement and the arguments it is using.
Debug logging can be toggled on globally by setting the following global variable to `true` :
```go
boil.DebugMode = true
// Optionally set the writer as well. Defaults to os.Stdout
fh, _ := os.Open("debug.txt")
boil.DebugWriter = fh
```
2016-08-31 23:01:59 +02:00
Note: Debug output is messy at the moment. This is something we would like addressed.
2016-08-31 14:04:39 +02:00
2016-08-30 12:38:29 +02:00
### Select
2016-08-31 14:04:39 +02:00
Select is done through [Query Building ](#query-building ) and [Find ](#find ). Here's a short example:
```go
// Select one pilot
pilot, err := models.Pilots(db, qm.Where("name=?", "Tim")).One()
2016-08-31 23:03:11 +02:00
// Select specific columns of many jets
jets, err := models.Jets(db, qm.Select("age", "name")).All()
2016-08-31 14:04:39 +02:00
```
2016-08-30 12:38:29 +02:00
### Find
2016-08-31 14:04:39 +02:00
Find is used to find a single row by primary key:
```go
// Retrieve pilot with all columns filled
pilot, err := models.PilotFind(db, 1)
// Retrieve a subset of column values
jet, err := models.JetFind(db, 1, "name", "color")
```
2016-08-30 12:38:29 +02:00
### Insert
2016-09-01 02:35:32 +02:00
The main thing to be aware of with `Insert` is how the `whitelist` operates. If no whitelist
2016-08-31 14:04:39 +02:00
argument is provided, `Insert` will abide by the following rules:
2016-08-31 23:01:59 +02:00
- Insert all columns **without** a database default value.
- Insert all columns with a non-zero value that have a database default value.
2016-08-31 14:04:39 +02:00
On the other hand, if a whitelist is provided, we will only insert the columns specified in the whitelist.
2016-09-01 02:35:32 +02:00
Also note that your object will automatically be updated with any missing default values from the
2016-08-31 14:04:39 +02:00
database after the `Insert` is finished executing. This includes auto-incrementing column values.
```go
var p1 models.Pilot
p1.Name = "Larry"
err := p1.Insert(db) // Insert the first pilot with name "Larry"
// p1 now has an ID field set to 1
var p2 models.Pilot
2016-09-15 08:33:18 +02:00
p2.Name "Boris"
err := p2.Insert(db) // Insert the second pilot with name "Boris"
2016-08-31 14:04:39 +02:00
// p2 now has an ID field set to 2
var p3 models.Pilot
p3.ID = 25
p3.Name = "Rupert"
err := p3.Insert(db) // Insert the third pilot with a specific ID
// The id for this row was inserted as 25 in the database.
var p4 models.Pilot
p4.ID = 0
p4.Name = "Nigel"
err := p4.Insert(db, "id", "name") // Insert the fourth pilot with a zero value ID
// The id for this row was inserted as 0 in the database.
// Note: We had to use the whitelist for this, otherwise
// SQLBoiler would presume you wanted to auto-increment
```
2016-08-30 12:38:29 +02:00
### Update
2016-08-31 14:04:39 +02:00
`Update` can be performed on a single object, a slice of objects or as a [Finisher ](#finishers )
for a collection of rows.
`Update` on a single object optionally takes a `whitelist` . The purpose of the
whitelist is to specify which columns in your object should be updated in the database.
If no `whitelist` argument is provided, `Update` will update every column except for
`primary key` columns.
If a `whitelist` argument is provided, `update` will only update the columns specified.
```go
// Find a pilot and update his name
pilot, _ := models.FindPilot(db, 1)
pilot.Name = "Neo"
err := pilot.Update(db)
// Update a slice of pilots to have the name "Smith"
pilots, _ := models.Pilots(db).All()
err := pilots.UpdateAll(db, models.M{"name": "Smith"})
// Update all pilots in the database to to have the name "Smith"
err := models.Pilots(db).UpdateAll(models.M{"name", "Smith"})
```
2016-08-30 12:38:29 +02:00
### Delete
2016-08-31 14:04:39 +02:00
2016-08-31 14:21:43 +02:00
Delete a single object, a slice of objects or specific objects through [Query Building ](#query-building ).
2016-08-31 14:04:39 +02:00
```go
pilot, _ := models.FindPilot(db, 1)
// Delete the pilot from the database
err := pilot.Delete(db)
// Delete all pilots from the database
err := models.Pilots(db).DeleteAll()
// Delete a slice of pilots from the database
pilots, _ := models.Pilots(db).All()
err := pilots.DeleteAll(db)
```
2016-08-30 12:38:29 +02:00
### Upsert
2016-08-31 14:21:43 +02:00
[Upsert ](https://www.postgresql.org/docs/9.5/static/sql-insert.html ) allows you to perform an insert
2016-08-31 14:04:39 +02:00
that optionally performs an update when a conflict is found against existing row values.
The `whitelist` operates in the same fashion that it does for [Insert ](#insert ).
If an insert is performed, your object will be updated with any missing default values from the database,
such as auto-incrementing column values.
```go
var p1 models.Pilot
p1.ID = 5
p1.Name = "Gaben"
2016-09-01 02:35:32 +02:00
// INSERT INTO pilots ("id", "name") VALUES($1, $2)
2016-08-31 14:04:39 +02:00
// ON CONFLICT DO NOTHING
err := p1.Upsert(db, false, nil, nil)
2016-09-01 02:35:32 +02:00
// INSERT INTO pilots ("id", "name") VALUES ($1, $2)
2016-08-31 14:04:39 +02:00
// ON CONFLICT ("id") DO UPDATE SET "name" = EXCLUDED."name"
err := p1.Upsert(db, true, []string{"id"}, []string{"name"})
// Set p1.ID to a zero value. We will have to use the whitelist now.
p1.ID = 0
p1.Name = "Hogan"
2016-09-01 02:35:32 +02:00
// INSERT INTO pilots ("id", "name") VALUES ($1, $2)
2016-08-31 14:04:39 +02:00
// ON CONFLICT ("id") DO UPDATE SET "name" = EXCLUDED."name"
err := p1.Upsert(db, true, []string{"id"}, []string{"name"}, "id", "name")
```
2016-09-14 10:08:30 +02:00
The `updateOnConflict` argument allows you to specify whether you would like Postgres
to perform a `DO NOTHING` on conflict, opposed to a `DO UPDATE` . For MySQL, this param will not be generated.
2016-09-15 05:59:55 +02:00
The `conflictColumns` argument allows you to specify the `ON CONFLICT` columns for Postgres.
2016-09-14 10:08:30 +02:00
For MySQL, this param will not be generated.
2016-08-31 16:13:39 +02:00
Note: Passing a different set of column values to the update component is not currently supported.
2016-08-30 12:38:29 +02:00
### Reload
2016-08-31 14:21:43 +02:00
In the event that your objects get out of sync with the database for whatever reason,
you can use `Reload` and `ReloadAll` to reload the objects using the primary key values
attached to the objects.
```go
pilot, _ := models.FindPilot(db, 1)
2016-09-14 12:42:20 +02:00
// > Object becomes out of sync for some reason, perhaps async processing
2016-08-31 14:21:43 +02:00
// Refresh the object with the latest data from the db
2016-09-01 02:35:32 +02:00
err := pilot.Reload(db)
2016-08-31 14:21:43 +02:00
// Reload all objects in a slice
pilots, _ := models.Pilots(db).All()
err := pilots.ReloadAll(db)
```
2016-08-31 16:35:24 +02:00
Note: `Reload` and `ReloadAll` are not recursive, if you need your relationships reloaded
you will need to call the `Reload` methods on those yourself.
2016-08-31 23:01:59 +02:00
### Exists
```go
jet, err := models.FindJet(db, 1)
// Check if the pilot assigned to this jet exists.
exists := jet.Pilot(db).Exists()
// Check if the pilot with ID 5 exists
2016-09-01 02:35:32 +02:00
exists := models.Pilots(db, Where("id=?", 5)).Exists()
2016-09-01 01:05:06 +02:00
```
2016-08-30 12:38:29 +02:00
2016-08-23 07:32:26 +02:00
## FAQ
2016-08-30 16:04:39 +02:00
#### Won't compiling models for a huge database be very slow?
2016-08-30 10:54:21 +02:00
No, because Go's toolchain - unlike traditional toolchains - makes the compiler do most of the work
instead of the linker. This means that when the first `go install` is done it can take
a little bit of time because there is a lot of code that is generated. However, because of this
work balance between the compiler and linker in Go, linking to that code afterwards in the subsequent
2016-09-01 02:35:32 +02:00
compiles is extremely fast.
2016-09-02 10:07:11 +02:00
#### Missing imports for generated package
The generated models might import a couple of packages that are not on your system already, so
`cd` into your generated models directory and type `go get -u -t` to fetch them. You will only need
to run this command once, not per generation.
2016-09-04 09:58:48 +02:00
2016-09-08 19:39:27 +02:00
#### How should I handle multiple schemas?
If your database uses multiple schemas you should generate a new package for each of your schemas.
Note that this only applies to databases that use real, SQL standard schemas (like PostgreSQL), not
fake schemas (like MySQL).
2016-09-11 19:40:59 +02:00
#### How do I use types.BytesArray for Postgres bytea arrays?
Only "escaped format" is supported for types.BytesArray. This means that your byte slice needs to have
a format of "\\x00" (4 bytes per byte) opposed to "\x00" (1 byte per byte). This is to maintain compatibility
with all Postgres drivers. Example:
`x := types.BytesArray{0: []byte("\\x68\\x69")}`
Please note that multi-dimensional Postgres ARRAY types are not supported at this time.
2016-09-19 07:22:32 +02:00
#### Why aren't my time.Time or null.Time fields working in MySQL?
2016-09-20 03:59:46 +02:00
You *must* use a DSN flag in MySQL connections, see: [Requirements ](#requirements )
2016-09-19 07:22:32 +02:00
2016-09-09 21:15:50 +02:00
#### Where is the homepage?
2016-09-15 05:59:55 +02:00
The homepage for the [SQLBoiler ](https://github.com/vattle/sqlboiler ) [Golang ORM ](https://github.com/vattle/sqlboiler ) generator is located at: https://github.com/vattle/sqlboiler
2016-09-09 21:15:50 +02:00
2016-09-04 09:58:48 +02:00
## Benchmarks
2016-09-04 17:44:29 +02:00
If you'd like to run the benchmarks yourself check out our [boilbench ](https://github.com/vattle/boilbench ) repo.
2016-09-08 23:23:10 +02:00
Here are the results (lower is better):
2016-09-04 17:44:29 +02:00
`go test -bench . -benchmem`
```
BenchmarkGORMDelete/gorm-8 100000 15364 ns/op 5395 B/op 113 allocs/op
BenchmarkGORPDelete/gorp-8 1000000 1703 ns/op 304 B/op 12 allocs/op
BenchmarkXORMDelete/xorm-8 100000 14733 ns/op 3634 B/op 107 allocs/op
BenchmarkBoilDelete/boil-8 2000000 986 ns/op 120 B/op 7 allocs/op
BenchmarkGORMInsert/gorm-8 100000 19197 ns/op 8054 B/op 161 allocs/op
BenchmarkGORPInsert/gorp-8 500000 3413 ns/op 1008 B/op 32 allocs/op
BenchmarkXORMInsert/xorm-8 100000 15428 ns/op 5836 B/op 131 allocs/op
BenchmarkBoilInsert/boil-8 500000 3041 ns/op 568 B/op 21 allocs/op
BenchmarkGORMSelectAll/gorm-8 20000 85422 ns/op 29912 B/op 511 allocs/op
BenchmarkGORPSelectAll/gorp-8 50000 35824 ns/op 8837 B/op 312 allocs/op
BenchmarkXORMSelectAll/xorm-8 30000 58843 ns/op 13805 B/op 298 allocs/op
BenchmarkBoilSelectAll/boil-8 100000 13844 ns/op 2840 B/op 61 allocs/op
BenchmarkGORMSelectSubset/gorm-8 10000 100714 ns/op 30875 B/op 517 allocs/op
BenchmarkGORPSelectSubset/gorp-8 30000 43547 ns/op 8837 B/op 312 allocs/op
BenchmarkXORMSelectSubset/xorm-8 30000 48128 ns/op 12989 B/op 282 allocs/op
BenchmarkBoilSelectSubset/boil-8 100000 12316 ns/op 2977 B/op 65 allocs/op
BenchmarkGORMSelectComplex/gorm-8 10000 133598 ns/op 49398 B/op 772 allocs/op
BenchmarkGORPSelectComplex/gorp-8 50000 40588 ns/op 9037 B/op 321 allocs/op
BenchmarkXORMSelectComplex/xorm-8 30000 56367 ns/op 14174 B/op 313 allocs/op
BenchmarkBoilSelectComplex/boil-8 100000 16941 ns/op 3821 B/op 95 allocs/op
BenchmarkGORMUpdate/gorm-8 50000 25406 ns/op 9710 B/op 195 allocs/op
BenchmarkGORPUpdate/gorp-8 300000 3614 ns/op 1152 B/op 34 allocs/op
BenchmarkXORMUpdate/xorm-8 100000 17510 ns/op 4458 B/op 132 allocs/op
BenchmarkBoilUpdate/boil-8 500000 2958 ns/op 520 B/op 16 allocs/op
BenchmarkGORMRawBind/gorm-8 10000 112577 ns/op 38270 B/op 595 allocs/op
BenchmarkGORPRawBind/gorp-8 30000 40967 ns/op 8837 B/op 312 allocs/op
BenchmarkXORMRawBind/xorm-8 30000 54739 ns/op 12692 B/op 273 allocs/op
BenchmarkSQLXRawBind/sqlx-8 200000 13537 ns/op 4268 B/op 49 allocs/op
BenchmarkBoilRawBind/boil-8 200000 11144 ns/op 4334 B/op 49 allocs/op
```
2016-09-04 17:49:30 +02:00
< img style = "margin-right:6px;" src = "http://i.imgur.com/TglZGoI.png" / >
< img style = "margin-right:6px;" src = "http://i.imgur.com/Ktm2ta4.png" / >
< img style = "margin-right:6px;" src = "http://i.imgur.com/yv8kFPA.png" / >
< img style = "margin-right:6px;" src = "http://i.imgur.com/890Zswe.png" / >
< img style = "margin-right:6px;" src = "http://i.imgur.com/qMgoAFJ.png" / >
< img style = "margin-right:6px;" src = "http://i.imgur.com/sDoNiCN.png" / >
< img style = "margin-right:6px;" src = "http://i.imgur.com/EvUa4UT.png" / >