From 6a999f8116edd69a9ffd21fbb53abeae296eebc0 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Nieto?= <xiam@menteslibres.org>
Date: Sun, 2 Dec 2012 12:46:29 -0600
Subject: [PATCH] Cleaning a bit.

---
 sqlite/collection.go           | 576 +++++++++++++++++++++++++++++++
 sqlite/dumps/gotest.sqlite3.db | Bin 6144 -> 6144 bytes
 sqlite/sqlite.go               | 597 ++-------------------------------
 3 files changed, 601 insertions(+), 572 deletions(-)
 create mode 100644 sqlite/collection.go

diff --git a/sqlite/collection.go b/sqlite/collection.go
new file mode 100644
index 00000000..11ff1de3
--- /dev/null
+++ b/sqlite/collection.go
@@ -0,0 +1,576 @@
+/*
+  Copyright (c) 2012 JosĂŠ Carlos Nieto, http://xiam.menteslibres.org/
+
+  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 (
+	"database/sql"
+	"fmt"
+	"github.com/gosexy/db"
+	"github.com/gosexy/sugar"
+	"github.com/gosexy/to"
+	//_ "github.com/xiam/gosqlite3"
+	"reflect"
+	"regexp"
+	"strconv"
+	"strings"
+	"time"
+)
+
+func (self *Table) Name() string {
+	return self.name
+}
+
+func (t *Table) slFetchAll(rows sql.Rows) []db.Item {
+
+	items := []db.Item{}
+
+	columns, _ := rows.Columns()
+
+	for i, _ := range columns {
+		columns[i] = strings.ToLower(columns[i])
+	}
+
+	res := map[string]*sql.RawBytes{}
+
+	fargs := []reflect.Value{}
+
+	for _, name := range columns {
+		res[name] = &sql.RawBytes{}
+		fargs = append(fargs, reflect.ValueOf(res[name]))
+	}
+
+	sn := reflect.ValueOf(&rows)
+	fn := sn.MethodByName("Scan")
+
+	for rows.Next() {
+		item := db.Item{}
+
+		ret := fn.Call(fargs)
+
+		if ret[0].IsNil() != true {
+			panic(ret[0].Elem().Interface().(error))
+		}
+
+		for _, name := range columns {
+			strval := fmt.Sprintf("%s", *res[name])
+
+			switch t.types[name] {
+			case reflect.Uint64:
+				intval, _ := strconv.Atoi(strval)
+				item[name] = uint64(intval)
+			case reflect.Int64:
+				intval, _ := strconv.Atoi(strval)
+				item[name] = intval
+			case reflect.Float64:
+				floatval, _ := strconv.ParseFloat(strval, 10)
+				item[name] = floatval
+			default:
+				item[name] = strval
+			}
+		}
+
+		items = append(items, item)
+	}
+
+	return items
+}
+
+func (t *Table) invoke(fn string, terms []interface{}) []reflect.Value {
+
+	self := reflect.ValueOf(t)
+	method := self.MethodByName(fn)
+
+	args := make([]reflect.Value, len(terms))
+
+	itop := len(terms)
+	for i := 0; i < itop; i++ {
+		args[i] = reflect.ValueOf(terms[i])
+	}
+
+	exec := method.Call(args)
+
+	return exec
+}
+
+func (t *Table) compileSet(term db.Set) (string, db.SqlArgs) {
+	sql := []string{}
+	args := db.SqlArgs{}
+
+	for key, arg := range term {
+		sql = append(sql, fmt.Sprintf("%s = ?", key))
+		args = append(args, fmt.Sprintf("%v", arg))
+	}
+
+	return strings.Join(sql, ", "), args
+}
+
+func (t *Table) compileConditions(term interface{}) (string, db.SqlArgs) {
+	sql := []string{}
+	args := db.SqlArgs{}
+
+	switch term.(type) {
+	case []interface{}:
+		itop := len(term.([]interface{}))
+
+		for i := 0; i < itop; i++ {
+			rsql, rargs := t.compileConditions(term.([]interface{})[i])
+			if rsql != "" {
+				sql = append(sql, rsql)
+				for j := 0; j < len(rargs); j++ {
+					args = append(args, rargs[j])
+				}
+			}
+		}
+		if len(sql) > 0 {
+			return "(" + strings.Join(sql, " AND ") + ")", args
+		}
+	case db.Or:
+		itop := len(term.(db.Or))
+
+		for i := 0; i < itop; i++ {
+			rsql, rargs := t.compileConditions(term.(db.Or)[i])
+			if rsql != "" {
+				sql = append(sql, rsql)
+				for j := 0; j < len(rargs); j++ {
+					args = append(args, rargs[j])
+				}
+			}
+		}
+
+		if len(sql) > 0 {
+			return "(" + strings.Join(sql, " OR ") + ")", args
+		}
+	case db.And:
+		itop := len(term.(db.Or))
+
+		for i := 0; i < itop; i++ {
+			rsql, rargs := t.compileConditions(term.(db.Or)[i])
+			if rsql != "" {
+				sql = append(sql, rsql)
+				for j := 0; j < len(rargs); j++ {
+					args = append(args, rargs[j])
+				}
+			}
+		}
+
+		if len(sql) > 0 {
+			return "(" + strings.Join(sql, " AND ") + ")", args
+		}
+	case db.Cond:
+		return t.marshal(term.(db.Cond))
+	}
+
+	return "", args
+}
+
+func (t *Table) marshal(where db.Cond) (string, []string) {
+
+	for key, val := range where {
+		key = strings.Trim(key, " ")
+		chunks := strings.Split(key, " ")
+
+		strval := fmt.Sprintf("%v", val)
+
+		if len(chunks) >= 2 {
+			return fmt.Sprintf("%s %s ?", chunks[0], chunks[1]), []string{strval}
+		} else {
+			return fmt.Sprintf("%s = ?", chunks[0]), []string{strval}
+		}
+
+	}
+
+	return "", []string{}
+}
+
+// Deletes all the rows in the table.
+func (t *Table) Truncate() error {
+
+	_, err := t.parent.sqlExec(
+		"Exec",
+		fmt.Sprintf("DELETE FROM %s", t.Name()),
+	)
+
+	return err
+}
+
+// Deletes all the rows in the table that match certain conditions.
+func (t *Table) Remove(terms ...interface{}) error {
+
+	conditions, cargs := t.compileConditions(terms)
+
+	if conditions == "" {
+		conditions = "1 = 1"
+	}
+
+	_, err := t.parent.sqlExec(
+		"Exec",
+		fmt.Sprintf("DELETE FROM %s", t.Name()),
+		fmt.Sprintf("WHERE %s", conditions), cargs,
+	)
+
+	return err
+}
+
+// Modifies all the rows in the table that match certain conditions.
+func (t *Table) Update(terms ...interface{}) error {
+	var fields string
+	var fargs db.SqlArgs
+
+	conditions, cargs := t.compileConditions(terms)
+
+	for _, term := range terms {
+		switch term.(type) {
+		case db.Set:
+			fields, fargs = t.compileSet(term.(db.Set))
+		}
+	}
+
+	if conditions == "" {
+		conditions = "1 = 1"
+	}
+
+	_, err := t.parent.sqlExec(
+		"Exec",
+		fmt.Sprintf("UPDATE %s SET %s", t.Name(), fields), fargs,
+		fmt.Sprintf("WHERE %s", conditions), cargs,
+	)
+
+	return err
+}
+
+// Returns all the rows in the table that match certain conditions.
+func (t *Table) FindAll(terms ...interface{}) []db.Item {
+	var itop int
+
+	var relate interface{}
+	var relateAll interface{}
+
+	fields := "*"
+	conditions := ""
+	limit := ""
+	offset := ""
+	sort := ""
+
+	// Analyzing
+	itop = len(terms)
+
+	for i := 0; i < itop; i++ {
+		term := terms[i]
+
+		switch term.(type) {
+		case db.Limit:
+			limit = fmt.Sprintf("LIMIT %v", term.(db.Limit))
+		case db.Sort:
+			sortBy := []string{}
+			for k, v := range term.(db.Sort) {
+				v = strings.ToUpper(to.String(v))
+				if v == "-1" {
+					v = "DESC"
+				}
+				if v == "1" {
+					v = "ASC"
+				}
+				sortBy = append(sortBy, fmt.Sprintf("%s %s", k, v))
+			}
+			sort = fmt.Sprintf("ORDER BY %s", strings.Join(sortBy, ", "))
+		case db.Offset:
+			offset = fmt.Sprintf("OFFSET %v", term.(db.Offset))
+		case db.Fields:
+			fields = strings.Join(term.(db.Fields), ", ")
+		case db.Relate:
+			relate = term.(db.Relate)
+		case db.RelateAll:
+			relateAll = term.(db.RelateAll)
+		}
+	}
+
+	conditions, args := t.compileConditions(terms)
+
+	if conditions == "" {
+		conditions = "1 = 1"
+	}
+
+	rows, _ := t.parent.sqlExec(
+		"Query",
+		fmt.Sprintf("SELECT %s FROM %s", fields, t.Name()),
+		fmt.Sprintf("WHERE %s", conditions), args,
+		sort, limit, offset,
+	)
+
+	result := t.slFetchAll(rows)
+
+	var relations []sugar.Tuple
+	var rcollection db.Collection
+
+	// This query is related to other collections.
+	if relate != nil {
+		for rname, rterms := range relate.(db.Relate) {
+
+			rcollection = nil
+
+			ttop := len(rterms)
+			for t := ttop - 1; t >= 0; t-- {
+				rterm := rterms[t]
+				switch rterm.(type) {
+				case db.Collection:
+					rcollection = rterm.(db.Collection)
+				}
+			}
+
+			if rcollection == nil {
+				rcollection = t.parent.ExistentCollection(rname)
+			}
+
+			relations = append(relations, sugar.Tuple{"all": false, "name": rname, "collection": rcollection, "terms": rterms})
+		}
+	}
+
+	if relateAll != nil {
+		for rname, rterms := range relateAll.(db.RelateAll) {
+			rcollection = nil
+
+			ttop := len(rterms)
+			for t := ttop - 1; t >= 0; t-- {
+				rterm := rterms[t]
+				switch rterm.(type) {
+				case db.Collection:
+					rcollection = rterm.(db.Collection)
+				}
+			}
+
+			if rcollection == nil {
+				rcollection = t.parent.ExistentCollection(rname)
+			}
+
+			relations = append(relations, sugar.Tuple{"all": true, "name": rname, "collection": rcollection, "terms": rterms})
+		}
+	}
+
+	var term interface{}
+
+	jtop := len(relations)
+
+	itop = len(result)
+	items := make([]db.Item, itop)
+
+	for i := 0; i < itop; i++ {
+
+		item := db.Item{}
+
+		// Default values.
+		for key, val := range result[i] {
+			item[key] = val
+		}
+
+		// Querying relations
+		for j := 0; j < jtop; j++ {
+
+			relation := relations[j]
+
+			terms := []interface{}{}
+
+			ktop := len(relation["terms"].(db.On))
+
+			for k := 0; k < ktop; k++ {
+
+				//term = tcopy[k]
+				term = relation["terms"].(db.On)[k]
+
+				switch term.(type) {
+				// Just waiting for db.Cond statements.
+				case db.Cond:
+					for wkey, wval := range term.(db.Cond) {
+						//if reflect.TypeOf(wval).Kind() == reflect.String { // does not always work.
+						if reflect.TypeOf(wval).Name() == "string" {
+							// Matching dynamic values.
+							matched, _ := regexp.MatchString("\\{.+\\}", wval.(string))
+							if matched {
+								// Replacing dynamic values.
+								kname := strings.Trim(wval.(string), "{}")
+								term = db.Cond{wkey: item[kname]}
+							}
+						}
+					}
+				}
+				terms = append(terms, term)
+			}
+
+			// Executing external query.
+			if relation["all"] == true {
+				value := relation["collection"].(*Table).invoke("FindAll", terms)
+				item[relation["name"].(string)] = value[0].Interface().([]db.Item)
+			} else {
+				value := relation["collection"].(*Table).invoke("Find", terms)
+				item[relation["name"].(string)] = value[0].Interface().(db.Item)
+			}
+
+		}
+
+		// Appending to results.
+		items[i] = item
+	}
+
+	return items
+}
+
+// Returns the number of rows in the current table that match certain conditions.
+func (t *Table) Count(terms ...interface{}) (int, error) {
+
+	terms = append(terms, db.Fields{"COUNT(1) AS _total"})
+
+	result := t.invoke("FindAll", terms)
+
+	if len(result) > 0 {
+		response := result[0].Interface().([]db.Item)
+		if len(response) > 0 {
+			val, _ := strconv.Atoi(response[0]["_total"].(string))
+			return val, nil
+		}
+	}
+
+	return 0, nil
+}
+
+// Returns the first row in the table that matches certain conditions.
+func (t *Table) Find(terms ...interface{}) db.Item {
+
+	var item db.Item
+
+	terms = append(terms, db.Limit(1))
+
+	result := t.invoke("FindAll", terms)
+
+	if len(result) > 0 {
+		response := result[0].Interface().([]db.Item)
+		if len(response) > 0 {
+			item = response[0]
+		}
+	}
+
+	return item
+}
+
+func toInternal(val interface{}) string {
+
+	switch val.(type) {
+	case []byte:
+		return fmt.Sprintf("%s", string(val.([]byte)))
+	case time.Time:
+		return val.(time.Time).Format(dateFormat)
+	case time.Duration:
+		t := val.(time.Duration)
+		//return fmt.Sprintf(timeFormat, int(t.Hours()), int(t.Minutes())%60, int(t.Seconds())%60, int(t.Nanoseconds())%1e9)
+		return fmt.Sprintf(timeFormat, int(t.Hours()), int(t.Minutes())%60, int(t.Seconds())%60)
+	case bool:
+		if val.(bool) == true {
+			return "1"
+		} else {
+			return "0"
+		}
+	}
+
+	return fmt.Sprintf("%v", val)
+}
+
+func toNative(val interface{}) interface{} {
+
+	switch val.(type) {
+	}
+
+	return val
+
+}
+
+// Inserts rows into the currently active table.
+func (t *Table) Append(items ...interface{}) ([]db.Id, error) {
+
+	ids := []db.Id{}
+
+	itop := len(items)
+
+	for i := 0; i < itop; i++ {
+
+		values := []string{}
+		fields := []string{}
+
+		item := items[i]
+
+		for field, value := range item.(db.Item) {
+			fields = append(fields, field)
+			values = append(values, toInternal(value))
+		}
+
+		_, err := t.parent.sqlExec(
+			"Exec",
+			"INSERT INTO",
+			t.Name(),
+			sqlFields(fields),
+			"VALUES",
+			sqlValues(values),
+		)
+
+		res, _ := t.parent.sqlExec(
+			"Query",
+			"SELECT LAST_INSERT_ROWID()",
+		)
+
+		var lastId string
+
+		res.Next()
+
+		res.Scan(&lastId)
+
+		ids = append(ids, db.Id(lastId))
+
+		if err != nil {
+			return ids, err
+		}
+
+	}
+
+	return ids, nil
+}
+
+// Returns true if the collection exists.
+func (self *Table) Exists() bool {
+	result, err := self.parent.sqlExec(
+		"Query",
+		fmt.Sprintf(`
+			SELECT name
+				FROM sqlite_master
+				WHERE type = 'table' AND name = '%s'
+			`,
+			self.Name(),
+		),
+	)
+	if err != nil {
+		panic(err.Error())
+	}
+	if result.Next() == true {
+		result.Close()
+		return true
+	}
+	return false
+}
+
diff --git a/sqlite/dumps/gotest.sqlite3.db b/sqlite/dumps/gotest.sqlite3.db
index eedf0c9eaf6f7be66c32c448ef85c6a3c1ba4ef2..d3f9260cfcd36f7fe8c96e90c9bd7acf9cdfa0ed 100644
GIT binary patch
delta 610
zcmZvZy-wRu6o7rsx%W7UlNOR(Ba@WE#DJ=jA6|eFlqy0<OsxndEs+AL0t|F$Gj~d4
zsZ*ycOb`Jhf(5DY0!;7#44ujg^jsG)*^=+4^ZEGv*uDAQe18%%zXrucIZxIvXqNB~
z-r^-5VjmB11DCOiQ<#9ia1X!X7=FSx_yq6HW)dm*?oTNP-s+XkMzg!uncbcKxYcTJ
zPA~YcVtv&w#`=n1i1lTEGS-*!f%rKJZ}fH;y4m+R3E#N2*600Z`+170$;Ro58IRLt
zGZv>y=4Du7A703rr>e<BteAAfvhgg#!2KGo>MW?Ru5A`YtQd?~HefkX%FwmLG<4{Z
z9_XCzXh<U($*1hmpq~EVu}lzPt+69(q+I1Bga0d~lyVY5t<k+YYB-LQm;3p$fu|+6
z@bnjwB*8?zx!LV_XbaL(XSexf>ok4fj%&8dgVJob1=8V<-0L-$JsY9RsmQvVwA6|d
kmP)Y<BhTeEsST`cKVX)zB#T)(N-bpD4iqw2G7j_VA7$Kl*#H0l

delta 585
zcmZvY!AcxK5Qe9!x@&f3*0`(o$gY~`$y12#t}l>-hrotSE?$&mqeB!HS5`d;A+A?F
zsPq%)QHUD7B@qk><Sv1nd;kNv<pEMXLJ*lg)K7gySO5KYC%O}RWz5g+4?mUq@%06b
zBmTxK{Dg<NgKId4)A$5SNbm=K!B;o}3-2I-=jUU&5YRldyMFv)M0xNSpS4$$mBsPZ
z(fP%t*1~Ab3}@l08Op*HQ@(@k7yaIT=K@WcetXF=^hq6{swt*gF@;no<6hg)gYZDA
zp<3KyyVB*;t`bM~RL8dLZ*2PYrMK%z>%X-rqugWnam`Q`t{Tk36$4p#vWI?pOa~ra
z(+z#5A9SGTm`)_HE!uB{uOgOfC9F4>#Zu(EhHm|Z;wmWBo1JeTnvqssZs=wEP10Fw
z(_b&}+zG`=P`V8|5VOHxBU$LQWs*<lQqJ-lei6ASdqE)=oD$mY{zo&4BiEtgFr|tE
or&@E)snYD+01A-Rz*;<runP+`vr7laXBP)3pWXj~{lfwE55U%S)c^nh

diff --git a/sqlite/sqlite.go b/sqlite/sqlite.go
index c1442be9..254b4151 100644
--- a/sqlite/sqlite.go
+++ b/sqlite/sqlite.go
@@ -27,15 +27,11 @@ import (
 	"database/sql"
 	"fmt"
 	"github.com/gosexy/db"
-	"github.com/gosexy/sugar"
-	"github.com/gosexy/to"
-	//_ "github.com/xiam/gosqlite3"
-	_ "bitbucket.org/minux/go.sqlite3"
+	_ "github.com/xiam/gosqlite3"
+	//_ "bitbucket.org/minux/go.sqlite3"
 	"reflect"
 	"regexp"
-	"strconv"
 	"strings"
-	"time"
 )
 
 var Debug = false
@@ -44,16 +40,16 @@ const dateFormat = "2006-01-02 15:04:05"
 const timeFormat = "%d:%02d:%02d"
 
 func init() {
-	db.Register("sqlite", &SqliteDataSource{})
+	db.Register("sqlite", &Source{})
 }
 
-type slQuery struct {
+type sqlQuery struct {
 	Query   []string
 	SqlArgs []string
 }
 
-func slCompile(terms []interface{}) *slQuery {
-	q := &slQuery{}
+func sqlCompile(terms []interface{}) *sqlQuery {
+	q := &sqlQuery{}
 
 	q.Query = []string{}
 
@@ -78,15 +74,11 @@ func slCompile(terms []interface{}) *slQuery {
 	return q
 }
 
-func slTable(name string) string {
-	return name
-}
-
-func slFields(names []string) string {
+func sqlFields(names []string) string {
 	return "(" + strings.Join(names, ", ") + ")"
 }
 
-func slValues(values []string) db.SqlValues {
+func sqlValues(values []string) db.SqlValues {
 	ret := make(db.SqlValues, len(values))
 	for i, _ := range values {
 		ret[i] = values[i]
@@ -95,84 +87,25 @@ func slValues(values []string) db.SqlValues {
 }
 
 // Stores driver's session data.
-type SqliteDataSource struct {
+type Source struct {
 	config      db.DataSource
 	session     *sql.DB
 	name        string
 	collections map[string]db.Collection
 }
 
-func (self *SqliteDataSource) Name() string {
+func (self *Source) Name() string {
 	return self.config.Database
 }
 
-func (self *SqliteTable) Name() string {
-	return self.name
-}
-
-func (t *SqliteTable) slFetchAll(rows sql.Rows) []db.Item {
-
-	items := []db.Item{}
-
-	columns, _ := rows.Columns()
-
-	for i, _ := range columns {
-		columns[i] = strings.ToLower(columns[i])
-	}
-
-	res := map[string]*sql.RawBytes{}
-
-	fargs := []reflect.Value{}
-
-	for _, name := range columns {
-		res[name] = &sql.RawBytes{}
-		fargs = append(fargs, reflect.ValueOf(res[name]))
-	}
-
-	sn := reflect.ValueOf(&rows)
-	fn := sn.MethodByName("Scan")
-
-	for rows.Next() {
-		item := db.Item{}
-
-		ret := fn.Call(fargs)
-
-		if ret[0].IsNil() != true {
-			panic(ret[0].Elem().Interface().(error))
-		}
-
-		for _, name := range columns {
-			strval := fmt.Sprintf("%s", *res[name])
-
-			switch t.types[name] {
-			case reflect.Uint64:
-				intval, _ := strconv.Atoi(strval)
-				item[name] = uint64(intval)
-			case reflect.Int64:
-				intval, _ := strconv.Atoi(strval)
-				item[name] = intval
-			case reflect.Float64:
-				floatval, _ := strconv.ParseFloat(strval, 10)
-				item[name] = floatval
-			default:
-				item[name] = strval
-			}
-		}
-
-		items = append(items, item)
-	}
-
-	return items
-}
-
-func (sl *SqliteDataSource) slExec(method string, terms ...interface{}) (sql.Rows, error) {
+func (sl *Source) sqlExec(method string, terms ...interface{}) (sql.Rows, error) {
 
 	var rows sql.Rows
 
 	sn := reflect.ValueOf(sl.session)
 	fn := sn.MethodByName(method)
 
-	q := slCompile(terms)
+	q := sqlCompile(terms)
 
 	if Debug == true {
 		fmt.Printf("Q: %v\n", q.Query)
@@ -202,14 +135,14 @@ func (sl *SqliteDataSource) slExec(method string, terms ...interface{}) (sql.Row
 }
 
 // Represents a SQLite table.
-type SqliteTable struct {
-	parent *SqliteDataSource
+type Table struct {
+	parent *Source
 	name   string
 	types  map[string]reflect.Kind
 }
 
 // Configures and returns a SQLite database session.
-func (self *SqliteDataSource) Setup(config db.DataSource) error {
+func (self *Source) Setup(config db.DataSource) error {
 	self.config = config
 	self.collections = make(map[string]db.Collection)
 	return self.Open()
@@ -217,19 +150,19 @@ func (self *SqliteDataSource) Setup(config db.DataSource) error {
 
 // Deprecated: Configures and returns a SQLite database session.
 func SqliteSession(config db.DataSource) db.Database {
-	m := &SqliteDataSource{}
+	m := &Source{}
 	m.config = config
 	m.collections = make(map[string]db.Collection)
 	return m
 }
 
 // Returns a *sql.DB object that represents an internal session.
-func (sl *SqliteDataSource) Driver() interface{} {
+func (sl *Source) Driver() interface{} {
 	return sl.session
 }
 
 // Tries to open a connection to the current SQLite session.
-func (sl *SqliteDataSource) Open() error {
+func (sl *Source) Open() error {
 	var err error
 
 	if sl.config.Database == "" {
@@ -246,7 +179,7 @@ func (sl *SqliteDataSource) Open() error {
 }
 
 // Closes a previously opened SQLite database session.
-func (sl *SqliteDataSource) Close() error {
+func (sl *Source) Close() error {
 	if sl.session != nil {
 		return sl.session.Close()
 	}
@@ -254,20 +187,20 @@ func (sl *SqliteDataSource) Close() error {
 }
 
 // Changes the active database.
-func (sl *SqliteDataSource) Use(database string) error {
+func (sl *Source) Use(database string) error {
 	sl.config.Database = database
 	sl.session.Query(fmt.Sprintf("USE %s", database))
 	return nil
 }
 
 // Deletes the currently active database.
-func (sl *SqliteDataSource) Drop() error {
+func (sl *Source) Drop() error {
 	sl.session.Query(fmt.Sprintf("DROP DATABASE %s", sl.config.Database))
 	return nil
 }
 
 // Returns the list of SQLite tables in the current database.
-func (sl *SqliteDataSource) Collections() []string {
+func (sl *Source) Collections() []string {
 	var collections []string
 	var collection string
 
@@ -281,487 +214,7 @@ func (sl *SqliteDataSource) Collections() []string {
 	return collections
 }
 
-func (t *SqliteTable) invoke(fn string, terms []interface{}) []reflect.Value {
-
-	self := reflect.ValueOf(t)
-	method := self.MethodByName(fn)
-
-	args := make([]reflect.Value, len(terms))
-
-	itop := len(terms)
-	for i := 0; i < itop; i++ {
-		args[i] = reflect.ValueOf(terms[i])
-	}
-
-	exec := method.Call(args)
-
-	return exec
-}
-
-func (t *SqliteTable) compileSet(term db.Set) (string, db.SqlArgs) {
-	sql := []string{}
-	args := db.SqlArgs{}
-
-	for key, arg := range term {
-		sql = append(sql, fmt.Sprintf("%s = ?", key))
-		args = append(args, fmt.Sprintf("%v", arg))
-	}
-
-	return strings.Join(sql, ", "), args
-}
-
-func (t *SqliteTable) compileConditions(term interface{}) (string, db.SqlArgs) {
-	sql := []string{}
-	args := db.SqlArgs{}
-
-	switch term.(type) {
-	case []interface{}:
-		itop := len(term.([]interface{}))
-
-		for i := 0; i < itop; i++ {
-			rsql, rargs := t.compileConditions(term.([]interface{})[i])
-			if rsql != "" {
-				sql = append(sql, rsql)
-				for j := 0; j < len(rargs); j++ {
-					args = append(args, rargs[j])
-				}
-			}
-		}
-		if len(sql) > 0 {
-			return "(" + strings.Join(sql, " AND ") + ")", args
-		}
-	case db.Or:
-		itop := len(term.(db.Or))
-
-		for i := 0; i < itop; i++ {
-			rsql, rargs := t.compileConditions(term.(db.Or)[i])
-			if rsql != "" {
-				sql = append(sql, rsql)
-				for j := 0; j < len(rargs); j++ {
-					args = append(args, rargs[j])
-				}
-			}
-		}
-
-		if len(sql) > 0 {
-			return "(" + strings.Join(sql, " OR ") + ")", args
-		}
-	case db.And:
-		itop := len(term.(db.Or))
-
-		for i := 0; i < itop; i++ {
-			rsql, rargs := t.compileConditions(term.(db.Or)[i])
-			if rsql != "" {
-				sql = append(sql, rsql)
-				for j := 0; j < len(rargs); j++ {
-					args = append(args, rargs[j])
-				}
-			}
-		}
-
-		if len(sql) > 0 {
-			return "(" + strings.Join(sql, " AND ") + ")", args
-		}
-	case db.Cond:
-		return t.marshal(term.(db.Cond))
-	}
-
-	return "", args
-}
-
-func (t *SqliteTable) marshal(where db.Cond) (string, []string) {
-
-	for key, val := range where {
-		key = strings.Trim(key, " ")
-		chunks := strings.Split(key, " ")
-
-		strval := fmt.Sprintf("%v", val)
-
-		if len(chunks) >= 2 {
-			return fmt.Sprintf("%s %s ?", chunks[0], chunks[1]), []string{strval}
-		} else {
-			return fmt.Sprintf("%s = ?", chunks[0]), []string{strval}
-		}
-
-	}
-
-	return "", []string{}
-}
-
-// Deletes all the rows in the table.
-func (t *SqliteTable) Truncate() error {
-
-	_, err := t.parent.slExec(
-		"Exec",
-		fmt.Sprintf("DELETE FROM %s", t.Name()),
-	)
-
-	fmt.Printf("E: %v\n", err)
-
-	return err
-}
-
-// Deletes all the rows in the table that match certain conditions.
-func (t *SqliteTable) Remove(terms ...interface{}) error {
-
-	conditions, cargs := t.compileConditions(terms)
-
-	if conditions == "" {
-		conditions = "1 = 1"
-	}
-
-	_, err := t.parent.slExec(
-		"Exec",
-		fmt.Sprintf("DELETE FROM %s", slTable(t.name)),
-		fmt.Sprintf("WHERE %s", conditions), cargs,
-	)
-
-	return err
-}
-
-// Modifies all the rows in the table that match certain conditions.
-func (t *SqliteTable) Update(terms ...interface{}) error {
-	var fields string
-	var fargs db.SqlArgs
-
-	conditions, cargs := t.compileConditions(terms)
-
-	for _, term := range terms {
-		switch term.(type) {
-		case db.Set:
-			fields, fargs = t.compileSet(term.(db.Set))
-		}
-	}
-
-	if conditions == "" {
-		conditions = "1 = 1"
-	}
-
-	_, err := t.parent.slExec(
-		"Exec",
-		fmt.Sprintf("UPDATE %s SET %s", slTable(t.name), fields), fargs,
-		fmt.Sprintf("WHERE %s", conditions), cargs,
-	)
-
-	return err
-}
-
-// Returns all the rows in the table that match certain conditions.
-func (t *SqliteTable) FindAll(terms ...interface{}) []db.Item {
-	var itop int
-
-	var relate interface{}
-	var relateAll interface{}
-
-	fields := "*"
-	conditions := ""
-	limit := ""
-	offset := ""
-	sort := ""
-
-	// Analyzing
-	itop = len(terms)
-
-	for i := 0; i < itop; i++ {
-		term := terms[i]
-
-		switch term.(type) {
-		case db.Limit:
-			limit = fmt.Sprintf("LIMIT %v", term.(db.Limit))
-		case db.Sort:
-			sortBy := []string{}
-			for k, v := range term.(db.Sort) {
-				v = strings.ToUpper(to.String(v))
-				if v == "-1" {
-					v = "DESC"
-				}
-				if v == "1" {
-					v = "ASC"
-				}
-				sortBy = append(sortBy, fmt.Sprintf("%s %s", k, v))
-			}
-			sort = fmt.Sprintf("ORDER BY %s", strings.Join(sortBy, ", "))
-		case db.Offset:
-			offset = fmt.Sprintf("OFFSET %v", term.(db.Offset))
-		case db.Fields:
-			fields = strings.Join(term.(db.Fields), ", ")
-		case db.Relate:
-			relate = term.(db.Relate)
-		case db.RelateAll:
-			relateAll = term.(db.RelateAll)
-		}
-	}
-
-	conditions, args := t.compileConditions(terms)
-
-	if conditions == "" {
-		conditions = "1 = 1"
-	}
-
-	rows, _ := t.parent.slExec(
-		"Query",
-		fmt.Sprintf("SELECT %s FROM %s", fields, slTable(t.name)),
-		fmt.Sprintf("WHERE %s", conditions), args,
-		sort, limit, offset,
-	)
-
-	result := t.slFetchAll(rows)
-
-	var relations []sugar.Tuple
-	var rcollection db.Collection
-
-	// This query is related to other collections.
-	if relate != nil {
-		for rname, rterms := range relate.(db.Relate) {
-
-			rcollection = nil
-
-			ttop := len(rterms)
-			for t := ttop - 1; t >= 0; t-- {
-				rterm := rterms[t]
-				switch rterm.(type) {
-				case db.Collection:
-					rcollection = rterm.(db.Collection)
-				}
-			}
-
-			if rcollection == nil {
-				rcollection = t.parent.ExistentCollection(rname)
-			}
-
-			relations = append(relations, sugar.Tuple{"all": false, "name": rname, "collection": rcollection, "terms": rterms})
-		}
-	}
-
-	if relateAll != nil {
-		for rname, rterms := range relateAll.(db.RelateAll) {
-			rcollection = nil
-
-			ttop := len(rterms)
-			for t := ttop - 1; t >= 0; t-- {
-				rterm := rterms[t]
-				switch rterm.(type) {
-				case db.Collection:
-					rcollection = rterm.(db.Collection)
-				}
-			}
-
-			if rcollection == nil {
-				rcollection = t.parent.ExistentCollection(rname)
-			}
-
-			relations = append(relations, sugar.Tuple{"all": true, "name": rname, "collection": rcollection, "terms": rterms})
-		}
-	}
-
-	var term interface{}
-
-	jtop := len(relations)
-
-	itop = len(result)
-	items := make([]db.Item, itop)
-
-	for i := 0; i < itop; i++ {
-
-		item := db.Item{}
-
-		// Default values.
-		for key, val := range result[i] {
-			item[key] = val
-		}
-
-		// Querying relations
-		for j := 0; j < jtop; j++ {
-
-			relation := relations[j]
-
-			terms := []interface{}{}
-
-			ktop := len(relation["terms"].(db.On))
-
-			for k := 0; k < ktop; k++ {
-
-				//term = tcopy[k]
-				term = relation["terms"].(db.On)[k]
-
-				switch term.(type) {
-				// Just waiting for db.Cond statements.
-				case db.Cond:
-					for wkey, wval := range term.(db.Cond) {
-						//if reflect.TypeOf(wval).Kind() == reflect.String { // does not always work.
-						if reflect.TypeOf(wval).Name() == "string" {
-							// Matching dynamic values.
-							matched, _ := regexp.MatchString("\\{.+\\}", wval.(string))
-							if matched {
-								// Replacing dynamic values.
-								kname := strings.Trim(wval.(string), "{}")
-								term = db.Cond{wkey: item[kname]}
-							}
-						}
-					}
-				}
-				terms = append(terms, term)
-			}
-
-			// Executing external query.
-			if relation["all"] == true {
-				value := relation["collection"].(*SqliteTable).invoke("FindAll", terms)
-				item[relation["name"].(string)] = value[0].Interface().([]db.Item)
-			} else {
-				value := relation["collection"].(*SqliteTable).invoke("Find", terms)
-				item[relation["name"].(string)] = value[0].Interface().(db.Item)
-			}
-
-		}
-
-		// Appending to results.
-		items[i] = item
-	}
-
-	return items
-}
-
-// Returns the number of rows in the current table that match certain conditions.
-func (t *SqliteTable) Count(terms ...interface{}) (int, error) {
-
-	terms = append(terms, db.Fields{"COUNT(1) AS _total"})
-
-	result := t.invoke("FindAll", terms)
-
-	if len(result) > 0 {
-		response := result[0].Interface().([]db.Item)
-		if len(response) > 0 {
-			val, _ := strconv.Atoi(response[0]["_total"].(string))
-			return val, nil
-		}
-	}
-
-	return 0, nil
-}
-
-// Returns the first row in the table that matches certain conditions.
-func (t *SqliteTable) Find(terms ...interface{}) db.Item {
-
-	var item db.Item
-
-	terms = append(terms, db.Limit(1))
-
-	result := t.invoke("FindAll", terms)
-
-	if len(result) > 0 {
-		response := result[0].Interface().([]db.Item)
-		if len(response) > 0 {
-			item = response[0]
-		}
-	}
-
-	return item
-}
-
-func toInternal(val interface{}) string {
-
-	switch val.(type) {
-	case []byte:
-		return fmt.Sprintf("%s", string(val.([]byte)))
-	case time.Time:
-		return val.(time.Time).Format(dateFormat)
-	case time.Duration:
-		t := val.(time.Duration)
-		//return fmt.Sprintf(timeFormat, int(t.Hours()), int(t.Minutes())%60, int(t.Seconds())%60, int(t.Nanoseconds())%1e9)
-		return fmt.Sprintf(timeFormat, int(t.Hours()), int(t.Minutes())%60, int(t.Seconds())%60)
-	case bool:
-		if val.(bool) == true {
-			return "1"
-		} else {
-			return "0"
-		}
-	}
-
-	return fmt.Sprintf("%v", val)
-}
-
-func toNative(val interface{}) interface{} {
-
-	switch val.(type) {
-	}
-
-	return val
-
-}
-
-// Inserts rows into the currently active table.
-func (t *SqliteTable) Append(items ...interface{}) ([]db.Id, error) {
-
-	ids := []db.Id{}
-
-	itop := len(items)
-
-	for i := 0; i < itop; i++ {
-
-		values := []string{}
-		fields := []string{}
-
-		item := items[i]
-
-		for field, value := range item.(db.Item) {
-			fields = append(fields, field)
-			values = append(values, toInternal(value))
-		}
-
-		_, err := t.parent.slExec(
-			"Exec",
-			"INSERT INTO",
-			slTable(t.name),
-			slFields(fields),
-			"VALUES",
-			slValues(values),
-		)
-
-		res, _ := t.parent.slExec(
-			"Query",
-			"SELECT LAST_INSERT_ROWID()",
-		)
-
-		var lastId string
-
-		res.Next()
-
-		res.Scan(&lastId)
-
-		ids = append(ids, db.Id(lastId))
-
-		if err != nil {
-			return ids, err
-		}
-
-	}
-
-	return ids, nil
-}
-
-// Returns true if the collection exists.
-func (self *SqliteTable) Exists() bool {
-	result, err := self.parent.slExec(
-		"Query",
-		fmt.Sprintf(`
-			SELECT name
-				FROM sqlite_master
-				WHERE type = 'table' AND name = '%s'
-			`,
-			self.Name(),
-		),
-	)
-	if err != nil {
-		panic(err.Error())
-	}
-	if result.Next() == true {
-		result.Close()
-		return true
-	}
-	return false
-}
-
-func (self *SqliteDataSource) ExistentCollection(name string) db.Collection {
+func (self *Source) ExistentCollection(name string) db.Collection {
 	col, err := self.Collection(name)
 	if err != nil {
 		panic(err)
@@ -770,13 +223,13 @@ func (self *SqliteDataSource) ExistentCollection(name string) db.Collection {
 }
 
 // Returns a SQLite table structure by name.
-func (sl *SqliteDataSource) Collection(name string) (db.Collection, error) {
+func (sl *Source) Collection(name string) (db.Collection, error) {
 
 	if collection, ok := sl.collections[name]; ok == true {
 		return collection, nil
 	}
 
-	t := &SqliteTable{}
+	t := &Table{}
 
 	t.parent = sl
 	t.name = name
-- 
GitLab