Skip to content

get item by partition key returns error only inside lambda #412

Description

@orr-levinger

Describe the bug
This bug happens to me only when running in a lambda. When running locally this doesnt happen.
here are my libs versions:

dynamo-easy version: 8.0.0-next.3
aws v3 dynamo version: 3.445.0
Node.js Version: v18.18.0

I have a model that has a string field called status:

import {
Model,
PartitionKey,
SortKey,
LSISortKey,
GSIPartitionKey,
GSISortKey,
Property,
fromDb as fromDBB,
PropertyMetadata,
metadataForModel,
Attributes,
ModelConstructor,
} from '@shiftcoders/dynamo-easy';
import { BaseDynamoModel } from '@models/base-dynamo-model';
import { MATCH_TABLE } from '@static/consts';
import { MatchGraphQLType, Quality, RejectReason } from '@type/Match';
import type { MatchStatus } from '@type/Match';
import { Avatar, Gender } from '@type/User';
import type { MapperForType, StringAttribute } from '@shiftcoders/dynamo-easy';
@Model({ tableName: MATCH_TABLE })
export class MatchModel extends BaseDynamoModel implements MatchGraphQLType {
static readonly byUniqueId = 'byUniqueId';
static readonly byMatchIdUserId = 'byMatchId-userId';
static readonly byUserIdStatus = 'byUserId-status';
static readonly byUserIdActive = 'byUserId-active';
static readonly byConversationId = 'byConversationId';
@GSIPartitionKey(MatchModel.byUniqueId)
id: string;
@PartitionKey()
@GSISortKey(MatchModel.byMatchIdUserId)
userId: string;
@SortKey()
@GSIPartitionKey(MatchModel.byMatchIdUserId)
matchId: string;
@LSISortKey(MatchModel.byUserIdStatus)
@Property({ mapper: statusMapper })
**status: MatchStatus;**
@LSISortKey(MatchModel.byUserIdActive)
active: 'true' | 'false';
}
export type MatchStatus =
| 'pending'
| 'invited'
| 'accepted'
| 'failure'
| 'success';

here is the DDB table definition:

 MatchesTable:
DeletionPolicy: Delete
Type: "AWS::DynamoDB::Table"
Properties:
Tags:
- Key: env
Value: ${sls:stage}
AttributeDefinitions:
- AttributeName: id
AttributeType: S
- AttributeName: status
AttributeType: S
- AttributeName: userId
AttributeType: S
- AttributeName: matchId
AttributeType: S
- AttributeName: active
AttributeType: S
KeySchema:
- AttributeName: userId
KeyType: HASH
- AttributeName: matchId
KeyType: RANGE
LocalSecondaryIndexes:
- IndexName: byUserId-status
KeySchema:
- AttributeName: userId
KeyType: HASH
- AttributeName: status
KeyType: RANGE
Projection:
ProjectionType: ALL
- IndexName: byUserId-active
KeySchema:
- AttributeName: userId
KeyType: HASH
- AttributeName: active
KeyType: RANGE
Projection:
ProjectionType: ALL
GlobalSecondaryIndexes:
- IndexName: byUniqueId
KeySchema:
- AttributeName: id
KeyType: HASH
Projection:
ProjectionType: ALL
- IndexName: byMatchId-userId
KeySchema:
- AttributeName: matchId
KeyType: HASH
- AttributeName: userId
KeyType: RANGE
Projection:
ProjectionType: ALL
BillingMode: PAY_PER_REQUEST
TableName: ${self:custom.base}-matches
StreamSpecification:
StreamViewType: NEW_AND_OLD_IMAGES

here is my table item instance:

 "userId": {
"S": "f43276be-3a2c-4888-b2b9-9ae23471094c"
},
"matchId": {
"S": "4913f5ad-198e-4fcd-b929-2f3e996ce6ce"
},
"active": {
"S": "true"
},
"id": {
"S": "f43276be-3a2c-4888-b2b9-9ae23471094c_4913f5ad-198e-4fcd-b929-2f3e996ce6ce"
},
"status": {
"S": "invited"
}
}

this is the query i run:

 async getMatchById(id: string) {
return this.query().index(MatchModel.byUniqueId).wherePartitionKey(id).execSingle();
}

only when this code runs inside lambda i get the error:
{
"errorType": "Error",
"errorMessage": "could not resolve the dynamo db type for attribute value invited",
"stack": [
"Error: could not resolve the dynamo db type for attribute value invited",
" at typeOfFromDb (/opt/nodejs/node_modules/@shiftcoders/dynamo-easy/src/mapper/util.ts:231:9)",
" at fromDbOne (/opt/nodejs/node_modules/@shiftcoders/dynamo-easy/src/mapper/mapper.ts:291:64)",
" at /opt/nodejs/node_modules/@shiftcoders/dynamo-easy/src/mapper/mapper.ts:274:20",
" at Array.forEach ()",
" at fromDb (/opt/nodejs/node_modules/@shiftcoders/dynamo-easy/src/mapper/mapper.ts:244:44)",
" at Object.fromDb (/var/task/src/functions/events/webpack:/blind-chat-backend/src/models/match-model.ts:75:14)",
" at /opt/nodejs/node_modules/@shiftcoders/dynamo-easy/src/mapper/mapper.ts:268:50",
" at Array.forEach ()",
" at fromDb (/opt/nodejs/node_modules/@shiftcoders/dynamo-easy/src/mapper/mapper.ts:244:44)",
" at /opt/nodejs/node_modules/@shiftcoders/dynamo-easy/src/dynamo/request/read-many.request.ts:222:63",
" at Array.map ()",
" at ReadManyRequest.mapFromDb (/opt/nodejs/node_modules/@shiftcoders/dynamo-easy/src/dynamo/request/read-many.request.ts:222:43)",
" at processTicksAndRejections (node:internal/process/task_queues:95:5)",
" at Runtime.v [as handler] (/var/task/src/functions/events/webpack:/blind-chat-backend/src/functions/events/get-match.ts:16:3)"
]
}

when creating a property mapper:

export const statusMapper: MapperForType<string, StringAttribute> = {
fromDb: (attributeValue: any): any => {
console.log('fromDb orr', attributeValue);
return attributeValue.S;
},
toDb: (modelValue: any): any => {
console.log('toDb orr', modelValue);
try {
return modelValue;
} catch (e) {
console.log('error', e);
return modelValue;
}
},
};

that does nothing special just what dynamo-easy was supposed to do it works..
and prints:
fromDb orr { S: 'invited' }

also noticed the wrong mapper is chosen:
INFO dynamo.mapper.mapper (Object): map toDb {"item":"Conscientiousness"}

image

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions