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

Fix 'in (false)' condition expression #159

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

ojii
Copy link

@ojii ojii commented Oct 26, 2022

dynalite incorrectly rejects condition expressions when using IN with false.

For example, if we have an item {key: {S: "key"}, val: {BOOL: false}} and do an update with a condition expression {ConditionExpression: "#v IN (:f)", ExpressionAttributeNames: {"#v": "val"}, ExpressionAttributeValues: {":f": {BOOL: false}} it will fail with conditional check failed, even though it should match (tested against real AWS DynamoDB and dynamodb-local).

I tried to fix it myself but unfortunately my JS skills proved to be insufficient, but I did manage to write a test that illustrates the issue, so hopefully someone else can write the actual fix for it. I figured out a fix, but I don't fully understand this whole code base so I'm not sure if the line I removed to fix this is somehow needed for other things to work

@ojii ojii changed the title Add failing test for 'in (false)' condition expr Fix 'in (false)' condition expression Oct 26, 2022
@dimaqq
Copy link

dimaqq commented Oct 26, 2022

I think 974b891 is not the correct fix, what I think that line does is short-circuiting "in an empty array" F("check").is_in([])... wait or maybe even short-circuiting F("check").is_in(undefined) like if the user forgot to supply the argument for the in clause.
Indeed it's kinda hard to understand what that code does 🙈

@dimaqq
Copy link

dimaqq commented Oct 26, 2022

Oh, wait, that line of code is indeed it prevents item field values false an null to match any in condition.
So, yeah, I'd say that line should be removed.
I'm not clear if that's everything that needs to be fixed, but your aiodynamo PR is actually a good test case for this change 🎉

ConditionExpression: '#a IN (:a)',
UpdateExpression: 'SET #a = :b',
ExpressionAttributeNames: {'#a': 'active'},
ExpressionAttributeValues: {':a': {BOOL: false}, ':b': {BOOL: true}},
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To make test cases comprehensive, consider adding all kinds of JS falsy things: false, null, 0, 0.0, ""

Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added another test for those values. null and 0/0.0 don't fail because they're encoded as {NULL:true} and {N: "0"} respectively, so their "attrVal" becomes true and "0".

The one that confuses me as to how it didn't fail is "" ({S:""}) because I feel like that should have the same issue but doesn't for reasons I cannot understand.

ExpressionAttributeValues: {':t': {BOOL: true}, ':v': value},
}), function(err, res) {
if (err) return cb(err)
res.statusCode.should.equal(200, `Update failed when checking for {${Object.keys(value)[0]}:${Object.values(value)[0]}}`)
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'd use JSON.stringify(value) over custom keys/values

Copy link

@dimaqq dimaqq left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Make sense to me.
@mhart ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Development

Successfully merging this pull request may close these issues.

2 participants