-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathraccoon.go
105 lines (91 loc) · 3.11 KB
/
raccoon.go
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
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
// package raccoon is a lightweight and minimal graph store library
package raccoon
import (
"fmt"
)
// RaccoonStore is a general purpose Graph store.
// It's built on top of a kv-store backend and provides common operations
// required while working with graphs.
//
// RaccoonStore has a lightweight secondary indexing framework,
// which can be used to optimize recurring access patterns.
//
// The main RaccoonStore type is a lightweight orchestrator on top
// of the primary index store and additional secondary index stores.
//
// TODO Make these atomic
type RaccoonStore[Edg Edge[N], N any] struct {
indexes map[string]SecondaryIndexStore[Edg, N]
recordStore EdgeStore[Edg, N]
}
// Build a Raccoon instance from a schema definition
func NewRaccoonStore[Edg Edge[N], N any](schema RaccoonSchema[Edg, N]) RaccoonStore[Edg, N] {
idxs := make(map[string]SecondaryIndexStore[Edg, N])
for _, idx := range schema.Indexes {
store := NewSecondaryIdxStore(schema.Store, schema.KeysPrefix, idx.Name, schema.Keyer, idx.Mapper, schema.Marshaler)
idxs[idx.Name] = store
}
primaryStore := NewEdgeStore(schema.Store, schema.KeysPrefix, schema.Keyer, schema.Marshaler)
return RaccoonStore[Edg, N]{
indexes: idxs,
recordStore: primaryStore,
}
}
// Set an Edge
func (s *RaccoonStore[Edg, N]) Set(edg Edg) error {
for _, idx := range s.indexes {
err := idx.Set(edg)
if err != nil {
return err
}
}
return s.recordStore.Set(edg)
}
// Fetch and Edge from the source and destiniation nodes
func (s *RaccoonStore[Edg, N]) Get(source, dest N) (Option[Edg], error) {
return s.recordStore.GetEdg(source, dest)
}
// Fetch all Edges from index idxName indexed by value
func (s *RaccoonStore[Edg, N]) GetByIdx(idxName string, value []byte) ([]Edg, error) {
idx, ok := s.indexes[idxName]
if !ok {
return nil, fmt.Errorf("unknown index: %s", idxName)
}
return idx.GetByIdx(value)
}
// Filter and return all Edges from index idxName, indexed by value
// that match the given predicate
func (s *RaccoonStore[Edg, N]) FilterByIdx(idxName string, value []byte, predicate Predicate[Edg]) ([]Edg, error) {
idx, ok := s.indexes[idxName]
if !ok {
return nil, fmt.Errorf("unknown index: %s", idxName)
}
return idx.FilterByIdx(value, predicate)
}
// Return the direct ancestors of a Node,
// that is, returns all edges that have node as dest.
// Note: Does not recursively fetch Ancestors
func (s *RaccoonStore[Edg, N]) GetAncestors(node N) ([]Edg, error) {
return s.recordStore.GetAncestors(node)
}
// Return all direct sucessors of a Node,
// that is, returns all edges that have node as source.
// Note: Does not recursively fetch Ancestors
func (s *RaccoonStore[Edg, N]) GetSucessors(node N) ([]Edg, error) {
return s.recordStore.GetSucessors(node)
}
// Delete edg from the persistent storage
func (s *RaccoonStore[Edg, N]) Delete(edg Edg) error {
for _, idx := range s.indexes {
err := idx.Delete(edg)
if err != nil {
return err
}
}
return s.recordStore.Delete(edg)
}
// List returns all Edges in RaccoonStore
func (s *RaccoonStore[Edg, N]) List() ([]Edg, error) {
return s.recordStore.List()
}
// TODO Define other methods such as filtering