-
Notifications
You must be signed in to change notification settings - Fork 2.2k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
fix: fixes #3692 - simple discriminator now bypasses isValid() calls …
…in getMatchingOption and getClosestMatchingOption for improved performance (#3845) * fix: fixes #3692 - simple discriminator now bypasses isValid() calls in getMatchingOption and getClosestMatchingOption.ts for improved performance * chore: update changelog * docs: add jsdoc to getOptionMatchingSimpleDiscriminator * test: add missing test for getFirstMatchingOption non-trivial discriminator
- Loading branch information
1 parent
1576c27
commit 208b148
Showing
8 changed files
with
298 additions
and
93 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
46 changes: 46 additions & 0 deletions
46
packages/utils/src/getOptionMatchingSimpleDiscriminator.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
import get from 'lodash/get'; | ||
import { PROPERTIES_KEY } from './constants'; | ||
import { RJSFSchema, StrictRJSFSchema } from './types'; | ||
|
||
/** Compares the value of `discriminatorField` within `formData` against the value of `discriminatorField` within schema for each `option`. | ||
* Returns index of first `option` whose discriminator matches formData. Returns `undefined` if there is no match. | ||
* This function does not work with discriminators of `"type": "object"` and `"type": "array"` | ||
* | ||
* @param formData - The current formData, if any, used to figure out a match | ||
* @param options - The list of options to find a matching options from | ||
* @param [discriminatorField] - The optional name of the field within the options object whose value is used to | ||
* determine which option is selected | ||
* @returns - The index of the matched option or undefined if there is no match | ||
*/ | ||
export default function getOptionMatchingSimpleDiscriminator<T = any, S extends StrictRJSFSchema = RJSFSchema>( | ||
formData: T | undefined, | ||
options: S[], | ||
discriminatorField?: string | ||
): number | undefined { | ||
if (formData && discriminatorField) { | ||
const value = get(formData, discriminatorField); | ||
|
||
if (value === undefined) { | ||
return; | ||
} | ||
|
||
for (let i = 0; i < options.length; i++) { | ||
const option = options[i]; | ||
const discriminator = get(option, [PROPERTIES_KEY, discriminatorField], {}); | ||
|
||
if (discriminator.type === 'object' || discriminator.type === 'array') { | ||
continue; | ||
} | ||
|
||
if (discriminator.const === value) { | ||
return i; | ||
} | ||
|
||
if (discriminator.enum?.includes(value)) { | ||
return i; | ||
} | ||
} | ||
} | ||
|
||
return; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
81 changes: 81 additions & 0 deletions
81
packages/utils/test/getOptionMatchingSimpleDiscriminator.test.ts
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,81 @@ | ||
import getOptionMatchingSimpleDiscriminator from '../src/getOptionMatchingSimpleDiscriminator'; | ||
|
||
describe('getOptionMatchingSimpleDiscriminator()', () => { | ||
describe('returns undefined if no option matches discriminator', () => { | ||
test('no options with no data', () => { | ||
expect(getOptionMatchingSimpleDiscriminator({}, [], 'id')).toEqual(undefined); | ||
}); | ||
|
||
test('no options with data', () => { | ||
expect(getOptionMatchingSimpleDiscriminator({ foo: 'foo' }, [], 'id')).toEqual(undefined); | ||
}); | ||
|
||
test('options with no data', () => { | ||
expect( | ||
getOptionMatchingSimpleDiscriminator({}, [{ type: 'object', properties: { foo: { const: 'foo' } } }], 'id') | ||
).toEqual(undefined); | ||
}); | ||
|
||
test('matching property, but no discriminatorField', () => { | ||
expect( | ||
getOptionMatchingSimpleDiscriminator({ foo: 'foo' }, [ | ||
{ type: 'object', properties: { foo: { const: 'foo' } } }, | ||
]) | ||
).toEqual(undefined); | ||
}); | ||
|
||
test('matching property different from discriminatorField', () => { | ||
expect( | ||
getOptionMatchingSimpleDiscriminator( | ||
{ foo: 'foo' }, | ||
[{ type: 'object', properties: { foo: { const: 'foo' } } }], | ||
'bar' | ||
) | ||
).toEqual(undefined); | ||
}); | ||
}); | ||
|
||
describe('returns option index if option matches discriminator', () => { | ||
test('const discriminator', () => { | ||
expect( | ||
getOptionMatchingSimpleDiscriminator( | ||
{ foo: 'foo' }, | ||
[{}, { type: 'object', properties: { foo: { const: 'foo' } } }], | ||
'foo' | ||
) | ||
).toEqual(1); | ||
}); | ||
|
||
test('enum discriminator', () => { | ||
expect( | ||
getOptionMatchingSimpleDiscriminator( | ||
{ foo: 'foo' }, | ||
[{}, { type: 'object', properties: { foo: { enum: ['bar', 'foo'] } } }], | ||
'foo' | ||
) | ||
).toEqual(1); | ||
}); | ||
}); | ||
|
||
describe('unsupported (non-simple) discriminator returns undefined', () => { | ||
test('object discriminator', () => { | ||
expect( | ||
getOptionMatchingSimpleDiscriminator( | ||
{ foo: 'foo' }, | ||
[{}, { type: 'object', properties: { foo: { type: 'object' } } }], | ||
'foo' | ||
) | ||
).toEqual(undefined); | ||
}); | ||
|
||
test('array discriminator', () => { | ||
expect( | ||
getOptionMatchingSimpleDiscriminator( | ||
{ foo: 'foo' }, | ||
[{}, { type: 'object', properties: { foo: { type: 'array' } } }], | ||
'foo' | ||
) | ||
).toEqual(undefined); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters