get files and children in scylla

This commit is contained in:
Namekuji 2023-08-12 23:59:54 -04:00
parent 38ad1cb38b
commit 411cbdc121
No known key found for this signature in database
GPG key ID: 1D62332C07FBA532
8 changed files with 118 additions and 24 deletions

View file

@ -9,6 +9,7 @@ DROP MATERIALIZED VIEW IF EXISTS global_timeline;
DROP MATERIALIZED VIEW IF EXISTS note_by_renote_id_and_user_id;
DROP MATERIALIZED VIEW IF EXISTS note_by_renote_id;
DROP MATERIALIZED VIEW IF EXISTS note_by_user_id;
DROP INDEX IF EXISTS note_by_reply_id;
DROP INDEX IF EXISTS note_by_id;
DROP INDEX IF EXISTS note_by_uri;
DROP INDEX IF EXISTS note_by_url;

View file

@ -75,6 +75,7 @@ CREATE TABLE IF NOT EXISTS note ( -- Store all posts
CREATE INDEX IF NOT EXISTS note_by_uri ON note ("uri");
CREATE INDEX IF NOT EXISTS note_by_url ON note ("url");
CREATE INDEX IF NOT EXISTS note_by_id ON note ("id");
CREATE INDEX IF NOT EXISTS note_by_reply_id ON note ("replyId");
CREATE MATERIALIZED VIEW IF NOT EXISTS note_by_user_id AS
SELECT * FROM note

View file

@ -48,6 +48,7 @@ export const scyllaQueries = {
byId: `SELECT * FROM note WHERE "id" = ?`,
byUserId: `SELECT * FROM note_by_user_id WHERE "userId" IN ?`,
byRenoteId: `SELECT * FROM note_by_renote_id WHERE "renoteId" = ?`,
byReplyId: `SELECT * FROM note_by_reply_id WHERE "replyId" = ?`
},
delete: `DELETE FROM note WHERE "createdAtDate" = ? AND "createdAt" = ? AND "userId" = ? AND "userHost" = ? AND "visibility" = ?`,
update: {

View file

@ -82,6 +82,24 @@ export interface ScyllaDriveFile {
height: number | null;
}
export function getScyllaDrivePublicUrl(file: ScyllaDriveFile, thumbnail = false): string | null {
const isImage =
file.type &&
[
"image/png",
"image/apng",
"image/gif",
"image/jpeg",
"image/webp",
"image/svg+xml",
"image/avif",
].includes(file.type);
return thumbnail
? file.thumbnailUrl || (isImage ? file.url : null)
: file.url;
}
export interface ScyllaNoteEditHistory {
content: string;
cw: string;

View file

@ -10,6 +10,7 @@ import { Meta } from "@/models/entities/meta.js";
import { fetchMeta } from "@/misc/fetch-meta.js";
import { Users, DriveFolders } from "../index.js";
import { deepClone } from "@/misc/clone.js";
import { ScyllaDriveFile } from "@/db/scylla.js";
type PackOptions = {
detail?: boolean;

View file

@ -33,6 +33,7 @@ import {
prepared,
scyllaClient,
parseScyllaReaction,
getScyllaDrivePublicUrl,
} from "@/db/scylla.js";
import { LocalFollowingsCache } from "@/misc/cache.js";
import { userByIdCache } from "@/services/user-cache.js";
@ -280,6 +281,7 @@ export const NoteRepository = db.getRepository(Note).extend({
files: scyllaClient
? (note as ScyllaNote).files.map((file) => ({
...file,
thumbnailUrl: getScyllaDrivePublicUrl(file, true),
createdAt: file.createdAt.toISOString(),
properties: {
width: file.width ?? undefined,

View file

@ -4,6 +4,9 @@ import { makePaginationQuery } from "../../common/make-pagination-query.js";
import { generateVisibilityQuery } from "../../common/generate-visibility-query.js";
import { generateMutedUserQuery } from "../../common/generate-muted-user-query.js";
import { generateBlockedUserQuery } from "../../common/generate-block-query.js";
import { parseScyllaNote, prepared, scyllaClient } from "@/db/scylla.js";
import { getNote } from "@/server/api/common/getters.js";
import type { Note } from "@/models/entities/note.js";
export const meta = {
tags: ["notes"],
@ -38,18 +41,52 @@ export const paramDef = {
} as const;
export default define(meta, paramDef, async (ps, user) => {
if (scyllaClient) {
const root = await getNote(ps.noteId, user).catch(() => null);
if (!root) {
return await Notes.packMany([]);
}
// Find replies in BFS manner
const queue = [root];
const foundReplies: Note[] = [];
let depth = 0;
while (
queue.length > 0 &&
foundReplies.length < ps.limit &&
depth < ps.depth
) {
const note = queue.shift();
if (note) {
const result = await scyllaClient.execute(
prepared.note.select.byReplyId,
[note.id],
{ prepare: true },
);
if (result.rowLength > 0) {
const replies = result.rows.map(parseScyllaNote);
foundReplies.push(...replies);
queue.push(...replies);
depth++;
}
}
}
return await Notes.packMany(foundReplies.slice(0, ps.limit), user, {
detail: false,
scyllaNote: true,
});
}
const query = makePaginationQuery(
Notes.createQueryBuilder("note"),
ps.sinceId,
ps.untilId,
)
.andWhere(
).andWhere(
"note.id IN (SELECT id FROM note_replies(:noteId, :depth, :limit))",
{ noteId: ps.noteId, depth: ps.depth, limit: ps.limit },
)
.innerJoinAndSelect("note.user", "user")
.leftJoinAndSelect("user.avatar", "avatar")
.leftJoinAndSelect("user.banner", "banner");
);
generateVisibilityQuery(query, user);
if (user) {

View file

@ -148,7 +148,7 @@ export default async function (
deletedAt: deletedAt,
});
//#region ローカルの投稿なら削除アクティビティを配送
//#region Deliver Delete activity if it's from a local account
if (Users.isLocalUser(user) && !note.localOnly) {
let renote: Note | null = null;
@ -159,10 +159,19 @@ export default async function (
!note.hasPoll &&
(note.fileIds == null || note.fileIds.length === 0)
) {
if (scyllaClient) {
const result = await scyllaClient.execute(
prepared.note.select.byId,
[note.renoteId],
{ prepare: true },
);
if (result.rowLength > 0) renote = parseScyllaNote(result.first());
} else {
renote = await Notes.findOneBy({
id: note.renoteId,
});
}
}
const content = renderActivity(
renote
@ -249,6 +258,28 @@ async function findCascadingNotes(note: Note) {
const cascadingNotes: Note[] = [];
const recursive = async (noteId: string) => {
let notes: Note[] = [];
if (scyllaClient) {
const replies = await scyllaClient.execute(
prepared.note.select.byReplyId,
[noteId],
{ prepare: true },
);
if (replies.rowLength > 0) {
notes.push(...replies.rows.map(parseScyllaNote));
}
const renotes = await scyllaClient.execute(
prepared.note.select.byRenoteId,
[noteId],
{ prepare: true },
);
if (renotes.rowLength > 0) {
notes.push(
...renotes.rows.map(parseScyllaNote).filter((note) => !!note.text),
);
}
} else {
const query = Notes.createQueryBuilder("note")
.where("note.replyId = :noteId", { noteId })
.orWhere(
@ -259,8 +290,10 @@ async function findCascadingNotes(note: Note) {
}),
)
.leftJoinAndSelect("note.user", "user");
const replies = await query.getMany();
for (const reply of replies) {
notes = await query.getMany();
}
for (const reply of notes) {
cascadingNotes.push(reply);
await recursive(reply.id);
}