瀏覽代碼

fix(revisions): indiciate if revision did not save

Karol Sójko 1 年之前
父節點
當前提交
a6039bd99a

+ 103 - 1
packages/revisions/src/Domain/Revision/Revision.spec.ts

@@ -1,4 +1,4 @@
-import { ContentType, Dates, Uuid } from '@standardnotes/domain-core'
+import { ContentType, Dates, UniqueEntityId, Uuid } from '@standardnotes/domain-core'
 
 
 import { Revision } from './Revision'
 import { Revision } from './Revision'
 
 
@@ -19,4 +19,106 @@ describe('Revision', () => {
     expect(entityOrError.isFailed()).toBeFalsy()
     expect(entityOrError.isFailed()).toBeFalsy()
     expect(entityOrError.getValue().id).not.toBeNull()
     expect(entityOrError.getValue().id).not.toBeNull()
   })
   })
+
+  it('should tell if a revision is identical to another revision', () => {
+    const entity1 = Revision.create(
+      {
+        itemUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        content: 'test',
+        contentType: ContentType.create('Note').getValue(),
+        itemsKeyId: 'test',
+        encItemKey: 'test',
+        authHash: 'test',
+        creationDate: new Date(1),
+        dates: Dates.create(new Date(1), new Date(2)).getValue(),
+      },
+      new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
+    ).getValue()
+
+    const entity2 = Revision.create(
+      {
+        itemUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        content: 'test',
+        contentType: ContentType.create('Note').getValue(),
+        itemsKeyId: 'test',
+        encItemKey: 'test',
+        authHash: 'test',
+        creationDate: new Date(1),
+        dates: Dates.create(new Date(1), new Date(2)).getValue(),
+      },
+      new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
+    ).getValue()
+
+    expect(entity1.isIdenticalTo(entity2)).toBeTruthy()
+  })
+
+  it('should tell if a revision is not identical to another revision', () => {
+    const entity1 = Revision.create(
+      {
+        itemUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        content: 'test',
+        contentType: ContentType.create('Note').getValue(),
+        itemsKeyId: 'test',
+        encItemKey: 'test',
+        authHash: 'test',
+        creationDate: new Date(1),
+        dates: Dates.create(new Date(1), new Date(2)).getValue(),
+      },
+      new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
+    ).getValue()
+
+    const entity2 = Revision.create(
+      {
+        itemUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        content: 'test2',
+        contentType: ContentType.create('Note').getValue(),
+        itemsKeyId: 'test',
+        encItemKey: 'test',
+        authHash: 'test',
+        creationDate: new Date(1),
+        dates: Dates.create(new Date(1), new Date(2)).getValue(),
+      },
+      new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
+    ).getValue()
+
+    expect(entity1.isIdenticalTo(entity2)).toBeFalsy()
+  })
+
+  it('should tell if a revision is not identical to another revision id ids do not match', () => {
+    const entity1 = Revision.create(
+      {
+        itemUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        content: 'test',
+        contentType: ContentType.create('Note').getValue(),
+        itemsKeyId: 'test',
+        encItemKey: 'test',
+        authHash: 'test',
+        creationDate: new Date(1),
+        dates: Dates.create(new Date(1), new Date(2)).getValue(),
+      },
+      new UniqueEntityId('00000000-0000-0000-0000-000000000000'),
+    ).getValue()
+
+    const entity2 = Revision.create(
+      {
+        itemUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        userUuid: Uuid.create('84c0f8e8-544a-4c7e-9adf-26209303bc1d').getValue(),
+        content: 'test',
+        contentType: ContentType.create('Note').getValue(),
+        itemsKeyId: 'test',
+        encItemKey: 'test',
+        authHash: 'test',
+        creationDate: new Date(1),
+        dates: Dates.create(new Date(1), new Date(2)).getValue(),
+      },
+      new UniqueEntityId('00000000-0000-0000-0000-000000000001'),
+    ).getValue()
+
+    expect(entity1.isIdenticalTo(entity2)).toBeFalsy()
+  })
 })
 })

+ 1 - 1
packages/revisions/src/Domain/Revision/RevisionRepositoryInterface.ts

@@ -12,5 +12,5 @@ export interface RevisionRepositoryInterface {
   findMetadataByItemId(itemUuid: Uuid, userUuid: Uuid): Promise<Array<RevisionMetadata>>
   findMetadataByItemId(itemUuid: Uuid, userUuid: Uuid): Promise<Array<RevisionMetadata>>
   updateUserUuid(itemUuid: Uuid, userUuid: Uuid): Promise<void>
   updateUserUuid(itemUuid: Uuid, userUuid: Uuid): Promise<void>
   findByUserUuid(dto: { userUuid: Uuid; offset?: number; limit?: number }): Promise<Array<Revision>>
   findByUserUuid(dto: { userUuid: Uuid; offset?: number; limit?: number }): Promise<Array<Revision>>
-  save(revision: Revision): Promise<Revision>
+  save(revision: Revision): Promise<boolean>
 }
 }

+ 19 - 1
packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser.spec.ts

@@ -96,7 +96,7 @@ describe('TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser', () => {
     primaryRevisionRepository.removeByUserUuid = jest.fn().mockResolvedValue(undefined)
     primaryRevisionRepository.removeByUserUuid = jest.fn().mockResolvedValue(undefined)
 
 
     secondaryRevisionRepository = {} as jest.Mocked<RevisionRepositoryInterface>
     secondaryRevisionRepository = {} as jest.Mocked<RevisionRepositoryInterface>
-    secondaryRevisionRepository.save = jest.fn().mockResolvedValue(undefined)
+    secondaryRevisionRepository.save = jest.fn().mockResolvedValue(true)
     secondaryRevisionRepository.removeByUserUuid = jest.fn().mockResolvedValue(undefined)
     secondaryRevisionRepository.removeByUserUuid = jest.fn().mockResolvedValue(undefined)
     secondaryRevisionRepository.countByUserUuid = jest.fn().mockResolvedValue(2)
     secondaryRevisionRepository.countByUserUuid = jest.fn().mockResolvedValue(2)
     secondaryRevisionRepository.findOneByUuid = jest
     secondaryRevisionRepository.findOneByUuid = jest
@@ -373,5 +373,23 @@ describe('TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser', () => {
       expect(primaryRevisionRepository.removeByUserUuid).not.toHaveBeenCalled()
       expect(primaryRevisionRepository.removeByUserUuid).not.toHaveBeenCalled()
       expect((secondaryRevisionRepository as RevisionRepositoryInterface).removeByUserUuid).toHaveBeenCalledTimes(1)
       expect((secondaryRevisionRepository as RevisionRepositoryInterface).removeByUserUuid).toHaveBeenCalledTimes(1)
     })
     })
+
+    it('should fail if a revisions did not save in the secondary database', async () => {
+      ;(secondaryRevisionRepository as RevisionRepositoryInterface).save = jest.fn().mockResolvedValue(false)
+
+      const useCase = createUseCase()
+
+      const result = await useCase.execute({
+        userUuid: '00000000-0000-0000-0000-000000000000',
+      })
+
+      expect(result.isFailed()).toBeTruthy()
+      expect(result.getError()).toEqual(
+        'Failed to save revision 00000000-0000-0000-0000-000000000000 to secondary database',
+      )
+
+      expect(primaryRevisionRepository.removeByUserUuid).not.toHaveBeenCalled()
+      expect((secondaryRevisionRepository as RevisionRepositoryInterface).removeByUserUuid).toHaveBeenCalledTimes(1)
+    })
   })
   })
 })
 })

+ 4 - 9
packages/revisions/src/Domain/UseCase/Transition/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser/TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser.ts

@@ -74,15 +74,9 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements
   private async migrateRevisionsForUser(userUuid: Uuid): Promise<Result<void>> {
   private async migrateRevisionsForUser(userUuid: Uuid): Promise<Result<void>> {
     try {
     try {
       const totalRevisionsCountForUser = await this.primaryRevisionsRepository.countByUserUuid(userUuid)
       const totalRevisionsCountForUser = await this.primaryRevisionsRepository.countByUserUuid(userUuid)
-      this.logger.info(`Total revisions count for user ${userUuid.value} is ${totalRevisionsCountForUser}`)
-
       const pageSize = 1
       const pageSize = 1
       const totalPages = Math.ceil(totalRevisionsCountForUser / pageSize)
       const totalPages = Math.ceil(totalRevisionsCountForUser / pageSize)
-      this.logger.info(`Total pages to migrate for user ${userUuid.value} is ${totalPages}`)
-
       for (let currentPage = 1; currentPage <= totalPages; currentPage++) {
       for (let currentPage = 1; currentPage <= totalPages; currentPage++) {
-        this.logger.info(`Migrating page ${currentPage} of ${totalPages} for user ${userUuid.value}`)
-
         const query = {
         const query = {
           userUuid: userUuid,
           userUuid: userUuid,
           offset: (currentPage - 1) * pageSize,
           offset: (currentPage - 1) * pageSize,
@@ -91,10 +85,11 @@ export class TransitionRevisionsFromPrimaryToSecondaryDatabaseForUser implements
 
 
         const revisions = await this.primaryRevisionsRepository.findByUserUuid(query)
         const revisions = await this.primaryRevisionsRepository.findByUserUuid(query)
 
 
-        this.logger.info(`Migrating ${revisions.length} revisions for user ${userUuid.value}`)
-
         for (const revision of revisions) {
         for (const revision of revisions) {
-          await (this.secondRevisionsRepository as RevisionRepositoryInterface).save(revision)
+          const didSave = await (this.secondRevisionsRepository as RevisionRepositoryInterface).save(revision)
+          if (!didSave) {
+            return Result.fail(`Failed to save revision ${revision.id.toString()} to secondary database`)
+          }
         }
         }
       }
       }
 
 

+ 3 - 3
packages/revisions/src/Infra/TypeORM/MongoDB/MongoDBRevisionRepository.ts

@@ -123,12 +123,12 @@ export class MongoDBRevisionRepository implements RevisionRepositoryInterface {
     )
     )
   }
   }
 
 
-  async save(revision: Revision): Promise<Revision> {
+  async save(revision: Revision): Promise<boolean> {
     const persistence = this.revisionMapper.toProjection(revision)
     const persistence = this.revisionMapper.toProjection(revision)
 
 
     const { _id, ...rest } = persistence
     const { _id, ...rest } = persistence
 
 
-    await this.mongoRepository.updateOne(
+    const updateResult = await this.mongoRepository.updateOne(
       { _id: { $eq: _id } },
       { _id: { $eq: _id } },
       {
       {
         $set: rest,
         $set: rest,
@@ -136,6 +136,6 @@ export class MongoDBRevisionRepository implements RevisionRepositoryInterface {
       { upsert: true },
       { upsert: true },
     )
     )
 
 
-    return revision
+    return updateResult.acknowledged
   }
   }
 }
 }

+ 2 - 2
packages/revisions/src/Infra/TypeORM/SQL/SQLRevisionRepository.ts

@@ -106,12 +106,12 @@ export class SQLRevisionRepository implements RevisionRepositoryInterface {
     return this.revisionMapper.toDomain(SQLRevision)
     return this.revisionMapper.toDomain(SQLRevision)
   }
   }
 
 
-  async save(revision: Revision): Promise<Revision> {
+  async save(revision: Revision): Promise<boolean> {
     const SQLRevision = this.revisionMapper.toProjection(revision)
     const SQLRevision = this.revisionMapper.toProjection(revision)
 
 
     await this.ormRepository.save(SQLRevision)
     await this.ormRepository.save(SQLRevision)
 
 
-    return revision
+    return true
   }
   }
 
 
   async findMetadataByItemId(itemUuid: Uuid, userUuid: Uuid): Promise<Array<RevisionMetadata>> {
   async findMetadataByItemId(itemUuid: Uuid, userUuid: Uuid): Promise<Array<RevisionMetadata>> {