Mind (Multi INDex list) lets you query in-memory collections by multiple fields using indexes, just like a database — but without one. It is particularly well suited where data is read more often than written.
⚠️ Mind is in an early stage of development and the API may change.
go get github.com/lima1909/mind| Index | Backed by | Datatype | Supported operations |
|---|---|---|---|
MapIndex | HashMap | comparable | =, !=, In |
SortedIndex | SkipList | ordered | =, != , >, >=, <, <=, Between, In |
RangeIndex | uint8 slice | uint8 | =, != , >, >=, <, <=, Between, In |
RangeEncodedIndex | Range Encoded slice | uint8 | >, >=, <, <=, Between |
FenwickIndex | Fenwick | uint, int | >, >=, <, <=, Between |
TrigramIndex | TrigramIndex | string | Like |
PhoneticIndex | American Soundex | string | Sounds |
FuzzyIndex | Fuzzy search (BK-tree for Levenshtein-distance) | string | Fuzzy, Fuzzy([string], [distance]) |
StringIndex | SkipList Or HashMap (can combined with Trigram, Phonetic, Fuzzy) | string | SortedIndex or MapIndex and combined Index |
All operations can be combined with AND, OR and NOT.
Like means:
- '%' or '%%' => all
- 'ab%' => startsWith (prefix): 'ab'
- '%ab' => endsWith (suffix): 'ab'
- '%ab%' => contains: 'ab'
- 'abc' => equals
- '%ab%cd%' => contains: 'ab' and 'cd', in this order
- Zero dependencies
- Generic — works with any struct type
- Fast reads via bitmap-accelerated index intersection
- SQL-like query language (with optimizer)
- Higher memory usage: indexes store additional data alongside user data
- Slower writes: every mutation updates all registered indexes
package main
import (
"fmt""github.com/lima1909/mind""github.com/lima1909/mind/index""github.com/lima1909/mind/query"
)
typeCarstruct {
namestringageuint8tags []string
}
func (c*Car) Name() string { returnc.name }
func (c*Car) Age() uint8 { returnc.age }
func (c*Car) Tags() []string { returnc.tags }
funcmain() {
l:=mind.NewList[Car]()
err:=l.CreateIndex("name", index.NewMapIndex((*Car).Name))
iferr!=nil {
panic(err)
}
err=l.CreateIndex("age", index.NewSortedIndex((*Car).Age))
iferr!=nil {
panic(err)
}
err=l.CreateIndex("tag", index.NewSortedIndexSlice((*Car).Tags))
iferr!=nil {
panic(err)
}
l.Insert(Car{name: "Dacia", age: 2, tags: []string{"blue", "new"}})
l.Insert(Car{name: "Opel", age: 12, tags: []string{"old", "red"}})
l.Insert(Car{name: "Mercedes", age: 5})
l.Insert(Car{name: "Dacia", age: 22, tags: []string{"blue", "old"}})
t:=&query.Tracer{}
values, _:=l.QueryStr(
`(name = "Opel" or name = "Dacia") and age >= 2 and tag = "old"`,
query.WithTracer(t),
).Values()
fmt.Println(values)
// Output:// [{Opel 12 [old red]} {Dacia 22 [blue old]}fmt.Println()
fmt.Println("Trace:")
fmt.Println(t.PrettyString())
// Output:// Trace:// └── name = Opel OR name = Dacia AND age >= 2 AND tag = old [5.695µs] (2 matches)// ├── name = Opel OR name = Dacia AND age >= 2 [4.754µs] (3 matches)// │ ├── name = Opel OR name = Dacia [2.483µs] (3 matches)// │ │ ├── name = Opel [1.289µs] (1 matches)// │ │ └── name = Dacia [131ns] (2 matches)// │ └── age >= 2 [1.924µs] (4 matches)// └── tag = old [733ns] (2 matches)
}package main
import (
"fmt""github.com/lima1909/mind""github.com/lima1909/mind/index""github.com/lima1909/mind/query"
)
typeCarstruct {
iduintnamestringageuint8
}
func (c*Car) ID() uint { returnc.id }
func (c*Car) Name() string { returnc.name }
func (c*Car) Age() uint8 { returnc.age }
funcmain() {
l:=mind.NewIDList((*Car).ID)
// ignore error_=l.CreateIndex("name", index.NewMapIndex((*Car).Name))
_=l.CreateIndex("age", index.NewSortedIndex((*Car).Age))
l.Insert(Car{id: 1, name: "Dacia", age: 2})
l.Insert(Car{id: 2, name: "Opel", age: 12})
l.Insert(Car{id: 3, name: "Mercedes", age: 5})
l.Insert(Car{id: 4, name: "Dacia", age: 22})
// ignore errormercedes, _:=l.Get(3)
fmt.Println(mercedes)
// Output:// {3 Mercedes 5removed, _, _:=l.Remove(4)
fmt.Println("Removed:", removed)
// Output:// truet:=&query.Tracer{}
values, _:=l.Query(
query.Or(query.Eq("name", "Opel"), query.Lt("age", 10)),
query.WithTracer(t),
).Values()
fmt.Println(values)
// Output:// [{1 Dacia 2} {2 Opel 12} {3 Mercedes 5}]fmt.Println()
fmt.Println("Trace:")
fmt.Println(t.PrettyString())
// Output:// Trace:// └── name = Opel OR age < 10 [1.85µs] (3 matches)// ├── name = Opel [620ns] (1 matches)// └── age < 10 [790ns] (2 matches)
}