diff --git a/packages/entity-database-adapter-knex/src/internal/EntityKnexDataManager.ts b/packages/entity-database-adapter-knex/src/internal/EntityKnexDataManager.ts index 87e772bb6..dfb7216b1 100644 --- a/packages/entity-database-adapter-knex/src/internal/EntityKnexDataManager.ts +++ b/packages/entity-database-adapter-knex/src/internal/EntityKnexDataManager.ts @@ -1,6 +1,7 @@ import type { EntityConfiguration, EntityQueryContext, IEntityMetricsAdapter } from '@expo/entity'; import { EntityDatabaseAdapterPaginationCursorInvalidError, + EntityMetricsCountType, EntityMetricsLoadType, getDatabaseFieldForEntityField, timeAndLogCountEventAsync, @@ -197,7 +198,7 @@ export class EntityKnexDataManager< ): Promise { return await timeAndLogCountEventAsync( this.metricsAdapter, - EntityMetricsLoadType.COUNT_EQUALITY_CONJUNCTION, + EntityMetricsCountType.COUNT_EQUALITY_CONJUNCTION, this.entityClassName, queryContext, )( @@ -235,7 +236,7 @@ export class EntityKnexDataManager< ): Promise { return await timeAndLogCountEventAsync( this.metricsAdapter, - EntityMetricsLoadType.COUNT_SQL, + EntityMetricsCountType.COUNT_SQL, this.entityClassName, queryContext, )(this.databaseAdapter.countBySQLFragmentAsync(queryContext, sqlFragment)); diff --git a/packages/entity/src/metrics/EntityMetricsUtils.ts b/packages/entity/src/metrics/EntityMetricsUtils.ts index 57c0d1735..05218db1f 100644 --- a/packages/entity/src/metrics/EntityMetricsUtils.ts +++ b/packages/entity/src/metrics/EntityMetricsUtils.ts @@ -2,6 +2,7 @@ import type { EntityQueryContext } from '../EntityQueryContext.ts'; import type { IEntityLoadValue } from '../internal/EntityLoadInterfaces.ts'; import { reduceMap } from '../utils/collections/maps.ts'; import type { + EntityMetricsCountType, EntityMetricsLoadType, EntityMetricsMutationType, IEntityMetricsAdapter, @@ -87,7 +88,7 @@ export const timeAndLogLoadMapEventAsync = export const timeAndLogCountEventAsync = ( metricsAdapter: IEntityMetricsAdapter, - loadType: EntityMetricsLoadType, + countType: EntityMetricsCountType, entityClassName: string, queryContext: EntityQueryContext, ) => @@ -96,8 +97,8 @@ export const timeAndLogCountEventAsync = const result = await promise; const endTime = Date.now(); - metricsAdapter.logDataManagerLoadEvent({ - type: loadType, + metricsAdapter.logDataManagerCountEvent({ + type: countType, isInTransaction: queryContext.isInTransaction(), entityClassName, duration: endTime - startTime, diff --git a/packages/entity/src/metrics/IEntityMetricsAdapter.ts b/packages/entity/src/metrics/IEntityMetricsAdapter.ts index 02ee8219c..13c3acb53 100644 --- a/packages/entity/src/metrics/IEntityMetricsAdapter.ts +++ b/packages/entity/src/metrics/IEntityMetricsAdapter.ts @@ -28,8 +28,14 @@ export enum EntityMetricsLoadType { * Knex loader load using loadPageAsync. */ LOAD_PAGE, +} + +/** + * The type of the count method being called. + */ +export enum EntityMetricsCountType { /** - * Knex loader count using countBySQLAsync. + * Knex loader count using countBySQLFragmentAsync. */ COUNT_SQL, /** @@ -68,6 +74,37 @@ export interface EntityMetricsLoadEvent { count: number; } +/** + * Event about a single call to an EntityLoader count method. Counts return a + * number rather than entities, so they are reported separately from loads. + */ +export interface EntityMetricsCountEvent { + /** + * EntityMetricsCountType for this count. + */ + type: EntityMetricsCountType; + + /** + * Whether this count is within a transaction. + */ + isInTransaction: boolean; + + /** + * Class name of the Entity being counted. + */ + entityClassName: string; + + /** + * Total duration of this count query. + */ + duration: number; + + /** + * The number returned by the count query. No entities are loaded for a count. + */ + count: number; +} + /** * The type of mutation being performed. */ @@ -201,6 +238,13 @@ export interface IEntityMetricsAdapter { */ logDataManagerLoadEvent(loadEvent: EntityMetricsLoadEvent): void; + /** + * Called when any count occurs. Counts return a number rather than entities, + * so they are reported separately from loads. + * @param countEvent - info about the count event + */ + logDataManagerCountEvent(countEvent: EntityMetricsCountEvent): void; + /** * Called when any mutation occurs. * @param mutationEvent - info about the mutation event diff --git a/packages/entity/src/metrics/NoOpEntityMetricsAdapter.ts b/packages/entity/src/metrics/NoOpEntityMetricsAdapter.ts index c01ac66a2..97b8e6c07 100644 --- a/packages/entity/src/metrics/NoOpEntityMetricsAdapter.ts +++ b/packages/entity/src/metrics/NoOpEntityMetricsAdapter.ts @@ -1,5 +1,6 @@ import type { EntityMetricsAuthorizationEvent, + EntityMetricsCountEvent, EntityMetricsLoadEvent, EntityMetricsMutationEvent, IEntityMetricsAdapter, @@ -9,6 +10,7 @@ import type { export class NoOpEntityMetricsAdapter implements IEntityMetricsAdapter { logAuthorizationEvent(_authorizationEvent: EntityMetricsAuthorizationEvent): void {} logDataManagerLoadEvent(_loadEvent: EntityMetricsLoadEvent): void {} + logDataManagerCountEvent(_countEvent: EntityMetricsCountEvent): void {} logMutatorMutationEvent(_mutationEvent: EntityMetricsMutationEvent): void {} incrementDataManagerLoadCount(_incrementLoadCountEvent: IncrementLoadCountEvent): void {} } diff --git a/packages/entity/src/metrics/__tests__/EntityMetricsUtils-test.ts b/packages/entity/src/metrics/__tests__/EntityMetricsUtils-test.ts index a8d433fd8..e06c05be5 100644 --- a/packages/entity/src/metrics/__tests__/EntityMetricsUtils-test.ts +++ b/packages/entity/src/metrics/__tests__/EntityMetricsUtils-test.ts @@ -9,7 +9,11 @@ import { timeAndLogMutationEventAsync, } from '../EntityMetricsUtils.ts'; import type { IEntityMetricsAdapter } from '../IEntityMetricsAdapter.ts'; -import { EntityMetricsLoadType, EntityMetricsMutationType } from '../IEntityMetricsAdapter.ts'; +import { + EntityMetricsCountType, + EntityMetricsLoadType, + EntityMetricsMutationType, +} from '../IEntityMetricsAdapter.ts'; describe(timeAndLogLoadEventAsync, () => { it('returns the result from the wrapped promise and logs', async () => { @@ -95,7 +99,7 @@ describe(timeAndLogCountEventAsync, () => { const result = await timeAndLogCountEventAsync( metricsAdapter, - EntityMetricsLoadType.COUNT_SQL, + EntityMetricsCountType.COUNT_SQL, 'TestEntity', queryContext, )(Promise.resolve(42)); @@ -103,9 +107,9 @@ describe(timeAndLogCountEventAsync, () => { expect(result).toBe(42); verify( - metricsAdapterMock.logDataManagerLoadEvent( + metricsAdapterMock.logDataManagerCountEvent( deepEqual({ - type: EntityMetricsLoadType.COUNT_SQL, + type: EntityMetricsCountType.COUNT_SQL, isInTransaction: false, entityClassName: 'TestEntity', duration: anyNumber(),