diff --git a/packages/api/src/models/index.ts b/packages/api/src/models/index.ts deleted file mode 100644 index 3e932d006a..0000000000 --- a/packages/api/src/models/index.ts +++ /dev/null @@ -1,67 +0,0 @@ -import mongoose from 'mongoose'; - -import * as config from '@/config'; -import { getCounter } from '@/utils/instrumentation'; -import logger from '@/utils/logger'; - -export type ObjectId = mongoose.Types.ObjectId; - -// Connection-lifecycle events were log-only. A counter keyed by the (bounded) -// event name makes flapping/reconnect storms visible on a dashboard and -// alertable (see agent_docs/observability.md). -const mongoConnectionEventsCounter = getCounter( - 'hyperdx.mongodb.connection_events', - { - description: - 'Count of MongoDB connection lifecycle events, labeled by event (connected, disconnected, error, reconnected, reconnect_failed).', - }, -); - -// set flags -mongoose.set('strictQuery', false); - -// Allow empty strings to be set to required fields -// https://github.com/Automattic/mongoose/issues/7150 -// ex. query in logview can be empty -mongoose.Schema.Types.String.checkRequired(v => v != null); - -// connection events handlers -mongoose.connection.on('connected', () => { - mongoConnectionEventsCounter.add(1, { event: 'connected' }); - logger.info('Connection established to MongoDB'); -}); - -mongoose.connection.on('disconnected', () => { - mongoConnectionEventsCounter.add(1, { event: 'disconnected' }); - logger.info('Lost connection to MongoDB server'); -}); - -mongoose.connection.on('error', err => { - mongoConnectionEventsCounter.add(1, { event: 'error' }); - logger.error({ err }, 'Could not connect to MongoDB'); -}); - -mongoose.connection.on('reconnected', () => { - mongoConnectionEventsCounter.add(1, { event: 'reconnected' }); - logger.warn('Reconnected to MongoDB'); -}); - -mongoose.connection.on('reconnectFailed', () => { - mongoConnectionEventsCounter.add(1, { event: 'reconnect_failed' }); - logger.error('Failed to reconnect to MongoDB'); -}); - -export const connectDB = async () => { - // breadcrumbs for future greppers: aws4 is included as a dependency of the api so that - // users can use AWS auth in their mongo connection string here, e.g. - // mongodb+srv://blahblah...mongodb.net/hyperdx?authSource=%24external&authMechanism=MONGODB-AWS - if (config.MONGO_URI == null) { - throw new Error('MONGO_URI is not set'); - } - await mongoose.connect(config.MONGO_URI, { - heartbeatFrequencyMS: 10000, // retry failed heartbeats - maxPoolSize: 100, // 5 nodes -> max 1000 connections - }); -}; - -export const mongooseConnection = mongoose.connection; diff --git a/packages/app/package.json b/packages/app/package.json index 0096acd488..d9ba57e175 100644 --- a/packages/app/package.json +++ b/packages/app/package.json @@ -115,6 +115,7 @@ "@testing-library/jest-dom": "^6.4.2", "@testing-library/react": "^16.3.0", "@testing-library/user-event": "^14.5.2", + "@total-typescript/shoehorn": "^0.1.2", "@types/crypto-js": "^4", "@types/flat": "^5.0.5", "@types/identity-obj-proxy": "^3", diff --git a/packages/app/src/components/__tests__/DBRowSidePanel.viewTraceTimeFilter.test.tsx b/packages/app/src/components/__tests__/DBRowSidePanel.viewTraceTimeFilter.test.tsx index 16d0dd4055..503fa52c1b 100644 --- a/packages/app/src/components/__tests__/DBRowSidePanel.viewTraceTimeFilter.test.tsx +++ b/packages/app/src/components/__tests__/DBRowSidePanel.viewTraceTimeFilter.test.tsx @@ -2,7 +2,7 @@ import React from 'react'; import { TSource } from '@hyperdx/common-utils/dist/types'; import { MantineProvider } from '@mantine/core'; import { fireEvent, render, screen } from '@testing-library/react'; - +import { fromPartial } from '@total-typescript/shoehorn'; // Controlled, in-memory replacement for nuqs' useQueryState so each side-panel // URL param can be seeded and its setter inspected independently. Values are // the already-parsed shapes the component consumes (arrays / strings), not URL @@ -30,7 +30,7 @@ jest.mock('nuqs', () => { ); const fallback = parser && 'defaultValue' in parser ? parser.defaultValue : null; - const value = hasValue ? mockQueryStore[key] : (fallback ?? null); + const value = hasValue ? mockQueryStore[key] : fallback ?? null; if (!mockSetters[key]) mockSetters[key] = jest.fn(); return [value, mockSetters[key]]; }, @@ -158,13 +158,13 @@ import useSidePanelStack from '@/hooks/useSidePanelStack'; import { getRowLookupWindow } from '@/utils/rowTimestamps'; // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -const ROOT_SOURCE = { +const ROOT_SOURCE = fromPartial({ id: 'log-src', kind: 'log', traceSourceId: 'trace-src', timestampValueExpression: 'Timestamp', resourceAttributesExpression: 'ResourceAttributes', -} as TSource; +}) as TSource; const TRACE_ID = '7316d5a2ab0dc2efa72258f64a98a405'; const SPAN_ID = 'e3748131832d6176'; diff --git a/packages/app/src/components/__tests__/DBTimeChart.test.tsx b/packages/app/src/components/__tests__/DBTimeChart.test.tsx index 380e832757..9ecbf2bd35 100644 --- a/packages/app/src/components/__tests__/DBTimeChart.test.tsx +++ b/packages/app/src/components/__tests__/DBTimeChart.test.tsx @@ -3,6 +3,8 @@ import { MantineProvider } from '@mantine/core'; import { Notifications } from '@mantine/notifications'; import { screen, waitFor } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; +import { fromPartial } from '@total-typescript/shoehorn'; +import { DisplayType } from '@hyperdx/common-utils/dist/types'; import api from '@/api'; import { ChartKeyJoiner } from '@/ChartUtils'; @@ -155,9 +157,11 @@ describe('DBTimeChart', () => { it('passes the same config to useMVOptimizationExplanation, useQueriedChartConfig, and MVOptimizationIndicator', () => { // Mock useSource to return a source so MVOptimizationIndicator is rendered - jest.mocked(useSource).mockReturnValue({ - data: { id: 'test-source', name: 'Test Source' }, - } as any); + jest.mocked(useSource).mockReturnValue( + fromPartial({ + data: { id: 'test-source', name: 'Test Source' }, + }) as ReturnType, + ); renderWithMantine(); @@ -183,9 +187,11 @@ describe('DBTimeChart', () => { }); it('disables the MV-optimization query when both MV and date-range indicators are hidden', () => { - jest.mocked(useSource).mockReturnValue({ - data: { id: 'test-source', name: 'Test Source' }, - } as any); + jest.mocked(useSource).mockReturnValue( + fromPartial({ + data: { id: 'test-source', name: 'Test Source' }, + }) as ReturnType, + ); renderWithMantine( { }); it('keeps the MV-optimization query enabled when only the date-range indicator is shown', () => { - jest.mocked(useSource).mockReturnValue({ - data: { id: 'test-source', name: 'Test Source' }, - } as any); + jest.mocked(useSource).mockReturnValue( + fromPartial({ + data: { id: 'test-source', name: 'Test Source' }, + }) as ReturnType, + ); renderWithMantine( { }; // Mock useMVOptimizationExplanation to return an optimized config with aligned date range - jest.mocked(useMVOptimizationExplanation).mockReturnValue({ - data: { - optimizedConfig: { - ...config, - dateRange: [alignedStartDate, alignedEndDate] as [Date, Date], - }, - explanations: [ - { - success: true, - mvConfig: { - minGranularity: '1 minute', - tableName: 'metrics_rollup_1m', - }, + jest.mocked(useMVOptimizationExplanation).mockReturnValue( + fromPartial({ + data: { + optimizedConfig: { + ...config, + dateRange: [alignedStartDate, alignedEndDate] as [Date, Date], }, - ], - }, - isLoading: false, - isPlaceholderData: false, - } as any); + explanations: [ + { + success: true, + mvConfig: { + minGranularity: '1 minute', + tableName: 'metrics_rollup_1m', + }, + }, + ], + }, + isLoading: false, + isPlaceholderData: false, + }) as ReturnType, + ); renderWithMantine(); @@ -477,14 +487,16 @@ describe('DBTimeChart', () => { }; // Mock useMVOptimizationExplanation to return no optimized config - jest.mocked(useMVOptimizationExplanation).mockReturnValue({ - data: { - optimizedConfig: undefined, - explanations: [], - }, - isLoading: false, - isPlaceholderData: false, - } as any); + jest.mocked(useMVOptimizationExplanation).mockReturnValue( + fromPartial({ + data: { + optimizedConfig: undefined, + explanations: [], + }, + isLoading: false, + isPlaceholderData: false, + }) as ReturnType, + ); renderWithMantine(); @@ -511,7 +523,7 @@ describe('DBTimeChart', () => { sqlTemplate: 'SELECT toStartOfInterval(ts, INTERVAL {intervalSeconds:Int64} SECOND) AS ts, count() AS count FROM logs GROUP BY ts ORDER BY ts ASC', connection: 'test-connection', - displayType: 'line' as any, + displayType: DisplayType.Line, dateRange: [new Date('2024-01-01'), new Date('2024-01-02')] as [ Date, Date, diff --git a/packages/app/src/components/__tests__/MetricTableModelForm.test.tsx b/packages/app/src/components/__tests__/MetricTableModelForm.test.tsx index 2f1ce9abab..8e6e8559cd 100644 --- a/packages/app/src/components/__tests__/MetricTableModelForm.test.tsx +++ b/packages/app/src/components/__tests__/MetricTableModelForm.test.tsx @@ -1,6 +1,7 @@ import React, { useEffect } from 'react'; import { useForm } from 'react-hook-form'; import { SourceKind, TSource } from '@hyperdx/common-utils/dist/types'; +import { fromPartial } from '@total-typescript/shoehorn'; import { MantineProvider } from '@mantine/core'; import { render, waitFor } from '@testing-library/react'; @@ -122,8 +123,7 @@ function autofilledTables() { .map(([path, value]) => [path, value]); } -// eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion -const SAVED_SOURCE: TSource = { +const SAVED_SOURCE = fromPartial({ id: 'metric-source-1', kind: SourceKind.Metric, name: 'Metrics', @@ -134,7 +134,7 @@ const SAVED_SOURCE: TSource = { gauge: 'otel_metrics_gauge', sum: 'otel_metrics_sum', }, -} as any; +}) as TSource; describe('MetricTableModelForm metric table autofill', () => { beforeEach(() => { @@ -238,11 +238,11 @@ describe('MetricTableModelForm metric table autofill', () => { // tables to preserve, so it autofills like a new source. it('autofills for an existing source switched to the metrics kind', async () => { // eslint-disable-next-line @typescript-eslint/no-unsafe-type-assertion - savedSource = { + savedSource = fromPartial({ ...SAVED_SOURCE, kind: SourceKind.Log, metricTables: undefined, - } as any; + }) as TSource; renderHarness( , diff --git a/yarn.lock b/yarn.lock index a7c0f5279a..1ac83dbcfe 100644 --- a/yarn.lock +++ b/yarn.lock @@ -4734,6 +4734,7 @@ __metadata: "@testing-library/jest-dom": "npm:^6.4.2" "@testing-library/react": "npm:^16.3.0" "@testing-library/user-event": "npm:^14.5.2" + "@total-typescript/shoehorn": "npm:^0.1.2" "@types/crypto-js": "npm:^4" "@types/flat": "npm:^5.0.5" "@types/identity-obj-proxy": "npm:^3" @@ -9976,6 +9977,13 @@ __metadata: languageName: node linkType: hard +"@total-typescript/shoehorn@npm:^0.1.2": + version: 0.1.2 + resolution: "@total-typescript/shoehorn@npm:0.1.2" + checksum: 10c0/e1bb904a3c46bd00a3a31a4f24a07a5de8f6c4aebb811f4ac108dfad066d2797c682b49bbcd09e98e2bd12e8b67db9bcb793e02e2ed8a996e1fe0d232a7efcf1 + languageName: node + linkType: hard + "@tsconfig/node10@npm:^1.0.7": version: 1.0.9 resolution: "@tsconfig/node10@npm:1.0.9"