2021-03-18 04:17:05 +02:00
|
|
|
// https://github.com/typeorm/typeorm/issues/2400
|
|
|
|
const types = require('pg').types;
|
|
|
|
types.setTypeParser(20, Number);
|
|
|
|
|
2019-04-07 15:50:36 +03:00
|
|
|
import { createConnection, Logger, getConnection } from 'typeorm';
|
2021-12-14 11:12:37 +02:00
|
|
|
import * as highlight from 'cli-highlight';
|
2021-08-19 15:55:45 +03:00
|
|
|
import config from '@/config/index';
|
2021-12-14 11:12:37 +02:00
|
|
|
|
2021-08-19 15:55:45 +03:00
|
|
|
import { dbLogger } from './logger';
|
2019-04-07 15:50:36 +03:00
|
|
|
|
2021-08-19 15:55:45 +03:00
|
|
|
import { User } from '@/models/entities/user';
|
|
|
|
import { DriveFile } from '@/models/entities/drive-file';
|
|
|
|
import { DriveFolder } from '@/models/entities/drive-folder';
|
|
|
|
import { AccessToken } from '@/models/entities/access-token';
|
|
|
|
import { App } from '@/models/entities/app';
|
|
|
|
import { PollVote } from '@/models/entities/poll-vote';
|
|
|
|
import { Note } from '@/models/entities/note';
|
|
|
|
import { NoteReaction } from '@/models/entities/note-reaction';
|
|
|
|
import { NoteWatching } from '@/models/entities/note-watching';
|
2021-10-31 08:30:22 +02:00
|
|
|
import { NoteThreadMuting } from '@/models/entities/note-thread-muting';
|
2021-08-19 15:55:45 +03:00
|
|
|
import { NoteUnread } from '@/models/entities/note-unread';
|
|
|
|
import { Notification } from '@/models/entities/notification';
|
|
|
|
import { Meta } from '@/models/entities/meta';
|
|
|
|
import { Following } from '@/models/entities/following';
|
|
|
|
import { Instance } from '@/models/entities/instance';
|
|
|
|
import { Muting } from '@/models/entities/muting';
|
|
|
|
import { SwSubscription } from '@/models/entities/sw-subscription';
|
|
|
|
import { Blocking } from '@/models/entities/blocking';
|
|
|
|
import { UserList } from '@/models/entities/user-list';
|
|
|
|
import { UserListJoining } from '@/models/entities/user-list-joining';
|
|
|
|
import { UserGroup } from '@/models/entities/user-group';
|
|
|
|
import { UserGroupJoining } from '@/models/entities/user-group-joining';
|
|
|
|
import { UserGroupInvitation } from '@/models/entities/user-group-invitation';
|
|
|
|
import { Hashtag } from '@/models/entities/hashtag';
|
|
|
|
import { NoteFavorite } from '@/models/entities/note-favorite';
|
|
|
|
import { AbuseUserReport } from '@/models/entities/abuse-user-report';
|
|
|
|
import { RegistrationTicket } from '@/models/entities/registration-tickets';
|
|
|
|
import { MessagingMessage } from '@/models/entities/messaging-message';
|
|
|
|
import { Signin } from '@/models/entities/signin';
|
|
|
|
import { AuthSession } from '@/models/entities/auth-session';
|
|
|
|
import { FollowRequest } from '@/models/entities/follow-request';
|
|
|
|
import { Emoji } from '@/models/entities/emoji';
|
|
|
|
import { UserNotePining } from '@/models/entities/user-note-pining';
|
|
|
|
import { Poll } from '@/models/entities/poll';
|
|
|
|
import { UserKeypair } from '@/models/entities/user-keypair';
|
|
|
|
import { UserPublickey } from '@/models/entities/user-publickey';
|
|
|
|
import { UserProfile } from '@/models/entities/user-profile';
|
|
|
|
import { UserSecurityKey } from '@/models/entities/user-security-key';
|
|
|
|
import { AttestationChallenge } from '@/models/entities/attestation-challenge';
|
|
|
|
import { Page } from '@/models/entities/page';
|
|
|
|
import { PageLike } from '@/models/entities/page-like';
|
|
|
|
import { GalleryPost } from '@/models/entities/gallery-post';
|
|
|
|
import { GalleryLike } from '@/models/entities/gallery-like';
|
|
|
|
import { ModerationLog } from '@/models/entities/moderation-log';
|
|
|
|
import { UsedUsername } from '@/models/entities/used-username';
|
|
|
|
import { Announcement } from '@/models/entities/announcement';
|
|
|
|
import { AnnouncementRead } from '@/models/entities/announcement-read';
|
|
|
|
import { Clip } from '@/models/entities/clip';
|
|
|
|
import { ClipNote } from '@/models/entities/clip-note';
|
|
|
|
import { Antenna } from '@/models/entities/antenna';
|
|
|
|
import { AntennaNote } from '@/models/entities/antenna-note';
|
|
|
|
import { PromoNote } from '@/models/entities/promo-note';
|
|
|
|
import { PromoRead } from '@/models/entities/promo-read';
|
2021-10-08 15:24:05 +03:00
|
|
|
import { envOption } from '../env';
|
2021-08-19 15:55:45 +03:00
|
|
|
import { Relay } from '@/models/entities/relay';
|
|
|
|
import { MutedNote } from '@/models/entities/muted-note';
|
|
|
|
import { Channel } from '@/models/entities/channel';
|
|
|
|
import { ChannelFollowing } from '@/models/entities/channel-following';
|
|
|
|
import { ChannelNotePining } from '@/models/entities/channel-note-pining';
|
|
|
|
import { RegistryItem } from '@/models/entities/registry-item';
|
|
|
|
import { Ad } from '@/models/entities/ad';
|
|
|
|
import { PasswordResetRequest } from '@/models/entities/password-reset-request';
|
2021-10-08 07:37:02 +03:00
|
|
|
import { UserPending } from '@/models/entities/user-pending';
|
2019-04-07 15:50:36 +03:00
|
|
|
|
2021-12-14 11:12:37 +02:00
|
|
|
import { entities as charts } from '@/services/chart/entities';
|
|
|
|
|
2019-04-07 15:50:36 +03:00
|
|
|
const sqlLogger = dbLogger.createSubLogger('sql', 'white', false);
|
|
|
|
|
|
|
|
class MyCustomLogger implements Logger {
|
|
|
|
private highlight(sql: string) {
|
|
|
|
return highlight.highlight(sql, {
|
|
|
|
language: 'sql', ignoreIllegals: true,
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
public logQuery(query: string, parameters?: any[]) {
|
2021-10-08 15:24:05 +03:00
|
|
|
if (envOption.verbose) {
|
2020-03-29 08:08:19 +03:00
|
|
|
sqlLogger.info(this.highlight(query));
|
|
|
|
}
|
2019-04-07 15:50:36 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
public logQueryError(error: string, query: string, parameters?: any[]) {
|
|
|
|
sqlLogger.error(this.highlight(query));
|
|
|
|
}
|
|
|
|
|
|
|
|
public logQuerySlow(time: number, query: string, parameters?: any[]) {
|
|
|
|
sqlLogger.warn(this.highlight(query));
|
|
|
|
}
|
|
|
|
|
|
|
|
public logSchemaBuild(message: string) {
|
|
|
|
sqlLogger.info(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
public log(message: string) {
|
|
|
|
sqlLogger.info(message);
|
|
|
|
}
|
|
|
|
|
|
|
|
public logMigration(message: string) {
|
|
|
|
sqlLogger.info(message);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-06-29 17:12:00 +03:00
|
|
|
export const entities = [
|
2020-01-29 21:37:25 +02:00
|
|
|
Announcement,
|
|
|
|
AnnouncementRead,
|
2019-06-29 17:12:00 +03:00
|
|
|
Meta,
|
|
|
|
Instance,
|
|
|
|
App,
|
|
|
|
AuthSession,
|
|
|
|
AccessToken,
|
|
|
|
User,
|
|
|
|
UserProfile,
|
|
|
|
UserKeypair,
|
|
|
|
UserPublickey,
|
|
|
|
UserList,
|
|
|
|
UserListJoining,
|
|
|
|
UserGroup,
|
|
|
|
UserGroupJoining,
|
2020-02-12 19:17:54 +02:00
|
|
|
UserGroupInvitation,
|
2019-06-29 17:12:00 +03:00
|
|
|
UserNotePining,
|
2019-07-03 14:18:07 +03:00
|
|
|
UserSecurityKey,
|
2019-07-22 04:15:00 +03:00
|
|
|
UsedUsername,
|
2019-07-03 14:18:07 +03:00
|
|
|
AttestationChallenge,
|
2019-06-29 17:12:00 +03:00
|
|
|
Following,
|
|
|
|
FollowRequest,
|
|
|
|
Muting,
|
|
|
|
Blocking,
|
|
|
|
Note,
|
|
|
|
NoteFavorite,
|
|
|
|
NoteReaction,
|
|
|
|
NoteWatching,
|
2021-10-31 08:30:22 +02:00
|
|
|
NoteThreadMuting,
|
2019-06-29 17:12:00 +03:00
|
|
|
NoteUnread,
|
|
|
|
Page,
|
|
|
|
PageLike,
|
2021-04-24 16:38:24 +03:00
|
|
|
GalleryPost,
|
|
|
|
GalleryLike,
|
2019-06-29 17:12:00 +03:00
|
|
|
DriveFile,
|
|
|
|
DriveFolder,
|
|
|
|
Poll,
|
|
|
|
PollVote,
|
|
|
|
Notification,
|
|
|
|
Emoji,
|
|
|
|
Hashtag,
|
|
|
|
SwSubscription,
|
|
|
|
AbuseUserReport,
|
|
|
|
RegistrationTicket,
|
|
|
|
MessagingMessage,
|
|
|
|
Signin,
|
2019-07-13 21:18:45 +03:00
|
|
|
ModerationLog,
|
2020-01-29 21:37:25 +02:00
|
|
|
Clip,
|
|
|
|
ClipNote,
|
|
|
|
Antenna,
|
|
|
|
AntennaNote,
|
2020-02-18 01:41:32 +02:00
|
|
|
PromoNote,
|
|
|
|
PromoRead,
|
2020-05-10 12:42:31 +03:00
|
|
|
Relay,
|
2020-07-27 07:34:20 +03:00
|
|
|
MutedNote,
|
2020-08-18 16:44:21 +03:00
|
|
|
Channel,
|
|
|
|
ChannelFollowing,
|
|
|
|
ChannelNotePining,
|
2021-01-11 13:38:34 +02:00
|
|
|
RegistryItem,
|
2021-05-04 15:15:57 +03:00
|
|
|
Ad,
|
2021-05-04 09:05:34 +03:00
|
|
|
PasswordResetRequest,
|
2021-10-08 07:37:02 +03:00
|
|
|
UserPending,
|
2021-12-14 11:12:37 +02:00
|
|
|
...charts,
|
2019-06-29 17:12:00 +03:00
|
|
|
];
|
|
|
|
|
2020-03-28 11:28:21 +02:00
|
|
|
export function initDb(justBorrow = false, sync = false, forceRecreate = false) {
|
2020-01-09 07:35:04 +02:00
|
|
|
if (!forceRecreate) {
|
|
|
|
try {
|
|
|
|
const conn = getConnection();
|
|
|
|
return Promise.resolve(conn);
|
|
|
|
} catch (e) {}
|
|
|
|
}
|
2019-04-07 15:50:36 +03:00
|
|
|
|
2020-03-29 08:08:19 +03:00
|
|
|
const log = process.env.NODE_ENV != 'production';
|
2020-03-28 11:28:21 +02:00
|
|
|
|
2019-04-07 15:50:36 +03:00
|
|
|
return createConnection({
|
|
|
|
type: 'postgres',
|
|
|
|
host: config.db.host,
|
|
|
|
port: config.db.port,
|
|
|
|
username: config.db.user,
|
|
|
|
password: config.db.pass,
|
|
|
|
database: config.db.db,
|
2019-05-23 21:26:56 +03:00
|
|
|
extra: config.db.extra,
|
2019-04-07 15:50:36 +03:00
|
|
|
synchronize: process.env.NODE_ENV === 'test' || sync,
|
|
|
|
dropSchema: process.env.NODE_ENV === 'test' && !justBorrow,
|
2019-06-11 14:49:08 +03:00
|
|
|
cache: !config.db.disableCache ? {
|
2019-05-25 02:35:16 +03:00
|
|
|
type: 'redis',
|
|
|
|
options: {
|
|
|
|
host: config.redis.host,
|
|
|
|
port: config.redis.port,
|
2019-07-07 01:59:59 +03:00
|
|
|
password: config.redis.pass,
|
2019-12-14 20:34:11 +02:00
|
|
|
prefix: `${config.redis.prefix}:query:`,
|
2021-12-09 16:58:30 +02:00
|
|
|
db: config.redis.db || 0,
|
|
|
|
},
|
2019-06-11 14:49:08 +03:00
|
|
|
} : false,
|
2019-04-17 10:45:31 +03:00
|
|
|
logging: log,
|
|
|
|
logger: log ? new MyCustomLogger() : undefined,
|
2021-12-09 16:58:30 +02:00
|
|
|
entities: entities,
|
2019-04-07 15:50:36 +03:00
|
|
|
});
|
|
|
|
}
|
2021-08-12 13:05:07 +03:00
|
|
|
|
|
|
|
export async function resetDb() {
|
2021-11-12 06:39:57 +02:00
|
|
|
const reset = async () => {
|
|
|
|
const conn = await getConnection();
|
|
|
|
const tables = await conn.query(`SELECT relname AS "table"
|
|
|
|
FROM pg_class C LEFT JOIN pg_namespace N ON (N.oid = C.relnamespace)
|
|
|
|
WHERE nspname NOT IN ('pg_catalog', 'information_schema')
|
|
|
|
AND C.relkind = 'r'
|
|
|
|
AND nspname !~ '^pg_toast';`);
|
2022-01-21 09:43:56 +02:00
|
|
|
for (const table of tables) {
|
|
|
|
await conn.query(`DELETE FROM "${table.table}" CASCADE`);
|
|
|
|
}
|
2021-11-12 06:39:57 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
for (let i = 1; i <= 3; i++) {
|
|
|
|
try {
|
|
|
|
await reset();
|
|
|
|
} catch (e) {
|
|
|
|
if (i === 3) {
|
|
|
|
throw e;
|
|
|
|
} else {
|
|
|
|
await new Promise(resolve => setTimeout(resolve, 1000));
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
2021-08-12 13:05:07 +03:00
|
|
|
}
|