From e39cecde4735bb0da65e8302104567c95fe7972f Mon Sep 17 00:00:00 2001 From: Antoine Jaussoin Date: Tue, 27 Dec 2022 14:14:39 +0000 Subject: [PATCH] Migration to latest version of TypeOrm (#447) --- .github/workflows/alpha.yml | 2 +- backend/package.json | 17 +-- backend/scripts/create-empty-migration.sh | 2 + backend/scripts/create-migration.sh | 2 + backend/src/db/actions/chat.ts | 2 +- backend/src/db/actions/delete.ts | 8 +- backend/src/db/actions/licences.ts | 5 +- backend/src/db/actions/merge.ts | 8 +- backend/src/db/actions/posts.ts | 35 +++--- backend/src/db/actions/sessions.ts | 106 +++++++++-------- backend/src/db/actions/subscriptions.ts | 20 ++-- backend/src/db/actions/transaction.ts | 5 +- backend/src/db/actions/users.ts | 78 ++++++------ backend/src/db/actions/votes.ts | 18 +-- backend/src/db/index.ts | 9 +- backend/src/db/orm-config.ts | 4 +- backend/src/db/repositories/BaseRepository.ts | 27 +++-- .../src/db/repositories/ColumnRepository.ts | 12 +- .../src/db/repositories/LicenceRepository.ts | 6 +- .../src/db/repositories/MessageRepository.ts | 16 +-- .../db/repositories/PostGroupRepository.ts | 12 +- backend/src/db/repositories/PostRepository.ts | 23 ++-- .../src/db/repositories/SessionRepository.ts | 20 ++-- .../repositories/SessionTemplateRepository.ts | 18 ++- .../db/repositories/SubscriptionRepository.ts | 27 +++-- .../repositories/TemplateColumnRepository.ts | 10 +- .../db/repositories/UserIdentityRepository.ts | 8 +- backend/src/db/repositories/UserRepository.ts | 20 ++-- backend/src/db/repositories/VoteRepository.ts | 10 +- backend/tsconfig.json | 2 +- backend/yarn.lock | 112 +++++++++--------- 31 files changed, 329 insertions(+), 315 deletions(-) create mode 100755 backend/scripts/create-empty-migration.sh create mode 100755 backend/scripts/create-migration.sh diff --git a/.github/workflows/alpha.yml b/.github/workflows/alpha.yml index 0b8beafed..1f74b8148 100644 --- a/.github/workflows/alpha.yml +++ b/.github/workflows/alpha.yml @@ -2,7 +2,7 @@ name: 'Alpha Build' on: push: - branches: [v4180/deps2] + branches: [v4190/typeorm] jobs: build: diff --git a/backend/package.json b/backend/package.json index dc2636338..755d74207 100644 --- a/backend/package.json +++ b/backend/package.json @@ -6,16 +6,16 @@ "scripts": { "build": "rimraf dist && tsc --build && yarn copy-templates", "start": "nodemon --exec 'yarn fix & ts-node' --files ./src/index.ts", - "create-migration": "ts-node ./node_modules/typeorm/cli.js --config src/db/orm-config.ts migration:generate -n ", - "create-empty-migration": "ts-node ./node_modules/typeorm/cli.js --config src/db/orm-config.ts migration:create -n ", - "migrate": "ts-node ./node_modules/typeorm/cli.js --config src/db/orm-config.ts migration:run", - "revert": "ts-node ./node_modules/typeorm/cli.js --config src/db/orm-config.ts migration:revert", + "create-migration": "scripty", + "create-empty-migration": "scripty", + "migrate": "typeorm-ts-node-commonjs -d src/db/index.ts migration:run", + "revert": "typeorm-ts-node-commonjs -d src/db/index.ts migration:revert", "lint": "eslint 'src/**/*.ts'", "test": "yarn jest", "ci-test": "CI=true yarn test", "fix": "eslint 'src/**/*.ts' --fix", "backend-production": "yarn migrate-production && cd ./dist/src && node index.js", - "migrate-production": "node ./node_modules/typeorm/cli.js --config dist/src/db/orm-config.js migration:run", + "migrate-production": "typeorm -d dist/src/db/index.js migration:run", "copy-templates": "copyfiles -u 0 src/**/*.html dist/" }, "dependencies": { @@ -80,15 +80,16 @@ "rate-limiter-flexible": "2.4.1", "redis": "3.1.2", "rimraf": "3.0.2", + "scripty": "^2.1.1", "shortid": "2.2.16", "socket.io": "4.5.4", "socket.io-redis": "6.1.1", "stripe": "11.1.0", "ts-jest": "29.0.3", "ts-node": "10.9.1", - "typeorm": "0.2.45", - "typeorm-naming-strategies": "3.0.0", - "typescript": "4.9.3", + "typeorm": "0.3.11", + "typeorm-naming-strategies": "4.1.0", + "typescript": "4.9.4", "uuid": "9.0.0" }, "resolutions": { diff --git a/backend/scripts/create-empty-migration.sh b/backend/scripts/create-empty-migration.sh new file mode 100755 index 000000000..01353d5bd --- /dev/null +++ b/backend/scripts/create-empty-migration.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +./node_modules/.bin/typeorm-ts-node-commonjs migration:create src/db/migrations/$1 \ No newline at end of file diff --git a/backend/scripts/create-migration.sh b/backend/scripts/create-migration.sh new file mode 100755 index 000000000..4bd7ce51b --- /dev/null +++ b/backend/scripts/create-migration.sh @@ -0,0 +1,2 @@ +#!/usr/bin/env sh +./node_modules/.bin/typeorm-ts-node-commonjs -d src/db/index.ts migration:generate src/db/migrations/$1 \ No newline at end of file diff --git a/backend/src/db/actions/chat.ts b/backend/src/db/actions/chat.ts index 3a7fc73b9..77ebdfc16 100644 --- a/backend/src/db/actions/chat.ts +++ b/backend/src/db/actions/chat.ts @@ -8,7 +8,7 @@ export async function saveChatMessage( message: Message ): Promise { return await transaction(async (manager) => { - const postRepository = manager.getCustomRepository(MessageRepository); + const postRepository = manager.withRepository(MessageRepository); const entity = await postRepository.saveFromJson( sessionId, userId, diff --git a/backend/src/db/actions/delete.ts b/backend/src/db/actions/delete.ts index f53f3ca1a..4abcc7ec7 100644 --- a/backend/src/db/actions/delete.ts +++ b/backend/src/db/actions/delete.ts @@ -69,7 +69,7 @@ async function delVotes( user: UserView, anon: UserIdentityEntity ) { - const repo = manager.getCustomRepository(VoteRepository); + const repo = manager.withRepository(VoteRepository); if (hardDelete) { await repo.delete({ user: { id: user.id } }); return true; @@ -85,8 +85,8 @@ async function delPosts( user: UserView, anon: UserIdentityEntity ) { - const repo = manager.getCustomRepository(PostRepository); - const groupRepo = manager.getCustomRepository(PostGroupRepository); + const repo = manager.withRepository(PostRepository); + const groupRepo = manager.withRepository(PostGroupRepository); if (hardDelete) { await manager.query( ` @@ -116,7 +116,7 @@ async function delSessions( user: UserView, anon: UserIdentityEntity ) { - const repo = manager.getCustomRepository(SessionRepository); + const repo = manager.withRepository(SessionRepository); if (hardDelete) { await manager.query( ` diff --git a/backend/src/db/actions/licences.ts b/backend/src/db/actions/licences.ts index 345bead59..b05cf5706 100644 --- a/backend/src/db/actions/licences.ts +++ b/backend/src/db/actions/licences.ts @@ -4,6 +4,7 @@ import { v4 } from 'uuid'; import { sendSelfHostWelcome } from '../../email/emailSender'; import { LicenceRepository } from '../repositories'; import { LicenceMetadata } from './../../types'; +import { saveAndReload } from '../repositories/BaseRepository'; export async function registerLicence( email: string | null, @@ -12,11 +13,11 @@ export async function registerLicence( sessionId: string ): Promise { return await transaction(async (manager) => { - const repository = manager.getCustomRepository(LicenceRepository); + const repository = manager.withRepository(LicenceRepository); const key = v4(); const licence = new LicenceEntity(v4(), email, key, customerId, sessionId); try { - const savedLicence = await repository.saveAndReload(licence); + const savedLicence = await saveAndReload(repository, licence); if (savedLicence) { if (email) { await sendSelfHostWelcome(email, name || '', key); diff --git a/backend/src/db/actions/merge.ts b/backend/src/db/actions/merge.ts index 6f3ee693f..acfba6ea2 100644 --- a/backend/src/db/actions/merge.ts +++ b/backend/src/db/actions/merge.ts @@ -58,10 +58,10 @@ async function migrateOne(main: UserView, target: UserView) { ` > Migrating data from ${target.id} (${target.name}) to ${main.id} (${main.name})` ); return await transaction(async (manager) => { - const voteRepo = manager.getCustomRepository(VoteRepository); - const postRepo = manager.getCustomRepository(PostRepository); - const groupRepo = manager.getCustomRepository(PostGroupRepository); - const sessionRepo = manager.getCustomRepository(SessionRepository); + const voteRepo = manager.withRepository(VoteRepository); + const postRepo = manager.withRepository(PostRepository); + const groupRepo = manager.withRepository(PostGroupRepository); + const sessionRepo = manager.withRepository(SessionRepository); await manager.query('update messages set user_id = $1 where user_id = $2', [ main.id, diff --git a/backend/src/db/actions/posts.ts b/backend/src/db/actions/posts.ts index 8147a01f7..ea3013c09 100644 --- a/backend/src/db/actions/posts.ts +++ b/backend/src/db/actions/posts.ts @@ -9,7 +9,7 @@ import { transaction } from './transaction'; export async function getNumberOfPosts(userId: string): Promise { return await transaction(async (manager) => { - const postRepository = manager.getCustomRepository(PostRepository); + const postRepository = manager.withRepository(PostRepository); return await postRepository.count({ where: { user: { id: userId } } }); }); } @@ -20,7 +20,7 @@ export async function savePost( post: Post ): Promise { return await transaction(async (manager) => { - const postRepository = manager.getCustomRepository(PostRepository); + const postRepository = manager.withRepository(PostRepository); const entity = await postRepository.saveFromJson(sessionId, userId, post); if (entity) { return entity.toJson(); @@ -36,9 +36,12 @@ export async function updatePost( groupId: string | null ): Promise { return await transaction(async (manager) => { - const postRepository = manager.getCustomRepository(PostRepository); - const entity = await postRepository.findOne(postData.id, { - where: { session: { id: sessionId } }, + const postRepository = manager.withRepository(PostRepository); + const entity = await postRepository.findOne({ + where: { + id: postData.id, + session: { id: sessionId }, + }, }); if (entity) { const post = entity.toJson(); @@ -62,8 +65,7 @@ export async function savePostGroup( group: PostGroup ): Promise { return await transaction(async (manager) => { - const postGroupRepository = - manager.getCustomRepository(PostGroupRepository); + const postGroupRepository = manager.withRepository(PostGroupRepository); const entity = await postGroupRepository.saveFromJson( sessionId, userId, @@ -82,10 +84,9 @@ export async function updatePostGroup( groupData: Omit, 'posts'> ) { return await transaction(async (manager) => { - const postGroupRepository = - manager.getCustomRepository(PostGroupRepository); - const entity = await postGroupRepository.findOne(groupData.id, { - where: { session: { id: sessionId } }, + const postGroupRepository = manager.withRepository(PostGroupRepository); + const entity = await postGroupRepository.findOne({ + where: { id: groupData.id, session: { id: sessionId } }, }); if (entity) { const group = entity.toJson(); @@ -111,7 +112,7 @@ export async function saveVote( vote: Vote ): Promise { return await transaction(async (manager) => { - const voteRepository = manager.getCustomRepository(VoteRepository); + const voteRepository = manager.withRepository(VoteRepository); await voteRepository.saveFromJson(postId, userId, vote); }); } @@ -123,7 +124,7 @@ export async function deletePost( ): Promise { return await transaction(async (manager) => { try { - const postRepository = manager.getCustomRepository(PostRepository); + const postRepository = manager.withRepository(PostRepository); const result = await postRepository.delete({ id: postId, user: { id: userId }, @@ -142,10 +143,10 @@ export async function deletePostGroup( ): Promise { return await transaction(async (manager) => { try { - const postGroupRepository = - manager.getCustomRepository(PostGroupRepository); - const sessionRepository = manager.getCustomRepository(SessionRepository); - const session = await sessionRepository.findOne(sessionId, { + const postGroupRepository = manager.withRepository(PostGroupRepository); + const sessionRepository = manager.withRepository(SessionRepository); + const session = await sessionRepository.findOne({ + where: { id: sessionId }, relations: ['visitors'], }); if ( diff --git a/backend/src/db/actions/sessions.ts b/backend/src/db/actions/sessions.ts index eb89e4f0b..88db81bad 100644 --- a/backend/src/db/actions/sessions.ts +++ b/backend/src/db/actions/sessions.ts @@ -38,7 +38,7 @@ export async function createSessionFromSlack( name: string ): Promise { return await transaction(async (manager) => { - const userRepository = manager.getCustomRepository(UserRepository); + const userRepository = manager.withRepository(UserRepository); const users = await userRepository.find({ where: { slackUserId } }); if (!users.length) { return null; @@ -56,13 +56,13 @@ export async function createSession( encryptionCheck?: string ): Promise { return await transaction(async (manager) => { - const userRepository = manager.getCustomRepository(UserRepository); - const sessionRepository = manager.getCustomRepository(SessionRepository); + const userRepository = manager.withRepository(UserRepository); + const sessionRepository = manager.withRepository(SessionRepository); const id = shortId(); - const userWithDefaultTemplate = await userRepository.findOne( - { id: author.id }, - { relations: ['defaultTemplate', 'defaultTemplate.columns'] } - ); + const userWithDefaultTemplate = await userRepository.findOne({ + where: { id: author.id }, + relations: ['defaultTemplate', 'defaultTemplate.columns'], + }); if (userWithDefaultTemplate?.defaultTemplate) { const template = userWithDefaultTemplate.defaultTemplate; const newSession = await sessionRepository.saveFromJson( @@ -112,13 +112,13 @@ export async function createCustom( author: UserEntity ): Promise { return await transaction(async (manager) => { - const userRepository = manager.getCustomRepository(UserRepository); - const sessionRepository = manager.getCustomRepository(SessionRepository); - const templateRepository = manager.getCustomRepository( + const userRepository = manager.withRepository(UserRepository); + const sessionRepository = manager.withRepository(SessionRepository); + const templateRepository = manager.withRepository( SessionTemplateRepository ); const id = shortId(); - const session = await sessionRepository.findOne({ id }); + const session = await sessionRepository.findOne({ where: { id } }); if (!session) { const newSession = await sessionRepository.saveFromJson( { @@ -149,36 +149,37 @@ export async function createCustom( export async function doesSessionExists(sessionId: string): Promise { return await transaction(async (manager) => { - const sessionRepository = manager.getCustomRepository(SessionRepository); + const sessionRepository = manager.withRepository(SessionRepository); return (await sessionRepository.count({ where: { id: sessionId } })) === 1; }); } export async function getSession(sessionId: string): Promise { return await transaction(async (manager) => { - const postRepository = manager.getCustomRepository(PostRepository); - const postGroupRepository = - manager.getCustomRepository(PostGroupRepository); - const sessionRepository = manager.getCustomRepository(SessionRepository); - const columnRepository = manager.getCustomRepository(ColumnRepository); - const messageRepository = manager.getCustomRepository(MessageRepository); - - const session = await sessionRepository.findOne({ id: sessionId }); + const postRepository = manager.withRepository(PostRepository); + const postGroupRepository = manager.withRepository(PostGroupRepository); + const sessionRepository = manager.withRepository(SessionRepository); + const columnRepository = manager.withRepository(ColumnRepository); + const messageRepository = manager.withRepository(MessageRepository); + + const session = await sessionRepository.findOne({ + where: { id: sessionId }, + }); if (session) { const posts = (await postRepository.find({ - where: { session }, + where: { session: { id: session.id } }, order: { created: 'ASC' }, })) as PostEntity[]; const groups = (await postGroupRepository.find({ - where: { session }, + where: { session: { id: session.id } }, order: { created: 'ASC' }, })) as PostGroupEntity[]; const columns = (await columnRepository.find({ - where: { session }, + where: { session: { id: session.id } }, order: { index: 'ASC' }, })) as ColumnDefinitionEntity[]; const messages = (await messageRepository.find({ - where: { session }, + where: { session: { id: session.id } }, order: { created: 'DESC' }, })) as MessageEntity[]; return { @@ -199,7 +200,7 @@ export async function saveSession( session: Session ): Promise { return await transaction(async (manager) => { - const sessionRepository = manager.getCustomRepository(SessionRepository); + const sessionRepository = manager.withRepository(SessionRepository); await sessionRepository.saveFromJson(session, userId); }); } @@ -209,8 +210,10 @@ export async function deleteSessions( sessionId: string ): Promise { return await transaction(async (manager) => { - const sessionRepository = manager.getCustomRepository(SessionRepository); - const session = await sessionRepository.findOne(sessionId); + const sessionRepository = manager.withRepository(SessionRepository); + const session = await sessionRepository.findOne({ + where: { id: sessionId }, + }); const user = await getUserViewInner(manager, identityId); if (!user) { console.info('Identity not found', identityId); @@ -297,11 +300,11 @@ export async function getDefaultTemplate( id: string ): Promise { return await transaction(async (manager) => { - const userRepository = manager.getCustomRepository(UserRepository); - const userWithDefaultTemplate = await userRepository.findOne( - { id }, - { relations: ['defaultTemplate', 'defaultTemplate.columns'] } - ); + const userRepository = manager.withRepository(UserRepository); + const userWithDefaultTemplate = await userRepository.findOne({ + where: { id }, + relations: ['defaultTemplate', 'defaultTemplate.columns'], + }); return userWithDefaultTemplate?.defaultTemplate || null; }); } @@ -311,7 +314,7 @@ export async function updateOptions( options: SessionOptions ): Promise { return await transaction(async (manager) => { - const sessionRepository = manager.getCustomRepository(SessionRepository); + const sessionRepository = manager.withRepository(SessionRepository); return await sessionRepository.updateOptions(sessionId, options); }); } @@ -321,7 +324,7 @@ export async function updateColumns( columns: ColumnDefinition[] ): Promise { return await transaction(async (manager) => { - const columnRepository = manager.getCustomRepository(ColumnRepository); + const columnRepository = manager.withRepository(ColumnRepository); return await columnRepository.updateColumns(sessionId, columns); }); } @@ -332,8 +335,8 @@ export async function saveTemplate( options: SessionOptions ) { return await transaction(async (manager) => { - const userRepository = manager.getCustomRepository(UserRepository); - const templateRepository = manager.getCustomRepository( + const userRepository = manager.withRepository(UserRepository); + const templateRepository = manager.withRepository( SessionTemplateRepository ); @@ -353,8 +356,10 @@ export async function updateName( ): Promise { return await transaction(async (manager) => { try { - const sessionRepository = manager.getCustomRepository(SessionRepository); - const session = await sessionRepository.findOne(sessionId); + const sessionRepository = manager.withRepository(SessionRepository); + const session = await sessionRepository.findOne({ + where: { id: sessionId }, + }); if (session) { session.name = name; await sessionRepository.save(session); @@ -379,8 +384,9 @@ async function getSessionWithVisitorsInner( manager: EntityManager, sessionId: string ): Promise { - const sessionRepository = manager.getCustomRepository(SessionRepository); - const session = await sessionRepository.findOne(sessionId, { + const sessionRepository = manager.withRepository(SessionRepository); + const session = await sessionRepository.findOne({ + where: { id: sessionId }, relations: ['visitors'], }); return session || null; @@ -397,7 +403,7 @@ async function storeVisitorInner( sessionId: string, user: UserEntity ) { - const sessionRepository = manager.getCustomRepository(SessionRepository); + const sessionRepository = manager.withRepository(SessionRepository); const session = await getSessionWithVisitorsInner(manager, sessionId); if ( session && @@ -411,8 +417,10 @@ async function storeVisitorInner( export async function toggleSessionLock(sessionId: string, lock: boolean) { return await transaction(async (manager) => { - const sessionRepository = manager.getCustomRepository(SessionRepository); - const session = await sessionRepository.findOne(sessionId); + const sessionRepository = manager.withRepository(SessionRepository); + const session = await sessionRepository.findOne({ + where: { id: sessionId }, + }); if (session) { session.locked = lock; await sessionRepository.save(session); @@ -425,8 +433,10 @@ export async function wasSessionCreatedBy( userId: string ): Promise { return await transaction(async (manager) => { - const sessionRepository = manager.getCustomRepository(SessionRepository); - const session = await sessionRepository.findOne(sessionId); + const sessionRepository = manager.withRepository(SessionRepository); + const session = await sessionRepository.findOne({ + where: { id: sessionId }, + }); return !!session && session.createdBy.id === userId; }); } @@ -462,8 +472,10 @@ export async function toggleReady( userId: string ): Promise { return await transaction(async (manager) => { - const sessionRepository = manager.getCustomRepository(SessionRepository); - const session = await sessionRepository.findOne(sessionId); + const sessionRepository = manager.withRepository(SessionRepository); + const session = await sessionRepository.findOne({ + where: { id: sessionId }, + }); if (!session) { return false; } diff --git a/backend/src/db/actions/subscriptions.ts b/backend/src/db/actions/subscriptions.ts index 304a8d36f..d049ff6c6 100644 --- a/backend/src/db/actions/subscriptions.ts +++ b/backend/src/db/actions/subscriptions.ts @@ -12,11 +12,11 @@ export async function activateSubscription( currency: Currency ): Promise { return await transaction(async (manager) => { - const userRepository = manager.getCustomRepository(UserRepository); - const subscriptionRepository = manager.getCustomRepository( + const userRepository = manager.withRepository(UserRepository); + const subscriptionRepository = manager.withRepository( SubscriptionRepository ); - const user = await userRepository.findOne(userId); + const user = await userRepository.findOne({ where: { id: userId } }); if (!user) { throw Error('Cannot activate subscription on a non existing user'); } @@ -36,7 +36,7 @@ export async function cancelSubscription( stripeSubscriptionId: string ): Promise { return await transaction(async (manager) => { - const subscriptionRepository = manager.getCustomRepository( + const subscriptionRepository = manager.withRepository( SubscriptionRepository ); try { @@ -55,7 +55,7 @@ export async function getActiveSubscriptionWhereUserIsOwner( userId: string ): Promise { return await transaction(async (manager) => { - const subscriptionRepository = manager.getCustomRepository( + const subscriptionRepository = manager.withRepository( SubscriptionRepository ); const subscriptions = await subscriptionRepository.find({ @@ -81,7 +81,7 @@ export async function getActiveSubscriptionWhereUserIsAdmin( email: string | null ): Promise { return await transaction(async (manager) => { - const subscriptionRepository = manager.getCustomRepository( + const subscriptionRepository = manager.withRepository( SubscriptionRepository ); @@ -110,7 +110,7 @@ export async function saveSubscription( subscription: SubscriptionEntity ): Promise { return await transaction(async (manager) => { - const subscriptionRepository = manager.getCustomRepository( + const subscriptionRepository = manager.withRepository( SubscriptionRepository ); await subscriptionRepository.save(subscription); @@ -120,9 +120,11 @@ export async function saveSubscription( export async function startTrial(userId: string): Promise { return await transaction(async (manager) => { const userViewRepository = manager.getRepository(UserView); - const fullUser = await userViewRepository.findOne({ id: userId }); + const fullUser = await userViewRepository.findOne({ + where: { id: userId }, + }); if (fullUser) { - const userRepository = manager.getCustomRepository(UserRepository); + const userRepository = manager.withRepository(UserRepository); const user = await userRepository.startTrial(fullUser); return user; } diff --git a/backend/src/db/actions/transaction.ts b/backend/src/db/actions/transaction.ts index 19828013a..b17dc6d90 100644 --- a/backend/src/db/actions/transaction.ts +++ b/backend/src/db/actions/transaction.ts @@ -1,9 +1,10 @@ -import { EntityManager, getConnection } from 'typeorm'; +import { dataSource } from '../index'; +import { EntityManager } from 'typeorm'; type Inner = (manager: EntityManager) => Promise; export async function transaction(cb: Inner): Promise { - return await getConnection().transaction(async (manager) => { + return await dataSource.transaction(async (manager) => { return cb(manager); }); } diff --git a/backend/src/db/actions/users.ts b/backend/src/db/actions/users.ts index 7507229f1..1b1e055c5 100644 --- a/backend/src/db/actions/users.ts +++ b/backend/src/db/actions/users.ts @@ -9,6 +9,7 @@ import { isSelfHostedAndLicenced } from '../../security/is-licenced'; import { v4 } from 'uuid'; import UserIdentityEntity from '../entities/UserIdentity'; import { comparePassword, hashPassword } from '../../utils'; +import { saveAndReload } from '../repositories/BaseRepository'; export async function getUser(userId: string): Promise { return await transaction(async (manager) => { @@ -38,8 +39,11 @@ async function getUserInner( manager: EntityManager, userId: string ): Promise { - const userRepository = manager.getCustomRepository(UserRepository); - const user = await userRepository.findOne(userId, { select: ALL_FIELDS }); + const userRepository = manager.withRepository(UserRepository); + const user = await userRepository.findOne({ + select: ALL_FIELDS, + where: { id: userId }, + }); return user || null; } @@ -47,11 +51,12 @@ async function getIdentityInner( manager: EntityManager, identityId: string ): Promise { - const identityRepository = manager.getCustomRepository( - UserIdentityRepository - ); - const user = await identityRepository.findOne(identityId, { + const identityRepository = manager.withRepository(UserIdentityRepository); + const user = await identityRepository.findOne({ select: ALL_FIELDS_IDENTITY, + where: { + id: identityId, + }, }); return user || null; } @@ -69,7 +74,7 @@ export async function getUserViewInner( identityId: string ): Promise { const userViewRepository = manager.getRepository(UserView); - const user = await userViewRepository.findOne({ identityId }); + const user = await userViewRepository.findOne({ where: { identityId } }); // All users are pro if self-hosted and licenced if (user && isSelfHostedAndLicenced()) { user.pro = true; @@ -81,12 +86,9 @@ export async function getPasswordIdentity( username: string ): Promise { return await transaction(async (manager) => { - const identityRepository = manager.getCustomRepository( - UserIdentityRepository - ); + const identityRepository = manager.withRepository(UserIdentityRepository); const identity = await identityRepository.findOne({ - username, - accountType: 'password', + where: { username, accountType: 'password' }, }); return identity || null; }); @@ -96,12 +98,9 @@ export async function getPasswordIdentityByUserId( userId: string ): Promise { return await transaction(async (manager) => { - const identityRepository = manager.getCustomRepository( - UserIdentityRepository - ); + const identityRepository = manager.withRepository(UserIdentityRepository); const identity = await identityRepository.findOne({ - user: { id: userId }, - accountType: 'password', + where: { user: { id: userId }, accountType: 'password' }, }); return identity || null; }); @@ -111,10 +110,8 @@ export async function getUserByUsername( username: string ): Promise { return await transaction(async (manager) => { - const identityRepository = manager.getCustomRepository( - UserIdentityRepository - ); - const identity = await identityRepository.findOne({ username }); + const identityRepository = manager.withRepository(UserIdentityRepository); + const identity = await identityRepository.findOne({ where: { username } }); return identity ? identity.user : null; }); } @@ -125,9 +122,7 @@ export async function updateIdentity( ): Promise { return await transaction(async (manager) => { try { - const identityRepository = manager.getCustomRepository( - UserIdentityRepository - ); + const identityRepository = manager.withRepository(UserIdentityRepository); await identityRepository.update(identityId, updatedIdentity); const newUser = await getUserViewInner(manager, identityId); return newUser || null; @@ -143,7 +138,7 @@ export async function updateUser( updatedUser: Partial ): Promise { return await transaction(async (manager) => { - const userRepository = manager.getCustomRepository(UserRepository); + const userRepository = manager.withRepository(UserRepository); const user = await getUserInner(manager, userId); if (user) { const result = await userRepository.update(userId, updatedUser); @@ -158,7 +153,7 @@ export async function getIdentityByUsername( username: string ): Promise { return await transaction(async (manager) => { - const repo = manager.getCustomRepository(UserIdentityRepository); + const repo = manager.withRepository(UserIdentityRepository); const identity = await repo.findOne({ where: { accountType, username }, }); @@ -186,10 +181,8 @@ export async function registerUser( registration: UserRegistration ): Promise { return await transaction(async (manager) => { - const userRepository = manager.getCustomRepository(UserRepository); - const identityRepository = manager.getCustomRepository( - UserIdentityRepository - ); + const userRepository = manager.withRepository(UserRepository); + const identityRepository = manager.withRepository(UserIdentityRepository); const [identity, existing] = await getOrCreateIdentity( manager, @@ -227,15 +220,12 @@ export async function registerAnonymousUser( password: string ): Promise { return await transaction(async (manager) => { - const userRepository = manager.getCustomRepository(UserRepository); - const identityRepository = manager.getCustomRepository( - UserIdentityRepository - ); + const userRepository = manager.withRepository(UserRepository); + const identityRepository = manager.withRepository(UserIdentityRepository); const actualUsername = username.split('^')[0]; const existingIdentity = await identityRepository.findOne({ - username, - accountType: 'anonymous', + where: { username, accountType: 'anonymous' }, }); if (!existingIdentity) { @@ -275,9 +265,7 @@ async function getOrCreateIdentity( email: string, accountType: AccountType ): Promise<[identity: UserIdentityEntity, existing: boolean]> { - const identityRepository = manager.getCustomRepository( - UserIdentityRepository - ); + const identityRepository = manager.withRepository(UserIdentityRepository); const identities = await identityRepository.find({ where: { username, accountType }, }); @@ -304,7 +292,7 @@ async function getOrCreateUser( manager: EntityManager, email: string ): Promise<[identity: UserEntity, existing: boolean]> { - const userRepository = manager.getCustomRepository(UserRepository); + const userRepository = manager.withRepository(UserRepository); const existingUser = await userRepository.findOne({ where: { email }, }); @@ -313,7 +301,7 @@ async function getOrCreateUser( } const user = new UserEntity(v4(), ''); user.email = email; - const savedUser = await userRepository.saveAndReload(user); + const savedUser = await saveAndReload(userRepository, user); return [savedUser, false]; } @@ -323,10 +311,12 @@ async function updateUserPassword( identityId: string, password: string ): Promise { - const identityRepo = manager.getCustomRepository(UserIdentityRepository); - const existingUser = await identityRepo.findOne(identityId); + const identityRepo = manager.withRepository(UserIdentityRepository); + const existingUser = await identityRepo.findOne({ + where: { id: identityId }, + }); if (existingUser) { - return await identityRepo.saveAndReload({ + return await saveAndReload(identityRepo, { ...existingUser, password, }); diff --git a/backend/src/db/actions/votes.ts b/backend/src/db/actions/votes.ts index 1eb2ac3d5..15a04d7ed 100644 --- a/backend/src/db/actions/votes.ts +++ b/backend/src/db/actions/votes.ts @@ -16,15 +16,17 @@ export async function registerVote( type: VoteType ): Promise { return await transaction(async (manager) => { - const sessionRepository = manager.getCustomRepository(SessionRepository); - const userRepository = manager.getCustomRepository(UserRepository); - const voteRepository = manager.getCustomRepository(VoteRepository); - const postRepository = manager.getCustomRepository(PostRepository); - const user = await userRepository.findOne(userId); - const post = await postRepository.findOne(postId, { - where: { session: { id: sessionId } }, + const sessionRepository = manager.withRepository(SessionRepository); + const userRepository = manager.withRepository(UserRepository); + const voteRepository = manager.withRepository(VoteRepository); + const postRepository = manager.withRepository(PostRepository); + const user = await userRepository.findOne({ where: { id: userId } }); + const post = await postRepository.findOne({ + where: { id: postId, session: { id: sessionId } }, + }); + const session = await sessionRepository.findOne({ + where: { id: sessionId }, }); - const session = await sessionRepository.findOne(sessionId); if (post && session && user) { const existingVote: Vote | undefined = find( post.votes, diff --git a/backend/src/db/index.ts b/backend/src/db/index.ts index 50adacd35..73b099337 100644 --- a/backend/src/db/index.ts +++ b/backend/src/db/index.ts @@ -1,9 +1,12 @@ import 'reflect-metadata'; import chalk from 'chalk'; -import { createConnection } from 'typeorm'; +import { DataSource } from 'typeorm'; import ormConfig from './orm-config'; -export default async function getDb(): Promise { +export const dataSource = new DataSource(ormConfig); + +export default async function getDb(): Promise { console.log(chalk`{yellow 💻 Using {red Postgres} database}`); - await createConnection(ormConfig); + await dataSource.initialize(); + return dataSource; } diff --git a/backend/src/db/orm-config.ts b/backend/src/db/orm-config.ts index c9a5ad522..251ceda91 100644 --- a/backend/src/db/orm-config.ts +++ b/backend/src/db/orm-config.ts @@ -1,5 +1,5 @@ import config from '../config'; -import { ConnectionOptions } from 'typeorm'; +import { DataSourceOptions } from 'typeorm'; import { PostEntity, PostGroupEntity, @@ -61,4 +61,4 @@ export default { cli: { migrationsDir: getMigrationsDirectory(), }, -} as ConnectionOptions; +} as DataSourceOptions; diff --git a/backend/src/db/repositories/BaseRepository.ts b/backend/src/db/repositories/BaseRepository.ts index 9a38a53f6..f971117d4 100644 --- a/backend/src/db/repositories/BaseRepository.ts +++ b/backend/src/db/repositories/BaseRepository.ts @@ -1,13 +1,20 @@ -import { DeepPartial, Repository, SaveOptions } from 'typeorm'; +import { DeepPartial, EntityTarget, Repository, SaveOptions } from 'typeorm'; import { Entity } from '../../common'; +import { dataSource } from '../index'; -export default class BaseRepository extends Repository { - async saveAndReload( - entity: DeepPartial, - options?: SaveOptions - ): Promise { - const saved = await this.save(entity, options); - const reloaded = await this.findOne(saved.id); - return reloaded!; - } +export async function saveAndReload( + repo: Repository, + entity: DeepPartial, + options?: SaveOptions +): Promise { + const saved = await repo.save(entity, options); + // eslint-disable-next-line @typescript-eslint/no-explicit-any + const reloaded = await repo.findOne({ where: { id: saved.id as any } }); + return reloaded!; } + +export function getBaseRepository(entity: EntityTarget) { + return dataSource.getRepository(entity); +} + +export default class BaseRepository extends Repository {} diff --git a/backend/src/db/repositories/ColumnRepository.ts b/backend/src/db/repositories/ColumnRepository.ts index 09c753bdc..efcc31073 100644 --- a/backend/src/db/repositories/ColumnRepository.ts +++ b/backend/src/db/repositories/ColumnRepository.ts @@ -1,11 +1,9 @@ -import { EntityRepository } from 'typeorm'; import { ColumnDefinitionEntity } from '../entities'; import { ColumnDefinition as JsonColumnDefinition } from '../../common'; import { v4 } from 'uuid'; -import BaseRepository from './BaseRepository'; +import { getBaseRepository } from './BaseRepository'; -@EntityRepository(ColumnDefinitionEntity) -export default class ColumnDefinitionRepository extends BaseRepository { +export default getBaseRepository(ColumnDefinitionEntity).extend({ async saveFromJson( colDef: JsonColumnDefinition, sessionId: string @@ -22,7 +20,7 @@ export default class ColumnDefinitionRepository extends BaseRepository {} +export default getBaseRepository(LicenceEntity).extend({}); diff --git a/backend/src/db/repositories/MessageRepository.ts b/backend/src/db/repositories/MessageRepository.ts index 45f3fce3c..2f38c20a3 100644 --- a/backend/src/db/repositories/MessageRepository.ts +++ b/backend/src/db/repositories/MessageRepository.ts @@ -1,20 +1,20 @@ -import { EntityRepository } from 'typeorm'; import { SessionEntity } from '../entities'; import { Message as JsonMessage } from '../../common'; import { cloneDeep } from 'lodash'; -import BaseRepository from './BaseRepository'; +import { getBaseRepository, saveAndReload } from './BaseRepository'; import MessageEntity from '../entities/Message'; -@EntityRepository(MessageEntity) -export default class MessageRepository extends BaseRepository { +export default getBaseRepository(MessageEntity).extend({ async saveFromJson( sessionId: string, userId: string, message: JsonMessage ): Promise { - const session = await this.manager.findOne(SessionEntity, sessionId); + const session = await this.manager.findOne(SessionEntity, { + where: { id: sessionId }, + }); if (session) { - return await this.saveAndReload({ + return await saveAndReload(this, { ...cloneDeep(message), user: { id: userId, @@ -26,5 +26,5 @@ export default class MessageRepository extends BaseRepository { } else { throw new Error('No session found'); } - } -} + }, +}); diff --git a/backend/src/db/repositories/PostGroupRepository.ts b/backend/src/db/repositories/PostGroupRepository.ts index 7e97cb79b..27be340ea 100644 --- a/backend/src/db/repositories/PostGroupRepository.ts +++ b/backend/src/db/repositories/PostGroupRepository.ts @@ -1,11 +1,9 @@ -import { EntityRepository } from 'typeorm'; import { PostGroupEntity } from '../entities'; import { PostGroup as JsonPostGroup } from '../../common'; import { cloneDeep } from 'lodash'; -import BaseRepository from './BaseRepository'; +import { getBaseRepository, saveAndReload } from './BaseRepository'; -@EntityRepository(PostGroupEntity) -export default class PostGroupRepository extends BaseRepository { +export default getBaseRepository(PostGroupEntity).extend({ async saveFromJson( sessionId: string, authorId: string, @@ -19,6 +17,6 @@ export default class PostGroupRepository extends BaseRepository }; delete groupWithoutPosts.posts; - return await this.saveAndReload(groupWithoutPosts); - } -} + return await saveAndReload(this, groupWithoutPosts); + }, +}); diff --git a/backend/src/db/repositories/PostRepository.ts b/backend/src/db/repositories/PostRepository.ts index 65de22db2..455166bf2 100644 --- a/backend/src/db/repositories/PostRepository.ts +++ b/backend/src/db/repositories/PostRepository.ts @@ -1,17 +1,15 @@ -import { EntityRepository } from 'typeorm'; import { SessionEntity, PostEntity } from '../entities'; import SessionRepository from './SessionRepository'; import { Post as JsonPost, defaultSession } from '../../common'; import { cloneDeep } from 'lodash'; -import BaseRepository from './BaseRepository'; +import { getBaseRepository, saveAndReload } from './BaseRepository'; -@EntityRepository(PostEntity) -export default class PostRepository extends BaseRepository { +export default getBaseRepository(PostEntity).extend({ async updateFromJson( sessionId: string, post: JsonPost ): Promise { - return await this.saveAndReload({ + return await saveAndReload(this, { ...cloneDeep(post), session: { id: sessionId, @@ -26,15 +24,17 @@ export default class PostRepository extends BaseRepository { } : null, }); - } + }, async saveFromJson( sessionId: string, userId: string, post: JsonPost ): Promise { - const session = await this.manager.findOne(SessionEntity, sessionId); + const session = await this.manager.findOne(SessionEntity, { + where: { id: sessionId }, + }); if (session) { - return await this.saveAndReload({ + return await saveAndReload(this, { ...cloneDeep(post), user: { id: userId, @@ -49,8 +49,7 @@ export default class PostRepository extends BaseRepository { : null, }); } else { - const sessionRepository = - this.manager.getCustomRepository(SessionRepository); + const sessionRepository = this.manager.withRepository(SessionRepository); const newSession = { ...defaultSession, id: sessionId, @@ -58,5 +57,5 @@ export default class PostRepository extends BaseRepository { await sessionRepository.saveFromJson(newSession, userId); return await this.saveFromJson(sessionId, userId, cloneDeep(post)); } - } -} + }, +}); diff --git a/backend/src/db/repositories/SessionRepository.ts b/backend/src/db/repositories/SessionRepository.ts index 339ca3dcf..9f31ddb6d 100644 --- a/backend/src/db/repositories/SessionRepository.ts +++ b/backend/src/db/repositories/SessionRepository.ts @@ -1,11 +1,9 @@ -import { EntityRepository } from 'typeorm'; import { SessionEntity } from '../entities'; import ColumnRepository from './ColumnRepository'; import { Session as JsonSession, SessionOptions } from '../../common'; -import BaseRepository from './BaseRepository'; +import { getBaseRepository, saveAndReload } from './BaseRepository'; -@EntityRepository(SessionEntity) -export default class SessionRepository extends BaseRepository { +export default getBaseRepository(SessionEntity).extend({ async updateOptions( sessionId: string, options: SessionOptions @@ -19,14 +17,14 @@ export default class SessionRepository extends BaseRepository { } catch { return null; } - } + }, async updateName(sessionId: string, name: string) { - const sessionEntity = await this.findOne(sessionId); + const sessionEntity = await this.findOne({ where: { id: sessionId } }); if (sessionEntity) { sessionEntity.name = name; await this.save(sessionEntity); } - } + }, async saveFromJson( session: Omit, authorId: string @@ -40,12 +38,12 @@ export default class SessionRepository extends BaseRepository { delete sessionWithoutPosts.posts; delete sessionWithoutPosts.columns; - const columnsRepo = this.manager.getCustomRepository(ColumnRepository); - const createdSession = await this.saveAndReload(sessionWithoutPosts); + const columnsRepo = this.manager.withRepository(ColumnRepository); + const createdSession = await saveAndReload(this, sessionWithoutPosts); for (let i = 0; i < session.columns.length; i++) { await columnsRepo.saveFromJson(session.columns[i], session.id); } return createdSession.toJson(); - } -} + }, +}); diff --git a/backend/src/db/repositories/SessionTemplateRepository.ts b/backend/src/db/repositories/SessionTemplateRepository.ts index 089df72f4..983f8351f 100644 --- a/backend/src/db/repositories/SessionTemplateRepository.ts +++ b/backend/src/db/repositories/SessionTemplateRepository.ts @@ -1,4 +1,3 @@ -import { EntityRepository } from 'typeorm'; import { SessionTemplateEntity } from '../entities'; import { SessionTemplate as JsonSessionTemplate, @@ -7,10 +6,9 @@ import { } from '../../common'; import { v4 } from 'uuid'; import { TemplateColumnRepository } from '.'; -import BaseRepository from './BaseRepository'; +import { getBaseRepository } from './BaseRepository'; -@EntityRepository(SessionTemplateEntity) -export default class SessionTemplateRepository extends BaseRepository { +export default getBaseRepository(SessionTemplateEntity).extend({ async saveFromJson( name: string, columns: JsonColumnDefinition[], @@ -25,12 +23,12 @@ export default class SessionTemplateRepository extends BaseRepository { +import { getBaseRepository, saveAndReload } from './BaseRepository'; + +export default getBaseRepository(SubscriptionEntity).extend({ async activate( stripeSubscriptionId: string, owner: UserEntity, plan: Plan, domain: string | null ): Promise { - const existingSub = await this.findOne(stripeSubscriptionId); + const existingSub = await this.findOne({ + where: { id: stripeSubscriptionId }, + }); if (!existingSub) { const newSubscription = new SubscriptionEntity( @@ -20,19 +21,21 @@ export default class SubscriptionRepository extends BaseRepository { - const existingSub = await this.findOne(stripeSubscriptionId); + const existingSub = await this.findOne({ + where: { id: stripeSubscriptionId }, + }); if (!existingSub) { throw Error('Cannot cancel a subscription that does not exist'); } existingSub.active = false; - return await this.saveAndReload(existingSub); - } -} + return await saveAndReload(this, existingSub); + }, +}); diff --git a/backend/src/db/repositories/TemplateColumnRepository.ts b/backend/src/db/repositories/TemplateColumnRepository.ts index 44e1538fa..fc6375c5a 100644 --- a/backend/src/db/repositories/TemplateColumnRepository.ts +++ b/backend/src/db/repositories/TemplateColumnRepository.ts @@ -1,11 +1,9 @@ -import { EntityRepository } from 'typeorm'; import { TemplateColumnDefinitionEntity } from '../entities'; import { ColumnDefinition as JsonColumnDefinition } from '../../common'; import { v4 } from 'uuid'; -import BaseRepository from './BaseRepository'; +import { getBaseRepository } from './BaseRepository'; -@EntityRepository(TemplateColumnDefinitionEntity) -export default class TemplateColumnDefinitionRepository extends BaseRepository { +export default getBaseRepository(TemplateColumnDefinitionEntity).extend({ async saveFromJson( colDef: JsonColumnDefinition, templateId: string @@ -15,5 +13,5 @@ export default class TemplateColumnDefinitionRepository extends BaseRepository {} +export default getBaseRepository(UserIdentityEntity).extend({}); diff --git a/backend/src/db/repositories/UserRepository.ts b/backend/src/db/repositories/UserRepository.ts index baa823970..a943216f0 100644 --- a/backend/src/db/repositories/UserRepository.ts +++ b/backend/src/db/repositories/UserRepository.ts @@ -1,24 +1,22 @@ -import { EntityRepository } from 'typeorm'; import { UserEntity } from '../entities'; import { FullUser, User as JsonUser } from '../../common'; import { addDays } from 'date-fns'; -import BaseRepository from './BaseRepository'; +import { getBaseRepository, saveAndReload } from './BaseRepository'; -@EntityRepository(UserEntity) -export default class UserRepository extends BaseRepository { +export default getBaseRepository(UserEntity).extend({ async saveFromJson(user: JsonUser): Promise { - return await this.saveAndReload(user); - } + return await saveAndReload(this, user as UserEntity); + }, async persistTemplate(userId: string, templateId: string): Promise { await this.update({ id: userId }, { defaultTemplate: { id: templateId } }); - } + }, async startTrial(user: FullUser): Promise { - const userEntity = await this.findOne(user.id); + const userEntity = await this.findOne({ where: { id: user.id } }); if (userEntity && !userEntity.trial && !user.pro) { userEntity.trial = addDays(new Date(), 30); - return await this.saveAndReload(userEntity); + return await saveAndReload(this, userEntity); } return null; - } -} + }, +}); diff --git a/backend/src/db/repositories/VoteRepository.ts b/backend/src/db/repositories/VoteRepository.ts index b3bee1d0b..a6370898f 100644 --- a/backend/src/db/repositories/VoteRepository.ts +++ b/backend/src/db/repositories/VoteRepository.ts @@ -1,10 +1,8 @@ -import { EntityRepository } from 'typeorm'; import { VoteEntity } from '../entities'; import { Vote as JsonVote } from '../../common'; -import BaseRepository from './BaseRepository'; +import { getBaseRepository } from './BaseRepository'; -@EntityRepository(VoteEntity) -export default class VoteRepository extends BaseRepository { +export default getBaseRepository(VoteEntity).extend({ async saveFromJson( postId: string, userId: string, @@ -22,5 +20,5 @@ export default class VoteRepository extends BaseRepository { console.error('Error while saving a vote', error); throw error; } - } -} + }, +}); diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 55f540cf3..021f37116 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -1,7 +1,7 @@ { "compilerOptions": { "outDir": "./dist", - "target": "es5", + "target": "es6", "module": "commonjs", "incremental": true, "moduleResolution": "node", diff --git a/backend/yarn.lock b/backend/yarn.lock index 2a32adb16..9baccb3ed 100644 --- a/backend/yarn.lock +++ b/backend/yarn.lock @@ -1134,11 +1134,6 @@ dependencies: "@types/yargs-parser" "*" -"@types/zen-observable@0.8.3": - version "0.8.3" - resolved "https://registry.yarnpkg.com/@types/zen-observable/-/zen-observable-0.8.3.tgz#781d360c282436494b32fe7d9f7f8e64b3118aa3" - integrity sha512-fbF6oTd4sGGy0xjHPKAt+eS2CrxJ3+6gQ3FGcBoIJR2TLAyCkCyI8JqZNy+FeON0AhVgNJoUumVoZQjBFUqHkw== - "@typescript-eslint/eslint-plugin@5.45.0": version "5.45.0" resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.45.0.tgz#ffa505cf961d4844d38cfa19dcec4973a6039e41" @@ -1343,6 +1338,13 @@ array-union@^2.1.0: resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== +async@^2.6.4: + version "2.6.4" + resolved "https://registry.yarnpkg.com/async/-/async-2.6.4.tgz#706b7ff6084664cd7eae713f6f965433b5504221" + integrity sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA== + dependencies: + lodash "^4.17.14" + asynckit@^0.4.0: version "0.4.0" resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" @@ -1761,7 +1763,7 @@ crypto-js@4.1.1: resolved "https://registry.yarnpkg.com/crypto-js/-/crypto-js-4.1.1.tgz#9e485bcf03521041bd85844786b83fb7619736cf" integrity sha512-o2JlM7ydqd3Qk9CA0L4NL6mTzU2sdx96a+oOfPu8Mkl/PK51vSyoi8/rQ8NknZtk44vq15lmhAj9CIAGwgeWKw== -date-fns@2.29.3: +date-fns@2.29.3, date-fns@^2.28.0: version "2.29.3" resolved "https://registry.yarnpkg.com/date-fns/-/date-fns-2.29.3.tgz#27402d2fc67eb442b511b70bbdf98e6411cd68a8" integrity sha512-dDCnyH2WnnKusqvZZ6+jA1O51Ibt8ZMRNkDZdyAyK4YfbDwa/cEmuztzG5pk6hqlp9aSBPYcjOlktquahGwGeA== @@ -1773,7 +1775,7 @@ debug@2.6.9: dependencies: ms "2.0.0" -debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: +debug@4, debug@^4.1.0, debug@^4.1.1, debug@^4.3.2, debug@^4.3.3, debug@^4.3.4, debug@~4.3.1, debug@~4.3.2: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" integrity sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ== @@ -1856,16 +1858,11 @@ doctrine@^3.0.0: dependencies: esutils "^2.0.2" -dotenv@16.0.3: +dotenv@16.0.3, dotenv@^16.0.0: version "16.0.3" resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07" integrity sha512-7GO6HghkA5fYG9TYnNxi14/7K9f5occMlp3zXAuSxn7CKCxt9xbNWG7yF8hTCSUchlfWSe3uLmlPfigevRItzQ== -dotenv@^8.2.0: - version "8.6.0" - resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-8.6.0.tgz#061af664d19f7f4d8fc6e4ff9b584ce237adcb8b" - integrity sha512-IrPdXQsk2BbzvCBGBOTmmSH5SodmqZNt4ERAZDmW4CT+tL8VtvinqywuANaFu4bOMWki16nqf0e4oC0QIaDr/g== - ee-first@1.1.1: version "1.1.1" resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" @@ -2380,7 +2377,7 @@ glob-parent@^6.0.2: dependencies: is-glob "^4.0.3" -glob@^7.0.5, glob@^7.1.3, glob@^7.1.4, glob@^7.1.6: +glob@^7.0.3, glob@^7.0.5, glob@^7.1.3, glob@^7.1.4, glob@^7.2.0: version "7.2.3" resolved "https://registry.yarnpkg.com/glob/-/glob-7.2.3.tgz#b8df0fb802bbfa8e89bd1d938b4e16578ed44f2b" integrity sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q== @@ -3111,7 +3108,7 @@ js-yaml@^3.13.1: argparse "^1.0.7" esprima "^4.0.0" -js-yaml@^4.0.0, js-yaml@^4.1.0: +js-yaml@^4.1.0: version "4.1.0" resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-4.1.0.tgz#c1fb65f8f5017901cdd2c951864ba18458a10602" integrity sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA== @@ -3195,7 +3192,7 @@ lodash.merge@^4.6.2: resolved "https://registry.yarnpkg.com/lodash.merge/-/lodash.merge-4.6.2.tgz#558aa53b43b661e1925a0afdfa36a9a1085fe57a" integrity sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ== -lodash@4.17.21: +lodash@4.17.21, lodash@^4.17.11, lodash@^4.17.14: version "4.17.21" resolved "https://registry.yarnpkg.com/lodash/-/lodash-4.17.21.tgz#679591c564c3bffaae8454cf0b3df370c3d6911c" integrity sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg== @@ -3962,6 +3959,11 @@ resolve-cwd@^3.0.0: dependencies: resolve-from "^5.0.0" +resolve-from@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-2.0.0.tgz#9480ab20e94ffa1d9e80a804c7ea147611966b57" + integrity sha512-qpFcKaXsq8+oRoLilkwyc7zHGF5i9Q2/25NIgLQQ/+VVv9rU4qvr6nXVAw1DsnXJyQkZsR4Ytfbtg5ehfcUssQ== + resolve-from@^4.0.0: version "4.0.0" resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-4.0.0.tgz#4abcd852ad32dd7baabfe9b40e00a36db5f392e6" @@ -3972,6 +3974,13 @@ resolve-from@^5.0.0: resolved "https://registry.yarnpkg.com/resolve-from/-/resolve-from-5.0.0.tgz#c35225843df8f776df21c57557bc087e9dfdfc69" integrity sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw== +resolve-pkg@^1.0.0: + version "1.0.0" + resolved "https://registry.yarnpkg.com/resolve-pkg/-/resolve-pkg-1.0.0.tgz#e19a15e78aca2e124461dc92b2e3943ef93494d9" + integrity sha512-L0/+vjdV3UjcQaXRlQcObpCyySS8GEqVNYGYRDAGlYOcw4J1y33WMIAD3XvYWIPnBeyN5Ilp5RHoifs3gR1S2g== + dependencies: + resolve-from "^2.0.0" + resolve.exports@^1.1.0: version "1.1.0" resolved "https://registry.yarnpkg.com/resolve.exports/-/resolve.exports-1.1.0.tgz#5ce842b94b05146c0e03076985d1d0e7e48c90c9" @@ -4025,6 +4034,16 @@ sax@>=0.6.0: resolved "https://registry.yarnpkg.com/sax/-/sax-1.2.4.tgz#2816234e2378bddc4e5354fab5caa895df7100d9" integrity sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw== +scripty@^2.1.1: + version "2.1.1" + resolved "https://registry.yarnpkg.com/scripty/-/scripty-2.1.1.tgz#41a9fb1472c042a4a631780df81dff079cdf8b15" + integrity sha512-yAutoO7+MfJcc7UAjAOp1CNbAI6GhxXYB63yFLEJe80BY1VkKQWrJ2xrdd57rh/UBnUIKmO31hzKUHWGxIupbA== + dependencies: + async "^2.6.4" + glob "^7.0.3" + lodash "^4.17.11" + resolve-pkg "^1.0.0" + semver@7.x, semver@^7.3.5, semver@^7.3.7: version "7.3.7" resolved "https://registry.yarnpkg.com/semver/-/semver-7.3.7.tgz#12c5b649afdbf9049707796e22a4028814ce523f" @@ -4415,10 +4434,10 @@ tslib@^1.8.1, tslib@^1.9.3: resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== -tslib@^2.1.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.0.tgz#7cecaa7f073ce680a05847aa77be941098f36dc3" - integrity sha512-d6xOpEDfsi2CZVlPQzGeux8XMwLT9hssAsaPYExaQMuYskwb+x1x7J371tWlbBdWHroy99KnVB6qIkUbs5X3UQ== +tslib@^2.3.1: + version "2.4.1" + resolved "https://registry.yarnpkg.com/tslib/-/tslib-2.4.1.tgz#0d0bfbaac2880b91e22df0768e55be9753a5b17e" + integrity sha512-tGyy4dAjRIEwI7BzsB0lynWgOpfqjUdq91XXAlIWD2OwKBH7oCl/GZG/HT4BOHrTlPMOASlMQ7veyTqpmRcrNA== tsutils@^3.21.0: version "3.21.0" @@ -4457,38 +4476,38 @@ type-is@~1.6.18: media-typer "0.3.0" mime-types "~2.1.24" -typeorm-naming-strategies@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/typeorm-naming-strategies/-/typeorm-naming-strategies-3.0.0.tgz#d709110a24bea464ce983a0b3e6e728e59ed88c1" - integrity sha512-N8unfoNa+TYzmH2G5hA2Uh2ZHDACRRshHv8GsB7l/oakcoA9cUTtdeNp24pjpb9HY96sBub2pb8wxXX1afT5RA== +typeorm-naming-strategies@4.1.0: + version "4.1.0" + resolved "https://registry.yarnpkg.com/typeorm-naming-strategies/-/typeorm-naming-strategies-4.1.0.tgz#1ec6eb296c8d7b69bb06764d5b9083ff80e814a9" + integrity sha512-vPekJXzZOTZrdDvTl1YoM+w+sUIfQHG4kZTpbFYoTsufyv9NIBRe4Q+PdzhEAFA2std3D9LZHEb1EjE9zhRpiQ== -typeorm@0.2.45: - version "0.2.45" - resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.2.45.tgz#e5bbb3af822dc4646bad96cfa48cd22fa4687cea" - integrity sha512-c0rCO8VMJ3ER7JQ73xfk0zDnVv0WDjpsP6Q1m6CVKul7DB9iVdWLRjPzc8v2eaeBuomsbZ2+gTaYr8k1gm3bYA== +typeorm@0.3.11: + version "0.3.11" + resolved "https://registry.yarnpkg.com/typeorm/-/typeorm-0.3.11.tgz#09b6ab0b0574bf33c1faf7344bab6c363cf28921" + integrity sha512-pzdOyWbVuz/z8Ww6gqvBW4nylsM0KLdUCDExr2gR20/x1khGSVxQkjNV/3YqliG90jrWzrknYbYscpk8yxFJVg== dependencies: "@sqltools/formatter" "^1.2.2" app-root-path "^3.0.0" buffer "^6.0.3" chalk "^4.1.0" cli-highlight "^2.1.11" - debug "^4.3.1" - dotenv "^8.2.0" - glob "^7.1.6" - js-yaml "^4.0.0" + date-fns "^2.28.0" + debug "^4.3.3" + dotenv "^16.0.0" + glob "^7.2.0" + js-yaml "^4.1.0" mkdirp "^1.0.4" reflect-metadata "^0.1.13" sha.js "^2.4.11" - tslib "^2.1.0" + tslib "^2.3.1" uuid "^8.3.2" xml2js "^0.4.23" - yargs "^17.0.1" - zen-observable-ts "^1.0.0" + yargs "^17.3.1" -typescript@4.9.3: - version "4.9.3" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.3.tgz#3aea307c1746b8c384435d8ac36b8a2e580d85db" - integrity sha512-CIfGzTelbKNEnLpLdGFgdyKhG23CKdKgQPOBc+OUNrkJ2vr+KSzsSV5kq5iWhEQbok+quxgGzrAtGWCyU7tHnA== +typescript@4.9.4: + version "4.9.4" + resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.4.tgz#a2a3d2756c079abda241d75f149df9d561091e78" + integrity sha512-Uz+dTXYzxXXbsFpM86Wh3dKCxrQqUcVMxwU54orwlJjOpO3ao8L7j5lH+dWfTwgCwIuM9GQ2kvVotzYJMXTBZg== uglify-js@^3.1.4: version "3.17.0" @@ -4701,7 +4720,7 @@ yargs@^16.0.0, yargs@^16.1.0: y18n "^5.0.5" yargs-parser "^20.2.2" -yargs@^17.0.1, yargs@^17.3.1: +yargs@^17.3.1: version "17.5.1" resolved "https://registry.yarnpkg.com/yargs/-/yargs-17.5.1.tgz#e109900cab6fcb7fd44b1d8249166feb0b36e58e" integrity sha512-t6YAJcxDkNX7NFYiVtKvWUz8l+PaKTLiL63mJYWR2GnHq2gjEWISzsLp9wg3aY36dY1j+gfIEL3pIF+XlJJfbA== @@ -4723,16 +4742,3 @@ yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b" integrity sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q== - -zen-observable-ts@^1.0.0: - version "1.1.0" - resolved "https://registry.yarnpkg.com/zen-observable-ts/-/zen-observable-ts-1.1.0.tgz#2d1aa9d79b87058e9b75698b92791c1838551f83" - integrity sha512-1h4zlLSqI2cRLPJUHJFL8bCWHhkpuXkF+dbGkRaWjgDIG26DmzyshUMrdV/rL3UnR+mhaX4fRq8LPouq0MYYIA== - dependencies: - "@types/zen-observable" "0.8.3" - zen-observable "0.8.15" - -zen-observable@0.8.15: - version "0.8.15" - resolved "https://registry.yarnpkg.com/zen-observable/-/zen-observable-0.8.15.tgz#96415c512d8e3ffd920afd3889604e30b9eaac15" - integrity sha512-PQ2PC7R9rslx84ndNBZB/Dkv8V8fZEpk83RLgXtYd0fwUgEjseMn1Dgajh2x6S8QbZAFa9p2qVCEuYZNgve0dQ==