/* This program has been developed by students from the bachelor Computer Science at Utrecht University within the Software Project course. © Copyright Utrecht University(Department of Information and Computing Sciences) */ package cypherv2 import ( "encoding/json" "fmt" "strings" "testing" "git.science.uu.nl/graphpolaris/query-conversion/entityv2" "github.com/stretchr/testify/assert" ) // All these tests test the entire flow func fixCypherSpaces(cypher *string) string { trimmedCypher := strings.Replace(*cypher, "\n", " ", -1) trimmedCypher = strings.Replace(trimmedCypher, " ", " ", -1) trimmedCypher = strings.Replace(trimmedCypher, "\t", "", -1) return trimmedCypher } func TestV2NoLogic(t *testing.T) { query := []byte(`{ "databaseName": "Movies3", "return": ["*"], "query": [ { "id": "path1", "node": { "label": "Person", "id": "p1", "relation": { "label": "DIRECTED", "direction": "TO", "depth": { "min": 1, "max": 1 }, "node": { "label": "Movie", "id": "m1" } } } }, { "id": "path2", "node": { "label": "Person", "id": "p1", "relation": { "label": "IN_GENRE", "direction": "TO", "depth": { "min": 1, "max": 1 }, "node": { "label": "Genre", "id": "g1" } } } } ], "limit": 5000 } `) var JSONQuery entityv2.IncomingQueryJSON err := json.Unmarshal(query, &JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } s := NewService() cypher, _, err := s.ConvertQuery(&JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } t.Log(*cypher) answer := `MATCH path1 = ((p1:Person)<-[:DIRECTED*1..1]-(m1:Movie)) MATCH path2 = ((p1:Person)<-[:IN_GENRE*1..1]-(g1:Genre)) RETURN * LIMIT 5000` fmt.Printf("Cypher: %s\n", answer) trimmedCypher := fixCypherSpaces(cypher) trimmedAnswer := fixCypherSpaces(&answer) assert.Equal(t, trimmedAnswer, trimmedCypher) } func TestV2Simple(t *testing.T) { query := []byte(`{ "databaseName": "Movies3", "return": ["*"], "logic": ["!=", "@p1.name", "\"Raymond Campbell\""], "query": [ { "id": "path1", "node": { "label": "Person", "id": "p1", "relation": { "label": "DIRECTED", "direction": "TO", "depth": { "min": 1, "max": 1 }, "node": { "label": "Movie", "id": "m1" } } } }, { "id": "path2", "node": { "label": "Person", "id": "p1", "relation": { "label": "IN_GENRE", "direction": "TO", "depth": { "min": 1, "max": 1 }, "node": { "label": "Genre", "id": "g1" } } } } ], "limit": 5000 } `) var JSONQuery entityv2.IncomingQueryJSON err := json.Unmarshal(query, &JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } s := NewService() cypher, _, err := s.ConvertQuery(&JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } t.Log(*cypher) answer := `MATCH path1 = ((p1:Person)<-[:DIRECTED*1..1]-(m1:Movie)) MATCH path2 = ((p1:Person)<-[:IN_GENRE*1..1]-(g1:Genre)) WHERE (p1.name <> "Raymond Campbell") RETURN * LIMIT 5000` fmt.Printf("Cypher: %s\n", answer) trimmedCypher := fixCypherSpaces(cypher) trimmedAnswer := fixCypherSpaces(&answer) assert.Equal(t, trimmedAnswer, trimmedCypher) } func TestV2GroupBy(t *testing.T) { query := []byte(`{ "databaseName": "TweedeKamer", "limit": 5000, "logic": ["AND", ["<", "@movie.imdbRating", 7.5], ["==", "p2.age", "p1.age"]], "query": [ { "ID": "path1", "node": { "label": "Person", "ID": "p1", "relation": { "ID": "acted", "label": "ACTED_IN", "depth": { "min": 1, "max": 1 }, "direction": "TO", "node": { "label": "Movie", "ID": "movie" } } } }, { "ID": "path2", "node": { "label": "Person", "ID": "p2" } } ], "return": ["@path2"] }`) var JSONQuery entityv2.IncomingQueryJSON err := json.Unmarshal(query, &JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } s := NewService() cypher, _, err := s.ConvertQuery(&JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } t.Log(*cypher) answer := `MATCH path1 = ((p1:Person)<-[acted:ACTED_IN*1..1]-(movie:Movie)) MATCH path2 = ((p2:Person)) WHERE ((movie.imdbRating < 7.500000) AND (p2.age = p1.age)) RETURN path2 LIMIT 5000` fmt.Printf("Cypher: %s\n", answer) trimmedCypher := fixCypherSpaces(cypher) trimmedAnswer := fixCypherSpaces(&answer) assert.Equal(t, trimmedAnswer, trimmedCypher) } func TestV2NoLabel(t *testing.T) { query := []byte(`{ "databaseName": "TweedeKamer", "limit": 5000, "logic": ["<", ["-", "@movie.year", "p1.year"], 10], "query": [ { "ID": "path1", "node": { "ID": "p1", "filter": [], "relation": { "ID": "acted", "depth": { "min": 1, "max": 1 }, "direction": "TO", "node": { "label": "Movie", "ID": "movie" } } } } ], "return": ["*"] }`) var JSONQuery entityv2.IncomingQueryJSON err := json.Unmarshal(query, &JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } s := NewService() cypher, _, err := s.ConvertQuery(&JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } t.Log(*cypher) answer := `MATCH path1 = ((p1)<-[acted*1..1]-(movie:Movie)) WHERE ((movie.year - p1.year) < 10.000000) RETURN * LIMIT 5000` fmt.Printf("Cypher: %s\n", answer) trimmedCypher := fixCypherSpaces(cypher) trimmedAnswer := fixCypherSpaces(&answer) assert.Equal(t, trimmedAnswer, trimmedCypher) } func TestV2NoDepth(t *testing.T) { query := []byte(`{ "databaseName": "TweedeKamer", "limit": 5000, "logic": ["AND", ["<", "@movie.imdbRating", 7.5], ["==", "p2.age", "p1.age"]], "query": [ { "ID": "path1", "node": { "ID": "p1", "relation": { "ID": "acted", "direction": "TO", "node": { "label": "Movie", "ID": "movie" } } } }, { "ID": "path2", "node": { "ID": "p2" } } ], "return": ["*"] }`) var JSONQuery entityv2.IncomingQueryJSON err := json.Unmarshal(query, &JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } fmt.Printf("%+v\n", JSONQuery) s := NewService() cypher, _, err := s.ConvertQuery(&JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } t.Log(*cypher) answer := `MATCH path1 = ((p1)<-[acted]-(movie:Movie)) MATCH path2 = ((p2)) WHERE ((movie.imdbRating < 7.500000) AND (p2.age = p1.age)) RETURN * LIMIT 5000` fmt.Printf("Cypher: %s\n", answer) trimmedCypher := fixCypherSpaces(cypher) trimmedAnswer := fixCypherSpaces(&answer) assert.Equal(t, trimmedAnswer, trimmedCypher) } func TestV2WithAverage(t *testing.T) { query := []byte(`{ "databaseName": "TweedeKamer", "limit": 5000, "logic": ["<", "@p1.age", ["Avg", "@p1.age"]], "query": [ { "ID": "path1", "node": { "label": "Person", "ID": "p1", "relation": { "ID": "acted", "label": "ACTED_IN", "depth": { "min": 1, "max": 1 }, "direction": "TO", "node": { "label": "Movie", "ID": "movie" } } } } ], "return": ["*"] }`) var JSONQuery entityv2.IncomingQueryJSON err := json.Unmarshal(query, &JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } s := NewService() cypher, _, err := s.ConvertQuery(&JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } t.Log(*cypher) answer := `MATCH path1 = ((p1:Person)<-[acted:ACTED_IN*1..1]-(movie:Movie)) WITH avg(p1.age) AS p1_age_avg MATCH path1 = ((p1:Person)<-[acted:ACTED_IN*1..1]-(movie:Movie)) WHERE (p1.age < p1_age_avg) RETURN * LIMIT 5000` fmt.Printf("Cypher: %s\n", answer) trimmedCypher := fixCypherSpaces(cypher) trimmedAnswer := fixCypherSpaces(&answer) assert.Equal(t, trimmedAnswer, trimmedCypher) } func TestV2WithAverage2Paths(t *testing.T) { query := []byte(`{ "databaseName": "TweedeKamer", "limit": 5000, "logic": ["<", "@p1.age", ["Avg", "@p1.age"]], "query": [ { "ID": "path1", "node": { "label": "Person", "ID": "p1", "relation": { "ID": "acted", "label": "ACTED_IN", "depth": { "min": 1, "max": 1 }, "direction": "TO", "node": { "label": "Movie", "ID": "movie" } } } },{ "ID": "path2", "node": { "label": "Person", "ID": "p2", "relation": { "ID": "acted", "label": "ACTED_IN", "depth": { "min": 1, "max": 1 }, "direction": "TO", "node": { "label": "Movie", "ID": "movie" } } } } ], "return": ["*"] }`) var JSONQuery entityv2.IncomingQueryJSON err := json.Unmarshal(query, &JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } s := NewService() cypher, _, err := s.ConvertQuery(&JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } t.Log(*cypher) answer := `MATCH path1 = ((p1:Person)<-[acted:ACTED_IN*1..1]-(movie:Movie)) MATCH path2 = ((p2:Person)<-[acted:ACTED_IN*1..1]-(movie:Movie)) WITH avg(p1.age) AS p1_age_avg MATCH path1 = ((p1:Person)<-[acted:ACTED_IN*1..1]-(movie:Movie)) MATCH path2 = ((p2:Person)<-[acted:ACTED_IN*1..1]-(movie:Movie)) WHERE (p1.age < p1_age_avg) RETURN * LIMIT 5000` fmt.Printf("Cypher: %s\n", answer) trimmedCypher := fixCypherSpaces(cypher) trimmedAnswer := fixCypherSpaces(&answer) assert.Equal(t, trimmedAnswer, trimmedCypher) } func TestV2SingleEntityWithLowerLike(t *testing.T) { query := []byte(`{ "databaseName": "TweedeKamer", "limit": 5000, "logic": ["Like", ["Lower", "@p1.name"], "\"john\""], "query": [ { "ID": "path1", "node": { "label": "Person", "ID": "p1" } } ], "return": ["*"] }`) var JSONQuery entityv2.IncomingQueryJSON err := json.Unmarshal(query, &JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } s := NewService() cypher, _, err := s.ConvertQuery(&JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } t.Log(*cypher) answer := `MATCH path1 = ((p1:Person)) MATCH path1 = ((p1:Person)) WHERE (toLower(p1.name) =~ (".*" + "john" + ".*")) RETURN * LIMIT 5000` fmt.Printf("Cypher: %s\n", answer) trimmedCypher := fixCypherSpaces(cypher) trimmedAnswer := fixCypherSpaces(&answer) assert.Equal(t, trimmedAnswer, trimmedCypher) } func TestV2Like(t *testing.T) { query := []byte(`{ "databaseName": "neo4j", "query": [ { "ID": "path_0", "node": { "ID": "id_1691576718400", "label": "Employee", "relation": { "ID": "id_1691576720177", "label": "REPORTS_TO", "direction": "TO", "node": {} } } } ], "limit": 500, "return": [ "*" ], "logic": [ "Like", "@id_1691576718400.title", "\"ale\"" ] }`) var JSONQuery entityv2.IncomingQueryJSON err := json.Unmarshal(query, &JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } s := NewService() cypher, _, err := s.ConvertQuery(&JSONQuery) if err != nil { fmt.Println(err) t.Log(err) } t.Log(*cypher) answer := `MATCH path_0 = ((id_1691576718400:Employee)<-[id_1691576720177:REPORTS_TO]-()) WHERE (id_1691576718400.title =~ (".*" + "ale" + ".*")) RETURN * LIMIT 500` fmt.Printf("Cypher: %s\n", answer) trimmedCypher := fixCypherSpaces(cypher) trimmedAnswer := fixCypherSpaces(&answer) assert.Equal(t, trimmedAnswer, trimmedCypher) } // func TestSmallChain(t *testing.T) { // query := []byte(`{ // "databaseName": "TweedeKamer", // "return": { // "entities": [ // 0, // 1, // 2 // ], // "relations": [ // 0, // 1 // ] // }, // "entities": [ // { // "name": "parliament", // "ID": 0, // "constraints": [ // { // "attribute": "name", // "value": "Geert", // "dataType": "string", // "matchType": "contains", // "inID": -1, // "inType": "" // } // ] // }, // { // "name": "parties", // "ID": 1, // "constraints": [] // }, // { // "name": "resolutions", // "ID": 2, // "constraints": [] // } // ], // "relations": [ // { // "ID": 0, // "name": "member_of", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 0, // "toType": "entity", // "toID": 1, // "constraints": [] // }, // { // "ID": 1, // "name": "submits", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 0, // "toType": "entity", // "toID": 2, // "constraints": [] // } // ], // "groupBys": [], // "machineLearning": [], // "limit": 5000 // } // `) // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // } // answer := `MATCH p0 = (e0:parliament)-[:member_of*1..1]-(e1:parties) // WHERE e0.name CONTAINS "%Geert%" // UNWIND relationships(p0) as r0 // WITH * // MATCH p1 = (e0:parliament)-[:submits*1..1]-(e2:resolutions) // WHERE e0.name CONTAINS "%Geert%" // UNWIND relationships(p1) as r1 // WITH * // UNWIND [r1,e0,e2,r0,e0,e1] AS x // RETURN DISTINCT x // LIMIT 5000;nodelink` // trimmedCypher := fixCypherSpaces(cypher) // trimmedAnswer := fixCypherSpaces(&answer) // assert.Equal(t, trimmedAnswer, trimmedCypher) // } // // This one does not really have dependencies, the order doesnt matter, maybe sort on numbers between equal dependencies? // func TestLargeQueryChain(t *testing.T) { // query := []byte(`{ // "databaseName": "TweedeKamer", // "return": { // "entities": [ // 0, // 1, // 2, // 3, // 4 // ], // "relations": [ // 0, // 1, // 2, // 3 // ] // }, // "entities": [ // { // "name": "parliament", // "ID": 0, // "constraints": [ // { // "attribute": "name", // "value": "A", // "dataType": "string", // "matchType": "contains", // "inID": -1, // "inType": "" // } // ] // }, // { // "name": "parties", // "ID": 1, // "constraints": [ // { // "attribute": "seats", // "value": "10", // "dataType": "int", // "matchType": "LT", // "inID": -1, // "inType": "" // } // ] // }, // { // "name": "resolutions", // "ID": 2, // "constraints": [ // { // "attribute": "date", // "value": "mei", // "dataType": "string", // "matchType": "contains", // "inID": -1, // "inType": "" // } // ] // }, // { // "name": "parliament", // "ID": 3, // "constraints": [] // }, // { // "name": "parties", // "ID": 4, // "constraints": [ // { // "attribute": "name", // "value": "Volkspartij voor Vrijheid en Democratie", // "dataType": "string", // "matchType": "==", // "inID": -1, // "inType": "" // } // ] // } // ], // "relations": [ // { // "ID": 0, // "name": "member_of", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 0, // "toType": "entity", // "toID": 1, // "constraints": [] // }, // { // "ID": 1, // "name": "submits", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 1, // "toType": "entity", // "toID": 2, // "constraints": [] // }, // { // "ID": 2, // "name": "submits", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 2, // "toType": "entity", // "toID": 3, // "constraints": [] // }, // { // "ID": 3, // "name": "member_of", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 3, // "toType": "entity", // "toID": 4, // "constraints": [] // } // ], // "groupBys": [], // "machineLearning": [], // "limit": 5000 // } // `) // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // } // answer := `MATCH p0 = (e0:parliament)-[:member_of*1..1]-(e1:parties) // WHERE e0.name CONTAINS "%A%" // AND e1.seats < 10 // UNWIND relationships(p0) as r0 // WITH * // MATCH p1 = (e1:parties)-[:submits*1..1]-(e2:resolutions) // WHERE e1.seats < 10 // AND e2.date CONTAINS "%mei%" // UNWIND relationships(p1) as r1 // WITH * // MATCH p2 = (e2:resolutions)-[:submits*1..1]-(e3:parliament) // WHERE e2.date CONTAINS "%mei%" // UNWIND relationships(p2) as r2 // WITH * // MATCH p3 = (e3:parliament)-[:member_of*1..1]-(e4:parties) // WHERE e4.name = "Volkspartij voor Vrijheid en Democratie" // UNWIND relationships(p3) as r3 // WITH * // UNWIND [r3,e3,e4,r2,e2,e3,r1,e1,e2,r0,e0,e1] AS x // RETURN DISTINCT x // LIMIT 5000;nodelink` // trimmedCypher := fixCypherSpaces(cypher) // trimmedAnswer := fixCypherSpaces(&answer) // assert.Equal(t, trimmedAnswer, trimmedCypher) // } // func TestInStatement(t *testing.T) { // query := []byte(`{ // "databaseName": "Movies3", // "entities": [ // { // "id": 0, // "name": "Person", // "constraints": [] // }, // { // "id": 1, // "name": "Movie", // "constraints": [] // }, // { // "id": 2, // "name": "Person", // "constraints": [ // { // "attribute": "bornIn", // "value": "", // "dataType": "string", // "matchType": "", // "inID": 0, // "inType": "groupBy" // } // ] // } // ], // "relations": [ // { // "id": 0, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 0, // "toType": "entity", // "toID": 1, // "constraints": [] // } // ], // "groupBys": [ // { // "id": 0, // "groupType": "entity", // "groupID": [1], // "groupAttribute": "imdbRating", // "byType": "entity", // "byID": [0], // "byAttribute": "bornIn", // "appliedModifier": "AVG", // "relationID": 0, // "constraints": [ // { // "attribute": "imdbRating", // "value": "7.5", // "dataType": "int", // "matchType": "GT", // "inID": -1, // "inType": "" // } // ] // } // ], // "machineLearning": [], // "limit": 5000 // } // `) // answer := `MATCH p0 = (e0:Person)-[:ACTED_IN*1..1]-(e1:Movie) // UNWIND relationships(p0) as r0 // WITH * // WITH e0.bornIn AS e0_bornIn, AVG(e1.imdbRating) AS AVG_imdbRating // WHERE AVG_imdbRating > 7.5 // MATCH (e2:Person) // WHERE e2.bornIn IN e0_bornIn // WITH * // UNWIND [e2] AS x // RETURN DISTINCT x // LIMIT 5000;nodelink` // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // } // trimmedCypher := fixCypherSpaces(cypher) // trimmedAnswer := fixCypherSpaces(&answer) // assert.Equal(t, trimmedAnswer, trimmedCypher) // } // func TestMultipleByStatementDisconnected(t *testing.T) { // query := []byte(`{ // "databaseName": "Movies3", // "entities": [ // { // "id": 0, // "name": "Person", // "constraints": [] // }, // { // "id": 1, // "name": "Movie", // "constraints": [] // }, // { // "id": 2, // "name": "Person", // "constraints": [] // }, // { // "id": 3, // "name": "Movie", // "constraints": [] // } // ], // "relations": [ // { // "id": 0, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 0, // "toType": "entity", // "toID": 1, // "constraints": [] // }, // { // "id": 2, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 2, // "toType": "entity", // "toID": 3, // "constraints": [] // } // ], // "groupBys": [ // { // "id": 0, // "groupType": "entity", // "groupID": [1,3], // "groupAttribute": "imdbRating", // "byType": "entity", // "byID": [0,2], // "byAttribute": "bornIn", // "appliedModifier": "AVG", // "relationID": 0, // "constraints": [ // { // "attribute": "imdbRating", // "value": "7.5", // "dataType": "int", // "matchType": "GT", // "inID": -1, // "inType": "" // } // ] // } // ], // "machineLearning": [], // "limit": 5000 // } // `) // answer := `MATCH p0 = (e0:Person)-[:ACTED_IN*1..1]-(e1:Movie) // UNWIND relationships(p0) as r0 // WITH * // MATCH p1 = (e2:Person)-[:ACTED_IN*1..1]-(e3:Movie) // UNWIND relationships(p1) as r2 // WITH * // UNWIND [e0,e2] AS e02L // UNWIND [e1,e3] AS e13L // WITH e02L.bornIn AS e02L_bornIn, AVG(e13L.imdbRating) AS AVG_imdbRating // WHERE AVG_imdbRating > 7.5 // RETURN e02L_bornIn, AVG_imdbRating // LIMIT 5000;table` // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // } // trimmedCypher := fixCypherSpaces(cypher) // trimmedAnswer := fixCypherSpaces(&answer) // assert.Equal(t, trimmedAnswer, trimmedCypher) // } // func TestDoubleInStatement(t *testing.T) { // query := []byte(`{ // "databaseName": "Movies3", // "entities": [ // { // "id": 0, // "name": "Person", // "constraints": [] // }, // { // "id": 1, // "name": "Movie", // "constraints": [] // }, // { // "id": 2, // "name": "Person", // "constraints": [ // { // "attribute": "bornIn", // "value": "", // "dataType": "string", // "matchType": "", // "inID": 0, // "inType": "groupBy" // } // ] // }, // { // "id": 3, // "name": "Person", // "constraints": [ // { // "attribute": "bornIn", // "value": "", // "dataType": "string", // "matchType": "", // "inID": 0, // "inType": "groupBy" // } // ] // } // ], // "relations": [ // { // "id": 0, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 0, // "toType": "entity", // "toID": 1, // "constraints": [] // } // ], // "groupBys": [ // { // "id": 0, // "groupType": "entity", // "groupID": [1], // "groupAttribute": "imdbRating", // "byType": "entity", // "byID": [0], // "byAttribute": "bornIn", // "appliedModifier": "AVG", // "relationID": 0, // "constraints": [ // { // "attribute": "imdbRating", // "value": "7.5", // "dataType": "int", // "matchType": "GT", // "inID": -1, // "inType": "" // } // ] // } // ], // "machineLearning": [], // "limit": 5000 // } // `) // answer := `MATCH p0 = (e0:Person)-[:ACTED_IN*1..1]-(e1:Movie) // UNWIND relationships(p0) as r0 // WITH * // WITH e0.bornIn AS e0_bornIn, AVG(e1.imdbRating) AS AVG_imdbRating // WHERE AVG_imdbRating > 7.5 // MATCH (e2:Person) // WHERE e2.bornIn IN e0_bornIn // WITH * // MATCH (e3:Person) // WHERE e3.bornIn IN e0_bornIn // WITH * // UNWIND [e3] AS x // RETURN DISTINCT x // LIMIT 5000;nodelink` // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // } // trimmedCypher := fixCypherSpaces(cypher) // trimmedAnswer := fixCypherSpaces(&answer) // assert.Equal(t, trimmedAnswer, trimmedCypher) // } // func TestEndOnGroupBy(t *testing.T) { // query := []byte(`{ // "return": { // "entities": [ // 11, // 12 // ], // "relations": [ // 10 // ], // "groupBys": [ // 1 // ] // }, // "entities": [ // { // "name": "Person", // "ID": 11, // "constraints": [] // }, // { // "name": "Movie", // "ID": 12, // "constraints": [] // } // ], // "relations": [ // { // "ID": 10, // "name": "DIRECTED", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 11, // "toType": "entity", // "toID": 12, // "constraints": [] // } // ], // "groupBys": [ // { // "id": 0, // "groupType": "entity", // "groupID": [11], // "groupAttribute": "imdbRating", // "byType": "entity", // "byID": [12], // "byAttribute": "bornIn", // "appliedModifier": "AVG", // "relationID": 10, // "constraints": [] // } // ], // "machineLearning": [], // "limit": 5000, // "databaseName": "Movies3" // } // `) // answer := `MATCH p0 = (e11:Person)-[:DIRECTED*1..1]-(e12:Movie) // UNWIND relationships(p0) as r10 // WITH * // WITH e12.bornIn AS e12_bornIn, AVG(e11.imdbRating) AS AVG_imdbRating // RETURN e12_bornIn, AVG_imdbRating // LIMIT 5000;table` // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // } // trimmedCypher := fixCypherSpaces(cypher) // trimmedAnswer := fixCypherSpaces(&answer) // assert.Equal(t, trimmedAnswer, trimmedCypher) // } // func TestSimpleQuery(t *testing.T) { // query := []byte(`{ // "return": { // "entities": [ // 11, // 12 // ], // "relations": [ // 10 // ], // "groupBys": [] // }, // "entities": [ // { // "name": "Person", // "ID": 11, // "constraints": [] // }, // { // "name": "Movie", // "ID": 12, // "constraints": [] // } // ], // "relations": [ // { // "ID": 10, // "name": "DIRECTED", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 11, // "toType": "entity", // "toID": 12, // "constraints": [] // } // ], // "groupBys": [], // "machineLearning": [], // "limit": 5000, // "databaseName": "Movies3" // } // `) // answer := `MATCH p0 = (e11:Person)-[:DIRECTED*1..1]-(e12:Movie) // UNWIND relationships(p0) as r10 // WITH * // UNWIND [r10,e11,e12] AS x // RETURN DISTINCT x // LIMIT 5000;nodelink` // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // } // trimmedCypher := fixCypherSpaces(cypher) // trimmedAnswer := fixCypherSpaces(&answer) // assert.Equal(t, trimmedAnswer, trimmedCypher) // } // func TestNoRelation(t *testing.T) { // query := []byte(`{ // "return": { // "entities": [ // 11, // 12 // ], // "relations": [ // 10 // ], // "groupBys": [] // }, // "entities": [ // { // "name": "Person", // "ID": 11, // "constraints": [] // }, // { // "name": "Movie", // "ID": 12, // "constraints": [] // } // ], // "relations": [], // "groupBys": [], // "machineLearning": [], // "limit": 5000, // "databaseName": "Movies3" // } // `) // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // fmt.Println(JSONQuery) // fmt.Println(" ") // s := NewService() // _, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // assert.Equal(t, err.Error(), "Invalid query") // } else { // // It should error, thus it must not reach this // t.Fail() // } // } // func TestNoEntities(t *testing.T) { // query := []byte(`{ // "return": { // "entities": [ // 11, // 12 // ], // "relations": [ // 10 // ], // "groupBys": [] // }, // "entities": [], // "relations": [ // { // "ID": 10, // "name": "DIRECTED", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 11, // "toType": "entity", // "toID": 12, // "constraints": [] // } // ], // "groupBys": [], // "machineLearning": [], // "limit": 5000, // "databaseName": "Movies3" // } // `) // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // fmt.Println(JSONQuery) // fmt.Println(" ") // s := NewService() // _, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // assert.Equal(t, err.Error(), "Invalid query") // } else { // // It should error, thus it must not reach this // t.Fail() // } // } // func TestTwoRelationsCycle(t *testing.T) { // query := []byte(`{ // "return": { // "entities": [ // 11, // 12 // ], // "relations": [ // 10 // ], // "groupBys": [] // }, // "entities": [ // { // "name": "Person", // "ID": 11, // "constraints": [] // }, // { // "name": "Movie", // "ID": 12, // "constraints": [] // } // ], // "relations": [ // { // "ID": 10, // "name": "DIRECTED", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 11, // "toType": "entity", // "toID": 12, // "constraints": [] // }, // { // "ID": 11, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 12, // "toType": "entity", // "toID": 11, // "constraints": [] // } // ], // "groupBys": [], // "machineLearning": [], // "limit": 5000, // "databaseName": "Movies3" // } // `) // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // fmt.Println(JSONQuery) // fmt.Println(" ") // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // t.Fail() // return // } // if cypher == nil { // t.Fail() // return // } // answer1 := `MATCH p0 = (e11:Person)-[:DIRECTED*1..1]-(e12:Movie) // UNWIND relationships(p0) as r10 // WITH * // MATCH p1 = (e12:Movie)-[:ACTED_IN*1..1]-(e11:Person) // UNWIND relationships(p1) as r11 // WITH * // UNWIND [r11,e12,e11,r10,e11,e12] AS x // RETURN DISTINCT x // LIMIT 5000;nodelink` // answer2 := `MATCH p1 = (e12:Movie)-[:ACTED_IN*1..1]-(e11:Person) // UNWIND relationships(p1) as r11 // WITH * // MATCH p0 = (e11:Person)-[:DIRECTED*1..1]-(e12:Movie) // UNWIND relationships(p0) as r10 // WITH * // UNWIND [r10,e11,e12,r11,e12,e11] AS x // RETURN DISTINCT x // LIMIT 5000;nodelink` // trimmedCypher := fixCypherSpaces(cypher) // trimmedAnswer1 := fixCypherSpaces(&answer1) // trimmedAnswer2 := fixCypherSpaces(&answer2) // fmt.Println(*cypher) // // Both answers are correct // if !(trimmedAnswer1 == trimmedCypher || trimmedAnswer2 == trimmedCypher) { // t.Fail() // } // } // func TestCyclePlusDependency(t *testing.T) { // query := []byte(`{ // "return": { // "entities": [ // 11, // 12 // ], // "relations": [ // 10 // ], // "groupBys": [] // }, // "entities": [ // { // "name": "Person", // "ID": 11, // "constraints": [] // }, // { // "name": "Movie", // "ID": 12, // "constraints": [] // }, // { // "name": "Person", // "ID": 13, // "constraints": [] // } // ], // "relations": [ // { // "ID": 10, // "name": "DIRECTED", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 11, // "toType": "entity", // "toID": 12, // "constraints": [] // }, // { // "ID": 11, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 12, // "toType": "entity", // "toID": 11, // "constraints": [] // }, // { // "ID": 12, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 13, // "toType": "entity", // "toID": 12, // "constraints": [] // } // ], // "groupBys": [], // "machineLearning": [], // "limit": 5000, // "databaseName": "Movies3" // } // `) // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // fmt.Println(JSONQuery) // fmt.Println(" ") // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // t.Fail() // return // } // if cypher == nil { // t.Fail() // return // } // answer := `MATCH p2 = (e13:Person)-[:ACTED_IN*1..1]-(e12:Movie) // UNWIND relationships(p2) as r12 // WITH * // MATCH p1 = (e12:Movie)-[:ACTED_IN*1..1]-(e11:Person) // UNWIND relationships(p1) as r11 // WITH * // MATCH p0 = (e11:Person)-[:DIRECTED*1..1]-(e12:Movie) // UNWIND relationships(p0) as r10 // WITH * // UNWIND [r10,e11,e12,r11,e12,e11,r12,e13,e12] AS x // RETURN DISTINCT x // LIMIT 5000;nodelink` // trimmedCypher := fixCypherSpaces(cypher) // trimmedAnswer := fixCypherSpaces(&answer) // fmt.Println(*cypher) // assert.Equal(t, trimmedAnswer, trimmedCypher) // } // func TestTripleCycle(t *testing.T) { // query := []byte(`{ // "return": { // "entities": [ // 11, // 12 // ], // "relations": [ // 10 // ], // "groupBys": [] // }, // "entities": [ // { // "name": "Person", // "ID": 11, // "constraints": [] // }, // { // "name": "Movie", // "ID": 12, // "constraints": [] // }, // { // "name": "Person", // "ID": 13, // "constraints": [] // } // ], // "relations": [ // { // "ID": 10, // "name": "DIRECTED", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 11, // "toType": "entity", // "toID": 12, // "constraints": [] // }, // { // "ID": 11, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 12, // "toType": "entity", // "toID": 13, // "constraints": [] // }, // { // "ID": 12, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 13, // "toType": "entity", // "toID": 11, // "constraints": [] // } // ], // "groupBys": [], // "machineLearning": [], // "limit": 5000, // "databaseName": "Movies3" // } // `) // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // assert.Equal(t, err, errors.New("Cyclic query detected")) // return // } // if cypher == nil { // t.Fail() // return // } // t.Fail() // } // func TestMultipleByStatementConnected(t *testing.T) { // query := []byte(`{ // "databaseName": "Movies3", // "entities": [ // { // "id": 0, // "name": "Person", // "constraints": [] // }, // { // "id": 1, // "name": "Movie", // "constraints": [] // }, // { // "id": 2, // "name": "Person", // "constraints": [] // } // ], // "relations": [ // { // "id": 0, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 0, // "toType": "entity", // "toID": 1, // "constraints": [] // }, // { // "id": 2, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 2, // "toType": "entity", // "toID": 1, // "constraints": [] // } // ], // "groupBys": [ // { // "id": 0, // "groupType": "entity", // "groupID": [1], // "groupAttribute": "imdbRating", // "byType": "entity", // "byID": [0,2], // "byAttribute": "bornIn", // "appliedModifier": "AVG", // "relationID": 0, // "constraints": [ // { // "attribute": "imdbRating", // "value": "7.5", // "dataType": "int", // "matchType": "GT", // "inID": -1, // "inType": "" // } // ] // } // ], // "machineLearning": [], // "limit": 5000 // } // `) // answer := `MATCH p0 = (e0:Person)-[:ACTED_IN*1..1]-(e1:Movie) // UNWIND relationships(p0) as r0 // WITH * // MATCH p1 = (e2:Person)-[:ACTED_IN*1..1]-(e1:Movie) // UNWIND relationships(p1) as r2 // WITH * // UNWIND [e0,e2] AS e02L // WITH e02L.bornIn AS e02L_bornIn, AVG(e1.imdbRating) AS AVG_imdbRating // WHERE AVG_imdbRating > 7.5 // RETURN e02L_bornIn, AVG_imdbRating // LIMIT 5000;table` // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // } // println(cypher) // trimmedCypher := fixCypherSpaces(cypher) // trimmedAnswer := fixCypherSpaces(&answer) // fmt.Println(*cypher) // assert.Equal(t, trimmedAnswer, trimmedCypher) // } // func TestRelationOnGroupBy(t *testing.T) { // query := []byte(`{ // "databaseName": "Movies3", // "entities": [ // { // "id": 0, // "name": "Person", // "constraints": [] // }, // { // "id": 1, // "name": "Movie", // "constraints": [] // }, // { // "id": 2, // "name": "Person", // "constraints": [] // }, // { // "id": 3, // "name": "Movie", // "constraints": [] // } // ], // "relations": [ // { // "id": 0, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 0, // "toType": "entity", // "toID": 1, // "constraints": [] // }, // { // "id": 1, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "entity", // "fromID": 2, // "toType": "entity", // "toID": 1, // "constraints": [] // }, // { // "id": 2, // "name": "ACTED_IN", // "depth": { // "min": 1, // "max": 1 // }, // "fromType": "groupBy", // "fromID": 0, // "toType": "entity", // "toID": 3, // "constraints": [] // } // ], // "groupBys": [ // { // "id": 0, // "groupType": "entity", // "groupID": [1], // "groupAttribute": "imdbRating", // "byType": "entity", // "byID": [0,2], // "byAttribute": "bornIn", // "appliedModifier": "AVG", // "relationID": 0, // "constraints": [ // { // "attribute": "imdbRating", // "value": "7.5", // "dataType": "int", // "matchType": "GT", // "inID": -1, // "inType": "" // } // ] // } // ], // "machineLearning": [], // "limit": 5000 // } // `) // answer1 := `MATCH p0 = (e0:Person)-[:ACTED_IN*1..1]-(e1:Movie) // UNWIND relationships(p0) as r0 // WITH * // MATCH p1 = (e2:Person)-[:ACTED_IN*1..1]-(e1:Movie) // UNWIND relationships(p1) as r1 // WITH * // UNWIND [e0,e2] AS e02L // WITH e02L.bornIn AS e02L_bornIn, AVG(e1.imdbRating) AS AVG_imdbRating // WHERE AVG_imdbRating > 7.5 // MATCH p2 = (eg02L:Person)-[:ACTED_IN*1..1]-(e3:Movie) // WHERE eg02L.bornIn IN e02L_bornIn // UNWIND relationships(p2) as r2 // WITH * // UNWIND [r2,eg02L,e3] AS x // RETURN DISTINCT x // LIMIT 5000;nodelink` // answer2 := `MATCH p1 = (e2:Person)-[:ACTED_IN*1..1]-(e1:Movie) // UNWIND relationships(p1) as r1 // WITH * // MATCH p0 = (e0:Person)-[:ACTED_IN*1..1]-(e1:Movie) // UNWIND relationships(p0) as r0 // WITH * // UNWIND [e0,e2] AS e02L // WITH e02L.bornIn AS e02L_bornIn, AVG(e1.imdbRating) AS AVG_imdbRating // WHERE AVG_imdbRating > 7.5 // MATCH p2 = (eg02L:Person)-[:ACTED_IN*1..1]-(e3:Movie) // WHERE eg02L.bornIn IN e02L_bornIn // UNWIND relationships(p2) as r2 // WITH * // UNWIND [r2,eg02L,e3] AS x // RETURN DISTINCT x // LIMIT 5000;nodelink` // var JSONQuery entity.IncomingQueryJSON // json.Unmarshal(query, &JSONQuery) // s := NewService() // cypher, _, err := s.ConvertQuery(&JSONQuery) // if err != nil { // fmt.Println(err) // } // trimmedCypher := fixCypherSpaces(cypher) // trimmedAnswer1 := fixCypherSpaces(&answer1) // trimmedAnswer2 := fixCypherSpaces(&answer2) // if !(trimmedCypher == trimmedAnswer1 || trimmedCypher == trimmedAnswer2) { // t.Fail() // } // }