From 934391105449150446f78bb0f78ed97543163c3d Mon Sep 17 00:00:00 2001 From: Agustina Aldasoro Date: Tue, 1 Feb 2022 11:01:42 -0300 Subject: [PATCH] Modify get entities query to avoid unnecessary join (#872) --- .gitignore | 1 + content/src/controller/Controller.ts | 11 +- .../database-queries/deployments-queries.ts | 143 ++++++++------ .../extensions/DeploymentsRepository.ts | 151 +-------------- content/src/service/ServiceImpl.ts | 4 +- .../service/deployments/DeploymentManager.ts | 66 +------ .../deployments/deployment-filters.spec.ts | 57 +----- .../integration/service/order-check.spec.ts | 13 +- .../service/same-timestamp-check.spec.ts | 6 +- .../unit/logic/deployments-queries.spec.ts | 10 - .../repository/DeploymentsRepository.spec.ts | 177 +----------------- 11 files changed, 111 insertions(+), 528 deletions(-) diff --git a/.gitignore b/.gitignore index 0cbf096d2..1a45c06ac 100644 --- a/.gitignore +++ b/.gitignore @@ -12,3 +12,4 @@ tmpbin linked-peer-package **/tsconfig.tsbuildinfo storage_*/** +serverStorage.json diff --git a/content/src/controller/Controller.ts b/content/src/controller/Controller.ts index f4c1b0e4e..99780ef75 100644 --- a/content/src/controller/Controller.ts +++ b/content/src/controller/Controller.ts @@ -268,7 +268,7 @@ export class Controller { // don't replace this until the denylist is implemented outside of the service const { deployments } = await this.components.deployer.getDeployments({ fields: [DeploymentField.AUDIT_INFO], - filters: { entityIds: [entityId], entityTypes: [type] } + filters: { entityIds: [entityId], entityTypes: [type], includeOverwrittenInfo: true } }) if (deployments.length > 0) { @@ -355,7 +355,8 @@ export class Controller { entityTypes: entityTypes as EntityType[] | undefined, from: fromFilter, to: toFilter, - includeAuthChain + includeAuthChain, + includeOverwrittenInfo: includeAuthChain } const { @@ -418,7 +419,7 @@ export class Controller { async getDeployments(req: express.Request, res: express.Response) { // Method: GET // Path: /deployments - // Query String: ?from={timestamp}&toLocalTimestamp={timestamp}&entityType={entityType}&entityId={entityId}&onlyCurrentlyPointed={boolean}&deployedBy={ethAddress} + // Query String: ?from={timestamp}&toLocalTimestamp={timestamp}&entityType={entityType}&entityId={entityId}&onlyCurrentlyPointed={boolean} const stringEntityTypes = this.asArray(req.query.entityType as string | string[]) const entityTypes: (EntityType | undefined)[] | undefined = stringEntityTypes @@ -426,9 +427,6 @@ export class Controller { : undefined const entityIds: EntityId[] | undefined = this.asArray(req.query.entityId) const onlyCurrentlyPointed: boolean | undefined = this.asBoolean(req.query.onlyCurrentlyPointed) - const deployedBy: EthAddress[] | undefined = this.asArray(req.query.deployedBy)?.map((p) => - p.toLowerCase() - ) const pointers: Pointer[] | undefined = this.asArray(req.query.pointer)?.map((p) => p.toLowerCase()) const offset: number | undefined = this.asInt(req.query.offset) const limit: number | undefined = this.asInt(req.query.limit) @@ -508,7 +506,6 @@ export class Controller { pointers, entityTypes: entityTypes as EntityType[], entityIds, - deployedBy, onlyCurrentlyPointed, from: fromFilter, to: toFilter diff --git a/content/src/logic/database-queries/deployments-queries.ts b/content/src/logic/database-queries/deployments-queries.ts index b999c9b99..a434cc235 100644 --- a/content/src/logic/database-queries/deployments-queries.ts +++ b/content/src/logic/database-queries/deployments-queries.ts @@ -81,28 +81,92 @@ export function getHistoricalDeploymentsQuery( const timestampField: string = sorting.field const order: string = sorting.order - const query = SQL` - SELECT - dep1.id, - dep1.entity_type, - dep1.entity_id, - dep1.entity_pointers, - date_part('epoch', dep1.entity_timestamp) * 1000 AS entity_timestamp, - dep1.entity_metadata, - dep1.deployer_address, - dep1.version, - dep1.auth_chain, - date_part('epoch', dep1.local_timestamp) * 1000 AS local_timestamp, - dep2.entity_id AS overwritten_by - FROM deployments AS dep1 - LEFT JOIN deployments AS dep2 ON dep1.deleter_deployment = dep2.id` + // Generate the select according the info needed + let query: SQLStatement + if (!!filters?.includeOverwrittenInfo) { + query = SQL` + SELECT + dep1.id, + dep1.entity_type, + dep1.entity_id, + dep1.entity_pointers, + date_part('epoch', dep1.entity_timestamp) * 1000 AS entity_timestamp, + dep1.entity_metadata, + dep1.deployer_address, + dep1.version, + dep1.auth_chain, + date_part('epoch', dep1.local_timestamp) * 1000 AS local_timestamp, + dep2.entity_id AS overwritten_by + FROM deployments AS dep1 + LEFT JOIN deployments AS dep2 ON dep1.deleter_deployment = dep2.id` + } else { + query = SQL` + SELECT + dep1.id, + dep1.entity_type, + dep1.entity_id, + dep1.entity_pointers, + date_part('epoch', dep1.entity_timestamp) * 1000 AS entity_timestamp, + dep1.entity_metadata, + dep1.deployer_address, + dep1.version, + dep1.auth_chain, + date_part('epoch', dep1.local_timestamp) * 1000 AS local_timestamp + FROM deployments AS dep1` + } const whereClause: SQLStatement[] = [] + // Configure sort and order + configureSortWhereClause(order, timestampField, filters, lastId, whereClause) + + if (filters?.entityTypes && filters.entityTypes.length > 0) { + const entityTypes = filters.entityTypes + whereClause.push(SQL`dep1.entity_type = ANY (${entityTypes})`) + } + + if (filters?.entityIds && filters.entityIds.length > 0) { + const entityIds = filters.entityIds + whereClause.push(SQL`dep1.entity_id = ANY (${entityIds})`) + } + + if (filters?.onlyCurrentlyPointed) { + whereClause.push(SQL`dep1.deleter_deployment IS NULL`) + } + + if (filters?.pointers && filters.pointers.length > 0) { + const pointers = filters.pointers.map((p) => p.toLowerCase()) + whereClause.push(SQL`dep1.entity_pointers && ${pointers}`) + } - /** The lastId is a field that we only want to compare with when paginating. - * If the filter specifies a timestamp value that it's repeated among many deployments, - * then to know where the page should start we will use the lastId. - */ + let where = SQL`` + if (whereClause.length > 0) { + where = SQL` WHERE `.append(whereClause[0]) + for (const condition of whereClause.slice(1)) { + where = where.append(' AND ').append(condition) + } + } + + query.append(where) + query + .append(` ORDER BY dep1.`) + .append(pg.Client.prototype.escapeIdentifier(timestampField)) + .append(` ${order}, LOWER(dep1.entity_id) ${order} `) // raw values need to be strings not sql templates + .append(SQL`LIMIT ${limit} OFFSET ${offset}`) + + return query +} + +/** The lastId is a field that we only want to compare with when paginating. + * If the filter specifies a timestamp value that it's repeated among many deployments, + * then to know where the page should start we will use the lastId. + */ +function configureSortWhereClause( + order: string, + timestampField: string, + filters: DeploymentFilters | undefined, + lastId: string | undefined, + whereClause: SQLStatement[] +) { const pageBorder: string = (order === SortingOrder.ASCENDING ? 'from' : 'to') + (timestampField === SortingField.ENTITY_TIMESTAMP ? 'EntityTimestamp' : 'LocalTimestamp') @@ -140,47 +204,6 @@ export function getHistoricalDeploymentsQuery( whereClause.push(SQL`dep1.entity_timestamp <= to_timestamp(${toEntityTimestamp} / 1000.0)`) } } - - if (filters?.deployedBy && filters.deployedBy.length > 0) { - const deployedBy = filters.deployedBy.map((deployedBy) => deployedBy.toLocaleLowerCase()) - whereClause.push(SQL`LOWER(dep1.deployer_address) = ANY (${deployedBy})`) - } - - if (filters?.entityTypes && filters.entityTypes.length > 0) { - const entityTypes = filters.entityTypes - whereClause.push(SQL`dep1.entity_type = ANY (${entityTypes})`) - } - - if (filters?.entityIds && filters.entityIds.length > 0) { - const entityIds = filters.entityIds - whereClause.push(SQL`dep1.entity_id = ANY (${entityIds})`) - } - - if (filters?.onlyCurrentlyPointed) { - whereClause.push(SQL`dep1.deleter_deployment IS NULL`) - } - - if (filters?.pointers && filters.pointers.length > 0) { - const pointers = filters.pointers.map((p) => p.toLowerCase()) - whereClause.push(SQL`dep1.entity_pointers && ${pointers}`) - } - - let where = SQL`` - if (whereClause.length > 0) { - where = SQL` WHERE `.append(whereClause[0]) - for (const condition of whereClause.slice(1)) { - where = where.append(' AND ').append(condition) - } - } - - query.append(where) - query - .append(` ORDER BY dep1.`) - .append(pg.Client.prototype.escapeIdentifier(timestampField)) - .append(` ${order}, LOWER(dep1.entity_id) ${order} `) // raw values need to be strings not sql templates - .append(SQL`LIMIT ${limit} OFFSET ${offset}`) - - return query } export async function getHistoricalDeployments( diff --git a/content/src/repository/extensions/DeploymentsRepository.ts b/content/src/repository/extensions/DeploymentsRepository.ts index db9d956fa..5bb5632e9 100644 --- a/content/src/repository/extensions/DeploymentsRepository.ts +++ b/content/src/repository/extensions/DeploymentsRepository.ts @@ -1,15 +1,4 @@ -import { - AuditInfo, - DeploymentFilters, - DeploymentSorting, - Entity, - EntityId, - EntityType, - Pointer, - SortingField, - SortingOrder, - Timestamp -} from 'dcl-catalyst-commons' +import { AuditInfo, Entity, EntityId, EntityType, Pointer, Timestamp } from 'dcl-catalyst-commons' import { AuthChain, Authenticator } from 'dcl-crypto' import { Database } from '../../repository/Database' @@ -52,144 +41,6 @@ export class DeploymentsRepository { return new Map(entries) } - getHistoricalDeployments( - offset: number, - limit: number, - filters?: DeploymentFilters, - sortBy?: DeploymentSorting, - lastId?: string - ) { - const sorting = Object.assign({ field: SortingField.LOCAL_TIMESTAMP, order: SortingOrder.DESCENDING }, sortBy) - return this.getDeploymentsBy(sorting.field, sorting.order, offset, limit, filters, lastId) - } - - private getDeploymentsBy( - timestampField: string, - order: string, - offset: number, - limit: number, - filters?: DeploymentFilters, - lastId?: string - ) { - let query = ` - SELECT - dep1.id, - dep1.entity_type, - dep1.entity_id, - dep1.entity_pointers, - date_part('epoch', dep1.entity_timestamp) * 1000 AS entity_timestamp, - dep1.entity_metadata, - dep1.deployer_address, - dep1.version, - dep1.auth_chain, - date_part('epoch', dep1.local_timestamp) * 1000 AS local_timestamp, - dep2.entity_id AS overwritten_by - FROM deployments AS dep1 - LEFT JOIN deployments AS dep2 ON dep1.deleter_deployment = dep2.id` - - const whereClause: string[] = [] - - const values: any = { - limit, - offset - } - - if (lastId) { - values.lastId = lastId - } - - /** The lastId is a field that we only want to compare with when paginating. - * If the filter specifies a timestamp value that it's repeated among many deployments, - * then to know where the page should start we will use the lastId. - */ - const pageBorder: string = - (order === SortingOrder.ASCENDING ? 'from' : 'to') + - (timestampField === SortingField.ENTITY_TIMESTAMP ? 'EntityTimestamp' : 'LocalTimestamp') - - if (filters?.from && timestampField == SortingField.LOCAL_TIMESTAMP) { - values.fromLocalTimestamp = filters.from - if (pageBorder == 'fromLocalTimestamp' && lastId) { - whereClause.push(this.createOrClause('local_timestamp', '>', 'fromLocalTimestamp')) - } else { - whereClause.push(`dep1.local_timestamp >= to_timestamp($(fromLocalTimestamp) / 1000.0)`) - } - } - if (filters?.to && timestampField == SortingField.LOCAL_TIMESTAMP) { - values.toLocalTimestamp = filters.to - if (pageBorder == 'toLocalTimestamp' && lastId) { - whereClause.push(this.createOrClause('local_timestamp', '<', 'toLocalTimestamp')) - } else { - whereClause.push(`dep1.local_timestamp <= to_timestamp($(toLocalTimestamp) / 1000.0)`) - } - } - - if (filters?.from && timestampField == SortingField.ENTITY_TIMESTAMP) { - values.fromEntityTimestamp = filters.from - if (pageBorder == 'fromEntityTimestamp' && lastId) { - whereClause.push(this.createOrClause('entity_timestamp', '>', 'fromEntityTimestamp')) - } else { - whereClause.push(`dep1.entity_timestamp >= to_timestamp($(fromEntityTimestamp) / 1000.0)`) - } - } - if (filters?.to && timestampField == SortingField.ENTITY_TIMESTAMP) { - values.toEntityTimestamp = filters.to - if (pageBorder == 'toEntityTimestamp' && lastId) { - whereClause.push(this.createOrClause('entity_timestamp', '<', 'toEntityTimestamp')) - } else { - whereClause.push(`dep1.entity_timestamp <= to_timestamp($(toEntityTimestamp) / 1000.0)`) - } - } - - if (filters?.deployedBy && filters.deployedBy.length > 0) { - values.deployedBy = filters.deployedBy.map((deployedBy) => deployedBy.toLocaleLowerCase()) - whereClause.push(`LOWER(dep1.deployer_address) IN ($(deployedBy:list))`) - } - - if (filters?.entityTypes && filters.entityTypes.length > 0) { - values.entityTypes = filters.entityTypes - whereClause.push(`dep1.entity_type IN ($(entityTypes:list))`) - } - - if (filters?.entityIds && filters.entityIds.length > 0) { - values.entityIds = filters.entityIds - whereClause.push(`dep1.entity_id IN ($(entityIds:list))`) - } - - if (filters?.onlyCurrentlyPointed) { - whereClause.push(`dep1.deleter_deployment IS NULL`) - } - - if (filters?.pointers && filters.pointers.length > 0) { - values.pointers = filters.pointers.map((p) => p.toLowerCase()) - whereClause.push(`dep1.entity_pointers && ARRAY[$(pointers:list)]`) - } - - const where = whereClause.length > 0 ? ' WHERE ' + whereClause.join(' AND ') : '' - - query += where - query += ` ORDER BY dep1.${timestampField} ${order}, LOWER(dep1.entity_id) ${order} LIMIT $(limit) OFFSET $(offset)` - - return this.db.map(query, values, (row) => ({ - deploymentId: row.id, - entityType: row.entity_type, - entityId: row.entity_id, - pointers: row.entity_pointers, - entityTimestamp: row.entity_timestamp, - metadata: row.entity_metadata ? row.entity_metadata.v : undefined, - deployerAddress: row.deployer_address, - version: row.version, - authChain: row.auth_chain, - localTimestamp: row.local_timestamp, - overwrittenBy: row.overwritten_by ?? undefined - })) - } - - private createOrClause(timestampField: string, compare: string, timestampFilter: string): string { - const equalWithEntityIdComparison = `(LOWER(dep1.entity_id) ${compare} LOWER($(lastId)) AND dep1.${timestampField} = to_timestamp($(${timestampFilter}) / 1000.0))` - const timestampComparison = `(dep1.${timestampField} ${compare} to_timestamp($(${timestampFilter}) / 1000.0))` - return `(${equalWithEntityIdComparison} OR ${timestampComparison})` - } - deploymentsSince(entityType: EntityType, timestamp: Timestamp): Promise { return this.db.one( `SELECT COUNT(*) AS count ` + diff --git a/content/src/service/ServiceImpl.ts b/content/src/service/ServiceImpl.ts index 8c054a8bb..0e0d61fda 100644 --- a/content/src/service/ServiceImpl.ts +++ b/content/src/service/ServiceImpl.ts @@ -341,7 +341,9 @@ export class ServiceImpl implements MetaverseContentService { } async getEntitiesByIds(ids: EntityId[]): Promise { - const deployments = await getDeployments(this.components, { filters: { entityIds: ids } }) + const deployments = await getDeployments(this.components, { + filters: { entityIds: ids, onlyCurrentlyPointed: true } + }) return this.mapDeploymentsToEntities(deployments) } diff --git a/content/src/service/deployments/DeploymentManager.ts b/content/src/service/deployments/DeploymentManager.ts index c93eb4065..3e171cfec 100644 --- a/content/src/service/deployments/DeploymentManager.ts +++ b/content/src/service/deployments/DeploymentManager.ts @@ -1,14 +1,11 @@ -import { AuditInfo, Deployment, Entity, EntityId, PartialDeploymentHistory } from 'dcl-catalyst-commons' +import { AuditInfo, Entity, EntityId } from 'dcl-catalyst-commons' import { ContentFilesRepository } from '../../repository/extensions/ContentFilesRepository' import { DeploymentPointerChangesRepository } from '../../repository/extensions/DeploymentPointerChangesRepository' import { DeploymentId, DeploymentsRepository } from '../../repository/extensions/DeploymentsRepository' import { MigrationDataRepository } from '../../repository/extensions/MigrationDataRepository' import { DeploymentResult } from '../pointers/PointerManager' -import { DeploymentOptions } from './types' export class DeploymentManager { - private static MAX_HISTORY_LIMIT = 500 - async getEntityById( deploymentsRepository: DeploymentsRepository, entityId: string @@ -22,67 +19,6 @@ export class DeploymentManager { return deploymentsRepository.getEntityById(entityId) } - async getDeployments( - deploymentsRepository: DeploymentsRepository, - contentFilesRepository: ContentFilesRepository, - migrationDataRepository: MigrationDataRepository, - options?: DeploymentOptions - ): Promise> { - const curatedOffset = options?.offset && options.offset >= 0 ? options.offset : 0 - const curatedLimit = - options?.limit && options.limit > 0 && options.limit <= DeploymentManager.MAX_HISTORY_LIMIT - ? options.limit - : DeploymentManager.MAX_HISTORY_LIMIT - - const deploymentsWithExtra = await deploymentsRepository.getHistoricalDeployments( - curatedOffset, - curatedLimit + 1, - options?.filters, - options?.sortBy, - options?.lastId - ) - - const moreData = deploymentsWithExtra.length > curatedLimit - - const deploymentsResult = deploymentsWithExtra.slice(0, curatedLimit) - const deploymentIds = deploymentsResult.map(({ deploymentId }) => deploymentId) - const content = await contentFilesRepository.getContentFiles(deploymentIds) - - // TODO [new-sync]: migrationData nolonger required - const migrationData = await migrationDataRepository.getMigrationData(deploymentIds) - - const deployments: Deployment[] = deploymentsResult.map((result) => ({ - entityVersion: result.version, - entityType: result.entityType, - entityId: result.entityId, - pointers: result.pointers, - entityTimestamp: result.entityTimestamp, - content: content.get(result.deploymentId), - metadata: result.metadata, - deployedBy: result.deployerAddress, - auditInfo: { - version: result.version, - authChain: result.authChain, - localTimestamp: result.localTimestamp, - overwrittenBy: result.overwrittenBy, - migrationData: migrationData.get(result.deploymentId) - } - })) - - return { - deployments: deployments, - filters: { - ...options?.filters - }, - pagination: { - offset: curatedOffset, - limit: curatedLimit, - moreData: moreData, - lastId: options?.lastId - } - } - } - async getActiveDeploymentsByContentHash( deploymentsRepository: DeploymentsRepository, hash: string diff --git a/content/test/integration/service/deployments/deployment-filters.spec.ts b/content/test/integration/service/deployments/deployment-filters.spec.ts index 8c05c1fb2..bab82b3f4 100644 --- a/content/test/integration/service/deployments/deployment-filters.spec.ts +++ b/content/test/integration/service/deployments/deployment-filters.spec.ts @@ -1,11 +1,5 @@ import { AuditInfo, DeploymentFilters, EntityType, EntityVersion, Timestamp } from 'dcl-catalyst-commons' -import { Authenticator } from 'dcl-crypto' -import { - DeploymentContext, - DeploymentResult, - isInvalidDeployment, - isSuccessfulDeployment -} from '../../../../src/service/Service' +import { DeploymentContext, DeploymentResult, isInvalidDeployment, isSuccessfulDeployment } from '../../../../src/service/Service' import { AppComponents } from '../../../../src/types' import { makeNoopServerValidator, makeNoopValidator } from '../../../helpers/service/validations/NoOpValidator' import { loadStandaloneTestEnvironment, testCaseWithComponents } from '../../E2ETestEnvironment' @@ -80,46 +74,6 @@ loadStandaloneTestEnvironment()('Integration - Deployment Filters', (testEnv) => } ) - testCaseWithComponents( - testEnv, - 'When deployed by filter is set, then results are calculated ignoring the casing', - async (components) => { - // make noop validator - makeNoopValidator(components) - makeNoopServerValidator(components) - - const identity1 = 'Some-Identity' - const identity2 = 'another-identity' - - // Deploy E1 and E2 - await deployWithIdentity(components, identity1, E1) - await deployWithIdentity(components, identity2, E2) - - await assertDeploymentsWithFilterAre(components, {}, E1, E2) - await assertDeploymentsWithFilterAre(components, { deployedBy: [identity1] }, E1) - await assertDeploymentsWithFilterAre(components, { deployedBy: [identity1.toLowerCase()] }, E1) - await assertDeploymentsWithFilterAre(components, { deployedBy: [identity2] }, E2) - await assertDeploymentsWithFilterAre(components, { deployedBy: [identity1, identity2] }, E1, E2) - await assertDeploymentsWithFilterAre(components, { deployedBy: ['not-and-identity'] }) - } - ) - - testCaseWithComponents( - testEnv, - 'When deployed by filter is set, then results are calculated correctly', - async (components) => { - // make noop validator - makeNoopValidator(components) - makeNoopServerValidator(components) - - await deploy(components, E1, E2, E3) - - await assertDeploymentsWithFilterAre(components, {}, E1, E2, E3) - await assertDeploymentsWithFilterAre(components, { onlyCurrentlyPointed: true }, E2, E3) - await assertDeploymentsWithFilterAre(components, { onlyCurrentlyPointed: false }, E1, E2, E3) - } - ) - testCaseWithComponents( testEnv, 'When pointers filter is set, then results are calculated correctly', @@ -174,15 +128,6 @@ loadStandaloneTestEnvironment()('Integration - Deployment Filters', (testEnv) => return deployWithAuditInfo(components, entities, {}) } - async function deployWithIdentity( - components: Pick, - deployedBy: string, - ...entities: EntityCombo[] - ): Promise { - const authChain = Authenticator.createSimpleAuthChain('', deployedBy, '') - return deployWithAuditInfo(components, entities, { authChain }) - } - async function deployWithAuditInfo( components: Pick, entities: EntityCombo[], diff --git a/content/test/integration/service/order-check.spec.ts b/content/test/integration/service/order-check.spec.ts index 8385c964f..19ecd3b9a 100644 --- a/content/test/integration/service/order-check.spec.ts +++ b/content/test/integration/service/order-check.spec.ts @@ -54,7 +54,12 @@ loadStandaloneTestEnvironment()('Integration - Order Check', (testEnv) => { } async function getActiveDeployments(components: Pick) { - const { deployments } = await components.deployer.getDeployments({ filters: { onlyCurrentlyPointed: true } }) + const { deployments } = await components.deployer.getDeployments({ + filters: { + onlyCurrentlyPointed: true, + includeOverwrittenInfo: true + } + }) return deployments } @@ -74,7 +79,11 @@ loadStandaloneTestEnvironment()('Integration - Order Check', (testEnv) => { async function getAuditInfo(components: Pick, entity: EntityCombo): Promise { const { deployments } = await components.deployer.getDeployments({ - filters: { entityTypes: [entity.controllerEntity.type], entityIds: [entity.controllerEntity.id] } + filters: { + entityTypes: [entity.controllerEntity.type], + entityIds: [entity.controllerEntity.id], + includeOverwrittenInfo: true + } }) return deployments[0].auditInfo } diff --git a/content/test/integration/service/same-timestamp-check.spec.ts b/content/test/integration/service/same-timestamp-check.spec.ts index f30f81294..9eebcb7d9 100644 --- a/content/test/integration/service/same-timestamp-check.spec.ts +++ b/content/test/integration/service/same-timestamp-check.spec.ts @@ -91,7 +91,11 @@ loadStandaloneTestEnvironment()('Integration - Same Timestamp Check', (testEnv) async function getAuditInfo(deployer: AppComponents['deployer'], entity: EntityCombo): Promise { const { deployments } = await deployer.getDeployments({ - filters: { entityTypes: [entity.controllerEntity.type], entityIds: [entity.controllerEntity.id] } + filters: { + entityTypes: [entity.controllerEntity.type], + entityIds: [entity.controllerEntity.id], + includeOverwrittenInfo: true + } }) return deployments[0].auditInfo } diff --git a/content/test/unit/logic/deployments-queries.spec.ts b/content/test/unit/logic/deployments-queries.spec.ts index f2077512d..91fa5496e 100644 --- a/content/test/unit/logic/deployments-queries.spec.ts +++ b/content/test/unit/logic/deployments-queries.spec.ts @@ -103,16 +103,6 @@ describe('deployments-queries', () => { }) }) - describe('when there is a deployed by filter', () => { - it('should add the expected where clause to the query with the addresses on lowercase', async () => { - const deployedBy = ['jOn', 'aGus'] - const result = getHistoricalDeploymentsQuery(offset, limit, { deployedBy }) - - expect(result.text).toContain(`LOWER(dep1.deployer_address) = ANY ($1)`) - expect(result.values).toEqual([['jon', 'agus'], limit, offset]) - }) - }) - describe('when there is entityTypes filter', () => { it('should add the expected where clause to the query', async () => { const entityTypes = [EntityType.SCENE, EntityType.PROFILE] diff --git a/content/test/unit/repository/DeploymentsRepository.spec.ts b/content/test/unit/repository/DeploymentsRepository.spec.ts index 9455d9bdc..eed912368 100644 --- a/content/test/unit/repository/DeploymentsRepository.spec.ts +++ b/content/test/unit/repository/DeploymentsRepository.spec.ts @@ -1,4 +1,4 @@ -import { Entity, EntityType, EntityVersion, SortingField, SortingOrder } from 'dcl-catalyst-commons' +import { Entity, EntityType, EntityVersion } from 'dcl-catalyst-commons' import { anything, capture, deepEqual, instance, mock, spy, verify, when } from 'ts-mockito' import { DeploymentsRepository } from '../../../src/repository/extensions/DeploymentsRepository' import MockedDataBase from './MockedDataBase' @@ -38,181 +38,6 @@ describe('DeploymentRepository', () => { }) }) - describe('getHistoricalDeployments', () => { - describe("when it doesn't receive a lastId", () => { - beforeEach(() => { - db = mock(MockedDataBase) - repository = new DeploymentsRepository(instance(db) as any) - when(db.map(anything(), anything(), anything())).thenReturn(Promise.resolve([])) - }) - - describe('when it receives a field or order to sort by', () => { - it('should call the database with the expected sorting', async () => { - await repository.getHistoricalDeployments( - 0, - 10, - { from: 1, to: 11 }, - { - field: SortingField.ENTITY_TIMESTAMP, - order: SortingOrder.ASCENDING - } - ) - - const args = capture(db.map).last() - - expect(args[0]).toContain(`ORDER BY dep1.entity_timestamp ASC`) - expect(args[0]).toContain( - `dep1.entity_timestamp >= to_timestamp($(fromEntityTimestamp) / 1000.0) AND dep1.entity_timestamp <= to_timestamp($(toEntityTimestamp) / 1000.0)` - ) - expect(args[1]).toEqual(expect.objectContaining({ fromEntityTimestamp: 1, toEntityTimestamp: 11 })) - }) - }) - - describe("when it doesn't receive a field or order to sort by", () => { - it('should call the database with the default sorting', async () => { - await repository.getHistoricalDeployments(0, 10, { from: 1, to: 11 }) - - const args = capture(db.map).last() - - expect(args[0]).toContain(`ORDER BY dep1.local_timestamp DESC`) - expect(args[0]).toContain( - `dep1.local_timestamp >= to_timestamp($(fromLocalTimestamp) / 1000.0) AND dep1.local_timestamp <= to_timestamp($(toLocalTimestamp) / 1000.0)` - ) - expect(args[1]).toEqual(expect.objectContaining({ fromLocalTimestamp: 1, toLocalTimestamp: 11 })) - }) - }) - }) - - describe('when it receives a lastId', () => { - const lastId = '1' - - beforeEach(() => { - db = mock(MockedDataBase) - repository = new DeploymentsRepository(instance(db) as any) - }) - - describe('when it receives a field or order to sort by', () => { - it('should call the database with the expected sorting', async () => { - await repository.getHistoricalDeployments( - 0, - 10, - { from: 1, to: 11 }, - { - field: SortingField.ENTITY_TIMESTAMP, - order: SortingOrder.ASCENDING - }, - lastId - ) - - const args = capture(db.map).last() - - expect(args[0]).toContain(`ORDER BY dep1.entity_timestamp ASC`) - expect(args[0]).toContain(`((LOWER(dep1.entity_id) > LOWER($(lastId))`) - expect(args[0]).toContain( - `dep1.entity_timestamp = to_timestamp($(fromEntityTimestamp) / 1000.0)) ` + - `OR (dep1.entity_timestamp > to_timestamp($(fromEntityTimestamp) / 1000.0))) ` + - `AND dep1.entity_timestamp <= to_timestamp($(toEntityTimestamp) / 1000.0)` - ) - - expect(args[1]).toEqual(expect.objectContaining({ fromEntityTimestamp: 1, toEntityTimestamp: 11 })) - }) - }) - - describe("when it doesn't receive a field or order to sort by", () => { - it('should call the database with the default sorting', async () => { - await repository.getHistoricalDeployments(0, 10, { from: 1, to: 11 }, undefined, lastId) - - const args = capture(db.map).last() - - expect(args[0]).toContain(`ORDER BY dep1.local_timestamp DESC`) - expect(args[0]).toContain(`((LOWER(dep1.entity_id) < LOWER($(lastId))`) - expect(args[0]).toContain( - `dep1.local_timestamp >= to_timestamp($(fromLocalTimestamp) / 1000.0) AND ` + - `((LOWER(dep1.entity_id) < LOWER($(lastId)) AND dep1.local_timestamp = to_timestamp($(toLocalTimestamp) / 1000.0)) ` + - `OR (dep1.local_timestamp < to_timestamp($(toLocalTimestamp) / 1000.0)))` - ) - - expect(args[1]).toEqual(expect.objectContaining({ fromLocalTimestamp: 1, toLocalTimestamp: 11 })) - }) - }) - }) - - describe('when there is a deployed by filter', () => { - beforeEach(() => { - db = mock(MockedDataBase) - repository = new DeploymentsRepository(instance(db) as any) - - when(db.map(anything(), anything(), anything())).thenReturn(Promise.resolve([])) - }) - - it('should add the expected where clause to the query with the addresses on lowercase', async () => { - const deployedBy = ['jOn', 'aGus'] - await repository.getHistoricalDeployments(0, 10, { deployedBy }) - - const args = capture(db.map).last() - - expect(args[0]).toContain(`LOWER(dep1.deployer_address) IN ($(deployedBy:list))`) - expect(args[1]).toEqual(expect.objectContaining({ deployedBy: ['jon', 'agus'] })) - }) - }) - - describe('when there is entityTypes filter', () => { - it('should add the expected where clause to the query', async () => { - const entityTypes = [EntityType.SCENE, EntityType.PROFILE] - await repository.getHistoricalDeployments(0, 10, { entityTypes }) - - const args = capture(db.map).last() - - expect(args[0]).toContain(`dep1.entity_type IN ($(entityTypes:list))`) - expect(args[1]).toEqual(expect.objectContaining({ entityTypes })) - }) - }) - - describe('when there is entityIds filter', () => { - it('should add the expected where clause to the query', async () => { - const entityIds = ['A custom string', 'Another custom string'] - - await repository.getHistoricalDeployments(0, 10, { entityIds }) - - const args = capture(db.map).last() - - expect(args[0]).toContain(`dep1.entity_id IN ($(entityIds:list))`) - expect(args[1]).toEqual(expect.objectContaining({ entityIds })) - }) - }) - - describe('when there is onlyCurrentlyPointed filter', () => { - it('should add the expected where clause to the query', async () => { - await repository.getHistoricalDeployments(0, 10, { onlyCurrentlyPointed: true }) - - const args = capture(db.map).last() - - expect(args[0]).toContain(`dep1.deleter_deployment IS NULL`) - }) - }) - - describe('when there is pointers filter', () => { - it('should add the expected where clause to the query with the pointers in lowercase', async () => { - const pointers = ['jOn', 'aGus'] - await repository.getHistoricalDeployments(0, 10, { pointers }) - - const args = capture(db.map).last() - - expect(args[0]).toContain(`dep1.entity_pointers && ARRAY[$(pointers:list)]`) - expect(args[1]).toEqual(expect.objectContaining({ pointers: pointers.map((x) => x.toLowerCase()) })) - }) - }) - - describe('when there is no filter', () => { - it('should not add a where clause', async () => { - await repository.getHistoricalDeployments(0, 10) - - const args = capture(db.map).last() - expect(args[0]).not.toContain(`WHERE`) - }) - }) - }) - describe('saveDeployment', () => { beforeEach(() => { db = mock(MockedDataBase)