Refactor: Better Post Metrics data fetching

This commit is contained in:
Donatas Kirda 2024-05-15 00:41:28 +03:00
parent 196166897e
commit a6f3c6c695
Signed by: bloodwiing
GPG Key ID: 63020D8D3F4A164F
8 changed files with 154 additions and 77 deletions

View File

@ -14,6 +14,8 @@
* @type {import("$types/base").CommentTreeNode[] | null} * @type {import("$types/base").CommentTreeNode[] | null}
*/ */
export let commentTree = null; export let commentTree = null;
$: isPreview = commentTree == null;
</script> </script>
<style lang="scss"> <style lang="scss">

View File

@ -24,12 +24,22 @@
posts.forEach((p, index) => { posts.forEach((p, index) => {
hidden[index] = p == post; hidden[index] = p == post;
}); });
goto(`/posts?glance=${currentPreview.id}`, {
replaceState: true,
noScroll: true
});
} }
function dismiss() { function dismiss() {
currentPreview = null; currentPreview = null;
hidden = Array(posts.length).fill(false); hidden = Array(posts.length).fill(false);
// goto(`/posts`, {
// replaceState: true,
// noScroll: true
// });
} }
function expand() { function expand() {

View File

@ -3,15 +3,32 @@ import { getUser, getUsersCachedByRef } from './user';
/** /**
* @typedef {import('$types/base').Post} Post * @typedef {import('$types/base').Post} Post
* @typedef {import('$types/base').PostMetrics} PostMetrics
*/ */
/**
* @param {import('postgres').Row} row
* @returns {PostMetrics}
*/
function parsePostMetricsFromRow(row) {
return {
commentCount: BigInt(row['comment_count']),
userCount: BigInt(row['user_count']),
latestActivity: row['latest_activity'],
engagement: BigInt(row['engagement']),
age: row['age'],
relevancy: row['relevancy'],
};
}
/** /**
* @param {import('$types/base').User | null} author * @param {import('$types/base').User | null} author
* @param {import('$types/base').Category} category * @param {import('$types/base').Category} category
* @param {import('postgres').Row} row * @param {import('postgres').Row} row
* @param {boolean} withMetrics
* @returns {Post} * @returns {Post}
*/ */
function parsePostFromRow(author, category, row) { function parsePostFromRow(author, category, row, withMetrics = false) {
return { return {
id: row['id'], id: row['id'],
author: author, author: author,
@ -22,7 +39,8 @@ function parsePostFromRow(author, category, row) {
rating: { rating: {
likes: BigInt(row['likes']), likes: BigInt(row['likes']),
dislikes: BigInt(row['dislikes']), dislikes: BigInt(row['dislikes']),
} },
metrics: withMetrics ? parsePostMetricsFromRow(row) : null,
}; };
} }
@ -31,19 +49,15 @@ function parsePostFromRow(author, category, row) {
* @param {import('$types/base').Category | undefined} category * @param {import('$types/base').Category | undefined} category
* @param {number} limit * @param {number} limit
* @param {number} offset * @param {number} offset
* @param {boolean} withMetrics
* @returns {Promise<Post[]>} * @returns {Promise<Post[]>}
*/ */
export async function getPosts(sql, category = undefined, limit = 10, offset = 0) { export async function getPosts(sql, category = undefined, limit = 10, offset = 0, withMetrics = false) {
let filter; const filter = category === undefined ? sql`` : sql`WHERE category_id = ${ category.id }`;
const metrics = !withMetrics ? sql`` : sql`, comment_count, user_count, latest_activity, engagement, age, relevancy`;
if (category === undefined) {
filter = sql``;
} else {
filter = sql`WHERE category_id = ${ category.id }`;
}
const query = sql` const query = sql`
SELECT id, author_id, name, category_id, latest_content, created_date, likes, dislikes SELECT id, author_id, name, category_id, latest_content, created_date, likes, dislikes ${ metrics }
FROM doki8902.message_post FROM doki8902.message_post
${ filter } ${ filter }
FETCH FIRST ${ limit } ROWS ONLY FETCH FIRST ${ limit } ROWS ONLY
@ -60,7 +74,8 @@ export async function getPosts(sql, category = undefined, limit = 10, offset = 0
return posts.map(row => parsePostFromRow( return posts.map(row => parsePostFromRow(
users.get(row['author_id']) || null, users.get(row['author_id']) || null,
/** @type {import('$types/base').Category} */ (categories.get(row['category_id'])), /** @type {import('$types/base').Category} */ (categories.get(row['category_id'])),
row row,
withMetrics
)); ));
} }

View File

@ -1,46 +1,89 @@
/** // /**
* @typedef {import('$types/base').PostMetrics} PostMetrics // * @typedef {import('$types/base').PostMetrics} PostMetrics
*/ // */
import { sql } from '$lib/db.server'; // import { sql } from '$lib/db.server';
/** // /**
* @param {import('$types/base').Post} post // * @param {import('$types/base').Post} post
* @param {import('postgres').Row} row // * @param {import('postgres').Row} row
* @returns {PostMetrics} // * @returns {PostMetrics}
*/ // */
function parsePostMetricsFromRow(post, row) { // function parsePostMetricsFromRowAndPost(post, row) {
return { // return {
post: post, // postId: post.id,
commentCount: BigInt(row['comment_count']), // commentCount: BigInt(row['comment_count']),
userCount: BigInt(row['user_count']), // userCount: BigInt(row['user_count']),
latestActivity: row['latest_activity'], // latestActivity: row['latest_activity'],
rating: post.rating, // rating: post.rating,
score: BigInt(row['score']), // score: BigInt(row['score']),
engagement: BigInt(row['engagement']), // engagement: BigInt(row['engagement']),
age: row['age'], // age: row['age'],
relevancy: row['relevancy'] // relevancy: row['relevancy']
}; // };
} // }
/** // /**
* @param {import('$types/base').Post} post // * @param {import('postgres').Row} row
* @returns {Promise<PostMetrics | import('$types/error').Error>} // * @returns {PostMetrics}
*/ // */
export async function getPostMetrics(post) { // function parsePostMetricsFromRow(row) {
const query = sql` // return {
SELECT comment_count, user_count, latest_activity, score, engagement, age, relevancy // postId: row['post_id'],
FROM doki8902.post_metrics // commentCount: BigInt(row['comment_count']),
WHERE post_id = ${ post.id }`; // userCount: BigInt(row['user_count']),
// latestActivity: row['latest_activity'],
// rating: {
// likes: row['likes'],
// dislikes: row['dislikes']
// },
// score: BigInt(row['score']),
// engagement: BigInt(row['engagement']),
// age: row['age'],
// relevancy: row['relevancy']
// };
// }
const result = await query; // /**
// * @param {import('$types/base').Post} post
// * @returns {Promise<PostMetrics | import('$types/error').Error>}
// */
// export async function getPostMetricsForPost(post) {
// const query = sql`
// SELECT comment_count, user_count, latest_activity, score, engagement, age, relevancy
// FROM doki8902.post_metrics
// WHERE post_id = ${ post.id }`;
if (result.length == 0) { // const result = await query;
return {
error: true,
msg: `Could not find PostMetrics for Post ID ${post.id}`
};
}
return parsePostMetricsFromRow(post, result[0]); // if (result.length == 0) {
} // return {
// error: true,
// msg: `Could not find PostMetrics for Post ID ${post.id}`
// };
// }
// return parsePostMetricsFromRowAndPost(post, result[0]);
// }
// /**
// * @param {number} post_id
// * @returns {Promise<PostMetrics | import('$types/error').Error>}
// */
// export async function getPostMetricsForPostId(post_id) {
// const query = sql`
// SELECT post_id, comment_count, user_count, latest_activity, likes, dislikes, score, engagement, age, relevancy
// FROM doki8902.post_metrics
// WHERE post_id = ${ post_id }`;
// const result = await query;
// if (result.length == 0) {
// return {
// error: true,
// msg: `Could not find PostMetrics for Post ID ${post_id}`
// };
// }
// return parsePostMetricsFromRow(result[0]);
// }

View File

@ -1,9 +1,20 @@
import { getPosts } from '$lib/server/db/post'; import { getPosts } from '$lib/server/db/post';
import { getPostMetricsForPostId } from '$lib/server/db/postmertics';
/** @type {import('./$types').PageServerLoad} */ /** @type {import('./$types').PageServerLoad} */
export async function load({ locals }) { export async function load({ locals, url }) {
let result = await getPosts(locals.sql); const result = await getPosts(locals.sql, undefined, 10, 0, true);
// const glance = url.searchParams.get('glance');
// const glanceID = glance ? parseInt(glance) : null
// let postMetrics = null;
// if (glanceID) {
// postMetrics = await getPostMetricsForPostId(glanceID);
// }
console.log(result);
return { return {
posts: result posts: result

View File

@ -2,7 +2,9 @@
import Postlist from "$comp/postlist.svelte"; import Postlist from "$comp/postlist.svelte";
/** /**
* @type {{posts: import("$types/base").Post[]}} * @type {{
* posts: import("$types/base").Post[]
* }}
*/ */
export let data; export let data;
</script> </script>

View File

@ -1,6 +1,5 @@
import { getCommentsForPost } from "$lib/server/db/comment"; import { getCommentsForPost } from "$lib/server/db/comment";
import { getPost } from "$lib/server/db/post"; import { getPost } from "$lib/server/db/post";
import { getPostMetrics } from "$lib/server/db/postmertics";
import { getIdFromName } from "$lib/util"; import { getIdFromName } from "$lib/util";
import { error } from "@sveltejs/kit"; import { error } from "@sveltejs/kit";
@ -16,8 +15,6 @@ export async function load({ params, locals }) {
const comments = await getCommentsForPost(locals.sql, post_id); const comments = await getCommentsForPost(locals.sql, post_id);
console.log(await getPostMetrics(post));
return { return {
post: post, post: post,
comments: comments comments: comments

View File

@ -3,19 +3,28 @@ export type Result<T> = Map<number, T>;
export type User = { export type User = {
id: number, id: number,
name: string, name: string,
joinDate: Date joinDate: Date,
}; };
export type Rating = { export type Rating = {
likes: bigint, likes: bigint,
dislikes: bigint dislikes: bigint,
} }
export type Category = { export type Category = {
id: number, id: number,
name: string name: string,
} }
export type PostMetrics = {
commentCount: bigint,
userCount: bigint,
latestActivity: Date,
engagement: bigint,
age: number,
relevancy: number,
};
export type Post = { export type Post = {
id: number, id: number,
author: User | null, author: User | null,
@ -23,7 +32,8 @@ export type Post = {
category: Category, category: Category,
content: string, content: string,
postDate: Date, postDate: Date,
rating: Rating rating: Rating,
metrics: PostMetrics | null,
}; };
export type Comment = { export type Comment = {
@ -32,23 +42,10 @@ export type Comment = {
content: string, content: string,
commentDate: Date, commentDate: Date,
rating: Rating, rating: Rating,
parentCommentId: number parentCommentId: number,
}; };
export type CommentTreeNode = { export type CommentTreeNode = {
parent: Comment, parent: Comment,
children: (CommentTreeNode | number)[] children: (CommentTreeNode | number)[],
};
export type PostMetrics = {
post: Post,
commentCount: bigint,
userCount: bigint,
latestActivity: Date,
rating: Rating,
score: bigint,
engagement: bigint,
age: number,
relevancy: number
}; };