// 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) } } }
// 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) } } } }
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) } }
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 }
// 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) } }
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) } } }
/* 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 }
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") } }
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 }
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) } }
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) }
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 }
// 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) }
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) } }
/* 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 } }
// 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) }
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}] }
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 }
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() }
// 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) } }
/* 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) }
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) } } }
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) }
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) } }