From ad0d1583c554aeee3ee3f454474e17c39f36ab49 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Nieto?= <jose.carlos@menteslibres.net>
Date: Thu, 28 May 2015 06:53:23 -0500
Subject: [PATCH] Adapting sqlite adapter to newer sqlgen

---
 sqlite/collection.go              | 245 ++---------
 sqlite/database.go                | 646 ++++++++++++++----------------
 sqlite/database_test.go           |  10 +-
 sqlite/result.go                  | 308 --------------
 sqlite/sqlite.go                  |  69 ++++
 sqlite/{layout.go => template.go} |  64 ++-
 sqlite/tx.go                      |  44 --
 7 files changed, 445 insertions(+), 941 deletions(-)
 delete mode 100644 sqlite/result.go
 create mode 100644 sqlite/sqlite.go
 rename sqlite/{layout.go => template.go} (66%)
 delete mode 100644 sqlite/tx.go

diff --git a/sqlite/collection.go b/sqlite/collection.go
index c65e64d4..199a56af 100644
--- a/sqlite/collection.go
+++ b/sqlite/collection.go
@@ -1,4 +1,4 @@
-// Copyright (c) 2012-2014 José Carlos Nieto, https://menteslibres.net/xiam
+// Copyright (c) 2012-2015 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
@@ -22,8 +22,6 @@
 package sqlite
 
 import (
-	"fmt"
-	"reflect"
 	"strings"
 
 	"database/sql"
@@ -31,228 +29,52 @@ import (
 	"upper.io/db"
 	"upper.io/db/util/sqlgen"
 	"upper.io/db/util/sqlutil"
+	"upper.io/db/util/sqlutil/result"
 )
 
-const defaultOperator = `=`
-
 type table struct {
 	sqlutil.T
-	source *source
-	names  []string
-}
-
-func whereValues(term interface{}) (where sqlgen.Where, args []interface{}) {
-
-	args = []interface{}{}
-
-	switch t := term.(type) {
-	case []interface{}:
-		l := len(t)
-		where = make(sqlgen.Where, 0, l)
-		for _, cond := range t {
-			w, v := whereValues(cond)
-			args = append(args, v...)
-			where = append(where, w...)
-		}
-	case db.And:
-		and := make(sqlgen.And, 0, len(t))
-		for _, cond := range t {
-			k, v := whereValues(cond)
-			args = append(args, v...)
-			and = append(and, k...)
-		}
-		where = append(where, and)
-	case db.Or:
-		or := make(sqlgen.Or, 0, len(t))
-		for _, cond := range t {
-			k, v := whereValues(cond)
-			args = append(args, v...)
-			or = append(or, k...)
-		}
-		where = append(where, or)
-	case db.Raw:
-		if s, ok := t.Value.(string); ok == true {
-			where = append(where, sqlgen.Raw{s})
-		}
-	case db.Cond:
-		k, v := conditionValues(t)
-		args = append(args, v...)
-		for _, kk := range k {
-			where = append(where, kk)
-		}
-	case db.Constrainer:
-		k, v := conditionValues(t.Constraint())
-		args = append(args, v...)
-		for _, kk := range k {
-			where = append(where, kk)
-		}
-	default:
-		panic(fmt.Sprintf(db.ErrUnknownConditionType.Error(), reflect.TypeOf(t)))
-	}
-
-	return where, args
-}
-
-func interfaceArgs(value interface{}) (args []interface{}) {
-	if value == nil {
-		return nil
-	}
-
-	v := reflect.ValueOf(value)
-
-	switch v.Type().Kind() {
-	case reflect.Slice:
-		var i, total int
-
-		total = v.Len()
-		if total > 0 {
-			args = make([]interface{}, total)
-
-			for i = 0; i < total; i++ {
-				args[i] = v.Index(i).Interface()
-			}
-
-			return args
-		}
-		return nil
-	default:
-		args = []interface{}{value}
-	}
-
-	return args
-}
-
-func conditionValues(cond db.Cond) (columnValues sqlgen.ColumnValues, args []interface{}) {
-
-	args = []interface{}{}
-
-	for column, value := range cond {
-		var columnValue sqlgen.ColumnValue
-
-		// Guessing operator from input, or using a default one.
-		column := strings.TrimSpace(column)
-		chunks := strings.SplitN(column, ` `, 2)
-
-		columnValue.Column = sqlgen.Column{chunks[0]}
-
-		if len(chunks) > 1 {
-			columnValue.Operator = chunks[1]
-		} else {
-			columnValue.Operator = defaultOperator
-		}
-
-		switch value := value.(type) {
-		case db.Func:
-			// Catches functions.
-			v := interfaceArgs(value.Args)
-			columnValue.Operator = value.Name
-
-			if v == nil {
-				// A function with no arguments.
-				columnValue.Value = sqlgen.Value{sqlgen.Raw{`()`}}
-			} else {
-				// A function with one or more arguments.
-				columnValue.Value = sqlgen.Value{sqlgen.Raw{fmt.Sprintf(`(?%s)`, strings.Repeat(`, ?`, len(v)-1))}}
-			}
-
-			args = append(args, v...)
-		default:
-			// Catches everything else.
-			v := interfaceArgs(value)
-			l := len(v)
-			if v == nil || l == 0 {
-				// Nil value given.
-				columnValue.Value = sqlgen.Value{sqlgen.Raw{`NULL`}}
-			} else {
-				if l > 1 {
-					// Array value given.
-					columnValue.Value = sqlgen.Value{sqlgen.Raw{fmt.Sprintf(`(?%s)`, strings.Repeat(`, ?`, len(v)-1))}}
-				} else {
-					// Single value given.
-					columnValue.Value = sqlPlaceholder
-				}
-				args = append(args, v...)
-			}
-		}
-
-		columnValues = append(columnValues, columnValue)
-	}
-
-	return columnValues, args
+	*database
 }
 
-func (c *table) Find(terms ...interface{}) db.Result {
-	where, arguments := whereValues(terms)
-
-	result := &result{
-		table:     c,
-		where:     where,
-		arguments: arguments,
-	}
+var _ = db.Collection(&table{})
 
-	return result
-}
-
-func (c *table) tableN(i int) string {
-	if len(c.names) > i {
-		chunks := strings.SplitN(c.names[i], " ", 2)
-		if len(chunks) > 0 {
-			return chunks[0]
-		}
-	}
-	return ""
+// Find creates a result set with the given conditions.
+func (t *table) Find(terms ...interface{}) db.Result {
+	where, arguments := sqlutil.ToWhereWithArguments(terms)
+	return result.NewResult(t, where, arguments)
 }
 
-// Deletes all the rows within the collection.
-func (c *table) Truncate() error {
-
-	_, err := c.source.doExec(sqlgen.Statement{
-		Type:  sqlgen.SqlTruncate,
-		Table: sqlgen.Table{c.tableN(0)},
+// Truncate deletes all rows from the table.
+func (t *table) Truncate() error {
+	_, err := t.database.Exec(sqlgen.Statement{
+		Type:  sqlgen.Truncate,
+		Table: sqlgen.TableWithName(t.MainTableName()),
 	})
 
 	if err != nil {
 		return err
 	}
-
 	return nil
 }
 
-// Appends an item (map or struct) into the collection.
-func (c *table) Append(item interface{}) (interface{}, error) {
-
+// Append inserts an item (map or struct) into the collection.
+func (t *table) Append(item interface{}) (interface{}, error) {
 	var pKey []string
-	var columns sqlgen.Columns
-	var values sqlgen.Values
-	var arguments []interface{}
 
-	cols, vals, err := c.FieldValues(item)
+	columnNames, columnValues, err := t.FieldValues(item)
 
-	// Error ocurred, stop appending.
 	if err != nil {
 		return nil, err
 	}
 
-	columns = make(sqlgen.Columns, 0, len(cols))
-	for i := range cols {
-		columns = append(columns, sqlgen.Column{cols[i]})
-	}
+	sqlgenCols, sqlgenVals, sqlgenArgs, err := sqlutil.ToColumnsValuesAndArguments(columnNames, columnValues)
 
-	arguments = make([]interface{}, 0, len(vals))
-	values = make(sqlgen.Values, 0, len(vals))
-	for i := range vals {
-		switch v := vals[i].(type) {
-		case sqlgen.Value:
-			// Adding value.
-			values = append(values, v)
-		default:
-			// Adding both value and placeholder.
-			values = append(values, sqlPlaceholder)
-			arguments = append(arguments, v)
-		}
+	if err != nil {
+		return nil, err
 	}
 
-	if pKey, err = c.source.getPrimaryKey(c.tableN(0)); err != nil {
+	if pKey, err = t.database.getPrimaryKey(t.MainTableName()); err != nil {
 		if err != sql.ErrNoRows {
 			// Can't tell primary key.
 			return nil, err
@@ -260,14 +82,14 @@ func (c *table) Append(item interface{}) (interface{}, error) {
 	}
 
 	stmt := sqlgen.Statement{
-		Type:    sqlgen.SqlInsert,
-		Table:   sqlgen.Table{c.tableN(0)},
-		Columns: columns,
-		Values:  values,
+		Type:    sqlgen.Insert,
+		Table:   sqlgen.TableWithName(t.MainTableName()),
+		Columns: sqlgenCols,
+		Values:  sqlgenVals,
 	}
 
 	var res sql.Result
-	if res, err = c.source.doExec(stmt, arguments...); err != nil {
+	if res, err = t.database.Exec(stmt, sqlgenArgs...); err != nil {
 		return nil, err
 	}
 
@@ -294,10 +116,10 @@ func (c *table) Append(item interface{}) (interface{}, error) {
 	// were given for constructing the composite key.
 	keyMap := make(map[string]interface{})
 
-	for i := range cols {
+	for i := range columnNames {
 		for j := 0; j < len(pKey); j++ {
-			if pKey[j] == cols[i] {
-				keyMap[pKey[j]] = vals[i]
+			if pKey[j] == columnNames[i] {
+				keyMap[pKey[j]] = columnValues[i]
 			}
 		}
 	}
@@ -320,14 +142,15 @@ func (c *table) Append(item interface{}) (interface{}, error) {
 	return keyMap, nil
 }
 
-// Returns true if the collection exists.
-func (c *table) Exists() bool {
-	if err := c.source.tableExists(c.names...); err != nil {
+// Exists returns true if the collection exists.
+func (t *table) Exists() bool {
+	if err := t.database.tableExists(t.Tables...); err != nil {
 		return false
 	}
 	return true
 }
 
-func (c *table) Name() string {
-	return strings.Join(c.names, `, `)
+// Name returns the name of the table or tables that form the collection.
+func (t *table) Name() string {
+	return strings.Join(t.Tables, `, `)
 }
diff --git a/sqlite/database.go b/sqlite/database.go
index d0998b15..d1d575ff 100644
--- a/sqlite/database.go
+++ b/sqlite/database.go
@@ -24,35 +24,26 @@ package sqlite
 import (
 	"database/sql"
 	"fmt"
-	"os"
 	"strings"
 	"time"
 
-	// Importing SQLite3 driver.
 	"github.com/jmoiron/sqlx"
-	_ "github.com/mattn/go-sqlite3"
-	"upper.io/cache"
+	_ "github.com/mattn/go-sqlite3" // SQLite3 driver.
 	"upper.io/db"
 	"upper.io/db/util/schema"
 	"upper.io/db/util/sqlgen"
 	"upper.io/db/util/sqlutil"
+	"upper.io/db/util/sqlutil/tx"
 )
 
-const (
-	// Adapter is the public name of the adapter.
-	Adapter = `sqlite`
-)
-
-var template *sqlgen.Template
-
 var (
-	sqlPlaceholder = sqlgen.Value{sqlgen.Raw{`?`}}
+	sqlPlaceholder = sqlgen.RawValue(`?`)
 )
 
-type source struct {
+type database struct {
 	connURL db.ConnectionURL
 	session *sqlx.DB
-	tx      *tx
+	tx      *sqltx.Tx
 	schema  *schema.DatabaseSchema
 	// columns property was introduced so we could query PRAGMA data only once
 	// and retrieve all the column information we'd need, such as name and if it
@@ -60,399 +51,391 @@ type source struct {
 	columns map[string][]columnSchemaT
 }
 
-type columnSchemaT struct {
-	Name string `db:"name"`
-	PK   int    `db:"pk"`
+type tx struct {
+	*sqltx.Tx
+	*database
 }
 
-func debugEnabled() bool {
-	if os.Getenv(db.EnvEnableDebug) != "" {
-		return true
-	}
-	return false
-}
+var (
+	_ = db.Database(&database{})
+	_ = db.Tx(&tx{})
+)
 
-func debugLog(query string, args []interface{}, err error, start int64, end int64) {
-	if debugEnabled() == true {
-		d := sqlutil.Debug{query, args, err, start, end}
-		d.Print()
-	}
+type columnSchemaT struct {
+	Name string `db:"name"`
+	PK   int    `db:"pk"`
 }
 
-func init() {
-
-	template = &sqlgen.Template{
-		sqlColumnSeparator,
-		sqlIdentifierSeparator,
-		sqlIdentifierQuote,
-		sqlValueSeparator,
-		sqlValueQuote,
-		sqlAndKeyword,
-		sqlOrKeyword,
-		sqlNotKeyword,
-		sqlDescKeyword,
-		sqlAscKeyword,
-		sqlDefaultOperator,
-		sqlClauseGroup,
-		sqlClauseOperator,
-		sqlColumnValue,
-		sqlTableAliasLayout,
-		sqlColumnAliasLayout,
-		sqlSortByColumnLayout,
-		sqlWhereLayout,
-		sqlOrderByLayout,
-		sqlInsertLayout,
-		sqlSelectLayout,
-		sqlUpdateLayout,
-		sqlDeleteLayout,
-		sqlTruncateLayout,
-		sqlDropDatabaseLayout,
-		sqlDropTableLayout,
-		sqlSelectCountLayout,
-		sqlGroupByLayout,
-		cache.NewCache(),
-	}
-
-	db.Register(Adapter, &source{})
+// Driver returns the underlying *sqlx.DB instance.
+func (d *database) Driver() interface{} {
+	return d.session
 }
 
-func (s *source) populateSchema() (err error) {
-	var collections []string
+// Open attempts to connect to the database server using already stored settings.
+func (d *database) Open() error {
+	var err error
 
-	s.schema = schema.NewDatabaseSchema()
+	// Before db.ConnectionURL we used a unified db.Settings struct. This
+	// condition checks for that type and provides backwards compatibility.
+	if settings, ok := d.connURL.(db.Settings); ok {
+		// User is providing a db.Settings struct, let's translate it into a
+		// ConnectionURL{}.
+		conn := ConnectionURL{
+			Database: settings.Database,
+			Options: map[string]string{
+				"cache": "shared",
+			},
+		}
 
-	var conn ConnectionURL
+		d.connURL = conn
+	}
 
-	if conn, err = ParseURL(s.connURL.String()); err != nil {
+	if d.session, err = sqlx.Open(`sqlite3`, d.connURL.String()); err != nil {
 		return err
 	}
 
-	s.schema.Name = conn.Database
+	d.session.Mapper = sqlutil.NewMapper()
 
-	// The Collections() call will populate schema if its nil.
-	if collections, err = s.Collections(); err != nil {
+	if err = d.populateSchema(); err != nil {
 		return err
 	}
 
-	for i := range collections {
-		// Populate each collection.
-		if _, err = s.Collection(collections[i]); err != nil {
-			return err
-		}
-	}
+	return nil
+}
 
-	return err
+// Clone returns a cloned db.Database session, this is typically used for
+// transactions.
+func (d *database) Clone() (db.Database, error) {
+	return d.clone()
 }
 
-func (s *source) doExec(stmt sqlgen.Statement, args ...interface{}) (sql.Result, error) {
-	var query string
-	var res sql.Result
-	var err error
-	var start, end int64
+func (d *database) clone() (*database, error) {
+	src := &database{}
+	src.Setup(d.connURL)
 
-	start = time.Now().UnixNano()
+	if err := src.Open(); err != nil {
+		return nil, err
+	}
 
-	defer func() {
-		end = time.Now().UnixNano()
-		debugLog(query, args, err, start, end)
-	}()
+	return src, nil
+}
 
-	if s.session == nil {
-		return nil, db.ErrNotConnected
+// Ping checks whether a connection to the database is still alive by pinging
+// it, establishing a connection if necessary.
+func (d *database) Ping() error {
+	return d.session.Ping()
+}
+
+// Close terminates the current database session.
+func (d *database) Close() error {
+	if d.session != nil {
+		return d.session.Close()
 	}
+	return nil
+}
 
-	query = stmt.Compile(template)
+// Collection returns a table by name.
+func (d *database) Collection(names ...string) (db.Collection, error) {
+	var err error
 
-	if s.tx != nil {
-		res, err = s.tx.sqlTx.Exec(query, args...)
-	} else {
-		res, err = s.session.Exec(query, args...)
+	if len(names) == 0 {
+		return nil, db.ErrMissingCollectionName
 	}
 
-	return res, err
-}
+	if d.tx != nil {
+		if d.tx.Done() {
+			return nil, sql.ErrTxDone
+		}
+	}
 
-func (s *source) doQuery(stmt sqlgen.Statement, args ...interface{}) (*sqlx.Rows, error) {
-	var rows *sqlx.Rows
-	var query string
-	var err error
-	var start, end int64
+	col := &table{database: d}
+	col.Tables = names
 
-	start = time.Now().UnixNano()
+	for _, name := range names {
+		chunks := strings.SplitN(name, ` `, 2)
 
-	defer func() {
-		end = time.Now().UnixNano()
-		debugLog(query, args, err, start, end)
-	}()
+		if len(chunks) == 0 {
+			return nil, db.ErrMissingCollectionName
+		}
 
-	if s.session == nil {
-		return nil, db.ErrNotConnected
-	}
+		tableName := chunks[0]
 
-	query = stmt.Compile(template)
+		if err := d.tableExists(tableName); err != nil {
+			return nil, err
+		}
 
-	if s.tx != nil {
-		rows, err = s.tx.sqlTx.Queryx(query, args...)
-	} else {
-		rows, err = s.session.Queryx(query, args...)
+		if col.Columns, err = d.tableColumns(tableName); err != nil {
+			return nil, err
+		}
 	}
 
-	return rows, err
+	return col, nil
 }
 
-func (s *source) doQueryRow(stmt sqlgen.Statement, args ...interface{}) (*sqlx.Row, error) {
-	var query string
-	var row *sqlx.Row
-	var err error
-	var start, end int64
+// Collections returns a list of non-system tables from the database.
+func (d *database) Collections() (collections []string, err error) {
 
-	start = time.Now().UnixNano()
+	tablesInSchema := len(d.schema.Tables)
 
-	defer func() {
-		end = time.Now().UnixNano()
-		debugLog(query, args, err, start, end)
-	}()
-
-	if s.session == nil {
-		return nil, db.ErrNotConnected
+	// Id.schema already populated?
+	if tablesInSchema > 0 {
+		// Pulling table names from schema.
+		return d.schema.Tables, nil
 	}
 
-	query = stmt.Compile(template)
+	// Schema is empty.
 
-	if s.tx != nil {
-		row = s.tx.sqlTx.QueryRowx(query, args...)
-	} else {
-		row = s.session.QueryRowx(query, args...)
+	// Querying table names.
+	stmt := sqlgen.Statement{
+		Type: sqlgen.Select,
+		Columns: sqlgen.JoinColumns(
+			sqlgen.ColumnWithName(`tbl_name`),
+		),
+		Table: sqlgen.TableWithName(`sqlite_master`),
+		Where: sqlgen.WhereConditions(
+			&sqlgen.ColumnValue{
+				Column:   sqlgen.ColumnWithName(`type`),
+				Operator: `=`,
+				Value:    sqlgen.NewValue(`table`),
+			},
+		),
 	}
 
-	return row, err
-}
-
-func (s *source) doRawQuery(query string, args ...interface{}) (*sqlx.Rows, error) {
+	// Executing statement.
 	var rows *sqlx.Rows
-	var err error
-	var start, end int64
+	if rows, err = d.Query(stmt); err != nil {
+		return nil, err
+	}
 
-	start = time.Now().UnixNano()
+	defer rows.Close()
 
-	defer func() {
-		end = time.Now().UnixNano()
-		debugLog(query, args, err, start, end)
-	}()
+	collections = []string{}
 
-	if s.session == nil {
-		return nil, db.ErrNotConnected
-	}
+	var name string
 
-	if s.tx != nil {
-		rows, err = s.tx.sqlTx.Queryx(query, args...)
-	} else {
-		rows, err = s.session.Queryx(query, args...)
+	for rows.Next() {
+		// Getting table name.
+		if err = rows.Scan(&name); err != nil {
+			return nil, err
+		}
+
+		// Adding table entry to schema.
+		d.schema.AddTable(name)
+
+		// Adding table to collections array.
+		collections = append(collections, name)
 	}
 
-	return rows, err
+	return collections, nil
 }
 
-// Returns the string name of the database.
-func (s *source) Name() string {
-	return s.schema.Name
-}
+// Use changes the active database.
+func (d *database) Use(database string) (err error) {
+	var conn ConnectionURL
+
+	if conn, err = ParseURL(d.connURL.String()); err != nil {
+		return err
+	}
+
+	conn.Database = database
+
+	d.connURL = conn
 
-//  Ping verifies a connection to the database is still alive,
-//  establishing a connection if necessary.
-func (s *source) Ping() error {
-	return s.session.Ping()
+	return d.Open()
 }
 
-func (s *source) clone() (*source, error) {
-	src := &source{}
-	src.Setup(s.connURL)
+// Drop removes all tables from the current database.
+func (d *database) Drop() error {
 
-	if err := src.Open(); err != nil {
-		return nil, err
-	}
+	_, err := d.Query(sqlgen.Statement{
+		Type:     sqlgen.DropDatabase,
+		Database: sqlgen.DatabaseWithName(d.schema.Name),
+	})
 
-	return src, nil
+	return err
+}
+
+// Setup stores database settings.
+func (d *database) Setup(connURL db.ConnectionURL) error {
+	d.connURL = connURL
+	return d.Open()
 }
 
-func (s *source) Clone() (db.Database, error) {
-	return s.clone()
+// Name returns the name of the database.
+func (d *database) Name() string {
+	return d.schema.Name
 }
 
-func (s *source) Transaction() (db.Tx, error) {
+// Transaction starts a transaction block and returns a db.Tx struct that can
+// be used to issue transactional queries.
+func (d *database) Transaction() (db.Tx, error) {
 	var err error
-	var clone *source
+	var clone *database
 	var sqlTx *sqlx.Tx
 
-	if sqlTx, err = s.session.Beginx(); err != nil {
+	if sqlTx, err = d.session.Beginx(); err != nil {
 		return nil, err
 	}
 
-	if clone, err = s.clone(); err != nil {
+	if clone, err = d.clone(); err != nil {
 		return nil, err
 	}
 
-	tx := &tx{source: clone, sqlTx: sqlTx}
-
-	clone.tx = tx
-
-	return tx, nil
-}
-
-// Stores database settings.
-func (s *source) Setup(conn db.ConnectionURL) error {
-	s.connURL = conn
-	return s.Open()
-}
+	clone.tx = sqltx.New(sqlTx)
 
-// Returns the underlying *sqlx.DB instance.
-func (s *source) Driver() interface{} {
-	return s.session
+	return tx{Tx: clone.tx, database: clone}, nil
 }
 
-// Attempts to connect to a database using the stored settings.
-func (s *source) Open() error {
+// Exec compiles and executes a statement that does not return any rows.
+func (d *database) Exec(stmt sqlgen.Statement, args ...interface{}) (sql.Result, error) {
+	var query string
+	var res sql.Result
 	var err error
+	var start, end int64
 
-	// Before db.ConnectionURL we used a unified db.Settings struct. This
-	// condition checks for that type and provides backwards compatibility.
-	if settings, ok := s.connURL.(db.Settings); ok {
-		// User is providing a db.Settings struct, let's translate it into a
-		// ConnectionURL{}.
-		conn := ConnectionURL{
-			Database: settings.Database,
-			Options: map[string]string{
-				"cache": "shared",
-			},
-		}
+	start = time.Now().UnixNano()
 
-		s.connURL = conn
-	}
+	defer func() {
+		end = time.Now().UnixNano()
+		sqlutil.Log(query, args, err, start, end)
+	}()
 
-	if s.session, err = sqlx.Open(`sqlite3`, s.connURL.String()); err != nil {
-		return err
+	if d.session == nil {
+		return nil, db.ErrNotConnected
 	}
 
-	s.session.Mapper = sqlutil.NewMapper()
+	query = stmt.Compile(template)
 
-	if err = s.populateSchema(); err != nil {
-		return err
+	if d.tx != nil {
+		res, err = d.tx.Exec(query, args...)
+	} else {
+		res, err = d.session.Exec(query, args...)
 	}
 
-	return nil
+	return res, err
 }
 
-// Closes the current database session.
-func (s *source) Close() error {
-	if s.session != nil {
-		return s.session.Close()
-	}
-	return nil
-}
+// Query compiles and executes a statement that returns rows.
+func (d *database) Query(stmt sqlgen.Statement, args ...interface{}) (*sqlx.Rows, error) {
+	var rows *sqlx.Rows
+	var query string
+	var err error
+	var start, end int64
 
-// Changes the active database.
-func (s *source) Use(database string) (err error) {
-	var conn ConnectionURL
+	start = time.Now().UnixNano()
 
-	if conn, err = ParseURL(s.connURL.String()); err != nil {
-		return err
+	defer func() {
+		end = time.Now().UnixNano()
+		sqlutil.Log(query, args, err, start, end)
+	}()
+
+	if d.session == nil {
+		return nil, db.ErrNotConnected
 	}
 
-	conn.Database = database
+	query = stmt.Compile(template)
 
-	s.connURL = conn
+	if d.tx != nil {
+		rows, err = d.tx.Queryx(query, args...)
+	} else {
+		rows, err = d.session.Queryx(query, args...)
+	}
 
-	return s.Open()
+	return rows, err
 }
 
-// Drops the currently active database.
-func (s *source) Drop() error {
-	return db.ErrUnsupported
-}
+// QueryRow compiles and executes a statement that returns at most one row.
+func (d *database) QueryRow(stmt sqlgen.Statement, args ...interface{}) (*sqlx.Row, error) {
+	var query string
+	var row *sqlx.Row
+	var err error
+	var start, end int64
 
-// Collections() Returns a list of non-system tables/collections contained
-// within the currently active database.
-func (s *source) Collections() (collections []string, err error) {
+	start = time.Now().UnixNano()
 
-	tablesInSchema := len(s.schema.Tables)
+	defer func() {
+		end = time.Now().UnixNano()
+		sqlutil.Log(query, args, err, start, end)
+	}()
 
-	// Is schema already populated?
-	if tablesInSchema > 0 {
-		// Pulling table names from schema.
-		return s.schema.Tables, nil
+	if d.session == nil {
+		return nil, db.ErrNotConnected
 	}
 
-	// Schema is empty.
+	query = stmt.Compile(template)
 
-	// Querying table names.
-	stmt := sqlgen.Statement{
-		Type: sqlgen.SqlSelect,
-		Columns: sqlgen.Columns{
-			{`tbl_name`},
-		},
-		Table: sqlgen.Table{`sqlite_master`},
-		Where: sqlgen.Where{
-			sqlgen.ColumnValue{
-				sqlgen.Column{`type`},
-				`=`,
-				sqlgen.Value{`table`},
-			},
-		},
+	if d.tx != nil {
+		row = d.tx.QueryRowx(query, args...)
+	} else {
+		row = d.session.QueryRowx(query, args...)
 	}
 
-	// Executing statement.
-	var rows *sqlx.Rows
-	if rows, err = s.doQuery(stmt); err != nil {
-		return nil, err
-	}
+	return row, err
+}
 
-	defer rows.Close()
+// populateSchema looks up for the table info in the database and populates its
+// schema for internal use.
+func (d *database) populateSchema() (err error) {
+	var collections []string
 
-	collections = []string{}
+	d.schema = schema.NewDatabaseSchema()
 
-	var name string
+	var conn ConnectionURL
 
-	for rows.Next() {
-		// Getting table name.
-		if err = rows.Scan(&name); err != nil {
-			return nil, err
-		}
+	if conn, err = ParseURL(d.connURL.String()); err != nil {
+		return err
+	}
 
-		// Adding table entry to schema.
-		s.schema.AddTable(name)
+	d.schema.Name = conn.Database
 
-		// Adding table to collections array.
-		collections = append(collections, name)
+	// The Collections() call will populate schema if its nil.
+	if collections, err = d.Collections(); err != nil {
+		return err
 	}
 
-	return collections, nil
+	for i := range collections {
+		// Populate each collection.
+		if _, err = d.Collection(collections[i]); err != nil {
+			return err
+		}
+	}
+
+	return err
 }
 
-func (s *source) tableExists(names ...string) error {
+func (d *database) tableExists(names ...string) error {
 	var stmt sqlgen.Statement
 	var err error
 	var rows *sqlx.Rows
 
 	for i := range names {
 
-		if s.schema.HasTable(names[i]) {
+		if d.schema.HasTable(names[i]) {
 			// We already know this table exists.
 			continue
 		}
 
 		stmt = sqlgen.Statement{
-			Type:  sqlgen.SqlSelect,
-			Table: sqlgen.Table{`sqlite_master`},
-			Columns: sqlgen.Columns{
-				{`tbl_name`},
-			},
-			Where: sqlgen.Where{
-				sqlgen.ColumnValue{sqlgen.Column{`type`}, `=`, sqlPlaceholder},
-				sqlgen.ColumnValue{sqlgen.Column{`tbl_name`}, `=`, sqlPlaceholder},
-			},
+			Type:  sqlgen.Select,
+			Table: sqlgen.TableWithName(`sqlite_master`),
+			Columns: sqlgen.JoinColumns(
+				sqlgen.ColumnWithName(`tbl_name`),
+			),
+			Where: sqlgen.WhereConditions(
+				&sqlgen.ColumnValue{
+					Column:   sqlgen.ColumnWithName(`type`),
+					Operator: `=`,
+					Value:    sqlPlaceholder,
+				},
+				&sqlgen.ColumnValue{
+					Column:   sqlgen.ColumnWithName(`tbl_name`),
+					Operator: `=`,
+					Value:    sqlPlaceholder,
+				},
+			),
 		}
 
-		if rows, err = s.doQuery(stmt, `table`, names[i]); err != nil {
+		if rows, err = d.Query(stmt, `table`, names[i]); err != nil {
 			return db.ErrCollectionDoesNotExist
 		}
 
@@ -466,10 +449,10 @@ func (s *source) tableExists(names ...string) error {
 	return nil
 }
 
-func (s *source) tableColumns(tableName string) ([]string, error) {
+func (d *database) tableColumns(tableName string) ([]string, error) {
 
 	// Making sure this table is allocated.
-	tableSchema := s.schema.Table(tableName)
+	tableSchema := d.schema.Table(tableName)
 
 	if len(tableSchema.Columns) > 0 {
 		return tableSchema.Columns, nil
@@ -477,10 +460,10 @@ func (s *source) tableColumns(tableName string) ([]string, error) {
 
 	q := fmt.Sprintf(`PRAGMA TABLE_INFO('%s')`, tableName)
 
-	rows, err := s.doRawQuery(q)
+	rows, err := d.doRawQuery(q)
 
-	if s.columns == nil {
-		s.columns = make(map[string][]columnSchemaT)
+	if d.columns == nil {
+		d.columns = make(map[string][]columnSchemaT)
 	}
 
 	columns := []columnSchemaT{}
@@ -489,81 +472,64 @@ func (s *source) tableColumns(tableName string) ([]string, error) {
 		return nil, err
 	}
 
-	s.columns[tableName] = columns
+	d.columns[tableName] = columns
 
-	s.schema.TableInfo[tableName].Columns = make([]string, 0, len(s.columns))
+	d.schema.TableInfo[tableName].Columns = make([]string, 0, len(d.columns))
 
-	for i := range s.columns[tableName] {
-		s.schema.TableInfo[tableName].Columns = append(s.schema.TableInfo[tableName].Columns, s.columns[tableName][i].Name)
+	for i := range d.columns[tableName] {
+		d.schema.TableInfo[tableName].Columns = append(d.schema.TableInfo[tableName].Columns, d.columns[tableName][i].Name)
 	}
 
-	return s.schema.TableInfo[tableName].Columns, nil
+	return d.schema.TableInfo[tableName].Columns, nil
 }
 
-// Returns a collection instance by name.
-func (s *source) Collection(names ...string) (db.Collection, error) {
-	var err error
-
-	if len(names) == 0 {
-		return nil, db.ErrMissingCollectionName
-	}
-
-	if s.tx != nil {
-		if s.tx.done {
-			return nil, sql.ErrTxDone
-		}
-	}
+func (d *database) getPrimaryKey(tableName string) ([]string, error) {
+	tableSchema := d.schema.Table(tableName)
 
-	col := &table{
-		source: s,
-		names:  names,
-	}
+	d.tableColumns(tableName)
 
-	for _, name := range names {
-		chunks := strings.SplitN(name, ` `, 2)
+	maxValue := -1
 
-		if len(chunks) == 0 {
-			return nil, db.ErrMissingCollectionName
+	for i := range d.columns[tableName] {
+		if d.columns[tableName][i].PK > 0 && d.columns[tableName][i].PK > maxValue {
+			maxValue = d.columns[tableName][i].PK
 		}
+	}
 
-		tableName := chunks[0]
-
-		if err := s.tableExists(tableName); err != nil {
-			return nil, err
-		}
+	if maxValue > 0 {
+		tableSchema.PrimaryKey = make([]string, maxValue)
 
-		if col.Columns, err = s.tableColumns(tableName); err != nil {
-			return nil, err
+		for i := range d.columns[tableName] {
+			if d.columns[tableName][i].PK > 0 {
+				tableSchema.PrimaryKey[d.columns[tableName][i].PK-1] = d.columns[tableName][i].Name
+			}
 		}
 	}
 
-	return col, nil
+	return tableSchema.PrimaryKey, nil
 }
 
-// getPrimaryKey returns the names of the columns that define the primary key
-// of the table.
-func (s *source) getPrimaryKey(tableName string) ([]string, error) {
-	tableSchema := s.schema.Table(tableName)
+func (d *database) doRawQuery(query string, args ...interface{}) (*sqlx.Rows, error) {
+	var rows *sqlx.Rows
+	var err error
+	var start, end int64
 
-	s.tableColumns(tableName)
+	start = time.Now().UnixNano()
 
-	maxValue := -1
+	defer func() {
+		end = time.Now().UnixNano()
+		sqlutil.Log(query, args, err, start, end)
+	}()
 
-	for i := range s.columns[tableName] {
-		if s.columns[tableName][i].PK > 0 && s.columns[tableName][i].PK > maxValue {
-			maxValue = s.columns[tableName][i].PK
-		}
+	if d.session == nil {
+		return nil, db.ErrNotConnected
 	}
 
-	if maxValue > 0 {
-		tableSchema.PrimaryKey = make([]string, maxValue)
-
-		for i := range s.columns[tableName] {
-			if s.columns[tableName][i].PK > 0 {
-				tableSchema.PrimaryKey[s.columns[tableName][i].PK-1] = s.columns[tableName][i].Name
-			}
-		}
+	if d.tx != nil {
+		rows, err = d.tx.Queryx(query, args...)
+	} else {
+		rows, err = d.session.Queryx(query, args...)
 	}
 
-	return tableSchema.PrimaryKey, nil
+	return rows, err
 }
diff --git a/sqlite/database_test.go b/sqlite/database_test.go
index 4480e392..43cf54d6 100644
--- a/sqlite/database_test.go
+++ b/sqlite/database_test.go
@@ -47,7 +47,7 @@ import (
 )
 
 const (
-	database = `_dumps/gotest.sqlite3.db`
+	databaseName = `_dumps/gotest.sqlite3.db`
 )
 
 const (
@@ -55,7 +55,7 @@ const (
 )
 
 var settings = ConnectionURL{
-	Database: database,
+	Database: databaseName,
 }
 
 // Structure for testing conversions and datatypes.
@@ -167,7 +167,7 @@ func TestOldSettings(t *testing.T) {
 	var sess db.Database
 
 	oldSettings := db.Settings{
-		Database: database,
+		Database: databaseName,
 	}
 
 	// Opening database.
@@ -1402,7 +1402,7 @@ func BenchmarkAppendRawSQL(b *testing.B) {
 
 	defer sess.Close()
 
-	driver := sess.Driver().(*sql.DB)
+	driver := sess.Driver().(*sqlx.DB)
 
 	if _, err = driver.Exec(`DELETE FROM "artist"`); err != nil {
 		b.Fatal(err)
@@ -1456,7 +1456,7 @@ func BenchmarkAppendTxRawSQL(b *testing.B) {
 
 	defer sess.Close()
 
-	driver := sess.Driver().(*sql.DB)
+	driver := sess.Driver().(*sqlx.DB)
 
 	if tx, err = driver.Begin(); err != nil {
 		b.Fatal(err)
diff --git a/sqlite/result.go b/sqlite/result.go
deleted file mode 100644
index 6504200c..00000000
--- a/sqlite/result.go
+++ /dev/null
@@ -1,308 +0,0 @@
-// 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.
-
-package sqlite
-
-import (
-	"fmt"
-	"strings"
-
-	"github.com/jmoiron/sqlx"
-	"upper.io/db"
-	"upper.io/db/util/sqlgen"
-	"upper.io/db/util/sqlutil"
-)
-
-type counter struct {
-	Total uint64 `db:"_t"`
-}
-
-type result struct {
-	table     *table
-	cursor    *sqlx.Rows // This is the main query cursor. It starts as a nil value.
-	limit     sqlgen.Limit
-	offset    sqlgen.Offset
-	columns   sqlgen.Columns
-	where     sqlgen.Where
-	orderBy   sqlgen.OrderBy
-	groupBy   sqlgen.GroupBy
-	arguments []interface{}
-}
-
-// Executes a SELECT statement that can feed Next(), All() or One().
-func (r *result) setCursor() error {
-	var err error
-	// We need a cursor, if the cursor does not exists yet then we create one.
-	if r.cursor == nil {
-		r.cursor, err = r.table.source.doQuery(sqlgen.Statement{
-			Type:    sqlgen.SqlSelect,
-			Table:   sqlgen.Table{r.table.Name()},
-			Columns: r.columns,
-			Limit:   r.limit,
-			Offset:  r.offset,
-			Where:   r.where,
-			OrderBy: r.orderBy,
-			GroupBy: r.groupBy,
-		}, r.arguments...)
-	}
-	return err
-}
-
-// Sets conditions for reducing the working set.
-func (r *result) Where(terms ...interface{}) db.Result {
-	r.where, r.arguments = whereValues(terms)
-	return r
-}
-
-// Determines the maximum limit of results to be returned.
-func (r *result) Limit(n uint) db.Result {
-	r.limit = sqlgen.Limit(n)
-	return r
-}
-
-// Determines how many documents will be skipped before starting to grab
-// results.
-func (r *result) Skip(n uint) db.Result {
-	r.offset = sqlgen.Offset(n)
-	return r
-}
-
-// Used to group results that have the same value in the same column or
-// columns.
-func (r *result) Group(fields ...interface{}) db.Result {
-
-	groupByColumns := make(sqlgen.GroupBy, 0, len(fields))
-
-	l := len(fields)
-
-	for i := 0; i < l; i++ {
-		switch value := fields[i].(type) {
-		// Maybe other types?
-		default:
-			groupByColumns = append(groupByColumns, sqlgen.Column{value})
-		}
-	}
-
-	r.groupBy = groupByColumns
-
-	return r
-}
-
-// Determines sorting of results according to the provided names. Fields may be
-// prefixed by - (minus) which means descending order, ascending order would be
-// used otherwise.
-func (r *result) Sort(fields ...interface{}) db.Result {
-
-	sortColumns := make(sqlgen.SortColumns, 0, len(fields))
-
-	l := len(fields)
-	for i := 0; i < l; i++ {
-		var sort sqlgen.SortColumn
-
-		switch value := fields[i].(type) {
-		case db.Raw:
-			sort = sqlgen.SortColumn{
-				sqlgen.Column{sqlgen.Raw{fmt.Sprintf(`%v`, value.Value)}},
-				sqlgen.SqlSortAsc,
-			}
-		case string:
-			if strings.HasPrefix(value, `-`) {
-				// Explicit descending order.
-				sort = sqlgen.SortColumn{
-					sqlgen.Column{value[1:]},
-					sqlgen.SqlSortDesc,
-				}
-			} else {
-				// Ascending order.
-				sort = sqlgen.SortColumn{
-					sqlgen.Column{value},
-					sqlgen.SqlSortAsc,
-				}
-			}
-		}
-		sortColumns = append(sortColumns, sort)
-	}
-
-	r.orderBy.SortColumns = sortColumns
-
-	return r
-}
-
-// Retrieves only the given fields.
-func (r *result) Select(fields ...interface{}) db.Result {
-
-	r.columns = make(sqlgen.Columns, 0, len(fields))
-
-	l := len(fields)
-	for i := 0; i < l; i++ {
-		var col sqlgen.Column
-		switch value := fields[i].(type) {
-		case db.Func:
-			v := interfaceArgs(value.Args)
-			var s string
-			if len(v) == 0 {
-				s = fmt.Sprintf(`%s()`, value.Name)
-			} else {
-				ss := make([]string, 0, len(v))
-				for j := range v {
-					ss = append(ss, fmt.Sprintf(`%v`, v[j]))
-				}
-				s = fmt.Sprintf(`%s(%s)`, value.Name, strings.Join(ss, `, `))
-			}
-			col = sqlgen.Column{sqlgen.Raw{s}}
-		case db.Raw:
-			col = sqlgen.Column{sqlgen.Raw{fmt.Sprintf(`%v`, value.Value)}}
-		default:
-			col = sqlgen.Column{value}
-		}
-		r.columns = append(r.columns, col)
-	}
-
-	return r
-}
-
-// Dumps all results into a pointer to an slice of structs or maps.
-func (r *result) All(dst interface{}) error {
-	var err error
-
-	if r.cursor != nil {
-		return db.ErrQueryIsPending
-	}
-
-	// Current cursor.
-	err = r.setCursor()
-
-	if err != nil {
-		return err
-	}
-
-	defer r.Close()
-
-	// Fetching all results within the cursor.
-	err = sqlutil.FetchRows(r.cursor, dst)
-
-	return err
-}
-
-// Fetches only one result from the resultset.
-func (r *result) One(dst interface{}) error {
-	var err error
-
-	if r.cursor != nil {
-		return db.ErrQueryIsPending
-	}
-
-	defer r.Close()
-
-	err = r.Next(dst)
-
-	return err
-}
-
-// Fetches the next result from the resultset.
-func (r *result) Next(dst interface{}) (err error) {
-
-	if err = r.setCursor(); err != nil {
-		r.Close()
-		return err
-	}
-
-	if err = sqlutil.FetchRow(r.cursor, dst); err != nil {
-		r.Close()
-		return err
-	}
-
-	return nil
-}
-
-// Removes the matching items from the collection.
-func (r *result) Remove() error {
-	var err error
-
-	_, err = r.table.source.doExec(sqlgen.Statement{
-		Type:  sqlgen.SqlDelete,
-		Table: sqlgen.Table{r.table.Name()},
-		Where: r.where,
-	}, r.arguments...)
-
-	return err
-
-}
-
-// Updates matching items from the collection with values of the given map or
-// struct.
-func (r *result) Update(values interface{}) error {
-
-	ff, vv, err := r.table.FieldValues(values)
-	if err != nil {
-		return err
-	}
-
-	total := len(ff)
-
-	cvs := make(sqlgen.ColumnValues, 0, total)
-
-	for i := 0; i < total; i++ {
-		cvs = append(cvs, sqlgen.ColumnValue{sqlgen.Column{ff[i]}, "=", sqlPlaceholder})
-	}
-
-	vv = append(vv, r.arguments...)
-
-	_, err = r.table.source.doExec(sqlgen.Statement{
-		Type:         sqlgen.SqlUpdate,
-		Table:        sqlgen.Table{r.table.Name()},
-		ColumnValues: cvs,
-		Where:        r.where,
-	}, vv...)
-
-	return err
-}
-
-// Closes the result set.
-func (r *result) Close() (err error) {
-	if r.cursor != nil {
-		err = r.cursor.Close()
-		r.cursor = nil
-	}
-	return err
-}
-
-// Counts the elements within the main conditions of the set.
-func (r *result) Count() (uint64, error) {
-	var count counter
-
-	row, err := r.table.source.doQueryRow(sqlgen.Statement{
-		Type:  sqlgen.SqlSelectCount,
-		Table: sqlgen.Table{r.table.Name()},
-		Where: r.where,
-	}, r.arguments...)
-
-	if err != nil {
-		return 0, err
-	}
-
-	err = row.Scan(&count.Total)
-	if err != nil {
-		return 0, err
-	}
-
-	return count.Total, nil
-}
diff --git a/sqlite/sqlite.go b/sqlite/sqlite.go
new file mode 100644
index 00000000..eecef2d3
--- /dev/null
+++ b/sqlite/sqlite.go
@@ -0,0 +1,69 @@
+// Copyright (c) 2012-2015 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.
+
+package sqlite
+
+import (
+	"upper.io/cache"
+	"upper.io/db"
+	"upper.io/db/util/sqlgen"
+)
+
+// Adapter is the public name of the adapter.
+const Adapter = `sqlite`
+
+var template *sqlgen.Template
+
+func init() {
+	template = &sqlgen.Template{
+		ColumnSeparator:     adapterColumnSeparator,
+		IdentifierSeparator: adapterIdentifierSeparator,
+		IdentifierQuote:     adapterIdentifierQuote,
+		ValueSeparator:      adapterValueSeparator,
+		ValueQuote:          adapterValueQuote,
+		AndKeyword:          adapterAndKeyword,
+		OrKeyword:           adapterOrKeyword,
+		NotKeyword:          adapterNotKeyword,
+		DescKeyword:         adapterDescKeyword,
+		AscKeyword:          adapterAscKeyword,
+		DefaultOperator:     adapterDefaultOperator,
+		ClauseGroup:         adapterClauseGroup,
+		ClauseOperator:      adapterClauseOperator,
+		ColumnValue:         adapterColumnValue,
+		TableAliasLayout:    adapterTableAliasLayout,
+		ColumnAliasLayout:   adapterColumnAliasLayout,
+		SortByColumnLayout:  adapterSortByColumnLayout,
+		WhereLayout:         adapterWhereLayout,
+		OrderByLayout:       adapterOrderByLayout,
+		InsertLayout:        adapterInsertLayout,
+		SelectLayout:        adapterSelectLayout,
+		UpdateLayout:        adapterUpdateLayout,
+		DeleteLayout:        adapterDeleteLayout,
+		TruncateLayout:      adapterTruncateLayout,
+		DropDatabaseLayout:  adapterDropDatabaseLayout,
+		DropTableLayout:     adapterDropTableLayout,
+		CountLayout:         adapterSelectCountLayout,
+		GroupByLayout:       adapterGroupByLayout,
+		Cache:               cache.NewCache(),
+	}
+
+	db.Register(Adapter, &database{})
+}
diff --git a/sqlite/layout.go b/sqlite/template.go
similarity index 66%
rename from sqlite/layout.go
rename to sqlite/template.go
index 9d937696..48c1ce6d 100644
--- a/sqlite/layout.go
+++ b/sqlite/template.go
@@ -22,37 +22,37 @@
 package sqlite
 
 const (
-	sqlColumnSeparator     = `.`
-	sqlIdentifierSeparator = `, `
-	sqlIdentifierQuote     = `"{{.Raw}}"`
-	sqlValueSeparator      = `, `
-	sqlValueQuote          = `'{{.}}'`
-	sqlAndKeyword          = `AND`
-	sqlOrKeyword           = `OR`
-	sqlNotKeyword          = `NOT`
-	sqlDescKeyword         = `DESC`
-	sqlAscKeyword          = `ASC`
-	sqlDefaultOperator     = `=`
-	sqlClauseGroup         = `({{.}})`
-	sqlClauseOperator      = ` {{.}} `
-	sqlColumnValue         = `{{.Column}} {{.Operator}} {{.Value}}`
-	sqlTableAliasLayout    = `{{.Name}}{{if .Alias}} AS {{.Alias}}{{end}}`
-	sqlColumnAliasLayout   = `{{.Name}}{{if .Alias}} AS {{.Alias}}{{end}}`
-	sqlSortByColumnLayout  = `{{.Column}} {{.Sort}}`
-
-	sqlOrderByLayout = `
+	adapterColumnSeparator     = `.`
+	adapterIdentifierSeparator = `, `
+	adapterIdentifierQuote     = `"{{.Value}}"`
+	adapterValueSeparator      = `, `
+	adapterValueQuote          = `'{{.}}'`
+	adapterAndKeyword          = `AND`
+	adapterOrKeyword           = `OR`
+	adapterNotKeyword          = `NOT`
+	adapterDescKeyword         = `DESC`
+	adapterAscKeyword          = `ASC`
+	adapterDefaultOperator     = `=`
+	adapterClauseGroup         = `({{.}})`
+	adapterClauseOperator      = ` {{.}} `
+	adapterColumnValue         = `{{.Column}} {{.Operator}} {{.Value}}`
+	adapterTableAliasLayout    = `{{.Name}}{{if .Alias}} AS {{.Alias}}{{end}}`
+	adapterColumnAliasLayout   = `{{.Name}}{{if .Alias}} AS {{.Alias}}{{end}}`
+	adapterSortByColumnLayout  = `{{.Column}} {{.Order}}`
+
+	adapterOrderByLayout = `
 		{{if .SortColumns}}
 			ORDER BY {{.SortColumns}}
 		{{end}}
 	`
 
-	sqlWhereLayout = `
+	adapterWhereLayout = `
 		{{if .Conds}}
 			WHERE {{.Conds}}
 		{{end}}
 	`
 
-	sqlSelectLayout = `
+	adapterSelectLayout = `
 		SELECT
 
 			{{if .Columns}}
@@ -75,24 +75,24 @@ const (
 
 			{{if .Offset}}
 				{{if not .Limit}}
-					LIMIT -1 
+					LIMIT -1
 				{{end}}
 				OFFSET {{.Offset}}
 			{{end}}
 	`
-	sqlDeleteLayout = `
+	adapterDeleteLayout = `
 		DELETE
 			FROM {{.Table}}
 			{{.Where}}
 	`
-	sqlUpdateLayout = `
+	adapterUpdateLayout = `
 		UPDATE
 			{{.Table}}
 		SET {{.ColumnValues}}
 			{{ .Where }}
 	`
 
-	sqlSelectCountLayout = `
+	adapterSelectCountLayout = `
 		SELECT
 			COUNT(1) AS _t
 		FROM {{.Table}}
@@ -104,13 +104,13 @@ const (
 
 			{{if .Offset}}
 				{{if not .Limit}}
-					LIMIT -1 
+					LIMIT -1
 				{{end}}
 				OFFSET {{.Offset}}
 			{{end}}
 	`
 
-	sqlInsertLayout = `
+	adapterInsertLayout = `
 		INSERT INTO {{.Table}}
 			({{.Columns}})
 		VALUES
@@ -118,23 +118,21 @@ const (
 		{{.Extra}}
 	`
 
-	sqlTruncateLayout = `
+	adapterTruncateLayout = `
 		DELETE FROM {{.Table}}
 	`
 
-	sqlDropDatabaseLayout = `
+	adapterDropDatabaseLayout = `
 		DROP DATABASE {{.Database}}
 	`
 
-	sqlDropTableLayout = `
+	adapterDropTableLayout = `
 		DROP TABLE {{.Table}}
 	`
 
-	sqlGroupByLayout = `
+	adapterGroupByLayout = `
 		{{if .GroupColumns}}
 			GROUP BY {{.GroupColumns}}
 		{{end}}
 	`
-
-	sqlNull = `NULL`
 )
diff --git a/sqlite/tx.go b/sqlite/tx.go
deleted file mode 100644
index dbfc7698..00000000
--- a/sqlite/tx.go
+++ /dev/null
@@ -1,44 +0,0 @@
-// 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.
-
-package sqlite
-
-import (
-	"github.com/jmoiron/sqlx"
-)
-
-type tx struct {
-	*source
-	sqlTx *sqlx.Tx
-	done  bool
-}
-
-func (t *tx) Commit() (err error) {
-	err = t.sqlTx.Commit()
-	if err == nil {
-		t.done = true
-	}
-	return err
-}
-
-func (t *tx) Rollback() error {
-	return t.sqlTx.Rollback()
-}
-- 
GitLab