Forráskód Böngészése

fix: merge mysql and mysql-legacy together (#883)

Karol Sójko 1 éve
szülő
commit
e19f7a7b7f
51 módosított fájl, 512 hozzáadás és 1584 törlés
  1. 0 41
      packages/revisions/migrations/mysql-legacy/1669113322388-init.ts
  2. 0 28
      packages/revisions/migrations/mysql-legacy/1669636497932-remove-date-indexes.ts
  3. 0 13
      packages/revisions/migrations/mysql-legacy/1669735585016-make-user-uuid-nullable.ts
  4. 1 1
      packages/revisions/migrations/mysql/1669636497932-remove-date-indexes.ts
  5. 1 1
      packages/revisions/migrations/mysql/1669735585016-make-user-uuid-nullable.ts
  6. 8 4
      packages/revisions/migrations/mysql/1693915383950-add-shared-vault-information.ts
  7. 1 1
      packages/revisions/migrations/mysql/1694425333972-rename_revisions_table.ts
  8. 8 34
      packages/revisions/src/Bootstrap/Container.ts
  9. 2 12
      packages/revisions/src/Bootstrap/DataSource.ts
  10. 0 5
      packages/revisions/src/Bootstrap/Types.ts
  11. 0 83
      packages/revisions/src/Infra/TypeORM/SQL/SQLLegacyRevision.ts
  12. 0 161
      packages/revisions/src/Infra/TypeORM/SQL/SQLLegacyRevisionRepository.ts
  13. 81 4
      packages/revisions/src/Infra/TypeORM/SQL/SQLRevision.ts
  14. 86 17
      packages/revisions/src/Infra/TypeORM/SQL/SQLRevisionRepository.ts
  15. 0 51
      packages/revisions/src/Mapping/Persistence/SQL/SQLLegacyRevisionMetadataPersistenceMapper.ts
  16. 0 78
      packages/revisions/src/Mapping/Persistence/SQL/SQLLegacyRevisionPersistenceMapper.ts
  17. 0 50
      packages/syncing-server/migrations/mysql-legacy/1606470249552-init_database.ts
  18. 0 15
      packages/syncing-server/migrations/mysql-legacy/1617615657558-add_extension_settings.ts
  19. 0 27
      packages/syncing-server/migrations/mysql-legacy/1629964808297-drop_unused_indexes.ts
  20. 0 11
      packages/syncing-server/migrations/mysql-legacy/1630318893601-refactor_calculating_integrity_hash.ts
  21. 0 12
      packages/syncing-server/migrations/mysql-legacy/1630417724617-restrict_content_type.ts
  22. 0 26
      packages/syncing-server/migrations/mysql-legacy/1631529502150-add_revision_for_duplicated_items.ts
  23. 0 13
      packages/syncing-server/migrations/mysql-legacy/1631530260504-drop_item_revisions_joining_table.ts
  24. 0 36
      packages/syncing-server/migrations/mysql-legacy/1632219307742-cleanup_orphan_items_and_revisions.ts
  25. 0 28
      packages/syncing-server/migrations/mysql-legacy/1632221263106-add_revisions_items_relation.ts
  26. 0 13
      packages/syncing-server/migrations/mysql-legacy/1637738491169-add_item_content_size.ts
  27. 0 11
      packages/syncing-server/migrations/mysql-legacy/1639134926025-remove_extension_settings.ts
  28. 0 11
      packages/syncing-server/migrations/mysql-legacy/1642073387521-remove_sf_extension_items.ts
  29. 0 11
      packages/syncing-server/migrations/mysql-legacy/1647501696205-remove_user_agent.ts
  30. 0 13
      packages/syncing-server/migrations/mysql-legacy/1654518291191-add_updated_with_session.ts
  31. 0 16
      packages/syncing-server/migrations/mysql-legacy/1689671563304-add-notifications.ts
  32. 0 25
      packages/syncing-server/migrations/mysql-legacy/1689671563305-add-shared-vault-and-key-system-associations.ts
  33. 0 29
      packages/syncing-server/migrations/mysql-legacy/1689677728282-add-shared-vaults-with-users-and-invites.ts
  34. 0 17
      packages/syncing-server/migrations/mysql-legacy/1689745128577-add-messages.ts
  35. 0 27
      packages/syncing-server/migrations/mysql-legacy/1689746180559-rename-key-message-identifier.ts
  36. 0 23
      packages/syncing-server/migrations/mysql-legacy/1690900526061-delete_privileges.ts
  37. 0 11
      packages/syncing-server/migrations/mysql-legacy/1690975361562-update_unknown_content.ts
  38. 0 22
      packages/syncing-server/migrations/mysql-legacy/1692176803410-remove_revisions_foreign_key.ts
  39. 0 21
      packages/syncing-server/migrations/mysql-legacy/1692264556858-remove_associations.ts
  40. 0 13
      packages/syncing-server/migrations/mysql-legacy/1692619430384-remove-shared-vault-limit.ts
  41. 0 13
      packages/syncing-server/migrations/mysql-legacy/1695284084365-add-designated-survivor.ts
  42. 0 11
      packages/syncing-server/migrations/mysql-legacy/1695643525793-remove_notifications.ts
  43. 6 6
      packages/syncing-server/migrations/mysql/1693219736168-add-shared-vault-information.ts
  44. 5 20
      packages/syncing-server/src/Bootstrap/Container.ts
  45. 2 10
      packages/syncing-server/src/Bootstrap/DataSource.ts
  46. 0 2
      packages/syncing-server/src/Bootstrap/Types.ts
  47. 116 4
      packages/syncing-server/src/Infra/TypeORM/SQLItem.ts
  48. 195 20
      packages/syncing-server/src/Infra/TypeORM/SQLItemRepository.ts
  49. 0 118
      packages/syncing-server/src/Infra/TypeORM/SQLLegacyItem.ts
  50. 0 263
      packages/syncing-server/src/Infra/TypeORM/SQLLegacyItemRepository.ts
  51. 0 102
      packages/syncing-server/src/Mapping/Persistence/SQLLegacyItemPersistenceMapper.ts

+ 0 - 41
packages/revisions/migrations/mysql-legacy/1669113322388-init.ts

@@ -1,41 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class init1669113322388 implements MigrationInterface {
-  name = 'init1669113322388'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await this.syncSchemaBetweenLegacyRevisions(queryRunner)
-
-    await queryRunner.query(
-      'CREATE TABLE IF NOT EXISTS `revisions` (`uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `content` mediumtext NULL, `content_type` varchar(255) NULL, `items_key_id` varchar(255) NULL, `enc_item_key` text NULL, `auth_hash` varchar(255) NULL, `creation_date` date NULL, `created_at` datetime(6) NULL, `updated_at` datetime(6) NULL, INDEX `item_uuid` (`item_uuid`), INDEX `user_uuid` (`user_uuid`), INDEX `creation_date` (`creation_date`), INDEX `created_at` (`created_at`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('DROP INDEX `created_at` ON `revisions`')
-    await queryRunner.query('DROP INDEX `creation_date` ON `revisions`')
-    await queryRunner.query('DROP INDEX `user_uuid` ON `revisions`')
-    await queryRunner.query('DROP INDEX `item_uuid` ON `revisions`')
-    await queryRunner.query('DROP TABLE `revisions`')
-  }
-
-  private async syncSchemaBetweenLegacyRevisions(queryRunner: QueryRunner): Promise<void> {
-    const revisionsTableExistsQueryResult = await queryRunner.manager.query(
-      'SELECT COUNT(*) as count FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = "revisions"',
-    )
-    const revisionsTableExists = revisionsTableExistsQueryResult[0].count === 1
-    if (!revisionsTableExists) {
-      return
-    }
-
-    const revisionsTableHasUserUuidColumnQueryResult = await queryRunner.manager.query(
-      'SELECT COUNT(*) as count FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = "revisions" AND column_name = "user_uuid"',
-    )
-    const revisionsTableHasUserUuidColumn = revisionsTableHasUserUuidColumnQueryResult[0].count === 1
-    if (revisionsTableHasUserUuidColumn) {
-      return
-    }
-
-    await queryRunner.query('ALTER TABLE `revisions` ADD COLUMN `user_uuid` varchar(36) NULL')
-  }
-}

+ 0 - 28
packages/revisions/migrations/mysql-legacy/1669636497932-remove-date-indexes.ts

@@ -1,28 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class removeDateIndexes1669636497932 implements MigrationInterface {
-  name = 'removeDateIndexes1669636497932'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    const indexRevisionsOnCreatedAt = await queryRunner.manager.query(
-      'SHOW INDEX FROM `revisions` where `key_name` = "created_at"',
-    )
-    const indexRevisionsOnCreatedAtExist = indexRevisionsOnCreatedAt && indexRevisionsOnCreatedAt.length > 0
-    if (indexRevisionsOnCreatedAtExist) {
-      await queryRunner.query('DROP INDEX `created_at` ON `revisions`')
-    }
-
-    const indexRevisionsOnCreationDate = await queryRunner.manager.query(
-      'SHOW INDEX FROM `revisions` where `key_name` = "creation_date"',
-    )
-    const indexRevisionsOnCreationDateAtExist = indexRevisionsOnCreationDate && indexRevisionsOnCreationDate.length > 0
-    if (indexRevisionsOnCreationDateAtExist) {
-      await queryRunner.query('DROP INDEX `creation_date` ON `revisions`')
-    }
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('CREATE INDEX `creation_date` ON `revisions` (`creation_date`)')
-    await queryRunner.query('CREATE INDEX `created_at` ON `revisions` (`created_at`)')
-  }
-}

+ 0 - 13
packages/revisions/migrations/mysql-legacy/1669735585016-make-user-uuid-nullable.ts

@@ -1,13 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class makeUserUuidNullable1669735585016 implements MigrationInterface {
-  name = 'makeUserUuidNullable1669735585016'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `revisions` CHANGE `user_uuid` `user_uuid` varchar(36) NULL')
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `revisions` CHANGE `user_uuid` `user_uuid` varchar(36) NOT NULL')
-  }
-}

+ 1 - 1
packages/revisions/migrations/mysql/1669636497932-remove-date-indexes.ts

@@ -34,7 +34,7 @@ export class removeDateIndexes1669636497932 implements MigrationInterface {
     )
     const revisionsTableExists = revisionsTableExistsQueryResult[0].count === 1
     if (revisionsTableExists) {
-      await queryRunner.query('RENAME TABLE `revisions` TO `revisions_revisions`')
+      await queryRunner.query('ALTER TABLE `revisions` RENAME TO `revisions_revisions`, ALGORITHM=INSTANT')
     }
   }
 }

+ 1 - 1
packages/revisions/migrations/mysql/1669735585016-make-user-uuid-nullable.ts

@@ -19,7 +19,7 @@ export class makeUserUuidNullable1669735585016 implements MigrationInterface {
     )
     const revisionsTableExists = revisionsTableExistsQueryResult[0].count === 1
     if (revisionsTableExists) {
-      await queryRunner.query('RENAME TABLE `revisions` TO `revisions_revisions`')
+      await queryRunner.query('ALTER TABLE `revisions` RENAME TO `revisions_revisions`, ALGORITHM=INSTANT')
     }
   }
 }

+ 8 - 4
packages/revisions/migrations/mysql/1693915383950-add-shared-vault-information.ts

@@ -4,9 +4,13 @@ export class AddSharedVaultInformation1693915383950 implements MigrationInterfac
   public async up(queryRunner: QueryRunner): Promise<void> {
     await this.renameRevisionsTable(queryRunner)
 
-    await queryRunner.query('ALTER TABLE `revisions_revisions` ADD `edited_by` varchar(36) NULL')
-    await queryRunner.query('ALTER TABLE `revisions_revisions` ADD `shared_vault_uuid` varchar(36) NULL')
-    await queryRunner.query('ALTER TABLE `revisions_revisions` ADD `key_system_identifier` varchar(36) NULL')
+    await queryRunner.query('ALTER TABLE `revisions_revisions` ADD `edited_by` varchar(36) NULL, ALGORITHM = INSTANT')
+    await queryRunner.query(
+      'ALTER TABLE `revisions_revisions` ADD `shared_vault_uuid` varchar(36) NULL, ALGORITHM = INSTANT',
+    )
+    await queryRunner.query(
+      'ALTER TABLE `revisions_revisions` ADD `key_system_identifier` varchar(36) NULL, ALGORITHM = INSTANT',
+    )
     await queryRunner.query(
       'CREATE INDEX `index_revisions_on_shared_vault_uuid` ON `revisions_revisions` (`shared_vault_uuid`)',
     )
@@ -25,7 +29,7 @@ export class AddSharedVaultInformation1693915383950 implements MigrationInterfac
     )
     const revisionsTableExists = revisionsTableExistsQueryResult[0].count === 1
     if (revisionsTableExists) {
-      await queryRunner.query('RENAME TABLE `revisions` TO `revisions_revisions`')
+      await queryRunner.query('ALTER TABLE `revisions` RENAME TO `revisions_revisions`, ALGORITHM=INSTANT')
     }
   }
 }

+ 1 - 1
packages/revisions/migrations/mysql/1694425333972-rename_revisions_table.ts

@@ -9,7 +9,7 @@ export class RenameRevisionsTable1694425333972 implements MigrationInterface {
     )
     const revisionsTableExists = revisionsTableExistsQueryResult[0].count === 1
     if (revisionsTableExists) {
-      await queryRunner.query('RENAME TABLE `revisions` TO `revisions_revisions`')
+      await queryRunner.query('ALTER TABLE `revisions` RENAME TO `revisions_revisions`, ALGORITHM=INSTANT')
     }
   }
 

+ 8 - 34
packages/revisions/src/Bootstrap/Container.ts

@@ -11,8 +11,6 @@ import * as winston from 'winston'
 import { Revision } from '../Domain/Revision/Revision'
 import { RevisionMetadata } from '../Domain/Revision/RevisionMetadata'
 import { RevisionRepositoryInterface } from '../Domain/Revision/RevisionRepositoryInterface'
-import { SQLLegacyRevisionRepository } from '../Infra/TypeORM/SQL/SQLLegacyRevisionRepository'
-import { SQLLegacyRevision } from '../Infra/TypeORM/SQL/SQLLegacyRevision'
 import { AppDataSource } from './DataSource'
 import { Env } from './Env'
 import TYPES from './Types'
@@ -48,8 +46,6 @@ import { S3DumpRepository } from '../Infra/S3/S3ItemDumpRepository'
 import { RevisionItemStringMapper } from '../Mapping/Backup/RevisionItemStringMapper'
 import { BaseRevisionsController } from '../Infra/InversifyExpress/Base/BaseRevisionsController'
 import { Transform } from 'stream'
-import { SQLLegacyRevisionMetadataPersistenceMapper } from '../Mapping/Persistence/SQL/SQLLegacyRevisionMetadataPersistenceMapper'
-import { SQLLegacyRevisionPersistenceMapper } from '../Mapping/Persistence/SQL/SQLLegacyRevisionPersistenceMapper'
 import { RevisionHttpMapper } from '../Mapping/Http/RevisionHttpMapper'
 import { RevisionMetadataHttpRepresentation } from '../Mapping/Http/RevisionMetadataHttpRepresentation'
 import { RevisionHttpRepresentation } from '../Mapping/Http/RevisionHttpRepresentation'
@@ -160,25 +156,14 @@ export class ContainerConfigLoader {
     }
 
     // Map
-    container
-      .bind<MapperInterface<RevisionMetadata, SQLLegacyRevision>>(
-        TYPES.Revisions_SQLLegacyRevisionMetadataPersistenceMapper,
-      )
-      .toConstantValue(new SQLLegacyRevisionMetadataPersistenceMapper())
     container
       .bind<MapperInterface<RevisionMetadata, SQLRevision>>(TYPES.Revisions_SQLRevisionMetadataPersistenceMapper)
       .toConstantValue(new SQLRevisionMetadataPersistenceMapper())
-    container
-      .bind<MapperInterface<Revision, SQLLegacyRevision>>(TYPES.Revisions_SQLLegacyRevisionPersistenceMapper)
-      .toConstantValue(new SQLLegacyRevisionPersistenceMapper(container.get<TimerInterface>(TYPES.Revisions_Timer)))
     container
       .bind<MapperInterface<Revision, SQLRevision>>(TYPES.Revisions_SQLRevisionPersistenceMapper)
       .toConstantValue(new SQLRevisionPersistenceMapper(container.get<TimerInterface>(TYPES.Revisions_Timer)))
 
     // ORM
-    container
-      .bind<Repository<SQLLegacyRevision>>(TYPES.Revisions_ORMLegacyRevisionRepository)
-      .toDynamicValue(() => appDataSource.getRepository(SQLLegacyRevision))
     container
       .bind<Repository<SQLRevision>>(TYPES.Revisions_ORMRevisionRepository)
       .toConstantValue(appDataSource.getRepository(SQLRevision))
@@ -187,25 +172,14 @@ export class ContainerConfigLoader {
     container
       .bind<RevisionRepositoryInterface>(TYPES.Revisions_SQLRevisionRepository)
       .toConstantValue(
-        isConfiguredForHomeServerOrSelfHosting
-          ? new SQLRevisionRepository(
-              container.get<Repository<SQLRevision>>(TYPES.Revisions_ORMRevisionRepository),
-              container.get<MapperInterface<RevisionMetadata, SQLRevision>>(
-                TYPES.Revisions_SQLRevisionMetadataPersistenceMapper,
-              ),
-              container.get<MapperInterface<Revision, SQLRevision>>(TYPES.Revisions_SQLRevisionPersistenceMapper),
-              container.get<winston.Logger>(TYPES.Revisions_Logger),
-            )
-          : new SQLLegacyRevisionRepository(
-              container.get<Repository<SQLLegacyRevision>>(TYPES.Revisions_ORMLegacyRevisionRepository),
-              container.get<MapperInterface<RevisionMetadata, SQLLegacyRevision>>(
-                TYPES.Revisions_SQLLegacyRevisionMetadataPersistenceMapper,
-              ),
-              container.get<MapperInterface<Revision, SQLLegacyRevision>>(
-                TYPES.Revisions_SQLLegacyRevisionPersistenceMapper,
-              ),
-              container.get<winston.Logger>(TYPES.Revisions_Logger),
-            ),
+        new SQLRevisionRepository(
+          container.get<Repository<SQLRevision>>(TYPES.Revisions_ORMRevisionRepository),
+          container.get<MapperInterface<RevisionMetadata, SQLRevision>>(
+            TYPES.Revisions_SQLRevisionMetadataPersistenceMapper,
+          ),
+          container.get<MapperInterface<Revision, SQLRevision>>(TYPES.Revisions_SQLRevisionPersistenceMapper),
+          container.get<winston.Logger>(TYPES.Revisions_Logger),
+        ),
       )
 
     container

+ 2 - 12
packages/revisions/src/Bootstrap/DataSource.ts

@@ -1,8 +1,6 @@
 import { DataSource, EntityTarget, LoggerOptions, ObjectLiteral, Repository } from 'typeorm'
 import { MysqlConnectionOptions } from 'typeorm/driver/mysql/MysqlConnectionOptions'
 
-import { SQLLegacyRevision } from '../Infra/TypeORM/SQL/SQLLegacyRevision'
-
 import { Env } from './Env'
 import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions'
 import { SQLRevision } from '../Infra/TypeORM/SQL/SQLRevision'
@@ -34,23 +32,15 @@ export class AppDataSource {
 
     const isConfiguredForMySQL = this.configuration.env.get('DB_TYPE') === 'mysql'
 
-    const isConfiguredForHomeServerOrSelfHosting =
-      this.configuration.env.get('MODE', true) === 'home-server' ||
-      this.configuration.env.get('MODE', true) === 'self-hosted'
-
     const maxQueryExecutionTime = this.configuration.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
       ? +this.configuration.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
       : 45_000
 
-    const migrationsSourceDirectoryName = isConfiguredForMySQL
-      ? isConfiguredForHomeServerOrSelfHosting
-        ? 'mysql'
-        : 'mysql-legacy'
-      : 'sqlite'
+    const migrationsSourceDirectoryName = isConfiguredForMySQL ? 'mysql' : 'sqlite'
 
     const commonDataSourceOptions = {
       maxQueryExecutionTime,
-      entities: [isConfiguredForHomeServerOrSelfHosting ? SQLRevision : SQLLegacyRevision],
+      entities: [SQLRevision],
       migrations: [`${__dirname}/../../migrations/${migrationsSourceDirectoryName}/*.js`],
       migrationsRun: this.configuration.runMigrations,
       logging: <LoggerOptions>this.configuration.env.get('DB_DEBUG_LEVEL', true) ?? 'info',

+ 0 - 5
packages/revisions/src/Bootstrap/Types.ts

@@ -7,18 +7,13 @@ const TYPES = {
   Revisions_S3: Symbol.for('Revisions_S3'),
   Revisions_Env: Symbol.for('Revisions_Env'),
   // Map
-  Revisions_SQLLegacyRevisionMetadataPersistenceMapper: Symbol.for(
-    'Revisions_SQLLegacyRevisionMetadataPersistenceMapper',
-  ),
   Revisions_SQLRevisionMetadataPersistenceMapper: Symbol.for('Revisions_SQLRevisionMetadataPersistenceMapper'),
-  Revisions_SQLLegacyRevisionPersistenceMapper: Symbol.for('Revisions_SQLLegacyRevisionPersistenceMapper'),
   Revisions_SQLRevisionPersistenceMapper: Symbol.for('Revisions_SQLRevisionPersistenceMapper'),
   Revisions_RevisionItemStringMapper: Symbol.for('Revisions_RevisionItemStringMapper'),
   Revisions_RevisionHttpMapper: Symbol.for('Revisions_RevisionHttpMapper'),
   Revisions_RevisionMetadataHttpMapper: Symbol.for('Revisions_RevisionMetadataHttpMapper'),
   // ORM
   Revisions_ORMRevisionRepository: Symbol.for('Revisions_ORMRevisionRepository'),
-  Revisions_ORMLegacyRevisionRepository: Symbol.for('Revisions_ORMLegacyRevisionRepository'),
   // Repositories
   Revisions_SQLRevisionRepository: Symbol.for('Revisions_SQLRevisionRepository'),
   Revisions_DumpRepository: Symbol.for('Revisions_DumpRepository'),

+ 0 - 83
packages/revisions/src/Infra/TypeORM/SQL/SQLLegacyRevision.ts

@@ -1,83 +0,0 @@
-import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'
-
-@Entity({ name: 'revisions' })
-export class SQLLegacyRevision {
-  @PrimaryGeneratedColumn('uuid')
-  declare uuid: string
-
-  @Column({
-    name: 'item_uuid',
-    length: 36,
-  })
-  @Index('item_uuid')
-  declare itemUuid: string
-
-  @Column({
-    name: 'user_uuid',
-    length: 36,
-    type: 'varchar',
-    nullable: true,
-  })
-  @Index('user_uuid')
-  declare userUuid: string | null
-
-  @Column({
-    type: 'text',
-    nullable: true,
-  })
-  declare content: string | null
-
-  @Column({
-    name: 'content_type',
-    type: 'varchar',
-    length: 255,
-    nullable: true,
-  })
-  declare contentType: string | null
-
-  @Column({
-    type: 'varchar',
-    name: 'items_key_id',
-    length: 255,
-    nullable: true,
-  })
-  declare itemsKeyId: string | null
-
-  @Column({
-    name: 'enc_item_key',
-    type: 'text',
-    nullable: true,
-  })
-  declare encItemKey: string | null
-
-  @Column({
-    name: 'auth_hash',
-    type: 'varchar',
-    length: 255,
-    nullable: true,
-  })
-  declare authHash: string | null
-
-  @Column({
-    name: 'creation_date',
-    type: 'date',
-    nullable: true,
-  })
-  declare creationDate: Date
-
-  @Column({
-    name: 'created_at',
-    type: 'datetime',
-    precision: 6,
-    nullable: true,
-  })
-  declare createdAt: Date
-
-  @Column({
-    name: 'updated_at',
-    type: 'datetime',
-    precision: 6,
-    nullable: true,
-  })
-  declare updatedAt: Date
-}

+ 0 - 161
packages/revisions/src/Infra/TypeORM/SQL/SQLLegacyRevisionRepository.ts

@@ -1,161 +0,0 @@
-import { MapperInterface, Uuid } from '@standardnotes/domain-core'
-import { Repository } from 'typeorm'
-import { Logger } from 'winston'
-
-import { Revision } from '../../../Domain/Revision/Revision'
-import { RevisionMetadata } from '../../../Domain/Revision/RevisionMetadata'
-import { RevisionRepositoryInterface } from '../../../Domain/Revision/RevisionRepositoryInterface'
-import { SQLLegacyRevision } from './SQLLegacyRevision'
-
-export class SQLLegacyRevisionRepository implements RevisionRepositoryInterface {
-  constructor(
-    protected ormRepository: Repository<SQLLegacyRevision>,
-    protected revisionMetadataMapper: MapperInterface<RevisionMetadata, SQLLegacyRevision>,
-    protected revisionMapper: MapperInterface<Revision, SQLLegacyRevision>,
-    protected logger: Logger,
-  ) {}
-
-  async clearSharedVaultAndKeySystemAssociations(_dto: { itemUuid?: Uuid; sharedVaultUuid: Uuid }): Promise<void> {
-    this.logger.error('Method clearSharedVaultAndKeySystemAssociations not implemented.')
-  }
-
-  async countByUserUuid(userUuid: Uuid): Promise<number> {
-    return this.ormRepository
-      .createQueryBuilder()
-      .where('user_uuid = :userUuid', { userUuid: userUuid.value })
-      .getCount()
-  }
-
-  async findByUserUuid(dto: { userUuid: Uuid; offset?: number; limit?: number }): Promise<Revision[]> {
-    const queryBuilder = this.ormRepository
-      .createQueryBuilder('revision')
-      .where('revision.user_uuid = :userUuid', { userUuid: dto.userUuid.value })
-      .orderBy('revision.created_at', 'ASC')
-
-    if (dto.offset !== undefined) {
-      queryBuilder.skip(dto.offset)
-    }
-
-    if (dto.limit !== undefined) {
-      queryBuilder.take(dto.limit)
-    }
-
-    const sqlRevisions = await queryBuilder.getMany()
-
-    const revisions = []
-    for (const sqlRevision of sqlRevisions) {
-      revisions.push(this.revisionMapper.toDomain(sqlRevision))
-    }
-
-    return revisions
-  }
-
-  async updateUserUuid(itemUuid: Uuid, userUuid: Uuid): Promise<void> {
-    await this.ormRepository
-      .createQueryBuilder()
-      .update()
-      .set({
-        userUuid: userUuid.value,
-      })
-      .where('item_uuid = :itemUuid', { itemUuid: itemUuid.value })
-      .execute()
-  }
-
-  async findByItemUuid(itemUuid: Uuid): Promise<Revision[]> {
-    const SQLLegacyRevisions = await this.ormRepository
-      .createQueryBuilder()
-      .where('item_uuid = :itemUuid', { itemUuid: itemUuid.value })
-      .getMany()
-
-    const revisions = []
-    for (const revision of SQLLegacyRevisions) {
-      revisions.push(this.revisionMapper.toDomain(revision))
-    }
-
-    return revisions
-  }
-
-  async removeByUserUuid(userUuid: Uuid): Promise<void> {
-    await this.ormRepository
-      .createQueryBuilder()
-      .delete()
-      .from('revisions')
-      .where('user_uuid = :userUuid', { userUuid: userUuid.value })
-      .execute()
-  }
-
-  async removeOneByUuid(revisionUuid: Uuid, userUuid: Uuid): Promise<void> {
-    await this.ormRepository
-      .createQueryBuilder()
-      .delete()
-      .from('revisions')
-      .where('uuid = :revisionUuid AND user_uuid = :userUuid', {
-        userUuid: userUuid.value,
-        revisionUuid: revisionUuid.value,
-      })
-      .execute()
-  }
-
-  async findOneByUuid(revisionUuid: Uuid, userUuid: Uuid, _sharedVaultUuids: Uuid[]): Promise<Revision | null> {
-    const SQLLegacyRevision = await this.ormRepository
-      .createQueryBuilder()
-      .where('uuid = :revisionUuid', { revisionUuid: revisionUuid.value })
-      .andWhere('user_uuid = :userUuid', { userUuid: userUuid.value })
-      .getOne()
-
-    if (SQLLegacyRevision === null) {
-      return null
-    }
-
-    return this.revisionMapper.toDomain(SQLLegacyRevision)
-  }
-
-  async insert(revision: Revision): Promise<boolean> {
-    const projection = this.revisionMapper.toProjection(revision)
-
-    await this.ormRepository.insert(projection)
-
-    return true
-  }
-
-  async update(revision: Revision): Promise<boolean> {
-    const projection = this.revisionMapper.toProjection(revision)
-
-    const { uuid, ...rest } = projection
-
-    await this.ormRepository.update({ uuid: uuid }, rest)
-
-    return true
-  }
-
-  async findMetadataByItemId(
-    itemUuid: Uuid,
-    userUuid: Uuid,
-    _sharedVaultUuids: Uuid[],
-  ): Promise<Array<RevisionMetadata>> {
-    const queryBuilder = this.ormRepository
-      .createQueryBuilder()
-      .select('uuid', 'uuid')
-      .addSelect('content_type', 'contentType')
-      .addSelect('created_at', 'createdAt')
-      .addSelect('updated_at', 'updatedAt')
-      .addSelect('item_uuid', 'itemUuid')
-      .where('item_uuid = :itemUuid', { itemUuid: itemUuid.value })
-      .andWhere('user_uuid = :userUuid', { userUuid: userUuid.value })
-      .orderBy('created_at', 'DESC')
-
-    const simplifiedRevisions = await queryBuilder.getRawMany()
-
-    this.logger.debug(
-      `Found ${simplifiedRevisions.length} revisions entries for item ${itemUuid.value}`,
-      simplifiedRevisions,
-    )
-
-    const metadata = []
-    for (const simplifiedRevision of simplifiedRevisions) {
-      metadata.push(this.revisionMetadataMapper.toDomain(simplifiedRevision))
-    }
-
-    return metadata
-  }
-}

+ 81 - 4
packages/revisions/src/Infra/TypeORM/SQL/SQLRevision.ts

@@ -1,9 +1,86 @@
-import { Column, Entity, Index } from 'typeorm'
-
-import { SQLLegacyRevision } from './SQLLegacyRevision'
+import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'
 
 @Entity({ name: 'revisions_revisions' })
-export class SQLRevision extends SQLLegacyRevision {
+export class SQLRevision {
+  @PrimaryGeneratedColumn('uuid')
+  declare uuid: string
+
+  @Column({
+    name: 'item_uuid',
+    length: 36,
+  })
+  @Index('item_uuid')
+  declare itemUuid: string
+
+  @Column({
+    name: 'user_uuid',
+    length: 36,
+    type: 'varchar',
+    nullable: true,
+  })
+  @Index('user_uuid')
+  declare userUuid: string | null
+
+  @Column({
+    type: 'text',
+    nullable: true,
+  })
+  declare content: string | null
+
+  @Column({
+    name: 'content_type',
+    type: 'varchar',
+    length: 255,
+    nullable: true,
+  })
+  declare contentType: string | null
+
+  @Column({
+    type: 'varchar',
+    name: 'items_key_id',
+    length: 255,
+    nullable: true,
+  })
+  declare itemsKeyId: string | null
+
+  @Column({
+    name: 'enc_item_key',
+    type: 'text',
+    nullable: true,
+  })
+  declare encItemKey: string | null
+
+  @Column({
+    name: 'auth_hash',
+    type: 'varchar',
+    length: 255,
+    nullable: true,
+  })
+  declare authHash: string | null
+
+  @Column({
+    name: 'creation_date',
+    type: 'date',
+    nullable: true,
+  })
+  declare creationDate: Date
+
+  @Column({
+    name: 'created_at',
+    type: 'datetime',
+    precision: 6,
+    nullable: true,
+  })
+  declare createdAt: Date
+
+  @Column({
+    name: 'updated_at',
+    type: 'datetime',
+    precision: 6,
+    nullable: true,
+  })
+  declare updatedAt: Date
+
   @Column({
     type: 'varchar',
     name: 'edited_by',

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

@@ -4,20 +4,18 @@ import { Logger } from 'winston'
 
 import { Revision } from '../../../Domain/Revision/Revision'
 import { RevisionMetadata } from '../../../Domain/Revision/RevisionMetadata'
-import { SQLLegacyRevisionRepository } from './SQLLegacyRevisionRepository'
+import { RevisionRepositoryInterface } from '../../../Domain/Revision/RevisionRepositoryInterface'
 import { SQLRevision } from './SQLRevision'
 
-export class SQLRevisionRepository extends SQLLegacyRevisionRepository {
+export class SQLRevisionRepository implements RevisionRepositoryInterface {
   constructor(
-    protected override ormRepository: Repository<SQLRevision>,
-    protected override revisionMetadataMapper: MapperInterface<RevisionMetadata, SQLRevision>,
-    protected override revisionMapper: MapperInterface<Revision, SQLRevision>,
-    protected override logger: Logger,
-  ) {
-    super(ormRepository, revisionMetadataMapper, revisionMapper, logger)
-  }
+    protected ormRepository: Repository<SQLRevision>,
+    protected revisionMetadataMapper: MapperInterface<RevisionMetadata, SQLRevision>,
+    protected revisionMapper: MapperInterface<Revision, SQLRevision>,
+    protected logger: Logger,
+  ) {}
 
-  override async removeByUserUuid(userUuid: Uuid): Promise<void> {
+  async removeByUserUuid(userUuid: Uuid): Promise<void> {
     await this.ormRepository
       .createQueryBuilder()
       .delete()
@@ -26,7 +24,7 @@ export class SQLRevisionRepository extends SQLLegacyRevisionRepository {
       .execute()
   }
 
-  override async removeOneByUuid(revisionUuid: Uuid, userUuid: Uuid): Promise<void> {
+  async removeOneByUuid(revisionUuid: Uuid, userUuid: Uuid): Promise<void> {
     await this.ormRepository
       .createQueryBuilder()
       .delete()
@@ -38,7 +36,7 @@ export class SQLRevisionRepository extends SQLLegacyRevisionRepository {
       .execute()
   }
 
-  override async findOneByUuid(revisionUuid: Uuid, userUuid: Uuid, sharedVaultUuids: Uuid[]): Promise<Revision | null> {
+  async findOneByUuid(revisionUuid: Uuid, userUuid: Uuid, sharedVaultUuids: Uuid[]): Promise<Revision | null> {
     const queryBuilder = this.ormRepository.createQueryBuilder()
 
     if (sharedVaultUuids.length > 0) {
@@ -66,10 +64,7 @@ export class SQLRevisionRepository extends SQLLegacyRevisionRepository {
     return this.revisionMapper.toDomain(sqlRevision)
   }
 
-  override async clearSharedVaultAndKeySystemAssociations(dto: {
-    itemUuid?: Uuid
-    sharedVaultUuid: Uuid
-  }): Promise<void> {
+  async clearSharedVaultAndKeySystemAssociations(dto: { itemUuid?: Uuid; sharedVaultUuid: Uuid }): Promise<void> {
     const queryBuilder = this.ormRepository.createQueryBuilder().update().set({
       sharedVaultUuid: null,
       keySystemIdentifier: null,
@@ -89,7 +84,7 @@ export class SQLRevisionRepository extends SQLLegacyRevisionRepository {
     await queryBuilder.execute()
   }
 
-  override async findMetadataByItemId(
+  async findMetadataByItemId(
     itemUuid: Uuid,
     userUuid: Uuid,
     sharedVaultUuids: Uuid[],
@@ -134,4 +129,78 @@ export class SQLRevisionRepository extends SQLLegacyRevisionRepository {
 
     return metadata
   }
+
+  async countByUserUuid(userUuid: Uuid): Promise<number> {
+    return this.ormRepository
+      .createQueryBuilder()
+      .where('user_uuid = :userUuid', { userUuid: userUuid.value })
+      .getCount()
+  }
+
+  async findByUserUuid(dto: { userUuid: Uuid; offset?: number; limit?: number }): Promise<Revision[]> {
+    const queryBuilder = this.ormRepository
+      .createQueryBuilder('revision')
+      .where('revision.user_uuid = :userUuid', { userUuid: dto.userUuid.value })
+      .orderBy('revision.created_at', 'ASC')
+
+    if (dto.offset !== undefined) {
+      queryBuilder.skip(dto.offset)
+    }
+
+    if (dto.limit !== undefined) {
+      queryBuilder.take(dto.limit)
+    }
+
+    const sqlRevisions = await queryBuilder.getMany()
+
+    const revisions = []
+    for (const sqlRevision of sqlRevisions) {
+      revisions.push(this.revisionMapper.toDomain(sqlRevision))
+    }
+
+    return revisions
+  }
+
+  async updateUserUuid(itemUuid: Uuid, userUuid: Uuid): Promise<void> {
+    await this.ormRepository
+      .createQueryBuilder()
+      .update()
+      .set({
+        userUuid: userUuid.value,
+      })
+      .where('item_uuid = :itemUuid', { itemUuid: itemUuid.value })
+      .execute()
+  }
+
+  async findByItemUuid(itemUuid: Uuid): Promise<Revision[]> {
+    const SQLRevisions = await this.ormRepository
+      .createQueryBuilder()
+      .where('item_uuid = :itemUuid', { itemUuid: itemUuid.value })
+      .getMany()
+
+    const revisions = []
+    for (const revision of SQLRevisions) {
+      revisions.push(this.revisionMapper.toDomain(revision))
+    }
+
+    return revisions
+  }
+
+  async insert(revision: Revision): Promise<boolean> {
+    const projection = this.revisionMapper.toProjection(revision)
+
+    await this.ormRepository.insert(projection)
+
+    return true
+  }
+
+  async update(revision: Revision): Promise<boolean> {
+    const projection = this.revisionMapper.toProjection(revision)
+
+    const { uuid, ...rest } = projection
+
+    await this.ormRepository.update({ uuid: uuid }, rest)
+
+    return true
+  }
 }

+ 0 - 51
packages/revisions/src/Mapping/Persistence/SQL/SQLLegacyRevisionMetadataPersistenceMapper.ts

@@ -1,51 +0,0 @@
-import { MapperInterface, Dates, UniqueEntityId, ContentType, Uuid } from '@standardnotes/domain-core'
-
-import { RevisionMetadata } from '../../../Domain/Revision/RevisionMetadata'
-import { SQLLegacyRevision } from '../../../Infra/TypeORM/SQL/SQLLegacyRevision'
-
-export class SQLLegacyRevisionMetadataPersistenceMapper
-  implements MapperInterface<RevisionMetadata, SQLLegacyRevision>
-{
-  toDomain(projection: SQLLegacyRevision): RevisionMetadata {
-    const contentTypeOrError = ContentType.create(projection.contentType)
-    if (contentTypeOrError.isFailed()) {
-      throw new Error(`Could not create content type: ${contentTypeOrError.getError()}`)
-    }
-    const contentType = contentTypeOrError.getValue()
-
-    const createdAt = projection.createdAt instanceof Date ? projection.createdAt : new Date(projection.createdAt)
-    const updatedAt = projection.updatedAt instanceof Date ? projection.updatedAt : new Date(projection.updatedAt)
-
-    const datesOrError = Dates.create(createdAt, updatedAt)
-    if (datesOrError.isFailed()) {
-      throw new Error(`Could not create dates: ${datesOrError.getError()}`)
-    }
-    const dates = datesOrError.getValue()
-
-    const itemUuidOrError = Uuid.create(projection.itemUuid)
-    if (itemUuidOrError.isFailed()) {
-      throw new Error(`Could not create item uuid: ${itemUuidOrError.getError()}`)
-    }
-    const itemUuid = itemUuidOrError.getValue()
-
-    const revisionMetadataOrError = RevisionMetadata.create(
-      {
-        contentType,
-        dates,
-        sharedVaultUuid: null,
-        itemUuid,
-      },
-      new UniqueEntityId(projection.uuid),
-    )
-
-    if (revisionMetadataOrError.isFailed()) {
-      throw new Error(`Could not create revision metdata: ${revisionMetadataOrError.getError()}`)
-    }
-
-    return revisionMetadataOrError.getValue()
-  }
-
-  toProjection(_domain: RevisionMetadata): SQLLegacyRevision {
-    throw new Error('Method not implemented.')
-  }
-}

+ 0 - 78
packages/revisions/src/Mapping/Persistence/SQL/SQLLegacyRevisionPersistenceMapper.ts

@@ -1,78 +0,0 @@
-import { MapperInterface, Dates, UniqueEntityId, Uuid, ContentType } from '@standardnotes/domain-core'
-import { TimerInterface } from '@standardnotes/time'
-
-import { Revision } from '../../../Domain/Revision/Revision'
-import { SQLLegacyRevision } from '../../../Infra/TypeORM/SQL/SQLLegacyRevision'
-
-export class SQLLegacyRevisionPersistenceMapper implements MapperInterface<Revision, SQLLegacyRevision> {
-  constructor(private timer: TimerInterface) {}
-
-  toDomain(projection: SQLLegacyRevision): Revision {
-    const contentTypeOrError = ContentType.create(projection.contentType)
-    if (contentTypeOrError.isFailed()) {
-      throw new Error(`Could not map typeorm revision to domain revision: ${contentTypeOrError.getError()}`)
-    }
-    const contentType = contentTypeOrError.getValue()
-
-    const datesOrError = Dates.create(projection.createdAt, projection.updatedAt)
-    if (datesOrError.isFailed()) {
-      throw new Error(`Could not map typeorm revision to domain revision: ${datesOrError.getError()}`)
-    }
-    const dates = datesOrError.getValue()
-
-    const itemUuidOrError = Uuid.create(projection.itemUuid)
-    if (itemUuidOrError.isFailed()) {
-      throw new Error(`Could not map typeorm revision to domain revision: ${itemUuidOrError.getError()}`)
-    }
-    const itemUuid = itemUuidOrError.getValue()
-
-    let userUuid = null
-    if (projection.userUuid !== null) {
-      const userUuidOrError = Uuid.create(projection.userUuid)
-      if (userUuidOrError.isFailed()) {
-        throw new Error(`Could not map typeorm revision to domain revision: ${userUuidOrError.getError()}`)
-      }
-      userUuid = userUuidOrError.getValue()
-    }
-
-    const revisionOrError = Revision.create(
-      {
-        authHash: projection.authHash,
-        content: projection.content,
-        contentType,
-        creationDate: new Date(this.timer.convertDateToFormattedString(projection.creationDate, 'YYYY-MM-DD')),
-        encItemKey: projection.encItemKey,
-        itemsKeyId: projection.itemsKeyId,
-        itemUuid,
-        userUuid,
-        dates,
-      },
-      new UniqueEntityId(projection.uuid),
-    )
-    if (revisionOrError.isFailed()) {
-      throw new Error(`Could not map typeorm revision to domain revision: ${revisionOrError.getError()}`)
-    }
-
-    return revisionOrError.getValue()
-  }
-
-  toProjection(domain: Revision): SQLLegacyRevision {
-    const sqlRevision = new SQLLegacyRevision()
-
-    sqlRevision.authHash = domain.props.authHash
-    sqlRevision.content = domain.props.content
-    sqlRevision.contentType = domain.props.contentType.value
-    sqlRevision.createdAt = domain.props.dates.createdAt
-    sqlRevision.updatedAt = domain.props.dates.updatedAt
-    sqlRevision.creationDate = new Date(
-      this.timer.convertDateToFormattedString(domain.props.creationDate, 'YYYY-MM-DD'),
-    )
-    sqlRevision.encItemKey = domain.props.encItemKey
-    sqlRevision.itemUuid = domain.props.itemUuid.value
-    sqlRevision.itemsKeyId = domain.props.itemsKeyId
-    sqlRevision.userUuid = domain.props.userUuid ? domain.props.userUuid.value : null
-    sqlRevision.uuid = domain.id.toString()
-
-    return sqlRevision
-  }
-}

+ 0 - 50
packages/syncing-server/migrations/mysql-legacy/1606470249552-init_database.ts

@@ -1,50 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class initDatabase1606470249552 implements MigrationInterface {
-  name = 'initDatabase1606470249552'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await this.fixUpdatedAtTimestampsFromLegacyMigration(queryRunner)
-
-    await queryRunner.query(
-      'CREATE TABLE IF NOT EXISTS `items` (`uuid` varchar(36) NOT NULL, `duplicate_of` varchar(36) NULL, `items_key_id` varchar(255) NULL, `content` mediumtext NULL, `content_type` varchar(255) NULL, `enc_item_key` text NULL, `auth_hash` varchar(255) NULL, `user_uuid` varchar(36) NULL, `deleted` tinyint(1) NULL DEFAULT 0, `last_user_agent` text NULL, `created_at` datetime(6) NOT NULL, `updated_at` datetime(6) NOT NULL, `created_at_timestamp` BIGINT NOT NULL, `updated_at_timestamp` BIGINT NOT NULL, INDEX `index_items_on_content_type` (`content_type`), INDEX `index_items_on_user_uuid` (`user_uuid`), INDEX `index_items_on_deleted` (`deleted`), INDEX `updated_at_timestamp` (`updated_at_timestamp`), INDEX `index_items_on_updated_at` (`updated_at`), INDEX `user_uuid_and_updated_at_timestamp_and_created_at_timestamp` (`user_uuid`, `updated_at_timestamp`, `created_at_timestamp`), INDEX `index_items_on_user_uuid_and_updated_at_and_created_at` (`user_uuid`, `updated_at`, `created_at`), INDEX `index_items_on_user_uuid_and_content_type` (`user_uuid`, `content_type`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-    await queryRunner.query(
-      'CREATE TABLE IF NOT EXISTS `revisions` (`uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NULL, `content` mediumtext NULL, `content_type` varchar(255) NULL, `items_key_id` varchar(255) NULL, `enc_item_key` text NULL, `auth_hash` varchar(255) NULL, `creation_date` date NULL, `created_at` datetime(6) NULL, `updated_at` datetime(6) NULL, INDEX `index_revisions_on_item_uuid` (`item_uuid`), INDEX `index_revisions_on_creation_date` (`creation_date`), INDEX `index_revisions_on_created_at` (`created_at`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-    await queryRunner.query(
-      'CREATE TABLE IF NOT EXISTS `item_revisions` (`uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NOT NULL, `revision_uuid` varchar(36) NOT NULL, INDEX `index_item_revisions_on_item_uuid` (`item_uuid`), INDEX `index_item_revisions_on_revision_uuid` (`revision_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-  }
-
-  public async down(_queryRunner: QueryRunner): Promise<void> {
-    return
-  }
-
-  private async fixUpdatedAtTimestampsFromLegacyMigration(queryRunner: QueryRunner): Promise<void> {
-    const itemsTableExistsQueryResult = await queryRunner.manager.query(
-      'SELECT COUNT(*) as count FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = "items"',
-    )
-    const itemsTableExists = itemsTableExistsQueryResult[0].count === 1
-    if (!itemsTableExists) {
-      return
-    }
-
-    const updatedAtTimestampColumnExistsQueryResult = await queryRunner.manager.query(
-      'SELECT COUNT(*) as count FROM information_schema.columns WHERE table_schema = DATABASE() AND table_name = "items" AND column_name = "updated_at_timestamp"',
-    )
-    const updatedAtTimestampColumnExists = updatedAtTimestampColumnExistsQueryResult[0].count === 1
-    if (updatedAtTimestampColumnExists) {
-      return
-    }
-
-    await queryRunner.query('ALTER TABLE `items` ADD COLUMN `updated_at_timestamp` BIGINT NOT NULL')
-    await queryRunner.query('ALTER TABLE `items` ADD COLUMN `created_at_timestamp` BIGINT NOT NULL')
-    await queryRunner.query(
-      'ALTER TABLE `items` ADD INDEX `user_uuid_and_updated_at_timestamp_and_created_at_timestamp` (`user_uuid`, `updated_at_timestamp`, `created_at_timestamp`)',
-    )
-    await queryRunner.query('ALTER TABLE `items` ADD INDEX `updated_at_timestamp` (`updated_at_timestamp`)')
-    await queryRunner.query('UPDATE `items` SET `created_at_timestamp` = UNIX_TIMESTAMP(`created_at`) * 1000000')
-    await queryRunner.query('UPDATE `items` SET `updated_at_timestamp` = UNIX_TIMESTAMP(`updated_at`) * 1000000')
-  }
-}

+ 0 - 15
packages/syncing-server/migrations/mysql-legacy/1617615657558-add_extension_settings.ts

@@ -1,15 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class addExtensionSettings1617615657558 implements MigrationInterface {
-  name = 'addExtensionSettings1617615657558'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query(
-      'CREATE TABLE IF NOT EXISTS `extension_settings` (`uuid` varchar(36) NOT NULL, `extension_id` varchar(255) NULL, `mute_emails` tinyint(1) NULL DEFAULT 0, `created_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, `updated_at` datetime NOT NULL DEFAULT CURRENT_TIMESTAMP, INDEX `index_extension_settings_on_extension_id` (`extension_id`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-  }
-
-  public async down(_queryRunner: QueryRunner): Promise<void> {
-    return
-  }
-}

+ 0 - 27
packages/syncing-server/migrations/mysql-legacy/1629964808297-drop_unused_indexes.ts

@@ -1,27 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class dropUnusedIndexes1629964808297 implements MigrationInterface {
-  name = 'dropUnusedIndexes1629964808297'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    const indexItemsOnUserAndTimestamp = await queryRunner.manager.query(
-      'SHOW INDEX FROM `items` where `key_name` = "index_items_on_user_uuid_and_updated_at_and_created_at"',
-    )
-    const indexItemsOnUserAndTimestampExists = indexItemsOnUserAndTimestamp && indexItemsOnUserAndTimestamp.length > 0
-    if (indexItemsOnUserAndTimestampExists) {
-      await queryRunner.query('ALTER TABLE `items` DROP INDEX index_items_on_user_uuid_and_updated_at_and_created_at')
-    }
-
-    const indexItemsOnUpdatedAt = await queryRunner.manager.query(
-      'SHOW INDEX FROM `items` where `key_name` = "index_items_on_updated_at"',
-    )
-    const indexItemsOnUpdatedAtExists = indexItemsOnUpdatedAt && indexItemsOnUpdatedAt.length > 0
-    if (indexItemsOnUpdatedAtExists) {
-      await queryRunner.query('ALTER TABLE `items` DROP INDEX index_items_on_updated_at')
-    }
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 11
packages/syncing-server/migrations/mysql-legacy/1630318893601-refactor_calculating_integrity_hash.ts

@@ -1,11 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class refactorCalculatingIntegrityHash1630318893601 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `items` ADD INDEX `user_uuid_and_deleted` (`user_uuid`, `deleted`)')
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 12
packages/syncing-server/migrations/mysql-legacy/1630417724617-restrict_content_type.ts

@@ -1,12 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class restrictContentType1630417724617 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('UPDATE `items` SET content_type = "Unknown" WHERE `content_type` IS NULL')
-    await queryRunner.query('ALTER TABLE `items` CHANGE `content_type` `content_type` varchar(255) NOT NULL')
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 26
packages/syncing-server/migrations/mysql-legacy/1631529502150-add_revision_for_duplicated_items.ts

@@ -1,26 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-import { v4 } from 'uuid'
-
-export class addRevisionForDuplicatedItems1631529502150 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    const itemRevisions = await queryRunner.manager.query(
-      'SELECT r.uuid as originalRevisionUuid, ir.item_uuid as properItemUuid, ir.uuid as relationUuid FROM revisions r INNER JOIN item_revisions ir ON ir.revision_uuid = r.uuid AND ir.item_uuid <> r.item_uuid',
-    )
-
-    for (const itemRevision of itemRevisions) {
-      const revisionUuid = v4()
-
-      await queryRunner.manager.query(
-        `INSERT INTO revisions (uuid, item_uuid, content, content_type, items_key_id, enc_item_key, auth_hash, creation_date, created_at, updated_at) SELECT "${revisionUuid}", "${itemRevision['properItemUuid']}", content, content_type, items_key_id, enc_item_key, auth_hash, creation_date, created_at, updated_at FROM revisions WHERE uuid = "${itemRevision['originalRevisionUuid']}"`,
-      )
-      await queryRunner.manager.query(
-        `UPDATE item_revisions SET revision_uuid = "${revisionUuid}" WHERE uuid = "${itemRevision['relationUuid']}"`,
-      )
-    }
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 13
packages/syncing-server/migrations/mysql-legacy/1631530260504-drop_item_revisions_joining_table.ts

@@ -1,13 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class dropItemRevisionsJoiningTable1631530260504 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('DROP TABLE `item_revisions`')
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query(
-      'CREATE TABLE `item_revisions` (`uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NOT NULL, `revision_uuid` varchar(36) NOT NULL, INDEX `index_item_revisions_on_item_uuid` (`item_uuid`), INDEX `index_item_revisions_on_revision_uuid` (`revision_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-  }
-}

+ 0 - 36
packages/syncing-server/migrations/mysql-legacy/1632219307742-cleanup_orphan_items_and_revisions.ts

@@ -1,36 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class cleanupOrphanItemsAndRevisions1632219307742 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    const usersTableExistsQueryResult = await queryRunner.manager.query(
-      'SELECT COUNT(*) as count FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = "users"',
-    )
-    const usersTableExists = usersTableExistsQueryResult[0].count === 1
-    if (usersTableExists) {
-      const orphanedItems = await queryRunner.manager.query(
-        'SELECT i.uuid as uuid FROM items i LEFT JOIN users u ON i.user_uuid = u.uuid WHERE u.uuid IS NULL',
-      )
-
-      for (const orphanedItem of orphanedItems) {
-        await queryRunner.manager.query(`DELETE FROM revisions WHERE item_uuid = "${orphanedItem['uuid']}"`)
-        await queryRunner.manager.query(`DELETE FROM items WHERE uuid = "${orphanedItem['uuid']}"`)
-      }
-    }
-
-    await queryRunner.manager.query('DELETE FROM items WHERE user_uuid IS NULL')
-
-    const orphanedRevisions = await queryRunner.manager.query(
-      'SELECT r.uuid as uuid FROM revisions r LEFT JOIN items i ON r.item_uuid = i.uuid WHERE i.uuid IS NULL',
-    )
-
-    for (const orphanedRevision of orphanedRevisions) {
-      await queryRunner.manager.query(`DELETE FROM revisions WHERE uuid = "${orphanedRevision['uuid']}"`)
-    }
-
-    await queryRunner.manager.query('DELETE FROM revisions WHERE item_uuid IS NULL')
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 28
packages/syncing-server/migrations/mysql-legacy/1632221263106-add_revisions_items_relation.ts

@@ -1,28 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class addRevisionsItemsRelation1632221263106 implements MigrationInterface {
-  name = 'addRevisionsItemsRelation1632221263106'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    const indexRevisionsOnItemUuid = await queryRunner.manager.query(
-      'SHOW INDEX FROM `revisions` where `key_name` = "index_revisions_on_item_uuid"',
-    )
-    const indexRevisionsOnItemUuidExists = indexRevisionsOnItemUuid && indexRevisionsOnItemUuid.length > 0
-    if (indexRevisionsOnItemUuidExists) {
-      await queryRunner.query('DROP INDEX `index_revisions_on_item_uuid` ON `revisions`')
-    }
-
-    await queryRunner.query('ALTER TABLE `revisions` CHANGE `item_uuid` `item_uuid` varchar(36) NOT NULL')
-    await queryRunner.query('ALTER TABLE `items` CHANGE `user_uuid` `user_uuid` varchar(36) NOT NULL')
-    await queryRunner.query(
-      'ALTER TABLE `revisions` ADD CONSTRAINT `FK_ab3b92e54701fe3010022a31d90` FOREIGN KEY (`item_uuid`) REFERENCES `items`(`uuid`) ON DELETE CASCADE ON UPDATE NO ACTION',
-    )
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `revisions` DROP FOREIGN KEY `FK_ab3b92e54701fe3010022a31d90`')
-    await queryRunner.query('ALTER TABLE `items` CHANGE `user_uuid` `user_uuid` varchar(36) NULL')
-    await queryRunner.query('ALTER TABLE `revisions` CHANGE `item_uuid` `item_uuid` varchar(36) NULL')
-    await queryRunner.query('CREATE INDEX `index_revisions_on_item_uuid` ON `revisions` (`item_uuid`)')
-  }
-}

+ 0 - 13
packages/syncing-server/migrations/mysql-legacy/1637738491169-add_item_content_size.ts

@@ -1,13 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class addItemContentSize1637738491169 implements MigrationInterface {
-  name = 'addItemContentSize1637738491169'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `items` ADD `content_size` INT UNSIGNED NULL')
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `items` DROP COLUMN `content_size`')
-  }
-}

+ 0 - 11
packages/syncing-server/migrations/mysql-legacy/1639134926025-remove_extension_settings.ts

@@ -1,11 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class removeExtensionSettings1639134926025 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('DROP TABLE `extension_settings`')
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 11
packages/syncing-server/migrations/mysql-legacy/1642073387521-remove_sf_extension_items.ts

@@ -1,11 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class removeSfExtensionItems1642073387521 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.manager.query('DELETE FROM items WHERE content_type = "SF|Extension"')
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 11
packages/syncing-server/migrations/mysql-legacy/1647501696205-remove_user_agent.ts

@@ -1,11 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class removeUserAgent1647501696205 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `items` DROP COLUMN `last_user_agent`')
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 13
packages/syncing-server/migrations/mysql-legacy/1654518291191-add_updated_with_session.ts

@@ -1,13 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class addUpdatedWithSession1654518291191 implements MigrationInterface {
-  name = 'addUpdatedWithSession1654518291191'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `items` ADD `updated_with_session` varchar(36) NULL')
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `items` DROP COLUMN `updated_with_session`')
-  }
-}

+ 0 - 16
packages/syncing-server/migrations/mysql-legacy/1689671563304-add-notifications.ts

@@ -1,16 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class AddNotifications1689671563304 implements MigrationInterface {
-  name = 'AddNotifications1689671563304'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query(
-      'CREATE TABLE IF NOT EXISTS `notifications` (`uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `type` varchar(36) NOT NULL, `payload` text NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `index_notifications_on_user_uuid` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('DROP INDEX `index_notifications_on_user_uuid` ON `notifications`')
-    await queryRunner.query('DROP TABLE `notifications`')
-  }
-}

+ 0 - 25
packages/syncing-server/migrations/mysql-legacy/1689671563305-add-shared-vault-and-key-system-associations.ts

@@ -1,25 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class AddSharedVaultAndKeySystemAssociations1689671563305 implements MigrationInterface {
-  name = 'AddSharedVaultAndKeySystemAssociations1689671563305'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query(
-      'CREATE TABLE `shared_vault_associations` (`uuid` varchar(36) NOT NULL, `shared_vault_uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NOT NULL, `last_edited_by` varchar(36) NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `shared_vault_uuid_on_shared_vault_associations` (`shared_vault_uuid`), INDEX `item_uuid_on_shared_vault_associations` (`item_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-    await queryRunner.query(
-      'CREATE TABLE `key_system_associations` (`uuid` varchar(36) NOT NULL, `key_system_uuid` varchar(36) NOT NULL, `item_uuid` varchar(36) NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `key_system_uuid_on_key_system_associations` (`key_system_uuid`), INDEX `item_uuid_on_key_system_associations` (`item_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('DROP INDEX `item_uuid_on_key_system_associations` ON `key_system_associations`')
-    await queryRunner.query('DROP INDEX `key_system_uuid_on_key_system_associations` ON `key_system_associations`')
-    await queryRunner.query('DROP TABLE `key_system_associations`')
-    await queryRunner.query('DROP INDEX `item_uuid_on_shared_vault_associations` ON `shared_vault_associations`')
-    await queryRunner.query(
-      'DROP INDEX `shared_vault_uuid_on_shared_vault_associations` ON `shared_vault_associations`',
-    )
-    await queryRunner.query('DROP TABLE `shared_vault_associations`')
-  }
-}

+ 0 - 29
packages/syncing-server/migrations/mysql-legacy/1689677728282-add-shared-vaults-with-users-and-invites.ts

@@ -1,29 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class AddSharedVaultsWithUsersAndInvites1689677728282 implements MigrationInterface {
-  name = 'AddSharedVaultsWithUsersAndInvites1689677728282'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query(
-      'CREATE TABLE `shared_vaults` (`uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `file_upload_bytes_used` int NOT NULL, `file_upload_bytes_limit` int NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `user_uuid_on_shared_vaults` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-    await queryRunner.query(
-      'CREATE TABLE `shared_vault_users` (`uuid` varchar(36) NOT NULL, `shared_vault_uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `permission` varchar(24) NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `shared_vault_uuid_on_shared_vault_users` (`shared_vault_uuid`), INDEX `user_uuid_on_shared_vault_users` (`user_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-    await queryRunner.query(
-      'CREATE TABLE `shared_vault_invites` (`uuid` varchar(36) NOT NULL, `shared_vault_uuid` varchar(36) NOT NULL, `user_uuid` varchar(36) NOT NULL, `sender_uuid` varchar(36) NOT NULL, `encrypted_message` text NOT NULL, `permission` varchar(24) NOT NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `shared_vault_uuid_on_shared_vault_invites` (`shared_vault_uuid`), INDEX `user_uuid_on_shared_vault_invites` (`user_uuid`), INDEX `sender_uuid_on_shared_vault_invites` (`sender_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('DROP INDEX `sender_uuid_on_shared_vault_invites` ON `shared_vault_invites`')
-    await queryRunner.query('DROP INDEX `user_uuid_on_shared_vault_invites` ON `shared_vault_invites`')
-    await queryRunner.query('DROP INDEX `shared_vault_uuid_on_shared_vault_invites` ON `shared_vault_invites`')
-    await queryRunner.query('DROP TABLE `shared_vault_invites`')
-    await queryRunner.query('DROP INDEX `user_uuid_on_shared_vault_users` ON `shared_vault_users`')
-    await queryRunner.query('DROP INDEX `shared_vault_uuid_on_shared_vault_users` ON `shared_vault_users`')
-    await queryRunner.query('DROP TABLE `shared_vault_users`')
-    await queryRunner.query('DROP INDEX `user_uuid_on_shared_vaults` ON `shared_vaults`')
-    await queryRunner.query('DROP TABLE `shared_vaults`')
-  }
-}

+ 0 - 17
packages/syncing-server/migrations/mysql-legacy/1689745128577-add-messages.ts

@@ -1,17 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class AddMessages1689745128577 implements MigrationInterface {
-  name = 'AddMessages1689745128577'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query(
-      'CREATE TABLE `messages` (`uuid` varchar(36) NOT NULL, `recipient_uuid` varchar(36) NOT NULL, `sender_uuid` varchar(36) NOT NULL, `encrypted_message` text NOT NULL, `replaceability_identifier` varchar(255) NULL, `created_at_timestamp` bigint NOT NULL, `updated_at_timestamp` bigint NOT NULL, INDEX `recipient_uuid_on_messages` (`recipient_uuid`), INDEX `sender_uuid_on_messages` (`sender_uuid`), PRIMARY KEY (`uuid`)) ENGINE=InnoDB',
-    )
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('DROP INDEX `sender_uuid_on_messages` ON `messages`')
-    await queryRunner.query('DROP INDEX `recipient_uuid_on_messages` ON `messages`')
-    await queryRunner.query('DROP TABLE `messages`')
-  }
-}

+ 0 - 27
packages/syncing-server/migrations/mysql-legacy/1689746180559-rename-key-message-identifier.ts

@@ -1,27 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class RenameKeyMessageIdentifier1689746180559 implements MigrationInterface {
-  name = 'RenameKeyMessageIdentifier1689746180559'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('DROP INDEX `key_system_uuid_on_key_system_associations` ON `key_system_associations`')
-    await queryRunner.query(
-      'ALTER TABLE `key_system_associations` CHANGE `key_system_uuid` `key_system_identifier` varchar(36) NOT NULL',
-    )
-    await queryRunner.query(
-      'CREATE INDEX `key_system_identifier_on_key_system_associations` ON `key_system_associations` (`key_system_identifier`)',
-    )
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query(
-      'DROP INDEX `key_system_identifier_on_key_system_associations` ON `key_system_associations`',
-    )
-    await queryRunner.query(
-      'ALTER TABLE `key_system_associations` CHANGE `key_system_identifier` `key_system_uuid` varchar(36) NOT NULL',
-    )
-    await queryRunner.query(
-      'CREATE INDEX `key_system_uuid_on_key_system_associations` ON `key_system_associations` (`key_system_uuid`)',
-    )
-  }
-}

+ 0 - 23
packages/syncing-server/migrations/mysql-legacy/1690900526061-delete_privileges.ts

@@ -1,23 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class DeletePrivileges1690900526061 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    const itemsWithPrivilegesContentTypeQueryResult = await queryRunner.manager.query(
-      'SELECT COUNT(*) as count FROM items i WHERE i.content_type = "SN|Privileges"',
-    )
-    const itemsWithPrivilegesContentTypeCount = +itemsWithPrivilegesContentTypeQueryResult[0].count
-
-    const batchSize = 1_000
-    const batchCount = Math.ceil(itemsWithPrivilegesContentTypeCount / batchSize)
-
-    for (let batchIndex = 0; batchIndex < batchCount; batchIndex++) {
-      await queryRunner.startTransaction()
-      await queryRunner.manager.query(`DELETE FROM items WHERE content_type = "SN|Privileges" LIMIT ${batchSize}`)
-      await queryRunner.commitTransaction()
-    }
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 11
packages/syncing-server/migrations/mysql-legacy/1690975361562-update_unknown_content.ts

@@ -1,11 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class UpdateUnknownContent1690975361562 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.manager.query('UPDATE items SET content_type = "Note" WHERE content_type = "Unknown"')
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 22
packages/syncing-server/migrations/mysql-legacy/1692176803410-remove_revisions_foreign_key.ts

@@ -1,22 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class RemoveRevisionsForeignKey1692176803410 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    const revisionsTableExistsQueryResult = await queryRunner.manager.query(
-      'SELECT COUNT(*) as count FROM information_schema.tables WHERE table_schema = DATABASE() AND table_name = "revisions"',
-    )
-    const revisionsTableExists = revisionsTableExistsQueryResult[0].count === 1
-    if (revisionsTableExists) {
-      try {
-        await queryRunner.query('ALTER TABLE `revisions` DROP FOREIGN KEY `FK_ab3b92e54701fe3010022a31d90`')
-      } catch (error) {
-        // eslint-disable-next-line no-console
-        console.log('Error dropping foreign key: ', (error as Error).message)
-      }
-    }
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 21
packages/syncing-server/migrations/mysql-legacy/1692264556858-remove_associations.ts

@@ -1,21 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class RemoveAssociations1692264556858 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query(
-      'DROP INDEX `key_system_identifier_on_key_system_associations` ON `key_system_associations`',
-    )
-    await queryRunner.query('DROP INDEX `item_uuid_on_key_system_associations` ON `key_system_associations`')
-    await queryRunner.query('DROP TABLE `key_system_associations`')
-
-    await queryRunner.query('DROP INDEX `item_uuid_on_shared_vault_associations` ON `shared_vault_associations`')
-    await queryRunner.query(
-      'DROP INDEX `shared_vault_uuid_on_shared_vault_associations` ON `shared_vault_associations`',
-    )
-    await queryRunner.query('DROP TABLE `shared_vault_associations`')
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 0 - 13
packages/syncing-server/migrations/mysql-legacy/1692619430384-remove-shared-vault-limit.ts

@@ -1,13 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class RemoveSharedVaultLimit1692619430384 implements MigrationInterface {
-  name = 'RemoveSharedVaultLimit1692619430384'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `shared_vaults` DROP COLUMN `file_upload_bytes_limit`')
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `shared_vaults` ADD `file_upload_bytes_limit` int NOT NULL')
-  }
-}

+ 0 - 13
packages/syncing-server/migrations/mysql-legacy/1695284084365-add-designated-survivor.ts

@@ -1,13 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class AddDesignatedSurvivor1695284084365 implements MigrationInterface {
-  name = 'AddDesignatedSurvivor1695284084365'
-
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `shared_vault_users` ADD `is_designated_survivor` tinyint NOT NULL DEFAULT 0')
-  }
-
-  public async down(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `shared_vault_users` DROP COLUMN `is_designated_survivor`')
-  }
-}

+ 0 - 11
packages/syncing-server/migrations/mysql-legacy/1695643525793-remove_notifications.ts

@@ -1,11 +0,0 @@
-import { MigrationInterface, QueryRunner } from 'typeorm'
-
-export class RemoveNotifications1695643525793 implements MigrationInterface {
-  public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('DELETE FROM `notifications`')
-  }
-
-  public async down(): Promise<void> {
-    return
-  }
-}

+ 6 - 6
packages/syncing-server/migrations/mysql/1693219736168-add-shared-vault-information.ts

@@ -4,16 +4,16 @@ export class AddSharedVaultInformation1693219736168 implements MigrationInterfac
   name = 'AddSharedVaultInformation1693219736168'
 
   public async up(queryRunner: QueryRunner): Promise<void> {
-    await queryRunner.query('ALTER TABLE `items` ADD `last_edited_by` varchar(36) NULL')
-    await queryRunner.query('ALTER TABLE `items` ADD `shared_vault_uuid` varchar(36) NULL')
-    await queryRunner.query('ALTER TABLE `items` ADD `key_system_identifier` varchar(36) NULL')
+    await queryRunner.query('ALTER TABLE `items` ADD `last_edited_by` varchar(36) NULL, ALGORITHM = INSTANT')
+    await queryRunner.query('ALTER TABLE `items` ADD `shared_vault_uuid` varchar(36) NULL, ALGORITHM = INSTANT')
+    await queryRunner.query('ALTER TABLE `items` ADD `key_system_identifier` varchar(36) NULL, ALGORITHM = INSTANT')
     await queryRunner.query('CREATE INDEX `index_items_on_shared_vault_uuid` ON `items` (`shared_vault_uuid`)')
   }
 
   public async down(queryRunner: QueryRunner): Promise<void> {
     await queryRunner.query('DROP INDEX `index_items_on_shared_vault_uuid` ON `items`')
-    await queryRunner.query('ALTER TABLE `items` DROP COLUMN `key_system_identifier`')
-    await queryRunner.query('ALTER TABLE `items` DROP COLUMN `shared_vault_uuid`')
-    await queryRunner.query('ALTER TABLE `items` DROP COLUMN `last_edited_by`')
+    await queryRunner.query('ALTER TABLE `items` DROP COLUMN `key_system_identifier`, ALGORITHM = INSTANT')
+    await queryRunner.query('ALTER TABLE `items` DROP COLUMN `shared_vault_uuid`, ALGORITHM = INSTANT')
+    await queryRunner.query('ALTER TABLE `items` DROP COLUMN `last_edited_by`, ALGORITHM = INSTANT')
   }
 }

+ 5 - 20
packages/syncing-server/src/Bootstrap/Container.ts

@@ -6,7 +6,6 @@ import TYPES from './Types'
 import { AppDataSource } from './DataSource'
 import { SNSClient, SNSClientConfig } from '@aws-sdk/client-sns'
 import { ItemRepositoryInterface } from '../Domain/Item/ItemRepositoryInterface'
-import { SQLLegacyItemRepository } from '../Infra/TypeORM/SQLLegacyItemRepository'
 import { Repository } from 'typeorm'
 import { Item } from '../Domain/Item/Item'
 import {
@@ -64,8 +63,6 @@ import {
 } from '@standardnotes/domain-core'
 import { BaseItemsController } from '../Infra/InversifyExpressUtils/Base/BaseItemsController'
 import { Transform } from 'stream'
-import { SQLLegacyItem } from '../Infra/TypeORM/SQLLegacyItem'
-import { SQLLegacyItemPersistenceMapper } from '../Mapping/Persistence/SQLLegacyItemPersistenceMapper'
 import { ItemHttpRepresentation } from '../Mapping/Http/ItemHttpRepresentation'
 import { ItemHttpMapper } from '../Mapping/Http/ItemHttpMapper'
 import { SavedItemHttpRepresentation } from '../Mapping/Http/SavedItemHttpRepresentation'
@@ -303,9 +300,6 @@ export class ContainerConfigLoader {
       )
 
     // Mapping
-    container
-      .bind<MapperInterface<Item, SQLLegacyItem>>(TYPES.Sync_SQLLegacyItemPersistenceMapper)
-      .toConstantValue(new SQLLegacyItemPersistenceMapper())
     container
       .bind<MapperInterface<Item, SQLItem>>(TYPES.Sync_SQLItemPersistenceMapper)
       .toConstantValue(new SQLItemPersistenceMapper())
@@ -363,9 +357,6 @@ export class ContainerConfigLoader {
       .toConstantValue(new NotificationHttpMapper())
 
     // ORM
-    container
-      .bind<Repository<SQLLegacyItem>>(TYPES.Sync_ORMLegacyItemRepository)
-      .toDynamicValue(() => appDataSource.getRepository(SQLLegacyItem))
     container
       .bind<Repository<SQLItem>>(TYPES.Sync_ORMItemRepository)
       .toConstantValue(appDataSource.getRepository(SQLItem))
@@ -389,17 +380,11 @@ export class ContainerConfigLoader {
     container
       .bind<ItemRepositoryInterface>(TYPES.Sync_SQLItemRepository)
       .toConstantValue(
-        isConfiguredForHomeServerOrSelfHosting
-          ? new SQLItemRepository(
-              container.get<Repository<SQLItem>>(TYPES.Sync_ORMItemRepository),
-              container.get<MapperInterface<Item, SQLItem>>(TYPES.Sync_SQLItemPersistenceMapper),
-              container.get<Logger>(TYPES.Sync_Logger),
-            )
-          : new SQLLegacyItemRepository(
-              container.get<Repository<SQLLegacyItem>>(TYPES.Sync_ORMLegacyItemRepository),
-              container.get<MapperInterface<Item, SQLLegacyItem>>(TYPES.Sync_SQLLegacyItemPersistenceMapper),
-              container.get<Logger>(TYPES.Sync_Logger),
-            ),
+        new SQLItemRepository(
+          container.get<Repository<SQLItem>>(TYPES.Sync_ORMItemRepository),
+          container.get<MapperInterface<Item, SQLItem>>(TYPES.Sync_SQLItemPersistenceMapper),
+          container.get<Logger>(TYPES.Sync_Logger),
+        ),
       )
     container
       .bind<SharedVaultRepositoryInterface>(TYPES.Sync_SharedVaultRepository)

+ 2 - 10
packages/syncing-server/src/Bootstrap/DataSource.ts

@@ -2,7 +2,6 @@ import { DataSource, EntityTarget, LoggerOptions, ObjectLiteral, Repository } fr
 import { MysqlConnectionOptions } from 'typeorm/driver/mysql/MysqlConnectionOptions'
 import { Env } from './Env'
 import { SqliteConnectionOptions } from 'typeorm/driver/sqlite/SqliteConnectionOptions'
-import { SQLLegacyItem } from '../Infra/TypeORM/SQLLegacyItem'
 import { TypeORMNotification } from '../Infra/TypeORM/TypeORMNotification'
 import { TypeORMSharedVault } from '../Infra/TypeORM/TypeORMSharedVault'
 import { TypeORMSharedVaultUser } from '../Infra/TypeORM/TypeORMSharedVaultUser'
@@ -36,24 +35,17 @@ export class AppDataSource {
     this.configuration.env.load()
 
     const isConfiguredForMySQL = this.configuration.env.get('DB_TYPE') === 'mysql'
-    const isConfiguredForHomeServerOrSelfHosting =
-      this.configuration.env.get('MODE', true) === 'home-server' ||
-      this.configuration.env.get('MODE', true) === 'self-hosted'
 
     const maxQueryExecutionTime = this.configuration.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
       ? +this.configuration.env.get('DB_MAX_QUERY_EXECUTION_TIME', true)
       : 45_000
 
-    const migrationsSourceDirectoryName = isConfiguredForMySQL
-      ? isConfiguredForHomeServerOrSelfHosting
-        ? 'mysql'
-        : 'mysql-legacy'
-      : 'sqlite'
+    const migrationsSourceDirectoryName = isConfiguredForMySQL ? 'mysql' : 'sqlite'
 
     const commonDataSourceOptions = {
       maxQueryExecutionTime,
       entities: [
-        isConfiguredForHomeServerOrSelfHosting ? SQLItem : SQLLegacyItem,
+        SQLItem,
         TypeORMNotification,
         TypeORMSharedVault,
         TypeORMSharedVaultUser,

+ 0 - 2
packages/syncing-server/src/Bootstrap/Types.ts

@@ -15,7 +15,6 @@ const TYPES = {
   Sync_MessageRepository: Symbol.for('Sync_MessageRepository'),
   // ORM
   Sync_ORMItemRepository: Symbol.for('Sync_ORMItemRepository'),
-  Sync_ORMLegacyItemRepository: Symbol.for('Sync_ORMLegacyItemRepository'),
   Sync_ORMSharedVaultRepository: Symbol.for('Sync_ORMSharedVaultRepository'),
   Sync_ORMSharedVaultInviteRepository: Symbol.for('Sync_ORMSharedVaultInviteRepository'),
   Sync_ORMSharedVaultUserRepository: Symbol.for('Sync_ORMSharedVaultUserRepository'),
@@ -128,7 +127,6 @@ const TYPES = {
   Sync_MessagePersistenceMapper: Symbol.for('Sync_MessagePersistenceMapper'),
   Sync_MessageHttpMapper: Symbol.for('Sync_MessageHttpMapper'),
   Sync_NotificationHttpMapper: Symbol.for('Sync_NotificationHttpMapper'),
-  Sync_SQLLegacyItemPersistenceMapper: Symbol.for('Sync_SQLLegacyItemPersistenceMapper'),
   Sync_SQLItemPersistenceMapper: Symbol.for('Sync_SQLItemPersistenceMapper'),
   Sync_ItemHttpMapper: Symbol.for('Sync_ItemHttpMapper'),
   Sync_ItemHashHttpMapper: Symbol.for('Sync_ItemHashHttpMapper'),

+ 116 - 4
packages/syncing-server/src/Infra/TypeORM/SQLItem.ts

@@ -1,9 +1,121 @@
-import { Column, Entity, Index } from 'typeorm'
-
-import { SQLLegacyItem } from './SQLLegacyItem'
+import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'
 
 @Entity({ name: 'items' })
-export class SQLItem extends SQLLegacyItem {
+@Index('index_items_on_user_uuid_and_content_type', ['userUuid', 'contentType'])
+@Index('user_uuid_and_updated_at_timestamp_and_created_at_timestamp', [
+  'userUuid',
+  'updatedAtTimestamp',
+  'createdAtTimestamp',
+])
+@Index('user_uuid_and_deleted', ['userUuid', 'deleted'])
+export class SQLItem {
+  @PrimaryGeneratedColumn('uuid')
+  declare uuid: string
+
+  @Column({
+    type: 'varchar',
+    name: 'duplicate_of',
+    length: 36,
+    nullable: true,
+  })
+  declare duplicateOf: string | null
+
+  @Column({
+    type: 'varchar',
+    name: 'items_key_id',
+    length: 255,
+    nullable: true,
+  })
+  declare itemsKeyId: string | null
+
+  @Column({
+    type: 'text',
+    nullable: true,
+  })
+  declare content: string | null
+
+  @Column({
+    name: 'content_type',
+    type: 'varchar',
+    length: 255,
+    nullable: true,
+  })
+  @Index('index_items_on_content_type')
+  declare contentType: string | null
+
+  @Column({
+    name: 'content_size',
+    type: 'int',
+    nullable: true,
+  })
+  declare contentSize: number | null
+
+  @Column({
+    name: 'enc_item_key',
+    type: 'text',
+    nullable: true,
+  })
+  declare encItemKey: string | null
+
+  @Column({
+    name: 'auth_hash',
+    type: 'varchar',
+    length: 255,
+    nullable: true,
+  })
+  declare authHash: string | null
+
+  @Column({
+    name: 'user_uuid',
+    length: 36,
+  })
+  @Index('index_items_on_user_uuid')
+  declare userUuid: string
+
+  @Column({
+    type: 'tinyint',
+    precision: 1,
+    nullable: true,
+    default: 0,
+  })
+  @Index('index_items_on_deleted')
+  declare deleted: boolean
+
+  @Column({
+    name: 'created_at',
+    type: 'datetime',
+    precision: 6,
+  })
+  declare createdAt: Date
+
+  @Column({
+    name: 'updated_at',
+    type: 'datetime',
+    precision: 6,
+  })
+  declare updatedAt: Date
+
+  @Column({
+    name: 'created_at_timestamp',
+    type: 'bigint',
+  })
+  declare createdAtTimestamp: number
+
+  @Column({
+    name: 'updated_at_timestamp',
+    type: 'bigint',
+  })
+  @Index('updated_at_timestamp')
+  declare updatedAtTimestamp: number
+
+  @Column({
+    name: 'updated_with_session',
+    type: 'varchar',
+    length: 36,
+    nullable: true,
+  })
+  declare updatedWithSession: string | null
+
   @Column({
     type: 'varchar',
     name: 'last_edited_by',

+ 195 - 20
packages/syncing-server/src/Infra/TypeORM/SQLItemRepository.ts

@@ -3,20 +3,20 @@ import { MapperInterface, Uuid } from '@standardnotes/domain-core'
 import { Logger } from 'winston'
 
 import { Item } from '../../Domain/Item/Item'
-import { SQLItem } from './SQLItem'
-import { SQLLegacyItemRepository } from './SQLLegacyItemRepository'
 import { ItemQuery } from '../../Domain/Item/ItemQuery'
+import { ItemRepositoryInterface } from '../../Domain/Item/ItemRepositoryInterface'
+import { ExtendedIntegrityPayload } from '../../Domain/Item/ExtendedIntegrityPayload'
+import { ItemContentSizeDescriptor } from '../../Domain/Item/ItemContentSizeDescriptor'
+import { SQLItem } from './SQLItem'
 
-export class SQLItemRepository extends SQLLegacyItemRepository {
+export class SQLItemRepository implements ItemRepositoryInterface {
   constructor(
-    protected override ormRepository: Repository<SQLItem>,
-    protected override mapper: MapperInterface<Item, SQLItem>,
-    protected override logger: Logger,
-  ) {
-    super(ormRepository, mapper, logger)
-  }
+    protected ormRepository: Repository<SQLItem>,
+    protected mapper: MapperInterface<Item, SQLItem>,
+    protected logger: Logger,
+  ) {}
 
-  override async deleteByUserUuidInSharedVaults(userUuid: Uuid, sharedVaultUuids: Uuid[]): Promise<void> {
+  async deleteByUserUuidInSharedVaults(userUuid: Uuid, sharedVaultUuids: Uuid[]): Promise<void> {
     await this.ormRepository
       .createQueryBuilder('item')
       .delete()
@@ -28,7 +28,7 @@ export class SQLItemRepository extends SQLLegacyItemRepository {
       .execute()
   }
 
-  override async deleteByUserUuidAndNotInSharedVault(userUuid: Uuid): Promise<void> {
+  async deleteByUserUuidAndNotInSharedVault(userUuid: Uuid): Promise<void> {
     await this.ormRepository
       .createQueryBuilder('item')
       .delete()
@@ -38,25 +38,21 @@ export class SQLItemRepository extends SQLLegacyItemRepository {
       .execute()
   }
 
-  override async updateSharedVaultOwner(dto: {
-    sharedVaultUuid: Uuid
-    fromOwnerUuid: Uuid
-    toOwnerUuid: Uuid
-  }): Promise<void> {
+  async updateSharedVaultOwner(dto: { sharedVaultUuid: Uuid; fromOwnerUuid: Uuid; toOwnerUuid: Uuid }): Promise<void> {
     await this.ormRepository
       .createQueryBuilder('item')
       .update()
       .set({
         userUuid: dto.toOwnerUuid.value,
       })
-      .where('shared_vault_uuid = :sharedVaultUuid AND user_uuid = :fromOwnerUuid', {
-        sharedVaultUuid: dto.sharedVaultUuid.value,
+      .where('user_uuid = :fromOwnerUuid AND shared_vault_uuid = :sharedVaultUuid', {
         fromOwnerUuid: dto.fromOwnerUuid.value,
+        sharedVaultUuid: dto.sharedVaultUuid.value,
       })
       .execute()
   }
 
-  override async unassignFromSharedVault(sharedVaultUuid: Uuid): Promise<void> {
+  async unassignFromSharedVault(sharedVaultUuid: Uuid): Promise<void> {
     await this.ormRepository
       .createQueryBuilder('item')
       .update()
@@ -69,7 +65,186 @@ export class SQLItemRepository extends SQLLegacyItemRepository {
       .execute()
   }
 
-  protected override createFindAllQueryBuilder(query: ItemQuery): SelectQueryBuilder<SQLItem> {
+  async removeByUuid(uuid: Uuid): Promise<void> {
+    await this.ormRepository
+      .createQueryBuilder('item')
+      .delete()
+      .from('items')
+      .where('uuid = :uuid', { uuid: uuid.value })
+      .execute()
+  }
+
+  async insert(item: Item): Promise<void> {
+    const projection = this.mapper.toProjection(item)
+
+    await this.ormRepository.insert(projection)
+  }
+
+  async update(item: Item): Promise<void> {
+    const projection = this.mapper.toProjection(item)
+
+    const { uuid, ...updateValues } = projection
+
+    await this.ormRepository.update({ uuid: uuid }, updateValues)
+  }
+
+  async remove(item: Item): Promise<void> {
+    await this.ormRepository.remove(this.mapper.toProjection(item))
+  }
+
+  async updateContentSize(itemUuid: string, contentSize: number): Promise<void> {
+    await this.ormRepository
+      .createQueryBuilder('item')
+      .update()
+      .set({
+        contentSize,
+      })
+      .where('uuid = :itemUuid', {
+        itemUuid,
+      })
+      .execute()
+  }
+
+  async findContentSizeForComputingTransferLimit(query: ItemQuery): Promise<ItemContentSizeDescriptor[]> {
+    const queryBuilder = this.createFindAllQueryBuilder(query)
+    queryBuilder.select('item.uuid', 'uuid')
+    queryBuilder.addSelect('item.content_size', 'contentSize')
+
+    const items = await queryBuilder.getRawMany()
+
+    const itemContentSizeDescriptors: ItemContentSizeDescriptor[] = []
+    for (const item of items) {
+      const ItemContentSizeDescriptorOrError = ItemContentSizeDescriptor.create(item.uuid, item.contentSize)
+      if (ItemContentSizeDescriptorOrError.isFailed()) {
+        this.logger.error(
+          `Failed to create ItemContentSizeDescriptor for item ${
+            item.uuid
+          }: ${ItemContentSizeDescriptorOrError.getError()}`,
+        )
+        continue
+      }
+      itemContentSizeDescriptors.push(ItemContentSizeDescriptorOrError.getValue())
+    }
+
+    return itemContentSizeDescriptors
+  }
+
+  async findByUuid(uuid: Uuid): Promise<Item | null> {
+    const persistence = await this.ormRepository
+      .createQueryBuilder('item')
+      .where('item.uuid = :uuid', {
+        uuid: uuid.value,
+      })
+      .getOne()
+
+    if (persistence === null) {
+      return null
+    }
+
+    try {
+      const item = this.mapper.toDomain(persistence)
+
+      return item
+    } catch (error) {
+      this.logger.error(
+        `Failed to map item ${uuid.value} for user ${persistence.userUuid} by uuid: ${(error as Error).message}`,
+      )
+
+      return null
+    }
+  }
+
+  async findDatesForComputingIntegrityHash(userUuid: string): Promise<Array<{ updated_at_timestamp: number }>> {
+    const queryBuilder = this.ormRepository.createQueryBuilder('item')
+    queryBuilder.select('item.updated_at_timestamp')
+    queryBuilder.where('item.user_uuid = :userUuid', { userUuid: userUuid })
+    queryBuilder.andWhere('item.deleted = :deleted', { deleted: false })
+
+    const items = await queryBuilder.getRawMany()
+
+    return items.sort((itemA, itemB) => itemB.updated_at_timestamp - itemA.updated_at_timestamp)
+  }
+
+  async findItemsForComputingIntegrityPayloads(userUuid: string): Promise<ExtendedIntegrityPayload[]> {
+    const queryBuilder = this.ormRepository.createQueryBuilder('item')
+    queryBuilder.select('item.uuid', 'uuid')
+    queryBuilder.addSelect('item.updated_at_timestamp', 'updated_at_timestamp')
+    queryBuilder.addSelect('item.content_type', 'content_type')
+    queryBuilder.where('item.user_uuid = :userUuid', { userUuid: userUuid })
+    queryBuilder.andWhere('item.deleted = :deleted', { deleted: false })
+
+    const items = await queryBuilder.getRawMany()
+
+    return items.sort((itemA, itemB) => itemB.updated_at_timestamp - itemA.updated_at_timestamp)
+  }
+
+  async findByUuidAndUserUuid(uuid: string, userUuid: string): Promise<Item | null> {
+    const persistence = await this.ormRepository
+      .createQueryBuilder('item')
+      .where('item.uuid = :uuid AND item.user_uuid = :userUuid', {
+        uuid,
+        userUuid,
+      })
+      .getOne()
+
+    if (persistence === null) {
+      return null
+    }
+
+    try {
+      const item = this.mapper.toDomain(persistence)
+
+      return item
+    } catch (error) {
+      this.logger.error(
+        `Failed to map item ${uuid} for user ${persistence.userUuid} by uuid and userUuid: ${(error as Error).message}`,
+      )
+
+      return null
+    }
+  }
+
+  async findAll(query: ItemQuery): Promise<Item[]> {
+    const persistence = await this.createFindAllQueryBuilder(query).getMany()
+
+    const domainItems: Item[] = []
+    for (const persistencItem of persistence) {
+      try {
+        domainItems.push(this.mapper.toDomain(persistencItem))
+      } catch (error) {
+        this.logger.error(
+          `Failed to map item ${persistencItem.uuid} for user ${persistencItem.userUuid} to domain: ${
+            (error as Error).message
+          }`,
+        )
+      }
+    }
+
+    return domainItems
+  }
+
+  async countAll(query: ItemQuery): Promise<number> {
+    return this.createFindAllQueryBuilder(query).getCount()
+  }
+
+  async markItemsAsDeleted(itemUuids: Array<string>, updatedAtTimestamp: number): Promise<void> {
+    await this.ormRepository
+      .createQueryBuilder('item')
+      .update()
+      .set({
+        deleted: true,
+        content: null,
+        encItemKey: null,
+        authHash: null,
+        updatedAtTimestamp,
+      })
+      .where('uuid IN (:...uuids)', {
+        uuids: itemUuids,
+      })
+      .execute()
+  }
+
+  protected createFindAllQueryBuilder(query: ItemQuery): SelectQueryBuilder<SQLItem> {
     const queryBuilder = this.ormRepository.createQueryBuilder('item')
 
     if (query.sortBy !== undefined && query.sortOrder !== undefined) {

+ 0 - 118
packages/syncing-server/src/Infra/TypeORM/SQLLegacyItem.ts

@@ -1,118 +0,0 @@
-import { Column, Entity, Index, PrimaryGeneratedColumn } from 'typeorm'
-
-@Entity({ name: 'items' })
-@Index('index_items_on_user_uuid_and_content_type', ['userUuid', 'contentType'])
-@Index('user_uuid_and_updated_at_timestamp_and_created_at_timestamp', [
-  'userUuid',
-  'updatedAtTimestamp',
-  'createdAtTimestamp',
-])
-@Index('user_uuid_and_deleted', ['userUuid', 'deleted'])
-export class SQLLegacyItem {
-  @PrimaryGeneratedColumn('uuid')
-  declare uuid: string
-
-  @Column({
-    type: 'varchar',
-    name: 'duplicate_of',
-    length: 36,
-    nullable: true,
-  })
-  declare duplicateOf: string | null
-
-  @Column({
-    type: 'varchar',
-    name: 'items_key_id',
-    length: 255,
-    nullable: true,
-  })
-  declare itemsKeyId: string | null
-
-  @Column({
-    type: 'text',
-    nullable: true,
-  })
-  declare content: string | null
-
-  @Column({
-    name: 'content_type',
-    type: 'varchar',
-    length: 255,
-    nullable: true,
-  })
-  @Index('index_items_on_content_type')
-  declare contentType: string | null
-
-  @Column({
-    name: 'content_size',
-    type: 'int',
-    nullable: true,
-  })
-  declare contentSize: number | null
-
-  @Column({
-    name: 'enc_item_key',
-    type: 'text',
-    nullable: true,
-  })
-  declare encItemKey: string | null
-
-  @Column({
-    name: 'auth_hash',
-    type: 'varchar',
-    length: 255,
-    nullable: true,
-  })
-  declare authHash: string | null
-
-  @Column({
-    name: 'user_uuid',
-    length: 36,
-  })
-  @Index('index_items_on_user_uuid')
-  declare userUuid: string
-
-  @Column({
-    type: 'tinyint',
-    precision: 1,
-    nullable: true,
-    default: 0,
-  })
-  @Index('index_items_on_deleted')
-  declare deleted: boolean
-
-  @Column({
-    name: 'created_at',
-    type: 'datetime',
-    precision: 6,
-  })
-  declare createdAt: Date
-
-  @Column({
-    name: 'updated_at',
-    type: 'datetime',
-    precision: 6,
-  })
-  declare updatedAt: Date
-
-  @Column({
-    name: 'created_at_timestamp',
-    type: 'bigint',
-  })
-  declare createdAtTimestamp: number
-
-  @Column({
-    name: 'updated_at_timestamp',
-    type: 'bigint',
-  })
-  @Index('updated_at_timestamp')
-  declare updatedAtTimestamp: number
-
-  @Column({
-    name: 'updated_with_session',
-    type: 'varchar',
-    length: 36,
-    nullable: true,
-  })
-  declare updatedWithSession: string | null
-}

+ 0 - 263
packages/syncing-server/src/Infra/TypeORM/SQLLegacyItemRepository.ts

@@ -1,263 +0,0 @@
-import { Repository, SelectQueryBuilder } from 'typeorm'
-import { MapperInterface, Uuid } from '@standardnotes/domain-core'
-import { Logger } from 'winston'
-
-import { Item } from '../../Domain/Item/Item'
-import { ItemQuery } from '../../Domain/Item/ItemQuery'
-import { ItemRepositoryInterface } from '../../Domain/Item/ItemRepositoryInterface'
-import { ExtendedIntegrityPayload } from '../../Domain/Item/ExtendedIntegrityPayload'
-import { SQLLegacyItem } from './SQLLegacyItem'
-import { ItemContentSizeDescriptor } from '../../Domain/Item/ItemContentSizeDescriptor'
-
-export class SQLLegacyItemRepository implements ItemRepositoryInterface {
-  constructor(
-    protected ormRepository: Repository<SQLLegacyItem>,
-    protected mapper: MapperInterface<Item, SQLLegacyItem>,
-    protected logger: Logger,
-  ) {}
-
-  async deleteByUserUuidInSharedVaults(_userUuid: Uuid, _sharedVaultUuids: Uuid[]): Promise<void> {
-    this.logger.error('Method deleteByUserUuidInSharedVaults not supported.')
-  }
-
-  async updateSharedVaultOwner(_dto: { sharedVaultUuid: Uuid; fromOwnerUuid: Uuid; toOwnerUuid: Uuid }): Promise<void> {
-    this.logger.error('Method updateSharedVaultOwner not supported.')
-  }
-
-  async unassignFromSharedVault(_sharedVaultUuid: Uuid): Promise<void> {
-    this.logger.error('Method unassignFromSharedVault not supported.')
-  }
-
-  async removeByUuid(uuid: Uuid): Promise<void> {
-    await this.ormRepository
-      .createQueryBuilder('item')
-      .delete()
-      .from('items')
-      .where('uuid = :uuid', { uuid: uuid.value })
-      .execute()
-  }
-
-  async insert(item: Item): Promise<void> {
-    const projection = this.mapper.toProjection(item)
-
-    await this.ormRepository.insert(projection)
-  }
-
-  async update(item: Item): Promise<void> {
-    const projection = this.mapper.toProjection(item)
-
-    const { uuid, ...updateValues } = projection
-
-    await this.ormRepository.update({ uuid: uuid }, updateValues)
-  }
-
-  async remove(item: Item): Promise<void> {
-    await this.ormRepository.remove(this.mapper.toProjection(item))
-  }
-
-  async updateContentSize(itemUuid: string, contentSize: number): Promise<void> {
-    await this.ormRepository
-      .createQueryBuilder('item')
-      .update()
-      .set({
-        contentSize,
-      })
-      .where('uuid = :itemUuid', {
-        itemUuid,
-      })
-      .execute()
-  }
-
-  async findContentSizeForComputingTransferLimit(query: ItemQuery): Promise<ItemContentSizeDescriptor[]> {
-    const queryBuilder = this.createFindAllQueryBuilder(query)
-    queryBuilder.select('item.uuid', 'uuid')
-    queryBuilder.addSelect('item.content_size', 'contentSize')
-
-    const items = await queryBuilder.getRawMany()
-
-    const itemContentSizeDescriptors: ItemContentSizeDescriptor[] = []
-    for (const item of items) {
-      const ItemContentSizeDescriptorOrError = ItemContentSizeDescriptor.create(item.uuid, item.contentSize)
-      if (ItemContentSizeDescriptorOrError.isFailed()) {
-        this.logger.error(
-          `Failed to create ItemContentSizeDescriptor for item ${
-            item.uuid
-          }: ${ItemContentSizeDescriptorOrError.getError()}`,
-        )
-        continue
-      }
-      itemContentSizeDescriptors.push(ItemContentSizeDescriptorOrError.getValue())
-    }
-
-    return itemContentSizeDescriptors
-  }
-
-  async deleteByUserUuidAndNotInSharedVault(userUuid: Uuid): Promise<void> {
-    await this.ormRepository
-      .createQueryBuilder('item')
-      .delete()
-      .from('items')
-      .where('user_uuid = :userUuid', { userUuid: userUuid.value })
-      .execute()
-  }
-
-  async findByUuid(uuid: Uuid): Promise<Item | null> {
-    const persistence = await this.ormRepository
-      .createQueryBuilder('item')
-      .where('item.uuid = :uuid', {
-        uuid: uuid.value,
-      })
-      .getOne()
-
-    if (persistence === null) {
-      return null
-    }
-
-    try {
-      const item = this.mapper.toDomain(persistence)
-
-      return item
-    } catch (error) {
-      this.logger.error(
-        `Failed to map item ${uuid.value} for user ${persistence.userUuid} by uuid: ${(error as Error).message}`,
-      )
-
-      return null
-    }
-  }
-
-  async findDatesForComputingIntegrityHash(userUuid: string): Promise<Array<{ updated_at_timestamp: number }>> {
-    const queryBuilder = this.ormRepository.createQueryBuilder('item')
-    queryBuilder.select('item.updated_at_timestamp')
-    queryBuilder.where('item.user_uuid = :userUuid', { userUuid: userUuid })
-    queryBuilder.andWhere('item.deleted = :deleted', { deleted: false })
-
-    const items = await queryBuilder.getRawMany()
-
-    return items.sort((itemA, itemB) => itemB.updated_at_timestamp - itemA.updated_at_timestamp)
-  }
-
-  async findItemsForComputingIntegrityPayloads(userUuid: string): Promise<ExtendedIntegrityPayload[]> {
-    const queryBuilder = this.ormRepository.createQueryBuilder('item')
-    queryBuilder.select('item.uuid', 'uuid')
-    queryBuilder.addSelect('item.updated_at_timestamp', 'updated_at_timestamp')
-    queryBuilder.addSelect('item.content_type', 'content_type')
-    queryBuilder.where('item.user_uuid = :userUuid', { userUuid: userUuid })
-    queryBuilder.andWhere('item.deleted = :deleted', { deleted: false })
-
-    const items = await queryBuilder.getRawMany()
-
-    return items.sort((itemA, itemB) => itemB.updated_at_timestamp - itemA.updated_at_timestamp)
-  }
-
-  async findByUuidAndUserUuid(uuid: string, userUuid: string): Promise<Item | null> {
-    const persistence = await this.ormRepository
-      .createQueryBuilder('item')
-      .where('item.uuid = :uuid AND item.user_uuid = :userUuid', {
-        uuid,
-        userUuid,
-      })
-      .getOne()
-
-    if (persistence === null) {
-      return null
-    }
-
-    try {
-      const item = this.mapper.toDomain(persistence)
-
-      return item
-    } catch (error) {
-      this.logger.error(
-        `Failed to map item ${uuid} for user ${persistence.userUuid} by uuid and userUuid: ${(error as Error).message}`,
-      )
-
-      return null
-    }
-  }
-
-  async findAll(query: ItemQuery): Promise<Item[]> {
-    const persistence = await this.createFindAllQueryBuilder(query).getMany()
-
-    const domainItems: Item[] = []
-    for (const persistencItem of persistence) {
-      try {
-        domainItems.push(this.mapper.toDomain(persistencItem))
-      } catch (error) {
-        this.logger.error(
-          `Failed to map item ${persistencItem.uuid} for user ${persistencItem.userUuid} to domain: ${
-            (error as Error).message
-          }`,
-        )
-      }
-    }
-
-    return domainItems
-  }
-
-  async countAll(query: ItemQuery): Promise<number> {
-    return this.createFindAllQueryBuilder(query).getCount()
-  }
-
-  async markItemsAsDeleted(itemUuids: Array<string>, updatedAtTimestamp: number): Promise<void> {
-    await this.ormRepository
-      .createQueryBuilder('item')
-      .update()
-      .set({
-        deleted: true,
-        content: null,
-        encItemKey: null,
-        authHash: null,
-        updatedAtTimestamp,
-      })
-      .where('uuid IN (:...uuids)', {
-        uuids: itemUuids,
-      })
-      .execute()
-  }
-
-  protected createFindAllQueryBuilder(query: ItemQuery): SelectQueryBuilder<SQLLegacyItem> {
-    const queryBuilder = this.ormRepository.createQueryBuilder('item')
-
-    if (query.sortBy !== undefined && query.sortOrder !== undefined) {
-      queryBuilder.orderBy(`item.${query.sortBy}`, query.sortOrder)
-    }
-
-    if (query.userUuid !== undefined) {
-      queryBuilder.where('item.user_uuid = :userUuid', { userUuid: query.userUuid })
-    }
-
-    if (query.uuids && query.uuids.length > 0) {
-      queryBuilder.andWhere('item.uuid IN (:...uuids)', { uuids: query.uuids })
-    }
-    if (query.deleted !== undefined) {
-      queryBuilder.andWhere('item.deleted = :deleted', { deleted: query.deleted })
-    }
-    if (query.contentType) {
-      if (Array.isArray(query.contentType)) {
-        queryBuilder.andWhere('item.content_type IN (:...contentTypes)', { contentTypes: query.contentType })
-      } else {
-        queryBuilder.andWhere('item.content_type = :contentType', { contentType: query.contentType })
-      }
-    }
-    if (query.lastSyncTime && query.syncTimeComparison) {
-      queryBuilder.andWhere(`item.updated_at_timestamp ${query.syncTimeComparison} :lastSyncTime`, {
-        lastSyncTime: query.lastSyncTime,
-      })
-    }
-    if (query.createdBetween !== undefined) {
-      queryBuilder.andWhere('item.created_at >= :createdAfter AND item.created_at <= :createdBefore', {
-        createdAfter: query.createdBetween[0].toISOString(),
-        createdBefore: query.createdBetween[1].toISOString(),
-      })
-    }
-    if (query.offset !== undefined) {
-      queryBuilder.skip(query.offset)
-    }
-    if (query.limit !== undefined) {
-      queryBuilder.take(query.limit)
-    }
-
-    return queryBuilder
-  }
-}

+ 0 - 102
packages/syncing-server/src/Mapping/Persistence/SQLLegacyItemPersistenceMapper.ts

@@ -1,102 +0,0 @@
-import { Timestamps, MapperInterface, UniqueEntityId, Uuid, ContentType, Dates } from '@standardnotes/domain-core'
-
-import { Item } from '../../Domain/Item/Item'
-
-import { SQLLegacyItem } from '../../Infra/TypeORM/SQLLegacyItem'
-
-export class SQLLegacyItemPersistenceMapper implements MapperInterface<Item, SQLLegacyItem> {
-  toDomain(projection: SQLLegacyItem): Item {
-    const uuidOrError = Uuid.create(projection.uuid)
-    if (uuidOrError.isFailed()) {
-      throw new Error(`Failed to create item from projection: ${uuidOrError.getError()}`)
-    }
-    const uuid = uuidOrError.getValue()
-
-    let duplicateOf = null
-    if (projection.duplicateOf) {
-      const duplicateOfOrError = Uuid.create(projection.duplicateOf)
-      if (duplicateOfOrError.isFailed()) {
-        throw new Error(`Failed to create item from projection: ${duplicateOfOrError.getError()}`)
-      }
-      duplicateOf = duplicateOfOrError.getValue()
-    }
-
-    const contentTypeOrError = ContentType.create(projection.contentType)
-    if (contentTypeOrError.isFailed()) {
-      throw new Error(`Failed to create item from projection: ${contentTypeOrError.getError()}`)
-    }
-    const contentType = contentTypeOrError.getValue()
-
-    const userUuidOrError = Uuid.create(projection.userUuid)
-    if (userUuidOrError.isFailed()) {
-      throw new Error(`Failed to create item from projection: ${userUuidOrError.getError()}`)
-    }
-    const userUuid = userUuidOrError.getValue()
-
-    const datesOrError = Dates.create(projection.createdAt, projection.updatedAt)
-    if (datesOrError.isFailed()) {
-      throw new Error(`Failed to create item from projection: ${datesOrError.getError()}`)
-    }
-    const dates = datesOrError.getValue()
-
-    const timestampsOrError = Timestamps.create(projection.createdAtTimestamp, projection.updatedAtTimestamp)
-    if (timestampsOrError.isFailed()) {
-      throw new Error(`Failed to create item from projection: ${timestampsOrError.getError()}`)
-    }
-    const timestamps = timestampsOrError.getValue()
-
-    let updatedWithSession = null
-    if (projection.updatedWithSession) {
-      const updatedWithSessionOrError = Uuid.create(projection.updatedWithSession)
-      if (updatedWithSessionOrError.isFailed()) {
-        throw new Error(`Failed to create item from projection: ${updatedWithSessionOrError.getError()}`)
-      }
-      updatedWithSession = updatedWithSessionOrError.getValue()
-    }
-
-    const itemOrError = Item.create(
-      {
-        duplicateOf,
-        itemsKeyId: projection.itemsKeyId,
-        content: projection.content,
-        contentType,
-        contentSize: projection.contentSize ?? undefined,
-        encItemKey: projection.encItemKey,
-        authHash: projection.authHash,
-        userUuid,
-        deleted: !!projection.deleted,
-        dates,
-        timestamps,
-        updatedWithSession,
-      },
-      new UniqueEntityId(uuid.value),
-    )
-    if (itemOrError.isFailed()) {
-      throw new Error(`Failed to create item from projection: ${itemOrError.getError()}`)
-    }
-
-    return itemOrError.getValue()
-  }
-
-  toProjection(domain: Item): SQLLegacyItem {
-    const typeorm = new SQLLegacyItem()
-
-    typeorm.uuid = domain.id.toString()
-    typeorm.duplicateOf = domain.props.duplicateOf ? domain.props.duplicateOf.value : null
-    typeorm.itemsKeyId = domain.props.itemsKeyId
-    typeorm.content = domain.props.content
-    typeorm.contentType = domain.props.contentType.value
-    typeorm.contentSize = domain.props.contentSize ?? null
-    typeorm.encItemKey = domain.props.encItemKey
-    typeorm.authHash = domain.props.authHash
-    typeorm.userUuid = domain.props.userUuid.value
-    typeorm.deleted = !!domain.props.deleted
-    typeorm.createdAt = domain.props.dates.createdAt
-    typeorm.updatedAt = domain.props.dates.updatedAt
-    typeorm.createdAtTimestamp = domain.props.timestamps.createdAt
-    typeorm.updatedAtTimestamp = domain.props.timestamps.updatedAt
-    typeorm.updatedWithSession = domain.props.updatedWithSession ? domain.props.updatedWithSession.value : null
-
-    return typeorm
-  }
-}