Repository: mlange-42/arche
Pull request #83 (2023-02-15 10:48:37)

GetAll gets the entity, more examples


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 22bb428..1483b42 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -7,6 +7,7 @@
 * Generic queries support optional, additional and excluded components (#53, #56, #58, #59, #60, #63)
 * Logic filters for complex queries (#54, #58, #61)
 * `Query` and `World` have a method `Mask(Entity)` to access archetype masks (#65)
+* Generic query `GetAll` methods return the entity as first element (#83)
 * Added method `World.Stats()` for inspecting otherwise inaccessible world statistics (#67)
 * Entities can be initialized with components, via ID as well as using generics (#76)
 * A listener function can be registered to the world, for notification on entity changes (#77)
diff --git a/README.md b/README.md
index 1cb29e2..9c08231 100644
--- a/README.md
+++ b/README.md
@@ -86,7 +86,7 @@ func main() {
 		// Iterate it
 		for query.Next() {
 			// Component access through the Query.
-			pos, vel := query.GetAll()
+			_, pos, vel := query.GetAll()
 			// Update component fields.
 			pos.X += vel.X
 			pos.Y += vel.Y
diff --git a/ecs/event.go b/ecs/event.go
new file mode 100644
index 0000000..24da3ad
--- /dev/null
+++ b/ecs/event.go
@@ -0,0 +1,25 @@
+package ecs
+
+// ChangeEvent contains information about component changes.
+//
+// To receive change events, register a function func(e ChangeEvent) with [World.RegisterListener].
+type ChangeEvent struct {
+	// The entity that was changed.
+	Entity Entity
+	// The old and new component masks.
+	OldMask, NewMask BitMask
+	// Components added, removed, and after the change.
+	Added, Removed, Current []ID
+	// Whether the entity itself was added (> 0), removed (< 0), or only changed (= 0).
+	AddedRemoved int
+}
+
+// EntityAdded reports whether the entity was newly added.
+func (e *ChangeEvent) EntityAdded() bool {
+	return e.AddedRemoved > 0
+}
+
+// EntityRemoved reports whether the entity was removed.
+func (e *ChangeEvent) EntityRemoved() bool {
+	return e.AddedRemoved < 0
+}
diff --git a/ecs/world.go b/ecs/world.go
index 7584046..4de5ac4 100644
--- a/ecs/world.go
+++ b/ecs/world.go
@@ -1,27 +1,12 @@
 package ecs
 
 import (
-	"fmt"
 	"reflect"
 	"unsafe"
 
 	"github.com/mlange-42/arche/ecs/stats"
 )
 
-// ChangeEvent contains information about component changes.
-//
-// To receive change events, register a function func(e ChangeEvent) with [World.RegisterListener].
-type ChangeEvent struct {
-	// The entity that was changed.
-	Entity Entity
-	// The old and new component masks.
-	OldMask, NewMask BitMask
-	// Components added, removed, and after the change.
-	Added, Removed, Current []ID
-	// Whether the entity itself was added (> 0), removed (< 0), or only changed (= 0).
-	AddedRemoved int
-}
-
 // ComponentID returns the ID for a component type via generics. Registers the type if it is not already registered.
 func ComponentID[T any](w *World) ID {
 	tp := reflect.TypeOf((*T)(nil)).Elem()
@@ -372,13 +357,12 @@ func (w *World) IsLocked() bool {
 //
 // Events notified are entity creation, removal and changes to the component composition.
 //
-// Returns an error if there is already a listener registered.
-func (w *World) RegisterListener(listener func(e ChangeEvent)) error {
+// Panics if there is already a listener registered.
+func (w *World) RegisterListener(listener func(e ChangeEvent)) {
 	if w.listener != nil {
-		return fmt.Errorf("the world already has a change listener registered")
+		panic("the world already has a change listener registered")
 	}
 	w.listener = listener
-	return nil
 }
 
 // Stats reports statistics for inspecting the World.
diff --git a/examples/change_listener/main.go b/examples/change_listener/main.go
new file mode 100644
index 0000000..a873ddb
--- /dev/null
+++ b/examples/change_listener/main.go
@@ -0,0 +1,60 @@
+// Demonstrates the use of a ChangeEvent listener.
+package main
+
+import (
+	"fmt"
+
+	"github.com/mlange-42/arche/ecs"
+	"github.com/mlange-42/arche/generic"
+)
+
+// Position component
+type Position struct {
+	X float64
+	Y float64
+}
+
+// Velocity component
+type Velocity struct {
+	X float64
+	Y float64
+}
+
+// Rotation component
+type Rotation struct {
+	A float64
+}
+
+// Listen is called on entity changes.
+func Listen(evt ecs.ChangeEvent) {
+	// Just prints out what the event is about.
+	// This could also be a method of a type that manages events.
+	// Could use e.g. filters to distribute events to interested/registered systems.
+	if evt.EntityAdded() {
+		fmt.Printf("Entity added, has components %v\n", evt.Current)
+	} else if evt.EntityRemoved() {
+		fmt.Printf("Entity removed, had components %v\n", evt.Current)
+	} else {
+		fmt.Printf("Entity changed, has components %v\n", evt.Current)
+	}
+}
+
+func main() {
+	// Create a World.
+	world := ecs.NewWorld()
+
+	// Register a listener function.
+	world.RegisterListener(Listen)
+
+	// Create/manipulate/delete entities and observe the listener's output
+	e0, _ := generic.NewEntity1[Position](&world)
+	e1, _, _ := generic.NewEntity2[Position, Velocity](&world)
+
+	generic.Add1[Velocity](&world, e0)
+	generic.Add1[Rotation](&world, e1)
+
+	generic.Remove2[Position, Velocity](&world, e1)
+
+	world.RemEntity(e0)
+	world.RemEntity(e1)
+}
diff --git a/examples/generic/main.go b/examples/generic/main.go
index 72d62e3..b23ea13 100644
--- a/examples/generic/main.go
+++ b/examples/generic/main.go
@@ -60,7 +60,7 @@ func main() {
 		// Iterate it.
 		for query.Next() {
 			// Component access through the Query.
-			pos, vel := query.GetAll()
+			_, pos, vel := query.GetAll()
 			// Update component fields.
 			pos.X += vel.X
 			pos.Y += vel.Y
@@ -78,7 +78,7 @@ func main() {
 	q := filter.Query(&world)
 
 	for q.Next() {
-		pos, vel := q.GetAll()
+		_, pos, vel := q.GetAll()
 		pos.X += vel.X
 		pos.Y += vel.Y
 	}
diff --git a/examples/locked_world/main.go b/examples/locked_world/main.go
new file mode 100644
index 0000000..2ed54fe
--- /dev/null
+++ b/examples/locked_world/main.go
@@ -0,0 +1,113 @@
+// Demonstrates how to create, remove or alter entities,
+// despite the locked World during query iteration.
+package main
+
+import (
+	"fmt"
+	"math/rand"
+
+	"github.com/mlange-42/arche/ecs"
+	"github.com/mlange-42/arche/generic"
+)
+
+// Position component
+type Position struct {
+	X float64
+	Y float64
+}
+
+// Energy component
+type Energy struct {
+	Value float64
+}
+
+// Reproduction is a helper for delaying reproduction events
+type Reproduction struct {
+	X         float64
+	Y         float64
+	Offspring int
+}
+
+func main() {
+
+	// Create a World.
+	world := ecs.NewWorld()
+
+	// Create entities.
+	for i := 0; i < 1000; i++ {
+		// Create a new Entity.
+		_, pos, en := generic.NewEntity2[Position, Energy](&world)
+		pos.X = rand.Float64() * 100
+		pos.Y = rand.Float64() * 100
+		en.Value = rand.Float64()
+	}
+
+	// Filter for generating queries.
+	filter := generic.NewFilter2[Position, Energy]()
+
+	// Slices to collect events to perform after the world is unlocked.
+	toDie := []ecs.Entity{}
+	toReproduce := []Reproduction{}
+
+	// Time loop.
+	for t := 0; t < 100; t++ {
+		// Get a fresh query iterator.
+		query := filter.Query(&world)
+		// We want to count our entities
+		alive := 0
+		born := 0
+		died := 0
+		// Iterate it.
+		// During iteration, the world is locked.
+		// Thus, it is not possible to add or remove entities or components.
+		for query.Next() {
+			// Component access through the Query.
+			entity, pos, ene := query.GetAll()
+			// Do model logic.
+			ene.Value += rand.NormFloat64() * 0.05
+
+			// Entities with zero energy die
+			if ene.Value <= 0.0 {
+				// Put the entity into a slice for later processing
+				toDie = append(toDie, entity)
+				died++
+				continue
+			}
+
+			alive++
+
+			// Entities with energy > 0 reproduce
+			if ene.Value >= 1.0 {
+				ene.Value = 0.5
+				offspring := 1 + rand.Intn(3)
+				born += offspring
+				// Put the reproduction information into a slice for later processing
+				toReproduce = append(toReproduce, Reproduction{pos.X, pos.Y, offspring})
+			}
+		}
+		// Here, the world lock is released automatically
+
+		// Remove entities that are to die
+		for _, entity := range toDie {
+			world.RemEntity(entity)
+		}
+
+		// Create entities through reproduction
+		for _, repro := range toReproduce {
+			// Create offspring entities.
+			for i := 0; i < repro.Offspring; i++ {
+				// Create a new Entity and initialize it.
+				_, pos, en := generic.NewEntity2[Position, Energy](&world)
+				pos.X = repro.X + rand.NormFloat64()
+				pos.Y = repro.Y + rand.NormFloat64()
+				en.Value = rand.Float64() * 0.5
+			}
+		}
+
+		// Clear the slices
+		toDie = toDie[:0]
+		toReproduce = toReproduce[:0]
+
+		fmt.Printf("Alive: %4d, Born: %2d, Died: %2d\n", alive, born, died)
+	}
+}
diff --git a/examples/readme/main.go b/examples/readme/main.go
index f6785fd..eca9174 100644
--- a/examples/readme/main.go
+++ b/examples/readme/main.go
@@ -48,7 +48,7 @@ func main() {
 		// Iterate it
 		for query.Next() {
 			// Component access through the Query.
-			pos, vel := query.GetAll()
+			_, pos, vel := query.GetAll()
 			// Update component fields.
 			pos.X += vel.X
 			pos.Y += vel.Y
diff --git a/generic/generate/main.go b/generic/generate/main.go
index 0a93c09..96c0338 100644
--- a/generic/generate/main.go
+++ b/generic/generate/main.go
@@ -62,7 +62,7 @@ func main() {
 		returnAll := ""
 		if i > 0 {
 			types = "[" + strings.Join(typeLetters[:i], ", ") + "]"
-			returnTypes = "(*" + strings.Join(typeLetters[:i], ", *") + ")"
+			returnTypes = "*" + strings.Join(typeLetters[:i], ", *")
 			fullTypes = "[" + strings.Join(typeLetters[:i], " any, ") + " any]"
 			include = "include: []reflect.Type{typeOf[" + strings.Join(typeLetters[:i], "](), typeOf[") + "]()},"
 			for j := 0; j < i; j++ {
diff --git a/generic/generate/query_getall.gotxt b/generic/generate/query_getall.gotxt
index 792b729..d6aaecd 100644
--- a/generic/generate/query_getall.gotxt
+++ b/generic/generate/query_getall.gotxt
@@ -1,5 +1,5 @@
 
-// GetAll returns all queried components for the current query position
-func (q *Query{{ .Index }}{{ .Types }}) GetAll() {{ .TypesReturn }} {
-	return {{ .ReturnAll }}
+// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query{{ .Index }}{{ .Types }}) GetAll() (ecs.Entity, {{ .TypesReturn }}) {
+	return q.Entity(), {{ .ReturnAll }}
 }
diff --git a/generic/query_generated.go b/generic/query_generated.go
index 2a6f367..8f647ac 100644
--- a/generic/query_generated.go
+++ b/generic/query_generated.go
@@ -154,9 +154,9 @@ type Query1[A any] struct {
 	ids []ecs.ID
 }
 
-// GetAll returns all queried components for the current query position
-func (q *Query1[A]) GetAll() *A {
-	return (*A)(q.Query.Get(q.ids[0]))
+// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query1[A]) GetAll() (ecs.Entity, *A) {
+	return q.Entity(), (*A)(q.Query.Get(q.ids[0]))
 }
 
 // Get1 returns the first queried component for the current query position
@@ -238,9 +238,9 @@ type Query2[A any, B any] struct {
 	ids []ecs.ID
 }
 
-// GetAll returns all queried components for the current query position
-func (q *Query2[A, B]) GetAll() (*A, *B) {
-	return (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1]))
+// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query2[A, B]) GetAll() (ecs.Entity, *A, *B) {
+	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1]))
 }
 
 // Get1 returns the first queried component for the current query position
@@ -327,9 +327,9 @@ type Query3[A any, B any, C any] struct {
 	ids []ecs.ID
 }
 
-// GetAll returns all queried components for the current query position
-func (q *Query3[A, B, C]) GetAll() (*A, *B, *C) {
-	return (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2]))
+// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query3[A, B, C]) GetAll() (ecs.Entity, *A, *B, *C) {
+	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2]))
 }
 
 // Get1 returns the first queried component for the current query position
@@ -421,9 +421,9 @@ type Query4[A any, B any, C any, D any] struct {
 	ids []ecs.ID
 }
 
-// GetAll returns all queried components for the current query position
-func (q *Query4[A, B, C, D]) GetAll() (*A, *B, *C, *D) {
-	return (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3]))
+// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query4[A, B, C, D]) GetAll() (ecs.Entity, *A, *B, *C, *D) {
+	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3]))
 }
 
 // Get1 returns the first queried component for the current query position
@@ -520,9 +520,9 @@ type Query5[A any, B any, C any, D any, E any] struct {
 	ids []ecs.ID
 }
 
-// GetAll returns all queried components for the current query position
-func (q *Query5[A, B, C, D, E]) GetAll() (*A, *B, *C, *D, *E) {
-	return (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4]))
+// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query5[A, B, C, D, E]) GetAll() (ecs.Entity, *A, *B, *C, *D, *E) {
+	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4]))
 }
 
 // Get1 returns the first queried component for the current query position
@@ -624,9 +624,9 @@ type Query6[A any, B any, C any, D any, E any, F any] struct {
 	ids []ecs.ID
 }
 
-// GetAll returns all queried components for the current query position
-func (q *Query6[A, B, C, D, E, F]) GetAll() (*A, *B, *C, *D, *E, *F) {
-	return (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5]))
+// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query6[A, B, C, D, E, F]) GetAll() (ecs.Entity, *A, *B, *C, *D, *E, *F) {
+	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5]))
 }
 
 // Get1 returns the first queried component for the current query position
@@ -733,9 +733,9 @@ type Query7[A any, B any, C any, D any, E any, F any, G any] struct {
 	ids []ecs.ID
 }
 
-// GetAll returns all queried components for the current query position
-func (q *Query7[A, B, C, D, E, F, G]) GetAll() (*A, *B, *C, *D, *E, *F, *G) {
-	return (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5])), (*G)(q.Query.Get(q.ids[6]))
+// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query7[A, B, C, D, E, F, G]) GetAll() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G) {
+	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5])), (*G)(q.Query.Get(q.ids[6]))
 }
 
 // Get1 returns the first queried component for the current query position
@@ -847,9 +847,9 @@ type Query8[A any, B any, C any, D any, E any, F any, G any, H any] struct {
 	ids []ecs.ID
 }
 
-// GetAll returns all queried components for the current query position
-func (q *Query8[A, B, C, D, E, F, G, H]) GetAll() (*A, *B, *C, *D, *E, *F, *G, *H) {
-	return (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5])), (*G)(q.Query.Get(q.ids[6])), (*H)(q.Query.Get(q.ids[7]))
+// GetAll returns the [ecs.Entity] and all queried components for the current query iterator position.
+func (q *Query8[A, B, C, D, E, F, G, H]) GetAll() (ecs.Entity, *A, *B, *C, *D, *E, *F, *G, *H) {
+	return q.Entity(), (*A)(q.Query.Get(q.ids[0])), (*B)(q.Query.Get(q.ids[1])), (*C)(q.Query.Get(q.ids[2])), (*D)(q.Query.Get(q.ids[3])), (*E)(q.Query.Get(q.ids[4])), (*F)(q.Query.Get(q.ids[5])), (*G)(q.Query.Get(q.ids[6])), (*H)(q.Query.Get(q.ids[7]))
 }
 
 // Get1 returns the first queried component for the current query position


Test patch:
diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml
index 675ecaa..65f53a3 100644
--- a/.github/workflows/tests.yml
+++ b/.github/workflows/tests.yml
@@ -75,6 +75,8 @@ jobs:
       - name: Run examples
         run: |
           go run ./examples/base
+          go run ./examples/change_listener
           go run ./examples/filter
           go run ./examples/generic
+          go run ./examples/locked_world
           go run ./examples/readme
diff --git a/ecs/event_test.go b/ecs/event_test.go
new file mode 100644
index 0000000..eb81559
--- /dev/null
+++ b/ecs/event_test.go
@@ -0,0 +1,24 @@
+package ecs
+
+import (
+	"testing"
+
+	"github.com/stretchr/testify/assert"
+)
+
+func TestChangeEvent(t *testing.T) {
+	e := ChangeEvent{AddedRemoved: 0}
+
+	assert.False(t, e.EntityAdded())
+	assert.False(t, e.EntityRemoved())
+
+	e = ChangeEvent{AddedRemoved: 1}
+
+	assert.True(t, e.EntityAdded())
+	assert.False(t, e.EntityRemoved())
+
+	e = ChangeEvent{AddedRemoved: -1}
+
+	assert.False(t, e.EntityAdded())
+	assert.True(t, e.EntityRemoved())
+}
diff --git a/ecs/world_test.go b/ecs/world_test.go
index 1964f35..6ee2a81 100644
--- a/ecs/world_test.go
+++ b/ecs/world_test.go
@@ -428,11 +428,8 @@ func TestWorldListener(t *testing.T) {
 
 	w := NewWorld()
 
-	err := w.RegisterListener(listen)
-	assert.Nil(t, err)
-
-	err = w.RegisterListener(listen)
-	assert.NotNil(t, err)
+	w.RegisterListener(listen)
+	assert.Panics(t, func() { w.RegisterListener(listen) })
 
 	posID := ComponentID[position](&w)
 	velID := ComponentID[velocity](&w)
diff --git a/generic/query_test.go b/generic/query_test.go
index d018a12..ea8482e 100644
--- a/generic/query_test.go
+++ b/generic/query_test.go
@@ -134,7 +134,7 @@ func TestQuery1(t *testing.T) {
 	query := filter.Query(&w)
 	for query.Next() {
 		c0 := query.Get1()
-		c02 := query.GetAll()
+		_, c02 := query.GetAll()
 		assert.Equal(t, c0, c02)
 		assert.Equal(t, cnt+1, int(c0.val))
 		cnt++
@@ -180,7 +180,7 @@ func TestQuery2(t *testing.T) {
 			assert.Equal(t, cnt+1, int(c1.val))
 			assert.Equal(t, cnt+2, int(c2.val))
 
-			c12, c22 := q.GetAll()
+			_, c12, c22 := q.GetAll()
 			assert.Equal(t, c1, c12)
 			assert.Equal(t, c2, c22)
 			cnt++
@@ -231,7 +231,7 @@ func TestQuery3(t *testing.T) {
 		assert.Equal(t, cnt+2, int(c2.val))
 		assert.Equal(t, cnt+3, int(c3.val))
 
-		c12, c22, c32 := query.GetAll()
+		_, c12, c22, c32 := query.GetAll()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)
@@ -288,7 +288,7 @@ func TestQuery4(t *testing.T) {
 		assert.Equal(t, cnt+3, int(c3.val))
 		assert.Equal(t, cnt+4, int(c4.val))
 
-		c12, c22, c32, c42 := query.GetAll()
+		_, c12, c22, c32, c42 := query.GetAll()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)
@@ -352,7 +352,7 @@ func TestQuery5(t *testing.T) {
 		assert.Equal(t, cnt+4, int(c4.val))
 		assert.Equal(t, cnt+5, int(c5.val))
 
-		c12, c22, c32, c42, c52 := query.GetAll()
+		_, c12, c22, c32, c42, c52 := query.GetAll()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)
@@ -423,7 +423,7 @@ func TestQuery6(t *testing.T) {
 		assert.Equal(t, cnt+5, int(c5.val))
 		assert.Equal(t, cnt+6, int(c6.val))
 
-		c12, c22, c32, c42, c52, c62 := query.GetAll()
+		_, c12, c22, c32, c42, c52, c62 := query.GetAll()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)
@@ -504,7 +504,7 @@ func TestQuery7(t *testing.T) {
 		assert.Equal(t, cnt+6, int(c6.val))
 		assert.Equal(t, cnt+7, int(c7.val))
 
-		c12, c22, c32, c42, c52, c62, c72 := query.GetAll()
+		_, c12, c22, c32, c42, c52, c62, c72 := query.GetAll()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)
@@ -584,7 +584,7 @@ func TestQuery8(t *testing.T) {
 		assert.Equal(t, cnt+7, int(c7.val))
 		assert.Equal(t, cnt+8, int(c8.val))
 
-		c12, c22, c32, c42, c52, c62, c72, c82 := query.GetAll()
+		_, c12, c22, c32, c42, c52, c62, c72, c82 := query.GetAll()
 		assert.Equal(t, c1, c12)
 		assert.Equal(t, c2, c22)
 		assert.Equal(t, c3, c32)