database

package module
v1.0.0 Latest Latest
Warning

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

Go to latest
Published: Dec 2, 2018 License: MIT Imports: 8 Imported by: 2

README

database

GoDoc Build Status

Database helper to read and write models.

Install
go get github.com/altipla-consulting/database
Contributing

You can make pull requests or create issues in GitHub. Any code you send should be formatted using gofmt.

Running tests

Download any dependency your system may need:

make deps

Then run the tests and configure a local MySQL instance for them:

make test
License

MIT License

Documentation

Overview

Package database writes and reads structs to SQL tables and helps building the queries with a very simple access model.

Index

Constants

This section is empty.

Variables

View Source
var (
	// ErrNoSuchEntity is returned from a Get operation when there is not a model
	// that matches the query
	ErrNoSuchEntity = errors.New("database: no such entity")

	// ErrDone is returned from the Next() method of an iterator when all results
	// have been read.
	ErrDone = errors.New("query has no more results")

	// ErrConcurrentTransaction is returned when trying to update a model that has been
	// updated in the background by other process. This errors will prevent you from
	// potentially overwriting those changes.
	ErrConcurrentTransaction = errors.New("database: concurrent transaction")
)

Functions

func EscapeLike

func EscapeLike(str string) string

EscapeLike escapes a value to insert it in a LIKE query without unexpected wildcards. After using this function to clean the value you can add the wildcards you need to the query.

Types

type Collection

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

Collection represents a table. You can apply further filters and operations to the collection and then query it with one of our read methods (Get, GetAll, ...) or use it to store new items (Put).

func (*Collection) Alias

func (c *Collection) Alias(alias string) *Collection

Alias changes the name of the table in the SQL query. It is useful in combination with FilterExists() to have a stable name for the tables that should be filtered.

func (*Collection) Clone

func (c *Collection) Clone() *Collection

Clone returns a new collection with the same filters and configuration of the original one.

func (*Collection) Count

func (c *Collection) Count() (int64, error)

Count queries the number of rows that the collection matches.

func (*Collection) Delete

func (c *Collection) Delete(instance Model) error

Delete removes a model from a collection. It uses the filters and the model primary key to find the row to remove, so it can return an error even if the PK exists when the filters do not match. Limits won't be applied but the offset of the collection will.

func (*Collection) Filter

func (c *Collection) Filter(sql string, value interface{}) *Collection

Filter applies a new simple filter to the collection. See the global Filter function for documentation.

func (*Collection) FilterCond

func (c *Collection) FilterCond(condition Condition) *Collection

FilterCond applies a generic condition to the collection. We have some helpers in this library to build conditions; and other libraries (like github.com/altipla-consulting/geo) can implement their own conditions too.

func (*Collection) FilterExists

func (c *Collection) FilterExists(sub *Collection, join string) *Collection

FilterExists applies the global FilterExists condition to this collection. See the global function for documentation.

func (*Collection) FilterIsNil

func (c *Collection) FilterIsNil(column string) *Collection

FilterIsNil applies a new NULL filter to the collection. See the global FilterIsNil function for documentation.

func (*Collection) FilterIsNotNil

func (c *Collection) FilterIsNotNil(column string) *Collection

FilterIsNotNil applies a new NOT NULL filter to the collection. See the global FilterIsNotNil function for documentation.

func (*Collection) First

func (c *Collection) First(instance Model) error

First returns the first model that matches the collection. If no one is found it will return ErrNoSuchEntity and it won't touch model.

func (*Collection) Get

func (c *Collection) Get(instance Model) error

Get retrieves the model matching the collection filters and the model primary key. If no model is found ErrNoSuchEntity will be returned and the model won't be touched.

func (*Collection) GetAll

func (c *Collection) GetAll(models interface{}) error

GetAll receives a pointer to an empty slice of models and retrieves all the models that match the filters of the collection. Take care to avoid fetching large collections of models or you will run out of memory.

func (*Collection) GetMulti

func (c *Collection) GetMulti(keys interface{}, models interface{}) error

GetMulti queries multiple rows and return all of them in a list. Keys should be a list of primary keys to retrieve and models should be a pointer to an empty slice of models. If any of the primary keys is not found a MultiError will be returned. You can check the error type for MultiError and then loop over the list of errors, they will be in the same order as the keys and they will have nil's when the row is found. The result list will also have the same length as keys with nil's filled when the row is not found.

func (*Collection) Iterator

func (c *Collection) Iterator() (*Iterator, error)

Iterator returns a new iterator that can be used to extract models one by one in a loop. You should close the Iterator after you are done with it.

func (*Collection) Limit

func (c *Collection) Limit(limit int64) *Collection

Limit adds a maximum number of results to the query.

func (*Collection) Offset

func (c *Collection) Offset(offset int64) *Collection

Offset moves the initial position of the query. In combination with Limit it allows you to paginate the results.

func (*Collection) Order

func (c *Collection) Order(column string) *Collection

Order the collection of items. You can pass "column" for ascendent order or "-column" for descendent order. If you want to order by mutliple columns call Order multiple times for each column, the will be joined.

func (*Collection) OrderSorter

func (c *Collection) OrderSorter(sorter Sorter) *Collection

OrderSorter sorts the collection of items. We have some helpers in this library to build sorters; and other libraries (like github.com/altipla-consulting/geo) can implement their own sorters too.

func (*Collection) Put

func (c *Collection) Put(instance Model) error

Put stores a new item of the collection. Any filter or limit of the collection won't be applied.

func (*Collection) Truncate

func (c *Collection) Truncate() error

Truncate removes every single row of a table. It also resets any autoincrement value it may have to the value "1".

type Condition

type Condition interface {
	// SQL returns the portion of the code that will be merged inside the WHERE
	// query. It can have placeholders with "?" to fill them apart.
	SQL() string

	// Values returns the list of placeholders values we should fill.
	Values() []interface{}
}

Condition should be implemented by any generic SQL condition we can apply to collections.

func And

func And(children []Condition) Condition

And applies an AND operation between each of the children conditions.

func CompareJSON

func CompareJSON(column, path string, value interface{}) Condition

CompareJSON creates a new condition that checks if a value inside a JSON object of a column is equal to the provided value.

func Filter

func Filter(sql string, value interface{}) Condition

Filter applies a new simple filter to the collection. There are multiple types of simple filters depending on the SQL you pass to it:

Filter("foo", "bar")
Filter("foo >", 3)
Filter("foo LIKE", "%bar%")
Filter("DATE_DIFF(?, mycolumn) > 30", time.Now())

func FilterExists

func FilterExists(sub *Collection, join string) Condition

FilterExists checks if a subquery matches for each row before accepting it. It will use the join SQL statement as an additional filter to those ones both queries have to join the rows of two queries. Not having a join statement will throw a panic.

No external parameters are allowed in the join statement because they can be supplied through normal filters in both collections. Limit yourself to relate both tables to make the FilterExists call useful.

You can alias both collections to use shorter names in the statement. It is recommend to always use aliases when referring to the columns in the join statement.

func FilterIsNil

func FilterIsNil(column string) Condition

FilterIsNil filter rows with with NULL in the column.

func FilterIsNotNil

func FilterIsNotNil(column string) Condition

FilterIsNotNil filter rows with with something other than NULL in the column.

func Or

func Or(children []Condition) Condition

Or applies an OR operation between each of the children conditions.

type Credentials

type Credentials struct {
	User, Password     string
	Address, Database  string
	Charset, Collation string
	Protocol           string
}

Credentials configures the authentication and address of the remote MySQL database.

func (Credentials) String

func (c Credentials) String() string

String returns the credentials with the exact format the Go MySQL driver needs to connect to it.

type Database

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

Database represents a reusable connection to a remote MySQL database.

func Open

func Open(credentials Credentials, options ...Option) (*Database, error)

Open starts a new connection to a remote MySQL database using the provided credentials

func (*Database) Close

func (db *Database) Close()

Close the connection. You should not use a database after closing it, nor any of its generated collections.

func (*Database) Collection

func (db *Database) Collection(model Model) *Collection

Collection prepares a new collection using the table name of the model. It won't make any query, it only prepares the structs.

func (*Database) Exec

func (db *Database) Exec(query string, params ...interface{}) error

Exec runs a raw SQL query in the database and returns nothing. It is recommended to use Collections instead.

func (*Database) QueryRow

func (db *Database) QueryRow(query string, params ...interface{}) *sql.Row

QueryRow runs a raw SQL query in the database and returns the raw row from MySQL. It is recommended to use Collections instead.

type Iterator

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

Iterator helps to loop through rows of a collection retrieving a single model each time.

func (*Iterator) Close

func (it *Iterator) Close()

Close finishes the iteration. Do not use the iterator after closing it.

func (*Iterator) Next

func (it *Iterator) Next(model Model) error

Next retrieves the next model of the list. It may or may communicate with the database depending on the local cache it has in every loop iteration.

When the iterator reaches the end of the collection it returns ErrDone.

type Model

type Model interface {
	// TableName returns the name of the table that should store this model. We
	// recommend a simple return with the string, though it can be dynamic too
	// if you really know what you are doing.
	TableName() string

	// Tracking returns the Tracking side helper that stores state about the model.
	Tracking() *ModelTracking
}

Model should be implemented by any model that want to be serializable to SQL.

type ModelTracking

type ModelTracking struct {
	Revision int64
	// contains filtered or unexported fields
}

ModelTracking is a struct you can inherit to implement the model interface. Insert directly inline in your struct without pointers or names and it will provide you with all the functionality needed to make the struct a Model, except for the TableName() function that you should implement yourself.

func (*ModelTracking) AfterDelete

func (tracking *ModelTracking) AfterDelete(props []*Property) error

AfterDelete is a hook called after a model is deleted from the database.

func (*ModelTracking) AfterGet

func (tracking *ModelTracking) AfterGet(props []*Property) error

AfterGet is a hook called after a model is retrieved from the database.

func (*ModelTracking) AfterPut

func (tracking *ModelTracking) AfterPut(props []*Property) error

AfterPut is a hook called after a model is updated or inserted in the database.

func (*ModelTracking) IsInserted

func (tracking *ModelTracking) IsInserted() bool

IsInserted returns true if the model has been previously retrieved from the database.

func (*ModelTracking) StoredRevision

func (tracking *ModelTracking) StoredRevision() int64

StoredRevision returns the stored revision when the model was retrieved. It can be -1 signalling that the model is a new one.

func (*ModelTracking) Tracking

func (tracking *ModelTracking) Tracking() *ModelTracking

Tracking returns the tracking instance of a model.

type MultiError

type MultiError []error

MultiError stores a list of error when retrieving multiple models and only some of them may fail.

func (MultiError) Error

func (merr MultiError) Error() string

func (MultiError) HasError

func (merr MultiError) HasError() bool

HasError returns if the multi error really contains any error or all the rows have been successfully retrieved. You don't have to check this method most of the time because GetMulti, GetAll, etc. will return nil if there is no errors instead of an empty MultiErrorto avoid hard to debug bugs.

type OnAfterPutHooker

type OnAfterPutHooker interface {
	OnAfterPutHook() error
}

OnAfterPutHooker can be implemented by any model to receive a call every time the model is saved to the database.

type OnBeforePutHooker

type OnBeforePutHooker interface {
	OnBeforePutHook() error
}

OnBeforePutHooker can be implemented by any model to receive a call every time the model is retrieved from the database. When multiple models are retrieved (GetMulti, GetAll, ...) every single model will receive the hook individually.

type Option

type Option func(db *Database)

Option can be passed when opening a new connection to a database.

func WithDebug

func WithDebug(debug bool) Option

WithDebug is a database option that enables debug logging in the library.

type Property

type Property struct {
	// Name of the column. Already escaped.
	Name string

	// Struct field name.
	Field string

	// Value of the field.
	Value interface{}

	// Pointer to the value of the field.
	Pointer interface{}

	// True if it's a primary key.
	PrimaryKey bool

	// Omit the column when the value is empty.
	OmitEmpty bool
}

Property represents a field of the model mapped to a database column.

type Sorter

type Sorter interface {
	// SQL returns the portion of the code that will be merged to the query.
	SQL() string
}

Sorter should be implemented by any generic SQL order we can apply to collections.

Jump to

Keyboard shortcuts

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