diff --git a/db/define_test.go b/db/define_test.go index bc50d57d..f1645dfe 100644 --- a/db/define_test.go +++ b/db/define_test.go @@ -1075,14 +1075,14 @@ func TestDefine(t *testing.T) { }) - Convey("Define a unique index on a table, and ensure it prevents duplicate record values", t, func() { + Convey("Define a single-field unique index on a table, and ensure it prevents duplicate record values", t, func() { setupDB(20) txt := ` USE NS test DB test; - DEFINE INDEX test ON person COLUMNS account, email UNIQUE; - UPDATE person:one SET account="demo", email="info@demo.com"; + DEFINE INDEX test ON person COLUMNS email UNIQUE; + UPDATE person:one SET account="one", email="info@demo.com"; UPDATE person:one SET account="demo", email="info@demo.com"; UPDATE person:one SET account="demo", email="info@demo.com"; UPDATE person:two SET account="demo", email="info@demo.com"; @@ -1109,6 +1109,78 @@ func TestDefine(t *testing.T) { }) + Convey("Define a multiple-field unique index on a table, and ensure it prevents duplicate record values", t, func() { + + setupDB(20) + + txt := ` + USE NS test DB test; + DEFINE INDEX test ON person COLUMNS account, email UNIQUE; + UPDATE person:one SET account="one", email="info@demo.com"; + UPDATE person:one SET account="one", email="info@demo.com"; + UPDATE person:one SET account="one", email="info@demo.com"; + UPDATE person:two SET account="two", email="info@demo.com"; + UPDATE person:tre SET account="tre", email="info@demo.com"; + SELECT * FROM person ORDER BY meta.id; + ` + + res, err := Execute(setupKV(), txt, nil) + So(err, ShouldBeNil) + So(res, ShouldHaveLength, 8) + So(res[1].Status, ShouldEqual, "OK") + So(res[2].Result, ShouldHaveLength, 1) + So(res[2].Status, ShouldEqual, "OK") + So(res[3].Result, ShouldHaveLength, 1) + So(res[3].Status, ShouldEqual, "OK") + So(res[4].Result, ShouldHaveLength, 1) + So(res[4].Status, ShouldEqual, "OK") + So(res[5].Result, ShouldHaveLength, 1) + So(res[5].Status, ShouldEqual, "OK") + So(res[6].Result, ShouldHaveLength, 1) + So(res[6].Status, ShouldEqual, "OK") + So(res[7].Result, ShouldHaveLength, 3) + So(data.Consume(res[7].Result[0]).Get("id").Data(), ShouldResemble, &sql.Thing{"person", "one"}) + So(data.Consume(res[7].Result[1]).Get("id").Data(), ShouldResemble, &sql.Thing{"person", "tre"}) + So(data.Consume(res[7].Result[2]).Get("id").Data(), ShouldResemble, &sql.Thing{"person", "two"}) + + }) + + Convey("Define a multiple-field foreign record unique index on a table, and ensure it prevents duplicate record values", t, func() { + + setupDB(20) + + txt := ` + USE NS test DB test; + DEFINE INDEX test ON person COLUMNS account, email UNIQUE; + UPDATE person:one SET account=tester:one, email="info@demo.com"; + UPDATE person:one SET account=tester:one, email="info@demo.com"; + UPDATE person:one SET account=tester:one, email="info@demo.com"; + UPDATE person:two SET account=tester:two, email="info@demo.com"; + UPDATE person:tre SET account=tester:tre, email="info@demo.com"; + SELECT * FROM person ORDER BY meta.id; + ` + + res, err := Execute(setupKV(), txt, nil) + So(err, ShouldBeNil) + So(res, ShouldHaveLength, 8) + So(res[1].Status, ShouldEqual, "OK") + So(res[2].Result, ShouldHaveLength, 1) + So(res[2].Status, ShouldEqual, "OK") + So(res[3].Result, ShouldHaveLength, 1) + So(res[3].Status, ShouldEqual, "OK") + So(res[4].Result, ShouldHaveLength, 1) + So(res[4].Status, ShouldEqual, "OK") + So(res[5].Result, ShouldHaveLength, 1) + So(res[5].Status, ShouldEqual, "OK") + So(res[6].Result, ShouldHaveLength, 1) + So(res[6].Status, ShouldEqual, "OK") + So(res[7].Result, ShouldHaveLength, 3) + So(data.Consume(res[7].Result[0]).Get("id").Data(), ShouldResemble, &sql.Thing{"person", "one"}) + So(data.Consume(res[7].Result[1]).Get("id").Data(), ShouldResemble, &sql.Thing{"person", "tre"}) + So(data.Consume(res[7].Result[2]).Get("id").Data(), ShouldResemble, &sql.Thing{"person", "two"}) + + }) + Convey("Redefine a unique index on a table, and ensure it prevents duplicate record values", t, func() { setupDB(20) diff --git a/db/document.go b/db/document.go index e7b16bbf..1ae485f8 100644 --- a/db/document.go +++ b/db/document.go @@ -360,7 +360,7 @@ func (d *document) storeThing(ctx context.Context) (err error) { defer d.ulock(ctx) - // Check that the rcord has been + // Check that the record has been // changed, and if not, return. if ok := d.changed(ctx); !ok { @@ -475,27 +475,31 @@ func (d *document) storeIndex(ctx context.Context) (err error) { } if ix.Uniq == true { - for _, v := range del { - didx := &keys.Index{KV: d.key.KV, NS: d.key.NS, DB: d.key.DB, TB: d.key.TB, IX: ix.Name.VA, FD: v} + for _, f := range del { + enfd := data.Consume(f).Encode() + didx := &keys.Index{KV: d.key.KV, NS: d.key.NS, DB: d.key.DB, TB: d.key.TB, IX: ix.Name.VA, FD: enfd} d.i.e.dbo.DelC(ctx, d.i.e.time, didx.Encode(), d.id.Bytes()) } - for _, v := range add { - aidx := &keys.Index{KV: d.key.KV, NS: d.key.NS, DB: d.key.DB, TB: d.key.TB, IX: ix.Name.VA, FD: v} + for _, f := range add { + enfd := data.Consume(f).Encode() + aidx := &keys.Index{KV: d.key.KV, NS: d.key.NS, DB: d.key.DB, TB: d.key.TB, IX: ix.Name.VA, FD: enfd} if _, err = d.i.e.dbo.PutC(ctx, 0, aidx.Encode(), d.id.Bytes(), nil); err != nil { - return &IndexError{tb: d.key.TB, name: ix.Name, cols: ix.Cols, vals: v} + return &IndexError{tb: d.key.TB, name: ix.Name, cols: ix.Cols, vals: f} } } } if ix.Uniq == false { - for _, v := range del { - didx := &keys.Point{KV: d.key.KV, NS: d.key.NS, DB: d.key.DB, TB: d.key.TB, IX: ix.Name.VA, FD: v, ID: d.key.ID} + for _, f := range del { + enfd := data.Consume(f).Encode() + didx := &keys.Point{KV: d.key.KV, NS: d.key.NS, DB: d.key.DB, TB: d.key.TB, IX: ix.Name.VA, FD: enfd, ID: d.key.ID} d.i.e.dbo.DelC(ctx, d.i.e.time, didx.Encode(), d.id.Bytes()) } - for _, v := range add { - aidx := &keys.Point{KV: d.key.KV, NS: d.key.NS, DB: d.key.DB, TB: d.key.TB, IX: ix.Name.VA, FD: v, ID: d.key.ID} + for _, f := range add { + enfd := data.Consume(f).Encode() + aidx := &keys.Point{KV: d.key.KV, NS: d.key.NS, DB: d.key.DB, TB: d.key.TB, IX: ix.Name.VA, FD: enfd, ID: d.key.ID} if _, err = d.i.e.dbo.PutC(ctx, 0, aidx.Encode(), d.id.Bytes(), nil); err != nil { - return &IndexError{tb: d.key.TB, name: ix.Name, cols: ix.Cols, vals: v} + return &IndexError{tb: d.key.TB, name: ix.Name, cols: ix.Cols, vals: f} } } }