Below is what I have in graphql-schema.js
:
import { neo4jgraphql } from "neo4j-graphql-js";
export const typeDefs = `
type User {
id: ID!
name: String
friends(first: Int = 10, offset: Int = 0): [User] @relation(name: "FRIENDS", direction: "BOTH")
reviews(first: Int = 10, offset: Int = 0): [Review] @relation(name: "WROTE", direction: "OUT")
avgStars: Float @cypher(statement: "MATCH (this)-[:WROTE]->(r:Review) RETURN toFloat(avg(r.stars))")
numReviews: Int @cypher(statement: "MATCH (this)-[:WROTE]->(r:Review) RETURN COUNT(r)")
totalStars: Int @cypher(statement: "MATCH (this)-[:WROTE]->(r:Review) RETURN SUM(r.stars)")
}
type Business {
id: ID!
name: String
address: String
city: String
state: String
reviews(first: Int = 10, offset: Int = 0): [Review] @relation(name: "REVIEWS", direction: "IN")
categories(first: Int = 10, offset: Int =0): [Category] @relation(name: "IN_CATEGORY", direction: "OUT")
numReviews: Int @cypher(statement: "MATCH (this)<-[:REVIEWS]-(r:Review) RETURN count(r)")
avgStars: Float @cypher(statement: "MATCH (this)<-[:REVIEWS]-(r:Review) WHERE r.stars IS NOT NULL RETURN toFloat(avg(r.stars))")
category: String @cypher(statement: "MATCH (this)-[:IN_CATEGORY]->(r:Category) RETURN r.name")
}
type Review {
id: ID!
stars: Int
text: String
business: Business @relation(name: "REVIEWS", direction: "OUT")
user: User @relation(name: "WROTE", direction: "IN")
business_name: String @cypher(statement: "MATCH (this)-[:REVIEWS]->(r:Business) RETURN r.name")
user_name: String @cypher(statement: "MATCH (this)<-[:WROTE]-(r:User) RETURN r.name")
}
type Category {
name: ID!
businesses(first: Int = 10, offset: Int = 0): [Business] @relation(name: "IN_CATEGORY", direction: "IN")
}
type Ring {
id: ID!
name: String
divisions(first: Int = 10, offset: Int = 0): [Division] @relation(name: "OCCURS_IN", direction: "IN")
}
type Division {
id: ID!
name: String
div: String
sex: String
rank: String
ageLow: Int
ageHigh: Int
status: String
}
type Person {
id: ID!
name: String
sex: String
age: Int
rank: String
}
type Query {
users(id: ID, name: String, first: Int = 10, offset: Int = 0): [User]
businesses(id: ID, name: String, first: Int = 10, offset: Int = 0): [Business]
reviews(id: ID, stars: Int, first: Int = 10, offset: Int = 0): [Review]
category(name: ID!): Category
usersBySubstring(substring: String, first: Int = 10, offset: Int = 0): [User] @cypher(statement: "MATCH (u:User) WHERE u.name CONTAINS $substring RETURN u")
divisions(id: ID, name: String, div: String, sex: String, rank: String, ageLow: Int, ageHigh: Int, status: String, first: Int, offset: Int): [Division]
rings(id: ID, name: String, first: Int = 10, offset: Int = 0): [Ring]
competitors(name: String): [Person]
judges(name: String): [Person] @cypher(statement: "MATCH (p:Person) WHERE p.age >=18 AND p.rank CONTAINS 'Black Belt' RETURN p")
}
`;
export const resolvers = {
Query: {
users: neo4jgraphql,
businesses: neo4jgraphql,
reviews: neo4jgraphql,
category: neo4jgraphql,
usersBySubstring: neo4jgraphql,
divisions: neo4jgraphql,
rings: neo4jgraphql,
competitors: neo4jgraphql,
judges: neo4jgraphql
}
};
Following the same general format as UserList.js
, 'BusinessList.js, etc., I created
RingList.js, in which I added a material card that expands to show a table. The card title is linked to the Query
ringsin which I would like to query all
divisionsassociated with that ring. It is the "nested or subquery"
divisionsthat I cannot seem to get working correctly. I have tried multiple things. As it is shown here now the
and
material components are associated/mapped with the
ringquery to pull each ring name. Then in
I have to tried to map to the
divisions` query.
import React from "react";
import { Query } from "react-apollo";
import gql from "graphql-tag";
import "./RingList.css";
import { withStyles } from "@material-ui/core/styles";
import Table from "@material-ui/core/Table";
import TableBody from "@material-ui/core/TableBody";
import TableCell from "@material-ui/core/TableCell";
import TableHead from "@material-ui/core/TableHead";
import TableRow from "@material-ui/core/TableRow";
import Tooltip from "@material-ui/core/Tooltip";
import Paper from "@material-ui/core/Paper";
import { TableSortLabel } from "@material-ui/core";
import classnames from 'classnames';
import Card from "@material-ui/core/Card";
import CardHeader from '@material-ui/core/CardHeader';
import CardContent from '@material-ui/core/CardContent';
import CardActions from "@material-ui/core/CardActions";
import IconButton from "@material-ui/core/IconButton";
import ExpandMoreIcon from '@material-ui/icons/ExpandMore';
import Collapse from '@material-ui/core/Collapse';
const styles = theme => ({
root: {
// maxWidth: 700,
marginTop: theme.spacing.unit * 3,
overflowX: "auto",
margin: "auto"
},
table: {
minWidth: 700
},
card: {
maxWidth: "auto",
},
expand: {
transform: 'rotate(0deg)',
transition: theme.transitions.create('transform', {
duration: theme.transitions.duration.shortest,
}),
marginLeft: 'auto',
[theme.breakpoints.up('sm')]: {
marginRight: -8,
},
},
expandOpen: {
transform: 'rotate(180deg)',
},
});
function getSorting(order, orderBy) {
return order === "desc"
? (a, b) => (b[orderBy] < a[orderBy] ? -1 : 1)
: (a, b) => (a[orderBy] < b[orderBy] ? -1 : 1);
}
class RingList extends React.Component {
constructor(props) {
super(props);
this.state = {
order: "asc",
orderBy: "name"
};
}
state = { expanded: false };
handleExpandClick = () => {
this.setState(state => ({ expanded: !state.expanded }));
};
handleSortRequest = property => {
const orderBy = property;
let order = "desc";
if (this.state.orderBy === property && this.state.order === "desc") {
order = "asc";
}
this.setState({ order, orderBy });
};
render() {
const { order, orderBy } = this.state;
return (
<Query
query={gql`
{
rings(first: 10, offset: 0) {
id
name
divisions(first: 10, offset: 0) {
id
name
div
sex
rank
ageLow
ageHigh
status
}
}
}
`}
>
{({ loading, error, data }) => {
if (loading) return <p>Loading...</p>;
if (error) return <p>Error</p>;
return (
<div >
{data.rings
.slice()
.map(n => {
return(
<Paper key={n.id} className={this.props.classes.root}>
{/*<Card key={n.name} className={this.props.classes.card}>*/}
<Card className={this.props.classes.card}>
<CardHeader
title={n.name}
/>
<CardContent>
{n.name}
</CardContent>
<CardActions>
<IconButton
className={classnames(this.props.classes.expand, {
[this.props.classes.expandOpen]: this.state.expanded,
})}
onClick={this.handleExpandClick}
aria-expanded={this.state.expanded}
aria-label="Show more"
>
<ExpandMoreIcon />
</IconButton>
</CardActions>
<Collapse in={this.state.expanded} timeout="auto" unmountOnExit>
<CardContent>
<Table className={this.props.classes.table}>
<TableHead>
<TableRow>
<TableCell
key="name"
sortDirection={orderBy === "name" ? order : false}
>
<Tooltip
title="Sort"
placement="bottom-start"
enterDelay={300}
>
<TableSortLabel
active={orderBy === "name"}
direction={order}
onClick={() => this.handleSortRequest("name")}
>
Name
</TableSortLabel>
</Tooltip>
</TableCell>
<TableCell
key="div"
sortDirection={orderBy === "div" ? order : false}
>
<Tooltip
title="Sort"
placement="bottom-end"
enterDelay={300}
>
<TableSortLabel
active={orderBy === "div"}
direction={order}
onClick={() => this.handleSortRequest("div")}
>
Div
</TableSortLabel>
</Tooltip>
</TableCell>
<TableCell
key="sex"
sortDirection={orderBy === "sex" ? order : false}
>
<Tooltip
title="Sort"
placement="bottom-start"
enterDelay={300}
>
<TableSortLabel
active={orderBy === "sex"}
direction={order}
onClick={() => this.handleSortRequest("sex")}
>
Sex
</TableSortLabel>
</Tooltip>
</TableCell>
<TableCell
key="rank"
sortDirection={orderBy === "rank" ? order : false}
>
<Tooltip
title="Sort"
placement="bottom-start"
enterDelay={300}
>
<TableSortLabel
active={orderBy === "rank"}
direction={order}
onClick={() => this.handleSortRequest("rank")}
>
Rank
</TableSortLabel>
</Tooltip>
</TableCell>
<TableCell
key="ageLow"
sortDirection={orderBy === "ageLow" ? order : false}
numeric
>
<Tooltip
title="Sort"
placement="bottom-start"
enterDelay={300}
>
<TableSortLabel
active={orderBy === "ageLow"}
direction={order}
onClick={() => this.handleSortRequest("ageLow")}
>
ageLow
</TableSortLabel>
</Tooltip>
</TableCell>
<TableCell
key="ageHigh"
sortDirection={orderBy === "ageHigh" ? order : false}
numeric
>
<Tooltip
title="Sort"
placement="bottom-start"
enterDelay={300}
>
<TableSortLabel
active={orderBy === "ageHigh"}
direction={order}
onClick={() => this.handleSortRequest("ageHigh")}
>
ageHigh
</TableSortLabel>
</Tooltip>
</TableCell>
<TableCell
key="status"
sortDirection={orderBy === "status" ? order : false}
numeric
>
<Tooltip
title="Sort"
placement="bottom-start"
enterDelay={300}
>
<TableSortLabel
active={orderBy === "status"}
direction={order}
onClick={() => this.handleSortRequest("status")}
>
Status
</TableSortLabel>
</Tooltip>
</TableCell>
</TableRow>
</TableHead>
<TableBody>
{data.rings
.slice()
.sort(getSorting(order, orderBy))
.map(m => {
return (
//<TableRow key={n.id}>
//<TableRow key={n.divisions.name}>
<TableRow key={m.divisions.id}>
<TableCell component="th" scope="row">
{m.divisions.name}
</TableCell>
<TableCell>{m.divisions.div}</TableCell>
<TableCell>{m.divisions.sex}</TableCell>
<TableCell>{m.divisions.rank}</TableCell>
<TableCell numeric>{m.divisions.ageLow}</TableCell>
<TableCell numeric>{m.divisions.ageHigh}</TableCell>
<TableCell>{m.divisions.status}</TableCell>
</TableRow>
);
})}
</TableBody>
</Table>
</CardContent>
</Collapse>
</Card>
</Paper>
);
})}
</div>
);
}}
</Query>
);
}
}
export default withStyles(styles)(RingList);