Beispiel #1
0
func main() {
	// To see how most of this works, see hello_world -- this just add in a transaction
	store, err := cayley.NewMemoryGraph()
	if err != nil {
		log.Fatalln(err)
	}

	// Create a transaction of work to do
	// NOTE: the transaction is independent of the storage type, so comes from cayley rather than store
	t := cayley.NewTransaction()
	t.AddQuad(quad.Make("food", "is", "good", nil))
	t.AddQuad(quad.Make("phrase of the day", "is of course", "Hello World!", nil))
	t.AddQuad(quad.Make("cats", "are", "awesome", nil))
	t.AddQuad(quad.Make("cats", "are", "scary", nil))
	t.AddQuad(quad.Make("cats", "want to", "kill you", nil))

	// Apply the transaction
	err = store.ApplyTransaction(t)
	if err != nil {
		log.Fatalln(err)
	}

	p := cayley.StartPath(store, quad.String("cats")).Out(quad.String("are"))

	err = p.Iterate(nil).EachValue(nil, func(v quad.Value) {
		fmt.Println("cats are", v.Native())
	})
	if err != nil {
		log.Fatalln(err)
	}
}
Beispiel #2
0
// StartQueryFromNods returns a new query starting at the node with the given IDs.
func (gl *GraphLayer) StartQueryFromNode(nodeId GraphNodeId) GraphQuery {
	singleStartingValue := nodeIdToValue(nodeId)
	return GraphQuery{
		path:     cayley.StartPath(gl.cayleyStore, singleStartingValue),
		layer:    gl,
		tagCount: 0,

		singleStartingValue: singleStartingValue,
		singlePredicate:     nil,
		singleDirection:     0,
	}
}
Beispiel #3
0
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)
	}
}
Beispiel #4
0
func storiesByKeys(g *cayley.Handle, keys []string) []*Story {
	stories := make([]*Story, 0, len(keys))
	it, _ := cayley.StartPath(g, keys...).Save(StoryID, StoryID).Save(StoryTitle, StoryTitle).Save(StoryDescription, StoryDescription).Save(SiteID, SiteID).BuildIterator().Optimize()
	defer it.Close()
	for cayley.RawNext(it) {
		s := Story{}
		results := map[string]graph.Value{}
		it.TagResults(results)
		s.Id = atoi(g.NameOf(results[StoryID]))
		s.Title = g.NameOf(results[StoryTitle])
		s.Desc = g.NameOf(results[StoryDescription])
		s.Site = Site(Site_value[g.NameOf(results[SiteID])])
		s.annotate()
		stories = append(stories, &s)
	}
	return stories
}
Beispiel #5
0
// StartQueryFromNodes returns a new query starting at the nodes with the given IDs.
func (gl *GraphLayer) StartQueryFromNodes(nodeIds ...GraphNodeId) GraphQuery {
	quadValues := graphIdsToQuadValues(nodeIds)

	var singleStartingValue quad.Value = nil
	if len(quadValues) == 1 {
		singleStartingValue = quadValues[0]
	}

	return GraphQuery{
		path:     cayley.StartPath(gl.cayleyStore, quadValues...),
		layer:    gl,
		tagCount: 0,

		singleStartingValue: singleStartingValue,
		singlePredicate:     nil,
		singleDirection:     0,
	}
}
Beispiel #6
0
// StartQuery returns a new query starting at the nodes with the given values (either graph node IDs
// or arbitrary values).
func (gl *GraphLayer) StartQuery(values ...interface{}) GraphQuery {
	quadValues := toQuadValues(values, gl)

	var singleStartingValue quad.Value = nil
	if len(values) == 1 {
		singleStartingValue = quadValues[0]
	}

	return GraphQuery{
		path:     cayley.StartPath(gl.cayleyStore, quadValues...),
		layer:    gl,
		tagCount: 0,

		singleStartingValue: singleStartingValue,
		singlePredicate:     nil,
		singleDirection:     0,
	}
}
Beispiel #7
0
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)
	}
}
Beispiel #8
0
// 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)
		}
	}
}
Beispiel #9
0
// TestDeleteItem tests the insert and deletion of a item.
func TestDeleteItem(t *testing.T) {
	store := setup(t)
	defer teardown(t, store)

	t.Log("Given the need to delete an item.")
	{
		//----------------------------------------------------------------------
		// Delete the Item.

		url := "/v1/item/ITEST_d1dfa366-d2f7-4a4a-a64f-af89d4c97d82"
		r := httptest.NewRequest("DELETE", url, nil)
		w := httptest.NewRecorder()

		a.ServeHTTP(w, r)

		t.Logf("\tWhen calling url to delete : %s", url)
		{
			if w.Code != http.StatusNoContent {
				t.Fatalf("\t%s\tShould be able to delete the item : %v", tests.Failed, w.Code)
			}
			t.Logf("\t%s\tShould be able to delete the item.", tests.Success)
		}

		//----------------------------------------------------------------------
		// Retrieve the Item.

		url = "/v1/view/ITEST_d1dfa366-d2f7-4a4a-a64f-af89d4c97d82"
		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 != 404 {
				t.Fatalf("\t%s\tShould not be able to retrieve the item : %v", tests.Failed, w.Code)
			}
			t.Logf("\t%s\tShould not be able to retrieve 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)

	}
}
Beispiel #10
0
func (s Story) checkExistsTitle(g *cayley.Handle) bool {
	it, _ := cayley.StartPath(g, s.key()).Out(StoryTitle).BuildIterator().Optimize()
	defer it.Close()
	return cayley.RawNext(it)
}
Beispiel #11
0
func (u User) checkExists(g *cayley.Handle) bool {
	it, _ := cayley.StartPath(g, u.key()).Out(UserID).BuildIterator().Optimize()
	defer it.Close()
	return cayley.RawNext(it)
}
Beispiel #12
0
// viewPathToGraphPath translates the path in a view into a "path"
// utilized in graph queries.
func viewPathToGraphPath(v *view.View, key string, graphDB *cayley.Handle) (*path.Path, error) {

	// outputPath is the final tranlated graph path.
	var outputPath *path.Path

	// Loop over the paths in the view translating the metadata.
	for idx, pth := range v.Paths {

		// We create an alias prefix for tags, so we can track which
		// path a tag is in.
		alias := strconv.Itoa(idx+1) + "_"

		// Sort the view Path value.
		sort.Sort(pth.Segments)

		// graphPath will contain the entire strict graph path.
		var graphPath *path.Path

		// subPaths will contain each sub path of the full graph path,
		// as a separate graph path.
		var subPaths []path.Path

		// Loop over the path segments translating the path.
		level := 1
		for _, segment := range pth.Segments {

			// Check that the level is the level we expect (i.e., that the levels
			// are in order)
			if level != segment.Level {
				err := fmt.Errorf("Invalid view path level, expected %d but seeing %d", level, segment.Level)
				return graphPath, err
			}

			// Initialize the path, if we are on level 1.
			if level == 1 {

				// Add the first level relationship.
				switch segment.Direction {
				case inString:
					graphPath = cayley.StartPath(graphDB, quad.String(key)).In(quad.String(segment.Predicate))
				case outString:
					graphPath = cayley.StartPath(graphDB, quad.String(key)).Out(quad.String(segment.Predicate))
				}

				// Add the tag, if present.
				if segment.Tag != "" {
					graphPath = graphPath.Clone().Tag(alias + segment.Tag)
				}

				// Track this as a subpath.
				subPaths = append(subPaths, *graphPath.Clone())

				level++
				continue
			}

			// Add the relationship.
			switch segment.Direction {
			case inString:
				graphPath = graphPath.Clone().In(quad.String(segment.Predicate))
			case outString:
				graphPath = graphPath.Clone().Out(quad.String(segment.Predicate))
			}

			// Add the tag, if present.
			if segment.Tag != "" {
				graphPath = graphPath.Clone().Tag(alias + segment.Tag)
			}

			// Add this as a subpath.
			subPaths = append(subPaths, *graphPath.Clone())

			level++
		}

		// If we are forcing a strict path, return only the resulting or
		// tagged items along the full path.
		if pth.StrictPath {
			if outputPath == nil {
				outputPath = graphPath
				continue
			}
			outputPath = outputPath.Clone().Or(graphPath)
			continue
		}

		// Otherwise add all the subpaths to the output path.
		for _, subPath := range subPaths {
			if outputPath == nil {
				addedPath := &subPath
				outputPath = addedPath.Clone()
				continue
			}
			outputPath = outputPath.Clone().Or(&subPath)
		}
	}

	return outputPath, 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)
		}
	}
}
Beispiel #14
0
// 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)
	}
}