mirror of https://github.com/perkeep/perkeep.git
index: implement EdgesTo
For finding back references in the graph.
This commit is contained in:
parent
0c3e700006
commit
f696007a14
|
@ -554,9 +554,44 @@ func (x *Index) GetFileInfo(fileRef *blobref.BlobRef) (*search.FileInfo, error)
|
|||
return fi, nil
|
||||
}
|
||||
|
||||
func (x *Index) EdgesTo(ref *blobref.BlobRef, opts *search.EdgesToOpts) ([]*search.Edge, error) {
|
||||
// unimplemented.
|
||||
return nil, errors.New("TODO: implement")
|
||||
func (x *Index) EdgesTo(ref *blobref.BlobRef, opts *search.EdgesToOpts) (edges []*search.Edge, err error) {
|
||||
it := x.queryPrefix(keyEdgeBackward, ref)
|
||||
defer closeIterator(it, &err)
|
||||
permanodeParents := map[string]*blobref.BlobRef{} // blobref key => blobref set
|
||||
for it.Next() {
|
||||
keyPart := strings.Split(it.Key(), "|")[1:]
|
||||
if len(keyPart) < 2 {
|
||||
continue
|
||||
}
|
||||
parent := keyPart[1]
|
||||
parentRef := blobref.Parse(parent)
|
||||
if parentRef == nil {
|
||||
continue
|
||||
}
|
||||
valPart := strings.Split(it.Value(), "|")
|
||||
if len(valPart) < 2 {
|
||||
continue
|
||||
}
|
||||
parentType, parentName := valPart[0], valPart[1]
|
||||
if parentType == "permanode" {
|
||||
permanodeParents[parent] = parentRef
|
||||
} else {
|
||||
edges = append(edges, &search.Edge{
|
||||
From: parentRef,
|
||||
FromType: parentType,
|
||||
FromTitle: parentName,
|
||||
To: ref,
|
||||
})
|
||||
}
|
||||
}
|
||||
for _, parentRef := range permanodeParents {
|
||||
edges = append(edges, &search.Edge{
|
||||
From: parentRef,
|
||||
FromType: "permanode",
|
||||
To: ref,
|
||||
})
|
||||
}
|
||||
return edges, nil
|
||||
}
|
||||
|
||||
func (x *Index) Storage() IndexStorage { return x.s }
|
||||
|
|
|
@ -55,6 +55,10 @@ func TestFiles_Memory(t *testing.T) {
|
|||
indextest.Files(t, index.NewMemoryIndex)
|
||||
}
|
||||
|
||||
func TestEdgesTo_Memory(t *testing.T) {
|
||||
indextest.EdgesTo(t, index.NewMemoryIndex)
|
||||
}
|
||||
|
||||
var (
|
||||
// those dirs are not packages implementing indexers,
|
||||
// hence we do not want to check them.
|
||||
|
@ -62,7 +66,7 @@ var (
|
|||
// A map is used in hasAllRequiredTests to note which required
|
||||
// tests have been found in a package, by setting the corresponding
|
||||
// booleans to true. Those are the keys for this map.
|
||||
requiredTests = []string{"TestIndex_", "TestPathsOfSignerTarget_", "TestFiles_"}
|
||||
requiredTests = []string{"TestIndex_", "TestPathsOfSignerTarget_", "TestFiles_", "TestEdgesTo_"}
|
||||
)
|
||||
|
||||
// This function checks that all the functions using the tests
|
||||
|
|
|
@ -488,3 +488,37 @@ func Files(t *testing.T, initIdx func() *index.Index) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func EdgesTo(t *testing.T, initIdx func() *index.Index) {
|
||||
idx := initIdx()
|
||||
id := NewIndexDeps(idx)
|
||||
id.Fataler = t
|
||||
|
||||
// pn1 ---member---> pn2
|
||||
pn1 := id.NewPermanode()
|
||||
pn2 := id.NewPermanode()
|
||||
id.AddAttribute(pn1, "camliMember", pn2.String())
|
||||
|
||||
t.Logf("edge %s --> %s", pn1, pn2)
|
||||
|
||||
id.dumpIndex(t)
|
||||
|
||||
// Look for pn1
|
||||
{
|
||||
edges, err := idx.EdgesTo(pn2, nil)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(edges) != 1 {
|
||||
t.Fatalf("num edges = %d; want 1", len(edges))
|
||||
}
|
||||
wantEdge := &search.Edge{
|
||||
From: pn1,
|
||||
To: pn2,
|
||||
FromType: "permanode",
|
||||
}
|
||||
if got, want := edges[0].String(), wantEdge.String(); got != want {
|
||||
t.Errorf("Wrong edge.\n GOT: %v\nWANT: %v", got, want)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -205,8 +205,8 @@ var (
|
|||
keyEdgeBackward = &keyType{
|
||||
"edgeback",
|
||||
[]part{
|
||||
{"child", typeBlobRef}, // the thing we want to find parent(s) of
|
||||
{"parent", typeBlobRef}, // the parent (e.g. permanode blobref)
|
||||
{"child", typeBlobRef}, // the edge target; thing we want to find parent(s) of
|
||||
{"parent", typeBlobRef}, // the parent / edge source (e.g. permanode blobref)
|
||||
// the blobref is the blob establishing the relationship
|
||||
// (for a permanode: the claim; for static: often same as parent)
|
||||
{"blobref", typeBlobRef},
|
||||
|
|
|
@ -93,3 +93,7 @@ func TestPathsOfSignerTarget_Mongo(t *testing.T) {
|
|||
func TestFiles_Mongo(t *testing.T) {
|
||||
mongoTester{}.test(t, indextest.Files)
|
||||
}
|
||||
|
||||
func TestEdgesTo_Mongo(t *testing.T) {
|
||||
mongoTester{}.test(t, indextest.EdgesTo)
|
||||
}
|
||||
|
|
|
@ -104,3 +104,7 @@ func TestPathsOfSignerTarget_MySQL(t *testing.T) {
|
|||
func TestFiles_MySQL(t *testing.T) {
|
||||
mysqlTester{}.test(t, indextest.Files)
|
||||
}
|
||||
|
||||
func TestEdgesTo_MySQL(t *testing.T) {
|
||||
mysqlTester{}.test(t, indextest.EdgesTo)
|
||||
}
|
||||
|
|
|
@ -142,3 +142,11 @@ func TestFiles_Postgres(t *testing.T) {
|
|||
}
|
||||
postgresTester{}.test(t, indextest.Files)
|
||||
}
|
||||
|
||||
func TestEdgesTo_Postgres(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Logf("skipping test in short mode")
|
||||
return
|
||||
}
|
||||
postgresTester{}.test(t, indextest.EdgesTo)
|
||||
}
|
||||
|
|
|
@ -95,3 +95,7 @@ func TestPathsOfSignerTarget_SQLite(t *testing.T) {
|
|||
func TestFiles_SQLite(t *testing.T) {
|
||||
sqliteTester{}.test(t, indextest.Files)
|
||||
}
|
||||
|
||||
func TestEdgesTo_SQLite(t *testing.T) {
|
||||
sqliteTester{}.test(t, indextest.EdgesTo)
|
||||
}
|
||||
|
|
|
@ -137,6 +137,10 @@ type Edge struct {
|
|||
To *blobref.BlobRef
|
||||
}
|
||||
|
||||
func (e *Edge) String() string {
|
||||
return fmt.Sprintf("[edge from:%s to:%s type:%s title:%s]", e.From, e.To, e.FromType, e.FromTitle)
|
||||
}
|
||||
|
||||
type Index interface {
|
||||
// dest must be closed, even when returning an error.
|
||||
// limit is <= 0 for default. smallest possible default is 0
|
||||
|
|
Loading…
Reference in New Issue