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

RangeError: Maximum call stack size exceeded #922

Open
Mario2280 opened this issue Jun 18, 2024 · 12 comments
Open

RangeError: Maximum call stack size exceeded #922

Mario2280 opened this issue Jun 18, 2024 · 12 comments
Assignees
Labels
duplicate This issue or pull request already exists good first issue Good for newcomers question Further information is requested wontfix This will not be worked on

Comments

@Mario2280
Copy link

Mario2280 commented Jun 18, 2024

Feature Request

Fix all funtions like validate equals and creating types
for highly nested objects.
Or if I didn't read the documentation well, how can I solve this problem using your wonderful library

  • A description of the problem you're trying to solve.
    Hi I wanted to create a custom PaginationBody type. I created this interface
interface PaginationQueryDto<
  EntityCreateDto,
  EntityWhereInputType,
> {
  /**
   * Limit of items to return
   */
  limit: number & tags.Minimum<1> & tags.Type<'uint32'> & tags.Default<10>;
  /**
   * Offset for items to return
   */
  offset: number & tags.Minimum<0> & tags.Type<'uint32'> & tags.Default<0>;
  /**
   * Column to sort by
   */
  sortingColumn?: null | keyof EntityCreateDto;
  /**
   * Sort order
   */
  sort: SortType & tags.Default<SortType.ASC>;
  /**
   * Text to search across fields
   */
  searchString?: null | string;

  where: EntityWhereInputType;

}

And i use it like this

export type PaymentPaginationType = PaginationQueryDto<
  PaymentCreateDto,
  Prisma.PaymentWhereInput,
  Prisma.PaymentSelect
>;
export const equalPaymentFindAllValidator = createValidateEquals<PaymentPaginationType>();

The problem is that prisma generates a looping dependency Prisma.PaymentWhereInput:

export type PaymentWhereInput = {
    AND?: PaymentWhereInput | PaymentWhereInput[]
    OR?: PaymentWhereInput[]
    NOT?: PaymentWhereInput | PaymentWhereInput[]
    id?: StringFilter<"Payment"> | string
    payment_source_type?: EnumPaymentTypeFilter<"Payment"> | $Enums.PaymentType
    shop_id?: StringFilter<"Payment"> | string
    createdAt?: DateTimeFilter<"Payment"> | Date | string
    shop?: XOR<ShopRelationFilter, ShopWhereInput>
  }

This code throw error

const randomWhere = typia.random<PaymentPaginationType>();
console.log(randomWhere);
RangeError: Maximum call stack size exceeded
    at $ro107 (E:\Work\PR1\tapply-be\test.is-working.ts:3952:11)
    at E:\Work\PR1\tapply-be\test.is-working.ts:3043:19
    at $ro91 (E:\Work\PR1\tapply-be\test.is-working.ts:3050:11) 
    at E:\Work\PR1\tapply-be\test.is-working.ts:2993:19
    at $ro90 (E:\Work\PR1\tapply-be\test.is-working.ts:2994:11) 
    at E:\Work\PR1\tapply-be\test.is-working.ts:545:19
    at $ro14 (E:\Work\PR1\tapply-be\test.is-working.ts:546:11)  
    at E:\Work\PR1\tapply-be\test.is-working.ts:1322:19
    at $ro35 (E:\Work\PR1\tapply-be\test.is-working.ts:1323:11) 
    at E:\Work\PR1\tapply-be\test.is-working.ts:978:19
  • An overview of the suggested solution.
    I used one package when I wrote an application using graphql and the type generation library (https://github.com/unlight/prisma-nestjs-graphql). Validation was generated there and there was no problem with large nesting.
    PS

I also noticed that if an object is highly nested and there is not necessarily a cyclic dependency, it generates an error (Error: Error on typia.equals(): no transform has been configured. Read and follow https://typia.io/docs/setup please). I followed all the installation steps, but the problem was not solved. This is most likely a separate issue, but perhaps they are related.

@samchon
Copy link
Owner

samchon commented Jun 19, 2024

Have you tried to run the tsc command?

@samchon samchon self-assigned this Jun 19, 2024
@Mario2280
Copy link
Author

Have you tried to run the tsc command?

No, I tried to run it through ts-node. I'll try it via tsc and post the results.

@Mario2280
Copy link
Author

Mario2280 commented Jun 19, 2024

@samchon Here is my router that does not work as originally intended. You were right, I really removed all the errors and tried to build the project. The assembly was successful. But swagger:build showed that I was using incorrect types for validation, namely nested objects and the union type:

@TypedRoute.Get()
  async findAll(
    @Query({ validate: equalPaymentFindAllValidator, type: 'validate' }) 
    paginationQuery: PaymentPaginationType,
    @Res() res: Response,
  ): Promise<Response> {
    try {
      const payments = await this.paymentService.findMany(paginationQuery);
      return res.status(HttpStatus.OK).json(payments);
    } catch (error) {
      return res
        .status(HttpStatus.BAD_REQUEST)
        .json({ message: error.message });
    }
  }

npm run swagger:build:

src\modules\promo-code\promo-code.controller.ts:42:4:PromoCodeController.findAll:paginationQuery - error TS(@nestia/sdk): invalid type detected.

  - union type is not allowed.
  - nested object type is not allowed.

In this regard, I would like to ask 2 questions. These 2 restrictions make it impossible to validate most queries because most often there are nested objects and unions.

  1. Is it possible to somehow solve this problem, maybe I somehow misunderstood the documentation and did not use all the capabilities of your wonderful library, or is it still impossible to do?

  2. If this cannot be done and the architecture of your library is based on these rules and changing them is impossible due to breaking changes, then how can you implement such things as I tried to do, because I think that this is a fairly popular request for validation of nested objects and unions.

I'd really like to fix this because I was so impressed with your library that I implemented it into my work project. 🙏🙏🙏

UDP I tried replacing TypedQuery with TypedBody cause it doesn't have these restrictions., but as expected I got the same error:

Analyzing reflections
  - controllers: #17
  - paths: #94
  - routes: #94
Analyzing source codes
Generating Swagger Documents
RangeError: Maximum call stack size exceeded
    at assign (<anonymous>)
    at node_modules\typia\src\programmers\internal\application_v31_schema.ts:32:7 
    at node_modules\typia\src\programmers\internal\application_escaped.ts:14:44   
    at node_modules\typia\src\programmers\internal\application_v31_schema.ts:51:73
    at node_modules\typia\src\programmers\internal\application_array.ts:19:16     
    at node_modules\typia\src\programmers\internal\application_v31_schema.ts:71:71
    at node_modules\typia\src\programmers\internal\application_array.ts:19:16     
    at node_modules\typia\src\programmers\internal\application_v31_schema.ts:71:71
    at node_modules\typia\src\programmers\internal\application_array.ts:19:16     
    at node_modules\typia\src\programmers\internal\application_v31_schema.ts:71:71

As I said earlier, validation breaks down when analyzing looped links(
I think there is a mistake in this place:

export type PaymentPaginationType = PaginationQueryDto<
  PaymentCreateDto,
  Omit<Prisma.PaymentWhereInput, 'AND' | 'OR' | 'NOT' | 'shop'>         <--It’s strange that I even decided to exclude 
                                                                properties that create loopholes, but it didn’t help
>;


  export type PaymentWhereInput = { <--------------------many circular dependencies
    AND?: PaymentWhereInput | PaymentWhereInput[]
    OR?: PaymentWhereInput[]
    NOT?: PaymentWhereInput | PaymentWhereInput[]
    id?: StringFilter<"Payment"> | string
    payment_source_type?: EnumPaymentTypeFilter<"Payment"> | $Enums.PaymentType
    shop_id?: StringFilter<"Payment"> | string
    createdAt?: DateTimeFilter<"Payment"> | Date | string
    shop?: XOR<ShopRelationFilter, ShopWhereInput>
  }

Is there some way to fix this in your library?

@samchon samchon added the duplicate This issue or pull request already exists label Jun 20, 2024
@samchon
Copy link
Owner

samchon commented Jun 20, 2024

  1. Query parameter cannot be union type. Considering the characteristics of url query parameters, union type is equivalent with any like type.
  2. Nested object type is not supported either. No way to represent nested object type in the url query parameters. If you write x.y.z=3 text, it means not nested object construction statement, but just `query["x.y.z"] = "3".
  3. Therefore, if you want both union and nested type supporting, you have to use request body instead

@samchon samchon added good first issue Good for newcomers question Further information is requested labels Jun 20, 2024
samchon added a commit that referenced this issue Jun 20, 2024
Fix #922: change no transform configuration error message.
@Mario2280
Copy link
Author

Mario2280 commented Jun 20, 2024

@samchon Yes, that's what I understood, but you probably misunderstood the last part of my message. I tried using TypedBody and encountered a stack overflow due to a looped reference. That is, my problem is not solved. Is there a plan to fix this in the future or could you tell me where I could look and fix it in your code myself? I just need to write a crutch that would limit looped repetitions to, for example, 3 times.

@samchon
Copy link
Owner

samchon commented Jun 20, 2024

Can you give me a reproducible repo with the @TypedBody() decorated recursive type?

@samchon samchon reopened this Jun 20, 2024
@Mario2280
Copy link
Author

@samchon Yes give me a couple of minutes

@Mario2280
Copy link
Author

@samchon I tried to reproduce this task using route 1 as an example. But something strange happens (it works). When I write the same thing in a working project, this error appears with recursion. I'll try to fix my working repository exactly like in this repository (https://github.com/Mario2280/Nestia_test_recursion) and post the results to see if the problem is fixed

@samchon
Copy link
Owner

samchon commented Jun 20, 2024

If you case is belonged to this issue (samchon/typia#1108), it may be fixed by updating the typia version.

@Mario2280
Copy link
Author

Mario2280 commented Jun 20, 2024

@samchon Will this fix work for types and for interfaces? Because I can’t change it if prisma generate will create a bunch of types (and interfaces will be needed)

UDP I did everything 1 in 1 in my working project, there in the test project the link to which I sent above. This is the error I get:

src/modules/payment/payment.controller.ts:48:5 - error TS(@nestia.core.TypedBody): unsupported type detected

- { id: string | RecommendationProductItemIdRecommendedItemIdCompoundUniqueInput; productItemId_recommendedItemId: string | RecommendationProductItemIdRecommendedItemIdCompoundUniqueInput; } & { ...; }.id: Prisma.RecommendationProductItemIdRecommendedItemIdCompoundUniqueInput & string
  - nonsensible intersection

- { id: string | RecommendationProductItemIdRecommendedItemIdCompoundUniqueInput; productItemId_recommendedItemId: string | RecommendationProductItemIdRecommendedItemIdCompoundUniqueInput; } & { ...; }.productItemId_recommendedItemId: string & Prisma.RecommendationProductItemIdRecommendedItemIdCompoundUniqueInput
  - nonsensible intersection

48     @Body()
       ~~~~~~~
49     paginationQuery: PaymentPaginationType,
   ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

Here is a short sequence of how these tables are connected. I tried to recreate the same thing in a test project, but I couldn’t find the source of the error (I had an assumption that it had something to do with the many-to-many relationship in the database):

model Payment{
  id          String   @id @default(uuid())
  shopId      String
  shop        Shop     @relation(fields: [shopId], references: [id])
}
model Shop {
  id               String             @id @default(uuid())
  Recommendation   Recommendation[]
}
model Recommendation {
  id                String      @id @default(uuid())
  productItemId     String
  recommendedItemId String
  productItem       ProductItem @relation("ProductRecommendations", fields: [productItemId], references: [id], onDelete: Cascade)
  recommendedItem   ProductItem @relation("RecommendedProductItems", fields: [recommendedItemId], references: [id], onDelete: Cascade)
  shopId            String
  shop              Shop        @relation(fields: [shopId], references: [id])

  @@unique([productItemId, recommendedItemId])
}
model ProductItem {
  id               String           @id @default(uuid())
  recommendations  Recommendation[] @relation("ProductRecommendations")
  recommendedBy    Recommendation[] @relation("RecommendedProductItems")
  shopId           String
  shop             Shop             @relation(fields: [shopId], references: [id])
}

I tried for several hours to figure out what the error was, but I couldn’t find it.

@samchon
Copy link
Owner

samchon commented Jun 21, 2024

The nonsensible intersection message comes by typia when contradictory type comes. In your reply, I found the reason why. Prisma.RecommendationProductItemIdRecommendedItemIdCompoundUniqueInput & string type is the case. It is the tremendous ridiculuous type because string and object type can't be intersected.

In such reason, I'm not using Prisma generated types as DTO directly. In the actual service, DTO cannot be 1:1 correspondent with ORM schemes, because the DTO has been composed by combinating DB entities complicately.

@samchon samchon added the wontfix This will not be worked on label Jun 21, 2024
@Mario2280
Copy link
Author

Mario2280 commented Jun 21, 2024

@samchon Can I put a stub specifically for this type to avoid errors and complete the generation of js code for validation without errors? This is very important to me because when I saw your library, the first thing I thought was to do something similar using Prisma types and try to implement it into a working project to validate complex queries with select where include commands(like this libs but it works with https://github.com/unlight/prisma-nestjs-graphql). I most likely understand that pure types are built into the core of your library and this rule is difficult to change, but imagine if it were possible to handle such problematic situations, this would give your library a very powerful feature. Do you have any ideas on how to get around this problem? Or there is no way out and I will have to register all these interfaces manually and eliminate this error (this is a lot of work, I would not like to do this...

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
duplicate This issue or pull request already exists good first issue Good for newcomers question Further information is requested wontfix This will not be worked on
Projects
No open projects
Status: To do
Development

No branches or pull requests

2 participants