From fc0382449108ddaf4e039c241eddbbe731c9c86e Mon Sep 17 00:00:00 2001 From: Blazej Kustra Date: Tue, 23 Jan 2024 21:55:34 +0100 Subject: [PATCH] Handle in operator with empty array with an impossible condition --- lib/condition/index.ts | 2 ++ lib/utils/constants.ts | 8 ++++++++ tests/e2e/condition.test.ts | 2 ++ tests/unit/condition/index.test.ts | 4 ++-- tests/unit/utils/constants.test.ts | 16 ++++++++++++++++ 5 files changed, 30 insertions(+), 2 deletions(-) diff --git a/lib/condition/index.ts b/lib/condition/index.ts index 25a031f..ccabc77 100644 --- a/lib/condition/index.ts +++ b/lib/condition/index.ts @@ -49,6 +49,8 @@ export default class Condition { }, in: (values: Array>): C => { if (values.length === 0) { + // DynamoDB does not support an empty IN condition because it is logically impossible to have any value in an empty array. Therefore, an impossible condition is added to handle this case. + this.operators.push(...OPERATORS.impossibleCondition(key)); return this; } diff --git a/lib/utils/constants.ts b/lib/utils/constants.ts index f0fad36..cae6fdc 100644 --- a/lib/utils/constants.ts +++ b/lib/utils/constants.ts @@ -842,6 +842,14 @@ export const OPERATORS = { BASE_OPERATOR.space, { value, key }, ], + /** attribute_exists(Id) AND attribute_not_exists(Id) */ + impossibleCondition: (key: string): Operators => [ + ...OPERATORS.attributeExists(key), + BASE_OPERATOR.space, + BASE_OPERATOR.and, + BASE_OPERATOR.space, + ...OPERATORS.attributeNotExists(key), + ], }; export const UPDATE_OPERATORS = { diff --git a/tests/e2e/condition.test.ts b/tests/e2e/condition.test.ts index 6c5741f..0398052 100644 --- a/tests/e2e/condition.test.ts +++ b/tests/e2e/condition.test.ts @@ -36,6 +36,7 @@ describe.sequential('EntityManager.condition', () => { MockEntityManager.condition().attribute('string').beginsWith('any'), MockEntityManager.condition().attribute('string').between('a', 'c'), MockEntityManager.condition().attribute('string').in(['anything', 'anything2']), + MockEntityManager.condition().attribute('string').in([]), MockEntityManager.condition().attribute('string').not().in(['string', 'string2']), MockEntityManager.condition().attribute('string').not().eq('string'), MockEntityManager.condition().attribute('string').not().ne('anything'), @@ -100,6 +101,7 @@ describe.sequential('EntityManager.condition', () => { MockEntityManager.condition().attribute('number').between(0, 2), MockEntityManager.condition().attribute('number').in([1]), MockEntityManager.condition().attribute('number').not().in([0]), + MockEntityManager.condition().attribute('string').not().in([]), // boolean MockEntityManager.condition().attribute('boolean').exists(), diff --git a/tests/unit/condition/index.test.ts b/tests/unit/condition/index.test.ts index 9525041..d3370f1 100644 --- a/tests/unit/condition/index.test.ts +++ b/tests/unit/condition/index.test.ts @@ -130,10 +130,10 @@ describe('Condition', () => { }); describe('in', () => { - test('Should not push in expression for en empty array', async () => { + test('Should push an impossible condition for an empty array', async () => { condition.attribute('partitionKey').in([]); - expect(condition['operators']).toEqual([]); + expect(condition['operators']).toEqual([...OPERATORS.impossibleCondition('partitionKey')]); }); test('Should push in expression', async () => { diff --git a/tests/unit/utils/constants.test.ts b/tests/unit/utils/constants.test.ts index b70b2a3..fad6951 100644 --- a/tests/unit/utils/constants.test.ts +++ b/tests/unit/utils/constants.test.ts @@ -363,6 +363,22 @@ describe('Constants', () => { { value: 'value', key: 'key' }, ]); }); + + test('impossibleCondition', async () => { + expect(OPERATORS.impossibleCondition('key')).toEqual([ + { expression: 'attribute_exists' }, + { expression: '(' }, + { key: 'key' }, + { expression: ')' }, + { expression: ' ' }, + { expression: 'AND' }, + { expression: ' ' }, + { expression: 'attribute_not_exists' }, + { expression: '(' }, + { key: 'key' }, + { expression: ')' }, + ]); + }); }); describe('UPDATE_OPERATORS', () => {