From 0451101006483eef7ee0faf77a40202e7368f570 Mon Sep 17 00:00:00 2001 From: Jinzhu Date: Sun, 21 Feb 2016 12:41:38 +0800 Subject: [PATCH] Init Gitbook --- .gitignore | 2 + README.md | 3 + SUMMARY.md | 1 + book.json | 3 + images/arrow-down.png | Bin 216 -> 0 bytes images/octocat-small.png | Bin 357 -> 0 bytes index.html | 1336 ---------------------------------- javascripts/scale.fix.js | 20 - params.json | 1 - stylesheets/github-light.css | 116 --- stylesheets/pygment_trac.css | 69 -- stylesheets/styles.css | 423 ----------- 12 files changed, 9 insertions(+), 1965 deletions(-) create mode 100644 .gitignore create mode 100644 README.md create mode 100644 SUMMARY.md create mode 100644 book.json delete mode 100644 images/arrow-down.png delete mode 100644 images/octocat-small.png delete mode 100644 index.html delete mode 100644 javascripts/scale.fix.js delete mode 100644 params.json delete mode 100644 stylesheets/github-light.css delete mode 100644 stylesheets/pygment_trac.css delete mode 100644 stylesheets/styles.css diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..017e4491 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +_book +node_modules diff --git a/README.md b/README.md new file mode 100644 index 00000000..4409686b --- /dev/null +++ b/README.md @@ -0,0 +1,3 @@ +# GORM + +This is GORM diff --git a/SUMMARY.md b/SUMMARY.md new file mode 100644 index 00000000..ac9323cb --- /dev/null +++ b/SUMMARY.md @@ -0,0 +1 @@ +# Summary diff --git a/book.json b/book.json new file mode 100644 index 00000000..700661e0 --- /dev/null +++ b/book.json @@ -0,0 +1,3 @@ +{ + "plugins": ["prism", "-highlight"] +} diff --git a/images/arrow-down.png b/images/arrow-down.png deleted file mode 100644 index 5c55c6a8c9edfaa47379862d770304c36c3ac7ff..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 216 zcmeAS@N?(olHy`uVBq!ia0vp^JU}eW!3HFke0{SLNX_?jaSYLzn4I9i%II*Xp^aIh zpz+6!8``B?P5)0c^x#?E7OdXC_y6D5zw1+Ygru)Ji1RWzykR(WyifLD&pJjGw#n?P zLqkH=Y}vm3H~*pZ^K<_6Lqu1mGH{74&_2}6eISp?=$Y`s3cD`%ef7U|_uU`DGt*!YlC@Am|DD>an&JK*_ z<>mi__UCKux;y>4Pqor7j|)IU*M9Gw z-IGbu2m_ZdUGO1GBT$h55cdP|c_4ld#Or}LA6*>)0_L))J+G2e00000NkvXXu0mjf DP-vTT diff --git a/index.html b/index.html deleted file mode 100644 index d0e110a1..00000000 --- a/index.html +++ /dev/null @@ -1,1336 +0,0 @@ - - - - - - Gorm by jinzhu - - - - - - - - -
-
-

Gorm

-

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

- - - -

This project is maintained by jinzhu

- - -
-
-

-GORM

- -

Join the chat at https://gitter.im/jinzhu/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.

-
- -
- - - - - - diff --git a/javascripts/scale.fix.js b/javascripts/scale.fix.js deleted file mode 100644 index 08716c00..00000000 --- a/javascripts/scale.fix.js +++ /dev/null @@ -1,20 +0,0 @@ -fixScale = function(doc) { - - var addEvent = 'addEventListener', - type = 'gesturestart', - qsa = 'querySelectorAll', - scales = [1, 1], - meta = qsa in doc ? doc[qsa]('meta[name=viewport]') : []; - - function fix() { - meta.content = 'width=device-width,minimum-scale=' + scales[0] + ',maximum-scale=' + scales[1]; - doc.removeEventListener(type, fix, true); - } - - if ((meta = meta[meta.length - 1]) && addEvent in doc) { - fix(); - scales = [.25, 1.6]; - doc[addEvent](type, fix, true); - } - -}; \ No newline at end of file diff --git a/params.json b/params.json deleted file mode 100644 index d4863d7a..00000000 --- a/params.json +++ /dev/null @@ -1 +0,0 @@ -{"name":"Gorm","tagline":"The fantastic ORM library for Golang, aims to be developer friendly.","body":"# GORM\r\n\r\n[![Join the chat at https://gitter.im/jinzhu/gorm](https://badges.gitter.im/Join%20Chat.svg)](https://gitter.im/jinzhu/gorm?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=badge)\r\n\r\nThe fantastic ORM library for Golang, aims to be developer friendly.\r\n\r\n[![wercker status](https://app.wercker.com/status/0cb7bb1039e21b74f8274941428e0921/s/master \"wercker status\")](https://app.wercker.com/project/bykey/0cb7bb1039e21b74f8274941428e0921)\r\n\r\n## Overview\r\n\r\n* Full-Featured ORM (almost)\r\n* Chainable API\r\n* Auto Migrations\r\n* Relations (Has One, Has Many, Belongs To, Many To Many, [Polymorphism](#polymorphism))\r\n* Callbacks (Before/After Create/Save/Update/Delete/Find)\r\n* Preloading (eager loading)\r\n* Transactions\r\n* Embed Anonymous Struct\r\n* Soft Deletes\r\n* Customizable Logger\r\n* Iteration Support via [Rows](#row--rows)\r\n* Every feature comes with tests\r\n* Developer Friendly\r\n\r\n# Getting Started\r\n\r\n## Install\r\n\r\n```\r\ngo get -u github.com/jinzhu/gorm\r\n```\r\n\r\n## Documentation \r\n\r\n[![GoDoc](https://godoc.org/github.com/jinzhu/gorm?status.svg)](https://godoc.org/github.com/jinzhu/gorm)\r\n\r\n`go doc` format documentation for this project can be viewed online without\r\ninstalling the package by using the GoDoc page at:\r\nhttp://godoc.org/github.com/jinzhu/gorm\r\n\r\n## Table of Contents\r\n\r\n- [Define Models (Structs)](#define-models-structs)\r\n- [Conventions](#conventions)\r\n- [Initialize Database](#initialize-database)\r\n- [Migration](#migration)\r\n- [Basic CRUD](#basic-crud)\r\n - [Create](#create-record)\r\n - [Query](#query)\r\n - [Query With Where (Plain SQL)](#query-with-where-plain-sql)\r\n - [Query With Where (Struct & Map)](#query-with-where-struct--map)\r\n - [Query With Not](#query-with-not)\r\n - [Query With Inline Condition](#query-with-inline-condition)\r\n - [Query With Or](#query-with-or)\r\n - [Query Chains](#query-chains)\r\n - [Preloading (Eager loading)](#preloading-eager-loading)\r\n - [Update](#update)\r\n - [Update Without Callbacks](#update-without-callbacks)\r\n - [Batch Updates](#batch-updates)\r\n - [Update with SQL Expression](#update-with-sql-expression)\r\n - [Delete](#delete)\r\n - [Batch Delete](#batch-delete)\r\n - [Soft Delete](#soft-delete)\r\n- [Associations](#associations)\r\n - [Has One](#has-one)\r\n - [Belongs To](#belongs-to)\r\n - [Has Many](#has-many)\r\n - [Many To Many](#many-to-many)\r\n - [Polymorphism](#polymorphism)\r\n- [Advanced Usage](#advanced-usage)\r\n\t- [FirstOrInit](#firstorinit)\r\n\t- [FirstOrCreate](#firstorcreate)\r\n\t- [Select](#select)\r\n\t- [Order](#order)\r\n\t- [Limit](#limit)\r\n\t- [Offset](#offset)\r\n\t- [Count](#count)\r\n\t- [Pluck](#pluck)\r\n\t- [Raw SQL](#raw-sql)\r\n\t- [Row & Rows](#row--rows)\r\n\t- [Scan](#scan)\r\n\t- [Group & Having](#group--having)\r\n\t- [Joins](#joins)\r\n\t- [Transactions](#transactions)\r\n\t- [Scopes](#scopes)\r\n\t- [Callbacks](#callbacks)\r\n\t- [Specifying The Table Name](#specifying-the-table-name)\r\n\t- [Error Handling](#error-handling)\r\n\t- [Logger](#logger)\r\n\t- [Existing Schema](#existing-schema)\r\n\t- [Composite Primary Key](#composite-primary-key)\r\n\t- [Database Indexes & Foreign Key](#database-indexes--foreign-key)\r\n\t- [Default values](#default-values)\r\n\t- [More examples with query chain](#more-examples-with-query-chain)\r\n\r\n## Define Models (Structs)\r\n\r\n```go\r\ntype User struct {\r\n\tID int\r\n\tBirthday time.Time\r\n\tAge int\r\n\tName string `sql:\"size:255\"` // Default size for string is 255, you could reset it with this tag\r\n\tNum int `sql:\"AUTO_INCREMENT\"`\r\n\tCreatedAt time.Time\r\n\tUpdatedAt time.Time\r\n\tDeletedAt *time.Time\r\n\r\n\tEmails []Email // One-To-Many relationship (has many)\r\n\tBillingAddress Address // One-To-One relationship (has one)\r\n\tBillingAddressID sql.NullInt64 // Foreign key of BillingAddress\r\n\tShippingAddress Address // One-To-One relationship (has one)\r\n\tShippingAddressID int // Foreign key of ShippingAddress\r\n\tIgnoreMe int `sql:\"-\"` // Ignore this field\r\n\tLanguages []Language `gorm:\"many2many:user_languages;\"` // Many-To-Many relationship, 'user_languages' is join table\r\n}\r\n\r\ntype Email struct {\r\n\tID int\r\n\tUserID int `sql:\"index\"` // Foreign key (belongs to), tag `index` will create index for this field when using AutoMigrate\r\n\tEmail string `sql:\"type:varchar(100);unique_index\"` // Set field's sql type, tag `unique_index` will create unique index\r\n\tSubscribed bool\r\n}\r\n\r\ntype Address struct {\r\n\tID int\r\n\tAddress1 string `sql:\"not null;unique\"` // Set field as not nullable and unique\r\n\tAddress2 string `sql:\"type:varchar(100);unique\"`\r\n\tPost sql.NullString `sql:\"not null\"`\r\n}\r\n\r\ntype Language struct {\r\n\tID int\r\n\tName string `sql:\"index:idx_name_code\"` // Create index with name, and will create combined index if find other fields defined same name\r\n\tCode string `sql:\"index:idx_name_code\"` // `unique_index` also works\r\n}\r\n```\r\n\r\n## Conventions\r\n\r\n* Table name is the plural of struct name's snake case, you can disable pluralization with `db.SingularTable(true)`, or [Specifying The Table Name For A Struct Permanently With TableName](#specifying-the-table-name-for-a-struct-permanently-with-tablename)\r\n\r\n```go\r\ntype User struct{} // struct User's database table name is \"users\" by default, will be \"user\" if you disabled pluralisation\r\n```\r\n\r\n* Column name is the snake case of field's name\r\n* Use `ID` field as primary key\r\n* Use `CreatedAt` to store record's created time if field exists\r\n* Use `UpdatedAt` to store record's updated time if field exists\r\n* Use `DeletedAt` to store record's deleted time if field exists [Soft Delete](#soft-delete)\r\n* Gorm provide a default model struct, you could embed it in your struct\r\n\r\n```go\r\ntype Model struct {\r\n\tID uint `gorm:\"primary_key\"`\r\n\tCreatedAt time.Time\r\n\tUpdatedAt time.Time\r\n\tDeletedAt *time.Time\r\n}\r\n\r\ntype User struct {\r\n\tgorm.Model\r\n\tName string\r\n}\r\n```\r\n\r\n## Initialize Database\r\n\r\n```go\r\nimport (\r\n\t\"github.com/jinzhu/gorm\"\r\n\t_ \"github.com/lib/pq\"\r\n\t_ \"github.com/go-sql-driver/mysql\"\r\n\t_ \"github.com/mattn/go-sqlite3\"\r\n)\r\n\r\ndb, err := gorm.Open(\"postgres\", \"user=gorm dbname=gorm sslmode=disable\")\r\n// db, err := gorm.Open(\"foundation\", \"dbname=gorm\") // FoundationDB.\r\n// db, err := gorm.Open(\"mysql\", \"user:password@/dbname?charset=utf8&parseTime=True&loc=Local\")\r\n// db, err := gorm.Open(\"sqlite3\", \"/tmp/gorm.db\")\r\n\r\n// You can also use an existing database connection handle\r\n// dbSql, _ := sql.Open(\"postgres\", \"user=gorm dbname=gorm sslmode=disable\")\r\n// db, _ := gorm.Open(\"postgres\", dbSql)\r\n\r\n// Get database connection handle [*sql.DB](http://golang.org/pkg/database/sql/#DB)\r\ndb.DB()\r\n\r\n// Then you could invoke `*sql.DB`'s functions with it\r\ndb.DB().Ping()\r\ndb.DB().SetMaxIdleConns(10)\r\ndb.DB().SetMaxOpenConns(100)\r\n\r\n// Disable table name's pluralization\r\ndb.SingularTable(true)\r\n```\r\n\r\n## Migration\r\n\r\n```go\r\n// Create table\r\ndb.CreateTable(&User{})\r\ndb.Set(\"gorm:table_options\", \"ENGINE=InnoDB\").CreateTable(&User{})\r\n\r\n// Drop table\r\ndb.DropTable(&User{})\r\n\r\n// ModifyColumn\r\ndb.Model(&User{}).ModifyColumn(\"description\", \"text\")\r\n\r\n// DropColumn\r\ndb.Model(&User{}).DropColumn(\"description\")\r\n\r\n// Automating Migration\r\ndb.AutoMigrate(&User{})\r\ndb.Set(\"gorm:table_options\", \"ENGINE=InnoDB\").AutoMigrate(&User{})\r\ndb.AutoMigrate(&User{}, &Product{}, &Order{})\r\n// Feel free to change your struct, AutoMigrate will keep your database up-to-date.\r\n// AutoMigrate will ONLY add *new columns* and *new indexes*,\r\n// WON'T update current column's type or delete unused columns, to protect your data.\r\n// If the table is not existing, AutoMigrate will create the table automatically.\r\n```\r\n\r\n# Basic CRUD\r\n\r\n## Create Record\r\n\r\n```go\r\nuser := User{Name: \"Jinzhu\", Age: 18, Birthday: time.Now()}\r\n\r\ndb.NewRecord(user) // => returns `true` if primary key is blank\r\n\r\ndb.Create(&user)\r\n\r\ndb.NewRecord(user) // => return `false` after `user` created\r\n\r\n// Associations will be inserted automatically when save the record\r\nuser := User{\r\n\tName: \"jinzhu\",\r\n\tBillingAddress: Address{Address1: \"Billing Address - Address 1\"},\r\n\tShippingAddress: Address{Address1: \"Shipping Address - Address 1\"},\r\n\tEmails: []Email{{Email: \"jinzhu@example.com\"}, {Email: \"jinzhu-2@example@example.com\"}},\r\n\tLanguages: []Language{{Name: \"ZH\"}, {Name: \"EN\"}},\r\n}\r\n\r\ndb.Create(&user)\r\n//// BEGIN TRANSACTION;\r\n//// INSERT INTO \"addresses\" (address1) VALUES (\"Billing Address - Address 1\");\r\n//// INSERT INTO \"addresses\" (address1) VALUES (\"Shipping Address - Address 1\");\r\n//// INSERT INTO \"users\" (name,billing_address_id,shipping_address_id) VALUES (\"jinzhu\", 1, 2);\r\n//// INSERT INTO \"emails\" (user_id,email) VALUES (111, \"jinzhu@example.com\");\r\n//// INSERT INTO \"emails\" (user_id,email) VALUES (111, \"jinzhu-2@example.com\");\r\n//// INSERT INTO \"languages\" (\"name\") VALUES ('ZH');\r\n//// INSERT INTO user_languages (\"user_id\",\"language_id\") VALUES (111, 1);\r\n//// INSERT INTO \"languages\" (\"name\") VALUES ('EN');\r\n//// INSERT INTO user_languages (\"user_id\",\"language_id\") VALUES (111, 2);\r\n//// COMMIT;\r\n```\r\n\r\nRefer [Associations](#associations) for more details\r\n\r\n## Query\r\n\r\n```go\r\n// Get the first record\r\ndb.First(&user)\r\n//// SELECT * FROM users ORDER BY id LIMIT 1;\r\n\r\n// Get the last record\r\ndb.Last(&user)\r\n//// SELECT * FROM users ORDER BY id DESC LIMIT 1;\r\n\r\n// Get all records\r\ndb.Find(&users)\r\n//// SELECT * FROM users;\r\n\r\n// Get record with primary key\r\ndb.First(&user, 10)\r\n//// SELECT * FROM users WHERE id = 10;\r\n```\r\n\r\n### Query With Where (Plain SQL)\r\n\r\n```go\r\n// Get the first matched record\r\ndb.Where(\"name = ?\", \"jinzhu\").First(&user)\r\n//// SELECT * FROM users WHERE name = 'jinzhu' limit 1;\r\n\r\n// Get all matched records\r\ndb.Where(\"name = ?\", \"jinzhu\").Find(&users)\r\n//// SELECT * FROM users WHERE name = 'jinzhu';\r\n\r\ndb.Where(\"name <> ?\", \"jinzhu\").Find(&users)\r\n\r\n// IN\r\ndb.Where(\"name in (?)\", []string{\"jinzhu\", \"jinzhu 2\"}).Find(&users)\r\n\r\n// LIKE\r\ndb.Where(\"name LIKE ?\", \"%jin%\").Find(&users)\r\n\r\n// AND\r\ndb.Where(\"name = ? and age >= ?\", \"jinzhu\", \"22\").Find(&users)\r\n\r\n// Time\r\ndb.Where(\"updated_at > ?\", lastWeek).Find(&users)\r\n\r\ndb.Where(\"created_at BETWEEN ? AND ?\", lastWeek, today).Find(&users)\r\n```\r\n\r\n### Query With Where (Struct & Map)\r\n\r\n```go\r\n// Struct\r\ndb.Where(&User{Name: \"jinzhu\", Age: 20}).First(&user)\r\n//// SELECT * FROM users WHERE name = \"jinzhu\" AND age = 20 LIMIT 1;\r\n\r\n// Map\r\ndb.Where(map[string]interface{}{\"name\": \"jinzhu\", \"age\": 20}).Find(&users)\r\n//// SELECT * FROM users WHERE name = \"jinzhu\" AND age = 20;\r\n\r\n// Slice of primary keys\r\ndb.Where([]int64{20, 21, 22}).Find(&users)\r\n//// SELECT * FROM users WHERE id IN (20, 21, 22);\r\n```\r\n\r\n### Query With Not\r\n\r\n```go\r\ndb.Not(\"name\", \"jinzhu\").First(&user)\r\n//// SELECT * FROM users WHERE name <> \"jinzhu\" LIMIT 1;\r\n\r\n// Not In\r\ndb.Not(\"name\", []string{\"jinzhu\", \"jinzhu 2\"}).Find(&users)\r\n//// SELECT * FROM users WHERE name NOT IN (\"jinzhu\", \"jinzhu 2\");\r\n\r\n// Not In slice of primary keys\r\ndb.Not([]int64{1,2,3}).First(&user)\r\n//// SELECT * FROM users WHERE id NOT IN (1,2,3);\r\n\r\ndb.Not([]int64{}).First(&user)\r\n//// SELECT * FROM users;\r\n\r\n// Plain SQL\r\ndb.Not(\"name = ?\", \"jinzhu\").First(&user)\r\n//// SELECT * FROM users WHERE NOT(name = \"jinzhu\");\r\n\r\n// Struct\r\ndb.Not(User{Name: \"jinzhu\"}).First(&user)\r\n//// SELECT * FROM users WHERE name <> \"jinzhu\";\r\n```\r\n\r\n### Query With Inline Condition\r\n\r\n```go\r\n// Get by primary key\r\ndb.First(&user, 23)\r\n//// SELECT * FROM users WHERE id = 23 LIMIT 1;\r\n\r\n// Plain SQL\r\ndb.Find(&user, \"name = ?\", \"jinzhu\")\r\n//// SELECT * FROM users WHERE name = \"jinzhu\";\r\n\r\ndb.Find(&users, \"name <> ? AND age > ?\", \"jinzhu\", 20)\r\n//// SELECT * FROM users WHERE name <> \"jinzhu\" AND age > 20;\r\n\r\n// Struct\r\ndb.Find(&users, User{Age: 20})\r\n//// SELECT * FROM users WHERE age = 20;\r\n\r\n// Map\r\ndb.Find(&users, map[string]interface{}{\"age\": 20})\r\n//// SELECT * FROM users WHERE age = 20;\r\n```\r\n\r\n### Query With Or\r\n\r\n```go\r\ndb.Where(\"role = ?\", \"admin\").Or(\"role = ?\", \"super_admin\").Find(&users)\r\n//// SELECT * FROM users WHERE role = 'admin' OR role = 'super_admin';\r\n\r\n// Struct\r\ndb.Where(\"name = 'jinzhu'\").Or(User{Name: \"jinzhu 2\"}).Find(&users)\r\n//// SELECT * FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2';\r\n\r\n// Map\r\ndb.Where(\"name = 'jinzhu'\").Or(map[string]interface{}{\"name\": \"jinzhu 2\"}).Find(&users)\r\n```\r\n\r\n### Query Chains\r\n\r\nGorm has a chainable API, you could use it like this\r\n\r\n```go\r\ndb.Where(\"name <> ?\",\"jinzhu\").Where(\"age >= ? and role <> ?\",20,\"admin\").Find(&users)\r\n//// SELECT * FROM users WHERE name <> 'jinzhu' AND age >= 20 AND role <> 'admin';\r\n\r\ndb.Where(\"role = ?\", \"admin\").Or(\"role = ?\", \"super_admin\").Not(\"name = ?\", \"jinzhu\").Find(&users)\r\n```\r\n\r\n### Preloading (Eager loading)\r\n\r\n```go\r\ndb.Preload(\"Orders\").Find(&users)\r\n//// SELECT * FROM users;\r\n//// SELECT * FROM orders WHERE user_id IN (1,2,3,4);\r\n\r\ndb.Preload(\"Orders\", \"state NOT IN (?)\", \"cancelled\").Find(&users)\r\n//// SELECT * FROM users;\r\n//// SELECT * FROM orders WHERE user_id IN (1,2,3,4) AND state NOT IN ('cancelled');\r\n\r\ndb.Where(\"state = ?\", \"active\").Preload(\"Orders\", \"state NOT IN (?)\", \"cancelled\").Find(&users)\r\n//// SELECT * FROM users WHERE state = 'active';\r\n//// SELECT * FROM orders WHERE user_id IN (1,2) AND state NOT IN ('cancelled');\r\n\r\ndb.Preload(\"Orders\").Preload(\"Profile\").Preload(\"Role\").Find(&users)\r\n//// SELECT * FROM users;\r\n//// SELECT * FROM orders WHERE user_id IN (1,2,3,4); // has many\r\n//// SELECT * FROM profiles WHERE user_id IN (1,2,3,4); // has one\r\n//// SELECT * FROM roles WHERE id IN (4,5,6); // belongs to\r\n```\r\n\r\n#### Nested Preloading\r\n\r\n```go\r\ndb.Preload(\"Orders.OrderItems\").Find(&users)\r\ndb.Preload(\"Orders\", \"state = ?\", \"paid\").Preload(\"Orders.OrderItems\").Find(&users)\r\n```\r\n\r\n## Update\r\n\r\n```go\r\n// Update an existing struct\r\ndb.First(&user)\r\nuser.Name = \"jinzhu 2\"\r\nuser.Age = 100\r\ndb.Save(&user)\r\n//// UPDATE users SET name='jinzhu 2', age=100, updated_at = '2013-11-17 21:34:10' WHERE id=111;\r\n\r\ndb.Where(\"active = ?\", true).Save(&user)\r\n//// UPDATE users SET name='jinzhu 2', age=100, updated_at = '2013-11-17 21:34:10' WHERE id=111 AND active = true;\r\n\r\n// Update an attribute if it is changed\r\ndb.Model(&user).Update(\"name\", \"hello\")\r\n//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111;\r\n\r\ndb.Model(&user).Where(\"active = ?\", true).Update(\"name\", \"hello\")\r\n//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111 AND active = true;\r\n\r\ndb.First(&user, 111).Update(\"name\", \"hello\")\r\n//// SELECT * FROM users LIMIT 1;\r\n//// UPDATE users SET name='hello', updated_at = '2013-11-17 21:34:10' WHERE id=111;\r\n\r\n// Update multiple attributes if they are changed\r\ndb.Model(&user).Updates(map[string]interface{}{\"name\": \"hello\", \"age\": 18, \"actived\": false})\r\n\r\n// Update multiple attributes if they are changed (update with struct only works with none zero values)\r\ndb.Model(&user).Updates(User{Name: \"hello\", Age: 18})\r\n//// UPDATE users SET name='hello', age=18, updated_at = '2013-11-17 21:34:10' WHERE id = 111;\r\n```\r\n\r\n### Update Without Callbacks\r\n\r\nBy default, update will call BeforeUpdate, AfterUpdate callbacks, if you want to update w/o callbacks and w/o saving associations:\r\n\r\n```go\r\ndb.Model(&user).UpdateColumn(\"name\", \"hello\")\r\n//// UPDATE users SET name='hello' WHERE id = 111;\r\n\r\n// Update with struct only works with none zero values, or use map[string]interface{}\r\ndb.Model(&user).UpdateColumns(User{Name: \"hello\", Age: 18})\r\n//// UPDATE users SET name='hello', age=18 WHERE id = 111;\r\n```\r\n\r\n### Batch Updates\r\n\r\n```go\r\ndb.Table(\"users\").Where(\"id = ?\", 10).Updates(map[string]interface{}{\"name\": \"hello\", \"age\": 18})\r\n//// UPDATE users SET name='hello', age=18 WHERE id = 10;\r\n\r\n// Update with struct only works with none zero values, or use map[string]interface{}\r\ndb.Model(User{}).Updates(User{Name: \"hello\", Age: 18})\r\n//// UPDATE users SET name='hello', age=18;\r\n\r\n// Callbacks won't run when do batch updates\r\n\r\n// Use `RowsAffected` to get the count of affected records\r\ndb.Model(User{}).Updates(User{Name: \"hello\", Age: 18}).RowsAffected\r\n```\r\n\r\n### Update with SQL Expression\r\n\r\n```go\r\nDB.Model(&product).Update(\"price\", gorm.Expr(\"price * ? + ?\", 2, 100))\r\n//// UPDATE \"products\" SET \"code\" = 'L1212', \"price\" = price * '2' + '100', \"updated_at\" = '2013-11-17 21:34:10' WHERE \"id\" = '2';\r\n\r\nDB.Model(&product).Updates(map[string]interface{}{\"price\": gorm.Expr(\"price * ? + ?\", 2, 100)})\r\n//// UPDATE \"products\" SET \"code\" = 'L1212', \"price\" = price * '2' + '100', \"updated_at\" = '2013-11-17 21:34:10' WHERE \"id\" = '2';\r\n\r\nDB.Model(&product).UpdateColumn(\"quantity\", gorm.Expr(\"quantity - ?\", 1))\r\n//// UPDATE \"products\" SET \"quantity\" = quantity - 1 WHERE \"id\" = '2';\r\n\r\nDB.Model(&product).Where(\"quantity > 1\").UpdateColumn(\"quantity\", gorm.Expr(\"quantity - ?\", 1))\r\n//// UPDATE \"products\" SET \"quantity\" = quantity - 1 WHERE \"id\" = '2' AND quantity > 1;\r\n```\r\n\r\n## Delete\r\n\r\n```go\r\n// Delete an existing record\r\ndb.Delete(&email)\r\n//// DELETE from emails where id=10;\r\n```\r\n\r\n### Batch Delete\r\n\r\n```go\r\ndb.Where(\"email LIKE ?\", \"%jinzhu%\").Delete(Email{})\r\n//// DELETE from emails where email LIKE \"%jinhu%\";\r\n```\r\n\r\n### Soft Delete\r\n\r\nIf struct has `DeletedAt` field, it will get soft delete ability automatically!\r\nThen it won't be deleted from database permanently when call `Delete`.\r\n\r\n```go\r\ndb.Delete(&user)\r\n//// UPDATE users SET deleted_at=\"2013-10-29 10:23\" WHERE id = 111;\r\n\r\n// Batch Delete\r\ndb.Where(\"age = ?\", 20).Delete(&User{})\r\n//// UPDATE users SET deleted_at=\"2013-10-29 10:23\" WHERE age = 20;\r\n\r\n// Soft deleted records will be ignored when query them\r\ndb.Where(\"age = 20\").Find(&user)\r\n//// SELECT * FROM users WHERE age = 20 AND (deleted_at IS NULL OR deleted_at <= '0001-01-02');\r\n\r\n// Find soft deleted records with Unscoped\r\ndb.Unscoped().Where(\"age = 20\").Find(&users)\r\n//// SELECT * FROM users WHERE age = 20;\r\n\r\n// Delete record permanently with Unscoped\r\ndb.Unscoped().Delete(&order)\r\n//// DELETE FROM orders WHERE id=10;\r\n```\r\n\r\n## Associations\r\n\r\n### Has One\r\n\r\n```go\r\n// User has one address\r\ndb.Model(&user).Related(&address)\r\n//// SELECT * FROM addresses WHERE id = 123; // 123 is user's foreign key AddressId\r\n\r\n// Specify the foreign key\r\ndb.Model(&user).Related(&address1, \"BillingAddressId\")\r\n//// SELECT * FROM addresses WHERE id = 123; // 123 is user's foreign key BillingAddressId\r\n```\r\n\r\n### Belongs To\r\n\r\n```go\r\n// Email belongs to user\r\ndb.Model(&email).Related(&user)\r\n//// SELECT * FROM users WHERE id = 111; // 111 is email's foreign key UserId\r\n\r\n// Specify the foreign key\r\ndb.Model(&email).Related(&user, \"ProfileId\")\r\n//// SELECT * FROM users WHERE id = 111; // 111 is email's foreign key ProfileId\r\n```\r\n\r\n### Has Many\r\n\r\n```go\r\n// User has many emails\r\ndb.Model(&user).Related(&emails)\r\n//// SELECT * FROM emails WHERE user_id = 111;\r\n// user_id is the foreign key, 111 is user's primary key's value\r\n\r\n// Specify the foreign key\r\ndb.Model(&user).Related(&emails, \"ProfileId\")\r\n//// SELECT * FROM emails WHERE profile_id = 111;\r\n// profile_id is the foreign key, 111 is user's primary key's value\r\n```\r\n\r\n### Many To Many\r\n\r\n```go\r\n// User has many languages and belongs to many languages\r\ndb.Model(&user).Related(&languages, \"Languages\")\r\n//// SELECT * FROM \"languages\" INNER JOIN \"user_languages\" ON \"user_languages\".\"language_id\" = \"languages\".\"id\" WHERE \"user_languages\".\"user_id\" = 111\r\n// `Languages` is user's column name, this column's tag defined join table like this `gorm:\"many2many:user_languages;\"`\r\n```\r\n\r\nThere is also a mode used to handle many to many relations easily\r\n\r\n```go\r\n// Query\r\ndb.Model(&user).Association(\"Languages\").Find(&languages)\r\n// same as `db.Model(&user).Related(&languages, \"Languages\")`\r\n\r\ndb.Where(\"name = ?\", \"ZH\").First(&languageZH)\r\ndb.Where(\"name = ?\", \"EN\").First(&languageEN)\r\n\r\n// Append\r\ndb.Model(&user).Association(\"Languages\").Append([]Language{languageZH, languageEN})\r\ndb.Model(&user).Association(\"Languages\").Append([]Language{{Name: \"DE\"}})\r\ndb.Model(&user).Association(\"Languages\").Append(Language{Name: \"DE\"})\r\n\r\n// Delete\r\ndb.Model(&user).Association(\"Languages\").Delete([]Language{languageZH, languageEN})\r\ndb.Model(&user).Association(\"Languages\").Delete(languageZH, languageEN)\r\n\r\n// Replace\r\ndb.Model(&user).Association(\"Languages\").Replace([]Language{languageZH, languageEN})\r\ndb.Model(&user).Association(\"Languages\").Replace(Language{Name: \"DE\"}, languageEN)\r\n\r\n// Count\r\ndb.Model(&user).Association(\"Languages\").Count()\r\n// Return the count of languages the user has\r\n\r\n// Clear\r\ndb.Model(&user).Association(\"Languages\").Clear()\r\n// Remove all relations between the user and languages\r\n```\r\n\r\n### Polymorphism\r\n\r\nSupports polymorphic has-many and has-one associations.\r\n\r\n```go\r\n type Cat struct {\r\n Id int\r\n Name string\r\n Toy Toy `gorm:\"polymorphic:Owner;\"`\r\n }\r\n\r\n type Dog struct {\r\n Id int\r\n Name string\r\n Toy Toy `gorm:\"polymorphic:Owner;\"`\r\n }\r\n\r\n type Toy struct {\r\n Id int\r\n Name string\r\n OwnerId int\r\n OwnerType string\r\n }\r\n```\r\nNote: polymorphic belongs-to and many-to-many are explicitly NOT supported, and will throw errors.\r\n\r\n## Advanced Usage\r\n\r\n## FirstOrInit\r\n\r\nGet the first matched record, or initialize a record with search conditions.\r\n\r\n```go\r\n// Unfound\r\ndb.FirstOrInit(&user, User{Name: \"non_existing\"})\r\n//// user -> User{Name: \"non_existing\"}\r\n\r\n// Found\r\ndb.Where(User{Name: \"Jinzhu\"}).FirstOrInit(&user)\r\n//// user -> User{Id: 111, Name: \"Jinzhu\", Age: 20}\r\ndb.FirstOrInit(&user, map[string]interface{}{\"name\": \"jinzhu\"})\r\n//// user -> User{Id: 111, Name: \"Jinzhu\", Age: 20}\r\n```\r\n\r\n### Attrs\r\n\r\nIgnore some values when searching, but use them to initialize the struct if record is not found.\r\n\r\n```go\r\n// Unfound\r\ndb.Where(User{Name: \"non_existing\"}).Attrs(User{Age: 20}).FirstOrInit(&user)\r\n//// SELECT * FROM USERS WHERE name = 'non_existing';\r\n//// user -> User{Name: \"non_existing\", Age: 20}\r\n\r\ndb.Where(User{Name: \"noexisting_user\"}).Attrs(\"age\", 20).FirstOrInit(&user)\r\n//// SELECT * FROM USERS WHERE name = 'non_existing';\r\n//// user -> User{Name: \"non_existing\", Age: 20}\r\n\r\n// Found\r\ndb.Where(User{Name: \"Jinzhu\"}).Attrs(User{Age: 30}).FirstOrInit(&user)\r\n//// SELECT * FROM USERS WHERE name = jinzhu';\r\n//// user -> User{Id: 111, Name: \"Jinzhu\", Age: 20}\r\n```\r\n\r\n### Assign\r\n\r\nIgnore some values when searching, but assign it to the result regardless it is found or not.\r\n\r\n```go\r\n// Unfound\r\ndb.Where(User{Name: \"non_existing\"}).Assign(User{Age: 20}).FirstOrInit(&user)\r\n//// user -> User{Name: \"non_existing\", Age: 20}\r\n\r\n// Found\r\ndb.Where(User{Name: \"Jinzhu\"}).Assign(User{Age: 30}).FirstOrInit(&user)\r\n//// SELECT * FROM USERS WHERE name = jinzhu';\r\n//// user -> User{Id: 111, Name: \"Jinzhu\", Age: 30}\r\n```\r\n\r\n## FirstOrCreate\r\n\r\nGet the first matched record, or create with search conditions.\r\n\r\n```go\r\n// Unfound\r\ndb.FirstOrCreate(&user, User{Name: \"non_existing\"})\r\n//// INSERT INTO \"users\" (name) VALUES (\"non_existing\");\r\n//// user -> User{Id: 112, Name: \"non_existing\"}\r\n\r\n// Found\r\ndb.Where(User{Name: \"Jinzhu\"}).FirstOrCreate(&user)\r\n//// user -> User{Id: 111, Name: \"Jinzhu\"}\r\n```\r\n\r\n### Attrs\r\n\r\nIgnore some values when searching, but use them to create the struct if record is not found. like `FirstOrInit`\r\n\r\n```go\r\n// Unfound\r\ndb.Where(User{Name: \"non_existing\"}).Attrs(User{Age: 20}).FirstOrCreate(&user)\r\n//// SELECT * FROM users WHERE name = 'non_existing';\r\n//// INSERT INTO \"users\" (name, age) VALUES (\"non_existing\", 20);\r\n//// user -> User{Id: 112, Name: \"non_existing\", Age: 20}\r\n\r\n// Found\r\ndb.Where(User{Name: \"jinzhu\"}).Attrs(User{Age: 30}).FirstOrCreate(&user)\r\n//// SELECT * FROM users WHERE name = 'jinzhu';\r\n//// user -> User{Id: 111, Name: \"jinzhu\", Age: 20}\r\n```\r\n\r\n### Assign\r\n\r\nIgnore some values when searching, but assign it to the record regardless it is found or not, then save back to database. like `FirstOrInit`\r\n\r\n```go\r\n// Unfound\r\ndb.Where(User{Name: \"non_existing\"}).Assign(User{Age: 20}).FirstOrCreate(&user)\r\n//// SELECT * FROM users WHERE name = 'non_existing';\r\n//// INSERT INTO \"users\" (name, age) VALUES (\"non_existing\", 20);\r\n//// user -> User{Id: 112, Name: \"non_existing\", Age: 20}\r\n\r\n// Found\r\ndb.Where(User{Name: \"jinzhu\"}).Assign(User{Age: 30}).FirstOrCreate(&user)\r\n//// SELECT * FROM users WHERE name = 'jinzhu';\r\n//// UPDATE users SET age=30 WHERE id = 111;\r\n//// user -> User{Id: 111, Name: \"jinzhu\", Age: 30}\r\n```\r\n\r\n## Select\r\n\r\n```go\r\ndb.Select(\"name, age\").Find(&users)\r\n//// SELECT name, age FROM users;\r\n\r\ndb.Select([]string{\"name\", \"age\"}).Find(&users)\r\n//// SELECT name, age FROM users;\r\n\r\ndb.Table(\"users\").Select(\"COALESCE(age,?)\", 42).Rows()\r\n//// SELECT COALESCE(age,'42') FROM users;\r\n```\r\n\r\n## Order\r\n\r\n```go\r\ndb.Order(\"age desc, name\").Find(&users)\r\n//// SELECT * FROM users ORDER BY age desc, name;\r\n\r\n// Multiple orders\r\ndb.Order(\"age desc\").Order(\"name\").Find(&users)\r\n//// SELECT * FROM users ORDER BY age desc, name;\r\n\r\n// ReOrder\r\ndb.Order(\"age desc\").Find(&users1).Order(\"age\", true).Find(&users2)\r\n//// SELECT * FROM users ORDER BY age desc; (users1)\r\n//// SELECT * FROM users ORDER BY age; (users2)\r\n```\r\n\r\n## Limit\r\n\r\n```go\r\ndb.Limit(3).Find(&users)\r\n//// SELECT * FROM users LIMIT 3;\r\n\r\n// Cancel limit condition with -1\r\ndb.Limit(10).Find(&users1).Limit(-1).Find(&users2)\r\n//// SELECT * FROM users LIMIT 10; (users1)\r\n//// SELECT * FROM users; (users2)\r\n```\r\n\r\n## Offset\r\n\r\n```go\r\ndb.Offset(3).Find(&users)\r\n//// SELECT * FROM users OFFSET 3;\r\n\r\n// Cancel offset condition with -1\r\ndb.Offset(10).Find(&users1).Offset(-1).Find(&users2)\r\n//// SELECT * FROM users OFFSET 10; (users1)\r\n//// SELECT * FROM users; (users2)\r\n```\r\n\r\n## Count\r\n\r\n```go\r\ndb.Where(\"name = ?\", \"jinzhu\").Or(\"name = ?\", \"jinzhu 2\").Find(&users).Count(&count)\r\n//// SELECT * from USERS WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (users)\r\n//// SELECT count(*) FROM users WHERE name = 'jinzhu' OR name = 'jinzhu 2'; (count)\r\n\r\ndb.Model(User{}).Where(\"name = ?\", \"jinzhu\").Count(&count)\r\n//// SELECT count(*) FROM users WHERE name = 'jinzhu'; (count)\r\n\r\ndb.Table(\"deleted_users\").Count(&count)\r\n//// SELECT count(*) FROM deleted_users;\r\n```\r\n\r\n## Pluck\r\n\r\nGet selected attributes as map\r\n\r\n```go\r\nvar ages []int64\r\ndb.Find(&users).Pluck(\"age\", &ages)\r\n\r\nvar names []string\r\ndb.Model(&User{}).Pluck(\"name\", &names)\r\n\r\ndb.Table(\"deleted_users\").Pluck(\"name\", &names)\r\n\r\n// Requesting more than one column? Do it like this:\r\ndb.Select(\"name, age\").Find(&users)\r\n```\r\n\r\n## Raw SQL\r\n\r\n```go\r\ndb.Exec(\"DROP TABLE users;\")\r\ndb.Exec(\"UPDATE orders SET shipped_at=? WHERE id IN (?)\", time.Now, []int64{11,22,33})\r\n```\r\n\r\n## Row & Rows\r\n\r\nIt is even possible to get query result as `*sql.Row` or `*sql.Rows`\r\n\r\n```go\r\nrow := db.Table(\"users\").Where(\"name = ?\", \"jinzhu\").Select(\"name, age\").Row() // (*sql.Row)\r\nrow.Scan(&name, &age)\r\n\r\nrows, err := db.Model(User{}).Where(\"name = ?\", \"jinzhu\").Select(\"name, age, email\").Rows() // (*sql.Rows, error)\r\ndefer rows.Close()\r\nfor rows.Next() {\r\n\t...\r\n\trows.Scan(&name, &age, &email)\r\n\t...\r\n}\r\n\r\n// Raw SQL\r\nrows, err := db.Raw(\"select name, age, email from users where name = ?\", \"jinzhu\").Rows() // (*sql.Rows, error)\r\ndefer rows.Close()\r\nfor rows.Next() {\r\n\t...\r\n\trows.Scan(&name, &age, &email)\r\n\t...\r\n}\r\n```\r\n\r\n## Scan\r\n\r\nScan results into another struct.\r\n\r\n```go\r\ntype Result struct {\r\n\tName string\r\n\tAge int\r\n}\r\n\r\nvar result Result\r\ndb.Table(\"users\").Select(\"name, age\").Where(\"name = ?\", 3).Scan(&result)\r\n\r\n// Raw SQL\r\ndb.Raw(\"SELECT name, age FROM users WHERE name = ?\", 3).Scan(&result)\r\n```\r\n\r\n## Group & Having\r\n\r\n```go\r\nrows, err := db.Table(\"orders\").Select(\"date(created_at) as date, sum(amount) as total\").Group(\"date(created_at)\").Rows()\r\nfor rows.Next() {\r\n\t...\r\n}\r\n\r\nrows, err := db.Table(\"orders\").Select(\"date(created_at) as date, sum(amount) as total\").Group(\"date(created_at)\").Having(\"sum(amount) > ?\", 100).Rows()\r\nfor rows.Next() {\r\n\t...\r\n}\r\n\r\ntype Result struct {\r\n\tDate time.Time\r\n\tTotal int64\r\n}\r\ndb.Table(\"orders\").Select(\"date(created_at) as date, sum(amount) as total\").Group(\"date(created_at)\").Having(\"sum(amount) > ?\", 100).Scan(&results)\r\n```\r\n\r\n## Joins\r\n\r\n```go\r\nrows, err := db.Table(\"users\").Select(\"users.name, emails.email\").Joins(\"left join emails on emails.user_id = users.id\").Rows()\r\nfor rows.Next() {\r\n\t...\r\n}\r\n\r\ndb.Table(\"users\").Select(\"users.name, emails.email\").Joins(\"left join emails on emails.user_id = users.id\").Scan(&results)\r\n\r\n// find a user by email address\r\ndb.Joins(\"inner join emails on emails.user_id = users.id\").Where(\"emails.email = ?\", \"x@example.org\").Find(&user)\r\n\r\n// find all email addresses for a user\r\ndb.Joins(\"left join users on users.id = emails.user_id\").Where(\"users.name = ?\", \"jinzhu\").Find(&emails)\r\n```\r\n\r\n## Transactions\r\n\r\nTo perform a set of operations within a transaction, the general flow is as below.\r\nThe database handle returned from ``` db.Begin() ``` should be used for all operations within the transaction.\r\n(Note that all individual save and delete operations are run in a transaction by default.)\r\n\r\n```go\r\n// begin\r\ntx := db.Begin()\r\n\r\n// do some database operations (use 'tx' from this point, not 'db')\r\ntx.Create(...)\r\n...\r\n\r\n// rollback in case of error\r\ntx.Rollback()\r\n\r\n// Or commit if all is ok\r\ntx.Commit()\r\n```\r\n\r\n### A Specific Example\r\n```\r\nfunc CreateAnimals(db *gorm.DB) err {\r\n tx := db.Begin()\r\n // Note the use of tx as the database handle once you are within a transaction\r\n\r\n if err := tx.Create(&Animal{Name: \"Giraffe\"}).Error; err != nil {\r\n tx.Rollback()\r\n return err\r\n }\r\n\r\n if err := tx.Create(&Animal{Name: \"Lion\"}).Error; err != nil {\r\n tx.Rollback()\r\n return err\r\n }\r\n\r\n tx.Commit()\r\n return nil\r\n}\r\n```\r\n\r\n## Scopes\r\n\r\n```go\r\nfunc AmountGreaterThan1000(db *gorm.DB) *gorm.DB {\r\n\treturn db.Where(\"amount > ?\", 1000)\r\n}\r\n\r\nfunc PaidWithCreditCard(db *gorm.DB) *gorm.DB {\r\n\treturn db.Where(\"pay_mode_sign = ?\", \"C\")\r\n}\r\n\r\nfunc PaidWithCod(db *gorm.DB) *gorm.DB {\r\n\treturn db.Where(\"pay_mode_sign = ?\", \"C\")\r\n}\r\n\r\nfunc OrderStatus(status []string) func (db *gorm.DB) *gorm.DB {\r\n\treturn func (db *gorm.DB) *gorm.DB {\r\n\t\treturn db.Scopes(AmountGreaterThan1000).Where(\"status in (?)\", status)\r\n\t}\r\n}\r\n\r\ndb.Scopes(AmountGreaterThan1000, PaidWithCreditCard).Find(&orders)\r\n// Find all credit card orders and amount greater than 1000\r\n\r\ndb.Scopes(AmountGreaterThan1000, PaidWithCod).Find(&orders)\r\n// Find all COD orders and amount greater than 1000\r\n\r\ndb.Scopes(OrderStatus([]string{\"paid\", \"shipped\"})).Find(&orders)\r\n// Find all paid, shipped orders\r\n```\r\n\r\n## Callbacks\r\n\r\nCallbacks are methods defined on the pointer of struct.\r\nIf any callback returns an error, gorm will stop future operations and rollback all changes.\r\n\r\nHere is the list of all available callbacks:\r\n(listed in the same order in which they will get called during the respective operations)\r\n\r\n### Creating An Object\r\n\r\n```go\r\nBeforeSave\r\nBeforeCreate\r\n// save before associations\r\n// save self\r\n// save after associations\r\nAfterCreate\r\nAfterSave\r\n```\r\n### Updating An Object\r\n\r\n```go\r\nBeforeSave\r\nBeforeUpdate\r\n// save before associations\r\n// save self\r\n// save after associations\r\nAfterUpdate\r\nAfterSave\r\n```\r\n\r\n### Destroying An Object\r\n\r\n```go\r\nBeforeDelete\r\n// delete self\r\nAfterDelete\r\n```\r\n\r\n### After Find\r\n\r\n```go\r\n// load data from database\r\nAfterFind\r\n```\r\n\r\n### Example\r\n\r\n```go\r\nfunc (u *User) BeforeUpdate() (err error) {\r\n\tif u.readonly() {\r\n\t\terr = errors.New(\"read only user\")\r\n\t}\r\n\treturn\r\n}\r\n\r\n// Rollback the insertion if user's id greater than 1000\r\nfunc (u *User) AfterCreate() (err error) {\r\n\tif (u.Id > 1000) {\r\n\t\terr = errors.New(\"user id is already greater than 1000\")\r\n\t}\r\n\treturn\r\n}\r\n```\r\n\r\nAs you know, save/delete operations in gorm are running in a transaction,\r\nThis is means if changes made in the transaction is not visiable unless it is commited,\r\nSo if you want to use those changes in your callbacks, you need to run SQL in same transaction.\r\nFortunately, gorm support pass transaction to callbacks as you needed, you could do it like this:\r\n\r\n```go\r\nfunc (u *User) AfterCreate(tx *gorm.DB) (err error) {\r\n\ttx.Model(u).Update(\"role\", \"admin\")\r\n\treturn\r\n}\r\n```\r\n\r\n## Specifying The Table Name\r\n\r\n```go\r\n// Create `deleted_users` table with struct User's definition\r\ndb.Table(\"deleted_users\").CreateTable(&User{})\r\n\r\nvar deleted_users []User\r\ndb.Table(\"deleted_users\").Find(&deleted_users)\r\n//// SELECT * FROM deleted_users;\r\n\r\ndb.Table(\"deleted_users\").Where(\"name = ?\", \"jinzhu\").Delete()\r\n//// DELETE FROM deleted_users WHERE name = 'jinzhu';\r\n```\r\n\r\n### Specifying The Table Name For A Struct Permanently with TableName\r\n\r\n```go\r\ntype Cart struct {\r\n}\r\n\r\nfunc (c Cart) TableName() string {\r\n\treturn \"shopping_cart\"\r\n}\r\n\r\nfunc (u User) TableName() string {\r\n\tif u.Role == \"admin\" {\r\n\t\treturn \"admin_users\"\r\n\t} else {\r\n\t\treturn \"users\"\r\n\t}\r\n}\r\n```\r\n\r\n## Error Handling\r\n\r\n```go\r\nquery := db.Where(\"name = ?\", \"jinzhu\").First(&user)\r\nquery := db.First(&user).Limit(10).Find(&users)\r\n// query.Error will return the last happened error\r\n\r\n// So you could do error handing in your application like this:\r\nif err := db.Where(\"name = ?\", \"jinzhu\").First(&user).Error; err != nil {\r\n\t// error handling...\r\n}\r\n\r\n// RecordNotFound\r\n// If no record found when you query data, gorm will return RecordNotFound error, you could check it like this:\r\ndb.Where(\"name = ?\", \"hello world\").First(&User{}).Error == gorm.RecordNotFound\r\n// Or use the shortcut method\r\ndb.Where(\"name = ?\", \"hello world\").First(&user).RecordNotFound()\r\n\r\nif db.Model(&user).Related(&credit_card).RecordNotFound() {\r\n\t// no credit card found error handling\r\n}\r\n```\r\n\r\n## Logger\r\n\r\nGorm has built-in logger support\r\n\r\n```go\r\n// Enable Logger\r\ndb.LogMode(true)\r\n\r\n// Diable Logger\r\ndb.LogMode(false)\r\n\r\n// Debug a single operation\r\ndb.Debug().Where(\"name = ?\", \"jinzhu\").First(&User{})\r\n```\r\n\r\n![logger](https://raw.github.com/jinzhu/gorm/master/images/logger.png)\r\n\r\n### Customize Logger\r\n\r\n```go\r\n// Refer gorm's default logger for how to: https://github.com/jinzhu/gorm/blob/master/logger.go#files\r\ndb.SetLogger(gorm.Logger{revel.TRACE})\r\ndb.SetLogger(log.New(os.Stdout, \"\\r\\n\", 0))\r\n```\r\n\r\n## Existing Schema\r\n\r\nIf 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.\r\n\r\n```go\r\ntype Animal struct {\r\n\tAnimalId int64 `gorm:\"primary_key\"`\r\n\tBirthday time.Time `sql:\"DEFAULT:current_timestamp\"`\r\n\tName string `sql:\"default:'galeone'\"`\r\n\tAge int64\r\n}\r\n```\r\n\r\nIf your column names differ from the struct fields, you can specify them like this:\r\n\r\n```go\r\ntype Animal struct {\r\n\tAnimalId int64 `gorm:\"column:beast_id;primary_key\"`\r\n\tBirthday time.Time `gorm:\"column:day_of_the_beast\"`\r\n\tAge int64 `gorm:\"column:age_of_the_beast\"`\r\n}\r\n```\r\n\r\n## Composite Primary Key\r\n\r\n```go\r\ntype Product struct {\r\n\tID string `gorm:\"primary_key\"`\r\n\tLanguageCode string `gorm:\"primary_key\"`\r\n}\r\n```\r\n\r\n## Database Indexes & Foreign Key\r\n\r\n```go\r\n// Add foreign key\r\n// 1st param : foreignkey field\r\n// 2nd param : destination table(id)\r\n// 3rd param : ONDELETE\r\n// 4th param : ONUPDATE\r\ndb.Model(&User{}).AddForeignKey(\"city_id\", \"cities(id)\", \"RESTRICT\", \"RESTRICT\")\r\n\r\n// Add index\r\ndb.Model(&User{}).AddIndex(\"idx_user_name\", \"name\")\r\n\r\n// Multiple column index\r\ndb.Model(&User{}).AddIndex(\"idx_user_name_age\", \"name\", \"age\")\r\n\r\n// Add unique index\r\ndb.Model(&User{}).AddUniqueIndex(\"idx_user_name\", \"name\")\r\n\r\n// Multiple column unique index\r\ndb.Model(&User{}).AddUniqueIndex(\"idx_user_name_age\", \"name\", \"age\")\r\n\r\n// Remove index\r\ndb.Model(&User{}).RemoveIndex(\"idx_user_name\")\r\n```\r\n\r\n## Default values\r\n\r\n```go\r\ntype Animal struct {\r\n\tID int64\r\n\tName string `sql:\"default:'galeone'\"`\r\n\tAge int64\r\n}\r\n```\r\n\r\nIf you have defined a default value in the `sql` tag, the generated create SQl will ignore these fields if it is blank.\r\n\r\nEg.\r\n\r\n```go\r\ndb.Create(&Animal{Age: 99, Name: \"\"})\r\n```\r\n\r\nThe generated SQL will be:\r\n\r\n```sql\r\nINSERT INTO animals(\"age\") values('99');\r\n```\r\n\r\nThe same thing occurs in update statements.\r\n\r\n## More examples with query chain\r\n\r\n```go\r\ndb.First(&first_article).Count(&total_count).Limit(10).Find(&first_page_articles).Offset(10).Find(&second_page_articles)\r\n//// SELECT * FROM articles LIMIT 1; (first_article)\r\n//// SELECT count(*) FROM articles; (total_count)\r\n//// SELECT * FROM articles LIMIT 10; (first_page_articles)\r\n//// SELECT * FROM articles LIMIT 10 OFFSET 10; (second_page_articles)\r\n\r\n\r\ndb.Where(\"created_at > ?\", \"2013-10-10\").Find(&cancelled_orders, \"state = ?\", \"cancelled\").Find(&shipped_orders, \"state = ?\", \"shipped\")\r\n//// SELECT * FROM orders WHERE created_at > '2013/10/10' AND state = 'cancelled'; (cancelled_orders)\r\n//// SELECT * FROM orders WHERE created_at > '2013/10/10' AND state = 'shipped'; (shipped_orders)\r\n\r\n\r\n// Use variables to keep query chain\r\ntodays_orders := db.Where(\"created_at > ?\", \"2013-10-29\")\r\ncancelled_orders := todays_orders.Where(\"state = ?\", \"cancelled\")\r\nshipped_orders := todays_orders.Where(\"state = ?\", \"shipped\")\r\n\r\n\r\n// Search with shared conditions for different tables\r\ndb.Where(\"product_name = ?\", \"fancy_product\").Find(&orders).Find(&shopping_carts)\r\n//// SELECT * FROM orders WHERE product_name = 'fancy_product'; (orders)\r\n//// SELECT * FROM carts WHERE product_name = 'fancy_product'; (shopping_carts)\r\n\r\n\r\n// Search with shared conditions from different tables with specified table\r\ndb.Where(\"mail_type = ?\", \"TEXT\").Find(&users1).Table(\"deleted_users\").Find(&users2)\r\n//// SELECT * FROM users WHERE mail_type = 'TEXT'; (users1)\r\n//// SELECT * FROM deleted_users WHERE mail_type = 'TEXT'; (users2)\r\n\r\n\r\n// FirstOrCreate example\r\ndb.Where(\"email = ?\", \"x@example.org\").Attrs(User{RegisteredIp: \"111.111.111.111\"}).FirstOrCreate(&user)\r\n//// SELECT * FROM users WHERE email = 'x@example.org';\r\n//// INSERT INTO \"users\" (email,registered_ip) VALUES (\"x@example.org\", \"111.111.111.111\") // if record not found\r\n```\r\n\r\n## TODO\r\n* Github Pages\r\n\r\n# Author\r\n\r\n**jinzhu**\r\n\r\n* \r\n* \r\n* \r\n\r\n## License\r\n\r\nReleased under the [MIT License](https://github.com/jinzhu/gorm/blob/master/License).\r\n","google":"UA-23459165-4","note":"Don't delete this file! It's used internally to help with page regeneration."} \ No newline at end of file diff --git a/stylesheets/github-light.css b/stylesheets/github-light.css deleted file mode 100644 index 872a6f4b..00000000 --- a/stylesheets/github-light.css +++ /dev/null @@ -1,116 +0,0 @@ -/* - Copyright 2014 GitHub Inc. - - Licensed under the Apache License, Version 2.0 (the "License"); - you may not use this file except in compliance with the License. - You may obtain a copy of the License at - - http://www.apache.org/licenses/LICENSE-2.0 - - Unless required by applicable law or agreed to in writing, software - distributed under the License is distributed on an "AS IS" BASIS, - WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - See the License for the specific language governing permissions and - limitations under the License. - -*/ - -.pl-c /* comment */ { - color: #969896; -} - -.pl-c1 /* constant, markup.raw, meta.diff.header, meta.module-reference, meta.property-name, support, support.constant, support.variable, variable.other.constant */, -.pl-s .pl-v /* string variable */ { - color: #0086b3; -} - -.pl-e /* entity */, -.pl-en /* entity.name */ { - color: #795da3; -} - -.pl-s .pl-s1 /* string source */, -.pl-smi /* storage.modifier.import, storage.modifier.package, storage.type.java, variable.other, variable.parameter.function */ { - color: #333; -} - -.pl-ent /* entity.name.tag */ { - color: #63a35c; -} - -.pl-k /* keyword, storage, storage.type */ { - color: #a71d5d; -} - -.pl-pds /* punctuation.definition.string, string.regexp.character-class */, -.pl-s /* string */, -.pl-s .pl-pse .pl-s1 /* string punctuation.section.embedded source */, -.pl-sr /* string.regexp */, -.pl-sr .pl-cce /* string.regexp constant.character.escape */, -.pl-sr .pl-sra /* string.regexp string.regexp.arbitrary-repitition */, -.pl-sr .pl-sre /* string.regexp source.ruby.embedded */ { - color: #183691; -} - -.pl-v /* variable */ { - color: #ed6a43; -} - -.pl-id /* invalid.deprecated */ { - color: #b52a1d; -} - -.pl-ii /* invalid.illegal */ { - background-color: #b52a1d; - color: #f8f8f8; -} - -.pl-sr .pl-cce /* string.regexp constant.character.escape */ { - color: #63a35c; - font-weight: bold; -} - -.pl-ml /* markup.list */ { - color: #693a17; -} - -.pl-mh /* markup.heading */, -.pl-mh .pl-en /* markup.heading entity.name */, -.pl-ms /* meta.separator */ { - color: #1d3e81; - font-weight: bold; -} - -.pl-mq /* markup.quote */ { - color: #008080; -} - -.pl-mi /* markup.italic */ { - color: #333; - font-style: italic; -} - -.pl-mb /* markup.bold */ { - color: #333; - font-weight: bold; -} - -.pl-md /* markup.deleted, meta.diff.header.from-file */ { - background-color: #ffecec; - color: #bd2c00; -} - -.pl-mi1 /* markup.inserted, meta.diff.header.to-file */ { - background-color: #eaffea; - color: #55a532; -} - -.pl-mdr /* meta.diff.range */ { - color: #795da3; - font-weight: bold; -} - -.pl-mo /* meta.output */ { - color: #1d3e81; -} - diff --git a/stylesheets/pygment_trac.css b/stylesheets/pygment_trac.css deleted file mode 100644 index c6a6452d..00000000 --- a/stylesheets/pygment_trac.css +++ /dev/null @@ -1,69 +0,0 @@ -.highlight { background: #ffffff; } -.highlight .c { color: #999988; font-style: italic } /* Comment */ -.highlight .err { color: #a61717; background-color: #e3d2d2 } /* Error */ -.highlight .k { font-weight: bold } /* Keyword */ -.highlight .o { font-weight: bold } /* Operator */ -.highlight .cm { color: #999988; font-style: italic } /* Comment.Multiline */ -.highlight .cp { color: #999999; font-weight: bold } /* Comment.Preproc */ -.highlight .c1 { color: #999988; font-style: italic } /* Comment.Single */ -.highlight .cs { color: #999999; font-weight: bold; font-style: italic } /* Comment.Special */ -.highlight .gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */ -.highlight .gd .x { color: #000000; background-color: #ffaaaa } /* Generic.Deleted.Specific */ -.highlight .ge { font-style: italic } /* Generic.Emph */ -.highlight .gr { color: #aa0000 } /* Generic.Error */ -.highlight .gh { color: #999999 } /* Generic.Heading */ -.highlight .gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */ -.highlight .gi .x { color: #000000; background-color: #aaffaa } /* Generic.Inserted.Specific */ -.highlight .go { color: #888888 } /* Generic.Output */ -.highlight .gp { color: #555555 } /* Generic.Prompt */ -.highlight .gs { font-weight: bold } /* Generic.Strong */ -.highlight .gu { color: #800080; font-weight: bold; } /* Generic.Subheading */ -.highlight .gt { color: #aa0000 } /* Generic.Traceback */ -.highlight .kc { font-weight: bold } /* Keyword.Constant */ -.highlight .kd { font-weight: bold } /* Keyword.Declaration */ -.highlight .kn { font-weight: bold } /* Keyword.Namespace */ -.highlight .kp { font-weight: bold } /* Keyword.Pseudo */ -.highlight .kr { font-weight: bold } /* Keyword.Reserved */ -.highlight .kt { color: #445588; font-weight: bold } /* Keyword.Type */ -.highlight .m { color: #009999 } /* Literal.Number */ -.highlight .s { color: #d14 } /* Literal.String */ -.highlight .na { color: #008080 } /* Name.Attribute */ -.highlight .nb { color: #0086B3 } /* Name.Builtin */ -.highlight .nc { color: #445588; font-weight: bold } /* Name.Class */ -.highlight .no { color: #008080 } /* Name.Constant */ -.highlight .ni { color: #800080 } /* Name.Entity */ -.highlight .ne { color: #990000; font-weight: bold } /* Name.Exception */ -.highlight .nf { color: #990000; font-weight: bold } /* Name.Function */ -.highlight .nn { color: #555555 } /* Name.Namespace */ -.highlight .nt { color: #000080 } /* Name.Tag */ -.highlight .nv { color: #008080 } /* Name.Variable */ -.highlight .ow { font-weight: bold } /* Operator.Word */ -.highlight .w { color: #bbbbbb } /* Text.Whitespace */ -.highlight .mf { color: #009999 } /* Literal.Number.Float */ -.highlight .mh { color: #009999 } /* Literal.Number.Hex */ -.highlight .mi { color: #009999 } /* Literal.Number.Integer */ -.highlight .mo { color: #009999 } /* Literal.Number.Oct */ -.highlight .sb { color: #d14 } /* Literal.String.Backtick */ -.highlight .sc { color: #d14 } /* Literal.String.Char */ -.highlight .sd { color: #d14 } /* Literal.String.Doc */ -.highlight .s2 { color: #d14 } /* Literal.String.Double */ -.highlight .se { color: #d14 } /* Literal.String.Escape */ -.highlight .sh { color: #d14 } /* Literal.String.Heredoc */ -.highlight .si { color: #d14 } /* Literal.String.Interpol */ -.highlight .sx { color: #d14 } /* Literal.String.Other */ -.highlight .sr { color: #009926 } /* Literal.String.Regex */ -.highlight .s1 { color: #d14 } /* Literal.String.Single */ -.highlight .ss { color: #990073 } /* Literal.String.Symbol */ -.highlight .bp { color: #999999 } /* Name.Builtin.Pseudo */ -.highlight .vc { color: #008080 } /* Name.Variable.Class */ -.highlight .vg { color: #008080 } /* Name.Variable.Global */ -.highlight .vi { color: #008080 } /* Name.Variable.Instance */ -.highlight .il { color: #009999 } /* Literal.Number.Integer.Long */ - -.type-csharp .highlight .k { color: #0000FF } -.type-csharp .highlight .kt { color: #0000FF } -.type-csharp .highlight .nf { color: #000000; font-weight: normal } -.type-csharp .highlight .nc { color: #2B91AF } -.type-csharp .highlight .nn { color: #000000 } -.type-csharp .highlight .s { color: #A31515 } -.type-csharp .highlight .sc { color: #A31515 } diff --git a/stylesheets/styles.css b/stylesheets/styles.css deleted file mode 100644 index 647f08db..00000000 --- a/stylesheets/styles.css +++ /dev/null @@ -1,423 +0,0 @@ -@import url(https://fonts.googleapis.com/css?family=Arvo:400,700,400italic); - -/* MeyerWeb Reset */ - -html, body, div, span, applet, object, iframe, -h1, h2, h3, h4, h5, h6, p, blockquote, pre, -a, abbr, acronym, address, big, cite, code, -del, dfn, em, img, ins, kbd, q, s, samp, -small, strike, strong, sub, sup, tt, var, -b, u, i, center, -dl, dt, dd, ol, ul, li, -fieldset, form, label, legend, -table, caption, tbody, tfoot, thead, tr, th, td, -article, aside, canvas, details, embed, -figure, figcaption, footer, header, hgroup, -menu, nav, output, ruby, section, summary, -time, mark, audio, video { - margin: 0; - padding: 0; - border: 0; - font: inherit; - vertical-align: baseline; -} - - -/* Base text styles */ - -body { - padding:10px 50px 0 0; - font-family:"Helvetica Neue", Helvetica, Arial, sans-serif; - font-size: 14px; - color: #232323; - background-color: #FBFAF7; - margin: 0; - line-height: 1.8em; - -webkit-font-smoothing: antialiased; - -} - -h1, h2, h3, h4, h5, h6 { - color:#232323; - margin:36px 0 10px; -} - -p, ul, ol, table, dl { - margin:0 0 22px; -} - -h1, h2, h3 { - font-family: Arvo, Monaco, serif; - line-height:1.3; - font-weight: normal; -} - -h1,h2, h3 { - display: block; - border-bottom: 1px solid #ccc; - padding-bottom: 5px; -} - -h1 { - font-size: 30px; -} - -h2 { - font-size: 24px; -} - -h3 { - font-size: 18px; -} - -h4, h5, h6 { - font-family: Arvo, Monaco, serif; - font-weight: 700; -} - -a { - color:#C30000; - font-weight:200; - text-decoration:none; -} - -a:hover { - text-decoration: underline; -} - -a small { - font-size: 12px; -} - -em { - font-style: italic; -} - -strong { - font-weight:700; -} - -ul { - list-style-position: inside; - list-style: disc; - padding-left: 25px; -} - -ol { - list-style-position: inside; - list-style: decimal; - padding-left: 25px; -} - -blockquote { - margin: 0; - padding: 0 0 0 20px; - font-style: italic; -} - -dl, dt, dd, dl p { - font-color: #444; -} - -dl dt { - font-weight: bold; -} - -dl dd { - padding-left: 20px; - font-style: italic; -} - -dl p { - padding-left: 20px; - font-style: italic; -} - -hr { - border:0; - background:#ccc; - height:1px; - margin:0 0 24px; -} - -/* Images */ - -img { - position: relative; - margin: 0 auto; - max-width: 650px; - padding: 5px; - margin: 10px 0 32px 0; - border: 1px solid #ccc; -} - -p img { - display: inline; - margin: 0; - padding: 0; - vertical-align: middle; - text-align: center; - border: none; -} - -/* Code blocks */ - -code, pre { - font-family: Monaco, "Bitstream Vera Sans Mono", "Lucida Console", Terminal, monospace; - color:#000; - font-size:14px; -} - -pre { - padding: 4px 12px; - background: #FDFEFB; - border-radius:4px; - border:1px solid #D7D8C8; - overflow: auto; - overflow-y: hidden; - margin-bottom: 32px; -} - - -/* Tables */ - -table { - width:100%; -} - -table { - border: 1px solid #ccc; - margin-bottom: 32px; - text-align: left; - } - -th { - font-family: 'Arvo', Helvetica, Arial, sans-serif; - font-size: 18px; - font-weight: normal; - padding: 10px; - background: #232323; - color: #FDFEFB; - } - -td { - padding: 10px; - background: #ccc; - } - - -/* Wrapper */ -.wrapper { - width:960px; -} - - -/* Header */ - -header { - background-color: #171717; - color: #FDFDFB; - width:170px; - float:left; - position:fixed; - border: 1px solid #000; - -webkit-border-top-right-radius: 4px; - -webkit-border-bottom-right-radius: 4px; - -moz-border-radius-topright: 4px; - -moz-border-radius-bottomright: 4px; - border-top-right-radius: 4px; - border-bottom-right-radius: 4px; - padding: 34px 25px 22px 50px; - margin: 30px 25px 0 0; - -webkit-font-smoothing: antialiased; -} - -p.header { - font-size: 16px; -} - -h1.header { - font-family: Arvo, sans-serif; - font-size: 30px; - font-weight: 300; - line-height: 1.3em; - border-bottom: none; - margin-top: 0; -} - - -h1.header, a.header, a.name, header a{ - color: #fff; -} - -a.header { - text-decoration: underline; -} - -a.name { - white-space: nowrap; -} - -header ul { - list-style:none; - padding:0; -} - -header li { - list-style-type: none; - width:132px; - height:15px; - margin-bottom: 12px; - line-height: 1em; - padding: 6px 6px 6px 7px; - - background: #AF0011; - background: -moz-linear-gradient(top, #AF0011 0%, #820011 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); - background: -webkit-linear-gradient(top, #AF0011 0%,#820011 100%); - background: -o-linear-gradient(top, #AF0011 0%,#820011 100%); - background: -ms-linear-gradient(top, #AF0011 0%,#820011 100%); - background: linear-gradient(top, #AF0011 0%,#820011 100%); - - border-radius:4px; - border:1px solid #0D0D0D; - - -webkit-box-shadow: inset 0px 1px 1px 0 rgba(233,2,38, 1); - box-shadow: inset 0px 1px 1px 0 rgba(233,2,38, 1); - -} - -header li:hover { - background: #C3001D; - background: -moz-linear-gradient(top, #C3001D 0%, #950119 100%); - background: -webkit-gradient(linear, left top, left bottom, color-stop(0%,#f8f8f8), color-stop(100%,#dddddd)); - background: -webkit-linear-gradient(top, #C3001D 0%,#950119 100%); - background: -o-linear-gradient(top, #C3001D 0%,#950119 100%); - background: -ms-linear-gradient(top, #C3001D 0%,#950119 100%); - background: linear-gradient(top, #C3001D 0%,#950119 100%); -} - -a.buttons { - -webkit-font-smoothing: antialiased; - background: url(../images/arrow-down.png) no-repeat; - font-weight: normal; - text-shadow: rgba(0, 0, 0, 0.4) 0 -1px 0; - padding: 2px 2px 2px 22px; - height: 30px; -} - -a.github { - background: url(../images/octocat-small.png) no-repeat 1px; -} - -a.buttons:hover { - color: #fff; - text-decoration: none; -} - - -/* Section - for main page content */ - -section { - width:650px; - float:right; - padding-bottom:50px; -} - - -/* Footer */ - -footer { - width:170px; - float:left; - position:fixed; - bottom:10px; - padding-left: 50px; -} - -@media print, screen and (max-width: 960px) { - - div.wrapper { - width:auto; - margin:0; - } - - header, section, footer { - float:none; - position:static; - width:auto; - } - - footer { - border-top: 1px solid #ccc; - margin:0 84px 0 50px; - padding:0; - } - - header { - padding-right:320px; - } - - section { - padding:20px 84px 20px 50px; - margin:0 0 20px; - } - - header a small { - display:inline; - } - - header ul { - position:absolute; - right:130px; - top:84px; - } -} - -@media print, screen and (max-width: 720px) { - body { - word-wrap:break-word; - } - - header { - padding:10px 20px 0; - margin-right: 0; - } - - section { - padding:10px 0 10px 20px; - margin:0 0 30px; - } - - footer { - margin: 0 0 0 30px; - } - - header ul, header p.view { - position:static; - } -} - -@media print, screen and (max-width: 480px) { - - header ul li.download { - display:none; - } - - footer { - margin: 0 0 0 20px; - } - - footer a{ - display:block; - } - -} - -@media print { - body { - padding:0.4in; - font-size:12pt; - color:#444; - } -} \ No newline at end of file