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