sam-goodwin / typesafe-dynamodb

TypeSafe type definitions for the AWS DynamoDB API
Apache License 2.0
205 stars 11 forks source link

TS2589: Type instantiation is excessively deep and possibly infinite. #29

Closed snarky-puppy closed 2 years ago

snarky-puppy commented 2 years ago

Good morning!

I'm trying to update a large map. In other use cases the validation is working perfectly, but after we add about 10-15 fields, we start getting the error above.

Example code:


    .update({
      TableName: "",
      Key: {
        PK: `USER#${userId}`,
        SK: `ORDER#${orderId}`,
      },
      UpdateExpression: `SET MyMapName.myLongFieldNameA = :myLongFieldValueA, 
                             MyMapName.myLongFieldNameB = :myLongFieldValueB,
                             MyMapName.myLongFieldNameC = :myLongFieldValueC,
                             MyMapName.myLongFieldNameD = :myLongFieldValueD,
                             MyMapName.myLongFieldNameE = :myLongFieldValueE,
                             MyMapName.myLongFieldNameF = :myLongFieldValueF,
                             MyMapName.myLongFieldNameG = :myLongFieldValueG,
                             MyMapName.myLongFieldNameG = :myLongFieldValueH,
                             MyMapName.myLongFieldNameG = :myLongFieldValueI,
                             MyMapName.myLongFieldNameG = :myLongFieldValueJ,
                             MyMapName.myLongFieldNameG = :myLongFieldValueK,
                             MyMapName.myLongFieldNameG = :myLongFieldValueL,
                             MyMapName.myLongFieldNameG = :myLongFieldValueM,
                             MyMapName.myLongFieldNameG = :myLongFieldValueN,
                          `,
        ExpressionAttributeValues: {
          ':x': 1,
            ':myLongFieldValueA': 1,
            ':myLongFieldValueB': 1,
            ':myLongFieldValueC': 1,
            ':myLongFieldValueD': 1,
            ':myLongFieldValueE': 1,
            ':myLongFieldValueF': 1,
            ':myLongFieldValueG': 1,
            ':myLongFieldValueH': 1,
            ':myLongFieldValueI': 1,
            ':myLongFieldValueJ': 1,
            ':myLongFieldValueK': 1,
            ':myLongFieldValueL': 1,
            ':myLongFieldValueM': 1,
            ':myLongFieldValueN': 1,
        },
      ReturnValues: "NONE",
    })
    .promise();```

Any suggestions or workarounds appreciated!

TIA
sam-goodwin commented 2 years ago

Dang, this one might be tricky to workaround because of how typesafe-dynamodb uses recursive types to parse the UpdateExpression. At a certain point, the string length is too long, requiring >50 depth (TS's hard-coded maximum). The only way to solve this that I can think of is to try and optimize the code that parses the string:

https://github.com/sam-goodwin/typesafe-dynamodb/blob/d72c099c25aa28600b8d84c72453a5bee1815c6b/src/expression-attributes.ts#L31-L79

Some workaround ideas:

  1. slap a // @ts-ignore on top and skip the checking - not ideal, at all
    // @ts-ignore
    UpdateExpression: `SET MyMapName.myLongFieldNameA = :myLongFieldValueA, 
  2. Maybe use a variable for the MyMapName and myLongFieldNameA to shorten the UpdateExpression string. The string length will affect the depth because each character is consumed recursively.
    UpdateExpression: `SET #m.#n1 = :v1`
    ExpressionAttributeNames: {
    "#m": "MyMapName",
    "#n1": "myLongFieldNameA"
    }
  3. Minimize the white-space in the string, each character contributes to depth (as far as I know).

I hope these workarounds can unblock you. I will take a look and see if there are any optimizations I can do.

sam-goodwin commented 2 years ago

Had a brainwave and figured out a way to extend the limit by splitting the update expression by , and processing each string separately. The 50-max depth limit will now only apply to a single expression. I tested with your example and it now compiles - i even found an error in it ;)

https://github.com/sam-goodwin/typesafe-dynamodb/pull/30

sam-goodwin commented 2 years ago

Fixed in 0.1.8.

snarky-puppy commented 2 years ago

Awesome, thanks @sam-goodwin ! Learning a lot from your code :-)