Skip to content

Latest commit

 

History

History
1242 lines (1102 loc) · 22.3 KB

File metadata and controls

1242 lines (1102 loc) · 22.3 KB

Movie Test TCK

Schema

type Movie {
  _id: Int
  movieId: ID!
  title: String
  year: Int
  released: Int # was DateTime
  plot: String
  poster: String
  imdbRating: Float
  genres: [Genre] @relation(name: "IN_GENRE", direction: OUT)
  similar(first: Int = 3, offset: Int = 0): [Movie] @cypher(statement: "MATCH (this)--(:Genre)--(o:Movie) RETURN o")
  mostSimilar: Movie @cypher(statement: "RETURN this")
  degree: Int @cypher(statement: "RETURN SIZE((this)--())")
  actors(first: Int = 3, offset: Int = 0, name: String): [Actor] @relation(name: "ACTED_IN", direction:IN)
  avgStars: Float
  filmedIn: State @relation(name: "FILMED_IN", direction: OUT)
  scaleRating(scale: Int = 3): Float @cypher(statement: "RETURN $scale * this.imdbRating")
  scaleRatingFloat(scale: Float = 1.5): Float @cypher(statement: "RETURN $scale * this.imdbRating")
  actorMovies: [Movie] @cypher(statement: """
  MATCH (this)-[:ACTED_IN*2]-(other:Movie)
  RETURN other
  """)
  publishedBy: Publisher @relation(name: "PUBLISHED_BY", direction: OUT)
  ratings: [Rated] @relation(name:"RATED")
}
type Publisher {
  name: ID!
}
type Genre {
  _id: String!
  name: ID!
  movies(first: Int = 3, offset: Int = 0): [Movie] @relation(name: "IN_GENRE", direction: IN)
  highestRatedMovie: Movie @cypher(statement: "MATCH (m:Movie)-[:IN_GENRE]->(this) RETURN m ORDER BY m.imdbRating DESC LIMIT 1")
}
type State {
  _id: ID!
  name: String
}
interface Person {
  userId: ID!
  name: String
}
type Actor implements Person
{
  userId: ID!
  name: String
  movies: [Movie] @relation(name: "ACTED_IN", direction:OUT)
  born: _Neo4jDateTime
}
type User implements Person
{
  userId: ID!
  name: String
  rated(rating: Int): [Rated]
  friends(since: Int): [FriendOf]
  knows: [User] @relation(name: "KNOWS", direction:OUT)
  born: _Neo4jDateTime
}
type FriendOf {
  from: User
  since: Int
  to: User
}
type Rated @relation(name:"RATED") {
  _id: ID!
  from: User
  rating: Int
  to: Movie
}
enum BookGenre {
  Mystery,
  Science,
  Math
}
type Book {
  genre: BookGenre
}
enum _MovieOrdering {
  title_desc,
  title_asc
}
enum _GenreOrdering {
  name_desc,
  name_asc
}
type Query {
  Movie(_id: String, movieId: ID, title: String, year: Int, plot: String, poster: String, imdbRating: Float, first: Int, offset: Int, orderBy: _MovieOrdering): [Movie]
  MoviesByYear(year: Int): [Movie]
  MovieById(movieId: ID!): Movie
  MovieBy_Id(_id: String!): Movie
  GenresBySubstring(substring: String): [Genre] @cypher(statement: "MATCH (g:Genre) WHERE toLower(g.name) CONTAINS toLower($substring) RETURN g")
  Books: [Book]
  User: [User]
}
type Mutation {
  createGenre(name:String): Genre @cypher(statement:"CREATE (g:Genre) SET g.name = name RETURN g")
  changePerson(name: String): Person
}
# scalar DateTime

Queries

Top Level Query

GraphQL-Query
query {
  Movie {
    movieId
  }
}
Cypher Params
{}
Cypher
MATCH (movie:Movie)
RETURN movie { .movieId } AS movie

Query Single Object

GraphQL-Query
{
  MovieById(movieId: "18") {
    title
  }
}
Cypher Params
{
  "movieByIdMovieId": "18"
}
Cypher
MATCH (movieById:Movie)
WHERE movieById.movieId = $movieByIdMovieId
RETURN movieById { .title } AS movieById

Basic Query with Parameter

GraphQL-Query
{  Movie(title: "River Runs Through It, A")  {  title }  }
Cypher Params
{
  "movieTitle": "River Runs Through It, A"
}
Cypher
MATCH (movie:Movie)
WHERE  movie.title = $movieTitle
RETURN movie { .title } AS movie

Paging

GraphQL-Query
{
  Movie(title: "River Runs Through It, A", first: 1, offset: 1) {
    title
    year
  }
}
Cypher Params
{
  "movieTitle": "River Runs Through It, A",
  "movieOffset": 1,
  "movieFirst": 1
}
Cypher
MATCH (movie:Movie)
WHERE movie.title = $movieTitle
RETURN movie { .title, .year } AS movie
SKIP $movieOffset LIMIT $movieFirst

Query Single Relation

GraphQL-Query
{
  MovieById(movieId: "3100") {
    title
    filmedIn {
      name
    }
  }
}
Cypher Params
{
  "movieByIdMovieId": "3100"
}
Cypher
MATCH (movieById:Movie)
WHERE movieById.movieId = $movieByIdMovieId
RETURN movieById {
  .title,
  filmedIn:[(movieById)-[:FILMED_IN]->(movieByIdFilmedIn:State) | movieByIdFilmedIn { .name }][0]
} AS movieById

Query Single Object and Array of Object Relations

GraphQL-Query
{
  MovieById(movieId: "3100") {
    title
    actors {
      name
    }
    filmedIn{
      name
    }
  }
}
Cypher Params
{
  "movieByIdMovieId": "3100"
}
Cypher
MATCH (movieById:Movie)
WHERE movieById.movieId = $movieByIdMovieId
RETURN movieById {
  .title,
  actors:[(movieById)<-[:ACTED_IN]-(movieByIdActors:Actor) | movieByIdActors { .name }],
  filmedIn:[(movieById)-[:FILMED_IN]->(movieByIdFilmedIn:State) | movieByIdFilmedIn { .name }][0]
} AS movieById

Relationship Expansion

GraphQL-Query
{
  Movie(title: "River Runs Through It, A") {
    title
    actors {
      name
    }
  }
}
Cypher Params
{
  "movieTitle": "River Runs Through It, A"
}
Cypher
MATCH (movie:Movie)
WHERE movie.title = $movieTitle
RETURN movie {
  .title,
  actors:[(movie)<-[:ACTED_IN]-(movieActors:Actor) | movieActors { .name }]
} AS movie

Projection with sub-paging

GraphQL-Query
{
  Movie(title: "River Runs Through It, A") {
    title
    actors(first:3) {
      name
    }
  }
}
Cypher Params
{
  "movieTitle": "River Runs Through It, A",
  "movieActorsFirst": 3
}
Cypher
MATCH (movie:Movie)
WHERE movie.title = $movieTitle
RETURN movie {
  .title,
  actors:[(movie)<-[:ACTED_IN]-(movieActors:Actor) | movieActors { .name }][0..$movieActorsFirst]
} AS movie

Subquery Cypher Directive

GraphQL-Query
{
  Movie {
    title
    similar {
      title
    }
  }
}
Cypher Params
{
  "movieFirst": 3,
  "movieOffset": 0
}
Cypher
MATCH (movie:Movie)
RETURN movie {
  .title,
  similar:[movieSimilar
    IN apoc.cypher.runFirstColumnMany('WITH $this AS this, $first AS first, $offset AS offset MATCH (this)--(:Genre)--(o:Movie) RETURN o', {
        this:movie,
        first:$movieFirst,
        offset:$movieOffset
      }) | movieSimilar {
        .title
      }]
} AS movie

Subquery Cypher Directive Paging

GraphQL-Query
{
  Movie {
    title
    similar(first:3) {
      title
    }
  }
}
Cypher Params
{
  "movieFirst": 3,
  "movieOffset": 0,
  "movieSimilarFirst": 3
}
Cypher
MATCH (movie:Movie)
RETURN movie {
  .title,
  similar:[movieSimilar
    IN apoc.cypher.runFirstColumnMany('WITH $this AS this, $first AS first, $offset AS offset MATCH (this)--(:Genre)--(o:Movie) RETURN o', {
      this:movie,
      first:$movieFirst,
      offset:$movieOffset
    }) | movieSimilar {
      .title
    }][0..$movieSimilarFirst]
} AS movie

Handle Cypher Directive on Query Type

GraphQL-Query
{
  GenresBySubstring(substring:"Action") {
    name
    movies(first: 3) {
      title
    }
  }
}
Cypher Params
{
  "genresBySubstringSubstring": "Action",
  "genresBySubstringMoviesFirst": 3
}
Cypher
UNWIND apoc.cypher.runFirstColumnMany('WITH $substring AS substring MATCH (g:Genre) WHERE toLower(g.name) CONTAINS toLower($substring) RETURN g', { substring:$genresBySubstringSubstring }) AS genresBySubstring
RETURN genresBySubstring {
  .name,
  movies:[(genresBySubstring)<-[:IN_GENRE]-(genresBySubstringMovies:Movie) | genresBySubstringMovies { .title }][0..$genresBySubstringMoviesFirst]
} AS genresBySubstring

Handle Cypher directive on Mutation type

GraphQL-Query
mutation someMutation {
  createGenre(name: "Wildlife Documentary") {
    name
  }
}
Cypher Params
{
  "createGenreName": "Wildlife Documentary"
}
Cypher
CALL apoc.cypher.doIt('WITH $name AS name CREATE (g:Genre) SET g.name = name RETURN g', { name:$createGenreName }) YIELD value
WITH value[head(keys(value))] AS createGenre
RETURN createGenre { .name } AS createGenre

Query using Inline Fragment

GraphQL-Query
{
  Movie(title: "River Runs Through It, A") {
    title
    ratings {
      rating
      from {
        ... on User {
          name
          userId
        }
      }
    }
  }
}
Cypher Params
{
  "movieTitle": "River Runs Through It, A"
}
Cypher
MATCH (movie:Movie)
WHERE movie.title = $movieTitle
RETURN movie {
  .title,
  ratings:[(movie)<-[movieRatings:RATED]-(movieRatingsFrom:User) | movieRatings {
    .rating,
    from:movieRatingsFrom { .name, .userId }
  }]
} AS movie

Deeply nested object query

GraphQL-Query
{
  Movie(title: "River Runs Through It, A") {
    title
    actors {
      name
      movies {
        title
        actors(name: "Tom Hanks") {
          name
          movies {
            title
            year
            similar(first: 3) {
              title
              year
            }
          }
        }
      }
    }
  }
}
Cypher Params
{
  "movieTitle": "River Runs Through It, A",
  "movieActorsMoviesActorsName": "Tom Hanks",
  "movieActorsMoviesActorsMoviesFirst": 3,
  "movieActorsMoviesActorsMoviesOffset": 0,
  "movieActorsMoviesActorsMoviesSimilarFirst": 3
}
Cypher
MATCH (movie:Movie)
WHERE movie.title = $movieTitle
RETURN movie { .title, actors:[(movie)<-[:ACTED_IN]-(movieActors:Actor) |
       movieActors { .name, movies:[(movieActors)-[:ACTED_IN]->(movieActorsMovies:Movie) |
         movieActorsMovies { .title, actors:[(movieActorsMovies)<-[:ACTED_IN]-(movieActorsMoviesActors:Actor)
           WHERE movieActorsMoviesActors.name = $movieActorsMoviesActorsName |
             movieActorsMoviesActors { .name, movies:[(movieActorsMoviesActors)-[:ACTED_IN]->(movieActorsMoviesActorsMovies:Movie) |
               movieActorsMoviesActorsMovies { .title, .year, similar:[movieActorsMoviesActorsMoviesSimilar
                 IN apoc.cypher.runFirstColumnMany('WITH $this AS this, $first AS first, $offset AS offset MATCH (this)--(:Genre)--(o:Movie) RETURN o', { this:movieActorsMoviesActorsMovies, first:$movieActorsMoviesActorsMoviesFirst, offset:$movieActorsMoviesActorsMoviesOffset }) |
                   movieActorsMoviesActorsMoviesSimilar { .title, .year }][0..$movieActorsMoviesActorsMoviesSimilarFirst] }] }] }] }] } AS movie

Should merge an actor by the userId

GraphQL-Query
mutation {
  actor: mergeActor(userId: "1", name: "Andrea") {
    name
  }
}
Cypher Params
{
  "actorUserId": "1",
  "actorName": "Andrea"
}
Cypher
MERGE (actor:Actor { userId: $actorUserId })
SET actor += { name: $actorName }
WITH actor
RETURN actor { .name } AS actor

Should auto generate add relationship mutations for arrays

GraphQL-Query
mutation {
  add: addMovieGenres(movieId: 1, genres: ["Action", "Fantasy"]) {
    title
  }
}
Cypher Params
{
  "fromMovieId": 1,
  "toGenres": [
    "Action",
    "Fantasy"
  ]
}
Cypher
MATCH (from:Movie { movieId: $fromMovieId })
MATCH (to:Genre) WHERE to.name IN $toGenres
MERGE (from)-[:IN_GENRE]->(to)
WITH DISTINCT from AS add
RETURN add { .title } AS add

Should auto generate delete relationship mutations for arrays

GraphQL-Query
mutation {
  del: deleteMovieGenres(movieId: 1, genres: ["Action", "Fantasy"]) {
    title
  }
}
Cypher Params
{
  "fromMovieId": 1,
  "toGenres": [
    "Action",
    "Fantasy"
  ]
}
Cypher
MATCH (from:Movie { movieId: $fromMovieId })
MATCH (to:Genre) WHERE to.name IN $toGenres
MATCH (from)-[r:IN_GENRE]->(to)
DELETE r
WITH DISTINCT from AS del
RETURN del { .title } AS del

Should auto generate add relationship mutations

GraphQL-Query
mutation {
  add: addMoviePublishedBy(movieId: 1, publishedBy: "Company") {
    title
  }
}
Cypher Params
{
  "fromMovieId": 1,
  "toPublishedBy": "Company"
}
Cypher
MATCH (from:Movie { movieId: $fromMovieId })
MATCH (to:Publisher { name: $toPublishedBy })
MERGE (from)-[:PUBLISHED_BY]->(to)
WITH DISTINCT from AS add
RETURN add { .title } AS add

Should auto generate delete relationship mutations

GraphQL-Query
mutation {
  del: deleteMoviePublishedBy(movieId: 1, publishedBy: "Company") {
    title
  }
}
Cypher Params
{
  "fromMovieId": 1,
  "toPublishedBy": "Company"
}
Cypher
MATCH (from:Movie { movieId: $fromMovieId })
MATCH (to:Publisher { name: $toPublishedBy })
MATCH (from)-[r:PUBLISHED_BY]->(to)
DELETE r
WITH DISTINCT from AS del
RETURN del { .title } AS del

Should auto generate add recursive relationship mutations for arrays

GraphQL-Query
mutation {
  add: addUserKnows(userId: 1, knows: [10, 23]) {
    name
  }
}
Cypher Params
{
  "fromUserId": 1,
  "toKnows": [
    10,
    23
  ]
}
Cypher
MATCH (from:User { userId: $fromUserId })
MATCH (to:User) WHERE to.userId IN $toKnows
MERGE (from)-[:KNOWS]->(to)
WITH DISTINCT from AS add
RETURN add { .name } AS add

Order By

Descending, top level

GraphQL-Query
{
  Movie(year: 2010, orderBy:title_desc, first: 10) {
    title
  }
}
Cypher Params
{
  "movieYear": 2010,
  "movieFirst": 10
}
Cypher
MATCH (movie:Movie)
WHERE movie.year = $movieYear
RETURN movie { .title } AS movie
ORDER BY movie.title DESC
LIMIT $movieFirst

Descending, number

GraphQL-Query
{  Movie(orderBy:year_desc, first:10)  {  title }  }
Cypher Params
{
  "movieFirst": 10
}
Cypher
MATCH  (movie:Movie)
RETURN  movie  {  .title  } AS  movie
ORDER BY movie.year DESC LIMIT $movieFirst

Find all relations

GraphQL-Query
{ rated(_id:1){
    rating
 }
}
Cypher Params
{ "rated_id": 1}
Cypher
MATCH ()-[rated:RATED]->()
WHERE ID(rated) = toInteger($rated_id)
RETURN rated { .rating } AS rated

Create relation

GraphQL-Query
mutation {
  createRated(from_userId: "1", to_movieId: "2", rating: 5) {
    _id
 }
}
Cypher Params
{
  "fromFrom_userId": "1",
  "toTo_movieId": "2",
  "createRatedRating": 5
}
Cypher
MATCH (from:User { userId: $fromFrom_userId })
MATCH (to:Movie { movieId: $toTo_movieId })
CREATE (from)-[createRated:RATED { rating: $createRatedRating }]->(to)
WITH createRated
RETURN createRated { _id:ID(createRated) } AS createRated

Mutate relation

GraphQL-Query
mutation {
 updateRated(_id:1, rating: 5){
    rating
 }
}
Cypher Params
{
  "updateRated_id": 1,
  "updateRatedRating": 5
}
Cypher
MATCH ()-[updateRated:RATED]->()
WHERE ID(updateRated) = toInteger($updateRated_id)
SET updateRated = { rating: $updateRatedRating }
WITH updateRated
RETURN updateRated { .rating } AS updateRated

create object with multiple labels

GraphQL-Query
mutation {
 createUser(userId:1){
    userId,
    __typename
 }
}
Cypher Params
{
  "createUserUserId": 1,
  "createUserValidTypes": [
    "User"
  ]
}
Cypher
CREATE (createUser:User:Person { userId: $createUserUserId })
WITH createUser
RETURN createUser {
  .userId,
  __typename: head( [ label IN labels(createUser) WHERE label IN $createUserValidTypes ] )
} AS createUser

create relation

GraphQL-Query
mutation {
 addGenreMovies(name:"Action", movies: ["m1"]){
    name
 }
}
Cypher Params
{
  "fromName": "Action",
  "toMovies": [
    "m1"
  ]
}
Cypher
MATCH (from:Genre { name: $fromName })
MATCH (to:Movie) WHERE to.movieId IN $toMovies
MERGE (from)-[:IN_GENRE]->(to)
WITH DISTINCT from AS addGenreMovies
RETURN addGenreMovies { .name } AS addGenreMovies

Neo4j Data Types queryies

User born extraction

GraphQL-Query
query {
  User {
    born {
      formatted
      year
    }
  }
}
Cypher Params
{}
Cypher
MATCH (user:User)
RETURN user { born: { formatted: user.born, year: user.born.year } } AS user

User born query filter with multiple fields

GraphQL-Query
query {
  User {
    born(formatted: "2015-06-24T12:50:35.556000000+01:00", year: 2015) {
      year
    }
  }
}
Cypher Params
{"userBornFormatted": "2015-06-24T12:50:35.556000000+01:00", "userBornYear": 2015}
Cypher
MATCH (user:User)
WHERE user.born = datetime($userBornFormatted) AND user.born.year = $userBornYear
RETURN user { born: { year: user.born.year } } AS user

Merge Actor with born field formatted

GraphQL-Query
mutation {
  actor: mergeActor(userId: "1", name: "Andrea", born: { formatted: "2015-06-24T12:50:35.556000000+01:00" }) {
    name
  }
}
Cypher Params
{
  "actorUserId": "1",
  "actorName": "Andrea",
  "actorBorn": {
    "formatted": "2015-06-24T12:50:35.556000000+01:00"
  }
}
Cypher
MERGE (actor:Actor {userId:$actorUserId})
SET actor += { name: $actorName, born: datetime($actorBorn.formatted) }
WITH actor
RETURN actor { .name } AS actor

Create Actor with born field formatted

GraphQL-Query
mutation {
  actor: createActor(userId: "1", name: "Andrea", born: { formatted: "2015-06-24T12:50:35.556000000+01:00" }) {
    name
  }
}
Cypher Params
{
  "actorUserId": "1",
  "actorName": "Andrea",
  "actorBorn": {
    "formatted": "2015-06-24T12:50:35.556000000+01:00"
  }
}
Cypher
CREATE (actor:Actor:Person {
  userId: $actorUserId,
  name: $actorName,
  born: datetime($actorBorn.formatted)
})
WITH actor
RETURN actor { .name } AS actor

Merge Actor with born field object

GraphQL-Query
mutation {
  actor: mergeActor(userId: "1", name: "Andrea", born: { year: 2018
                                                         month: 11
                                                         day: 23
                                                         hour: 10
                                                         minute: 30
                                                         second: 1
                                                         millisecond: 2
                                                         microsecond: 3
                                                         nanosecond: 4
                                                         timezone: "America/Los_Angeles" }) {
    name
  }
}
Cypher Params
{"actorUserId": "1", "actorName": "Andrea", "actorBorn": { "year": 2018,
                                                           "month": 11,
                                                           "day": 23,
                                                           "hour": 10,
                                                           "minute": 30,
                                                           "second": 1,
                                                           "millisecond": 2,
                                                           "microsecond": 3,
                                                           "nanosecond": 4,
                                                           "timezone": "America/Los_Angeles" }}
Cypher
MERGE (actor:Actor {userId:$actorUserId})
SET actor += {
  name: $actorName,
  born: datetime($actorBorn)
}
WITH actor
RETURN actor { .name } AS actor

Create Actor with born field object

GraphQL-Query
mutation {
  actor: createActor(userId: "1", name: "Andrea", born: { year: 2018
                                                         month: 11
                                                         day: 23
                                                         hour: 10
                                                         minute: 30
                                                         second: 1
                                                         millisecond: 2
                                                         microsecond: 3
                                                         nanosecond: 4
                                                         timezone: "America/Los_Angeles" }) {
    name
    born {
      year
      month
    }
  }
}
Cypher Params
{"actorUserId": "1", "actorName": "Andrea", "actorBorn": { "year": 2018,
                                                           "month": 11,
                                                           "day": 23,
                                                           "hour": 10,
                                                           "minute": 30,
                                                           "second": 1,
                                                           "millisecond": 2,
                                                           "microsecond": 3,
                                                           "nanosecond": 4,
                                                           "timezone": "America/Los_Angeles" }}
Cypher
CREATE (actor:Actor:Person {
  userId: $actorUserId,
  name: $actorName,
  born: datetime($actorBorn)
})
WITH actor
RETURN actor { .name,born: { year: actor.born.year, month: actor.born.month } } AS actor