Beispiel #1
0
// Create user node and "IS_IN" edge to room if non-existent.
func joined(msg *irc.Message, DB *neoism.Database) {
	room := msg.Params[0]
	user := cleanName(msg.Prefix.Name)

	if users[user] == nil {
		users[user] = []string{room}
	}

	contains := false
	for _, r := range users[user] {
		if r == room {
			contains = true
			break
		}
	}

	if contains != true {
		users[user] = append(users[user], room)

		statement := fmt.Sprintf(
			`MERGE (n:Room {name: "%v"})
			 MERGE (u:User {name: "%v"})
			 MERGE (n)<-[:IS_IN]-(u)`,
			room, user)

		// Create new room node if non-existent
		query := neoism.CypherQuery{
			Statement: statement,
		}
		err := DB.Cypher(&query)
		if err != nil {
			fmt.Println(err)
		}
	}
}
Beispiel #2
0
// Check if reference to a person associated with that room.
// If it is, create a "REFERENCED" edge between speaker and
// the reference.  If that edge already exists, increment
// the "times" property by 1.
func messaged(msg *irc.Message, DB *neoism.Database) {
	message := msg.Trailing
	for name, _ := range users {
		if strings.Contains(message, name) {
			speaker := cleanName(msg.Prefix.Name)
			reference := name

			fmt.Printf("%v was referenced by %v\n", speaker, reference)

			statement := fmt.Sprintf(
				`MERGE (s:User {name: "%v"})
				 MERGE (u:User {name: "%v"})
				 MERGE (s)-[r:REFERENCED]->(u)
				 ON MATCH SET r.times = coalesce(r.times, 0) + 1`, speaker, reference)

			query := neoism.CypherQuery{
				Statement: statement,
			}
			err := DB.Cypher(&query)
			if err != nil {
				fmt.Println(err)
			}
		}
	}
}
Beispiel #3
0
func InsertUID(conn *neoism.Database, key *puck_gpg.PrimaryKey, uid *puck_gpg.UserID) {
	kid := key.KeyID()
	app.Logger.Debugf("Inserting UID %s of %s", uid.Keywords, kid)

	parsed := parseUID(uid.Keywords)

	cq0 := neoism.CypherQuery{
		Statement: `
			MATCH 
				(k:Key {keyid: {keyid}})
			MERGE k-[r:HasID]-(i:UserID {
						keyword: {keyword}, 
						uuid: {uuid},
						name: {name},
						comment: {comment},
						email: {email},
						domain: {domain}
						})`,
		Parameters: neoism.Props{
			"keyid":   key.KeyID(),
			"keyword": uid.Keywords,
			"uuid":    uid.UUID,
			"name":    parsed.name,
			"comment": parsed.comment,
			"email":   parsed.email,
			"domain":  parsed.domain,
		},
	}

	err := conn.Cypher(&cq0)
	if err != nil {
		panic(err)
	}
}
Beispiel #4
0
func getFrequencyRelations(db *neoism.Database, r *model.Relationship, t *testing.T) int {
	res := []struct {
		Frequency int `json:"frequency"`
	}{}

	cq := neoism.CypherQuery{
		Statement: fmt.Sprintf(
			`
            	MATCH (subject:%[1]s)-[r:%[2]s]->(object:%[3]s)
            	WHERE subject.id = {subjectId} AND object.id = {objectId}
            	RETURN r.frequency as frequency
            `,
			util.UpperCaseFirst(r.Subject), strings.ToUpper(r.Relationship),
			util.UpperCaseFirst(r.Object),
		),
		Parameters: neoism.Props{"subjectId": r.SubjectID, "objectId": r.ObjectID},
		Result:     &res,
	}
	if err := db.Cypher(&cq); err != nil {
		assert.Fail(t, "Unexpected error: "+err.Error())
		return -1
	}

	if len(res) > 0 {
		return res[0].Frequency
	}
	return -1
}
Beispiel #5
0
// GetOrCreateNode returns a Node, creates one if it does not exist. This method
// overrides the neoism one as there is a bug
func GetOrCreateNode(db *neoism.Database, label, key string, p neoism.Props) (n *neoism.Node, created bool, err error) {
	node, created, err := db.GetOrCreateNode(util.UpperCaseFirst(label), key, p)
	// due to a bug in neoism, label is not added
	// see: https://github.com/jmcvetta/neoism/issues/62
	if created {
		node.AddLabel(util.UpperCaseFirst(label))
	}
	return node, created, err
}
func cleanupConstraints(t *testing.T, db *neoism.Database) {
	err := db.CypherBatch([]*neoism.CypherQuery{
		&neoism.CypherQuery{
			Statement: `DROP CONSTRAINT ON (x:NeoUtilsTest) ASSERT x.name IS UNIQUE`,
		},
	})
	if err != nil {
		t.Fatal(err)
	}
}
Beispiel #7
0
func doQueries(conn *neoism.Database, queries []string) {
	for _, s := range queries {
		q := neoism.CypherQuery{
			Statement: s,
		}
		err := conn.Cypher(&q)
		if err != nil {
			panic(err)
		}
	}
}
Beispiel #8
0
/*
GetTags returns collection of news
*/
func GetTags(db *neoism.Database) (*[]Tag, error) {
	var tags []Tag
	if err := db.Cypher(&neoism.CypherQuery{
		Statement: `MATCH (tag:Tag)
                RETURN DISTINCT ID(tag) as id, tag.name as name`,
		Result: &tags,
	}); err != nil {
		return nil, err
	}
	return &tags, nil
}
/*
GetNewsProviders returns collection of news
*/
func GetNewsProviders(db *neoism.Database) (*[]NewsProvider, error) {
	var newsproviders []NewsProvider
	if err := db.Cypher(&neoism.CypherQuery{
		Statement: `MATCH (newsprovider:NewsProvider)
                RETURN DISTINCT ID(newsprovider) as id, newsprovider.name as name`,
		Result: &newsproviders,
	}); err != nil {
		return nil, err
	}
	return &newsproviders, nil
}
func cleanup(t *testing.T, db *neoism.Database) {

	err := db.CypherBatch([]*neoism.CypherQuery{
		&neoism.CypherQuery{
			Statement: `MATCH (x:NeoUtilsTest) DETACH DELETE x`,
		},
	})
	if err != nil {
		t.Fatal(err)
	}
}
/*
GetLocations returns collection of news
*/
func GetLocations(db *neoism.Database) (*[]Location, error) {
	var locations []Location
	if err := db.Cypher(&neoism.CypherQuery{
		Statement: `MATCH (location:Location)
                RETURN DISTINCT ID(location) as id, location.name as name`,
		Result: &locations,
	}); err != nil {
		return nil, err
	}
	return &locations, nil
}
Beispiel #12
0
func addIndexes(conn *neoism.Database) {

	_, err := conn.CreateIndex("Key", "domain")
	if err != nil {
		app.Logger.Info("Failed to create index, probably already exists")
	}

	_, err = conn.CreateIndex("Key", "email")
	if err != nil {
		app.Logger.Info("Failed to create index, probably already exists")
	}
}
Beispiel #13
0
func addConstraints(conn *neoism.Database) {

	_, err := conn.CreateUniqueConstraint("Key", "keyid")
	if err != nil {
		app.Logger.Info("Failed to create constraint, probably already exists")
	}

	_, err = conn.CreateUniqueConstraint("UserID", "uuid")
	if err != nil {
		app.Logger.Info("Failed to create constraint, probably already exists")
	}
}
/*
GetCompanies returns collection of news
*/
func GetCompanies(db *neoism.Database) (*[]Company, error) {

	var companies []Company
	if err := db.Cypher(&neoism.CypherQuery{
		Statement: `MATCH (company:Company)
                RETURN DISTINCT ID(company) as id, company.name as name`,
		Result: &companies,
	}); err != nil {
		return nil, err
	}
	return &companies, nil
}
/*
GetPeople returns collection of news
*/
func GetPeople(db *neoism.Database) (*[]Person, error) {

	var people []Person
	if err := db.Cypher(&neoism.CypherQuery{
		Statement: `MATCH (person:Person)
                RETURN DISTINCT ID(person) as id, person.name as name`,
		Result: &people,
	}); err != nil {
		return nil, err
	}
	return &people, nil
}
Beispiel #16
0
func cleanup(db *neoism.Database) {
	qs := []*neoism.CypherQuery{
		&neoism.CypherQuery{
			Statement: `START r=rel(*) DELETE r`,
		},
		&neoism.CypherQuery{
			Statement: `START n=node(*) DELETE n`,
		},
	}
	err := db.CypherBatch(qs)
	if err != nil {
		log.Fatal(err)
	}
}
Beispiel #17
0
func create(db *neoism.Database) {
	kirk, err := db.CreateNode(neoism.Props{"name": "Kirk", "shirt": "yellow"})
	if err != nil {
		log.Fatal(err)
	}
	fmt.Println(kirk.Properties()) // map[shirt:yellow name:Kirk] <nil>
	// Ignoring subsequent errors for brevity
	spock, _ := db.CreateNode(neoism.Props{"name": "Spock", "shirt": "blue"})
	mccoy, _ := db.CreateNode(neoism.Props{"name": "McCoy", "shirt": "blue"})
	r, _ := kirk.Relate("outranks", spock.Id(), nil) // No properties on this relationship
	start, _ := r.Start()
	fmt.Println(start.Properties()) // map[name:Kirk shirt:yellow] <nil>
	kirk.Relate("outranks", mccoy.Id(), nil)
	spock.Relate("outranks", mccoy.Id(), nil)
}
Beispiel #18
0
func (s *state) getEntity(db *neoism.Database, xid string) *neoism.Node {
	p := neoism.Props{"_xid_": xid}
	e, created, err := db.GetOrCreateNode("Entity", "_xid_", p)
	if err != nil {
		glog.Fatal(err)
	}
	if created {
		e.AddLabel("Entity")
		glog.WithFields(logrus.Fields{
			"id":    e.Id(),
			"_xid_": xid,
		}).Debug("Added new entity")
	}
	return e
}
Beispiel #19
0
// DeleteRelationship deletes a relationship
func DeleteRelationship(db *neoism.Database, r *model.Relationship) error {
	cq := neoism.CypherQuery{
		Statement: fmt.Sprintf(
			`
                MATCH (a:%s)-[r:%s]->(b:%s)
                WHERE a.id = {subjectId} AND b.id = {objectId}
                DELETE r
            `,
			util.UpperCaseFirst(r.Subject), strings.ToUpper(r.Relationship),
			util.UpperCaseFirst(r.Object),
		),
		Parameters: neoism.Props{
			"subjectId": r.SubjectID, "objectId": r.ObjectID,
		},
	}
	return db.Cypher(&cq)
}
Beispiel #20
0
func InsertPubKey(conn *neoism.Database, k *puck_gpg.PrimaryKey) {

	cq0 := neoism.CypherQuery{
		Statement: `
			MERGE (n:Key {keyid: {keyid}})
			ON CREATE SET
			n.fingerprint = {fingerprint}
			ON MATCH SET
			n.fingerprint = {fingerprint};`,
		Parameters: neoism.Props{
			"keyid":       k.KeyID(),
			"fingerprint": k.Fingerprint()}}

	err := conn.Cypher(&cq0)
	if err != nil {
		panic(err)
	}
}
Beispiel #21
0
/*
GetNewsItem returns the new with that id
*/
func GetNewsItem(db *neoism.Database, id int) (*NewsItem, error) {
	var news []NewsItem
	if err := db.Cypher(&neoism.CypherQuery{
		Statement: `MATCH (new:NewsItem)<-[r]-(k:NewsProvider)
								WHERE ID(new) = {id}
								RETURN DISTINCT ID(new) as id, new.title as title, new.url as url,new.image as image, new.body as body, new.language as language, k.name as source`,
		Parameters: neoism.Props{"id": id},
		Result:     &news,
	}); err != nil {
		return nil, err

	} else if len(news) == 0 {
		return nil, errors.New("not found")

	} else {
		return &news[0], nil
	}
}
Beispiel #22
0
// CreateOrIncRelationship creates a relationship or increments a property if it
// already exists
func CreateOrIncRelationship(db *neoism.Database, r *model.Relationship) error {
	cq := neoism.CypherQuery{
		Statement: fmt.Sprintf(
			`
			MATCH (a:%s), (b:%s)
			WHERE a.id = {subjectId} AND b.id = {objectId}
			CREATE UNIQUE (a)-[r:%s]->(b)
			SET r.frequency = COALESCE(r.frequency, 0) + 1
			`,
			util.UpperCaseFirst(r.Subject), util.UpperCaseFirst(r.Object),
			strings.ToUpper(r.Relationship),
		),
		Parameters: neoism.Props{
			"subjectId": r.SubjectID, "objectId": r.ObjectID,
		},
	}
	return db.Cypher(&cq)
}
Beispiel #23
0
func cypher(db *neoism.Database) {
	cq := neoism.CypherQuery{
		Statement: `
			START n=node(*)
			MATCH (n)-[r:outranks]->(m)
			WHERE n.shirt = {color}
			RETURN n.name, type(r), m.name
			`,
		Parameters: neoism.Props{"color": "blue"},
		Result: &[]struct {
			N   string `json:"n.name"`
			Rel string `json:"type(r)"`
			M   string `json:"m.name"`
		}{},
	}
	// db.Session.Log = true
	db.Cypher(&cq)
	fmt.Println(cq.Result)
	// &[{Spock outranks McCoy} {Spock outranks Scottie} {McCoy outranks Scottie}]
}
Beispiel #24
0
func getOrCreateNode(db *neoism.Database, label string, key string, value string, props neoism.Props) *neoism.Node {
	res := []struct {
		// `json:` tags matches column names in query
		N neoism.Node
	}{}

	//MATCH (n:Tag { name: 'deporte' }) RETURN n
	st := "MATCH (n:" + label + " { " + key + ": '" + value + "' }) RETURN n"
	println(st)

	cq0 := neoism.CypherQuery{
		// Use backticks for long statements - Cypher is whitespace indifferent
		Statement:  st,
		Parameters: neoism.Props{},
		Result:     &res,
	}

	db.Cypher(&cq0)

	// println("largo")
	// println(len(res))
	// tagName, err := n1.Property("name")
	// println(tagName)
	// println(err)

	var node *neoism.Node

	if len(res) > 0 { // existe el tag
		println("si")
		node = &res[0].N
		node.Db = db
	} else {
		println("no")
		node, _ = db.CreateNode(props)
		node.AddLabel(label)
	}

	return node
}
Beispiel #25
0
func transaction(db *neoism.Database) {
	qs := []*neoism.CypherQuery{
		&neoism.CypherQuery{
			Statement: `CREATE (n {name: "Scottie", shirt: "red"}) RETURN n`,
		},
		&neoism.CypherQuery{
			Statement: `START n=node(*), m=node(*)
				WHERE m.name = {name} AND n.shirt IN {colors}
				CREATE (n)-[r:outranks]->(m)
				RETURN n.name, type(r), m.name`,
			Parameters: neoism.Props{"name": "Scottie", "colors": []string{"yellow", "blue"}},
			Result: &[]struct {
				N   string `json:"n.name"` // `json` tag matches column name in query
				Rel string `json:"type(r)"`
				M   string `json:"m.name"`
			}{},
		},
	}
	tx, _ := db.Begin(qs)
	fmt.Println(qs[1].Result) // &[{Kirk outranks Scottie} {Spock outranks Scottie} {McCoy o...
	tx.Commit()
}
Beispiel #26
0
// Adds nodes for users who were already in the room before
// spectator was started.  If they were added from another
// room, they are not added.  An edge is drawn to show that
// they are in the room.
func inchan(msg *irc.Message, DB *neoism.Database) {
	nicks := strings.Split(msg.Trailing, " ")
	room := msg.Params[2]

	queryStart := fmt.Sprintf(`MERGE (n:Room {name: "%v"}) `, room)
	rawQuery := []string{queryStart}

	for i, u := range nicks {
		cu := cleanName(u)
		if users[u] == nil {
			pattern := fmt.Sprintf(`MERGE (u%v:User {name: "%v"}) MERGE (u%v)-[:IS_IN]->(n)`, i, cu, i)
			rawQuery = append(rawQuery, pattern)
		}
	}

	query := neoism.CypherQuery{
		Statement: strings.Join(rawQuery, " "),
	}
	err := DB.Cypher(&query)
	if err != nil {
		fmt.Println(err)
	}
}
Beispiel #27
0
/*
 Insert a signature in to the database.
*/
func InsertSignature(conn *neoism.Database, pubkey *puck_gpg.PrimaryKey, uid *puck_gpg.UserID, sig *puck_gpg.Signature) {

	signerKID := sig.IssuerKeyID()
	signeeKID := pubkey.KeyID()

	app.Logger.Debugf("Got Signature by %s on %s", signerKID, signeeKID)

	// Stub out the signer key, in case it's not yet in the DB
	q_signer := neoism.CypherQuery{
		Statement:  `MERGE (n:Key {keyid: {kid}});`,
		Parameters: neoism.Props{"kid": signerKID},
	}
	err := conn.Cypher(&q_signer)
	if err != nil {
		log.Fatal(err)
	}

	//Add the signature record
	q_signature := neoism.CypherQuery{
		Statement: `
			MATCH 
				(m:Key {keyid: {signee}})-[ii:HasID]-(i:UserID {uuid: {uuid}}), 
				(n:Key {keyid: {signer}})
			MERGE n-[r:SIGNS]->i`,
		Parameters: neoism.Props{
			"uuid":   uid.UUID,
			"signee": signeeKID,
			"signer": signerKID,
		},
	}
	err = conn.Cypher(&q_signature)
	if err != nil {
		log.Fatal(err)
	}

	app.SigCounter.Mark(1)
}
Beispiel #28
0
func ensureIndexes(db *neoism.Database) {

	indexes, err := db.Indexes("Organisation")
	if err != nil {
		panic(err)
	}
	if len(indexes) == 0 {
		if _, err := db.CreateIndex("Organisation", "uuid"); err != nil {
			panic(err)
		}
		if _, err := db.CreateIndex("Industry", "uuid"); err != nil {
			panic(err)
		}
	}
}
Beispiel #29
0
func CreateEquality(db *neoism.Database, w http.ResponseWriter, r *http.Request) {
	source, err := helpers.ParseURL(r.FormValue("source"))
	if err != nil {
		http.Error(w, "source is invalid URL: "+r.FormValue("source"), 400)
		return
	}
	target, err := helpers.ParseURL(r.FormValue("target"))
	if err != nil {
		http.Error(w, "target is invalid URL: "+r.FormValue("target"), 400)
		return
	}
	sourceTitle, err := helpers.GetTitle(source)
	if err != nil {
		http.Error(w, "Couldn't fetch title for "+source.String(), 400)
		return
	}
	targetTitle, err := helpers.GetTitle(target)
	if err != nil {
		http.Error(w, "Couldn't fetch title for "+target.String(), 400)
		return
	}
	if helpers.EqualURLs(source, target) {
		http.Error(w, "urls are equal.", 400)
		return
	}

	// standardize urls
	stdsource := helpers.GetStandardizedURL(source)
	stdtarget := helpers.GetStandardizedURL(target)

	// get user
	user := "******"
	// user.GetKarma()

	now := time.Now().UTC().Format("20060102150405")

	var queries []*neoism.CypherQuery
	res := []struct {
		SN            int
		TN            int
		SU            int
		TU            int
		RELATIONSHIPS []int
	}{}
	cq := neoism.CypherQuery{
		Statement: `
MERGE (su:URL {stdurl: {stdsource}})
ON CREATE SET su.title = {sourceTitle}
SET su.rawurl = {rawsource}

MERGE (tu:URL {stdurl: {stdtarget}})
ON CREATE SET tu.title = {targetTitle}
SET su.rawurl = {rawtarget}

WITH su, tu
OPTIONAL MATCH (su)<-[:INSTANCE]-(sn:Node)
OPTIONAL MATCH (tu)<-[:INSTANCE]-(tn:Node)
OPTIONAL MATCH (sn)-[r:RELATIONSHIP]-()

WITH sn, tn, su, tu, collect(r) AS rels
RETURN id(sn) AS sn,
       id(tn) AS tn,
       id(su) AS su,
       id(tu) AS tu,
       extract(rel IN rels | id(rel)) AS relationships
        `,
		Parameters: neoism.Props{
			"stdsource":   stdsource,
			"stdtarget":   stdtarget,
			"rawsource":   source.String(),
			"rawtarget":   target.String(),
			"sourceTitle": sourceTitle,
			"targetTitle": targetTitle,
		},
		Result: &res,
	}
	queries = append(queries, &cq)

	txn, err := db.Begin(queries)
	if err != nil {
		pretty.Log(err)
		http.Error(w, err.Error(), 500)
		txn.Rollback()
		return
	}

	row := res[0]

	// do our checks to decide if we are going to create Nodes, mix them or what
	queries = make([]*neoism.CypherQuery, 0)
	if row.SN == row.TN && row.SN != 0 {
		// they exist and are the same, so we do nothing
	} else if row.SN != 0 && row.TN != 0 {
		// both exists, transfer everything from the source to target and delete source
		for _, r := range row.RELATIONSHIPS {
			log.Print(row.SN, row.TN, r)
			queries = append(queries, &neoism.CypherQuery{
				Statement: `
MATCH (sn) WHERE id(sn) = {sn}
MATCH (tn) WHERE id(tn) = {tn}
MATCH (a)-[r]->(b) WHERE id(r) = {r}

FOREACH (x IN CASE WHEN a = sn THEN [1] ELSE [] END |
  MERGE (tn)-[newrel:RELATIONSHIP {user: r.user}]->(b)
  ON CREATE SET newrel.created = r.created
  SET newrel.kind = r.kind
)

FOREACH (x IN CASE WHEN b = sn THEN [1] ELSE [] END |
  MERGE (a)<-[newrel:RELATIONSHIP {user: r.user}]-(tn)
  ON CREATE SET newrel.created = r.created
  SET newrel.kind = r.kind
)
                `,
				Parameters: neoism.Props{
					"sn": row.SN,
					"tn": row.TN,
					"r":  r,
				},
			})
		}
		queries = append(queries, &neoism.CypherQuery{
			Statement: `
MATCH (sn) WHERE id(sn) = {sn}
MATCH (tn) WHERE id(tn) = {tn}
MATCH (su) WHERE id(su) = {su}

MATCH (sn)-[oldinstance:INSTANCE]->(su)
MERGE (tn)-[newinstance:INSTANCE]->(su)
ON CREATE SET newinstance = oldinstance
ON CREATE SET newinstance.user = {user}

WITH oldinstance, sn
MATCH (sn)-[srels:RELATIONSHIP]-()
DELETE oldinstance, sn, srels
            `,
			Parameters: neoism.Props{
				"sn":   row.SN,
				"tn":   row.TN,
				"su":   row.SU,
				"user": user,
			},
		})
	} else if row.SN == 0 && row.TN == 0 {
		// none exist, create one for both
		queries = append(queries, &neoism.CypherQuery{
			Statement: `
MATCH (su) WHERE id(su) = {su}
MATCH (tu) WHERE id(tu) = {tu}

CREATE (n:Node {created: {now}, name: tu.title})
MERGE (n)-[r1:INSTANCE {user: {user}}]->(su) ON CREATE SET r1.created = {now}
MERGE (n)-[r2:INSTANCE {user: {user}}]->(tu) ON CREATE SET r2.created = {now}
            `,
			Parameters: neoism.Props{
				"su":   row.SU,
				"tu":   row.TU,
				"user": user,
				"now":  now,
			},
		})
		pretty.Log(queries)
	} else {
		var floating int
		var appendTo int
		if row.SN != 0 {
			// only SN exist, append TU to SN
			floating = row.TU
			appendTo = row.SN

		} else if row.TN != 0 {
			// only TN exist, append SU to TN
			floating = row.SU
			appendTo = row.TN
		}
		queries = append(queries, &neoism.CypherQuery{
			Statement: `
MATCH (floating) WHERE id(floating) = {floating}
MATCH (appendTo) WHERE id(appendTo) = {appendTo}

MERGE (appendTo)-[r:INSTANCE {user: {user}}]->(floating) ON CREATE SET r.created = {now}
            `,
			Parameters: neoism.Props{
				"floating": floating,
				"appendTo": appendTo,
				"user":     user,
				"now":      now,
			},
		})
	}

	err = txn.Query(queries)
	if err != nil {
		pretty.Log(err)
		pretty.Log(queries)
		http.Error(w, err.Error(), 500)
		txn.Rollback()
		return
	}

	err = txn.Commit()
	if err != nil {
		pretty.Log(err)
		http.Error(w, err.Error(), 500)
		txn.Rollback()
		return
	}

	w.WriteHeader(http.StatusOK)
}
Beispiel #30
0
func ViewRelationships(db *neoism.Database, w http.ResponseWriter, r *http.Request) {
	log.Print(r.URL.Query().Get("url"))

	// get nodes from database concerning the url requested
	rawurl, err := url.QueryUnescape(r.URL.Query().Get("url"))
	if err != nil {
		http.Error(w, "URL should be escaped.", 400)
		return
	}

	u, err := helpers.ParseURL(rawurl)
	if err != nil {
		http.Error(w, "URL is invalid.", 400)
		return
	}
	stdurl := helpers.GetStandardizedURL(u)

	res := []struct {
		ANAME   string
		BNAME   string
		AID     int
		BID     int
		RELKIND string
		RELID   int
		URLS    []string
	}{}
	cq := neoism.CypherQuery{
		Statement: `
MATCH (u:URL)<-[:INSTANCE]-(a) WHERE u.stdurl = {url} OR u.url = {url}
MATCH path=(a)-[r:RELATIONSHIP*1..10]-(b)
WITH nodes(path) AS nodes
UNWIND nodes AS n
WITH DISTINCT n AS n
MATCH (u)<-[:INSTANCE]-(n)
RETURN
  n.name AS aname,
  id(n) AS aid,
  extract(url IN collect(DISTINCT u) | url.stdurl) AS urls,
  '' AS bname,
  0 AS bid,
  '' AS relkind,
  0 AS relid

UNION ALL

MATCH (u:URL)<-[:INSTANCE]-(a) WHERE u.stdurl = {url} OR u.url = {url}
MATCH path=(a)-[r:RELATIONSHIP*1..10]-(b)
WITH relationships(path) AS rels
UNWIND rels AS r
WITH DISTINCT r AS r
WITH startnode(r) AS a, endnode(r) AS b, r
RETURN
  a.name AS aname,
  id(a) AS aid,
  b.name AS bname,
  id(b) AS bid,
  r.kind AS relkind,
  id(r) AS relid,
  [] AS urls
        `,
		Parameters: neoism.Props{"url": stdurl},
		Result:     &res,
	}
	err = db.Cypher(&cq)
	if err != nil {
		log.Print(err)
		http.Error(w, "An error ocurred", 400)
		return
	}

	// make dot string
	s := helpers.GenerateDotString(res, r.URL.Query())
	log.Print(s)

	// generate svg graph
	buffer := helpers.RenderGraph(s)

	// write the response as image
	w.Header().Set("Content-Type", "image/svg+xml")
	if _, err := w.Write(buffer.Bytes()); err != nil {
		log.Print("unable to write image. ", err)
	}
}