diff --git a/config.go b/config.go
index 26cb1523f8c12786bae5734c41736c0e3d6bb16c..f0e34e8249e83f3c79ea5a6dc0f7f5e8e8f5e27c 100644
--- a/config.go
+++ b/config.go
@@ -1,3 +1,24 @@
+// Copyright (c) 2012-present The upper.io/db authors. All rights reserved.
+//
+// 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.
+
 package db
 
 import (
@@ -5,8 +26,7 @@ import (
 	"sync/atomic"
 )
 
-// Settings defines methods to get or set configuration settings, use db.Conf
-// to get or set global configuration settings.
+// Settings defines methods to get or set configuration values.
 type Settings interface {
 	// SetLogging enables or disables logging.
 	SetLogging(bool)
@@ -15,7 +35,7 @@ type Settings interface {
 
 	// SetLogger defines which logger to use.
 	SetLogger(Logger)
-	// Returns the configured logger.
+	// Returns the currently configured logger.
 	Logger() Logger
 }
 
@@ -60,5 +80,5 @@ func (c *conf) LoggingEnabled() bool {
 	return false
 }
 
-// Conf has global configuration settings for upper-db.
+// Conf provides global configuration settings for upper-db.
 var Conf Settings = &conf{}
diff --git a/db.go b/db.go
index 877c300d4e7944115697da0ab3f94d4cfce95fb8..a5de8ad5f7b162cb5beb21030c470746ab4f410b 100644
--- a/db.go
+++ b/db.go
@@ -19,12 +19,12 @@
 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
 
-// Package db provides a common interface to work with different data sources
-// using adapters that wrap mature database drivers.
+// Package db (or upper-db) provides a common interface to work with different
+// data sources using adapters that wrap mature database drivers.
 //
-// The main purpose of db is to abstract common database operations and
+// The main purpose of upper-db is to abstract common database operations and
 // encourage users perform advanced operations directly using the underlying
-// driver.  db supports the MySQL, PostgreSQL, SQLite and QL databases and
+// driver. upper-db supports the MySQL, PostgreSQL, SQLite and QL databases and
 // provides partial support (CRUD, no transactions) for MongoDB.
 //
 //  go get upper.io/db.v2
@@ -73,7 +73,7 @@
 //  }
 //
 // See more usage examples and documentation for users at
-// http://beta.upper.io/db.v2.
+// https://upper.io/db.v2.
 package db // import "upper.io/db.v2"
 
 import (
@@ -82,22 +82,38 @@ import (
 	"time"
 )
 
-// Constraint interface represents a condition.
+// Constraint interface represents a single condition, like "a = 1".  where `a`
+// is the key and `1` is the value. This is an exported interface but it's
+// rarely used directly, you may want to use the `db.Cond{}` map instead.
 type Constraint interface {
+	// Key is the leftmost part of the constraint and usually contains a column
+	// name.
 	Key() interface{}
+
+	// Value if the rightmost part of the constraint and usually contains a
+	// column value.
 	Value() interface{}
 }
 
-// Constraints interface represents an array of constraints.
+// Constraints interface represents an array or constraints, like "a = 1, b =
+// 2, c = 3".
 type Constraints interface {
+	// Constraints returns an array of constraints.
 	Constraints() []Constraint
 }
 
-// Compound represents an statement that has one or many sentences joined by a
-// compound operator, like AND or OR.
+// Compound represents an statement that has one or many sentences joined by by
+// an operator like "AND" or "OR". This is an exported interface but it's
+// rarely used directly, you may want to use the `db.And()` or `db.Or()`
+// functions instead.
 type Compound interface {
+	// Sentences returns child sentences.
 	Sentences() []Compound
+
+	// Operator returns the operator that joins the compound's child sentences.
 	Operator() CompoundOperator
+
+	// Empty returns true if the compound has zero children, false otherwise.
 	Empty() bool
 }
 
@@ -111,34 +127,49 @@ const (
 	OperatorOr
 )
 
-// RawValue interface represents values that can bypass SQL filters. Use with
-// care.
+// RawValue interface represents values that can bypass SQL filters. This is an
+// exported interface but it's rarely used directly, you may want to use
+// the `db.Raw()` function instead.
 type RawValue interface {
 	fmt.Stringer
 	Compound
+
+	// Raw returns the string representation of the value that the user wants to
+	// pass without any escaping.
 	Raw() string
+
+	// Arguments returns the arguments to be replaced on the query.
 	Arguments() []interface{}
 }
 
 // Function interface defines methods for representing database functions.
+// This is an exported interface but it's rarely used directly, you may want to
+// use the `db.Func()` function instead.
 type Function interface {
+	// Name returns the function name.
 	Name() string
+
+	// Argument returns the function arguments.
 	Arguments() []interface{}
 }
 
-// Marshaler is the interface implemented by struct fields that can marshal
-// themselves into a value that can be saved to a database.
+// Marshaler is the interface implemented by struct fields that can transform
+// themselves into values that can be stored on a database.
 type Marshaler interface {
+	// MarshalDB returns the internal database representation of the Go value.
 	MarshalDB() (interface{}, error)
 }
 
-// Unmarshaler is the interface implemented by struct fields that can unmarshal
-// themselves from database data into a Go value.
+// Unmarshaler is the interface implemented by struct fields that can transform
+// themselves from stored database values into Go values.
 type Unmarshaler interface {
+	// UnmarshalDB receives an internal database representation of a value and
+	// must transform that into a Go value.
 	UnmarshalDB(interface{}) error
 }
 
-// Cond is a map that defines conditions for a query.
+// Cond is a map that defines conditions for a query and satisfies the
+// Constraints and Compound interfaces.
 //
 // Each entry of the map represents a condition (a column-value relation bound
 // by a comparison operator). The comparison operator is optional and can be
@@ -155,7 +186,8 @@ type Unmarshaler interface {
 //  // Where id is in a list of ids.
 //  db.Cond{"id IN": []{1, 2, 3}}
 //
-//  // Where age is lower than 18 (mongodb-like operator).
+//  // Where age is lower than 18 (you could use this syntax when using
+//  // mongodb).
 //  db.Cond{"age $lt": 18}
 //
 //  // Where age > 32 and age < 35
@@ -253,7 +285,7 @@ func (c *compound) push(a ...Compound) *compound {
 	return c
 }
 
-// Union represents an OR compound.
+// Union represents a compound joined by OR.
 type Union struct {
 	*compound
 }
@@ -285,7 +317,7 @@ func (a *Intersection) Empty() bool {
 	return a.compound.Empty()
 }
 
-// Intersection represents an AND compound.
+// Intersection represents a compound joined by AND.
 type Intersection struct {
 	*compound
 }
@@ -313,7 +345,7 @@ func NewConstraint(key interface{}, value interface{}) Constraint {
 	return constraint{k: key, v: value}
 }
 
-// Func represents a database function.
+// Func represents a database function and satisfies the db.Function interface.
 //
 // Examples:
 //
@@ -398,6 +430,8 @@ func Or(conds ...Compound) *Union {
 //
 //	// SOUNDEX('Hello')
 //	Raw("SOUNDEX('Hello')")
+//
+// Raw returns a value that satifies the db.RawValue interface.
 func Raw(value string, args ...interface{}) RawValue {
 	r := rawValue{v: value, a: nil}
 	if len(args) > 0 {
@@ -460,23 +494,24 @@ type Tx interface {
 // Collection is an interface that defines methods useful for handling tables.
 type Collection interface {
 	// Insert inserts a new item into the collection, it accepts one argument
-	// that can be either a map or a struct. When the call is successful, it
-	// returns the ID of the newly added element as an interface (the underlying
-	// type of this ID depends on the database adapter). The ID returned by
-	// Insert() can be passed directly to Find() in order to retrieve the newly
-	// added element.
+	// that can be either a map or a struct. If the call suceeds, it returns the
+	// ID of the newly added element as an `interface{}` (the underlying type of
+	// this ID is unknown and depends on the database adapter). The ID returned
+	// by Insert() could be passed directly to Find() to retrieve the newly added
+	// element.
 	Insert(interface{}) (interface{}, error)
 
 	// InsertReturning is like Insert() but it updates the passed pointer to map
-	// or struct with the newly inserted element. This is all done automically
-	// within a transaction. If the database does not support transactions this
-	// method returns db.ErrUnsupported.
+	// or struct with the newly inserted element (and with automatic fields, like
+	// IDs, timestamps, etc). This is all done atomically within a transaction.
+	// If the database does not support transactions this method returns
+	// db.ErrUnsupported.
 	InsertReturning(interface{}) error
 
-	// Exists returns true if the collection exists.
+	// Exists returns true if the collection exists, false otherwise.
 	Exists() bool
 
-	// Find returns a result set with the given filters.
+	// Find defines a new result set with elements from the collection.
 	Find(...interface{}) Result
 
 	// Truncate removes all elements on the collection and resets the
@@ -511,7 +546,7 @@ type Result interface {
 	// set.
 	Select(...interface{}) Result
 
-	// Where discards the initial filtering conditions and sets new ones.
+	// Where resets the initial filtering conditions and sets new ones.
 	Where(...interface{}) Result
 
 	// Group is used to group results that have the same value in the same column
@@ -551,18 +586,24 @@ type Result interface {
 	// using All().
 	All(sliceOfStructs interface{}) error
 
-	// Close closes the result set.
+	// Close closes the result set and frees all locked resources.
 	Close() error
 }
 
-// ConnectionURL represents a connection string
+// ConnectionURL represents a connection string.
 type ConnectionURL interface {
 	// String returns the connection string that is going to be passed to the
 	// adapter.
 	String() string
 }
 
-// Ensure interface compatibility
+// Default limits for database/sql limit methods.
+var (
+	DefaultConnMaxLifetime = time.Duration(0) // 0 means reuse forever.
+	DefaultMaxIdleConns    = 10               // Keep 10 idle connections.
+	DefaultMaxOpenConns    = 0                // 0 means unlimited.
+)
+
 var (
 	_ Function    = &dbFunc{}
 	_ Constraints = Cond{}
@@ -570,10 +611,3 @@ var (
 	_ Constraint  = &constraint{}
 	_ RawValue    = &rawValue{}
 )
-
-// Default limits for database/sql limit methods.
-var (
-	DefaultConnMaxLifetime = time.Duration(0) // 0 means reuse forever.
-	DefaultMaxIdleConns    = 10               // Keep 10 idle connections.
-	DefaultMaxOpenConns    = 0                // 0 means unlimited.
-)
diff --git a/env.go b/env.go
index 6ff0cd39ad4ac724a61d31ba6f0821a2bbe9c8a4..70cbd63c07d4a211b63fa1954cb5bf9713dc349a 100644
--- a/env.go
+++ b/env.go
@@ -1,3 +1,24 @@
+// Copyright (c) 2012-present The upper.io/db authors. All rights reserved.
+//
+// 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.
+
 package db
 
 import (
diff --git a/errors.go b/errors.go
index afccfc4c5e0609c3f288c3fd610df0f06f9398fb..e6b160110b6631ead0830c476a147ea507c2193b 100644
--- a/errors.go
+++ b/errors.go
@@ -25,7 +25,7 @@ import (
 	"errors"
 )
 
-// Shared error messages.
+// Error messages.
 var (
 	ErrNoMoreRows               = errors.New(`upper: no more rows in this result set`)
 	ErrNotConnected             = errors.New(`upper: you're currently not connected`)
diff --git a/internal/cache/cache.go b/internal/cache/cache.go
index 826a5902434244f2dffc5d7a04707d062493f1ab..d81cebe246f6ff0f768cee0d986dbd4d66afbf71 100644
--- a/internal/cache/cache.go
+++ b/internal/cache/cache.go
@@ -83,8 +83,8 @@ func (c *Cache) Read(h Hashable) (string, bool) {
 // does not exists returns nil and false.
 func (c *Cache) ReadRaw(h Hashable) (interface{}, bool) {
 	c.mu.RLock()
+	defer c.mu.RUnlock()
 	data, ok := c.cache[h.Hash()]
-	c.mu.RUnlock()
 	if ok {
 		return data.Value.(*item).value, true
 	}
@@ -106,7 +106,7 @@ func (c *Cache) Write(h Hashable, value interface{}) {
 
 	c.cache[key] = c.li.PushFront(&item{key, value})
 
-	if c.li.Len() > c.capacity {
+	for c.li.Len() > c.capacity {
 		el := c.li.Remove(c.li.Back())
 		delete(c.cache, el.(*item).key)
 		if p, ok := el.(*item).value.(HasOnPurge); ok {
diff --git a/internal/sqladapter/database.go b/internal/sqladapter/database.go
index 26e7291fc782b6af2c1bcc75c3120a2c58d435cf..9d7370fd826287eb0ded04893827e7662b98ff44 100644
--- a/internal/sqladapter/database.go
+++ b/internal/sqladapter/database.go
@@ -19,7 +19,8 @@ var (
 	lastTxID   uint64
 )
 
-// HasCleanUp
+// HasCleanUp is implemented by structs that have a clean up routine that needs
+// to be called before Close().
 type HasCleanUp interface {
 	CleanUp() error
 }
@@ -257,8 +258,8 @@ func (d *database) StatementExec(stmt *exql.Statement, args ...interface{}) (res
 					status.RowsAffected = &rowsAffected
 				}
 
-				if lastInsertId, err := res.LastInsertId(); err == nil {
-					status.LastInsertID = &lastInsertId
+				if lastInsertID, err := res.LastInsertId(); err == nil {
+					status.LastInsertID = &lastInsertID
 				}
 			}
 
@@ -266,13 +267,14 @@ func (d *database) StatementExec(stmt *exql.Statement, args ...interface{}) (res
 		}(time.Now())
 	}
 
-	var p *sql.Stmt
+	var p *Stmt
 	if p, query, err = d.prepareStatement(stmt); err != nil {
 		return nil, err
 	}
+	defer p.Close()
 
 	if execer, ok := d.PartialDatabase.(HasStatementExec); ok {
-		res, err = execer.StatementExec(p, args...)
+		res, err = execer.StatementExec(p.Stmt, args...)
 		return
 	}
 
@@ -298,10 +300,11 @@ func (d *database) StatementQuery(stmt *exql.Statement, args ...interface{}) (ro
 		}(time.Now())
 	}
 
-	var p *sql.Stmt
+	var p *Stmt
 	if p, query, err = d.prepareStatement(stmt); err != nil {
 		return nil, err
 	}
+	defer p.Close()
 
 	rows, err = p.Query(args...)
 	return
@@ -326,10 +329,11 @@ func (d *database) StatementQueryRow(stmt *exql.Statement, args ...interface{})
 		}(time.Now())
 	}
 
-	var p *sql.Stmt
+	var p *Stmt
 	if p, query, err = d.prepareStatement(stmt); err != nil {
 		return nil, err
 	}
+	defer p.Close()
 
 	row, err = p.QueryRow(args...), nil
 	return
@@ -347,37 +351,33 @@ func (d *database) Driver() interface{} {
 // prepareStatement converts a *exql.Statement representation into an actual
 // *sql.Stmt.  This method will attempt to used a cached prepared statement, if
 // available.
-func (d *database) prepareStatement(stmt *exql.Statement) (*sql.Stmt, string, error) {
+func (d *database) prepareStatement(stmt *exql.Statement) (*Stmt, string, error) {
 	if d.sess == nil && d.Transaction() == nil {
 		return nil, "", db.ErrNotConnected
 	}
 
 	pc, ok := d.cachedStatements.ReadRaw(stmt)
-
 	if ok {
 		// The statement was cached.
-		ps := pc.(*cachedStatement)
-		return ps.Stmt, ps.query, nil
+		ps := pc.(*Stmt).Open()
+		return ps, ps.query, nil
 	}
 
 	// Plain SQL query.
 	query := d.PartialDatabase.CompileStatement(stmt)
 
-	var p *sql.Stmt
-	var err error
-
-	if d.Transaction() != nil {
-		p, err = d.Transaction().(*sqlTx).Prepare(query)
-	} else {
-		p, err = d.sess.Prepare(query)
-	}
-
+	sqlStmt, err := func() (*sql.Stmt, error) {
+		if d.Transaction() != nil {
+			return d.Transaction().(*sqlTx).Prepare(query)
+		}
+		return d.sess.Prepare(query)
+	}()
 	if err != nil {
 		return nil, query, err
 	}
 
-	d.cachedStatements.Write(stmt, &cachedStatement{p, query})
-
+	p := NewStatement(sqlStmt, query)
+	d.cachedStatements.Write(stmt, p)
 	return p, query, nil
 }
 
diff --git a/internal/sqladapter/statement.go b/internal/sqladapter/statement.go
index 51e4f1d7f0fbecf3996a29483e09b2c504750d83..be520be8fbf69f4f0b7bda247d944a3784f355a3 100644
--- a/internal/sqladapter/statement.go
+++ b/internal/sqladapter/statement.go
@@ -2,15 +2,51 @@ package sqladapter
 
 import (
 	"database/sql"
+	"sync/atomic"
 )
 
-// cachedStatement represents a *sql.Stmt that is cached and provides the
+// Stmt represents a *sql.Stmt that is cached and provides the
 // OnPurge method to allow it to clean after itself.
-type cachedStatement struct {
+type Stmt struct {
 	*sql.Stmt
+
 	query string
+
+	count int64
+	dead  int32
+}
+
+// NewStatement creates an returns an opened statement
+func NewStatement(stmt *sql.Stmt, query string) *Stmt {
+	return &Stmt{
+		Stmt:  stmt,
+		query: query,
+		count: 1,
+	}
+}
+
+// Open marks the statement as in-use
+func (c *Stmt) Open() *Stmt {
+	atomic.AddInt64(&c.count, 1)
+	return c
+}
+
+// Close closes the underlying statement if no other go-routine is using it.
+func (c *Stmt) Close() {
+	if atomic.AddInt64(&c.count, -1) > 0 {
+		// There are another goroutines using this statement so we don't want to
+		// close it for real.
+		return
+	}
+	if atomic.LoadInt32(&c.dead) > 0 {
+		// Statement is dead and we can close it for real.
+		c.Stmt.Close()
+	}
 }
 
-func (c *cachedStatement) OnPurge() {
-	c.Stmt.Close()
+// OnPurge marks the statement as ready to be cleaned up.
+func (c *Stmt) OnPurge() {
+	// Mark as dead, you can continue using it but it will be closed for real
+	// when c.count reaches 0.
+	atomic.StoreInt32(&c.dead, 1)
 }
diff --git a/internal/sqladapter/testing/adapter.go.tpl b/internal/sqladapter/testing/adapter.go.tpl
index 92b2e89974a7cf18ef88c23e1444cbc9f8467527..6cc8dc27c03e8259bb792de77705bc029077d353 100644
--- a/internal/sqladapter/testing/adapter.go.tpl
+++ b/internal/sqladapter/testing/adapter.go.tpl
@@ -1370,6 +1370,34 @@ func TestBuilder(t *testing.T) {
 	assert.NotZero(t, all)
 }
 
+func TestStressPreparedStatementCache(t *testing.T) {
+	sess := mustOpen()
+	defer sess.Close()
+
+	var tMu sync.Mutex
+	tFatal := func(err error) {
+		tMu.Lock()
+		defer tMu.Unlock()
+		t.Fatal(err)
+	}
+
+	var wg sync.WaitGroup
+
+	for i := 1; i < 1000; i++ {
+		wg.Add(1)
+		go func(i int) {
+			defer wg.Done()
+			res := sess.Collection("artist").Find().Select(db.Raw(fmt.Sprintf("COUNT(%d)", i%5)))
+			var data map[string]interface{}
+			if err := res.One(&data); err != nil {
+				tFatal(err)
+			}
+		}(i)
+	}
+
+	wg.Wait()
+}
+
 func TestExhaustConnectionPool(t *testing.T) {
 	if Adapter == "ql" {
 		t.Skip("Currently not supported.")
diff --git a/internal/sqladapter/tx.go b/internal/sqladapter/tx.go
index ee34446a746884e51c29c14eef21ab26b674b197..e1a5dcd8d518f563cc312a68831b5b301d46b4f6 100644
--- a/internal/sqladapter/tx.go
+++ b/internal/sqladapter/tx.go
@@ -29,7 +29,7 @@ import (
 	"upper.io/db.v2/lib/sqlbuilder"
 )
 
-// Tx represents a database session within a transaction.
+// DatabaseTx represents a database session within a transaction.
 type DatabaseTx interface {
 	BaseDatabase
 	BaseTx
@@ -98,6 +98,7 @@ func (t *txWrapper) Rollback() error {
 	return t.BaseTx.Rollback()
 }
 
+// RunTx creates a transaction context and runs fn within it.
 func RunTx(d sqlbuilder.Database, fn func(tx sqlbuilder.Tx) error) error {
 	tx, err := d.NewTx()
 	if err != nil {
diff --git a/lib/sqlbuilder/builder.go b/lib/sqlbuilder/builder.go
index 03abd592bc7d9b8637c3ccbc10ab3e0c8d6acb2e..9130dba003c7845566997f3a3c58ae247c54abad 100644
--- a/lib/sqlbuilder/builder.go
+++ b/lib/sqlbuilder/builder.go
@@ -15,6 +15,7 @@ import (
 	"upper.io/db.v2/lib/reflectx"
 )
 
+// MapOptions represents options for the mapper.
 type MapOptions struct {
 	IncludeZeroed bool
 	IncludeNil    bool
diff --git a/lib/sqlbuilder/wrapper.go b/lib/sqlbuilder/wrapper.go
index b3d9f1883572ed28393e4f2ddefed8b2272633f5..6214a6c6aa05a7cfb7711d2ed0d3ce917de08fea 100644
--- a/lib/sqlbuilder/wrapper.go
+++ b/lib/sqlbuilder/wrapper.go
@@ -69,6 +69,8 @@ type Database interface {
 	Tx(fn func(sess Tx) error) error
 }
 
+// AdapterFuncMap is a struct that defines a set of functions that adapters
+// need to provide.
 type AdapterFuncMap struct {
 	New   func(sqlDB *sql.DB) (Database, error)
 	NewTx func(sqlTx *sql.Tx) (Tx, error)
@@ -108,14 +110,17 @@ func adapter(name string) AdapterFuncMap {
 	return missingAdapter(name)
 }
 
+// Open opens a SQL database.
 func Open(adapterName string, settings db.ConnectionURL) (Database, error) {
 	return adapter(adapterName).Open(settings)
 }
 
+// New wraps an active *sql.DB session.
 func New(adapterName string, sqlDB *sql.DB) (Database, error) {
 	return adapter(adapterName).New(sqlDB)
 }
 
+// NewTx wraps an active *sql.Tx transation.
 func NewTx(adapterName string, sqlTx *sql.Tx) (Tx, error) {
 	return adapter(adapterName).NewTx(sqlTx)
 }
diff --git a/logger.go b/logger.go
index f346598ea6ab8d94df698688ce184a73caf844cc..1703fb5828c3ceaaee5f4b75c63fd70aea38256c 100644
--- a/logger.go
+++ b/logger.go
@@ -1,3 +1,24 @@
+// Copyright (c) 2012-present The upper.io/db authors. All rights reserved.
+//
+// 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.
+
 package db
 
 import (
@@ -24,7 +45,7 @@ var (
 	reColumnCompareExclude = regexp.MustCompile(`[^a-zA-Z0-9]`)
 )
 
-// QueryStatus represents a query after being executed.
+// QueryStatus represents the status of a query after being executed.
 type QueryStatus struct {
 	SessID uint64
 	TxID   uint64
@@ -41,41 +62,42 @@ type QueryStatus struct {
 	End   time.Time
 }
 
+// String returns a formatted log message.
 func (q *QueryStatus) String() string {
-	s := make([]string, 0, 8)
+	lines := make([]string, 0, 8)
 
 	if q.SessID > 0 {
-		s = append(s, fmt.Sprintf(fmtLogSessID, q.SessID))
+		lines = append(lines, fmt.Sprintf(fmtLogSessID, q.SessID))
 	}
 
 	if q.TxID > 0 {
-		s = append(s, fmt.Sprintf(fmtLogTxID, q.TxID))
+		lines = append(lines, fmt.Sprintf(fmtLogTxID, q.TxID))
 	}
 
-	if qry := q.Query; qry != "" {
-		qry = reInvisibleChars.ReplaceAllString(qry, ` `)
-		qry = strings.TrimSpace(qry)
-		s = append(s, fmt.Sprintf(fmtLogQuery, qry))
+	if query := q.Query; query != "" {
+		query = reInvisibleChars.ReplaceAllString(query, ` `)
+		query = strings.TrimSpace(query)
+		lines = append(lines, fmt.Sprintf(fmtLogQuery, query))
 	}
 
 	if len(q.Args) > 0 {
-		s = append(s, fmt.Sprintf(fmtLogArgs, q.Args))
+		lines = append(lines, fmt.Sprintf(fmtLogArgs, q.Args))
 	}
 
 	if q.RowsAffected != nil {
-		s = append(s, fmt.Sprintf(fmtLogRowsAffected, *q.RowsAffected))
+		lines = append(lines, fmt.Sprintf(fmtLogRowsAffected, *q.RowsAffected))
 	}
 	if q.LastInsertID != nil {
-		s = append(s, fmt.Sprintf(fmtLogLastInsertID, *q.LastInsertID))
+		lines = append(lines, fmt.Sprintf(fmtLogLastInsertID, *q.LastInsertID))
 	}
 
 	if q.Err != nil {
-		s = append(s, fmt.Sprintf(fmtLogError, q.Err))
+		lines = append(lines, fmt.Sprintf(fmtLogError, q.Err))
 	}
 
-	s = append(s, fmt.Sprintf(fmtLogTimeTaken, float64(q.End.UnixNano()-q.Start.UnixNano())/float64(1e9)))
+	lines = append(lines, fmt.Sprintf(fmtLogTimeTaken, float64(q.End.UnixNano()-q.Start.UnixNano())/float64(1e9)))
 
-	return strings.Join(s, "\n")
+	return strings.Join(lines, "\n")
 }
 
 // EnvEnableDebug can be used by adapters to determine if the user has enabled
@@ -94,15 +116,9 @@ const (
 	EnvEnableDebug = `UPPERIO_DB_DEBUG`
 )
 
-func init() {
-	if envEnabled(EnvEnableDebug) {
-		Conf.SetLogging(true)
-	}
-}
-
 // Logger represents a logging collector. You can pass a logging collector to
 // db.Conf.SetLogger(myCollector) to make it collect db.QueryStatus messages
-// after every query.
+// after executing a query.
 type Logger interface {
 	Log(*QueryStatus)
 }
@@ -119,4 +135,10 @@ func (lg *defaultLogger) Log(m *QueryStatus) {
 	log.Printf("\n\t%s\n\n", strings.Replace(m.String(), "\n", "\n\t", -1))
 }
 
-var _ = Logger(&defaultLogger{})
+var _ Logger = &defaultLogger{}
+
+func init() {
+	if envEnabled(EnvEnableDebug) {
+		Conf.SetLogging(true)
+	}
+}