Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

#134 into [email protected] 👹 add 'oneOf' parameter into descriptor #181

Open
wants to merge 5 commits into
base: [email protected]
Choose a base branch
from

Conversation

MiaInturi
Copy link
Collaborator

No description provided.

describe('plainEntitySchema: checkMode exclude', () => {
test('Should return correct error path for descriptor (top and property level) without required value', () => {
const incorrectTopLevelDescriptorBodyEntities = {
test('Should return correct error path with descriptor schema checked before common record schema', () => {
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По сути прошлый тест как раз это и смотрел, но было прям неочевидно, что он проверял - сделал более явно, что тест проверяет, мол descriptor schema должна проходить валидацию раньше record schema

Comment on lines +11 to +18
export const extendedDiscriminatedUnion = <Discriminator extends string>(
discriminator: Discriminator,
options: [
ExtendedDiscriminatedUnionOption,
ExtendedDiscriminatedUnionOption,
...ExtendedDiscriminatedUnionOption[]
]
) =>
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По сути эта функция это просто адаптация этой функции из zod https://zod.dev/?id=discriminated-unions.
Т.е. так же принимается первым параметром название свойства, которое должно быть у проверяемого объекта и далее схемы, которые должны соответствовать каждому из возможных значений вышеупомянутого свойства - схемы это массив котрежей из 2 элементов, где первый элемент проверяет совпадение с выбранным свойством (discriminator), а второй элемент проверяет уже весь остальной объект (в случае, если первая схема была успешно провалидирована).
На самом деле супер просто все, это просто расширение обычного discriminatedUnion из zod, т.к. он в силу принципов своей работы вторым аргументом позволял передавать только массив z.object-ов, а это жесткое ограничение, которое по сути заставляло бы нас писать ту валидацию, от которой мы и хотели уйти с помощью zod.

Comment on lines +588 to +591
value: {
key1: 'value1',
key2: { nestedKey1: 'nestedValue1' }
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Из-за oneOf теперь массивы так не парсятся

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Подскажи подробней, а как раньше было. Было тип пройдись по всему массиву и посмотри каждый элемент и тут был был equal для 0 элемента ?

Но теперь у нас есть oneOf и если не указать его в явную, то он будет сверять массив типо

Но тут филосовский вопрос, oneOf по дефалту сейчас false, что наверное правильно

Comment on lines +98 to +106
if (
topLevelConvertedDescriptor.checkMode === 'exists' ||
topLevelConvertedDescriptor.checkMode === 'notExists'
) {
return resolveEntityValues({
checkMode: topLevelConvertedDescriptor.checkMode,
actualValue: graphQLInput.variables
});
}
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Нужно явно проверять checkMode-ы без descriptorValue для типизации

Comment on lines -39 to -49
export const CHECK_MODES = [
...CHECK_ACTUAL_VALUE_CHECK_MODES,
...COMPARE_WITH_DESCRIPTOR_VALUE_CHECK_MODES,
...CALCULATE_BY_DESCRIPTOR_VALUE_CHECK_MODES
] as const satisfies readonly CheckMode[];

export const PLAIN_ENTITY_CHECK_MODES = [
...CHECK_ACTUAL_VALUE_CHECK_MODES,
...COMPARE_WITH_DESCRIPTOR_ANY_VALUE_CHECK_MODES,
'function'
] as const satisfies readonly CheckMode[];
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Они просто не использовались нигде

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

По сути x instanceof RegExp выполняет ту же самую роль поэтому не вижу смысла в этой функции. Мб раньше TS автоматически не сужал тип, но сейчас все норм

Comment on lines +24 to +31
export type EntityDescriptor<
Check extends CheckMode = CheckMode,
Value = any
> = Check extends CheckActualValueCheckMode
? { checkMode: Check }
:
| { checkMode: Check; value: Value[]; oneOf: true }
| { checkMode: Check; value: Value; oneOf?: false };
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Теперь для CheckMode без descriptorValue типизация стала более явной

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Тут самые большие изменения, но основных 2:

  1. Раньше по сути из-за необычной логики массивов требовалось проверять 9 комбинаций: каждый из actual и descriptor value мог быть примитивом, массивом, объектом, таким образом 3х3 = 9. Теперь же для нас без разницы, массив это или объект, то есть комбинаций становится 4 = 2х2. Нам без разницы, т.к. определение логики, сравнивать ли массив целиком или же только один из элементов, забрал на себя oneOf.
  2. Теперь, когда функция 'resolveEntityValues' вызывается, то мы смотрим какое значение имеет oneOf. Если true, то просто идем по массиву descriptorValue и ищем хотя бы 1 совпадение, если же oneOf=false или не представлен, то сравниваем целиком

@MiaInturi MiaInturi self-assigned this Jun 25, 2024
@MiaInturi MiaInturi added the enhancement New feature or request label Jun 25, 2024
@MiaInturi MiaInturi linked an issue Jul 1, 2024 that may be closed by this pull request
debabin
debabin previously approved these changes Oct 25, 2024

return resolveEntityValues({
checkMode: topLevelConvertedDescriptor.checkMode,
actualValue,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

я бы поставил первым параметром в объекте

@@ -50,8 +50,7 @@ export const createRestRoutes = ({

const entries = Object.entries(entities) as Entries<Required<RestEntitiesByEntityName>>;
return entries.every(([entityName, entityDescriptorOrValue]) => {
const { checkMode, value: descriptorValue } =
convertToEntityDescriptor(entityDescriptorOrValue);
const topLevelConvertedDescriptor = convertToEntityDescriptor(entityDescriptorOrValue);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

const entityDescriptor = convertToEntityDescriptor(entityDescriptorOrValue);

а почему вот такой бы нейминг просто не поддержать, мне кажется что top level вообще не обязателен

const actualValue = Object.keys(request.body).length ? request.body : undefined;
return resolveEntityValues({
checkMode: 'equals',
actualValue,
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same про поставить выше

Comment on lines +102 to +106
const actualEntity = flatten<any, any>(request[entityName]);

// ✅ important: transform header keys to lower case because browsers send headers in lowercase
const actualValue =
actualEntity[entityName === 'headers' ? entityKey.toLowerCase() : entityKey];
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

// ✅ important: transform header keys to lower case because browsers send headers in lowercase
cosnt actualKey = entityName === 'headers' ? entityKey.toLowerCase() : entityKey
const actualValue = actualEntity[actualKey]

| ResolveEntityParamsWithEnabledOneOf
| ResolveEntityParamsWithDisabledOneOf;

export const resolveEntityValues = (params: ResolveEntityParams) => {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ResolveEntityValuesParams

Comment on lines +96 to +108
interface ResolveEntityParamsWithEnabledOneOf {
checkMode: Exclude<CheckMode, CheckActualValueCheckMode>;
actualValue: any;
descriptorValue: any[];
oneOf: true;
}

interface ResolveEntityParamsWithDisabledOneOf {
checkMode: Exclude<CheckMode, CheckActualValueCheckMode>;
actualValue: any;
descriptorValue: any;
oneOf?: false;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а разве нам нужно тут union, разве нам не пофиг если сделать вот так

interface ResolveEntityValuesParams {
checkMode: Exclude<CheckMode, CheckActualValueCheckMode>;
actualValue: any;
descriptorValue: any | any[];
oneOf?: boolean;
}

а уже снизу тут в коде один раз захоркодить as any[]

а то приходиться выше костылить true | false

Comment on lines +20 to +22
// ✅ important:
// recreate RegExp because 'g' flag can be cause of unexpected result
// this is about https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/RegExp/lastIndex#avoiding_side_effects
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

а точно ли стоит такое писать ? просто в коде уже есть такой кейс

@@ -40,141 +43,91 @@ const checkFunction: CheckFunction = (checkMode, actualValue, descriptorValue?):
throw new Error('Wrong checkMode');
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

мб еще добавим значение сюда check mode, ну тип wrong checmode ${checkmode}

Comment on lines +588 to +591
value: {
key1: 'value1',
key2: { nestedKey1: 'nestedValue1' }
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Подскажи подробней, а как раньше было. Было тип пройдись по всему массиву и посмотри каждый элемент и тут был был equal для 0 элемента ?

Но теперь у нас есть oneOf и если не указать его в явную, то он будет сверять массив типо

Но тут филосовский вопрос, oneOf по дефалту сейчас false, что наверное правильно

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
enhancement New feature or request [email protected] issues for [email protected]
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Add 'oneOf' parameter into descriptor
2 participants