From 1b19adeb4758179692f1a9b7d34ef4716bbe54c4 Mon Sep 17 00:00:00 2001
From: Carlos Nieto <jose.carlos@menteslibres.net>
Date: Mon, 14 Apr 2014 17:16:23 -0500
Subject: [PATCH] Adding db.Func{} support.

---
 mongo/collection.go    | 30 ++++++++++++++++++++----------
 mongo/database_test.go | 42 ++++++++++++++++++++++++++++++++++++++++++
 mongo/result.go        |  6 +++++-
 3 files changed, 67 insertions(+), 11 deletions(-)

diff --git a/mongo/collection.go b/mongo/collection.go
index 97bf700a..f3fb164a 100644
--- a/mongo/collection.go
+++ b/mongo/collection.go
@@ -70,15 +70,19 @@ func (self *Collection) Find(terms ...interface{}) db.Result {
 }
 
 // Transforms conditions into something *mgo.Session can understand.
-func compileStatement(where db.Cond) bson.M {
+func compileStatement(cond db.Cond) bson.M {
 	conds := bson.M{}
 
-	for key, val := range where {
-		key = strings.Trim(key, ` `)
-		chunks := strings.SplitN(key, ` `, 2)
+	// Walking over conditions
+	for field, value := range cond {
+		// Removing leading or trailing spaces.
+		field = strings.TrimSpace(field)
+
+		chunks := strings.SplitN(field, ` `, 2)
+
+		var op string
 
 		if len(chunks) > 1 {
-			op := ""
 			switch chunks[1] {
 			case `>`:
 				op = `$gt`
@@ -91,11 +95,17 @@ func compileStatement(where db.Cond) bson.M {
 			default:
 				op = chunks[1]
 			}
-			//conds[chunks[0]] = bson.M{op: toInternal(val)}
-			conds[chunks[0]] = bson.M{op: val}
-		} else {
-			//conds[key] = toInternal(val)
-			conds[key] = val
+		}
+
+		switch value := value.(type) {
+		case db.Func:
+			conds[chunks[0]] = bson.M{value.Name: value.Args}
+		default:
+			if op == "" {
+				conds[chunks[0]] = value
+			} else {
+				conds[chunks[0]] = bson.M{op: value}
+			}
 		}
 
 	}
diff --git a/mongo/database_test.go b/mongo/database_test.go
index a071612f..12bc4535 100644
--- a/mongo/database_test.go
+++ b/mongo/database_test.go
@@ -532,6 +532,48 @@ func TestUpdate(t *testing.T) {
 
 }
 
+// Test database functions
+func TestFunction(t *testing.T) {
+	var err error
+	var res db.Result
+
+	// Opening database.
+	sess, err := db.Open(wrapperName, settings)
+
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	// We should close the database when it's no longer in use.
+	defer sess.Close()
+
+	// Getting a pointer to the "artist" collection.
+	artist, err := sess.Collection("artist")
+
+	if err != nil {
+		t.Fatalf(err.Error())
+	}
+
+	row_s := struct {
+		Id   uint64
+		Name string
+	}{}
+
+	res = artist.Find(db.Cond{"_id $nin": []int{0, -1}})
+
+	if err = res.One(&row_s); err != nil {
+		t.Fatalf("One: %q", err)
+	}
+
+	res = artist.Find(db.Cond{"_id": db.Func{"$nin", []int{0, -1}}})
+
+	if err = res.One(&row_s); err != nil {
+		t.Fatalf("One: %q", err)
+	}
+
+	res.Close()
+}
+
 // This test tries to remove some previously added rows.
 func TestRemove(t *testing.T) {
 
diff --git a/mongo/result.go b/mongo/result.go
index 473f7640..abc6487c 100644
--- a/mongo/result.go
+++ b/mongo/result.go
@@ -126,7 +126,11 @@ func (self *Result) Next(dst interface{}) error {
 	success := self.iter.Next(dst)
 
 	if success == false {
-		return db.ErrNoMoreRows
+		err := self.iter.Err()
+		if err == nil {
+			return db.ErrNoMoreRows
+		}
+		return err
 	}
 
 	return nil
-- 
GitLab