Skip to content
This repository has been archived by the owner on May 26, 2022. It is now read-only.

Commit

Permalink
Migrate to official Neo4j GraphQL Library
Browse files Browse the repository at this point in the history
  • Loading branch information
johnymontana committed Apr 27, 2021
1 parent 12c6e43 commit 903484f
Show file tree
Hide file tree
Showing 19 changed files with 2,530 additions and 3,285 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ The root directory contains some global configuration and scripts:

![](img/graphql-playground.png)

This directory contains the GraphQL API application using Apollo Server and neo4j-graphql.js.
This directory contains the GraphQL API application using Apollo Server and the Neo4j GraphQL Library.

- Change environment variable settings in `.env`:

Expand Down
4,342 changes: 1,628 additions & 2,714 deletions api/package-lock.json

Large diffs are not rendered by default.

4 changes: 2 additions & 2 deletions api/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
"main": "src/index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"start:dev": "cross-env DEBUG=neo4j-graphql-js ./node_modules/.bin/nodemon --watch src --ext js,graphql --exec babel-node src/index.js",
"start:dev": "./node_modules/.bin/nodemon --watch src --ext js,graphql --exec babel-node src/index.js",
"build": "babel src --out-dir build && shx cp .env build 2>/dev/null || : && shx cp src/schema.graphql build",
"now-build": "babel src --out-dir build && shx cp src/schema.graphql build",
"start": "npm run build && node build/index.js",
Expand All @@ -20,7 +20,7 @@
"csv-parse": "^4.10.1",
"dotenv": "^7.0.0",
"neo4j-driver": "^4.2.2",
"neo4j-graphql-js": "^2.19.2",
"@neo4j/graphql": "^1.0.0-beta.2",
"node-fetch": "^2.6.0",
"react": "^16.13.1"
},
Expand Down
11 changes: 5 additions & 6 deletions api/src/functions/graphql/graphql.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
// as a lambda function

const { ApolloServer } = require('apollo-server-lambda')
const { makeAugmentedSchema } = require('neo4j-graphql-js')
import { Neo4jGraphQL } from '@neo4j/graphql'
const neo4j = require('neo4j-driver')

// This module is copied during the build step
Expand All @@ -14,14 +14,13 @@ const driver = neo4j.driver(
neo4j.auth.basic(
process.env.NEO4J_USER || 'neo4j',
process.env.NEO4J_PASSWORD || 'neo4j'
),
{
encrypted: process.env.NEO4J_ENCRYPTED ? 'ENCRYPTION_ON' : 'ENCRYPTION_OFF',
}
)
)

const neoSchema = new Neo4jGraphQL({ typeDefs, driver })

const server = new ApolloServer({
schema: makeAugmentedSchema({ typeDefs }),
schema: neoSchema.schema,
context: { driver, neo4jDatabase: process.env.NEO4J_DATABASE },
})

Expand Down
1,120 changes: 734 additions & 386 deletions api/src/functions/graphql/package-lock.json

Large diffs are not rendered by default.

3 changes: 2 additions & 1 deletion api/src/functions/graphql/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,8 @@
},
"dependencies": {
"apollo-server-lambda": "^2.14.2",
"neo4j-graphql-js": "^2.14.2",
"@neo4j/graphql": "^1.0.0-beta.2",
"graphql": "^15.5.0",
"neo4j-driver": "^4.0.2"
}
}
1 change: 0 additions & 1 deletion api/src/graphql-schema.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import { neo4jgraphql } from 'neo4j-graphql-js'
import fs from 'fs'
import path from 'path'

Expand Down
38 changes: 15 additions & 23 deletions api/src/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,34 +2,14 @@ import { typeDefs } from './graphql-schema'
import { ApolloServer } from 'apollo-server-express'
import express from 'express'
import neo4j from 'neo4j-driver'
import { makeAugmentedSchema } from 'neo4j-graphql-js'
import { Neo4jGraphQL } from '@neo4j/graphql'
import dotenv from 'dotenv'

// set environment variables from .env
dotenv.config()

const app = express()

/*
* Create an executable GraphQL schema object from GraphQL type definitions
* including autogenerated queries and mutations.
* Optionally a config object can be included to specify which types to include
* in generated queries and/or mutations. Read more in the docs:
* https://grandstack.io/docs/neo4j-graphql-js-api.html#makeaugmentedschemaoptions-graphqlschema
*/

const schema = makeAugmentedSchema({
typeDefs,
config: {
query: {
exclude: ['RatingCount'],
},
mutation: {
exclude: ['RatingCount'],
},
},
})

/*
* Create a Neo4j driver instance to connect to the database
* using credentials specified as environment variables
Expand All @@ -43,15 +23,27 @@ const driver = neo4j.driver(
)
)

/*
* Create an executable GraphQL schema object from GraphQL type definitions
* including autogenerated queries and mutations.
* Read more in the docs:
* https://neo4j.com/docs/graphql-manual/current/
*/

const neoSchema = new Neo4jGraphQL({ typeDefs, driver })

/*
* Create a new ApolloServer instance, serving the GraphQL schema
* created using makeAugmentedSchema above and injecting the Neo4j driver
* instance into the context object so it is available in the
* generated resolvers to connect to the database.
*/
const server = new ApolloServer({
context: { driver, neo4jDatabase: process.env.NEO4J_DATABASE },
schema: schema,
context: {
driver,
driverConfig: { database: process.env.NEO4J_DATABASE || 'neo4j' },
},
schema: neoSchema.schema,
introspection: true,
playground: true,
})
Expand Down
47 changes: 39 additions & 8 deletions api/src/schema.graphql
Original file line number Diff line number Diff line change
@@ -1,7 +1,11 @@
scalar Point
scalar DateTime
scalar PointInput

type User {
userId: ID!
name: String
reviews: [Review] @relation(name: "WROTE", direction: OUT)
reviews: [Review] @relationship(type: "WROTE", direction: OUT)
avgStars: Float
@cypher(
statement: "MATCH (this)-[:WROTE]->(r:Review) RETURN toFloat(avg(r.stars))"
Expand All @@ -25,25 +29,25 @@ type Business {
@cypher(
statement: "MATCH (this)<-[:REVIEWS]-(r:Review) RETURN coalesce(avg(r.stars),0.0)"
)
reviews: [Review] @relation(name: "REVIEWS", direction: IN)
categories: [Category] @relation(name: "IN_CATEGORY", direction: OUT)
reviews: [Review] @relationship(type: "REVIEWS", direction: IN)
categories: [Category] @relationship(type: "IN_CATEGORY", direction: OUT)
}

type Review {
reviewId: ID!
stars: Float
text: String
date: Date
business: Business @relation(name: "REVIEWS", direction: OUT)
user: User @relation(name: "WROTE", direction: IN)
date: DateTime
business: Business @relationship(type: "REVIEWS", direction: OUT)
user: User @relationship(type: "WROTE", direction: IN)
}

type Category {
name: ID!
businesses: [Business] @relation(name: "IN_CATEGORY", direction: IN)
businesses: [Business] @relationship(type: "IN_CATEGORY", direction: IN)
}

type RatingCount {
type RatingCount @exclude {
stars: Float!
count: Int!
}
Expand All @@ -53,6 +57,33 @@ type Mutation {
@cypher(
statement: "MATCH (b:Business {businessId: $businessId}) UNWIND $categories AS cat MERGE (c:Category {name: cat}) MERGE (b)-[:IN_CATEGORY]->(c) RETURN b"
)
mergeUser(name: String!, userId: ID!): User
@cypher(
statement: """
MERGE (u:User {userId: $userId})
ON CREATE SET u.name = $name
"""
)
mergeBusiness(
businessId: ID!
name: String!
address: String!
city: String!
state: String!
latitude: Float!
longitude: Float!
): Business
@cypher(
statement: """
MERGE (b:Business {businessId: $businessId})
ON CREATE SET b.name = $name,
b.address = $address,
b.city = $city,
b.state = $state,
b.location = Point({latitude: $latitude, longitude: $longitude})
RETURN b
"""
)
}

type Query {
Expand Down
64 changes: 28 additions & 36 deletions api/src/seed/seed-mutations.js
Original file line number Diff line number Diff line change
Expand Up @@ -32,65 +32,57 @@ const generateMutations = (records) => {
mutation: gql`
mutation mergeReviews(
$userId: ID!
$userName: String
$userName: String!
$businessId: ID!
$businessName: String
$businessCity: String
$businessState: String
$businessAddress: String
$latitude: Float
$longitude: Float
$businessName: String!
$businessCity: String!
$businessState: String!
$businessAddress: String!
$latitude: Float!
$longitude: Float!
$reviewId: ID!
$reviewText: String
$year: Int
$month: Int
$day: Int
$reviewDate: Date
$reviewStars: Float
$categories: [String!]!
) {
user: MergeUser(userId: $userId, name: $userName) {
user: mergeUser(userId: $userId, name: $userName) {
userId
}
business: MergeBusiness(
business: mergeBusiness(
businessId: $businessId
name: $businessName
address: $businessAddress
city: $businessCity
state: $businessState
location: { latitude: $latitude, longitude: $longitude }
latitude: $latitude
longitude: $longitude
) {
businessId
}
review: MergeReview(
reviewId: $reviewId
text: $reviewText
date: { year: $year, month: $month, day: $day }
stars: $reviewStars
businessCategories: mergeBusinessCategory(
categories: $categories
businessId: $businessId
) {
reviewId
businessId
}
reviewUser: MergeReviewUser(
from: { userId: $userId }
to: { reviewId: $reviewId }
) {
from {
userId
reviews: createReviews(
input: {
reviewId: $reviewId
stars: $reviewStars
text: $reviewText
date: $reviewDate
business: { connect: { where: { businessId: $businessId } } }
user: { connect: { where: { userId: $userId } } }
}
}
reviewBusiness: MergeReviewBusiness(
from: { reviewId: $reviewId }
to: { businessId: $businessId }
) {
from {
reviews {
reviewId
date
}
}
businessCategories: mergeBusinessCategory(
categories: $categories
businessId: $businessId
) {
businessId
}
}
`,
variables: rec,
Expand Down
Binary file modified img/graphql-playground.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion neo4j/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

You need a Neo4j instance, e.g. a [Neo4j Sandbox](http://neo4j.com/sandbox), a local instance via [Neo4j Desktop](https://neo4j.com/download), [Docker](http://hub.docker.com/_/neo4j) or a [Neo4j instance on AWS, Azure or GCP](http://neo4j.com/developer/guide-cloud-deployment) or [Neo4j Cloud](http://neo4j.com/cloud)

For schemas using the `@cypher` directive (as in this repo) via [`neo4j-graphql-js`](https://github.com/neo4j-graphql/neo4j-graphql-js), you need to have the [APOC library](https://github.com/neo4j-contrib/neo4j-apoc-procedures) installed, which should be automatic in Sandbox, Cloud and is a single click install in Neo4j Desktop. If when using the Sandbox / cloud you encounter an issue where an error similar to `Can not be converted to long: org.neo4j.kernel.impl.core.NodeProxy, Location: [object Object], Path: users` appears in the console when running the React app, try installing and using Neo4j locally instead.
For schemas using the `@cypher` directive (as in this repo) via [`@neo4j/graphql`](https://neo4j.com/docs/graphql-manual/current/type-definitions/cypher/), you need to have the [APOC library](https://github.com/neo4j-contrib/neo4j-apoc-procedures) installed, which should be automatic in Sandbox, Cloud and is a single click install in Neo4j Desktop. If when using the Sandbox / cloud you encounter an issue where an error similar to `Can not be converted to long: org.neo4j.kernel.impl.core.NodeProxy, Location: [object Object], Path: users` appears in the console when running the React app, try installing and using Neo4j locally instead.

#### Sandbox setup

Expand Down
1 change: 1 addition & 0 deletions web-react-ts/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
"@apollo/client": "^3.1.2",
"@material-ui/core": "^4.11.0",
"@material-ui/icons": "^4.9.1",
"moment": "^2.29.1",
"react": "^16.13.1",
"react-dom": "^16.13.1",
"react-router-dom": "^5.2.0",
Expand Down
13 changes: 6 additions & 7 deletions web-react-ts/src/components/RecentReviews.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,19 @@ import TableCell from '@material-ui/core/TableCell'
import TableHead from '@material-ui/core/TableHead'
import TableRow from '@material-ui/core/TableRow'
import Title from './Title'
import { useQuery, gql } from '@apollo/client';
import { useQuery, gql } from '@apollo/client'
import moment from 'moment'

const GET_RECENT_REVIEWS_QUERY = gql`
{
Review(first: 10, orderBy: date_desc) {
reviews(options: { limit: 10, sort: { date: DESC } }) {
user {
name
}
business {
name
}
date {
formatted
}
date
text
stars
}
Expand All @@ -44,9 +43,9 @@ export default function RecentReviews() {
</TableRow>
</TableHead>
<TableBody>
{data.Review.map((row: any) => (
{data.reviews.map((row: any) => (
<TableRow key={row.id}>
<TableCell>{row.date.formatted}</TableCell>
<TableCell>{moment(row.date).format('MMMM Do YYYY')}</TableCell>
<TableCell>{row.business.name}</TableCell>
<TableCell>{row.user.name}</TableCell>
<TableCell>{row.text}</TableCell>
Expand Down
Loading

0 comments on commit 903484f

Please sign in to comment.