gorm

package module
v0.0.0-...-048963c Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Sep 28, 2015 License: MIT Imports: 17 Imported by: 0

README

GORM

The fantastic ORM library for Golang, aims to be developer friendly.

wercker status

Overview

  • Full-Featured ORM (almost)
  • Chainable API
  • Auto Migrations
  • Relations (Has One, Has Many, Belongs To, Many To Many, Polymorphism)
  • Callbacks (Before/After Create/Save/Update/Delete/Find)
  • Preloading (eager loading)
  • Transactions
  • Embed Anonymous Struct
  • Soft Deletes
  • Customizable Logger
  • Iteration Support via Rows
  • Every feature comes with tests
  • Developer Friendly

Getting Started

Install

go get -u github.com/jinzhu/gorm

Documentation

GoDoc

go doc format documentation for this project can be viewed online without installing the package by using the GoDoc page at: http://godoc.org/github.com/jinzhu/gorm

Table of Contents

Define Models (Structs)

type User struct {
	ID           int
	Birthday     time.Time
	Age          int
	Name         string  `sql:"size:255"` // Default size for string is 255, you could reset it with this tag
	Num          int     `sql:"AUTO_INCREMENT"`
	CreatedAt    time.Time
	UpdatedAt    time.Time
	DeletedAt    *time.Time

	Emails            []Email         // One-To-Many relationship (has many)
	BillingAddress    Address         // One-To-One relationship (has one)
	BillingAddressID  sql.NullInt64   // Foreign key of BillingAddress
	ShippingAddress   Address         // One-To-One relationship (has one)
	ShippingAddressID int             // Foreign key of ShippingAddress
	IgnoreMe          int `sql:"-"`   // Ignore this field
	Languages         []Language `gorm:"many2many:user_languages;"` // Many-To-Many relationship, 'user_languages' is join table
}

type Email struct {
	ID      int
	UserID  int     `sql:"index"` // Foreign key (belongs to), tag `index` will create index for this field when using AutoMigrate
	Email   string  `sql:"type:varchar(100);unique_index"` // Set field's sql type, tag `unique_index` will create unique index
	Subscribed bool
}

type Address struct {
	ID       int
	Address1 string         `sql:"not null;unique"` // Set field as not nullable and unique
	Address2 string         `sql:"type:varchar(100);unique"`
	Post     sql.NullString `sql:"not null"`
}

type Language struct {
	ID   int
	Name string `sql:"index:idx_name_code"` // Create index with name, and will create combined index if find other fields defined same name
	Code string `sql:"index:idx_name_code"` // `unique_index` also works
}

Conventions

type User struct{} // struct User's database table name is "users" by default, will be "user" if you disabled pluralisation
  • Column name is the snake case of field's name
  • Use ID field as primary key
  • Use CreatedAt to store record's created time if field exists
  • Use UpdatedAt to store record's updated time if field exists
  • Use DeletedAt to store record's deleted time if field exists Soft Delete
  • Gorm provide a default model struct, you could embed it in your struct
type Model struct {
	ID        uint `gorm:"primary_key"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt *time.Time
}

type User struct {
	gorm.Model
	Name string
}

Initialize Database

import (
	"github.com/jinzhu/gorm"
	_ "github.com/lib/pq"
	_ "github.com/go-sql-driver/mysql"
	_ "github.com/mattn/go-sqlite3"
)

db, err := gorm.Open("postgres", "user=gorm dbname=gorm sslmode=disable")
// db, err := gorm.Open("foundation", "dbname=gorm") // FoundationDB.
// db, err := gorm.Open("mysql", "user:password@/dbname?charset=utf8&parseTime=True&loc=Local")
// db, err := gorm.Open("sqlite3", "/tmp/gorm.db")

// You can also use an existing database connection handle
// dbSql, _ := sql.Open("postgres", "user=gorm dbname=gorm sslmode=disable")
// db, _ := gorm.Open("postgres", dbSql)

// Get database connection handle [*sql.DB](http://golang.org/pkg/database/sql/#DB)
db.DB()

// Then you could invoke `*sql.DB`'s functions with it
db.DB().Ping()
db.DB().SetMaxIdleConns(10)
db.DB().SetMaxOpenConns(100)

// Disable table name's pluralization
db.SingularTable(true)

Migration

// Create table
db.CreateTable(&User{})
db.Set("gorm:table_options", "ENGINE=InnoDB").CreateTable(&User{})

// Drop table
db.DropTable(&User{})

// ModifyColumn
db.Model(&User{}).ModifyColumn("description", "text")

// DropColumn
db.Model(&User{}).DropColumn("description")

// Automating Migration
db.AutoMigrate(&User{})
db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&User{})
db.AutoMigrate(&User{}, &Product{}, &Order{})
// Feel free to change your struct, AutoMigrate will keep your database up-to-date.
// AutoMigrate will ONLY add *new columns* and *new indexes*,
// WON'T update current column's type or delete unused columns, to protect your data.
// If the table is not existing, AutoMigrate will create the table automatically.

Basic CRUD

Create Record

user := User{Name: "Jinzhu", Age: 18, Birthday: time.Now()}

db.NewRecord(user) // => returns `true` if primary key is blank

db.Create(&user)

db.NewRecord(user) // => return `false` after `user` created

// Associations will be inserted automatically when save the record
user := User{
	Name:            "jinzhu",
	BillingAddress:  Address{Address1: "Billing Address - Address 1"},
	ShippingAddress: Address{Address1: "Shipping Address - Address 1"},
	Emails:          []Email{{Email: "jinzhu@example.com"}, {Email: "jinzhu-2@example@example.com"}},
	Languages:       []Language{{Name: "ZH"}, {Name: "EN"}},
}

db.Create(&user)
//// BEGIN TRANSACTION;
//// INSERT INTO "addresses" (address1) VALUES ("Billing Address - Address 1");
//// INSERT INTO "addresses" (address1) VALUES ("Shipping Address - Address 1");
//// INSERT INTO "users" (name,billing_address_id,shipping_address_id) VALUES ("jinzhu", 1, 2);
//// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu@example.com");
//// INSERT INTO "emails" (user_id,email) VALUES (111, "jinzhu-2@example.com");
//// INSERT INTO "languages" ("name") VALUES ('ZH');
//// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 1);
//// INSERT INTO "languages" ("name") VALUES ('EN');
//// INSERT INTO user_languages ("user_id","language_id") VALUES (111, 2);
//// COMMIT;

Refer Associations for more details

Query

// Get the first record
db.First(&user)
//// SELECT * FROM users ORDER BY id LIMIT 1;

// Get the last record
db.Last(&user)
//// SELECT * FROM users ORDER BY id DESC LIMIT 1;

// Get all records
db.Find(&users)
//// SELECT * FROM users;

// Get record with primary key
db.First(&user, 10)
//// SELECT * FROM users WHERE id = 10;
Query With Where (Plain SQL)
// Get the first matched record
db.Where("name = ?", "jinzhu").First(&user)
//// SELECT * FROM users WHERE name = 'jinzhu' limit 1;

// Get all matched records
db.Where("name = ?", "jinzhu").Find(&users)
//// SELECT * FROM users WHERE name = 'jinzhu';

db.Where("name <> ?", "jinzhu").Find(&users)

// IN
db.Where("name in (?)", []string{"jinzhu", "jinzhu 2"}).Find(&users)

// LIKE
db.Where("name LIKE ?", "%jin%").Find(&users)

// AND
db.Where("name = ? and age >= ?", "jinzhu", "22").Find(&users)

// Time
db.Where("updated_at > ?", lastWeek).Find(&users)

db.Where("created_at BETWEEN ? AND ?", lastWeek, today).Find(&users)
Query With Where (Struct & Map)
// Struct
db.Where(&User{Name: "jinzhu", Age: 20}).First(&user)
//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20 LIMIT 1;

// Map
db.Where(map[string]interface{}{"name": "jinzhu", "age": 20}).Find(&users)
//// SELECT * FROM users WHERE name = "jinzhu" AND age = 20;

// Slice of primary keys
db.Where([]int64{20, 21, 22}).Find(&users)
//// SELECT * FROM users WHERE id IN (20, 21, 22);
Query With Not
db.Not("name", "jinzhu").First(&user)
//// SELECT * FROM users WHERE name <> "jinzhu" LIMIT 1;

// Not In
db.Not("name", []string{"jinzhu", "jinzhu 2"}).Find(&users)
//// SELECT * FROM users WHERE name NOT IN ("jinzhu", "jinzhu 2");

// Not In slice of primary keys
db.Not([]int64{1,2,3}).First(&user)
//// SELECT * FROM users WHERE id NOT IN (1,2,3);

db.Not([]int64{}).First(&user)
//// SELECT * FROM users;

// Plain SQL
db.Not("name = ?", "jinzhu").First(&user)
//// SELECT * FROM users WHERE NOT(name = "jinzhu");

// Struct
db.Not(User{Name: "jinzhu"}).First(&user)
//// SELECT * FROM users WHERE name <> "jinzhu";
Query With Inline Condition
// Get by primary key
db.First(&user, 23)
//// SELECT * FROM users WHERE id = 23 LIMIT 1;

// Plain SQL
db.Find(&user, "name = ?", "jinzhu")
//// SELECT * FROM users WHERE name = "jinzhu";

db.Find(&users, "name <> ? AND age > ?", "jinzhu", 20)
//// SELECT * FROM users WHERE name <> "jinzhu" AND age > 20;

// Struct
db.Find(&users, User{Age: 20})
//// SELECT * FROM users WHERE age = 20;

// Map
db.Find(&users, map[string]interface{}{"age": 20})
//// SELECT * FROM users WHERE age = 20;
Query With Or
db.Where("role = ?", "admin").Or("role = ?", "super_admin").Find(&users)
//// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';

// Struct
db.Where("name = 'jinzhu'").Or(User{Name: "jinzhu 2"}).Find(&users)
//// SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';

// Map
db.Where("name = 'jinzhu'").Or(map[string]interface{}{"name": "jinzhu 2"}).Find(&users)
Query Chains

Gorm has a chainable API, you could use it like this

db.Where("name <> ?","jinzhu").Where("age >= ? and role <> ?",20,"admin").Find(&users)
//// SELECT * FROM users WHERE name <> 'jinzhu' AND age >= 20 AND role <> 'admin';

db.Where("role = ?", "admin").Or("role = ?", "super_admin").Not("name = ?", "jinzhu").Find(&users)
Preloading (Eager loading)
db.Preload("Orders").Find(&users)
//// SELECT * FROM users;
//// SELECT * FROM orders WHERE user_id IN (1,2,3,4);

db.Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
//// SELECT * FROM users;
//// SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');

db.Where("state = ?", "active").Preload("Orders", "state NOT IN (?)", "cancelled").Find(&users)
//// SELECT * FROM users WHERE state = 'active';
//// SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');

db.Preload("Orders").Preload("Profile").Preload("Role").Find(&users)
//// SELECT * FROM users;
//// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many
//// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one
//// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to
Nested Preloading
db.Preload("Orders.OrderItems").Find(&users)
db.Preload("Orders", "state = ?", "paid").Preload("Orders.OrderItems").Find(&users)

Update

// Update an existing struct
db.First(&user)
user.Name = "jinzhu 2"
user.Age = 100
db.Save(&user)
//// UPDATE users SET name='jinzhu 2', age=100, updated_at = '2013-11-17 21:34:10' WHERE id=111;

db.Where("active = ?", true).Save(&user)
//// UPDATE users SET name='jinzhu 2', age=100, updated_at = '2013-11-17 21:34:10' WHERE id=111 AND active = true;

// Update an attribute if it is changed
db.Model(&user).Update("name", "hello")
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111;

db.Model(&user).Where("active = ?", true).Update("name", "hello")
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111 AND active = true;

db.First(&user, 111).Update("name", "hello")
//// SELECT * FROM users LIMIT 1;
//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111;

// Update multiple attributes if they are changed
db.Model(&user).Updates(map[string]interface{}{"name": "hello", "age": 18, "actived": false})

// Update multiple attributes if they are changed (update with struct only works with none zero values)
db.Model(&user).Updates(User{Name: "hello", Age: 18})
//// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;
Update Without Callbacks

By default, update will call BeforeUpdate, AfterUpdate callbacks, if you want to update w/o callbacks and w/o saving associations:

db.Model(&user).UpdateColumn("name", "hello")
//// UPDATE users SET name='hello' WHERE id = 111;

// Update with struct only works with none zero values, or use map[string]interface{}
db.Model(&user).UpdateColumns(User{Name: "hello", Age: 18})
//// UPDATE users SET name='hello', age=18 WHERE id = 111;
Batch Updates
db.Table("users").Where("id = ?", 10).Updates(map[string]interface{}{"name": "hello", "age": 18})
//// UPDATE users SET name='hello', age=18 WHERE id = 10;

// Update with struct only works with none zero values, or use map[string]interface{}
db.Model(User{}).Updates(User{Name: "hello", Age: 18})
//// UPDATE users SET name='hello', age=18;

// Callbacks won't run when do batch updates

// Use `RowsAffected` to get the count of affected records
db.Model(User{}).Updates(User{Name: "hello", Age: 18}).RowsAffected
Update with SQL Expression
DB.Model(&product).Update("price", gorm.Expr("price * ? + ?", 2, 100))
//// UPDATE "products" SET "code" = 'L1212', "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';

DB.Model(&product).Updates(map[string]interface{}{"price": gorm.Expr("price * ? + ?", 2, 100)})
//// UPDATE "products" SET "code" = 'L1212', "price" = price * '2' + '100', "updated_at" = '2013-11-17 21:34:10' WHERE "id" = '2';

DB.Model(&product).UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
//// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2';

DB.Model(&product).Where("quantity > 1").UpdateColumn("quantity", gorm.Expr("quantity - ?", 1))
//// UPDATE "products" SET "quantity" = quantity - 1 WHERE "id" = '2' AND quantity > 1;

Delete

// Delete an existing record
db.Delete(&email)
//// DELETE from emails where id=10;
Batch Delete
db.Where("email LIKE ?", "%jinzhu%").Delete(Email{})
//// DELETE from emails where email LIKE "%jinhu%";
Soft Delete

If struct has DeletedAt field, it will get soft delete ability automatically! Then it won't be deleted from database permanently when call Delete.

db.Delete(&user)
//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE id = 111;

// Batch Delete
db.Where("age = ?", 20).Delete(&User{})
//// UPDATE users SET deleted_at="2013-10-29 10:23" WHERE age = 20;

// Soft deleted records will be ignored when query them
db.Where("age = 20").Find(&user)
//// SELECT * FROM users WHERE age = 20 AND (deleted_at IS NULL OR deleted_at <= '0001-01-02');

// Find soft deleted records with Unscoped
db.Unscoped().Where("age = 20").Find(&users)
//// SELECT * FROM users WHERE age = 20;

// Delete record permanently with Unscoped
db.Unscoped().Delete(&order)
//// DELETE FROM orders WHERE id=10;

Associations

Has One
// User has one address
db.Model(&user).Related(&address)
//// SELECT * FROM addresses WHERE id = 123; // 123 is user's foreign key AddressId

// Specify the foreign key
db.Model(&user).Related(&address1, "BillingAddressId")
//// SELECT * FROM addresses WHERE id = 123; // 123 is user's foreign key BillingAddressId
Belongs To
// Email belongs to user
db.Model(&email).Related(&user)
//// SELECT * FROM users WHERE id = 111; // 111 is email's foreign key UserId

// Specify the foreign key
db.Model(&email).Related(&user, "ProfileId")
//// SELECT * FROM users WHERE id = 111; // 111 is email's foreign key ProfileId
Has Many
// User has many emails
db.Model(&user).Related(&emails)
//// SELECT * FROM emails WHERE user_id = 111;
// user_id is the foreign key, 111 is user's primary key's value

// Specify the foreign key
db.Model(&user).Related(&emails, "ProfileId")
//// SELECT * FROM emails WHERE profile_id = 111;
// profile_id is the foreign key, 111 is user's primary key's value
Many To Many
// User has many languages and belongs to many languages
db.Model(&user).Related(&languages, "Languages")
//// SELECT * FROM "languages" INNER JOIN "user_languages" ON "user_languages"."language_id" = "languages"."id" WHERE "user_languages"."user_id" = 111
// `Languages` is user's column name, this column's tag defined join table like this `gorm:"many2many:user_languages;"`

There is also a mode used to handle many to many relations easily

// Query
db.Model(&user).Association("Languages").Find(&languages)
// same as `db.Model(&user).Related(&languages, "Languages")`

db.Where("name = ?", "ZH").First(&languageZH)
db.Where("name = ?", "EN").First(&languageEN)

// Append
db.Model(&user).Association("Languages").Append([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Append([]Language{{Name: "DE"}})
db.Model(&user).Association("Languages").Append(Language{Name: "DE"})

// Delete
db.Model(&user).Association("Languages").Delete([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Delete(languageZH, languageEN)

// Replace
db.Model(&user).Association("Languages").Replace([]Language{languageZH, languageEN})
db.Model(&user).Association("Languages").Replace(Language{Name: "DE"}, languageEN)

// Count
db.Model(&user).Association("Languages").Count()
// Return the count of languages the user has

// Clear
db.Model(&user).Association("Languages").Clear()
// Remove all relations between the user and languages
Polymorphism

Supports polymorphic has-many and has-one associations.

  type Cat struct {
    Id    int
    Name  string
    Toy   Toy `gorm:"polymorphic:Owner;"`
  }

  type Dog struct {
    Id   int
    Name string
    Toy  Toy `gorm:"polymorphic:Owner;"`
  }

  type Toy struct {
    Id        int
    Name      string
    OwnerId   int
    OwnerType string
  }

Note: polymorphic belongs-to and many-to-many are explicitly NOT supported, and will throw errors.

Advanced Usage

FirstOrInit

Get the first matched record, or initialize a record with search conditions.

// Unfound
db.FirstOrInit(&user, User{Name: "non_existing"})
//// user -> User{Name: "non_existing"}

// Found
db.Where(User{Name: "Jinzhu"}).FirstOrInit(&user)
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
db.FirstOrInit(&user, map[string]interface{}{"name": "jinzhu"})
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
Attrs

Ignore some values when searching, but use them to initialize the struct if record is not found.

// Unfound
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrInit(&user)
//// SELECT * FROM USERS WHERE name = 'non_existing';
//// user -> User{Name: "non_existing", Age: 20}

db.Where(User{Name: "noexisting_user"}).Attrs("age", 20).FirstOrInit(&user)
//// SELECT * FROM USERS WHERE name = 'non_existing';
//// user -> User{Name: "non_existing", Age: 20}

// Found
db.Where(User{Name: "Jinzhu"}).Attrs(User{Age: 30}).FirstOrInit(&user)
//// SELECT * FROM USERS WHERE name = jinzhu';
//// user -> User{Id: 111, Name: "Jinzhu", Age: 20}
Assign

Ignore some values when searching, but assign it to the result regardless it is found or not.

// Unfound
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrInit(&user)
//// user -> User{Name: "non_existing", Age: 20}

// Found
db.Where(User{Name: "Jinzhu"}).Assign(User{Age: 30}).FirstOrInit(&user)
//// SELECT * FROM USERS WHERE name = jinzhu';
//// user -> User{Id: 111, Name: "Jinzhu", Age: 30}

FirstOrCreate

Get the first matched record, or create with search conditions.

// Unfound
db.FirstOrCreate(&user, User{Name: "non_existing"})
//// INSERT INTO "users" (name) VALUES ("non_existing");
//// user -> User{Id: 112, Name: "non_existing"}

// Found
db.Where(User{Name: "Jinzhu"}).FirstOrCreate(&user)
//// user -> User{Id: 111, Name: "Jinzhu"}
Attrs

Ignore some values when searching, but use them to create the struct if record is not found. like FirstOrInit

// Unfound
db.Where(User{Name: "non_existing"}).Attrs(User{Age: 20}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE name = 'non_existing';
//// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
//// user -> User{Id: 112, Name: "non_existing", Age: 20}

// Found
db.Where(User{Name: "jinzhu"}).Attrs(User{Age: 30}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE name = 'jinzhu';
//// user -> User{Id: 111, Name: "jinzhu", Age: 20}
Assign

Ignore some values when searching, but assign it to the record regardless it is found or not, then save back to database. like FirstOrInit

// Unfound
db.Where(User{Name: "non_existing"}).Assign(User{Age: 20}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE name = 'non_existing';
//// INSERT INTO "users" (name, age) VALUES ("non_existing", 20);
//// user -> User{Id: 112, Name: "non_existing", Age: 20}

// Found
db.Where(User{Name: "jinzhu"}).Assign(User{Age: 30}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE name = 'jinzhu';
//// UPDATE users SET age=30 WHERE id = 111;
//// user -> User{Id: 111, Name: "jinzhu", Age: 30}

Select

db.Select("name, age").Find(&users)
//// SELECT name, age FROM users;

db.Select([]string{"name", "age"}).Find(&users)
//// SELECT name, age FROM users;

db.Table("users").Select("COALESCE(age,?)", 42).Rows()
//// SELECT COALESCE(age,'42') FROM users;

Order

db.Order("age desc, name").Find(&users)
//// SELECT * FROM users ORDER BY age desc, name;

// Multiple orders
db.Order("age desc").Order("name").Find(&users)
//// SELECT * FROM users ORDER BY age desc, name;

// ReOrder
db.Order("age desc").Find(&users1).Order("age", true).Find(&users2)
//// SELECT * FROM users ORDER BY age desc; (users1)
//// SELECT * FROM users ORDER BY age; (users2)

Limit

db.Limit(3).Find(&users)
//// SELECT * FROM users LIMIT 3;

// Cancel limit condition with -1
db.Limit(10).Find(&users1).Limit(-1).Find(&users2)
//// SELECT * FROM users LIMIT 10; (users1)
//// SELECT * FROM users; (users2)

Offset

db.Offset(3).Find(&users)
//// SELECT * FROM users OFFSET 3;

// Cancel offset condition with -1
db.Offset(10).Find(&users1).Offset(-1).Find(&users2)
//// SELECT * FROM users OFFSET 10; (users1)
//// SELECT * FROM users; (users2)

Count

db.Where("name = ?", "jinzhu").Or("name = ?", "jinzhu 2").Find(&users).Count(&count)
//// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)
//// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)

db.Model(User{}).Where("name = ?", "jinzhu").Count(&count)
//// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)

db.Table("deleted_users").Count(&count)
//// SELECT count(*) FROM deleted_users;

Pluck

Get selected attributes as map

var ages []int64
db.Find(&users).Pluck("age", &ages)

var names []string
db.Model(&User{}).Pluck("name", &names)

db.Table("deleted_users").Pluck("name", &names)

// Requesting more than one column? Do it like this:
db.Select("name, age").Find(&users)

Raw SQL

db.Exec("DROP TABLE users;")
db.Exec("UPDATE orders SET shipped_at=? WHERE id IN (?)", time.Now, []int64{11,22,33})

Row & Rows

It is even possible to get query result as *sql.Row or *sql.Rows

row := db.Table("users").Where("name = ?", "jinzhu").Select("name, age").Row() // (*sql.Row)
row.Scan(&name, &age)

rows, err := db.Model(User{}).Where("name = ?", "jinzhu").Select("name, age, email").Rows() // (*sql.Rows, error)
defer rows.Close()
for rows.Next() {
	...
	rows.Scan(&name, &age, &email)
	...
}

// Raw SQL
rows, err := db.Raw("select name, age, email from users where name = ?", "jinzhu").Rows() // (*sql.Rows, error)
defer rows.Close()
for rows.Next() {
	...
	rows.Scan(&name, &age, &email)
	...
}

Scan

Scan results into another struct.

type Result struct {
	Name string
	Age  int
}

var result Result
db.Table("users").Select("name, age").Where("name = ?", 3).Scan(&result)

// Raw SQL
db.Raw("SELECT name, age FROM users WHERE name = ?", 3).Scan(&result)

Group & Having

rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Rows()
for rows.Next() {
	...
}

rows, err := db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Rows()
for rows.Next() {
	...
}

type Result struct {
	Date  time.Time
	Total int64
}
db.Table("orders").Select("date(created_at) as date, sum(amount) as total").Group("date(created_at)").Having("sum(amount) > ?", 100).Scan(&results)

Joins

rows, err := db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Rows()
for rows.Next() {
	...
}

db.Table("users").Select("users.name, emails.email").Joins("left join emails on emails.user_id = users.id").Scan(&results)

// find a user by email address
db.Joins("inner join emails on emails.user_id = users.id").Where("emails.email = ?", "x@example.org").Find(&user)

// find all email addresses for a user
db.Joins("left join users on users.id = emails.user_id").Where("users.name = ?", "jinzhu").Find(&emails)

Transactions

To perform a set of operations within a transaction, the general flow is as below. The database handle returned from db.Begin() should be used for all operations within the transaction. (Note that all individual save and delete operations are run in a transaction by default.)

// begin
tx := db.Begin()

// do some database operations (use 'tx' from this point, not 'db')
tx.Create(...)
...

// rollback in case of error
tx.Rollback()

// Or commit if all is ok
tx.Commit()
A Specific Example
func CreateAnimals(db *gorm.DB) err {
  tx := db.Begin()
  // Note the use of tx as the database handle once you are within a transaction

  if err := tx.Create(&Animal{Name: "Giraffe"}).Error; err != nil {
     tx.Rollback()
     return err
  }

  if err := tx.Create(&Animal{Name: "Lion"}).Error; err != nil {
     tx.Rollback()
     return err
  }

  tx.Commit()
  return nil
}

Scopes

func AmountGreaterThan1000(db *gorm.DB) *gorm.DB {
	return db.Where("amount > ?", 1000)
}

func PaidWithCreditCard(db *gorm.DB) *gorm.DB {
	return db.Where("pay_mode_sign = ?", "C")
}

func PaidWithCod(db *gorm.DB) *gorm.DB {
	return db.Where("pay_mode_sign = ?", "C")
}

func OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {
	return func (db *gorm.DB) *gorm.DB {
		return db.Scopes(AmountGreaterThan1000).Where("status in (?)", status)
	}
}

db.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)
// Find all credit card orders and amount greater than 1000

db.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)
// Find all COD orders and amount greater than 1000

db.Scopes(OrderStatus([]string{"paid", "shipped"})).Find(&orders)
// Find all paid, shipped orders

Callbacks

Callbacks are methods defined on the pointer of struct. If any callback returns an error, gorm will stop future operations and rollback all changes.

Here is the list of all available callbacks: (listed in the same order in which they will get called during the respective operations)

Creating An Object
BeforeSave
BeforeCreate
// save before associations
// save self
// save after associations
AfterCreate
AfterSave
Updating An Object
BeforeSave
BeforeUpdate
// save before associations
// save self
// save after associations
AfterUpdate
AfterSave
Destroying An Object
BeforeDelete
// delete self
AfterDelete
After Find
// load data from database
AfterFind
Example
func (u *User) BeforeUpdate() (err error) {
	if u.readonly() {
		err = errors.New("read only user")
	}
	return
}

// Rollback the insertion if user's id greater than 1000
func (u *User) AfterCreate() (err error) {
	if (u.Id > 1000) {
		err = errors.New("user id is already greater than 1000")
	}
	return
}

As you know, save/delete operations in gorm are running in a transaction, This is means if changes made in the transaction is not visiable unless it is commited, So if you want to use those changes in your callbacks, you need to run SQL in same transaction. Fortunately, gorm support pass transaction to callbacks as you needed, you could do it like this:

func (u *User) AfterCreate(tx *gorm.DB) (err error) {
	tx.Model(u).Update("role", "admin")
	return
}

Specifying The Table Name

// Create `deleted_users` table with struct User's definition
db.Table("deleted_users").CreateTable(&User{})

var deleted_users []User
db.Table("deleted_users").Find(&deleted_users)
//// SELECT * FROM deleted_users;

db.Table("deleted_users").Where("name = ?", "jinzhu").Delete()
//// DELETE FROM deleted_users WHERE name = 'jinzhu';
Specifying The Table Name For A Struct Permanently with TableName
type Cart struct {
}

func (c Cart) TableName() string {
	return "shopping_cart"
}

func (u User) TableName() string {
	if u.Role == "admin" {
		return "admin_users"
	} else {
		return "users"
	}
}

Error Handling

query := db.Where("name = ?", "jinzhu").First(&user)
query := db.First(&user).Limit(10).Find(&users)
// query.Error will return the last happened error

// So you could do error handing in your application like this:
if err := db.Where("name = ?", "jinzhu").First(&user).Error; err != nil {
	// error handling...
}

// RecordNotFound
// If no record found when you query data, gorm will return RecordNotFound error, you could check it like this:
db.Where("name = ?", "hello world").First(&User{}).Error == gorm.RecordNotFound
// Or use the shortcut method
db.Where("name = ?", "hello world").First(&user).RecordNotFound()

if db.Model(&user).Related(&credit_card).RecordNotFound() {
	// no credit card found error handling
}

Logger

Gorm has built-in logger support

// Enable Logger
db.LogMode(true)

// Diable Logger
db.LogMode(false)

// Debug a single operation
db.Debug().Where("name = ?", "jinzhu").First(&User{})

logger

Customize Logger
// Refer gorm's default logger for how to: https://github.com/jinzhu/gorm/blob/master/logger.go#files
db.SetLogger(gorm.Logger{revel.TRACE})
db.SetLogger(log.New(os.Stdout, "\r\n", 0))

Existing Schema

If you have an existing database schema, and the primary key field is different from id, you can add a tag to the field structure to specify that this field is a primary key.

type Animal struct {
	AnimalId     int64 `gorm:"primary_key"`
	Birthday     time.Time `sql:"DEFAULT:current_timestamp"`
	Name         string `sql:"default:'galeone'"`
	Age          int64
}

If your column names differ from the struct fields, you can specify them like this:

type Animal struct {
	AnimalId    int64     `gorm:"column:beast_id;primary_key"`
	Birthday    time.Time `gorm:"column:day_of_the_beast"`
	Age         int64     `gorm:"column:age_of_the_beast"`
}

Composite Primary Key

type Product struct {
	ID           string `gorm:"primary_key"`
	LanguageCode string `gorm:"primary_key"`
}

Database Indexes & Foreign Key

// Add foreign key
// 1st param : foreignkey field
// 2nd param : destination table(id)
// 3rd param : ONDELETE
// 4th param : ONUPDATE
db.Model(&User{}).AddForeignKey("city_id", "cities(id)", "RESTRICT", "RESTRICT")

// Add index
db.Model(&User{}).AddIndex("idx_user_name", "name")

// Multiple column index
db.Model(&User{}).AddIndex("idx_user_name_age", "name", "age")

// Add unique index
db.Model(&User{}).AddUniqueIndex("idx_user_name", "name")

// Multiple column unique index
db.Model(&User{}).AddUniqueIndex("idx_user_name_age", "name", "age")

// Remove index
db.Model(&User{}).RemoveIndex("idx_user_name")

Default values

type Animal struct {
	ID   int64
	Name string `sql:"default:'galeone'"`
	Age  int64
}

If you have defined a default value in the sql tag, the generated create SQl will ignore these fields if it is blank.

Eg.

db.Create(&Animal{Age: 99, Name: ""})

The generated SQL will be:

INSERT INTO animals("age") values('99');

The same thing occurs in update statements.

More examples with query chain

db.First(&first_article).Count(&total_count).Limit(10).Find(&first_page_articles).Offset(10).Find(&second_page_articles)
//// SELECT * FROM articles LIMIT 1; (first_article)
//// SELECT count(*) FROM articles; (total_count)
//// SELECT * FROM articles LIMIT 10; (first_page_articles)
//// SELECT * FROM articles LIMIT 10 OFFSET 10; (second_page_articles)


db.Where("created_at > ?", "2013-10-10").Find(&cancelled_orders, "state = ?", "cancelled").Find(&shipped_orders, "state = ?", "shipped")
//// SELECT * FROM orders WHERE created_at > '2013/10/10' AND state = 'cancelled'; (cancelled_orders)
//// SELECT * FROM orders WHERE created_at > '2013/10/10' AND state = 'shipped'; (shipped_orders)


// Use variables to keep query chain
todays_orders := db.Where("created_at > ?", "2013-10-29")
cancelled_orders := todays_orders.Where("state = ?", "cancelled")
shipped_orders := todays_orders.Where("state = ?", "shipped")


// Search with shared conditions for different tables
db.Where("product_name = ?", "fancy_product").Find(&orders).Find(&shopping_carts)
//// SELECT * FROM orders WHERE product_name = 'fancy_product'; (orders)
//// SELECT * FROM carts WHERE product_name = 'fancy_product'; (shopping_carts)


// Search with shared conditions from different tables with specified table
db.Where("mail_type = ?", "TEXT").Find(&users1).Table("deleted_users").Find(&users2)
//// SELECT * FROM users WHERE mail_type = 'TEXT'; (users1)
//// SELECT * FROM deleted_users WHERE mail_type = 'TEXT'; (users2)


// FirstOrCreate example
db.Where("email = ?", "x@example.org").Attrs(User{RegisteredIp: "111.111.111.111"}).FirstOrCreate(&user)
//// SELECT * FROM users WHERE email = 'x@example.org';
//// INSERT INTO "users" (email,registered_ip) VALUES ("x@example.org", "111.111.111.111")  // if record not found

TODO

  • Github Pages

Author

jinzhu

License

Released under the MIT License.

Documentation

Index

Constants

This section is empty.

Variables

View Source
var (
	RecordNotFound       = errors.New("record not found")
	InvalidSql           = errors.New("invalid sql")
	NoNewAttrs           = errors.New("no new attributes")
	NoValidTransaction   = errors.New("no valid transaction")
	CantStartTransaction = errors.New("can't start transaction")
)
View Source
var DefaultCallback = &callback{processors: []*callbackProcessor{}}
View Source
var DefaultTableNameHandler = func(db *DB, defaultTableName string) string {
	return defaultTableName
}
View Source
var NowFunc = func() time.Time {
	return time.Now()
}

NowFunc returns current time, this function is exported in order to be able to give the flexibility to the developer to customize it according to their needs

e.g: return time.Now().UTC()

Functions

func AfterCreate

func AfterCreate(scope *Scope)

func AfterDelete

func AfterDelete(scope *Scope)

func AfterQuery

func AfterQuery(scope *Scope)

func AfterUpdate

func AfterUpdate(scope *Scope)

func AssignUpdateAttributes

func AssignUpdateAttributes(scope *Scope)

func BeforeCreate

func BeforeCreate(scope *Scope)

func BeforeDelete

func BeforeDelete(scope *Scope)

func BeforeUpdate

func BeforeUpdate(scope *Scope)

func BeginTransaction

func BeginTransaction(scope *Scope)

func CommitOrRollbackTransaction

func CommitOrRollbackTransaction(scope *Scope)

func Create

func Create(scope *Scope)

func Delete

func Delete(scope *Scope)

func Expr

func Expr(expression string, args ...interface{}) *expr

func ForceReloadAfterCreate

func ForceReloadAfterCreate(scope *Scope)

func Preload

func Preload(scope *Scope)

func Query

func Query(scope *Scope)

func SaveAfterAssociations

func SaveAfterAssociations(scope *Scope)

func SaveBeforeAssociations

func SaveBeforeAssociations(scope *Scope)

func ToDBName

func ToDBName(name string) string

func Update

func Update(scope *Scope)

func UpdateTimeStampWhenCreate

func UpdateTimeStampWhenCreate(scope *Scope)

func UpdateTimeStampWhenUpdate

func UpdateTimeStampWhenUpdate(scope *Scope)

Types

type Association

type Association struct {
	Scope  *Scope
	Column string
	Error  error
	Field  *Field
}

func (*Association) Append

func (association *Association) Append(values ...interface{}) *Association

func (*Association) Clear

func (association *Association) Clear() *Association

func (*Association) Count

func (association *Association) Count() int

func (*Association) Delete

func (association *Association) Delete(values ...interface{}) *Association

func (*Association) Find

func (association *Association) Find(value interface{}) *Association

func (*Association) Replace

func (association *Association) Replace(values ...interface{}) *Association

type DB

type DB struct {
	Value        interface{}
	Error        error
	RowsAffected int64
	// contains filtered or unexported fields
}

func Open

func Open(dialect string, args ...interface{}) (DB, error)

func (*DB) AddError

func (s *DB) AddError(err error) error

func (*DB) AddForeignKey

func (s *DB) AddForeignKey(field string, dest string, onDelete string, onUpdate string) *DB

Add foreign key to the given scope

Example:

db.Model(&User{}).AddForeignKey("city_id", "cities(id)", "RESTRICT", "RESTRICT")

func (*DB) AddIndex

func (s *DB) AddIndex(indexName string, column ...string) *DB

func (*DB) AddUniqueIndex

func (s *DB) AddUniqueIndex(indexName string, column ...string) *DB

func (*DB) Assign

func (s *DB) Assign(attrs ...interface{}) *DB

func (*DB) Association

func (s *DB) Association(column string) *Association

func (*DB) Attrs

func (s *DB) Attrs(attrs ...interface{}) *DB

func (*DB) AutoMigrate

func (s *DB) AutoMigrate(values ...interface{}) *DB

func (*DB) Begin

func (s *DB) Begin() *DB

func (*DB) Callback

func (s *DB) Callback() *callback

func (*DB) Close

func (s *DB) Close() error

func (*DB) Commit

func (s *DB) Commit() *DB

func (*DB) CommonDB

func (s *DB) CommonDB() sqlCommon

CommonDB Return the underlying sql.DB or sql.Tx instance. Use of this method is discouraged. It's mainly intended to allow coexistence with legacy non-GORM code.

func (*DB) Count

func (s *DB) Count(value interface{}) *DB

func (*DB) Create

func (s *DB) Create(value interface{}) *DB

func (*DB) CreateTable

func (s *DB) CreateTable(values ...interface{}) *DB

Migrations

func (*DB) CurrentDatabase

func (s *DB) CurrentDatabase() string

func (*DB) DB

func (s *DB) DB() *sql.DB

func (*DB) Debug

func (s *DB) Debug() *DB

func (*DB) Delete

func (s *DB) Delete(value interface{}, where ...interface{}) *DB

func (*DB) DropColumn

func (s *DB) DropColumn(column string) *DB

func (*DB) DropTable

func (s *DB) DropTable(values ...interface{}) *DB

func (*DB) DropTableIfExists

func (s *DB) DropTableIfExists(values ...interface{}) *DB

func (*DB) Exec

func (s *DB) Exec(sql string, values ...interface{}) *DB

func (*DB) Find

func (s *DB) Find(out interface{}, where ...interface{}) *DB

func (*DB) First

func (s *DB) First(out interface{}, where ...interface{}) *DB

func (*DB) FirstOrCreate

func (s *DB) FirstOrCreate(out interface{}, where ...interface{}) *DB

func (*DB) FirstOrInit

func (s *DB) FirstOrInit(out interface{}, where ...interface{}) *DB

func (*DB) Get

func (s *DB) Get(name string) (value interface{}, ok bool)

Get get value by name

func (*DB) GetErrors

func (s *DB) GetErrors() (errors []error)

func (*DB) Group

func (s *DB) Group(query string) *DB

func (*DB) HasTable

func (s *DB) HasTable(value interface{}) bool

func (*DB) Having

func (s *DB) Having(query string, values ...interface{}) *DB

func (*DB) InstantSet

func (s *DB) InstantSet(name string, value interface{}) *DB

func (*DB) Joins

func (s *DB) Joins(query string) *DB

func (*DB) Last

func (s *DB) Last(out interface{}, where ...interface{}) *DB

func (*DB) Limit

func (s *DB) Limit(value interface{}) *DB

func (*DB) LogMode

func (s *DB) LogMode(enable bool) *DB

func (*DB) Model

func (s *DB) Model(value interface{}) *DB

func (*DB) ModifyColumn

func (s *DB) ModifyColumn(column string, typ string) *DB

func (*DB) New

func (s *DB) New() *DB

func (*DB) NewRecord

func (s *DB) NewRecord(value interface{}) bool

func (*DB) NewScope

func (db *DB) NewScope(value interface{}) *Scope

NewScope create scope for callbacks, including DB's search information

func (*DB) Not

func (s *DB) Not(query interface{}, args ...interface{}) *DB

func (*DB) Offset

func (s *DB) Offset(value interface{}) *DB

func (*DB) Omit

func (s *DB) Omit(columns ...string) *DB

func (*DB) Or

func (s *DB) Or(query interface{}, args ...interface{}) *DB

func (*DB) Order

func (s *DB) Order(value string, reorder ...bool) *DB

func (*DB) Pluck

func (s *DB) Pluck(column string, value interface{}) *DB

func (*DB) Preload

func (s *DB) Preload(column string, conditions ...interface{}) *DB

func (*DB) Raw

func (s *DB) Raw(sql string, values ...interface{}) *DB

func (*DB) RecordNotFound

func (s *DB) RecordNotFound() bool

func (*DB) Related

func (s *DB) Related(value interface{}, foreignKeys ...string) *DB

func (*DB) RemoveIndex

func (s *DB) RemoveIndex(indexName string) *DB

func (*DB) Rollback

func (s *DB) Rollback() *DB

func (*DB) Row

func (s *DB) Row() *sql.Row

func (*DB) Rows

func (s *DB) Rows() (*sql.Rows, error)

func (*DB) Save

func (s *DB) Save(value interface{}) *DB

func (*DB) Scan

func (s *DB) Scan(dest interface{}) *DB

func (*DB) Scopes

func (s *DB) Scopes(funcs ...func(*DB) *DB) *DB

func (*DB) Select

func (s *DB) Select(query interface{}, args ...interface{}) *DB

func (*DB) Set

func (s *DB) Set(name string, value interface{}) *DB

Set set value by name

func (*DB) SetJoinTableHandler

func (s *DB) SetJoinTableHandler(source interface{}, column string, handler JoinTableHandlerInterface)

func (*DB) SetLogger

func (s *DB) SetLogger(l logger)

func (*DB) SingularTable

func (s *DB) SingularTable(enable bool)

func (*DB) Table

func (s *DB) Table(name string) *DB

func (*DB) Unscoped

func (s *DB) Unscoped() *DB

func (*DB) Update

func (s *DB) Update(attrs ...interface{}) *DB

func (*DB) UpdateColumn

func (s *DB) UpdateColumn(attrs ...interface{}) *DB

func (*DB) UpdateColumns

func (s *DB) UpdateColumns(values interface{}) *DB

func (*DB) Updates

func (s *DB) Updates(values interface{}, ignoreProtectedAttrs ...bool) *DB

func (*DB) Where

func (s *DB) Where(query interface{}, args ...interface{}) *DB

type Dialect

type Dialect interface {
	BinVar(i int) string
	SupportLastInsertId() bool
	HasTop() bool
	SqlTag(value reflect.Value, size int, autoIncrease bool) string
	ReturningStr(tableName, key string) string
	SelectFromDummyTable() string
	Quote(key string) string
	HasTable(scope *Scope, tableName string) bool
	HasColumn(scope *Scope, tableName string, columnName string) bool
	HasIndex(scope *Scope, tableName string, indexName string) bool
	RemoveIndex(scope *Scope, indexName string)
	CurrentDatabase(scope *Scope) string
}

func NewDialect

func NewDialect(driver string) Dialect

type Errors

type Errors struct {
	// contains filtered or unexported fields
}

func (*Errors) Add

func (errs *Errors) Add(err error)

func (Errors) Error

func (errs Errors) Error() string

func (Errors) GetErrors

func (errs Errors) GetErrors() []error

type Field

type Field struct {
	*StructField
	IsBlank bool
	Field   reflect.Value
}

func (*Field) Set

func (field *Field) Set(value interface{}) error

type Hstore

type Hstore map[string]*string

func (*Hstore) Scan

func (h *Hstore) Scan(value interface{}) error

func (Hstore) Value

func (h Hstore) Value() (driver.Value, error)

type JoinTableForeignKey

type JoinTableForeignKey struct {
	DBName            string
	AssociationDBName string
}

type JoinTableHandler

type JoinTableHandler struct {
	TableName   string          `sql:"-"`
	Source      JoinTableSource `sql:"-"`
	Destination JoinTableSource `sql:"-"`
}

func (JoinTableHandler) Add

func (s JoinTableHandler) Add(handler JoinTableHandlerInterface, db *DB, source1 interface{}, source2 interface{}) error

func (JoinTableHandler) Delete

func (s JoinTableHandler) Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error

func (*JoinTableHandler) DestinationForeignKeys

func (s *JoinTableHandler) DestinationForeignKeys() []JoinTableForeignKey

func (JoinTableHandler) GetSearchMap

func (s JoinTableHandler) GetSearchMap(db *DB, sources ...interface{}) map[string]interface{}

func (JoinTableHandler) JoinWith

func (s JoinTableHandler) JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB

func (*JoinTableHandler) Setup

func (s *JoinTableHandler) Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type)

func (*JoinTableHandler) SourceForeignKeys

func (s *JoinTableHandler) SourceForeignKeys() []JoinTableForeignKey

func (JoinTableHandler) Table

func (s JoinTableHandler) Table(db *DB) string

type JoinTableHandlerInterface

type JoinTableHandlerInterface interface {
	Setup(relationship *Relationship, tableName string, source reflect.Type, destination reflect.Type)
	Table(db *DB) string
	Add(handler JoinTableHandlerInterface, db *DB, source interface{}, destination interface{}) error
	Delete(handler JoinTableHandlerInterface, db *DB, sources ...interface{}) error
	JoinWith(handler JoinTableHandlerInterface, db *DB, source interface{}) *DB
	SourceForeignKeys() []JoinTableForeignKey
	DestinationForeignKeys() []JoinTableForeignKey
}

type JoinTableSource

type JoinTableSource struct {
	ModelType   reflect.Type
	ForeignKeys []JoinTableForeignKey
}

type LogWriter

type LogWriter interface {
	Println(v ...interface{})
}

type Logger

type Logger struct {
	LogWriter
}

func (Logger) Print

func (logger Logger) Print(values ...interface{})

type Model

type Model struct {
	ID        uint `gorm:"primary_key"`
	CreatedAt time.Time
	UpdatedAt time.Time
	DeletedAt *time.Time `sql:"index"`
}

type ModelStruct

type ModelStruct struct {
	PrimaryFields []*StructField
	StructFields  []*StructField
	ModelType     reflect.Type
	// contains filtered or unexported fields
}

func (ModelStruct) TableName

func (s ModelStruct) TableName(db *DB) string

type Relationship

type Relationship struct {
	Kind                               string
	PolymorphicType                    string
	PolymorphicDBName                  string
	ForeignFieldNames                  []string
	ForeignDBNames                     []string
	AssociationForeignFieldNames       []string
	AssociationForeignStructFieldNames []string
	AssociationForeignDBNames          []string
	JoinTableHandler                   JoinTableHandlerInterface
}

type Scope

type Scope struct {
	Search  *search
	Value   interface{}
	Sql     string
	SqlVars []interface{}
	// contains filtered or unexported fields
}

func (*Scope) AddToVars

func (scope *Scope) AddToVars(value interface{}) string

AddToVars add value as sql's vars, gorm will escape them

func (*Scope) Begin

func (scope *Scope) Begin() *Scope

Begin start a transaction

func (*Scope) CallMethod

func (scope *Scope) CallMethod(name string, checkError bool)

func (*Scope) CallMethodWithErrorCheck

func (scope *Scope) CallMethodWithErrorCheck(name string)

func (*Scope) CombinedConditionSql

func (scope *Scope) CombinedConditionSql() string

CombinedConditionSql get combined condition sql

func (*Scope) CommitOrRollback

func (scope *Scope) CommitOrRollback() *Scope

CommitOrRollback commit current transaction if there is no error, otherwise rollback it

func (*Scope) DB

func (scope *Scope) DB() *DB

func (*Scope) Dialect

func (scope *Scope) Dialect() Dialect

Dialect get dialect

func (*Scope) Err

func (scope *Scope) Err(err error) error

Err write error

func (*Scope) Exec

func (scope *Scope) Exec() *Scope

Exec invoke sql

func (*Scope) FieldByName

func (scope *Scope) FieldByName(name string) (field *Field, ok bool)

func (*Scope) Fields

func (scope *Scope) Fields() map[string]*Field

Fields get value's fields

func (*Scope) Get

func (scope *Scope) Get(name string) (interface{}, bool)

Get get value by name

func (*Scope) GetModelStruct

func (scope *Scope) GetModelStruct() *ModelStruct

func (*Scope) GetStructFields

func (scope *Scope) GetStructFields() (fields []*StructField)

func (*Scope) HasColumn

func (scope *Scope) HasColumn(column string) bool

HasColumn to check if has column

func (*Scope) HasError

func (scope *Scope) HasError() bool

HasError check if there are any error

func (*Scope) IndirectValue

func (scope *Scope) IndirectValue() reflect.Value

func (*Scope) InstanceGet

func (scope *Scope) InstanceGet(name string) (interface{}, bool)

func (*Scope) InstanceId

func (scope *Scope) InstanceId() string

InstanceId get InstanceId for scope

func (*Scope) InstanceSet

func (scope *Scope) InstanceSet(name string, value interface{}) *Scope

func (*Scope) Log

func (scope *Scope) Log(v ...interface{})

Log print log message

func (*Scope) NeedPtr

func (scope *Scope) NeedPtr() *Scope

func (*Scope) New

func (scope *Scope) New(value interface{}) *Scope

New create a new Scope without search information

func (*Scope) NewDB

func (scope *Scope) NewDB() *DB

NewDB create a new DB without search information

func (*Scope) OmitAttrs

func (scope *Scope) OmitAttrs() []string

func (*Scope) PrimaryField

func (scope *Scope) PrimaryField() *Field

func (*Scope) PrimaryFields

func (scope *Scope) PrimaryFields() []*Field

func (*Scope) PrimaryKey

func (scope *Scope) PrimaryKey() string

PrimaryKey get the primary key's column name

func (*Scope) PrimaryKeyValue

func (scope *Scope) PrimaryKeyValue() interface{}

PrimaryKeyValue get the primary key's value

func (*Scope) PrimaryKeyZero

func (scope *Scope) PrimaryKeyZero() bool

PrimaryKeyZero check the primary key is blank or not

func (*Scope) Quote

func (scope *Scope) Quote(str string) string

Quote used to quote database column name according to database dialect

func (*Scope) QuoteIfPossible

func (scope *Scope) QuoteIfPossible(str string) string

func (*Scope) QuotedTableName

func (scope *Scope) QuotedTableName() (name string)

func (*Scope) Raw

func (scope *Scope) Raw(sql string) *Scope

Raw set sql

func (*Scope) SelectAttrs

func (scope *Scope) SelectAttrs() []string

func (*Scope) Set

func (scope *Scope) Set(name string, value interface{}) *Scope

Set set value by name

func (*Scope) SetColumn

func (scope *Scope) SetColumn(column interface{}, value interface{}) error

SetColumn to set the column's value

func (*Scope) SkipLeft

func (scope *Scope) SkipLeft()

SkipLeft skip remaining callbacks

func (*Scope) SqlDB

func (scope *Scope) SqlDB() sqlCommon

SqlDB return *sql.DB

func (*Scope) TableName

func (scope *Scope) TableName() string

TableName get table name

func (*Scope) Trace

func (scope *Scope) Trace(t time.Time)

Trace print sql log

type StructField

type StructField struct {
	DBName          string
	Name            string
	Names           []string
	IsPrimaryKey    bool
	IsNormal        bool
	IsIgnored       bool
	IsScanner       bool
	HasDefaultValue bool
	Tag             reflect.StructTag
	Struct          reflect.StructField
	IsForeignKey    bool
	Relationship    *Relationship
}

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL