working comments with cache updates

This commit is contained in:
keyan 2021-04-17 13:15:18 -05:00
parent 95d6d789fa
commit 6792d1d5ff
10 changed files with 200 additions and 30 deletions

15
.vscode/launch.json vendored Normal file
View File

@ -0,0 +1,15 @@
{
"version": "0.2.0",
"configurations": [
{
"type": "pwa-node",
"request": "attach",
"name": "Launch Program",
"skipFiles": [
"<node_internals>/**"
],
"port": 9229,
"outputCapture": "std"
}
]
}

View File

@ -24,7 +24,75 @@ const createItem = async (parent, { title, text, url, parentId }, { me, models }
}
}
return await models.item.create({ data })
const item = await models.item.create({ data })
item.comments = []
console.log(item)
return item
}
// function nestComments (flat, parentId) {
// const result = []
// for (let i = 0; i < flat.length; i++) {
// if (Number(flat[i].parentId) === Number(parentId)) {
// result.push(flat[i])
// } else if (result.length > 0) {
// // this comment is a child of the last one pushed
// const last = result[result.length - 1]
// last.comments = nestComments(flat.slice(i), last.id)
// // we consumed this many comments
// i += last.comments.length
// }
// }
// return result
// }
// function nestComments (flat, parentId) {
// const result = []
// let last
// for (let i = 0; i < flat.length; i++) {
// // initialize all comments
// if (!flat[i].comments) flat[i].comments = []
// if (Number(flat[i].parentId) === Number(parentId)) {
// result.push(flat[i])
// last = flat[i]
// } else if (last && Number(last.id) === flat[i].parentId) {
// const nested = nestComments(flat.slice(i), last.id)
// if (nested.length > 0) {
// last.comments.push(...nested)
// i += nested.length - 1
// }
// }
// }
// return result
// }
function nestComments (flat, parentId) {
const result = []
let added = 0
for (let i = 0; i < flat.length;) {
if (!flat[i].comments) flat[i].comments = []
if (Number(flat[i].parentId) === Number(parentId)) {
result.push(flat[i])
added++
i++
} else if (result.length > 0) {
const item = result[result.length - 1]
const [nested, newAdded] = nestComments(flat.slice(i), item.id)
if (newAdded === 0) {
break
}
item.comments.push(...nested)
i += newAdded
added += newAdded
} else {
break
}
}
return [result, added]
}
export default {
@ -44,7 +112,7 @@ export default {
WHERE id = ${id}`)
return res.length ? res[0] : null
},
comments: async (parent, { parentId }, { models }) => {
flatcomments: async (parent, { parentId }, { models }) => {
return await models.$queryRaw(`
SELECT id, "created_at" as "createdAt", text, "parentId",
"userId", nlevel(path)-1 AS depth, ltree2text("path") AS "path"
@ -52,6 +120,15 @@ export default {
WHERE path <@ (SELECT path FROM "Item" where id = ${parentId}) AND id != ${parentId}
ORDER BY "path"`)
},
comments: async (parent, { parentId }, { models }) => {
const flat = await models.$queryRaw(`
SELECT id, "created_at" as "createdAt", text, "parentId",
"userId", nlevel(path)-1 AS depth, ltree2text("path") AS "path"
FROM "Item"
WHERE path <@ (SELECT path FROM "Item" where id = ${parentId}) AND id != ${parentId}
ORDER BY "path"`)
return nestComments(flat, parentId)[0]
},
root: async (parent, { id }, { models }) => {
const res = await models.$queryRaw(`
SELECT id, title

View File

@ -5,6 +5,7 @@ export default gql`
items: [Item!]!
item(id: ID!): Item
comments(parentId: ID!): [Item!]!
flatcomments(parentId: ID!): [Item!]!
root(id: ID!): Item
}
@ -25,5 +26,6 @@ export default gql`
depth: Int!
sats: Int!
ncomments: Int!
comments: [Item!]!
}
`

View File

@ -95,13 +95,15 @@ export default function Comment ({ item, children, replyOpen, includeParent }) {
>
{reply ? 'cancel' : 'reply'}
</div>
{reply && <Reply parentId={item.id} />}
{reply && <Reply item={item} />}
{children}
{item.comments
? item.comments.map((item) => (
<Comment key={item.id} item={item} />
))
: null}
<div className={styles.comments}>
{item.comments
? item.comments.map((item) => (
<Comment key={item.id} item={item} />
))
: null}
</div>
</div>
</>
)

View File

@ -18,4 +18,9 @@
.children {
margin-top: .4rem;
}
.comments {
margin-left: 16px;
margin-top: .5rem;
}

View File

@ -1,19 +1,15 @@
import { useQuery, gql } from '@apollo/client'
import Comment from './comment'
import { COMMENTS } from '../fragments'
export default function Comments ({ parentId, baseDepth }) {
export default function Comments ({ parentId }) {
const { data } = useQuery(
gql`{
gql`
${COMMENTS}
{
comments(parentId: ${parentId}) {
id
createdAt
text
user {
name
}
depth
sats
ncomments
...CommentsRecursive
}
}`
)
@ -23,10 +19,7 @@ export default function Comments ({ parentId, baseDepth }) {
return (
<div className='mt-5'>
{data.comments.map(item => (
<div
key={item.id} className='mt-2'
style={{ marginLeft: `${42 * (item.depth - baseDepth - 1)}px` }}
>
<div key={item.id} className='mt-2'>
<Comment item={item} />
</div>
))}

View File

@ -2,19 +2,41 @@ import { Form, Input, SubmitButton } from '../components/form'
import * as Yup from 'yup'
import { gql, useMutation } from '@apollo/client'
import styles from './reply.module.css'
import { COMMENTS } from '../fragments'
export const CommentSchema = Yup.object({
text: Yup.string().required('required').trim()
})
export default function Reply ({ parentId }) {
export default function Reply ({ item }) {
const parentId = item.id
const [createComment] = useMutation(
gql`
${COMMENTS}
mutation createComment($text: String!, $parentId: ID!) {
createComment(text: $text, parentId: $parentId) {
id
...CommentFields
comments {
...CommentsRecursive
}
}
}`
}`, {
update (cache, { data: { createComment } }) {
cache.modify({
id: `Item:${item.id}`,
fields: {
comments (existingCommentRefs = [], { readField }) {
const newCommentRef = cache.writeFragment({
data: createComment,
fragment: COMMENTS,
fragmentName: 'CommentsRecursive'
})
return [newCommentRef, ...existingCommentRefs]
}
}
})
}
}
)
return (

55
fragments/index.js Normal file
View File

@ -0,0 +1,55 @@
import { gql } from '@apollo/client'
export const COMMENT_FIELDS = gql`
fragment CommentFields on Item {
id
parentId
createdAt
text
user {
name
}
sats
ncomments
}
`
export const COMMENTS = gql`
${COMMENT_FIELDS}
fragment CommentsRecursive on Item {
...CommentFields
comments {
...CommentFields
comments {
...CommentFields
comments {
...CommentFields
comments {
...CommentFields
comments {
...CommentFields
comments {
...CommentFields
comments {
...CommentFields
comments {
...CommentFields
comments {
...CommentFields
comments {
...CommentFields
comments {
...CommentFields
}
}
}
}
}
}
}
}
}
}
}
}`

View File

@ -43,4 +43,4 @@
"prisma": "2.19.0",
"standard": "^16.0.3"
}
}
}

View File

@ -21,7 +21,6 @@ export async function getServerSideProps ({ params }) {
user {
name
}
depth
sats
ncomments
}
@ -50,11 +49,11 @@ export default function FullItem ({ item }) {
<>
<Item item={item}>
{item.text && <Text>{item.text}</Text>}
<Reply parentId={item.id} />
<Reply item={item} />
</Item>
</>
)}
<Comments parentId={item.id} baseDepth={item.depth} />
<Comments parentId={item.id} />
</Layout>
)
}