func main() { // File for your new BoltDB. Use path to regular file and not temporary in the real world tmpfile, err := ioutil.TempFile("", "example") if err != nil { log.Fatal(err) } defer os.Remove(tmpfile.Name()) // clean up // Initialize the database graph.InitQuadStore("bolt", tmpfile.Name(), nil) // Open and use the database store, err := cayley.NewGraph("bolt", tmpfile.Name(), nil) if err != nil { log.Fatalln(err) } store.AddQuad(quad.Make("phrase of the day", "is of course", "Hello BoltDB!", "demo graph")) // Now we create the path, to get to our data p := cayley.StartPath(store, quad.String("phrase of the day")).Out(quad.String("is of course")) // This is more advanced example of the query. // Simpler equivalent can be found in hello_world example. // Now we get an iterator for the path and optimize it. // The second return is if it was optimized, but we don't care for now. it, _ := p.BuildIterator().Optimize() // Optimize iterator on quad store level. // After this step iterators will be replaced with backend-specific ones. it, _ = store.OptimizeIterator(it) // remember to cleanup after yourself defer it.Close() // While we have items for it.Next() { token := it.Result() // get a ref to a node (backend-specific) value := store.NameOf(token) // get the value in the node (RDF) nativeValue := quad.NativeOf(value) // convert value to normal Go type fmt.Println(nativeValue) // print it! } if err := it.Err(); err != nil { log.Fatalln(err) } }
func main() { // Create a brand new graph store, err := cayley.NewMemoryGraph() if err != nil { log.Fatalln(err) } store.AddQuad(quad.Make("phrase of the day", "is of course", "Hello World!", nil)) // Now we create the path, to get to our data p := cayley.StartPath(store, quad.String("phrase of the day")).Out(quad.String("is of course")) // Now we iterate over results. Arguments: // 1. Optional context used for cancellation. // 2. Quad store, but we can omit it because we have already built path with it. err = p.Iterate(nil).EachValue(nil, func(value quad.Value) { nativeValue := quad.NativeOf(value) // this converts RDF values to normal Go types fmt.Println(nativeValue) }) if err != nil { log.Fatalln(err) } }
// TestUpsertItem tests the insert and update of an item. func TestUpsertItem(t *testing.T) { store := setup(t) defer teardown(t, store) t.Log("Given the need to insert and then update an item.") { //---------------------------------------------------------------------- // Get the fixture. items, err := itemfix.Get() if err != nil { t.Fatalf("\t%s\tShould be able to retrieve the fixture : %v", tests.Failed, err) } t.Logf("\t%s\tShould be able to retrieve the fixture.", tests.Success) itemStrData, err := json.Marshal(&items[0]) if err != nil { t.Fatalf("\t%s\tShould be able to marshal the fixture : %v", tests.Failed, err) } t.Logf("\t%s\tShould be able to marshal the fixture.", tests.Success) //---------------------------------------------------------------------- // Insert the Item. url := "/v1/item" r := httptest.NewRequest("PUT", url, bytes.NewBuffer(itemStrData)) w := httptest.NewRecorder() a.ServeHTTP(w, r) t.Logf("\tWhen calling url to insert : %s", url) { if w.Code != http.StatusOK { t.Fatalf("\t%s\tShould be able to insert the item : %v", tests.Failed, w.Code) } t.Logf("\t%s\tShould be able to insert the item.", tests.Success) } //---------------------------------------------------------------------- // Check the inferred relationship. p := cayley.StartPath(store, quad.String("ITEST_80aa936a-f618-4234-a7be-df59a14cf8de")).Out(quad.String("authored")) it, _ := p.BuildIterator().Optimize() defer it.Close() for it.Next() { token := it.Result() value := store.NameOf(token) if quad.NativeOf(value) != "ITEST_d1dfa366-d2f7-4a4a-a64f-af89d4c97d82" { t.Fatalf("\t%s\tShould be able to get the inferred relationships from the graph", tests.Failed) } } if err := it.Err(); err != nil { t.Fatalf("\t%s\tShould be able to get the inferred relationships from the graph : %s", tests.Failed, err) } it.Close() t.Logf("\t%s\tShould be able to get the inferred relationships from the graph.", tests.Success) //---------------------------------------------------------------------- // Retrieve the item. url = "/v1/item/" + items[0].ID r = httptest.NewRequest("GET", url, nil) w = httptest.NewRecorder() a.ServeHTTP(w, r) t.Logf("\tWhen calling url to get : %s", url) { if w.Code != http.StatusOK { t.Fatalf("\t%s\tShould be able to retrieve the item : %v", tests.Failed, w.Code) } t.Logf("\t%s\tShould be able to retrieve the item.", tests.Success) var itemsBack []item.Item if err := json.Unmarshal(w.Body.Bytes(), &itemsBack); err != nil { t.Fatalf("\t%s\tShould be able to unmarshal the results : %v", tests.Failed, err) } t.Logf("\t%s\tShould be able to unmarshal the results.", tests.Success) if itemsBack[0].ID != items[0].ID || itemsBack[0].Type != items[0].Type { t.Logf("\t%+v", items[0]) t.Logf("\t%+v", itemsBack[0]) t.Fatalf("\t%s\tShould be able to get back the same item.", tests.Failed) } t.Logf("\t%s\tShould be able to get back the same item.", tests.Success) } //---------------------------------------------------------------------- // Update the Item. items[0].Version = 2 itemStrData, err = json.Marshal(items[0]) if err != nil { t.Fatalf("\t%s\tShould be able to marshal the changed fixture : %v", tests.Failed, err) } t.Logf("\t%s\tShould be able to marshal the changed fixture.", tests.Success) url = "/v1/item" r = httptest.NewRequest("PUT", url, bytes.NewBuffer(itemStrData)) w = httptest.NewRecorder() a.ServeHTTP(w, r) t.Logf("\tWhen calling url to update : %s", url) { if w.Code != http.StatusOK { t.Fatalf("\t%s\tShould be able to update the item : %v", tests.Failed, w.Code) } t.Logf("\t%s\tShould be able to update the item.", tests.Success) } //---------------------------------------------------------------------- // Retrieve the Item. url = "/v1/item/" + items[0].ID r = httptest.NewRequest("GET", url, nil) w = httptest.NewRecorder() a.ServeHTTP(w, r) t.Logf("\tWhen calling url to get : %s", url) { if w.Code != http.StatusOK { t.Fatalf("\t%s\tShould be able to retrieve the item : %v", tests.Failed, w.Code) } t.Logf("\t%s\tShould be able to retrieve the item.", tests.Success) var itUpdated []item.Item if err := json.Unmarshal(w.Body.Bytes(), &itUpdated); err != nil { t.Fatalf("\t%s\tShould be able to unmarshal the results : %v", tests.Failed, err) } t.Logf("\t%s\tShould be able to unmarshal the results.", tests.Success) if itUpdated[0].Version != 2 { t.Log(w.Body.String()) t.Fatalf("\t%s\tShould get the expected result.", tests.Failed) } t.Logf("\t%s\tShould get the expected result.", tests.Success) } } }
// viewIDs retrieves the item IDs associated with the view. func viewIDs(v *view.View, path *path.Path, key string, graphDB *cayley.Handle) ([]string, embeddedRels, error) { // Build the Cayley iterator. it := path.BuildIterator() it, _ = it.Optimize() defer it.Close() // tagOrder will allow us to look up the ordering of a tag or // the tag corresponding to an order on demand. tagOrder := make(map[string]string) // Extract any tags and the ordering in the View value. var viewTags []string for idx, pth := range v.Paths { alias := strconv.Itoa(idx+1) + "_" for _, segment := range pth.Segments { if segment.Tag != "" { viewTags = append(viewTags, alias+segment.Tag) tagOrder[alias+segment.Tag] = alias + strconv.Itoa(segment.Level) tagOrder[alias+strconv.Itoa(segment.Level)] = alias + segment.Tag } } } // Retrieve the end path and tagged item IDs. var ids []string var embeds embeddedRels for it.Next() { // Tag the results. resultTags := make(map[string]graph.Value) it.TagResults(resultTags) // Extract the tagged item IDs. taggedIDs := make(map[string]relList) for _, tag := range viewTags { if t, ok := resultTags[tag]; ok { // Append the view item ID. ids = append(ids, quad.NativeOf(graphDB.NameOf(t)).(string)) // Add the tagged ID to the tagged map for embedded // relationship extraction. current, ok := taggedIDs[tag] if !ok { taggedIDs[tag] = []string{quad.NativeOf(graphDB.NameOf(t)).(string)} continue } updated := append(current, quad.NativeOf(graphDB.NameOf(t)).(string)) taggedIDs[tag] = updated } } // Extract any IDs that need to be embedded in view items. embed, err := extractEmbeddedRels(v, taggedIDs, tagOrder, key) if err != nil { return ids, embeds, err } embeds = append(embeds, embed...) } if it.Err() != nil { return ids, embeds, it.Err() } // Remove duplicates. found := make(map[string]bool) j := 0 for i, x := range ids { if !found[x] { found[x] = true ids[j] = ids[i] j++ } } ids = ids[:j] // Add root item. if v.ReturnRoot == true { ids = append(ids, key) } return ids, embeds, nil }
// TestAddRemoveGraph tests if we can add/remove relationship quads to/from cayley. func TestAddRemoveGraph(t *testing.T) { db, store, items := setupGraph(t) defer tests.DisplayLog() t.Log("Given the need to add/remove relationship quads from the Cayley graph.") { t.Log("\tWhen starting from an empty graph") { //---------------------------------------------------------------------- // Infer and add the relationships to the graph. if err := wire.AddToGraph(tests.Context, db, store, items[0]); err != nil { t.Fatalf("\t%s\tShould be able to add relationships to the graph : %s", tests.Failed, err) } t.Logf("\t%s\tShould be able to add relationships to the graph.", tests.Success) //---------------------------------------------------------------------- // Get the relationship quads from the graph. p := cayley.StartPath(store, quad.String("WTEST_80aa936a-f618-4234-a7be-df59a14cf8de")).Out(quad.String("WTEST_flagged")) it, _ := p.BuildIterator().Optimize() defer it.Close() var count int for it.Next() { count++ token := it.Result() value := store.NameOf(token) if quad.NativeOf(value) != "WTEST_d1dfa366-d2f7-4a4a-a64f-af89d4c97d82" { t.Fatalf("\t%s\tShould be able to get the relationships from the graph", tests.Failed) } } if err := it.Err(); err != nil { t.Fatalf("\t%s\tShould be able to get the relationships from the graph : %s", tests.Failed, err) } it.Close() p = cayley.StartPath(store, quad.String("WTEST_d1dfa366-d2f7-4a4a-a64f-af89d4c97d82")).Out(quad.String("WTEST_on")) it, _ = p.BuildIterator().Optimize() defer it.Close() for it.Next() { count++ token := it.Result() value := store.NameOf(token) if quad.NativeOf(value) != "WTEST_c1b2bbfe-af9f-4903-8777-bd47c4d5b20a" { t.Fatalf("\t%s\tShould be able to get the relationships from the graph", tests.Failed) } } if err := it.Err(); err != nil { t.Fatalf("\t%s\tShould be able to get the relationships from the graph : %s", tests.Failed, err) } it.Close() if count != 2 { t.Fatalf("\t%s\tShould be able to get relationships from the graph", tests.Failed) } t.Logf("\t%s\tShould be able to get relationships from the graph.", tests.Success) //---------------------------------------------------------------------- // Try to infer and add the relationships again. if err := wire.AddToGraph(tests.Context, db, store, items[0]); err != nil { t.Fatalf("\t%s\tShould be able to add an item again and maintain relationships : %s", tests.Failed, err) } t.Logf("\t%s\tShould be able to add an item again and maintain relationships.", tests.Success) //---------------------------------------------------------------------- // Remove the relationships from the graph. if err := wire.RemoveFromGraph(tests.Context, db, store, items[0]); err != nil { t.Fatalf("\t%s\tShould be able to remove relationships from the graph : %s", tests.Failed, err) } t.Logf("\t%s\tShould be able to remove relationships from the graph.", tests.Success) //---------------------------------------------------------------------- // Try to get the relationships. count = 0 p = cayley.StartPath(store, quad.String("WTEST_80aa936a-f618-4234-a7be-df59a14cf8de")).Out(quad.String("WTEST_authored")) it, _ = p.BuildIterator().Optimize() defer it.Close() for it.Next() { count++ } if err := it.Err(); err != nil { t.Fatalf("\t%s\tShould be able to verify the empty graph : %s", tests.Failed, err) } it.Close() p = cayley.StartPath(store, quad.String("WTEST_d1dfa366-d2f7-4a4a-a64f-af89d4c97d82")).Out(quad.String("WTEST_on")) it, _ = p.BuildIterator().Optimize() defer it.Close() for it.Next() { count++ } if err := it.Err(); err != nil { t.Fatalf("\t%s\tShould be able to verify the empty graph : %s", tests.Failed, err) } it.Close() if count != 0 { t.Fatalf("\t%s\tShould be able to verify the empty graph", tests.Failed) } t.Logf("\t%s\tShould be able to verify the empty graph.", tests.Success) } } }
// TestImportRemoveItem tests the insert and update of an item. func TestImportRemoveItem(t *testing.T) { db, store := setup(t) defer teardown(t, db, store) t.Log("Given the need to import an item.") { //---------------------------------------------------------------------- // Get the fixture. items, err := itemfix.Get() if err != nil { t.Fatalf("\t%s\tShould be able to retrieve the fixture : %v", tests.Failed, err) } t.Logf("\t%s\tShould be able to retrieve the fixture.", tests.Success) //---------------------------------------------------------------------- // Import the Item. if err := sponge.Import(tests.Context, db, store, &items[0]); err != nil { t.Fatalf("\t%s\tShould be able to import an item : %s", tests.Failed, err) } t.Logf("\t%s\tShould be able to import an item", tests.Success) //---------------------------------------------------------------------- // Check the inferred relationship. p := cayley.StartPath(store, quad.String("ITEST_80aa936a-f618-4234-a7be-df59a14cf8de")).Out(quad.String("authored")) it, _ := p.BuildIterator().Optimize() defer it.Close() for it.Next() { token := it.Result() value := store.NameOf(token) if quad.NativeOf(value) != "ITEST_d1dfa366-d2f7-4a4a-a64f-af89d4c97d82" { t.Fatalf("\t%s\tShould be able to get the inferred relationships from the graph", tests.Failed) } } if err := it.Err(); err != nil { t.Fatalf("\t%s\tShould be able to get the inferred relationships from the graph : %s", tests.Failed, err) } it.Close() t.Logf("\t%s\tShould be able to get the inferred relationships from the graph.", tests.Success) //---------------------------------------------------------------------- // Import the Item again to test for duplicate imports. if err := sponge.Import(tests.Context, db, store, &items[0]); err != nil { t.Fatalf("\t%s\tShould be able to import a duplicate item : %s", tests.Failed, err) } t.Logf("\t%s\tShould be able to import a duplicate item", tests.Success) //---------------------------------------------------------------------- // Remove the item. if err := sponge.Remove(tests.Context, db, store, items[0].ID); err != nil { t.Fatalf("\t%s\tShould be able to remove the item : %s", tests.Failed, err) } t.Logf("\t%s\tShould be able to remove the item", tests.Success) //---------------------------------------------------------------------- // Check the inferred relationships. p = cayley.StartPath(store, quad.String("ITEST_80aa936a-f618-4234-a7be-df59a14cf8de")).Out(quad.String("authored")) it, _ = p.BuildIterator().Optimize() defer it.Close() var count int for it.Next() { count++ } if err := it.Err(); err != nil { t.Fatalf("\t%s\tShould be able to confirm removed relationships : %s", tests.Failed, err) } if count > 0 { t.Fatalf("\t%s\tShould be able to confirm removed relationships.", tests.Failed) } t.Logf("\t%s\tShould be able to confirm removed relationships.", tests.Success) } }