summaryrefslogtreecommitdiff
path: root/runtimeindex.go
blob: 394c6a8cbc3c8b845fc683c378231fc22f40e18d (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
// SPDX-FileCopyrightText: 2026 Stefan Majewsky <majewsky@gmx.net>
// SPDX-License-Identifier: Apache-2.0

package oblast

// RuntimeIndex provides methods for sorting records (R) by some type of key (K) at runtime.
// It is most commonly used with the result of [Store.Select] or [Store.SelectWhere], to build a lookup table for or partition of the retrieved records.
type RuntimeIndex[R any, K comparable] func(R) K

// NewRuntimeIndex casts a function into type [RuntimeIndex].
//
// In practice, this is more compact than writing the cast directly
// because type arguments can be inferred for function calls, but not type casts.
func NewRuntimeIndex[R any, K comparable](f func(R) K) RuntimeIndex[R, K] {
	return RuntimeIndex[R, K](f)
}

// Index builds a lookup table of the provided records.
//
// This should only be used when the index yields unique values for each record.
// If there can be duplicates, use [RuntimeIndex.Partition] instead.
func (i RuntimeIndex[R, K]) Index(records []R) map[K]R {
	result := make(map[K]R, len(records))
	for _, r := range records {
		result[i(r)] = r
	}
	return result
}

// IndexFrom is like Index, but can directly wrap a [Store.Select] or [Store.SelectWhere] call.
// If there is an error, it is passed through unchanged.
func (i RuntimeIndex[R, K]) IndexFrom(s Selection[R]) (map[K]R, error) {
	result := make(map[K]R)
	err := s.Foreach(func(record R) error {
		result[i(record)] = record
		return nil
	})
	return result, err
}

// Partition builds a partition of the resulting records by their index value.
// Within each partition, the original order of records is retained.
func (i RuntimeIndex[R, K]) Partition(records []R) map[K][]R {
	result := make(map[K][]R, len(records))
	for _, r := range records {
		key := i(r)
		result[key] = append(result[key], r)
	}
	return result
}

// PartitionFrom is like Partition, but can directly wrap a [Store.Select] or [Store.SelectWhere] call.
// If there is an error, it is passed through unchanged.
func (i RuntimeIndex[R, K]) PartitionFrom(s Selection[R]) (map[K][]R, error) {
	result := make(map[K][]R)
	err := s.Foreach(func(record R) error {
		key := i(record)
		result[key] = append(result[key], record)
		return nil
	})
	return result, err
}