First pass at adding comment trees. (#2362)

* First pass at adding comment trees.

- Extracted comment replies into its own table.
- Added ltree column to comment
- Added parent_id param to GetComments to fetch a tree branch
- No paging / limiting yet

* Adding child_count to comment_aggregates.

* Adding parent comment update counts

* Fix unit tests.

* Comment tree paging mostly done.

* Fix clippy

* Fix drone tests wrong postgres version.

* Fix unit tests.

* Add back in delete in unit test.

* Add postgres upgrade script.

* Fixing some PR comments.

* Move update ltree into Comment::create

* Updating based on comments.

* Fix send soft fail.
This commit is contained in:
Dessalines 2022-07-29 23:55:59 -04:00 committed by GitHub
parent becb8b4f66
commit 9c3efe32e7
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
72 changed files with 3692 additions and 2661 deletions

View file

@ -155,7 +155,7 @@ steps:
services:
- name: database
image: postgres:12-alpine
image: postgres:14-alpine
environment:
POSTGRES_USER: lemmy
POSTGRES_PASSWORD: password

43
Cargo.lock generated
View file

@ -834,12 +834,12 @@ dependencies = [
[[package]]
name = "darling"
version = "0.13.1"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d0d720b8683f8dd83c65155f0530560cba68cd2bf395f6513a483caee57ff7f4"
checksum = "a01d95850c592940db9b8194bc39f4bc0e89dee5c4265e4b1807c34a9aba453c"
dependencies = [
"darling_core 0.13.1",
"darling_macro 0.13.1",
"darling_core 0.13.4",
"darling_macro 0.13.4",
]
[[package]]
@ -868,9 +868,9 @@ dependencies = [
[[package]]
name = "darling_core"
version = "0.13.1"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7a340f241d2ceed1deb47ae36c4144b2707ec7dd0b649f894cb39bb595986324"
checksum = "859d65a907b6852c9361e3185c862aae7fafd2887876799fa55f5f99dc40d610"
dependencies = [
"fnv",
"ident_case",
@ -907,11 +907,11 @@ dependencies = [
[[package]]
name = "darling_macro"
version = "0.13.1"
version = "0.13.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "72c41b3b7352feb3211a0d743dc5700a4e3b60f51bd2b368892d1e0f9a95f44b"
checksum = "9c972679f83bdf9c42bd905396b6c3588a843a17f0f16dfcfa3e2c5d57441835"
dependencies = [
"darling_core 0.13.1",
"darling_core 0.13.4",
"quote 1.0.18",
"syn 1.0.96",
]
@ -1058,6 +1058,16 @@ dependencies = [
"syn 1.0.96",
]
[[package]]
name = "diesel_ltree"
version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "55a0b2b2e948a2d8ab673ccee9f37b20bdcc8b7acb40a242a0fdf53d4c2678b0"
dependencies = [
"byteorder",
"diesel",
]
[[package]]
name = "diesel_migrations"
version = "1.4.0"
@ -1132,7 +1142,7 @@ name = "doku-derive"
version = "0.11.0"
source = "git+https://github.com/anixe/doku#10a0339a82be92b5f160aac325d11c9c2ef875e1"
dependencies = [
"darling 0.13.1",
"darling 0.13.4",
"proc-macro2 1.0.39",
"quote 1.0.18",
"syn 1.0.96",
@ -1984,6 +1994,7 @@ dependencies = [
"chrono",
"diesel",
"diesel-derive-newtype",
"diesel_ltree",
"diesel_migrations",
"lemmy_utils",
"once_cell",
@ -2002,6 +2013,7 @@ name = "lemmy_db_views"
version = "0.16.5"
dependencies = [
"diesel",
"diesel_ltree",
"lemmy_db_schema",
"serde",
"serial_test",
@ -3507,22 +3519,21 @@ dependencies = [
[[package]]
name = "serde_with"
version = "1.12.0"
version = "1.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec1e6ec4d8950e5b1e894eac0d360742f3b1407a6078a604a731c4b3f49cefbc"
checksum = "678b5a069e50bf00ecd22d0cd8ddf7c236f68581b03db652061ed5eb13a312ff"
dependencies = [
"rustversion",
"serde",
"serde_with_macros",
]
[[package]]
name = "serde_with_macros"
version = "1.5.1"
version = "1.5.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "12e47be9471c72889ebafb5e14d5ff930d89ae7a67bbdb5f8abb564f845a927e"
checksum = "e182d6ec6f05393cc0e5ed1bf81ad6db3a8feedf8ee515ecdd369809bcce8082"
dependencies = [
"darling 0.13.1",
"darling 0.13.4",
"proc-macro2 1.0.39",
"quote 1.0.18",
"syn 1.0.96",

View file

@ -12,14 +12,17 @@
"api-test": "jest -i follow.spec.ts && jest -i src/post.spec.ts && jest -i comment.spec.ts && jest -i private_message.spec.ts && jest -i user.spec.ts && jest -i community.spec.ts"
},
"devDependencies": {
"@sniptt/monads": "^0.5.10",
"@types/jest": "^26.0.23",
"eslint": "^7.30.0",
"eslint-plugin-jane": "^9.0.3",
"class-transformer": "^0.5.1",
"eslint": "^8.20.0",
"eslint-plugin-jane": "^11.2.2",
"jest": "^27.0.6",
"lemmy-js-client": "0.17.0-rc.11",
"lemmy-js-client": "0.17.0-rc.37",
"node-fetch": "^2.6.1",
"prettier": "^2.3.2",
"prettier": "^2.7.1",
"reflect-metadata": "^0.1.13",
"ts-jest": "^27.0.3",
"typescript": "^4.3.5"
"typescript": "^4.6.4"
}
}

View file

@ -1,4 +1,8 @@
jest.setTimeout(180000);
import {None, Some} from '@sniptt/monads';
import { CommentView } from 'lemmy-js-client';
import { PostResponse } from 'lemmy-js-client';
import {
alpha,
beta,
@ -24,10 +28,9 @@ import {
randomString,
API,
unfollows,
getComments,
getCommentParentId,
} from './shared';
import { CommentView } from 'lemmy-js-client';
import { PostResponse } from 'lemmy-js-client';
let postRes: PostResponse;
@ -39,7 +42,7 @@ beforeAll(async () => {
let betaCommunity = (await resolveBetaCommunity(alpha)).community;
postRes = await createPost(
alpha,
betaCommunity.community.id
betaCommunity.unwrap().community.id
);
});
@ -62,14 +65,14 @@ function assertCommentFederation(
}
test('Create a comment', async () => {
let commentRes = await createComment(alpha, postRes.post_view.post.id);
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
expect(commentRes.comment_view.comment.content).toBeDefined();
expect(commentRes.comment_view.community.local).toBe(false);
expect(commentRes.comment_view.creator.local).toBe(true);
expect(commentRes.comment_view.counts.score).toBe(1);
// Make sure that comment is liked on beta
let betaComment = (await resolveComment(beta, commentRes.comment_view.comment)).comment;
let betaComment = (await resolveComment(beta, commentRes.comment_view.comment)).comment.unwrap();
expect(betaComment).toBeDefined();
expect(betaComment.community.local).toBe(true);
expect(betaComment.creator.local).toBe(false);
@ -78,15 +81,15 @@ test('Create a comment', async () => {
});
test('Create a comment in a non-existent post', async () => {
let commentRes = await createComment(alpha, -1);
expect(commentRes).toStrictEqual({ error: 'couldnt_find_post' });
let commentRes = await createComment(alpha, -1, None) as any;
expect(commentRes.error).toBe('couldnt_find_post');
});
test('Update a comment', async () => {
let commentRes = await createComment(alpha, postRes.post_view.post.id);
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
// Federate the comment first
let betaComment = (await resolveComment(beta, commentRes.comment_view.comment)).comment;
assertCommentFederation(betaComment, commentRes.comment_view);
assertCommentFederation(betaComment.unwrap(), commentRes.comment_view);
let updateCommentRes = await editComment(
alpha,
@ -102,7 +105,7 @@ test('Update a comment', async () => {
let betaCommentUpdated = (await resolveComment(
beta,
commentRes.comment_view.comment
)).comment;
)).comment.unwrap();
assertCommentFederation(
betaCommentUpdated,
updateCommentRes.comment_view
@ -110,7 +113,7 @@ test('Update a comment', async () => {
});
test('Delete a comment', async () => {
let commentRes = await createComment(alpha, postRes.post_view.post.id);
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
let deleteCommentRes = await deleteComment(
alpha,
@ -121,8 +124,8 @@ test('Delete a comment', async () => {
expect(deleteCommentRes.comment_view.comment.content).toBe("");
// Make sure that comment is undefined on beta
let betaCommentRes: any = await resolveComment(beta, commentRes.comment_view.comment);
expect(betaCommentRes).toStrictEqual({ error: 'couldnt_find_object' });
let betaCommentRes = await resolveComment(beta, commentRes.comment_view.comment) as any;
expect(betaCommentRes.error).toBe('couldnt_find_object');
let undeleteCommentRes = await deleteComment(
alpha,
@ -132,7 +135,7 @@ test('Delete a comment', async () => {
expect(undeleteCommentRes.comment_view.comment.deleted).toBe(false);
// Make sure that comment is undeleted on beta
let betaComment2 = (await resolveComment(beta, commentRes.comment_view.comment)).comment;
let betaComment2 = (await resolveComment(beta, commentRes.comment_view.comment)).comment.unwrap();
expect(betaComment2.comment.deleted).toBe(false);
assertCommentFederation(
betaComment2,
@ -141,12 +144,12 @@ test('Delete a comment', async () => {
});
test('Remove a comment from admin and community on the same instance', async () => {
let commentRes = await createComment(alpha, postRes.post_view.post.id);
let commentRes = await createComment(alpha, postRes.post_view.post.id, None);
// Get the id for beta
let betaCommentId = (
await resolveComment(beta, commentRes.comment_view.comment)
).comment.comment.id;
).comment.unwrap().comment.id;
// The beta admin removes it (the community lives on beta)
let removeCommentRes = await removeComment(beta, true, betaCommentId);
@ -154,17 +157,17 @@ test('Remove a comment from admin and community on the same instance', async ()
expect(removeCommentRes.comment_view.comment.content).toBe("");
// Make sure that comment is removed on alpha (it gets pushed since an admin from beta removed it)
let refetchedPost = await getPost(alpha, postRes.post_view.post.id);
expect(refetchedPost.comments[0].comment.removed).toBe(true);
let refetchedPostComments = await getComments(alpha, postRes.post_view.post.id);
expect(refetchedPostComments.comments[0].comment.removed).toBe(true);
let unremoveCommentRes = await removeComment(beta, false, betaCommentId);
expect(unremoveCommentRes.comment_view.comment.removed).toBe(false);
// Make sure that comment is unremoved on beta
let refetchedPost2 = await getPost(alpha, postRes.post_view.post.id);
expect(refetchedPost2.comments[0].comment.removed).toBe(false);
let refetchedPostComments2 = await getComments(alpha, postRes.post_view.post.id);
expect(refetchedPostComments2.comments[0].comment.removed).toBe(false);
assertCommentFederation(
refetchedPost2.comments[0],
refetchedPostComments2.comments[0],
unremoveCommentRes.comment_view