mirror of
https://github.com/versia-pub/server.git
synced 2025-12-06 08:28:19 +01:00
fix(api): 🐛 Fix incorrect database columns in status queries
Column instanceId of status didn't actually do anything and it was removed
This commit is contained in:
parent
8fc725639c
commit
19f442ec65
19
cli.ts
19
cli.ts
|
|
@ -8,7 +8,15 @@ import { CliBuilder, CliCommand } from "cli-parser";
|
||||||
import { CliParameterType } from "cli-parser/cli-builder.type";
|
import { CliParameterType } from "cli-parser/cli-builder.type";
|
||||||
import Table from "cli-table";
|
import Table from "cli-table";
|
||||||
import { config } from "config-manager";
|
import { config } from "config-manager";
|
||||||
import { type SQL, eq, inArray, isNotNull, isNull, like } from "drizzle-orm";
|
import {
|
||||||
|
type SQL,
|
||||||
|
eq,
|
||||||
|
inArray,
|
||||||
|
isNotNull,
|
||||||
|
isNull,
|
||||||
|
like,
|
||||||
|
sql,
|
||||||
|
} from "drizzle-orm";
|
||||||
import extract from "extract-zip";
|
import extract from "extract-zip";
|
||||||
import { MediaBackend } from "media-manager";
|
import { MediaBackend } from "media-manager";
|
||||||
import { lookup } from "mime-types";
|
import { lookup } from "mime-types";
|
||||||
|
|
@ -948,16 +956,15 @@ const cliBuilder = new CliBuilder([
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
let instanceQuery: SQL<unknown> | undefined = isNull(
|
let instanceQuery: SQL<unknown> | undefined =
|
||||||
status.instanceId,
|
sql`EXISTS (SELECT 1 FROM "User" WHERE "User"."id" = ${status.authorId} AND "User"."instanceId" IS NULL)`;
|
||||||
);
|
|
||||||
|
|
||||||
if (local && remote) {
|
if (local && remote) {
|
||||||
instanceQuery = undefined;
|
instanceQuery = undefined;
|
||||||
} else if (local) {
|
} else if (local) {
|
||||||
instanceQuery = isNull(status.instanceId);
|
instanceQuery = sql`EXISTS (SELECT 1 FROM "User" WHERE "User"."id" = ${status.authorId} AND "User"."instanceId" IS NULL)`;
|
||||||
} else if (remote) {
|
} else if (remote) {
|
||||||
instanceQuery = isNotNull(status.instanceId);
|
instanceQuery = sql`EXISTS (SELECT 1 FROM "User" WHERE "User"."id" = ${status.authorId} AND "User"."instanceId" IS NOT NULL)`;
|
||||||
}
|
}
|
||||||
|
|
||||||
const notes = await findManyStatuses({
|
const notes = await findManyStatuses({
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,11 @@ export default {
|
||||||
out: "./drizzle",
|
out: "./drizzle",
|
||||||
schema: "./drizzle/schema.ts",
|
schema: "./drizzle/schema.ts",
|
||||||
dbCredentials: {
|
dbCredentials: {
|
||||||
|
/* host: "localhost",
|
||||||
|
port: 40000,
|
||||||
|
user: "lysand",
|
||||||
|
password: "lysand",
|
||||||
|
database: "lysand", */
|
||||||
host: config.database.host,
|
host: config.database.host,
|
||||||
port: Number(config.database.port),
|
port: Number(config.database.port),
|
||||||
user: config.database.username,
|
user: config.database.username,
|
||||||
|
|
|
||||||
3
drizzle/0007_naive_sleeper.sql
Normal file
3
drizzle/0007_naive_sleeper.sql
Normal file
|
|
@ -0,0 +1,3 @@
|
||||||
|
ALTER TABLE "Status" DROP CONSTRAINT "Status_instanceId_Instance_id_fk";
|
||||||
|
--> statement-breakpoint
|
||||||
|
ALTER TABLE "Status" DROP COLUMN IF EXISTS "instanceId";
|
||||||
1753
drizzle/meta/0007_snapshot.json
Normal file
1753
drizzle/meta/0007_snapshot.json
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -50,6 +50,13 @@
|
||||||
"when": 1713057159867,
|
"when": 1713057159867,
|
||||||
"tag": "0006_messy_network",
|
"tag": "0006_messy_network",
|
||||||
"breakpoints": true
|
"breakpoints": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"idx": 7,
|
||||||
|
"version": "5",
|
||||||
|
"when": 1713227918208,
|
||||||
|
"tag": "0007_naive_sleeper",
|
||||||
|
"breakpoints": true
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
|
@ -223,10 +223,6 @@ export const status = pgTable(
|
||||||
visibility: text("visibility").notNull(),
|
visibility: text("visibility").notNull(),
|
||||||
inReplyToPostId: uuid("inReplyToPostId"),
|
inReplyToPostId: uuid("inReplyToPostId"),
|
||||||
quotingPostId: uuid("quotingPostId"),
|
quotingPostId: uuid("quotingPostId"),
|
||||||
instanceId: uuid("instanceId").references(() => instance.id, {
|
|
||||||
onDelete: "cascade",
|
|
||||||
onUpdate: "cascade",
|
|
||||||
}),
|
|
||||||
sensitive: boolean("sensitive").notNull(),
|
sensitive: boolean("sensitive").notNull(),
|
||||||
spoilerText: text("spoiler_text").default("").notNull(),
|
spoilerText: text("spoiler_text").default("").notNull(),
|
||||||
applicationId: uuid("applicationId").references(() => application.id, {
|
applicationId: uuid("applicationId").references(() => application.id, {
|
||||||
|
|
@ -683,7 +679,6 @@ export const emojiRelations = relations(emoji, ({ one, many }) => ({
|
||||||
|
|
||||||
export const instanceRelations = relations(instance, ({ many }) => ({
|
export const instanceRelations = relations(instance, ({ many }) => ({
|
||||||
users: many(user),
|
users: many(user),
|
||||||
statuses: many(status),
|
|
||||||
emojis: many(emoji),
|
emojis: many(emoji),
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
import { apiRoute, applyConfig } from "@api";
|
import { apiRoute, applyConfig } from "@api";
|
||||||
import { jsonResponse } from "@response";
|
import { jsonResponse } from "@response";
|
||||||
import { and, count, countDistinct, eq, gte, isNull } from "drizzle-orm";
|
import { and, count, countDistinct, eq, gte, isNull, sql } from "drizzle-orm";
|
||||||
import { findFirstUser, userToAPI } from "~database/entities/User";
|
import { findFirstUser, userToAPI } from "~database/entities/User";
|
||||||
import { db } from "~drizzle/db";
|
import { db } from "~drizzle/db";
|
||||||
import { instance, status, user } from "~drizzle/schema";
|
import { instance, status, user } from "~drizzle/schema";
|
||||||
|
|
@ -31,7 +31,9 @@ export default apiRoute(async (req, matchedRoute, extraData) => {
|
||||||
count: count(),
|
count: count(),
|
||||||
})
|
})
|
||||||
.from(status)
|
.from(status)
|
||||||
.where(isNull(status.instanceId))
|
.where(
|
||||||
|
sql`EXISTS (SELECT 1 FROM "User" WHERE "User"."id" = ${status.authorId} AND "User"."instanceId" IS NULL)`,
|
||||||
|
)
|
||||||
)[0].count;
|
)[0].count;
|
||||||
|
|
||||||
const userCount = (
|
const userCount = (
|
||||||
|
|
|
||||||
|
|
@ -51,10 +51,6 @@ export default apiRoute<typeof meta, typeof schema>(
|
||||||
),
|
),
|
||||||
or(
|
or(
|
||||||
eq(status.authorId, user.id),
|
eq(status.authorId, user.id),
|
||||||
/* inArray(
|
|
||||||
status.authorId,
|
|
||||||
followers.map((f) => f.ownerId),
|
|
||||||
), */
|
|
||||||
// All statuses where the user is mentioned, using table _StatusToUser which has a: status.id and b: user.id
|
// All statuses where the user is mentioned, using table _StatusToUser which has a: status.id and b: user.id
|
||||||
// WHERE format (... = ...)
|
// WHERE format (... = ...)
|
||||||
sql`EXISTS (SELECT 1 FROM "StatusToMentions" WHERE "StatusToMentions"."statusId" = ${status.id} AND "StatusToMentions"."userId" = ${user.id})`,
|
sql`EXISTS (SELECT 1 FROM "StatusToMentions" WHERE "StatusToMentions"."statusId" = ${status.id} AND "StatusToMentions"."userId" = ${user.id})`,
|
||||||
|
|
|
||||||
|
|
@ -63,6 +63,59 @@ describe(meta.route, () => {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
test("should only fetch local statuses", async () => {
|
||||||
|
const response = await sendTestRequest(
|
||||||
|
new Request(
|
||||||
|
new URL(
|
||||||
|
`${meta.route}?limit=20&local=true`,
|
||||||
|
config.http.base_url,
|
||||||
|
),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[0].accessToken}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
expect(response.headers.get("content-type")).toBe("application/json");
|
||||||
|
|
||||||
|
const objects = (await response.json()) as APIStatus[];
|
||||||
|
|
||||||
|
expect(objects.length).toBe(20);
|
||||||
|
for (const [index, status] of objects.entries()) {
|
||||||
|
expect(status.account).toBeDefined();
|
||||||
|
expect(status.account.id).toBe(users[0].id);
|
||||||
|
expect(status.content).toBeDefined();
|
||||||
|
expect(status.created_at).toBeDefined();
|
||||||
|
expect(status.id).toBe(timeline[index].id);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
test("should only fetch remote statuses (0)", async () => {
|
||||||
|
const response = await sendTestRequest(
|
||||||
|
new Request(
|
||||||
|
new URL(
|
||||||
|
`${meta.route}?limit=20&remote=true`,
|
||||||
|
config.http.base_url,
|
||||||
|
),
|
||||||
|
{
|
||||||
|
headers: {
|
||||||
|
Authorization: `Bearer ${tokens[0].accessToken}`,
|
||||||
|
},
|
||||||
|
},
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
|
expect(response.status).toBe(200);
|
||||||
|
expect(response.headers.get("content-type")).toBe("application/json");
|
||||||
|
|
||||||
|
const objects = (await response.json()) as APIStatus[];
|
||||||
|
|
||||||
|
expect(objects.length).toBe(0);
|
||||||
|
});
|
||||||
|
|
||||||
describe("should paginate properly", async () => {
|
describe("should paginate properly", async () => {
|
||||||
test("should send correct Link header", async () => {
|
test("should send correct Link header", async () => {
|
||||||
const response = await sendTestRequest(
|
const response = await sendTestRequest(
|
||||||
|
|
|
||||||
|
|
@ -50,10 +50,11 @@ export default apiRoute<typeof meta, typeof schema>(
|
||||||
max_id ? lt(status.id, max_id) : undefined,
|
max_id ? lt(status.id, max_id) : undefined,
|
||||||
since_id ? gte(status.id, since_id) : undefined,
|
since_id ? gte(status.id, since_id) : undefined,
|
||||||
min_id ? gt(status.id, min_id) : undefined,
|
min_id ? gt(status.id, min_id) : undefined,
|
||||||
|
// use authorId to grab user, then use user.instanceId to filter local/remote statuses
|
||||||
remote
|
remote
|
||||||
? isNotNull(status.instanceId)
|
? sql`EXISTS (SELECT 1 FROM "User" WHERE "User"."id" = ${status.authorId} AND "User"."instanceId" IS NOT NULL)`
|
||||||
: local
|
: local
|
||||||
? isNull(status.instanceId)
|
? sql`EXISTS (SELECT 1 FROM "User" WHERE "User"."id" = ${status.authorId} AND "User"."instanceId" IS NULL)`
|
||||||
: undefined,
|
: undefined,
|
||||||
only_media
|
only_media
|
||||||
? sql`EXISTS (SELECT 1 FROM "Attachment" WHERE "Attachment"."statusId" = ${status.id})`
|
? sql`EXISTS (SELECT 1 FROM "Attachment" WHERE "Attachment"."statusId" = ${status.id})`
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue