Comments & Updated caching

This commit is contained in:
2024-05-10 09:44:20 +03:00
parent 9983720bd1
commit 2781724f8f
11 changed files with 244 additions and 84 deletions
+21 -15
View File
@@ -1,5 +1,5 @@
import { createCache } from '$lib/cache.server';
import { cacheUpdater, cachedMethod } from './root';
import { cacheUpdater, cachedMethod, refExtendCachedMethod } from './root';
const cache = createCache();
@@ -12,6 +12,17 @@ const cache = createCache();
* @typedef {import('$types/base').Category} Category
*/
/**
* @param {import('postgres').Row} row
* @returns {Category}
*/
function parseCategoryFromRow(row) {
return {
id: row['id'],
name: row['name']
};
}
/**
* @param {Result<Category>} categories
* @returns {Result<Category>}
@@ -25,13 +36,15 @@ const updateCategoryCache = cacheUpdater(cache);
*/
export const getCategoriesCached = cachedMethod(cache, getCategories);
export const getCategoriesCachedByRef = refExtendCachedMethod(getCategoriesCached);
/**
* @param {import('postgres').Sql} sql
* @param {number[]} category_ids
* @returns {Promise<Result<Category>>}
*/
export async function getCategories(sql, category_ids) {
if (category_ids.length == 0) return {};
if (category_ids.length == 0) return new Map();
const query = sql`
SELECT id, name
@@ -43,13 +56,10 @@ export async function getCategories(sql, category_ids) {
/**
* @type {Result<Category>}
*/
let result = {};
let result = new Map();
categories.forEach(row => {
result[row['id']] = {
id: row['id'],
name: row['name']
}
result.set(row['id'], parseCategoryFromRow(row));
})
return updateCategoryCache(result);
@@ -64,12 +74,8 @@ export async function getCategories(sql, category_ids) {
export async function getCategoryCached(sql, category_id) {
const categories = await getCategoriesCached(sql, [category_id]);
if (Object.keys(categories).length == 0) {
return {
error: true,
msg: `Could not find Category of ID ${category_id}`
};
}
return categories[category_id];
return categories.get(category_id) || {
error: true,
msg: `Could not find Category of ID ${category_id}`
};
}
+48
View File
@@ -0,0 +1,48 @@
import { getUser, getUsersCached, getUsersCachedByRef } from './user';
/**
* @typedef {import('$types/base').Comment} Comment
*/
/**
* @param {import('$types/base').User | null} author
* @param {import('postgres').Row} row
* @returns {Comment}
*/
function parseCommentFromRow(author, row) {
return {
id: row['id'],
author: author,
parentCommentId: row['parent_comment_id'],
content: row['latest_content'],
commentDate: row['created_date'],
rating: {
likes: BigInt(row['likes']),
dislikes: BigInt(row['dislikes']),
}
};
}
/**
* @param {import('postgres').Sql} sql
* @param {number} post_id
* @returns {Promise<Comment[]>}
*/
export async function getCommentsForPost(sql, post_id) {
const query = sql`
SELECT id, author_id, latest_content, parent_comment_id, created_date, likes, dislikes
FROM doki8902.message_comment
WHERE post_id = ${ post_id };`;
const comments = await query;
const users = await getUsersCachedByRef(sql, comments, c => c['author_id']);
/**
* @type {Comment[]}
*/
return comments.map(row => parseCommentFromRow(
users.get(row['author_id']) || null,
row
));
}
+31 -35
View File
@@ -1,10 +1,31 @@
import { getCategoriesCached, getCategoryCached } from './category';
import { getUser, getUsersCached } from './user';
import { getCategoriesCached, getCategoriesCachedByRef, getCategoryCached } from './category';
import { getUser, getUsersCached, getUsersCachedByRef } from './user';
/**
* @typedef {import('$types/base').Post} Post
*/
/**
* @param {import('$types/base').User | null} author
* @param {import('$types/base').Category} category
* @param {import('postgres').Row} row
* @returns {Post}
*/
function parsePostFromRow(author, category, row) {
return {
id: row['id'],
author: author,
name: row['name'],
category: category,
content: row['latest_content'],
postDate: row['created_date'],
rating: {
likes: BigInt(row['likes']),
dislikes: BigInt(row['dislikes']),
}
};
}
/**
* @param {import('postgres').Sql} sql
* @param {import('$types/base').Category | undefined} category
@@ -30,31 +51,17 @@ export async function getPosts(sql, category = undefined, limit = 10, offset = 0
const posts = await query;
const users = await getUsersCached(sql, posts.map(row => {
return row['author_id'];
}));
const categories = await getCategoriesCached(sql, posts.map(row => {
return row['category_id'];
}));
const users = await getUsersCachedByRef(sql, posts, p => p['author_id']);
const categories = await getCategoriesCachedByRef(sql, posts, p => p['category_id']);
/**
* @type {Post[]}
*/
return posts.map(row => {
return {
id: row['id'],
author: users[row['author_id']] || null,
name: row['name'],
category: categories[row['category_id']],
content: row['latest_content'],
post_date: row['created_date'],
rating: {
likes: BigInt(row['likes']),
dislikes: BigInt(row['dislikes']),
}
};
});
return posts.map(row => parsePostFromRow(
users.get(row['author_id']) || null,
/** @type {import('$types/base').Category} */ (categories.get(row['category_id'])),
row
));
}
/**
@@ -108,16 +115,5 @@ export async function getPost(sql, post_id) {
/**
* @type {Post}
*/
return {
id: post['id'],
author: author,
name: post['name'],
category: category,
content: post['latest_content'],
post_date: post['created_date'],
rating: {
likes: BigInt(post['likes']),
dislikes: BigInt(post['dislikes']),
}
};
return parsePostFromRow(author, category, post);
}
+20 -9
View File
@@ -1,12 +1,12 @@
/**
* @template T
* @param {import('node-cache')} cache
* @returns {function({[id: number]: T})}
* @returns {function(import('$types/base').Result<T>)}
*/
export const cacheUpdater = (cache) => {
return function updateUserCache(data) {
Object.keys(data).forEach(id => {
cache.set(parseInt(id), data[parseInt(id)]);
data.forEach((val, id) => {
cache.set(id, val);
});
return data;
}
@@ -15,15 +15,15 @@ export const cacheUpdater = (cache) => {
/**
* @template T
* @param {import('node-cache')} cache
* @param {function(import('postgres').Sql, number[]): Promise<{[id: number]: T}>} method
* @returns {function(import('postgres').Sql, number[]): Promise<{[id: number]: T}>}
* @param {function(import('postgres').Sql, number[]): Promise<import('$types/base').Result<T>>} method
* @returns {function(import('postgres').Sql, number[]): Promise<import('$types/base').Result<T>>}
*/
export const cachedMethod = (cache, method) => {
return async function(sql, ids) {
/**
* @type {{[id: number]: T}}
* @type {import('$types/base').Result<T>}
*/
let results = {};
let results = new Map();
/**
* @type {number[]}
*/
@@ -34,13 +34,24 @@ export const cachedMethod = (cache, method) => {
return;
let user = cache.get(id);
if (user)
results[id] = user;
results.set(id, user);
else
missing.push(id);
});
const remaining = await method(sql, missing);
return Object.assign({}, results, remaining);
return new Map([...results, ...remaining]);
};
}
/**
* @template T
* @param {function(import('postgres').Sql, number[]): Promise<import('$types/base').Result<T>>} cachedMethod
* @returns {function(import('postgres').Sql, import('postgres').RowList<import('postgres').Row[]>, function(import('postgres').Row): number): Promise<import('$types/base').Result<T>>}
*/
export const refExtendCachedMethod = (cachedMethod) => {
return async function(sql, rows, getRef) {
return await cachedMethod(sql, rows.map(r => getRef(r)));
}
}
+22 -16
View File
@@ -1,5 +1,5 @@
import { createCache } from '$lib/cache.server';
import { cacheUpdater, cachedMethod } from './root';
import { cacheUpdater, cachedMethod, refExtendCachedMethod } from './root';
const cache = createCache();
@@ -12,6 +12,18 @@ const cache = createCache();
* @typedef {import('$types/base').User} User
*/
/**
* @param {import('postgres').Row} row
* @returns {User}
*/
function parseUserFromRow(row) {
return {
id: row['id'],
name: row['username'],
joinDate: row['join_time']
};
}
/**
* @param {Result<User>} users
* @returns {Result<User>}
@@ -25,13 +37,15 @@ const updateUserCache = cacheUpdater(cache);
*/
export const getUsersCached = cachedMethod(cache, getUsers);
export const getUsersCachedByRef = refExtendCachedMethod(getUsersCached);
/**
* @param {import('postgres').Sql} sql
* @param {number[]} user_ids
* @returns {Promise<Result<User>>}
*/
export async function getUsers(sql, user_ids) {
if (user_ids.length == 0) return {};
if (user_ids.length == 0) return new Map();
const query = sql`
SELECT id, username, join_time
@@ -43,14 +57,10 @@ export async function getUsers(sql, user_ids) {
/**
* @type {Result<User>}
*/
let result = {};
let result = new Map();
users.forEach(row => {
result[row['id']] = {
id: row['id'],
name: row['username'],
join_date: row['join_time']
}
result.set(row['id'], parseUserFromRow(row));
})
return updateUserCache(result);
@@ -64,12 +74,8 @@ export async function getUsers(sql, user_ids) {
export async function getUser(sql, user_id) {
const users = await getUsers(sql, [user_id]);
if (Object.keys(users).length == 0) {
return {
error: true,
msg: `Could not find user of ID ${user_id}`
};
}
return users[user_id];
return users.get(user_id) || {
error: true,
msg: `Could not find user of ID ${user_id}`
};
}