Bläddra i källkod

fix(auth): reduce session select queries in favor of insert/update model

Karol Sójko 1 år sedan
förälder
incheckning
25a875cbbc

+ 2 - 1
packages/auth/src/Domain/Session/EphemeralSessionRepositoryInterface.ts

@@ -5,5 +5,6 @@ export interface EphemeralSessionRepositoryInterface {
   findOneByUuidAndUserUuid(uuid: string, userUuid: string): Promise<EphemeralSession | null>
   findAllByUserUuid(userUuid: string): Promise<Array<EphemeralSession>>
   deleteOne(uuid: string, userUuid: string): Promise<void>
-  save(ephemeralSession: EphemeralSession): Promise<void>
+  insert(ephemeralSession: EphemeralSession): Promise<void>
+  update(ephemeralSession: EphemeralSession): Promise<void>
 }

+ 2 - 1
packages/auth/src/Domain/Session/RevokedSessionRepositoryInterface.ts

@@ -3,7 +3,8 @@ import { RevokedSession } from './RevokedSession'
 export interface RevokedSessionRepositoryInterface {
   findOneByUuid(uuid: string): Promise<RevokedSession | null>
   findAllByUserUuid(userUuid: string): Promise<Array<RevokedSession>>
-  save(revokedSession: RevokedSession): Promise<RevokedSession>
+  insert(revokedSession: RevokedSession): Promise<void>
+  update(revokedSession: RevokedSession): Promise<void>
   remove(revokedSession: RevokedSession): Promise<RevokedSession>
   clearUserAgentByUserUuid(userUuid: string): Promise<void>
 }

+ 2 - 1
packages/auth/src/Domain/Session/SessionRepositoryInterface.ts

@@ -9,7 +9,8 @@ export interface SessionRepositoryInterface {
   findAllByUserUuid(userUuid: string): Promise<Array<Session>>
   deleteAllByUserUuidExceptOne(dto: { userUuid: Uuid; currentSessionUuid: Uuid }): Promise<void>
   deleteOneByUuid(uuid: string): Promise<void>
-  save(session: Session): Promise<Session>
+  insert(session: Session): Promise<void>
+  update(session: Session): Promise<void>
   remove(session: Session): Promise<Session>
   clearUserAgentByUserUuid(userUuid: string): Promise<void>
   removeExpiredBefore(date: Date): Promise<void>

+ 20 - 17
packages/auth/src/Domain/Session/SessionService.spec.ts

@@ -69,18 +69,21 @@ describe('SessionService', () => {
     sessionRepository = {} as jest.Mocked<SessionRepositoryInterface>
     sessionRepository.findOneByUuid = jest.fn().mockReturnValue(null)
     sessionRepository.deleteOneByUuid = jest.fn()
-    sessionRepository.save = jest.fn().mockReturnValue(existingSession)
+    sessionRepository.insert = jest.fn()
+    sessionRepository.update = jest.fn()
 
     settingService = {} as jest.Mocked<SettingServiceInterface>
     settingService.findSettingWithDecryptedValue = jest.fn().mockReturnValue(null)
 
     ephemeralSessionRepository = {} as jest.Mocked<EphemeralSessionRepositoryInterface>
-    ephemeralSessionRepository.save = jest.fn()
+    ephemeralSessionRepository.insert = jest.fn()
+    ephemeralSessionRepository.update = jest.fn()
     ephemeralSessionRepository.findOneByUuid = jest.fn()
     ephemeralSessionRepository.deleteOne = jest.fn()
 
     revokedSessionRepository = {} as jest.Mocked<RevokedSessionRepositoryInterface>
-    revokedSessionRepository.save = jest.fn()
+    revokedSessionRepository.insert = jest.fn()
+    revokedSessionRepository.update = jest.fn()
 
     existingEphemeralSession = {} as jest.Mocked<EphemeralSession>
     existingEphemeralSession.uuid = '2-3-4'
@@ -129,7 +132,7 @@ describe('SessionService', () => {
   it('should mark a revoked session as received', async () => {
     await createService().markRevokedSessionAsReceived(revokedSession)
 
-    expect(revokedSessionRepository.save).toHaveBeenCalledWith({
+    expect(revokedSessionRepository.update).toHaveBeenCalledWith({
       uuid: '2e1e43',
       received: true,
       receivedAt: new Date(1),
@@ -145,8 +148,8 @@ describe('SessionService', () => {
       readonly_access: false,
     })
 
-    expect(sessionRepository.save).toHaveBeenCalled()
-    expect(ephemeralSessionRepository.save).not.toHaveBeenCalled()
+    expect(sessionRepository.update).toHaveBeenCalled()
+    expect(ephemeralSessionRepository.update).not.toHaveBeenCalled()
   })
 
   it('should refresh access and refresh tokens for an ephemeral session', async () => {
@@ -158,8 +161,8 @@ describe('SessionService', () => {
       readonly_access: false,
     })
 
-    expect(sessionRepository.save).not.toHaveBeenCalled()
-    expect(ephemeralSessionRepository.save).toHaveBeenCalled()
+    expect(sessionRepository.update).not.toHaveBeenCalled()
+    expect(ephemeralSessionRepository.update).toHaveBeenCalled()
   })
 
   it('should create new session for a user', async () => {
@@ -173,8 +176,8 @@ describe('SessionService', () => {
       readonlyAccess: false,
     })
 
-    expect(sessionRepository.save).toHaveBeenCalledWith(expect.any(Session))
-    expect(sessionRepository.save).toHaveBeenCalledWith({
+    expect(sessionRepository.insert).toHaveBeenCalledWith(expect.any(Session))
+    expect(sessionRepository.insert).toHaveBeenCalledWith({
       accessExpiration: expect.any(Date),
       apiVersion: '003',
       createdAt: expect.any(Date),
@@ -209,8 +212,8 @@ describe('SessionService', () => {
       readonlyAccess: false,
     })
 
-    expect(sessionRepository.save).toHaveBeenCalledWith(expect.any(Session))
-    expect(sessionRepository.save).toHaveBeenCalledWith({
+    expect(sessionRepository.insert).toHaveBeenCalledWith(expect.any(Session))
+    expect(sessionRepository.insert).toHaveBeenCalledWith({
       accessExpiration: expect.any(Date),
       apiVersion: '003',
       createdAt: expect.any(Date),
@@ -248,8 +251,8 @@ describe('SessionService', () => {
       readonlyAccess: false,
     })
 
-    expect(sessionRepository.save).toHaveBeenCalledWith(expect.any(Session))
-    expect(sessionRepository.save).toHaveBeenCalledWith({
+    expect(sessionRepository.insert).toHaveBeenCalledWith(expect.any(Session))
+    expect(sessionRepository.insert).toHaveBeenCalledWith({
       accessExpiration: expect.any(Date),
       apiVersion: '003',
       createdAt: expect.any(Date),
@@ -405,8 +408,8 @@ describe('SessionService', () => {
       readonlyAccess: false,
     })
 
-    expect(ephemeralSessionRepository.save).toHaveBeenCalledWith(expect.any(EphemeralSession))
-    expect(ephemeralSessionRepository.save).toHaveBeenCalledWith({
+    expect(ephemeralSessionRepository.insert).toHaveBeenCalledWith(expect.any(EphemeralSession))
+    expect(ephemeralSessionRepository.insert).toHaveBeenCalledWith({
       accessExpiration: expect.any(Date),
       apiVersion: '003',
       createdAt: expect.any(Date),
@@ -684,7 +687,7 @@ describe('SessionService', () => {
   it('should revoked a session', async () => {
     await createService().createRevokedSession(existingSession)
 
-    expect(revokedSessionRepository.save).toHaveBeenCalledWith({
+    expect(revokedSessionRepository.insert).toHaveBeenCalledWith({
       uuid: '2e1e43',
       userUuid: '1-2-3',
       userAgent: 'Chrome',

+ 10 - 6
packages/auth/src/Domain/Session/SessionService.ts

@@ -57,7 +57,7 @@ export class SessionService implements SessionServiceInterface {
 
     const sessionPayload = await this.createTokens(session)
 
-    await this.sessionRepository.save(session)
+    await this.sessionRepository.insert(session)
 
     try {
       const userSubscription = await this.userSubscriptionRepository.findOneByUserUuid(dto.user.uuid)
@@ -92,7 +92,7 @@ export class SessionService implements SessionServiceInterface {
 
     const sessionPayload = await this.createTokens(ephemeralSession)
 
-    await this.ephemeralSessionRepository.save(ephemeralSession)
+    await this.ephemeralSessionRepository.insert(ephemeralSession)
 
     return {
       sessionHttpRepresentation: sessionPayload,
@@ -104,9 +104,9 @@ export class SessionService implements SessionServiceInterface {
     const sessionPayload = await this.createTokens(dto.session)
 
     if (dto.isEphemeral) {
-      await this.ephemeralSessionRepository.save(dto.session)
+      await this.ephemeralSessionRepository.update(dto.session)
     } else {
-      await this.sessionRepository.save(dto.session)
+      await this.sessionRepository.update(dto.session)
     }
 
     return sessionPayload
@@ -221,7 +221,9 @@ export class SessionService implements SessionServiceInterface {
     revokedSession.received = true
     revokedSession.receivedAt = this.timer.getUTCDate()
 
-    return this.revokedSessionRepository.save(revokedSession)
+    await this.revokedSessionRepository.update(revokedSession)
+
+    return revokedSession
   }
 
   async deleteSessionByToken(token: string): Promise<string | null> {
@@ -248,7 +250,9 @@ export class SessionService implements SessionServiceInterface {
     revokedSession.apiVersion = session.apiVersion
     revokedSession.userAgent = session.userAgent
 
-    return this.revokedSessionRepository.save(revokedSession)
+    await this.revokedSessionRepository.insert(revokedSession)
+
+    return revokedSession
   }
 
   private async createSession(dto: {

+ 6 - 2
packages/auth/src/Infra/Redis/RedisEphemeralSessionRepository.ts

@@ -42,7 +42,7 @@ export class RedisEphemeralSessionRepository implements EphemeralSessionReposito
     session.accessExpiration = accessExpiration
     session.refreshExpiration = refreshExpiration
 
-    await this.save(session)
+    await this.update(session)
   }
 
   async findAllByUserUuid(userUuid: string): Promise<Array<EphemeralSession>> {
@@ -77,7 +77,7 @@ export class RedisEphemeralSessionRepository implements EphemeralSessionReposito
     return JSON.parse(stringifiedSession)
   }
 
-  async save(ephemeralSession: EphemeralSession): Promise<void> {
+  async insert(ephemeralSession: EphemeralSession): Promise<void> {
     const ttl = this.ephemeralSessionAge
 
     const stringifiedSession = JSON.stringify(ephemeralSession)
@@ -92,4 +92,8 @@ export class RedisEphemeralSessionRepository implements EphemeralSessionReposito
 
     await pipeline.exec()
   }
+
+  async update(ephemeralSession: EphemeralSession): Promise<void> {
+    return this.insert(ephemeralSession)
+  }
 }

+ 5 - 1
packages/auth/src/Infra/TypeORM/TypeORMEphemeralSessionRepository.ts

@@ -71,7 +71,11 @@ export class TypeORMEphemeralSessionRepository implements EphemeralSessionReposi
     return JSON.parse(stringifiedSession.props.value)
   }
 
-  async save(ephemeralSession: EphemeralSession): Promise<void> {
+  async update(ephemeralSession: EphemeralSession): Promise<void> {
+    return this.insert(ephemeralSession)
+  }
+
+  async insert(ephemeralSession: EphemeralSession): Promise<void> {
     const ttl = this.ephemeralSessionAge
 
     ephemeralSession.updatedAt = this.timer.getUTCDate()

+ 8 - 2
packages/auth/src/Infra/TypeORM/TypeORMRevokedSessionRepository.ts

@@ -12,8 +12,14 @@ export class TypeORMRevokedSessionRepository implements RevokedSessionRepository
     private ormRepository: Repository<RevokedSession>,
   ) {}
 
-  async save(revokedSession: RevokedSession): Promise<RevokedSession> {
-    return this.ormRepository.save(revokedSession)
+  async insert(revokedSession: RevokedSession): Promise<void> {
+    await this.ormRepository.insert(revokedSession)
+  }
+
+  async update(revokedSession: RevokedSession): Promise<void> {
+    const { uuid, ...revokedSessionProps } = revokedSession
+
+    await this.ormRepository.update({ uuid }, revokedSessionProps)
   }
 
   async remove(revokedSession: RevokedSession): Promise<RevokedSession> {

+ 10 - 2
packages/auth/src/Infra/TypeORM/TypeORMSessionRepository.ts

@@ -17,10 +17,18 @@ export class TypeORMSessionRepository implements SessionRepositoryInterface {
     @inject(TYPES.Auth_Timer) private timer: TimerInterface,
   ) {}
 
-  async save(session: Session): Promise<Session> {
+  async insert(session: Session): Promise<void> {
     session.updatedAt = this.timer.getUTCDate()
 
-    return this.ormRepository.save(session)
+    await this.ormRepository.insert(session)
+  }
+
+  async update(session: Session): Promise<void> {
+    session.updatedAt = this.timer.getUTCDate()
+
+    const { uuid, ...sessionProps } = session
+
+    await this.ormRepository.update({ uuid }, sessionProps)
   }
 
   async remove(session: Session): Promise<Session> {