Skip to content

Commit

Permalink
fix(qwik-city): correct validator failed type (QwikDev#5137)
Browse files Browse the repository at this point in the history
  • Loading branch information
wtlin1228 authored Sep 8, 2023
1 parent 5d7839c commit 10a5409
Show file tree
Hide file tree
Showing 4 changed files with 129 additions and 63 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ import type {
JSONValue,
LoadedRoute,
LoaderInternal,
FailReturn,
} from '../../runtime/src/types';
import { Cookie } from './cookie';
import { ErrorResponse } from './error-handler';
Expand Down Expand Up @@ -212,7 +213,7 @@ export function createRequestEvent(
return typeof returnData === 'function' ? returnData : () => returnData;
},

fail: <T extends Record<string, any>>(statusCode: number, data: T) => {
fail: <T extends Record<string, any>>(statusCode: number, data: T): FailReturn<T> => {
check();
status = statusCode;
headers.delete('Cache-Control');
Expand Down
4 changes: 2 additions & 2 deletions packages/qwik-city/runtime/src/api.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ export interface ActionConstructor {
<OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (data: GetValidatorType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: {
readonly id?: string;
readonly validation: [VALIDATOR, ...REST];
}): Action<StrictUnion<OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>> | FailOfRest<REST>>, GetValidatorType<VALIDATOR>, false>;
}): Action<StrictUnion<OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>> | FailReturn<FailOfRest<REST>>>, GetValidatorType<VALIDATOR>, false>;
// (undocumented)
<OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator>(actionQrl: (data: GetValidatorType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: {
readonly id?: string;
Expand All @@ -55,7 +55,7 @@ export interface ActionConstructor {
readonly validation: REST;
}): Action<StrictUnion<OBJ | FailReturn<FailOfRest<REST>>>>;
// (undocumented)
<OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (data: GetValidatorType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: VALIDATOR, ...rest: REST): Action<StrictUnion<OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>> | FailOfRest<REST>>, GetValidatorType<VALIDATOR>, false>;
<OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator, REST extends [DataValidator, ...DataValidator[]]>(actionQrl: (data: GetValidatorType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: VALIDATOR, ...rest: REST): Action<StrictUnion<OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>> | FailReturn<FailOfRest<REST>>>, GetValidatorType<VALIDATOR>, false>;
// (undocumented)
<OBJ extends Record<string, any> | void | null, VALIDATOR extends TypedDataValidator>(actionQrl: (data: GetValidatorType<VALIDATOR>, event: RequestEventAction) => ValueOrPromise<OBJ>, options: VALIDATOR): Action<StrictUnion<OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>>>, GetValidatorType<VALIDATOR>, false>;
// (undocumented)
Expand Down
16 changes: 12 additions & 4 deletions packages/qwik-city/runtime/src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -433,7 +433,9 @@ export interface ActionConstructor {
}
): Action<
StrictUnion<
OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>> | FailOfRest<REST>
| OBJ
| FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>>
| FailReturn<FailOfRest<REST>>
>,
GetValidatorType<VALIDATOR>,
false
Expand Down Expand Up @@ -478,7 +480,9 @@ export interface ActionConstructor {
...rest: REST
): Action<
StrictUnion<
OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>> | FailOfRest<REST>
| OBJ
| FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>>
| FailReturn<FailOfRest<REST>>
>,
GetValidatorType<VALIDATOR>,
false
Expand Down Expand Up @@ -531,7 +535,9 @@ export interface ActionConstructorQRL {
}
): Action<
StrictUnion<
OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>> | FailOfRest<REST>
| OBJ
| FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>>
| FailReturn<FailOfRest<REST>>
>,
GetValidatorType<VALIDATOR>,
false
Expand Down Expand Up @@ -574,7 +580,9 @@ export interface ActionConstructorQRL {
...rest: REST
): Action<
StrictUnion<
OBJ | FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>> | FailOfRest<REST>
| OBJ
| FailReturn<zod.typeToFlattenedError<GetValidatorType<VALIDATOR>>>
| FailReturn<FailOfRest<REST>>
>,
GetValidatorType<VALIDATOR>,
false
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,18 @@ import type {
RequestEventAction,
} from "packages/qwik-city/runtime/src/types";

type TypedDataValidatorError = z.typeToFlattenedError<{
category: "bird" | "dog" | "rat";
}>;

const typedDataValidator = zod$({
category: z.enum(["bird", "dog", "rat"]),
});

interface DataValidatorError {
message: string;
}

const dataValidator = validator$((ev) => {
if (ev.query.get("secret") === "123") {
return {
Expand All @@ -25,20 +33,28 @@ const dataValidator = validator$((ev) => {
success: false,
error: {
message: "Secret not found",
},
} as DataValidatorError,
};
});

interface ActionSuccessObject {
actionSuccess: string;
}

interface ActionFailedObject {
actionFail: string;
}

const actionQrl = (data: JSONObject, { fail }: RequestEventAction) => {
if (Math.random() > 0.5) {
return fail(500, {
actionFail: "secret",
});
} as ActionFailedObject);
}

return {
actionSuccess: "シマエナガ",
};
} as ActionSuccessObject;
};

export const useLoader = routeLoader$(() => {
Expand All @@ -64,20 +80,110 @@ export const useAction4 = routeAction$(
export const useAction5 = routeAction$(actionQrl, typedDataValidator);
export const useAction6 = routeAction$(actionQrl, dataValidator);
export const useAction7 = routeAction$(actionQrl);
export const useAction8 = routeAction$(() => true);
export const useAction9 = routeAction$(() => true, {
id: "route-action",
});
export const useAction8 = routeAction$(actionQrl, { id: "id-action-8" });

export default component$(() => {
const loader = useLoader();

// Use options object, use typed data validator, use data validator
const action1 = useAction1();
if (action1.value) {
if (action1.value.failed) {
action1.value satisfies { failed: true } & (
| TypedDataValidatorError
| DataValidatorError
| ActionFailedObject
);
} else {
action1.value satisfies ActionSuccessObject;
}
}

// Use options object, use typed data validator
const action2 = useAction2();
if (action2.value) {
if (action2.value.failed) {
action2.value satisfies { failed: true } & (
| TypedDataValidatorError
| ActionFailedObject
);
} else {
action2.value satisfies ActionSuccessObject;
}
}

// Use options object, use data validator
const action3 = useAction3();
if (action3.value) {
if (action3.value.failed) {
action3.value satisfies { failed: true } & (
| DataValidatorError
| ActionFailedObject
);
} else {
action3.value satisfies ActionSuccessObject;
}
}

// Use typed data validator, use data validator
const action4 = useAction4();
if (action4.value) {
if (action4.value.failed) {
action4.value satisfies { failed: true } & (
| TypedDataValidatorError
| DataValidatorError
| ActionFailedObject
);
} else {
action4.value satisfies ActionSuccessObject;
}
}

// Use typed data validator
const action5 = useAction5();
if (action5.value) {
if (action5.value.failed) {
action5.value satisfies { failed: true } & (
| TypedDataValidatorError
| ActionFailedObject
);
} else {
action5.value satisfies ActionSuccessObject;
}
}

// Use data validator
const action6 = useAction6();
if (action6.value) {
if (action6.value.failed) {
action6.value satisfies { failed: true } & (
| DataValidatorError
| ActionFailedObject
);
} else {
action6.value satisfies ActionSuccessObject;
}
}

// No validators
const action7 = useAction7();
if (action7.value) {
if (action7.value.failed) {
action7.value satisfies { failed: true } & ActionFailedObject;
} else {
action7.value satisfies ActionSuccessObject;
}
}

// No validators, with action id
const action8 = useAction7();
if (action8.value) {
if (action8.value.failed) {
action8.value satisfies { failed: true } & ActionFailedObject;
} else {
action8.value satisfies ActionSuccessObject;
}
}

return (
<div>
Expand All @@ -93,55 +199,6 @@ export default component$(() => {
<p>{loader.value.stuff}</p>
</div>
)}
<div>
<h2>
Use options object, use typed data validator, use data validator
</h2>
{action1.value?.actionSuccess}
{action1.value?.actionFail}
{action1.value?.message}
{action1.value?.fieldErrors?.category}
{action1.value?.formErrors}
</div>
<div>
<h2>Use options object, use typed data validator</h2>
{action2.value?.actionSuccess}
{action2.value?.actionFail}
{action2.value?.fieldErrors?.category}
{action2.value?.formErrors}
</div>
<div>
<h2>Use options object, use data validator</h2>
{action3.value?.actionSuccess}
{action3.value?.actionFail}
{action3.value?.message}
</div>
<div>
<h2>Use typed data validator, use data validator</h2>
{action4.value?.actionSuccess}
{action4.value?.actionFail}
{action4.value?.message}
{action4.value?.fieldErrors?.category}
{action4.value?.formErrors}
</div>
<div>
<h2>Use typed data validator</h2>
{action5.value?.actionSuccess}
{action5.value?.actionFail}
{action5.value?.fieldErrors?.category}
{action5.value?.formErrors}
</div>
<div>
<h2>Use data validator</h2>
{action6.value?.actionSuccess}
{action6.value?.actionFail}
{action6.value?.message}
</div>
<div>
<h2>No validators</h2>
{action7.value?.actionSuccess}
{action7.value?.actionFail}
</div>
</div>
);
});

0 comments on commit 10a5409

Please sign in to comment.