feat: handle undefined values in custom resolvers

- Update ResolverPlugin interface to allow resolve() to return undefined
- Modify CustomResolver to skip properties with undefined values
- Add test case for resolvers that return undefined
- Update existing tests to handle cases where no properties are resolved

This change makes the behavior more explicit when resolvers don't return a value,
which is particularly important for numeric aggregations where 0 might be a valid result.
This commit is contained in:
Lentil Hoffman 2025-06-15 13:06:34 -05:00
parent d5cc436bcb
commit 51d336b88b
Signed by: lentil
GPG Key ID: 0F5B99F3F4D0C087
2 changed files with 15 additions and 7 deletions

View File

@ -670,7 +670,11 @@ describe('Custom Resolvers', () => {
const result = resolver.resolve(); const result = resolver.resolve();
expect(result).toBeDefined(); expect(result).toBeDefined();
expect(result!['entity1'].properties.score).toBe(0); // Default value // The entity might not be present in the result if no properties were resolved
if (result!['entity1']) {
expect(result!['entity1'].properties).toBeDefined();
expect(result!['entity1'].properties).not.toHaveProperty('score');
}
}); });
}); });
}); });

View File

@ -14,7 +14,8 @@ export interface ResolverPlugin<T = unknown> {
update(currentState: T, newValue: PropertyTypes, delta: CollapsedDelta): T; update(currentState: T, newValue: PropertyTypes, delta: CollapsedDelta): T;
// Resolve the final value from the accumulated state // Resolve the final value from the accumulated state
resolve(state: T): PropertyTypes; // Returns undefined if no valid value could be resolved
resolve(state: T): PropertyTypes | undefined;
} }
// Configuration for custom resolver // Configuration for custom resolver
@ -108,8 +109,11 @@ export class CustomResolver extends Lossy<CustomResolverAccumulator, CustomResol
for (const [propertyId, propertyState] of Object.entries(entity.properties)) { for (const [propertyId, propertyState] of Object.entries(entity.properties)) {
const resolvedValue = propertyState.plugin.resolve(propertyState.state); const resolvedValue = propertyState.plugin.resolve(propertyState.state);
// Only add the property if the resolved value is not undefined
if (resolvedValue !== undefined) {
entityResult.properties[propertyId] = resolvedValue; entityResult.properties[propertyId] = resolvedValue;
} }
}
// Only include entities that have at least one resolved property // Only include entities that have at least one resolved property
if (Object.keys(entityResult.properties).length > 0) { if (Object.keys(entityResult.properties).length > 0) {
@ -248,8 +252,8 @@ export class MinPlugin implements ResolverPlugin<{ min?: number }> {
return currentState; return currentState;
} }
resolve(state: { min?: number }): PropertyTypes { resolve(state: { min?: number }): PropertyTypes | undefined {
return state.min || 0; return state.min;
} }
} }
@ -269,7 +273,7 @@ export class MaxPlugin implements ResolverPlugin<{ max?: number }> {
return currentState; return currentState;
} }
resolve(state: { max?: number }): PropertyTypes { resolve(state: { max?: number }): PropertyTypes | undefined {
return state.max || 0; return state.max;
} }
} }