diff --git a/cli.ts b/cli.ts index e95de867..95d8bd2b 100644 --- a/cli.ts +++ b/cli.ts @@ -8,7 +8,15 @@ import { CliBuilder, CliCommand } from "cli-parser"; import { CliParameterType } from "cli-parser/cli-builder.type"; import Table from "cli-table"; 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 { MediaBackend } from "media-manager"; import { lookup } from "mime-types"; @@ -948,16 +956,15 @@ const cliBuilder = new CliBuilder([ return 1; } - let instanceQuery: SQL | undefined = isNull( - status.instanceId, - ); + let instanceQuery: SQL | undefined = + sql`EXISTS (SELECT 1 FROM "User" WHERE "User"."id" = ${status.authorId} AND "User"."instanceId" IS NULL)`; if (local && remote) { instanceQuery = undefined; } 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) { - 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({ diff --git a/drizzle.config.ts b/drizzle.config.ts index 2deb46bb..a49f235d 100644 --- a/drizzle.config.ts +++ b/drizzle.config.ts @@ -6,6 +6,11 @@ export default { out: "./drizzle", schema: "./drizzle/schema.ts", dbCredentials: { + /* host: "localhost", + port: 40000, + user: "lysand", + password: "lysand", + database: "lysand", */ host: config.database.host, port: Number(config.database.port), user: config.database.username, diff --git a/drizzle/0007_naive_sleeper.sql b/drizzle/0007_naive_sleeper.sql new file mode 100644 index 00000000..f1b24049 --- /dev/null +++ b/drizzle/0007_naive_sleeper.sql @@ -0,0 +1,3 @@ +ALTER TABLE "Status" DROP CONSTRAINT "Status_instanceId_Instance_id_fk"; +--> statement-breakpoint +ALTER TABLE "Status" DROP COLUMN IF EXISTS "instanceId"; \ No newline at end of file diff --git a/drizzle/meta/0007_snapshot.json b/drizzle/meta/0007_snapshot.json new file mode 100644 index 00000000..ae9d23bc --- /dev/null +++ b/drizzle/meta/0007_snapshot.json @@ -0,0 +1,1753 @@ +{ + "id": "73c8df6a-c16d-4527-b959-46d6b32f56c6", + "prevId": "47f76353-0b58-4367-b273-8933b7c89e1f", + "version": "5", + "dialect": "pg", + "tables": { + "Application": { + "name": "Application", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "website": { + "name": "website", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "vapid_key": { + "name": "vapid_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "client_id": { + "name": "client_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "secret": { + "name": "secret", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scopes": { + "name": "scopes", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "redirect_uris": { + "name": "redirect_uris", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "Application_client_id_index": { + "name": "Application_client_id_index", + "columns": [ + "client_id" + ], + "isUnique": true + } + }, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Attachment": { + "name": "Attachment", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "remote_url": { + "name": "remote_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "thumbnail_url": { + "name": "thumbnail_url", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "mime_type": { + "name": "mime_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "description": { + "name": "description", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "blurhash": { + "name": "blurhash", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "sha256": { + "name": "sha256", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "fps": { + "name": "fps", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "duration": { + "name": "duration", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "width": { + "name": "width", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "height": { + "name": "height", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "size": { + "name": "size", + "type": "integer", + "primaryKey": false, + "notNull": false + }, + "statusId": { + "name": "statusId", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "Attachment_statusId_Status_id_fk": { + "name": "Attachment_statusId_Status_id_fk", + "tableFrom": "Attachment", + "tableTo": "Status", + "columnsFrom": [ + "statusId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Emoji": { + "name": "Emoji", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "shortcode": { + "name": "shortcode", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "url": { + "name": "url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "visible_in_picker": { + "name": "visible_in_picker", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "alt": { + "name": "alt", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "instanceId": { + "name": "instanceId", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "Emoji_instanceId_Instance_id_fk": { + "name": "Emoji_instanceId_Instance_id_fk", + "tableFrom": "Emoji", + "tableTo": "Instance", + "columnsFrom": [ + "instanceId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "EmojiToStatus": { + "name": "EmojiToStatus", + "schema": "", + "columns": { + "emojiId": { + "name": "emojiId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "statusId": { + "name": "statusId", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "EmojiToStatus_emojiId_statusId_index": { + "name": "EmojiToStatus_emojiId_statusId_index", + "columns": [ + "emojiId", + "statusId" + ], + "isUnique": true + }, + "EmojiToStatus_statusId_index": { + "name": "EmojiToStatus_statusId_index", + "columns": [ + "statusId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "EmojiToStatus_emojiId_Emoji_id_fk": { + "name": "EmojiToStatus_emojiId_Emoji_id_fk", + "tableFrom": "EmojiToStatus", + "tableTo": "Emoji", + "columnsFrom": [ + "emojiId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "EmojiToStatus_statusId_Status_id_fk": { + "name": "EmojiToStatus_statusId_Status_id_fk", + "tableFrom": "EmojiToStatus", + "tableTo": "Status", + "columnsFrom": [ + "statusId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "EmojiToUser": { + "name": "EmojiToUser", + "schema": "", + "columns": { + "emojiId": { + "name": "emojiId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "EmojiToUser_emojiId_userId_index": { + "name": "EmojiToUser_emojiId_userId_index", + "columns": [ + "emojiId", + "userId" + ], + "isUnique": true + }, + "EmojiToUser_userId_index": { + "name": "EmojiToUser_userId_index", + "columns": [ + "userId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "EmojiToUser_emojiId_Emoji_id_fk": { + "name": "EmojiToUser_emojiId_Emoji_id_fk", + "tableFrom": "EmojiToUser", + "tableTo": "Emoji", + "columnsFrom": [ + "emojiId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "EmojiToUser_userId_User_id_fk": { + "name": "EmojiToUser_userId_User_id_fk", + "tableFrom": "EmojiToUser", + "tableTo": "User", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Flag": { + "name": "Flag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "flag_type": { + "name": "flag_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'other'" + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "flaggeStatusId": { + "name": "flaggeStatusId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "flaggedUserId": { + "name": "flaggedUserId", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "Flag_flaggeStatusId_Status_id_fk": { + "name": "Flag_flaggeStatusId_Status_id_fk", + "tableFrom": "Flag", + "tableTo": "Status", + "columnsFrom": [ + "flaggeStatusId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Flag_flaggedUserId_User_id_fk": { + "name": "Flag_flaggedUserId_User_id_fk", + "tableFrom": "Flag", + "tableTo": "User", + "columnsFrom": [ + "flaggedUserId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Instance": { + "name": "Instance", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "base_url": { + "name": "base_url", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "name": { + "name": "name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "version": { + "name": "version", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "logo": { + "name": "logo", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "disable_automoderation": { + "name": "disable_automoderation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": {}, + "foreignKeys": {}, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Like": { + "name": "Like", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "likerId": { + "name": "likerId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "likedId": { + "name": "likedId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "Like_likerId_User_id_fk": { + "name": "Like_likerId_User_id_fk", + "tableFrom": "Like", + "tableTo": "User", + "columnsFrom": [ + "likerId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Like_likedId_Status_id_fk": { + "name": "Like_likedId_Status_id_fk", + "tableFrom": "Like", + "tableTo": "Status", + "columnsFrom": [ + "likedId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "LysandObject": { + "name": "LysandObject", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "remote_id": { + "name": "remote_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "uri": { + "name": "uri", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "authorId": { + "name": "authorId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "extra_data": { + "name": "extra_data", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "extensions": { + "name": "extensions", + "type": "jsonb", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "LysandObject_remote_id_index": { + "name": "LysandObject_remote_id_index", + "columns": [ + "remote_id" + ], + "isUnique": true + }, + "LysandObject_uri_index": { + "name": "LysandObject_uri_index", + "columns": [ + "uri" + ], + "isUnique": true + } + }, + "foreignKeys": { + "LysandObject_authorId_LysandObject_id_fk": { + "name": "LysandObject_authorId_LysandObject_id_fk", + "tableFrom": "LysandObject", + "tableTo": "LysandObject", + "columnsFrom": [ + "authorId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "ModNote": { + "name": "ModNote", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "notedStatusId": { + "name": "notedStatusId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "notedUserId": { + "name": "notedUserId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "modId": { + "name": "modId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "ModNote_notedStatusId_Status_id_fk": { + "name": "ModNote_notedStatusId_Status_id_fk", + "tableFrom": "ModNote", + "tableTo": "Status", + "columnsFrom": [ + "notedStatusId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "ModNote_notedUserId_User_id_fk": { + "name": "ModNote_notedUserId_User_id_fk", + "tableFrom": "ModNote", + "tableTo": "User", + "columnsFrom": [ + "notedUserId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "ModNote_modId_User_id_fk": { + "name": "ModNote_modId_User_id_fk", + "tableFrom": "ModNote", + "tableTo": "User", + "columnsFrom": [ + "modId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "ModTag": { + "name": "ModTag", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "taggedStatusId": { + "name": "taggedStatusId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "taggedUserId": { + "name": "taggedUserId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "modId": { + "name": "modId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "tag": { + "name": "tag", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "ModTag_taggedStatusId_Status_id_fk": { + "name": "ModTag_taggedStatusId_Status_id_fk", + "tableFrom": "ModTag", + "tableTo": "Status", + "columnsFrom": [ + "taggedStatusId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "ModTag_taggedUserId_User_id_fk": { + "name": "ModTag_taggedUserId_User_id_fk", + "tableFrom": "ModTag", + "tableTo": "User", + "columnsFrom": [ + "taggedUserId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "ModTag_modId_User_id_fk": { + "name": "ModTag_modId_User_id_fk", + "tableFrom": "ModTag", + "tableTo": "User", + "columnsFrom": [ + "modId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Notification": { + "name": "Notification", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "type": { + "name": "type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "notifiedId": { + "name": "notifiedId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "accountId": { + "name": "accountId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "statusId": { + "name": "statusId", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "Notification_notifiedId_User_id_fk": { + "name": "Notification_notifiedId_User_id_fk", + "tableFrom": "Notification", + "tableTo": "User", + "columnsFrom": [ + "notifiedId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Notification_accountId_User_id_fk": { + "name": "Notification_accountId_User_id_fk", + "tableFrom": "Notification", + "tableTo": "User", + "columnsFrom": [ + "accountId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Notification_statusId_Status_id_fk": { + "name": "Notification_statusId_Status_id_fk", + "tableFrom": "Notification", + "tableTo": "Status", + "columnsFrom": [ + "statusId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "OpenIdAccount": { + "name": "OpenIdAccount", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "server_id": { + "name": "server_id", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "issuer_id": { + "name": "issuer_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "OpenIdAccount_userId_User_id_fk": { + "name": "OpenIdAccount_userId_User_id_fk", + "tableFrom": "OpenIdAccount", + "tableTo": "User", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "OpenIdLoginFlow": { + "name": "OpenIdLoginFlow", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "code_verifier": { + "name": "code_verifier", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "applicationId": { + "name": "applicationId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "issuer_id": { + "name": "issuer_id", + "type": "text", + "primaryKey": false, + "notNull": true + } + }, + "indexes": {}, + "foreignKeys": { + "OpenIdLoginFlow_applicationId_Application_id_fk": { + "name": "OpenIdLoginFlow_applicationId_Application_id_fk", + "tableFrom": "OpenIdLoginFlow", + "tableTo": "Application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Relationship": { + "name": "Relationship", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "ownerId": { + "name": "ownerId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "subjectId": { + "name": "subjectId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "following": { + "name": "following", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "showing_reblogs": { + "name": "showing_reblogs", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "notifying": { + "name": "notifying", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "followed_by": { + "name": "followed_by", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "blocking": { + "name": "blocking", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "blocked_by": { + "name": "blocked_by", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "muting": { + "name": "muting", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "muting_notifications": { + "name": "muting_notifications", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "requested": { + "name": "requested", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "domain_blocking": { + "name": "domain_blocking", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "endorsed": { + "name": "endorsed", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "languages": { + "name": "languages", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + } + }, + "indexes": {}, + "foreignKeys": { + "Relationship_ownerId_User_id_fk": { + "name": "Relationship_ownerId_User_id_fk", + "tableFrom": "Relationship", + "tableTo": "User", + "columnsFrom": [ + "ownerId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Relationship_subjectId_User_id_fk": { + "name": "Relationship_subjectId_User_id_fk", + "tableFrom": "Relationship", + "tableTo": "User", + "columnsFrom": [ + "subjectId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Status": { + "name": "Status", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "uri": { + "name": "uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "authorId": { + "name": "authorId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "createdAt": { + "name": "createdAt", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updatedAt": { + "name": "updatedAt", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "reblogId": { + "name": "reblogId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "content": { + "name": "content", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "content_type": { + "name": "content_type", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "'text/plain'" + }, + "visibility": { + "name": "visibility", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "inReplyToPostId": { + "name": "inReplyToPostId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "quotingPostId": { + "name": "quotingPostId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "sensitive": { + "name": "sensitive", + "type": "boolean", + "primaryKey": false, + "notNull": true + }, + "spoiler_text": { + "name": "spoiler_text", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "applicationId": { + "name": "applicationId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "content_source": { + "name": "content_source", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + } + }, + "indexes": { + "Status_uri_index": { + "name": "Status_uri_index", + "columns": [ + "uri" + ], + "isUnique": true + } + }, + "foreignKeys": { + "Status_authorId_User_id_fk": { + "name": "Status_authorId_User_id_fk", + "tableFrom": "Status", + "tableTo": "User", + "columnsFrom": [ + "authorId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Status_applicationId_Application_id_fk": { + "name": "Status_applicationId_Application_id_fk", + "tableFrom": "Status", + "tableTo": "Application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "cascade" + }, + "Status_reblogId_Status_id_fk": { + "name": "Status_reblogId_Status_id_fk", + "tableFrom": "Status", + "tableTo": "Status", + "columnsFrom": [ + "reblogId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Status_inReplyToPostId_Status_id_fk": { + "name": "Status_inReplyToPostId_Status_id_fk", + "tableFrom": "Status", + "tableTo": "Status", + "columnsFrom": [ + "inReplyToPostId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "cascade" + }, + "Status_quotingPostId_Status_id_fk": { + "name": "Status_quotingPostId_Status_id_fk", + "tableFrom": "Status", + "tableTo": "Status", + "columnsFrom": [ + "quotingPostId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "set null", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "StatusToMentions": { + "name": "StatusToMentions", + "schema": "", + "columns": { + "statusId": { + "name": "statusId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "StatusToMentions_statusId_userId_index": { + "name": "StatusToMentions_statusId_userId_index", + "columns": [ + "statusId", + "userId" + ], + "isUnique": true + }, + "StatusToMentions_userId_index": { + "name": "StatusToMentions_userId_index", + "columns": [ + "userId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "StatusToMentions_statusId_Status_id_fk": { + "name": "StatusToMentions_statusId_Status_id_fk", + "tableFrom": "StatusToMentions", + "tableTo": "Status", + "columnsFrom": [ + "statusId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "StatusToMentions_userId_User_id_fk": { + "name": "StatusToMentions_userId_User_id_fk", + "tableFrom": "StatusToMentions", + "tableTo": "User", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "Token": { + "name": "Token", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "token_type": { + "name": "token_type", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "scope": { + "name": "scope", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "access_token": { + "name": "access_token", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "code": { + "name": "code", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "applicationId": { + "name": "applicationId", + "type": "uuid", + "primaryKey": false, + "notNull": false + } + }, + "indexes": {}, + "foreignKeys": { + "Token_userId_User_id_fk": { + "name": "Token_userId_User_id_fk", + "tableFrom": "Token", + "tableTo": "User", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "Token_applicationId_Application_id_fk": { + "name": "Token_applicationId_Application_id_fk", + "tableFrom": "Token", + "tableTo": "Application", + "columnsFrom": [ + "applicationId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "User": { + "name": "User", + "schema": "", + "columns": { + "id": { + "name": "id", + "type": "uuid", + "primaryKey": true, + "notNull": true, + "default": "uuid_generate_v7()" + }, + "uri": { + "name": "uri", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "username": { + "name": "username", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "display_name": { + "name": "display_name", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "password": { + "name": "password", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "email": { + "name": "email", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "note": { + "name": "note", + "type": "text", + "primaryKey": false, + "notNull": true, + "default": "''" + }, + "is_admin": { + "name": "is_admin", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "endpoints": { + "name": "endpoints", + "type": "jsonb", + "primaryKey": false, + "notNull": false + }, + "source": { + "name": "source", + "type": "jsonb", + "primaryKey": false, + "notNull": true + }, + "avatar": { + "name": "avatar", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "header": { + "name": "header", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "created_at": { + "name": "created_at", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "updated_at": { + "name": "updated_at", + "type": "timestamp(3)", + "primaryKey": false, + "notNull": true, + "default": "now()" + }, + "is_bot": { + "name": "is_bot", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_locked": { + "name": "is_locked", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "is_discoverable": { + "name": "is_discoverable", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + }, + "sanctions": { + "name": "sanctions", + "type": "text[]", + "primaryKey": false, + "notNull": false + }, + "public_key": { + "name": "public_key", + "type": "text", + "primaryKey": false, + "notNull": true + }, + "private_key": { + "name": "private_key", + "type": "text", + "primaryKey": false, + "notNull": false + }, + "instanceId": { + "name": "instanceId", + "type": "uuid", + "primaryKey": false, + "notNull": false + }, + "disable_automoderation": { + "name": "disable_automoderation", + "type": "boolean", + "primaryKey": false, + "notNull": true, + "default": false + } + }, + "indexes": { + "User_uri_index": { + "name": "User_uri_index", + "columns": [ + "uri" + ], + "isUnique": true + }, + "User_username_index": { + "name": "User_username_index", + "columns": [ + "username" + ], + "isUnique": true + }, + "User_email_index": { + "name": "User_email_index", + "columns": [ + "email" + ], + "isUnique": true + } + }, + "foreignKeys": { + "User_instanceId_Instance_id_fk": { + "name": "User_instanceId_Instance_id_fk", + "tableFrom": "User", + "tableTo": "Instance", + "columnsFrom": [ + "instanceId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + }, + "UserToPinnedNotes": { + "name": "UserToPinnedNotes", + "schema": "", + "columns": { + "userId": { + "name": "userId", + "type": "uuid", + "primaryKey": false, + "notNull": true + }, + "statusId": { + "name": "statusId", + "type": "uuid", + "primaryKey": false, + "notNull": true + } + }, + "indexes": { + "UserToPinnedNotes_userId_statusId_index": { + "name": "UserToPinnedNotes_userId_statusId_index", + "columns": [ + "userId", + "statusId" + ], + "isUnique": true + }, + "UserToPinnedNotes_statusId_index": { + "name": "UserToPinnedNotes_statusId_index", + "columns": [ + "statusId" + ], + "isUnique": false + } + }, + "foreignKeys": { + "UserToPinnedNotes_userId_Status_id_fk": { + "name": "UserToPinnedNotes_userId_Status_id_fk", + "tableFrom": "UserToPinnedNotes", + "tableTo": "Status", + "columnsFrom": [ + "userId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + }, + "UserToPinnedNotes_statusId_User_id_fk": { + "name": "UserToPinnedNotes_statusId_User_id_fk", + "tableFrom": "UserToPinnedNotes", + "tableTo": "User", + "columnsFrom": [ + "statusId" + ], + "columnsTo": [ + "id" + ], + "onDelete": "cascade", + "onUpdate": "cascade" + } + }, + "compositePrimaryKeys": {}, + "uniqueConstraints": {} + } + }, + "enums": {}, + "schemas": {}, + "_meta": { + "columns": {}, + "schemas": {}, + "tables": {} + } +} \ No newline at end of file diff --git a/drizzle/meta/_journal.json b/drizzle/meta/_journal.json index 0f160f1e..879a1e39 100644 --- a/drizzle/meta/_journal.json +++ b/drizzle/meta/_journal.json @@ -1,55 +1,62 @@ { - "version": "5", - "dialect": "pg", - "entries": [ - { - "idx": 0, - "version": "5", - "when": 1712805159664, - "tag": "0000_illegal_living_lightning", - "breakpoints": true - }, - { - "idx": 1, - "version": "5", - "when": 1713055774123, - "tag": "0001_salty_night_thrasher", - "breakpoints": true - }, - { - "idx": 2, - "version": "5", - "when": 1713056370431, - "tag": "0002_stiff_ares", - "breakpoints": true - }, - { - "idx": 3, - "version": "5", - "when": 1713056528340, - "tag": "0003_spicy_arachne", - "breakpoints": true - }, - { - "idx": 4, - "version": "5", - "when": 1713056712218, - "tag": "0004_burly_lockjaw", - "breakpoints": true - }, - { - "idx": 5, - "version": "5", - "when": 1713056917973, - "tag": "0005_sleepy_puma", - "breakpoints": true - }, - { - "idx": 6, - "version": "5", - "when": 1713057159867, - "tag": "0006_messy_network", - "breakpoints": true - } - ] -} + "version": "5", + "dialect": "pg", + "entries": [ + { + "idx": 0, + "version": "5", + "when": 1712805159664, + "tag": "0000_illegal_living_lightning", + "breakpoints": true + }, + { + "idx": 1, + "version": "5", + "when": 1713055774123, + "tag": "0001_salty_night_thrasher", + "breakpoints": true + }, + { + "idx": 2, + "version": "5", + "when": 1713056370431, + "tag": "0002_stiff_ares", + "breakpoints": true + }, + { + "idx": 3, + "version": "5", + "when": 1713056528340, + "tag": "0003_spicy_arachne", + "breakpoints": true + }, + { + "idx": 4, + "version": "5", + "when": 1713056712218, + "tag": "0004_burly_lockjaw", + "breakpoints": true + }, + { + "idx": 5, + "version": "5", + "when": 1713056917973, + "tag": "0005_sleepy_puma", + "breakpoints": true + }, + { + "idx": 6, + "version": "5", + "when": 1713057159867, + "tag": "0006_messy_network", + "breakpoints": true + }, + { + "idx": 7, + "version": "5", + "when": 1713227918208, + "tag": "0007_naive_sleeper", + "breakpoints": true + } + ] +} \ No newline at end of file diff --git a/drizzle/schema.ts b/drizzle/schema.ts index 82ec6fae..63844647 100644 --- a/drizzle/schema.ts +++ b/drizzle/schema.ts @@ -223,10 +223,6 @@ export const status = pgTable( visibility: text("visibility").notNull(), inReplyToPostId: uuid("inReplyToPostId"), quotingPostId: uuid("quotingPostId"), - instanceId: uuid("instanceId").references(() => instance.id, { - onDelete: "cascade", - onUpdate: "cascade", - }), sensitive: boolean("sensitive").notNull(), spoilerText: text("spoiler_text").default("").notNull(), applicationId: uuid("applicationId").references(() => application.id, { @@ -683,7 +679,6 @@ export const emojiRelations = relations(emoji, ({ one, many }) => ({ export const instanceRelations = relations(instance, ({ many }) => ({ users: many(user), - statuses: many(status), emojis: many(emoji), })); diff --git a/server/api/api/v1/instance/index.ts b/server/api/api/v1/instance/index.ts index feee39a1..78d761e2 100644 --- a/server/api/api/v1/instance/index.ts +++ b/server/api/api/v1/instance/index.ts @@ -1,6 +1,6 @@ import { apiRoute, applyConfig } from "@api"; 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 { db } from "~drizzle/db"; import { instance, status, user } from "~drizzle/schema"; @@ -31,7 +31,9 @@ export default apiRoute(async (req, matchedRoute, extraData) => { count: count(), }) .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; const userCount = ( diff --git a/server/api/api/v1/timelines/home.ts b/server/api/api/v1/timelines/home.ts index 1734595e..1c706b14 100644 --- a/server/api/api/v1/timelines/home.ts +++ b/server/api/api/v1/timelines/home.ts @@ -51,10 +51,6 @@ export default apiRoute( ), or( 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 // WHERE format (... = ...) sql`EXISTS (SELECT 1 FROM "StatusToMentions" WHERE "StatusToMentions"."statusId" = ${status.id} AND "StatusToMentions"."userId" = ${user.id})`, diff --git a/server/api/api/v1/timelines/public.test.ts b/server/api/api/v1/timelines/public.test.ts index 68dc2530..7c2fc398 100644 --- a/server/api/api/v1/timelines/public.test.ts +++ b/server/api/api/v1/timelines/public.test.ts @@ -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 () => { test("should send correct Link header", async () => { const response = await sendTestRequest( diff --git a/server/api/api/v1/timelines/public.ts b/server/api/api/v1/timelines/public.ts index 58bda3a4..44ebaa0c 100644 --- a/server/api/api/v1/timelines/public.ts +++ b/server/api/api/v1/timelines/public.ts @@ -50,10 +50,11 @@ export default apiRoute( max_id ? lt(status.id, max_id) : undefined, since_id ? gte(status.id, since_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 - ? isNotNull(status.instanceId) + ? sql`EXISTS (SELECT 1 FROM "User" WHERE "User"."id" = ${status.authorId} AND "User"."instanceId" IS NOT NULL)` : local - ? isNull(status.instanceId) + ? sql`EXISTS (SELECT 1 FROM "User" WHERE "User"."id" = ${status.authorId} AND "User"."instanceId" IS NULL)` : undefined, only_media ? sql`EXISTS (SELECT 1 FROM "Attachment" WHERE "Attachment"."statusId" = ${status.id})`