diff --git a/package.json b/package.json index 8a2c557b..8440fbbe 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "hawk.api", - "version": "1.4.13", + "version": "1.4.14", "main": "index.ts", "license": "BUSL-1.1", "scripts": { diff --git a/src/resolvers/project.js b/src/resolvers/project.js index 65fc2cdc..18da81f3 100644 --- a/src/resolvers/project.js +++ b/src/resolvers/project.js @@ -14,6 +14,7 @@ const { GitHubService } = require('../integrations/github/service'); const EVENTS_GROUP_HASH_INDEX_NAME = 'groupHashUnique'; const REPETITIONS_GROUP_HASH_INDEX_NAME = 'groupHash_hashed'; const REPETITIONS_USER_ID_INDEX_NAME = 'userId'; +const REPETITIONS_TIMESTAMP_INDEX_NAME = 'timestamp'; const EVENTS_TIMESTAMP_INDEX_NAME = 'timestamp'; const EVENTS_PAYLOAD_RELEASE_INDEX_NAME = 'payloadRelease'; const GROUPING_TIMESTAMP_INDEX_NAME = 'groupingTimestamp'; @@ -213,6 +214,13 @@ module.exports = { sparse: true, }); + await projectRepetitionsEventsCollection.createIndex({ + timestamp: 1, + }, { + name: REPETITIONS_TIMESTAMP_INDEX_NAME, + sparse: true, + }); + await projectEventsCollection.createIndex({ timestamp: 1, }, { diff --git a/test/resolvers/project.test.ts b/test/resolvers/project.test.ts index 8f50acbc..00a4a907 100644 --- a/test/resolvers/project.test.ts +++ b/test/resolvers/project.test.ts @@ -8,9 +8,24 @@ jest.mock('../../src/integrations/github/service', () => require('../__mocks__/g // eslint-disable-next-line @typescript-eslint/no-var-requires import { deleteInstallationMock, GitHubService } from '../__mocks__/github-service'; +jest.mock('../../src/mongo', () => ({ + databases: { + events: { + createCollection: jest.fn(), + }, + }, +})); + +jest.mock('../../src/utils/telegram', () => ({ + sendMessage: jest.fn(), +})); + // @ts-expect-error - CommonJS module, TypeScript can't infer types properly import projectResolverModule from '../../src/resolvers/project'; +// eslint-disable-next-line @typescript-eslint/no-var-requires +const mongoMock = require('../../src/mongo'); + /** * Type assertion for CommonJS module */ @@ -18,6 +33,7 @@ const projectResolver = projectResolverModule as { Mutation: { disconnectTaskManager: (...args: unknown[]) => Promise; updateTaskManagerSettings: (...args: unknown[]) => Promise; + createProject: (...args: unknown[]) => Promise; }; Query: { project: (...args: unknown[]) => Promise; @@ -518,3 +534,71 @@ describe('Project Resolver - Task Manager Mutations', () => { }); }); }); + +describe('Project Resolver - createProject', () => { + beforeEach(() => { + jest.clearAllMocks(); + }); + + it('should create a timestamp index on the repetitions collection', async () => { + const projectId = new ObjectId(); + + const eventsCollectionMock = { createIndex: jest.fn().mockResolvedValue(undefined) }; + const repetitionsCollectionMock = { createIndex: jest.fn().mockResolvedValue(undefined) }; + const dailyEventsCollectionMock = { createIndex: jest.fn().mockResolvedValue(undefined) }; + + mongoMock.databases.events.createCollection.mockImplementation((name: string) => { + if (name.startsWith('events:')) { + return Promise.resolve(eventsCollectionMock); + } + if (name.startsWith('repetitions:')) { + return Promise.resolve(repetitionsCollectionMock); + } + if (name.startsWith('dailyEvents:')) { + return Promise.resolve(dailyEventsCollectionMock); + } + return Promise.reject(new Error(`Unexpected collection name: ${name}`)); + }); + + const mockProject = { + _id: projectId, + createNotificationsRule: jest.fn().mockResolvedValue(undefined), + }; + + const mockProjectsFactory = { + create: jest.fn().mockResolvedValue(mockProject), + findById: jest.fn().mockResolvedValue(mockProject), + }; + + const mockWorkspacesFactory = { + findById: jest.fn().mockResolvedValue({ _id: new ObjectId(), name: 'Test Workspace' }), + }; + + const mockUsersFactory = { + findById: jest.fn().mockResolvedValue({ email: 'test@example.com' }), + }; + + const context = { + user: { id: new ObjectId().toString() }, + factories: { + workspacesFactory: mockWorkspacesFactory as any, + projectsFactory: mockProjectsFactory as any, + usersFactory: mockUsersFactory as any, + plansFactory: {} as any, + businessOperationsFactory: {} as any, + releasesFactory: {} as any, + }, + }; + + await projectResolver.Mutation.createProject( + {}, + { workspaceId: new ObjectId().toString(), name: 'Test Project', image: '' }, + context + ); + + expect(repetitionsCollectionMock.createIndex).toHaveBeenCalledWith( + { timestamp: 1 }, + { name: 'timestamp', sparse: true } + ); + }); +}); diff --git a/yarn.lock b/yarn.lock index bfe5bde9..995f6267 100644 --- a/yarn.lock +++ b/yarn.lock @@ -494,10 +494,10 @@ dependencies: tslib "^2.4.0" -"@hawk.so/nodejs@^3.3.1": - version "3.3.1" - resolved "https://registry.yarnpkg.com/@hawk.so/nodejs/-/nodejs-3.3.1.tgz#23e304607a64cd3a91e488d481cc968fccab6dba" - integrity sha512-GALpgM/96As5gE3YdwVcMglTc57Dfqez3b2EciKJoq0u174gK/h+8tayEL+/65pqBy7BNni8ptCQWdgw5Zv5yA== +"@hawk.so/nodejs@^3.3.2": + version "3.3.2" + resolved "https://registry.yarnpkg.com/@hawk.so/nodejs/-/nodejs-3.3.2.tgz#113db57546f82e5c405c43b6dc5709232827c4df" + integrity sha512-i8KFHjFfwmtgN///Q1oxNDTJSQEtjy5iBqDZBuSMAzpQhBBmBE2n9RNIRDaVOby8r+Z+oo3g4Sik2LlffB5AWQ== dependencies: "@hawk.so/types" "^0.5.8" axios "^0.21.1"