From 2ae4bf81e61387e445a35fa3637e29739b9f1cfa Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?Jos=C3=A9=20Carlos=20Nieto?= <jose.carlos@menteslibres.net>
Date: Fri, 5 Dec 2014 09:55:46 -0600
Subject: [PATCH] QL: Adding support for db.Constrainer and db.IDSetter
 interfaces.

---
 ql/_dumps/structs.sql | 10 ++++++
 ql/collection.go      | 15 ++++++++
 ql/database_test.go   | 81 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 106 insertions(+)

diff --git a/ql/_dumps/structs.sql b/ql/_dumps/structs.sql
index 372e5eed..96ca94f5 100644
--- a/ql/_dumps/structs.sql
+++ b/ql/_dumps/structs.sql
@@ -54,4 +54,14 @@ CREATE TABLE stats_test (
 	value int64
 );
 
+DROP TABLE IF EXISTS composite_keys;
+
+-- Composite keys are currently not supported in QL.
+CREATE TABLE composite_keys (
+-- code string,
+-- user_id string,
+  some_val string,
+-- primary key (code, user_id)
+);
+
 COMMIT;
diff --git a/ql/collection.go b/ql/collection.go
index 5ad91f3a..07b889f0 100644
--- a/ql/collection.go
+++ b/ql/collection.go
@@ -79,6 +79,14 @@ func whereValues(term interface{}) (where sqlgen.Where, args []interface{}) {
 		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
@@ -245,6 +253,13 @@ func (t *table) Append(item interface{}) (interface{}, error) {
 	var id int64
 	id, _ = res.LastInsertId()
 
+	// Does the item satisfy the db.ID interface?
+	if setter, ok := item.(db.IDSetter); ok {
+		if err := setter.SetID([]interface{}{id}...); err != nil {
+			return nil, err
+		}
+	}
+
 	return id, nil
 }
 
diff --git a/ql/database_test.go b/ql/database_test.go
index 64a9b89e..6befcf76 100644
--- a/ql/database_test.go
+++ b/ql/database_test.go
@@ -34,6 +34,7 @@ import (
 
 	"menteslibres.net/gosexy/to"
 	//"reflect"
+	"errors"
 	"math/rand"
 	"strings"
 	"testing"
@@ -77,6 +78,26 @@ type testValuesStruct struct {
 	Time  time.Duration `field:"_time"`
 }
 
+type ItemWithKey struct {
+	ID      int64  `db:",omitempty"`
+	SomeVal string `db:"some_val"`
+}
+
+func (item ItemWithKey) Constraint() db.Cond {
+	cond := db.Cond{
+		"id()": item.ID,
+	}
+	return cond
+}
+
+func (item *ItemWithKey) SetID(keys ...interface{}) error {
+	if len(keys) == 1 {
+		item.ID = keys[0].(int64)
+		return nil
+	}
+	return errors.New(`Expecting exactly two keys.`)
+}
+
 var testValues testValuesStruct
 
 func init() {
@@ -1120,6 +1141,66 @@ func TestTransactionsAndRollback(t *testing.T) {
 
 }
 
+// QL: Does not support composite keys, so we're testing db.Constrainer and
+// db.IDSetter interface.
+func TestCompositeKeys(t *testing.T) {
+	var err error
+	var id interface{}
+	var sess db.Database
+	var compositeKeys db.Collection
+
+	if sess, err = db.Open(Adapter, settings); err != nil {
+		t.Fatal(err)
+	}
+
+	defer sess.Close()
+
+	if compositeKeys, err = sess.Collection("composite_keys"); err != nil {
+		t.Fatal(err)
+	}
+
+	//n := rand.Intn(100000)
+
+	item := ItemWithKey{
+		// 		"ABCDEF",
+		// 		strconv.Itoa(n),
+		0,
+		"Some value",
+	}
+
+	if id, err = compositeKeys.Append(&item); err != nil {
+		t.Fatal(err)
+	}
+
+	//	ids := id.([]interface{})
+
+	// 	if ids[0].(string) != item.Code {
+	// 		t.Fatal(`Keys must match.`)
+	// 	}
+	//
+	// 	if ids[1].(string) != item.UserID {
+	// 		t.Fatal(`Keys must match.`)
+	// 	}
+
+	// Using constraint interface.
+	res := compositeKeys.Find(ItemWithKey{ID: id.(int64)})
+
+	var item2 ItemWithKey
+
+	if item2.SomeVal == item.SomeVal {
+		t.Fatal(`Values must be different before query.`)
+	}
+
+	if err := res.One(&item2); err != nil {
+		t.Fatal(err)
+	}
+
+	if item2.SomeVal != item.SomeVal {
+		t.Fatal(`Values must be equal after query.`)
+	}
+
+}
+
 /*
 // Attempts to add many different datatypes to a single row in a collection,
 // then it tries to get the stored datatypes and check if the stored and the
-- 
GitLab