index: implement EdgesTo

For finding back references in the graph.
This commit is contained in:
Brad Fitzpatrick 2012-11-05 10:29:42 +01:00
parent 0c3e700006
commit f696007a14
9 changed files with 103 additions and 6 deletions

View File

@ -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 }

View File

@ -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

View File

@ -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)
}
}
}

View File

@ -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},

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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)
}

View File

@ -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