Differences from Dynamo

Differences from Dynamo

Tynamo does not have to list every argument name used in an expression. This is because properties in Value Item (beginning with :) or entity properties (beginning with # ) are automatically written down. Consider the following expression.

{
    conditionalExpressions : "attribute_not_exists(#id) and :a < :b"
}

The above expression requires one entity property and two value property. Thus, Tynamo infers the following objects:

{
    ExpressionAttributeNames : {
        "#id" : "id"
    },
    ExpressionAttributeValues : {
        ":a" : { N|S|B : "?"},
        ":b" : { N|S|B : "?"}
    }
}

However, ExpressionAttributeValues ​​is an argument of AttributeMap type, which violates Tynamo design principles. As an alternative, use the following value class:

@DynamoEntity()
class MyExpressionValue {
    @DynamoProperty({ keyType: KeyType.hash })
    a!: number;

    @DynamoProperty({ keyType: KeyType.attr })
    b!: number;
    
    constructor(a:number, b:number){
        this.a = a;
        this.b = b;
    }
}

Currently, one HASH must be required in the ValueEntityClass also.

Attempting to use an argument that is not in the EntityClass or ValueEntityClass occurs error.

Custom EntityPropertyName

It is also possible to set an alias for the EntityProperty. If you want to use the name #identifier instead of id, you can pass it explicitly in ExpressionAttrubuteNames.

{
    conditionalExpressions : "attribute_not_exists(#identifier)",
    ExpressionAttributeNames : {
        "#identifier" : "id"
    }
}

Inferences made by Tynamo may conflict with what you explicitly conveyed. In this case, use the one passed explicitly.

{
    conditionalExpressions : "attribute_not_exists(#name)",
    ExpressionAttributeNames : {
        "#name" : "id"
    }
}

Although a name exists in the entity, it is used as aslias of id.

Skip unnecessary elements

Dynamo raises an error if there is a declared but unused value name. Tynamo finds these elements and helps them to be omitted at the time of the actual call. For example,

@DynamoEntity()
class ValueItem {
    @DynamoProperty({ keyType: KeyType.hash })
    a!: number;

    @DynamoProperty({ keyType: KeyType.attr })
    b!: number;

    constructor(a: number, b: number) {
        this.a = a;
        this.b = b;
    }
}

{
    conditionalExpressions : "attribute_not_exists(#id)",
    ExpressionAttributeNames: {
        "#unused" : "name"
    },
    ExpressionAttributeValues : new ValueItem(0, 0)
}

In the expression above, #unused, :a, and :b are declared but not used. Dynamo raises an error if there is such an element, but Tynamo sends only the element that is actually used so no error occurs. It is good for DynamicExpression.

Example

@DynamoEntity()
class Cat {
    @DynamoProperty({ keyType: KeyType.hash })
    id!: number;

    @DynamoProperty({ keyType: KeyType.attr })
    name!: string;

    constructor(id: number, name: string) {
        this.id = id;
        this.name = name;
    }
}

@DynamoEntity()
class ValueItem {
    @DynamoProperty({ keyType: KeyType.hash })
    a!: number;

    @DynamoProperty({ keyType: KeyType.attr })
    b!: number;

    constructor(a: number, b: number) {
        this.a = a;
        this.b = b;
    }
}

const tynamo: Tynamo = new Tynamo({
    region: "ap-northeast-2",
    endpoint: "http://localhost:8000"
});

await tynamo.putItem({
    Item: new Cat(666, "garfield"),
    ConditionExpression: "attribute_not_exists(#id) and :a < :b",
    ExpressionAttributeValues : new ValueItem(5, 0)
});

The above putItem opreration is always fails because :a < :b is false.

Last updated