diff --git a/README.md b/README.md index 19bac4846b31682064d1fcd5ef1776df40445815..2cb2f070a6d42853d823208f57739e0be801a579 100644 --- a/README.md +++ b/README.md @@ -1,24 +1,30 @@ # upper.io/db -`upper.io/db` is a [Go][2] package that allows developers to store and retrive -data to and from different kinds of databases through the use of adapters that -wrap well supported database drivers. +`upper.io/db` is a [Go][2] package that allows developers to communicate with +different databases through the use of *adapters* that wrap well-supported +database drivers. + +See the project page, recipes and user documentation at [upper.io/db][1]. + +[](https://travis-ci.org/upper/db) + +## Is this an ORM? `upper.io/db` is not an ORM, but you may not need one at all: ```go // This code works the same for all supported databases. var people []Person -res = col.Find(db.Cond{"name": "Max"}).Skip(1).Limit(2).Sort("-input") +res = col.Find(db.Cond{"name": "Max"}).Limit(10).Sort("-last_name") err = res.All(&people) ``` -See the project page, recipes and user documentation at [upper.io/db][1]. - -[](https://travis-ci.org/upper/db) - ## Supported databases +`upper.io/db` attempts to provide full compatiblity for [CRUD][2] operations +across adapters. Some other operations (such *transactions*) are supported only +on specific database adapters, such as MySQL, PostgreSQL and SQLite. + * [MongoDB](https://upper.io/db/mongo) via [mgo](http://godoc.org/labix.org/v2/mgo) * [MySQL](https://upper.io/db/mysql) via [mysql](https://github.com/go-sql-driver/mysql) * [PostgreSQL](https://upper.io/db/postgresql) via [pq](https://github.com/lib/pq) @@ -50,3 +56,4 @@ See the project page, recipes and user documentation at [upper.io/db][1]. [1]: https://upper.io/db [2]: http://golang.org +[3]: http://en.wikipedia.org/wiki/Create,_read,_update_and_delete diff --git a/main.go b/main.go index 93ef059d6c2129da2936867c7294e97d3e5ec635..a3a1990649cdfedc56e9da9aed1f81f3ae66be48 100644 --- a/main.go +++ b/main.go @@ -1,117 +1,178 @@ -/* - Copyright (c) 2012-2014 José Carlos Nieto, https://menteslibres.net/xiam - - Permission is hereby granted, free of charge, to any person obtaining - a copy of this software and associated documentation files (the - "Software"), to deal in the Software without restriction, including - without limitation the rights to use, copy, modify, merge, publish, - distribute, sublicense, and/or sell copies of the Software, and to - permit persons to whom the Software is furnished to do so, subject to - the following conditions: - - The above copyright notice and this permission notice shall be - included in all copies or substantial portions of the Software. - - THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, - EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND - NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE - LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION - OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION - WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -*/ - -// upper.io/db is a package that deals with saving and retrieving data from -// different databases using a reduced instruction set. +// Copyright (c) 2012-2014 José Carlos Nieto, https://menteslibres.net/xiam +// +// Permission is hereby granted, free of charge, to any person obtaining +// a copy of this software and associated documentation files (the +// "Software"), to deal in the Software without restriction, including +// without limitation the rights to use, copy, modify, merge, publish, +// distribute, sublicense, and/or sell copies of the Software, and to +// permit persons to whom the Software is furnished to do so, subject to +// the following conditions: +// +// The above copyright notice and this permission notice shall be +// included in all copies or substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + +// The upper.io/db package allows developers to communicate with different +// databases through the use of adapters that wrap well-supported database +// drivers. +// +// Usage: +// +// import( +// // Main package. +// "upper.io/db" +// // PostgreSQL adapter. +// "upper.io/db/postgresql" +// ) package db -/* - The db.Cond{} expression is used to define conditions in a query, it can be - viewed as a replacement for the SQL "WHERE" clause. - - Examples: - - db.Cond { "age": 18 } // Where age equals 18. - - db.Cond { "age >=": 18 } // Where age is greater than or equal to 18. - - db.Cond { "age $lt": 18 } // Where age is lower than 18 (MongoDB specific). -*/ +// The `db.Cond{}` expression is used to define conditions in a statement. +// +// Examples: +// +// // Where age equals 18. +// db.Cond { "age": 18 } +// +// Where age is greater than or equal to 18. +// db.Cond { "age >=": 18 } +// +// Where age is lower than 18 (On MongoDB context). +// db.Cond { "age $lt": 18 } type Cond map[string]interface{} -/* - The db.Func expression is used to represent database functions. -*/ +// The `db.Func{}` expression is used to represent database functions. +// +// Examples: +// +// // MOD(29, 9) +// db.Func{"MOD", []int{29, 9}} +// +// // CONCAT("foo", "bar") +// db.Func{"CONCAT", []string{"foo", "bar"}} +// +// // NOW() +// db.Func{"NOW"} +// +// // RTRIM("Hello ") +// db.Func{"RTRIM", "Hello "} type Func struct { Name string Args interface{} } -/* - The db.And() expression is used to glue two or more expressions under logical - conjunction, it accepts db.Cond{}, db.Or() and other db.And() expressions. - - Examples: - - db.And ( - db.Cond { "name": "Peter" }, - db.Cond { "last_name": "Parker "}, - ) - - db.And ( - db.Or ( - db.Cond{ "name": "Peter" }, - db.Cond{ "name": "Mickey" }, - ), - db.Cond{ "last_name": "Mouse" }, - ) -*/ +// The `db.And{}` expression is used to join two or more expressions under +// logical conjunction, it accepts `db.Cond{}`, `db.Or{}`, `db.Raw{}` and other +// `db.And{}` expressions. +// +// Examples: +// +// // SQL: name = "Peter" AND last_name = "Parker" +// db.And ( +// db.Cond { "name": "Peter" }, +// db.Cond { "last_name": "Parker "}, +// ) +// +// // SQL: (name = "Peter" OR name = "Mickey") AND last_name = "Mouse" +// db.And { +// db.Or { +// db.Cond{ "name": "Peter" }, +// db.Cond{ "name": "Mickey" }, +// }, +// db.Cond{ "last_name": "Mouse" }, +// } type And []interface{} -/* - The db.Or() expression is used to glue two or more expressions under logical - disjunction, it accepts db.Cond{}, db.And() and other db.Or() expressions. - - Example: - - db.Or ( - db.Cond { "year": 2012 }, - db.Cond { "year": 1987 }, - ) -*/ +// The `db.Or{}` expression is used to glue two or more expressions under +// logical disjunction, it accepts `db.Cond{}`, `db.And{}`, `db.Raw{}` and +// other `db.Or{}` expressions. +// +// Example: +// +// // SQL: year = 2012 OR year = 1987 +// db.Or { +// db.Cond{"year": 2012}, +// db.Cond{"year": 1987}, +// } type Or []interface{} +// The `db.Raw{}` expression is mean to hold chunks of data to be passed to the +// database without any filtering. +// +// When using `db.Raw{}`, the developer is responsible of providing a sanitized +// instruction to the database. +// +// The `db.Raw{}` expression is allowed as element on `db.Cond{}`, `db.And{}`, +// `db.Or{}` expressions and as argument on `db.Result.Select()` and +// `db.Collection.Find()` methods. +// +// Example: +// +// // SQL: SOUNDEX('Hello') +// Raw{"SOUNDEX('Hello')"} type Raw struct { Value interface{} } -// Connection and authentication data. +// The `db.Settings{}` struct holds database connection and authentication +// data. Not all fields must be supplied, is any field is skipped, the database +// adapter will either try to use database defaults or return an error. Refer +// to the specific adapter to see which fields are required. +// +// Example: +// +// db.Settings{ +// Host: "127.0.0.1", +// Database: "tests", +// User: "john", +// Password: "doe", +// } type Settings struct { - // Database server hostname or IP. Leave blank if using unix sockets. + // Database server hostname or IP. This field is ignored if using unix + // sockets or if the database does not require a connection to any host + // (SQLite, QL). Host string - // Database server port. Leave blank if using unix sockets. + // Database server port. This field is ignored if using unix sockets or if + // the database does not require a connection to any host (SQLite, QL). If + // not provided, the default database port is tried. Port int - // Name of the database. + // Name of the database. You can also use a filename if the database supports + // opening a raw file (SQLite, QL). Database string - // Username for authentication. + // Username for authentication, if required. User string - // Password for authentication. + // Password for authentication, if required. Password string - // A path of a UNIX socket file. Leave blank if using host and port. + // A path to a UNIX socket file. Leave blank if you rather use host and port. Socket string - // Database charset. + // Database charset. You can leave this field blank to use the default + // database charset. Charset string } -// Database methods. +// The `db.Database` interface defines methods that all adapters must provide. type Database interface { - // Returns the underlying driver the wrapper uses as an interface{}. + // Returns the underlying driver the wrapper uses. As an `interface{}`. + // + // In order to actually use the `interface{}` you must cast it to the known + // database driver type. + // + // Example: + // internalSQLDriver := sess.Driver().(*sql.DB) Driver() interface{} - // Attempts to stablish a connection with the database server. + // Attempts to stablish a connection with the database server, a previous + // call to Setup() is required. Open() error - // Clones the current database session. + // Clones the current database session. Returns an error if the clone could + // not be carried out. Clone() (Database, error) // Returns error if the database server cannot be reached. @@ -120,75 +181,108 @@ type Database interface { // Closes the currently active connection to the database. Close() error - // Returns a db.Collection struct by name. + // Returns a `db.Collection{}` struct by name. Some databases support + // collections of more than one source or table, refer to the documentation + // of the specific database adapter to see if using multiple sources is + // supported. Collection(...string) (Collection, error) - // Returns the names of all non-system collections within the active + // Returns the names of all non-system sources or tables within the active // database. Collections() ([]string, error) - // Switches the active database. + // Attempts to connect to another database using the same connection + // settings. Similar to MySQL's `USE` instruction. Use(string) error // Drops the active database. Drop() error - // Sets database connection settings. + // Sets the database connection settings. In order to connect, a call to + // `db.Database.Open()` is required. Setup(Settings) error // Returns the name of the active database. Name() string - // Starts a transaction block (if the database supports transactions). + // Starts a transaction block. Some databases do not support transactions, + // refer to the documentation of the specific database adapter to see the + // current status on transactions. Transaction() (Tx, error) } -// A transaction is basically a copy of the Database interface{} with an -// additional method. +// The `db.Tx` interface provides the same methods that the `db.Interface` +// does, plus some other that help the user deal with database transactions. In +// order to get a proper `db.Tx` interface the `db.Database.Transaction()` +// method must be called on an already opened database session. +// +// Example: +// ... +// if sess, err = db.Open(postgresql.Adapter, settings); err != nil { +// log.Fatal(err) +// } +// +// var tx db.Tx +// if tx, err = sess.Transaction(); err != nil { +// log.Fatal(err) +// } +// +// var artist db.Collection +// if artist, err = tx.Collection("artist"); err != nil { +// log.Fatal(err) +// } +// ... type Tx interface { Database + // Discards all the instructions issued during the transaction. Rollback() error + // Verifies that all the instructions isssued during the transaction were + // executed. Commit() error } -// Collection methods. +// The `db.Collection` interface defines methods for handling data sources or +// tables. type Collection interface { - // Inserts a new item into the collection. Can work with maps or structs. + // Inserts a new item into the collection. Accepts a map or a struct as + // argument. Append(interface{}) (interface{}, error) // Returns true if the collection exists. Exists() bool - // Creates a filter with the given conditions and returns a result set. + // Sets a filter on the collection with the given conditions and returns a + // result set. Find(...interface{}) Result - // Truncates the collection. + // Removes all elements on the collection and resets the IDs. Truncate() error // Returns the name of the collection. Name() string } -// Result methods. +// The `db.Result` interface defines methods for working with result sets. type Result interface { - // Defines the maximum number of results on this set. + + // Defines the maximum number of results in this set. Limit(uint) Result - // Skips over the n initial results from a query. + // Skips over the *n* initial results. Skip(uint) Result - // Receives fields that define the order in which elements will be returned in - // a query, field names may be prefixed with a minus sign (-) indicating - // descending order; ascending order would be used otherwise. + // Receives fields that define the order in which elements will be returned + // in a query, field names may be prefixed with a minus sign (-) indicating + // descending order; ascending order would be used by default. Sort(...string) Result - // Defines specific fields to be returned on results on this result set. + // Defines specific fields to be fulfilled on results in this result set. Select(...interface{}) Result - // Sets conditions. + // Discards the initial filtering conditions and sets new ones. Where(...interface{}) Result // Removes all items within the result set. @@ -219,6 +313,13 @@ type Result interface { Close() error } -var ( - EnvEnableDebug = `UPPERIO_DB_DEBUG` -) +// If the user sets the `UPPERIO_DB_DEBUG` environment variable to a +// non-empty value, all generated statements will be printed at runtime to +// the standard logger. +// +// Example: +// +// UPPERIO_DB_DEBUG=1 go test +// +// UPPERIO_DB_DEBUG=1 ./go-program +var EnvEnableDebug = `UPPERIO_DB_DEBUG`