pop

package module
v4.6.6+incompatible Latest Latest
Warning

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

Go to latest
Published: Aug 18, 2018 License: MIT Imports: 45 Imported by: 0

README

POP GoDoc Build Status

A Tasty Treat For All Your Database Needs

So what does Pop do exactly? Well, it wraps the absolutely amazing https://github.com/jmoiron/sqlx library. It cleans up some of the common patterns and work flows usually associated with dealing with databases in Go.

Pop makes it easy to do CRUD operations, run migrations, and build/execute queries. Is Pop an ORM? I'll leave that up to you, the reader, to decide.

Pop, by default, follows conventions that were influenced by the ActiveRecord Ruby gem. What does this mean?

  • Tables must have an "id" column and a corresponding "ID" field on the struct being used.
  • If there is a timestamp column named created_at, and a CreatedAt time.Time attribute on the struct, it will be set with the current time when the record is created.
  • If there is a timestamp column named updated_at, and a UpdatedAt time.Time attribute on the struct, it will be set with the current time when the record is updated.
  • Default database table names are lowercase, plural, and underscored versions of the struct name. Examples: User{} is "users", FooBar{} is "foo_bars", etc...

Supported Databases

  • PostgreSQL (>= 9.3)
  • MySQL (>= 5.7)
  • SQLite (>= 3.x)
  • CockroachDB (>= 1.1.1)

Connecting to Databases

Pop is easily configured using a YAML file. The configuration file should be stored in config/database.yml or database.yml.

Example Configuration File
development:
  dialect: "postgres"
  database: "your_db_development"
  host: "localhost"
  port: "5432"
  user: "postgres"
  password: "postgres"

test:
  dialect: "mysql"
  database: "your_db_test"
  host: "localhost"
  port: "3306"
  user: "root"
  password: "root"

staging:
  dialect: "sqlite3"
  database: "./staging.sqlite"

production:
  dialect: "postgres"
  url: {{ env "DATABASE_URL" }}

Note that the database.yml file is also a Go template, so you can use Go template syntax. There are two special functions that are included, env and envOr.

  • env - This function will look for the named environment variable and insert it into your file. This is useful for configuring production databases without having to store secret information in your repository. {{ env "DATABASE_URL" }}
  • envOr - This function will look for the named environment variable and use it. If the variable can not be found a default value will be used. {{ envOr "MYSQL_HOST" "localhost" }}

You can generate a default configuration file using the init command:

$ soda g config

The default will generate a database.yml file in the current directory for a PostgreSQL database. You can override the type of database using the -t flag and passing in any of the supported database types: postgres, cockroach, mysql, or sqlite3.

CockroachDB currently works best if you DO NOT use a URL and instead define each key item. Because CockroachDB more or less uses the same driver as postgres you have the same configuration options for both. In production you will also want to make sure you are using a secure cluster and have set all the needed connection parameters for said secure connection. If you do not set the sslmode or set it to disable this will put dump and load commands into --insecure mode.

In Your Code

Once you have a configuration file defined you can easily connect to one of these connections in your application.

db, err := pop.Connect("development")
if err != nil {
  log.Panic(err)
}

Now that you have your connection to the database you can start executing queries against it.

CLI Support

Pop features CLI support via the soda command for the following operations:

Available Commands:
  create      Creates databases for you
  drop        Drops databases for you
  generate
  help        Help about any command
  migrate     Runs migrations against your database.
  schema      Tools for working with your database schema
Installing CLI Support

Without sqlite 3 support:

$ go get github.com/gobuffalo/pop/...
$ go install github.com/gobuffalo/pop/soda

With sqlite 3 support:

$ go get -u -v -tags sqlite github.com/gobuffalo/pop/...
$ go install -tags sqlite github.com/gobuffalo/pop/soda

If you're not building your code with buffalo build, you'll also have to pass -tags sqlite to go build when building your program.

Managing Databases

Creating Databases

Assuming you defined a configuration file like that described in the above section you can automatically create those databases using the soda command:

Create All Databases
$ soda create -a
Create a Specific Database
$ soda create -e development
Dropping Databases

Assuming you defined a configuration file like that described in the above section you can automatically drop those databases using the soda command:

Drop All Databases
$ soda drop -a
Drop a Specific Database
$ soda drop -e development

Models

The soda command supports the generation of models.

A full list of commands available for model generation can be found by asking for help:

$ soda generate help
Generating Models

The soda command will generate Go models and, optionally, the associated migrations for you.

$ soda generate model user name:text email:text

Running this command will generate the following files:

models/user.go
models/user_test.go
migrations/20170115024143_create_users.up.fizz
migrations/20170115024143_create_users.down.fizz

The models/user.go file contains a structure named User with fields ID, CreatedAt, UpdatedAt, Name, and Email. The first three correspond to the columns commonly found in ActiveRecord models as mentioned before, and the last two correspond to the additional fields specified on the command line. The known types are:

  • text (string in Go)
  • blob ([]byte in Go)
  • time or timestamp (time.Time)
  • nulls.Text (nulls.String) which corresponds to a nullifyable string, which can be distinguished from an empty string
  • uuid (uuid.UUID)
  • Other types are passed thru and are used as Fizz types.

The models/user_test.go contains tests for the User model and they must be implemented by you.

The other two files correspond to the migrations as explained below. By default, it generates .fizz files but you can also generate .sql files by adding the flag --migration-type sql to the command. Be aware, that you will need to specify the appropriate environment, because .sql files are for specific databases.

$ soda generate model user name:text email:text --migration-type sql -e development

If developmentis associated with a postgresqlconfiguration, running this command will generate the following files:

models/user.go
models/user_test.go
migrations/20170115024143_create_users.postgres.up.sql
migrations/20170115024143_create_users.postgres.down.sql

Migrations

The soda command supports the creation and running of migrations.

A full list of commands available for migration can be found by asking for help:

$ soda migrate --help
Generating Migrations

The soda command will generate SQL migrations (both the up and down) files for you.

$ soda generate fizz name_of_migration

Running this command will generate the following files:

./migrations/20160815134952_name_of_migration.up.fizz
./migrations/20160815134952_name_of_migration.down.fizz

The generated files are fizz files. Fizz lets you use a common DSL for generating migrations. This means the same .fizz file can be run against any of the supported dialects of Pop! Find out more about Fizz

If you want to generate old fashion .sql files you can use the -t flag for that:

$ soda generate sql name_of_migration

Running this command will generate the following files:

./migrations/20160815134952_name_of_migration.up.sql
./migrations/20160815134952_name_of_migration.down.sql

The soda migrate command supports both .fizz and .sql files, so you can mix and match them to suit your needs.

Running Migrations

The soda command will run the migrations using the following command:

$ soda migrate up

Migrations will be run in sequential order.

Migrations can also be run in reverse to rollback the schema.

$ soda migrate down

The previously run migrations will be kept track of in a table named schema_migration in the database. The table name can be configured by setting migration_table_name of the configuration options. The example below will use migrations as the table name.

development:
  dialect: "postgres"
  url: "your_db_development"
  options:
    migration_table_name: migrations

Querying

Find By ID
user := User{}
err := db.Find(&user, id)
Find All
users := []User{}
err := db.All(&users)
err = db.Where("id in (?)", 1, 2, 3).All(&users)
Find Last
// Last() orders by created_at
user := models.User{}
err := tx.Last(&user)
Find Where
users := []models.User{}
query := db.Where("id = 1").Where("name = 'Mark'")
err := query.All(&users)

err = tx.Where("id in (?)", 1, 2, 3).All(&users)
Using in Queries
err = db.Where("id in (?)", 1, 2, 3).All(&users)
err = db.Where("id in (?)", 1, 2, 3).Where("foo = ?", "bar").All(&users)

Unfortunately, for a variety of reasons you can't use an and query in the same Where call as an in query.

// does not work:
err = db.Where("id in (?) and foo = ?", 1, 2, 3, "bar").All(&users)
// works:
err = db.Where("id in (?)", 1, 2, 3).Where("foo = ?", "bar").All(&users)
Select specific columns

Select allows you to load specific columns from a table. Useful when you don't want all columns from a table to be loaded in a query.

err = db.Select("name").All(&users)
// SELECT name FROM users

err = db.Select("max(age)").All(&users)
// SELECT max(age) FROM users

err = db.Select("age", "name").All(&users)
// SELECT age, name FROM users
Join Query
// page: page number
// perpage: limit
roles := []models.UserRole{}
query := models.DB.LeftJoin("roles", "roles.id=user_roles.role_id").
  LeftJoin("users u", "u.id=user_roles.user_id").
  Where(`roles.name like ?`, name).Paginate(page, perpage)

count, _ := query.Count(models.UserRole{})
count, _ := query.CountByField(models.UserRole{}, "*")
sql, args := query.ToSQL(&pop.Model{Value: models.UserRole{}}, "user_roles.*",
  "roles.name as role_name", "u.first_name", "u.last_name")
err := models.DB.RawQuery(sql, args...).All(&roles)

Creating New Records

// Create one record.
user := models.User{}
user.Name = "Mark"
err := tx.Create(&user)

// Create many records.
users := models.Users{
  {Name:"Mark"},
  {Name: "Larry"},
}

err := tx.Create(&users)

Saving Records

The Save method will attempt to create the record if the ID is empty. If there is an ID set it will attempt to update the record with that ID in the database.

// Save one record.
user := models.User{}
user.Name = "Mark"
err := tx.Save(&user)

// Save many records.
users := models.Users{
  {Name:"Mark"},
  {Name: "Larry"},
}

err := tx.Save(&users)

Updating Records

// Update one record.
user := models.User{}
user.Name = "Mark"
err := tx.Create(&user)

user.Name = "Mark Bates"
err = tx.Update(&user)

// Update many records.
users := models.Users{
  {Name:"Mark"},
  {Name: "Larry"},
}

err := tx.Create(&users)

users[0].Name = "Mark Bates"
users[1].Name = "Larry Morales"
err := tx.Update(&users)

Destroy

// Destroy one record.
user := models.User{}
user.Name = "Mark"
err := tx.Create(&user)

err = tx.Destroy(&user)

// Destroy many records.
users := models.Users{
  {Name:"Mark"},
  {Name: "Larry"},
}
err := tx.Create(&users)

err = tx.Destroy(&users)

Eager Loading

Pop allows you to perform an eager loading for associations defined in a model. By using pop.Connection.Eager() function plus some fields tags predefined in your model you can extract associated data from a model.

type User struct {
  ID           uuid.UUID
  Email        string
  Password     string
  Books        Books     `has_many:"books" order_by:"title asc"`
  FavoriteSong Song      `has_one:"song" fk_id:"u_id"`
  Houses       Addresses `many_to_many:"users_addresses"`
}
type Book struct {
  ID      uuid.UUID
  Title   string
  Isbn    string
  User    User        `belongs_to:"user"`
  UserID  uuid.UUID
  Writers Writers     `has_many:"writers"`
}
type Writer struct {
   ID     uuid.UUID   `db:"id"`
   Name   string      `db:"name"`
   BookID uuid.UUID   `db:"book_id"`
   Book   Book        `belongs_to:"book"`
}
type Song struct {
  ID      uuid.UUID
  Title   string
  UserID  uuid.UUID   `db:"u_id"`
}
type Address struct {
  ID           uuid.UUID
  Street       string
  HouseNumber  int
}

type Addresses []Address
  • has_many: will load all records from the books table that have a column named user_id or the column specified with fk_id that matches the User.ID value.

  • belongs_to: will load a record from users table that have a column named id that matches with Book.UserID value.

  • has_one: will load a record from the songs table that have a column named user_id or the column specified with fk_id that matches the User.ID value.

  • many_to_many: will load all records from the addresses table through the table users_addresses. Table users_addresses MUST define address_id and user_id columns to match User.ID and Address.ID values. You can also define a fk_id tag that will be used in the target association i.e addresses table.

  • fk_id: defines the column name in the target association that matches model ID. In the example above Song has a column named u_id that represents id of users table. When loading FavoriteSong, u_id will be used instead of user_id.

  • order_by: used in has_many and many_to_many to indicate the order for the association when loading. The format to use is order_by:"<column_name> <asc | desc>"

u := Users{}
// preload all associations for user with name 'Mark', i.e Books, Houses and FavoriteSong
err := tx.Eager().Where("name = 'Mark'").All(&u)
// preload only Books association for user with name 'Mark'.
err  = tx.Eager("Books").Where("name = 'Mark'").All(&u)
Eager Loading Nested Associations

Pop allows you to eager loading nested associations by using . character to concatenate them. Take a look at the example bellow.

// will load all Books for u and for every Book will load the user which will be the same as u.
tx.Eager("Books.User").First(&u)
// will load all Books for u and for every Book will load all Writers.
 tx.Eager("Books.Writers").First(&u)
// will load all Books for u and for every Book will load all Writers and for every writer will load the Book association.
tx.Eager("Books.Writers.Book").First(&u)
// will load all Books for u and for every Book will load all Writers. And Also it will load the favorite song for user.
tx.Eager("Books.Writers").Eager("FavoriteSong").First(&u)
Eager Creation

Pop allows you to create models and their associations in one step. You no longer need to create every association separately anymore. Pop will even create join table records for many_to_many associations.

Assuming the following pieces of pseudo-code:

user := User{
  Name: "Mark Bates",
  Books: Books{{Title: "Pop Book", Description: "Pop Book", Isbn: "PB1"}},
  FavoriteSong: Song{Title: "Don't know the title"},
  Houses: Addresses{
    Address{HouseNumber: 1, Street: "Golang"},
  },
}
err := tx.Eager().Create(&user)
  1. It will notice Books is a has_many association and it will realize that to actually store every book it will need to get the User ID first. So, it proceeds to store first User data so it can retrieve an ID and then use that ID to fill UserID field in every Book in Books. Later it stores all books in database.

  2. FavoriteSong is a has_one association and it uses same logic described in has_many association. Since User data was previously saved before creating all books, it already knows that User got an ID so it fills its UserID field with that value and FavoriteSong is then stored in database.

  3. Houses in this example is a many_to_many relationship and it will have to deal with two tables in this case: users and addresses. It will need to store all addresses first in addresses table before save them in the many to many table. Because User was already stored, it already have an ID. * This is a special case to deal with, since this behavior is different to all other associations, it is solved by implementing the AssociationCreatableStatement interface, all other associations implement by default AssociationCreatable interface.

For a belongs_to association like shown in the example below, it will need first to create User to retrieve ID value and then fill its UserID field before be saved in database.

book := Book{
   Title:      "Pop Book",
   Description: "Pop Book",
   Isbn:        "PB1",
   User: User{
        Name: nulls.NewString("Larry"),
   },
}
tx.Eager().Create(&book)

All these cases are assuming that none of models and associations has previously been saved in database.

Callbacks

Pop provides a means to execute code before and after database operations. This is done by defining specific methods on your models. For example, to hash a user password you may want to define the following method:

type User struct {
  ID       uuid.UUID
  Email    string
  Password string
}

func (u *User) BeforeSave(tx *pop.Connection) error {
  hash, err := bcrypt.GenerateFromPassword([]byte(u.Password), bcrypt.DefaultCost)
  if err != nil {
    return errors.WithStack(err)
  }

  u.Password = string(hash)

  return nil
}
Available Callbacks:
  • BeforeSave
  • BeforeCreate
  • BeforeUpdate
  • BeforeDestroy
  • AfterSave
  • AfterCreate
  • AfterUpdate
  • AfterDestroy
  • AfterFind

Further Reading

The Unofficial pop Book: a gentle introduction to new users.

Documentation

Overview

Package pop wraps the absolutely amazing https://github.com/jmoiron/sqlx library. It cleans up some of the common patterns and workflows usually associated with dealing with databases in Go.

Pop makes it easy to do CRUD operations, run migrations, and build/execute queries. Is Pop an ORM? I'll leave that up to you, the reader, to decide.

Pop, by default, follows conventions that were defined by the ActiveRecord Ruby gem, http://www.rubyonrails.org. What does this mean?

* Tables must have an "id" column and a corresponding "ID" field on the `struct` being used. * If there is a timestamp column named "created_at", "CreatedAt" on the `struct`, it will be set with the current time when the record is created. * If there is a timestamp column named "updated_at", "UpdatedAt" on the `struct`, it will be set with the current time when the record is updated. * Default databases are lowercase, underscored versions of the `struct` name. Examples: User{} is "users", FooBar{} is "foo_bars", etc...

Index

Constants

This section is empty.

Variables

View Source
var AvailableDialects = []string{"postgres", "mysql", "cockroach"}

AvailableDialects lists the available database dialects

View Source
var Color = true

Color mode, to toggle colored logs

View Source
var ConfigName = "database.yml"

ConfigName is the name of the YAML databases config file

View Source
var Connections = map[string]*Connection{}

Connections contains all of the available connections

View Source
var Debug = false

Debug mode, to toggle verbose log traces

View Source
var Log = func(s string, args ...interface{}) {
	if Debug {
		if len(args) > 0 {
			xargs := make([]string, len(args))
			for i, a := range args {
				switch a.(type) {
				case string:
					xargs[i] = fmt.Sprintf("%q", a)
				default:
					xargs[i] = fmt.Sprintf("%v", a)
				}
			}
			s = fmt.Sprintf("%s | %s", s, xargs)
		}
		if Color {
			s = color.YellowString(s)
		}
		logger.Println(s)
	}
}

Log a formatted string to the logger

View Source
var PaginatorPageKey = "page"

PaginatorPageKey is the query parameter holding the current page index

View Source
var PaginatorPerPageDefault = 20

PaginatorPerPageDefault is the amount of results per page

View Source
var PaginatorPerPageKey = "per_page"

PaginatorPerPageKey is the query parameter holding the amount of results per page to override the default one

Functions

func AddLookupPaths

func AddLookupPaths(paths ...string) error

AddLookupPaths add paths to the current lookup paths list

func CreateDB

func CreateDB(c *Connection) error

CreateDB creates a database, given a connection definition

func DialectSupported

func DialectSupported(d string) bool

DialectSupported checks support for the given database dialect

func DropDB

func DropDB(c *Connection) error

DropDB drops an existing database, given a connection definition

func LoadConfigFile

func LoadConfigFile() error

LoadConfigFile loads a POP config file from the configured lookup paths

func LoadFrom

func LoadFrom(r io.Reader) error

LoadFrom reads a configuration from the reader and sets up the connections

func LookupPaths

func LookupPaths() []string

LookupPaths returns the current configuration lookup paths

func MigrationCreate

func MigrationCreate(path, name, ext string, up, down []byte) error

MigrationCreate writes contents for a given migration in normalized files

Types

type AfterCreateable

type AfterCreateable interface {
	AfterCreate(*Connection) error
}

AfterCreateable callback will be called after a record is created in the database.

type AfterDestroyable

type AfterDestroyable interface {
	AfterDestroy(*Connection) error
}

AfterDestroyable callback will be called after a record is destroyed in the database.

type AfterFindable

type AfterFindable interface {
	AfterFind(*Connection) error
}

AfterFindable callback will be called after a record, or records, has been retrieved from the database.

type AfterSaveable

type AfterSaveable interface {
	AfterSave(*Connection) error
}

AfterSaveable callback will be called after a record is either created or updated in the database.

type AfterUpdateable

type AfterUpdateable interface {
	AfterUpdate(*Connection) error
}

AfterUpdateable callback will be called after a record is updated in the database.

type BeforeCreateable

type BeforeCreateable interface {
	BeforeCreate(*Connection) error
}

BeforeCreateable callback will be called before a record is created in the database.

type BeforeDestroyable

type BeforeDestroyable interface {
	BeforeDestroy(*Connection) error
}

BeforeDestroyable callback will be called before a record is destroyed in the database.

type BeforeSaveable

type BeforeSaveable interface {
	BeforeSave(*Connection) error
}

BeforeSaveable callback will be called before a record is either created or updated in the database.

type BeforeUpdateable

type BeforeUpdateable interface {
	BeforeUpdate(*Connection) error
}

BeforeUpdateable callback will be called before a record is updated in the database.

type Connection

type Connection struct {
	ID      string
	Store   store
	Dialect dialect
	Elapsed int64
	TX      *Tx
	// contains filtered or unexported fields
}

Connection represents all of the necessary details for talking with a datastore

func Connect

func Connect(e string) (*Connection, error)

Connect takes the name of a connection, default is "development", and will return that connection from the available `Connections`. If a connection with that name can not be found an error will be returned. If a connection is found, and it has yet to open a connection with its underlying datastore, a connection to that store will be opened.

func NewConnection

func NewConnection(deets *ConnectionDetails) (*Connection, error)

NewConnection creates a new connection, and sets it's `Dialect` appropriately based on the `ConnectionDetails` passed into it.

func (*Connection) All

func (c *Connection) All(models interface{}) error

All retrieves all of the records in the database that match the query.

c.All(&[]User{})

func (*Connection) BelongsTo

func (c *Connection) BelongsTo(model interface{}) *Query

BelongsTo adds a "where" clause based on the "ID" of the "model" passed into it.

func (*Connection) BelongsToAs

func (c *Connection) BelongsToAs(model interface{}, as string) *Query

BelongsToAs adds a "where" clause based on the "ID" of the "model" passed into it using an alias.

func (*Connection) BelongsToThrough

func (c *Connection) BelongsToThrough(bt, thru interface{}) *Query

BelongsToThrough adds a "where" clause that connects the "bt" model through the associated "thru" model.

func (*Connection) Close

func (c *Connection) Close() error

Close destroys an active datasource connection

func (*Connection) Count

func (c *Connection) Count(model interface{}) (int, error)

Count the number of records in the database.

c.Count(&User{})

func (*Connection) Create

func (c *Connection) Create(model interface{}, excludeColumns ...string) error

Create add a new given entry to the database, excluding the given columns. It updates `created_at` and `updated_at` columns automatically.

func (*Connection) Destroy

func (c *Connection) Destroy(model interface{}) error

Destroy deletes a given entry from the database

func (*Connection) Eager

func (c *Connection) Eager(fields ...string) *Connection

Eager will enable load associations of the model. by defaults loads all the associations on the model, but can take a variadic list of associations to load.

c.Eager().Find(model, 1) // will load all associations for model.
c.Eager("Books").Find(model, 1) // will load only Book association for model.

func (*Connection) Find

func (c *Connection) Find(model interface{}, id interface{}) error

Find the first record of the model in the database with a particular id.

c.Find(&User{}, 1)

func (*Connection) First

func (c *Connection) First(model interface{}) error

First record of the model in the database that matches the query.

c.First(&User{})

func (*Connection) Last

func (c *Connection) Last(model interface{}) error

Last record of the model in the database that matches the query.

c.Last(&User{})

func (*Connection) Limit

func (c *Connection) Limit(limit int) *Query

Limit will add a limit clause to the query.

func (*Connection) Load

func (c *Connection) Load(model interface{}, fields ...string) error

Load loads all association or the fields specified in params for an already loaded model.

tx.First(&u) tx.Load(&u)

func (*Connection) MigrateDown

func (c *Connection) MigrateDown(path string, step int) error

MigrateDown is deprecated, and will be removed in a future version. Use FileMigrator#Down instead.

func (*Connection) MigrateReset

func (c *Connection) MigrateReset(path string) error

MigrateReset is deprecated, and will be removed in a future version. Use FileMigrator#Reset instead.

func (*Connection) MigrateStatus

func (c *Connection) MigrateStatus(path string) error

MigrateStatus is deprecated, and will be removed in a future version. Use FileMigrator#Status instead.

func (*Connection) MigrateUp

func (c *Connection) MigrateUp(path string) error

MigrateUp is deprecated, and will be removed in a future version. Use FileMigrator#Up instead.

func (*Connection) MigrationTableName

func (c *Connection) MigrationTableName() string

MigrationTableName returns the name of the table to track migrations

func (*Connection) MigrationURL

func (c *Connection) MigrationURL() string

MigrationURL returns the datasource connection string used for running the migrations

func (*Connection) NewTransaction

func (c *Connection) NewTransaction() (*Connection, error)

NewTransaction starts a new transaction on the connection

func (*Connection) Open

func (c *Connection) Open() error

Open creates a new datasource connection

func (*Connection) Order

func (c *Connection) Order(stmt string) *Query

Order will append an order clause to the query.

c.Order("name desc")

func (*Connection) Paginate

func (c *Connection) Paginate(page int, perPage int) *Query

Paginate records returned from the database.

q := c.Paginate(2, 15)
q.All(&[]User{})
q.Paginator

func (*Connection) PaginateFromParams

func (c *Connection) PaginateFromParams(params PaginationParams) *Query

PaginateFromParams paginates records returned from the database.

q := c.PaginateFromParams(req.URL.Query())
q.All(&[]User{})
q.Paginator

func (*Connection) Q

func (c *Connection) Q() *Query

Q creates a new "empty" query for the current connection.

func (*Connection) RawQuery

func (c *Connection) RawQuery(stmt string, args ...interface{}) *Query

RawQuery will override the query building feature of Pop and will use whatever query you want to execute against the `Connection`. You can continue to use the `?` argument syntax.

c.RawQuery("select * from foo where id = ?", 1)

func (*Connection) Reload

func (c *Connection) Reload(model interface{}) error

Reload fetch fresh data for a given model, using its ID.

func (*Connection) Rollback

func (c *Connection) Rollback(fn func(tx *Connection)) error

Rollback will open a new transaction and automatically rollback that transaction when the inner function returns, regardless. This can be useful for tests, etc...

func (*Connection) Save

func (c *Connection) Save(model interface{}, excludeColumns ...string) error

Save wraps the Create and Update methods. It executes a Create if no ID is provided with the entry; or issues an Update otherwise.

func (*Connection) Scope

func (c *Connection) Scope(sf ScopeFunc) *Query

Scope the query by using a `ScopeFunc`

func ByName(name string) ScopeFunc {
	return func(q *Query) *Query {
		return q.Where("name = ?", name)
	}
}

func WithDeleted(q *pop.Query) *pop.Query {
	return q.Where("deleted_at is null")
}

c.Scope(ByName("mark)).Scope(WithDeleted).First(&User{})

func (*Connection) Select

func (c *Connection) Select(fields ...string) *Query

Select allows to query only fields passed as parameter. c.Select("field1", "field2").All(&model) => SELECT field1, field2 FROM models

func (*Connection) String

func (c *Connection) String() string

func (*Connection) Transaction

func (c *Connection) Transaction(fn func(tx *Connection) error) error

Transaction will start a new transaction on the connection. If the inner function returns an error then the transaction will be rolled back, otherwise the transaction will automatically commit at the end.

func (*Connection) TruncateAll

func (c *Connection) TruncateAll() error

TruncateAll truncates all data from the datasource

func (*Connection) URL

func (c *Connection) URL() string

URL returns the datasource connection string

func (*Connection) Update

func (c *Connection) Update(model interface{}, excludeColumns ...string) error

Update writes changes from an entry to the database, excluding the given columns. It updates the `updated_at` column automatically.

func (*Connection) ValidateAndCreate

func (c *Connection) ValidateAndCreate(model interface{}, excludeColumns ...string) (*validate.Errors, error)

ValidateAndCreate applies validation rules on the given entry, then creates it if the validation succeed, excluding the given columns.

func (*Connection) ValidateAndSave

func (c *Connection) ValidateAndSave(model interface{}, excludeColumns ...string) (*validate.Errors, error)

ValidateAndSave applies validation rules on the given entry, then save it if the validation succeed, excluding the given columns.

func (*Connection) ValidateAndUpdate

func (c *Connection) ValidateAndUpdate(model interface{}, excludeColumns ...string) (*validate.Errors, error)

ValidateAndUpdate applies validation rules on the given entry, then update it if the validation succeed, excluding the given columns.

func (*Connection) Where

func (c *Connection) Where(stmt string, args ...interface{}) *Query

Where will append a where clause to the query. You may use `?` in place of arguments.

c.Where("id = ?", 1)
q.Where("id in (?)", 1, 2, 3)

type ConnectionDetails

type ConnectionDetails struct {
	// Example: "postgres" or "sqlite3" or "mysql"
	Dialect string
	// The name of your database. Example: "foo_development"
	Database string
	// The host of your database. Example: "127.0.0.1"
	Host string
	// The port of your database. Example: 1234
	// Will default to the "default" port for each dialect.
	Port string
	// The username of the database user. Example: "root"
	User string
	// The password of the database user. Example: "password"
	Password string
	// The encoding to use to create the database and communicate with it.
	Encoding string
	// Instead of specifying each individual piece of the
	// connection you can instead just specify the URL of the
	// database. Example: "postgres://postgres:postgres@localhost:5432/pop_test?sslmode=disable"
	URL string
	// Defaults to 0 "unlimited". See https://golang.org/pkg/database/sql/#DB.SetMaxOpenConns
	Pool int
	// Defaults to 0 "unlimited". See https://golang.org/pkg/database/sql/#DB.SetMaxIdleConns
	IdlePool int
	Options  map[string]string
}

ConnectionDetails stores the data needed to connect to a datasource

func (*ConnectionDetails) Finalize

func (cd *ConnectionDetails) Finalize() error

Finalize cleans up the connection details by normalizing names, filling in default values, etc...

func (*ConnectionDetails) MigrationTableName

func (cd *ConnectionDetails) MigrationTableName() string

MigrationTableName returns the name of the table to track migrations

func (*ConnectionDetails) Parse

func (cd *ConnectionDetails) Parse(port string) error

Parse is deprecated! Please use `ConnectionDetails.Finalize()` instead!

func (*ConnectionDetails) RetryLimit

func (cd *ConnectionDetails) RetryLimit() int

RetryLimit returns the maximum number of accepted connection retries

func (*ConnectionDetails) RetrySleep

func (cd *ConnectionDetails) RetrySleep() time.Duration

RetrySleep returns the amount of time to wait between two connection retries

type FileMigrator

type FileMigrator struct {
	Migrator
	Path string
}

FileMigrator is a migrator for SQL and Fizz files on disk at a specified path.

func NewFileMigrator

func NewFileMigrator(path string, c *Connection) (FileMigrator, error)

NewFileMigrator for a path and a Connection

type GroupClause

type GroupClause struct {
	Field string
}

GroupClause holds the field to apply the GROUP clause on

func (GroupClause) String

func (c GroupClause) String() string

type HavingClause

type HavingClause struct {
	Condition string
	Arguments []interface{}
}

HavingClause defines a condition and its arguments for a HAVING clause

func (HavingClause) String

func (c HavingClause) String() string

type Migration

type Migration struct {
	// Path to the migration (./migrations/123_create_widgets.up.sql)
	Path string
	// Version of the migration (123)
	Version string
	// Name of the migration (create_widgets)
	Name string
	// Direction of the migration (up)
	Direction string
	// Type of migration (sql)
	Type string
	// DB type (all|postgres|mysql...)
	DBType string
	// Runner function to run/execute the migration
	Runner func(Migration, *Connection) error
}

Migration handles the data for a given database migration

func (Migration) Run

func (mf Migration) Run(c *Connection) error

Run the migration. Returns an error if there is no mf.Runner defined.

type MigrationBox

type MigrationBox struct {
	Migrator
	Box packr.Box
}

MigrationBox is a wrapper around packr.Box and Migrator. This will allow you to run migrations from a packed box inside of a compiled binary.

func NewMigrationBox

func NewMigrationBox(box packr.Box, c *Connection) (MigrationBox, error)

NewMigrationBox from a packr.Box and a Connection.

type Migrations

type Migrations []Migration

Migrations is a collection of Migration

func (Migrations) Len

func (mfs Migrations) Len() int

func (Migrations) Less

func (mfs Migrations) Less(i, j int) bool

func (Migrations) Swap

func (mfs Migrations) Swap(i, j int)

type Migrator

type Migrator struct {
	Connection *Connection
	SchemaPath string
	Migrations map[string]Migrations
}

Migrator forms the basis of all migrations systems. It does the actual heavy lifting of running migrations. When building a new migration system, you should embed this type into your migrator.

func NewMigrator

func NewMigrator(c *Connection) Migrator

NewMigrator returns a new "blank" migrator. It is recommended to use something like MigrationBox or FileMigrator. A "blank" Migrator should only be used as the basis for a new type of migration system.

func (Migrator) CreateSchemaMigrations

func (m Migrator) CreateSchemaMigrations() error

CreateSchemaMigrations sets up a table to track migrations. This is an idempotent operation.

func (Migrator) Down

func (m Migrator) Down(step int) error

Down runs pending "down" migrations and rolls back the database by the specified number of steps.

func (Migrator) DumpMigrationSchema

func (m Migrator) DumpMigrationSchema() error

DumpMigrationSchema will generate a file of the current database schema based on the value of Migrator.SchemaPath

func (Migrator) Reset

func (m Migrator) Reset() error

Reset the database by running the down migrations followed by the up migrations.

func (Migrator) Status

func (m Migrator) Status() error

Status prints out the status of applied/pending migrations.

func (Migrator) Up

func (m Migrator) Up() error

Up runs pending "up" migrations and applies them to the database.

func (Migrator) UpLogOnly

func (m Migrator) UpLogOnly() error

UpLogOnly insert pending "up" migrations logs only, without applying the patch. It's used when loading the schema dump, instead of the migrations.

type Model

type Model struct {
	Value

	As string
	// contains filtered or unexported fields
}

Model is used throughout Pop to wrap the end user interface that is passed in to many functions.

func (*Model) ID

func (m *Model) ID() interface{}

ID returns the ID of the Model. All models must have an `ID` field this is of type `int`,`int64` or of type `uuid.UUID`.

func (*Model) PrimaryKeyType

func (m *Model) PrimaryKeyType() string

PrimaryKeyType gives the primary key type of the `Model`.

func (*Model) TableName

func (m *Model) TableName() string

TableName returns the corresponding name of the underlying database table for a given `Model`. See also `TableNameAble` to change the default name of the table.

type PaginationParams

type PaginationParams interface {
	Get(key string) string
}

PaginationParams is a parameters provider interface to get the pagination params from

type Paginator

type Paginator struct {
	// Current page you're on
	Page int `json:"page"`
	// Number of results you want per page
	PerPage int `json:"per_page"`
	// Page * PerPage (ex: 2 * 20, Offset == 40)
	Offset int `json:"offset"`
	// Total potential records matching the query
	TotalEntriesSize int `json:"total_entries_size"`
	// Total records returns, will be <= PerPage
	CurrentEntriesSize int `json:"current_entries_size"`
	// Total pages
	TotalPages int `json:"total_pages"`
}

Paginator is a type used to represent the pagination of records from the database.

func NewPaginator

func NewPaginator(page int, perPage int) *Paginator

NewPaginator returns a new `Paginator` value with the appropriate defaults set.

func NewPaginatorFromParams

func NewPaginatorFromParams(params PaginationParams) *Paginator

NewPaginatorFromParams takes an interface of type `PaginationParams`, the `url.Values` type works great with this interface, and returns a new `Paginator` based on the params or `PaginatorPageKey` and `PaginatorPerPageKey`. Defaults are `1` for the page and PaginatorPerPageDefault for the per page value.

func (Paginator) String

func (p Paginator) String() string

type Query

type Query struct {
	RawSQL *clause

	Paginator  *Paginator
	Connection *Connection
	// contains filtered or unexported fields
}

Query is the main value that is used to build up a query to be executed against the `Connection`.

func Q

func Q(c *Connection) *Query

Q will create a new "empty" query from the current connection.

func (*Query) All

func (q *Query) All(models interface{}) error

All retrieves all of the records in the database that match the query.

q.Where("name = ?", "mark").All(&[]User{})

func (*Query) BelongsTo

func (q *Query) BelongsTo(model interface{}) *Query

BelongsTo adds a "where" clause based on the "ID" of the "model" passed into it.

func (*Query) BelongsToAs

func (q *Query) BelongsToAs(model interface{}, as string) *Query

BelongsToAs adds a "where" clause based on the "ID" of the "model" passed into it, using an alias.

func (*Query) BelongsToThrough

func (q *Query) BelongsToThrough(bt, thru interface{}) *Query

BelongsToThrough adds a "where" clause that connects the "bt" model through the associated "thru" model.

func (*Query) Clone

func (q *Query) Clone(targetQ *Query)

Clone will fill targetQ query with the connection used in q, if targetQ is not empty, Clone will override all the fields.

func (Query) Count

func (q Query) Count(model interface{}) (int, error)

Count the number of records in the database.

q.Where("name = ?", "mark").Count(&User{})

func (Query) CountByField

func (q Query) CountByField(model interface{}, field string) (int, error)

CountByField counts the number of records in the database, for a given field.

q.Where("sex = ?", "f").Count(&User{}, "name")

func (*Query) Eager

func (q *Query) Eager(fields ...string) *Query

Eager will enable load associations of the model. by defaults loads all the associations on the model, but can take a variadic list of associations to load.

q.Eager().Find(model, 1) // will load all associations for model.
q.Eager("Books").Find(model, 1) // will load only Book association for model.

func (*Query) Exec

func (q *Query) Exec() error

Exec runs the given query.

func (*Query) ExecWithCount

func (q *Query) ExecWithCount() (int, error)

ExecWithCount runs the given query, and returns the amount of affected rows.

func (*Query) Exists

func (q *Query) Exists(model interface{}) (bool, error)

Exists returns true/false if a record exists in the database that matches the query.

q.Where("name = ?", "mark").Exists(&User{})

func (*Query) Find

func (q *Query) Find(model interface{}, id interface{}) error

Find the first record of the model in the database with a particular id.

q.Find(&User{}, 1)

func (*Query) First

func (q *Query) First(model interface{}) error

First record of the model in the database that matches the query.

q.Where("name = ?", "mark").First(&User{})

func (*Query) GroupBy

func (q *Query) GroupBy(field string, fields ...string) *Query

GroupBy will append a GROUP BY clause to the query

func (*Query) Having

func (q *Query) Having(condition string, args ...interface{}) *Query

Having will append a HAVING clause to the query

func (*Query) Join

func (q *Query) Join(table string, on string, args ...interface{}) *Query

Join will append a JOIN clause to the query

func (*Query) Last

func (q *Query) Last(model interface{}) error

Last record of the model in the database that matches the query.

q.Where("name = ?", "mark").Last(&User{})

func (*Query) LeftInnerJoin

func (q *Query) LeftInnerJoin(table string, on string, args ...interface{}) *Query

LeftInnerJoin will append a LEFT INNER JOIN clause to the query

func (*Query) LeftJoin

func (q *Query) LeftJoin(table string, on string, args ...interface{}) *Query

LeftJoin will append a LEFT JOIN clause to the query

func (*Query) LeftOuterJoin

func (q *Query) LeftOuterJoin(table string, on string, args ...interface{}) *Query

LeftOuterJoin will append a LEFT OUTER JOIN clause to the query

func (*Query) Limit

func (q *Query) Limit(limit int) *Query

Limit will add a limit clause to the query.

func (*Query) Order

func (q *Query) Order(stmt string) *Query

Order will append an order clause to the query.

q.Order("name desc")

func (*Query) Paginate

func (q *Query) Paginate(page int, perPage int) *Query

Paginate records returned from the database.

q = q.Paginate(2, 15)
q.All(&[]User{})
q.Paginator

func (*Query) PaginateFromParams

func (q *Query) PaginateFromParams(params PaginationParams) *Query

PaginateFromParams paginates records returned from the database.

q = q.PaginateFromParams(req.URL.Query())
q.All(&[]User{})
q.Paginator

func (*Query) RawQuery

func (q *Query) RawQuery(stmt string, args ...interface{}) *Query

RawQuery will override the query building feature of Pop and will use whatever query you want to execute against the `Connection`. You can continue to use the `?` argument syntax.

q.RawQuery("select * from foo where id = ?", 1)

func (*Query) RightInnerJoin

func (q *Query) RightInnerJoin(table string, on string, args ...interface{}) *Query

RightInnerJoin will append a RIGHT INNER JOIN clause to the query

func (*Query) RightJoin

func (q *Query) RightJoin(table string, on string, args ...interface{}) *Query

RightJoin will append a RIGHT JOIN clause to the query

func (*Query) RightOuterJoin

func (q *Query) RightOuterJoin(table string, on string, args ...interface{}) *Query

RightOuterJoin will append a RIGHT OUTER JOIN clause to the query

func (*Query) Scope

func (q *Query) Scope(sf ScopeFunc) *Query

Scope the query by using a `ScopeFunc`

func ByName(name string) ScopeFunc {
	return func(q *Query) *Query {
		return q.Where("name = ?", name)
	}
}

func WithDeleted(q *pop.Query) *pop.Query {
	return q.Where("deleted_at is null")
}

c.Scope(ByName("mark)).Scope(WithDeleted).First(&User{})

func (*Query) Select

func (q *Query) Select(fields ...string) *Query

Select allows to query only fields passed as parameter. c.Select("field1", "field2").All(&model) => SELECT field1, field2 FROM models

func (Query) ToSQL

func (q Query) ToSQL(model *Model, addColumns ...string) (string, []interface{})

ToSQL will generate SQL and the appropriate arguments for that SQL from the `Model` passed in.

func (*Query) Where

func (q *Query) Where(stmt string, args ...interface{}) *Query

Where will append a where clause to the query. You may use `?` in place of arguments.

q.Where("id = ?", 1)
q.Where("id in (?)", 1, 2, 3)

type ScopeFunc

type ScopeFunc func(q *Query) *Query

ScopeFunc applies a custom operation on a given `Query`

type TableNameAble

type TableNameAble interface {
	TableName() string
}

TableNameAble interface allows for the customize table mapping between a name and the database. For example the value `User{}` will automatically map to "users". Implementing `TableNameAble` would allow this to change to be changed to whatever you would like.

type Tx

type Tx struct {
	ID int
	*sqlx.Tx
}

Tx stores a transaction with an ID to keep track.

func (*Tx) Close

func (tx *Tx) Close() error

Close does nothing. This is defined so it implements the `Store` interface.

func (*Tx) Transaction

func (tx *Tx) Transaction() (*Tx, error)

Transaction simply returns the current transaction, this is defined so it implements the `Store` interface.

type Value

type Value interface{}

Value is the contents of a `Model`.

Directories

Path Synopsis
cmd

Jump to

Keyboard shortcuts

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