working comments with cache updates
This commit is contained in:
parent
95d6d789fa
commit
6792d1d5ff
15
.vscode/launch.json
vendored
Normal file
15
.vscode/launch.json
vendored
Normal 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"
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
@ -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 {
|
export default {
|
||||||
@ -44,7 +112,7 @@ export default {
|
|||||||
WHERE id = ${id}`)
|
WHERE id = ${id}`)
|
||||||
return res.length ? res[0] : null
|
return res.length ? res[0] : null
|
||||||
},
|
},
|
||||||
comments: async (parent, { parentId }, { models }) => {
|
flatcomments: async (parent, { parentId }, { models }) => {
|
||||||
return await models.$queryRaw(`
|
return await models.$queryRaw(`
|
||||||
SELECT id, "created_at" as "createdAt", text, "parentId",
|
SELECT id, "created_at" as "createdAt", text, "parentId",
|
||||||
"userId", nlevel(path)-1 AS depth, ltree2text("path") AS "path"
|
"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}
|
WHERE path <@ (SELECT path FROM "Item" where id = ${parentId}) AND id != ${parentId}
|
||||||
ORDER BY "path"`)
|
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 }) => {
|
root: async (parent, { id }, { models }) => {
|
||||||
const res = await models.$queryRaw(`
|
const res = await models.$queryRaw(`
|
||||||
SELECT id, title
|
SELECT id, title
|
||||||
|
@ -5,6 +5,7 @@ export default gql`
|
|||||||
items: [Item!]!
|
items: [Item!]!
|
||||||
item(id: ID!): Item
|
item(id: ID!): Item
|
||||||
comments(parentId: ID!): [Item!]!
|
comments(parentId: ID!): [Item!]!
|
||||||
|
flatcomments(parentId: ID!): [Item!]!
|
||||||
root(id: ID!): Item
|
root(id: ID!): Item
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -25,5 +26,6 @@ export default gql`
|
|||||||
depth: Int!
|
depth: Int!
|
||||||
sats: Int!
|
sats: Int!
|
||||||
ncomments: Int!
|
ncomments: Int!
|
||||||
|
comments: [Item!]!
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
|
@ -95,13 +95,15 @@ export default function Comment ({ item, children, replyOpen, includeParent }) {
|
|||||||
>
|
>
|
||||||
{reply ? 'cancel' : 'reply'}
|
{reply ? 'cancel' : 'reply'}
|
||||||
</div>
|
</div>
|
||||||
{reply && <Reply parentId={item.id} />}
|
{reply && <Reply item={item} />}
|
||||||
{children}
|
{children}
|
||||||
{item.comments
|
<div className={styles.comments}>
|
||||||
? item.comments.map((item) => (
|
{item.comments
|
||||||
<Comment key={item.id} item={item} />
|
? item.comments.map((item) => (
|
||||||
))
|
<Comment key={item.id} item={item} />
|
||||||
: null}
|
))
|
||||||
|
: null}
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
@ -19,3 +19,8 @@
|
|||||||
.children {
|
.children {
|
||||||
margin-top: .4rem;
|
margin-top: .4rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.comments {
|
||||||
|
margin-left: 16px;
|
||||||
|
margin-top: .5rem;
|
||||||
|
}
|
@ -1,19 +1,15 @@
|
|||||||
import { useQuery, gql } from '@apollo/client'
|
import { useQuery, gql } from '@apollo/client'
|
||||||
import Comment from './comment'
|
import Comment from './comment'
|
||||||
|
import { COMMENTS } from '../fragments'
|
||||||
|
|
||||||
export default function Comments ({ parentId, baseDepth }) {
|
export default function Comments ({ parentId }) {
|
||||||
const { data } = useQuery(
|
const { data } = useQuery(
|
||||||
gql`{
|
gql`
|
||||||
|
${COMMENTS}
|
||||||
|
|
||||||
|
{
|
||||||
comments(parentId: ${parentId}) {
|
comments(parentId: ${parentId}) {
|
||||||
id
|
...CommentsRecursive
|
||||||
createdAt
|
|
||||||
text
|
|
||||||
user {
|
|
||||||
name
|
|
||||||
}
|
|
||||||
depth
|
|
||||||
sats
|
|
||||||
ncomments
|
|
||||||
}
|
}
|
||||||
}`
|
}`
|
||||||
)
|
)
|
||||||
@ -23,10 +19,7 @@ export default function Comments ({ parentId, baseDepth }) {
|
|||||||
return (
|
return (
|
||||||
<div className='mt-5'>
|
<div className='mt-5'>
|
||||||
{data.comments.map(item => (
|
{data.comments.map(item => (
|
||||||
<div
|
<div key={item.id} className='mt-2'>
|
||||||
key={item.id} className='mt-2'
|
|
||||||
style={{ marginLeft: `${42 * (item.depth - baseDepth - 1)}px` }}
|
|
||||||
>
|
|
||||||
<Comment item={item} />
|
<Comment item={item} />
|
||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
|
@ -2,19 +2,41 @@ import { Form, Input, SubmitButton } from '../components/form'
|
|||||||
import * as Yup from 'yup'
|
import * as Yup from 'yup'
|
||||||
import { gql, useMutation } from '@apollo/client'
|
import { gql, useMutation } from '@apollo/client'
|
||||||
import styles from './reply.module.css'
|
import styles from './reply.module.css'
|
||||||
|
import { COMMENTS } from '../fragments'
|
||||||
|
|
||||||
export const CommentSchema = Yup.object({
|
export const CommentSchema = Yup.object({
|
||||||
text: Yup.string().required('required').trim()
|
text: Yup.string().required('required').trim()
|
||||||
})
|
})
|
||||||
|
|
||||||
export default function Reply ({ parentId }) {
|
export default function Reply ({ item }) {
|
||||||
|
const parentId = item.id
|
||||||
const [createComment] = useMutation(
|
const [createComment] = useMutation(
|
||||||
gql`
|
gql`
|
||||||
|
${COMMENTS}
|
||||||
mutation createComment($text: String!, $parentId: ID!) {
|
mutation createComment($text: String!, $parentId: ID!) {
|
||||||
createComment(text: $text, parentId: $parentId) {
|
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 (
|
return (
|
||||||
|
55
fragments/index.js
Normal file
55
fragments/index.js
Normal 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
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}`
|
@ -21,7 +21,6 @@ export async function getServerSideProps ({ params }) {
|
|||||||
user {
|
user {
|
||||||
name
|
name
|
||||||
}
|
}
|
||||||
depth
|
|
||||||
sats
|
sats
|
||||||
ncomments
|
ncomments
|
||||||
}
|
}
|
||||||
@ -50,11 +49,11 @@ export default function FullItem ({ item }) {
|
|||||||
<>
|
<>
|
||||||
<Item item={item}>
|
<Item item={item}>
|
||||||
{item.text && <Text>{item.text}</Text>}
|
{item.text && <Text>{item.text}</Text>}
|
||||||
<Reply parentId={item.id} />
|
<Reply item={item} />
|
||||||
</Item>
|
</Item>
|
||||||
</>
|
</>
|
||||||
)}
|
)}
|
||||||
<Comments parentId={item.id} baseDepth={item.depth} />
|
<Comments parentId={item.id} />
|
||||||
</Layout>
|
</Layout>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user