Skip to content

Commit

Permalink
Start work on expression builder for updates
Browse files Browse the repository at this point in the history
  • Loading branch information
SethO committed Oct 25, 2023
1 parent c74355f commit 993538a
Show file tree
Hide file tree
Showing 2 changed files with 216 additions and 0 deletions.
34 changes: 34 additions & 0 deletions lib/updateExpressionBuilder.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
export type ExpressionBuilderResult = {
UpdateExpression: string;
ExpressionAttributeNames: any;
ExpressionAttributeValues: any;
};
export const updateExpressionBuilder = (item: any): ExpressionBuilderResult => ({
UpdateExpression: internalUpdateBuilder(item),
ExpressionAttributeNames: internalNameBuilder(item),
ExpressionAttributeValues: internalValueBuilder(item),
});

const internalUpdateBuilder = (item: any): string => {
const itemKeys = Object.keys(item);

return `SET ${itemKeys.map((k, index) => `#field_${index} = :value_${index}`).join(', ')}`;
};

const internalNameBuilder = (item: any): any => {
const itemKeys = Object.keys(item);

return itemKeys.reduce(
(accumulator, k, index) => ({ ...accumulator, [`#field_${index}`]: k }),
{},
);
};

const internalValueBuilder = (item: any): any => {
const itemKeys = Object.keys(item);
// itemKeys.reduce((accumulator, k, index) => ({ ...accumulator, [`:value${index}`]: item[k] }), {})
return itemKeys.reduce(
(accumulator, k, index) => ({ ...accumulator, [`:value_${index}`]: item[k] }),
{},
);
};
182 changes: 182 additions & 0 deletions test/updateExpressionBuilder.unit.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,182 @@
import { updateExpressionBuilder } from '../lib/updateExpressionBuilder';

describe('When building an update expression', () => {
describe('with primitive-only properties', () => {
it('should return an expression builder result', () => {
// ARRANGE
const item = { name: 'Francisco', age: 31, isCool: true };

// ACT
const result = updateExpressionBuilder(item);

// ASSERT
expect(result.UpdateExpression).not.toBeEmpty();
expect(result.ExpressionAttributeNames).toBeObject();
expect(result.ExpressionAttributeValues).toBeObject();
});

it('should add "#field_[index]" for each property', () => {
// ARRANGE
const item = { name: 'Francisco', age: 31, isCool: true };

// ACT
const result = updateExpressionBuilder(item);

// ASSERT
expect(result.UpdateExpression).toContain('#field_0');
expect(result.UpdateExpression).toContain('#field_1');
expect(result.UpdateExpression).toContain('#field_2');
});

it('should add ":value_[index]" for each property', () => {
// ARRANGE
const item = { name: 'Francisco', age: 31, isCool: true };

// ACT
const result = updateExpressionBuilder(item);

// ASSERT
expect(result.UpdateExpression).toContain(':value_0');
expect(result.UpdateExpression).toContain(':value_1');
expect(result.UpdateExpression).toContain(':value_2');
});

it('should correctly build Attribute Names', () => {
// ARRANGE
const item = { name: 'Francisco', age: 31, isCool: true };

// ACT
const { ExpressionAttributeNames } = updateExpressionBuilder(item);

// ASSERT
expect(ExpressionAttributeNames['#field_0']).toEqual('name');
expect(ExpressionAttributeNames['#field_1']).toEqual('age');
expect(ExpressionAttributeNames['#field_2']).toEqual('isCool');
});

it('should correctly build Attribute Values', () => {
// ARRANGE
const item = { name: 'Francisco', age: 31, isCool: true };

// ACT
const { ExpressionAttributeValues } = updateExpressionBuilder(item);

// ASSERT
expect(ExpressionAttributeValues[':value_0']).toEqual(item.name);
expect(ExpressionAttributeValues[':value_1']).toEqual(item.age);
expect(ExpressionAttributeValues[':value_2']).toEqual(item.isCool);
});
});

describe('with an array property', () => {
it('should add "#field_[index]" for the array', () => {
// ARRANGE
const item = {
name: 'Francisco',
age: 31,
isCool: true,
pursuits: ['philosophy', 'physics', 'mining'],
};

// ACT
const result = updateExpressionBuilder(item);

// ASSERT
expect(result.UpdateExpression).toContain('#field_3');
});

it('should add ":value_[index]" for the array', () => {
// ARRANGE
const item = {
name: 'Francisco',
age: 31,
isCool: true,
pursuits: ['philosophy', 'physics', 'mining'],
};

// ACT
const result = updateExpressionBuilder(item);

// ASSERT
expect(result.UpdateExpression).toContain(':value_3');
});

it('should correctly build Attribute Names', () => {
// ARRANGE
const item = {
name: 'Francisco',
age: 31,
isCool: true,
pursuits: ['philosophy', 'physics', 'mining'],
};

// ACT
const { ExpressionAttributeNames } = updateExpressionBuilder(item);

// ASSERT
expect(ExpressionAttributeNames['#field_3']).toEqual('pursuits');
});

it('should correctly build Attribute Values', () => {
// ARRANGE
const item = {
name: 'Francisco',
age: 31,
isCool: true,
pursuits: ['philosophy', 'physics', 'mining'],
};

// ACT
const { ExpressionAttributeValues } = updateExpressionBuilder(item);

// ASSERT
expect(ExpressionAttributeValues[':value_3']).toEqual(item.pursuits);
});
});

describe('with a map property', () => {
it('should add "#field_[index]" for the map', () => {
// ARRANGE
const item = { name: 'Francisco', age: 31, isCool: true, company: { location: 'Argentina' } };

// ACT
const result = updateExpressionBuilder(item);

// ASSERT
expect(result.UpdateExpression).toContain('#field_3');
});

it('should add ":value_[index]" for the map', () => {
// ARRANGE
const item = { name: 'Francisco', age: 31, isCool: true, company: { location: 'Argentina' } };

// ACT
const result = updateExpressionBuilder(item);

// ASSERT
expect(result.UpdateExpression).toContain(':value_3');
});

it('should correctly build Attribute Names', () => {
// ARRANGE
const item = { name: 'Francisco', age: 31, isCool: true, company: { location: 'Argentina' } };

// ACT
const { ExpressionAttributeNames } = updateExpressionBuilder(item);

// ASSERT
expect(ExpressionAttributeNames['#field_3']).toEqual('company');
});

it('should correctly build Attribute Values', () => {
// ARRANGE
const item = { name: 'Francisco', age: 31, isCool: true, company: { location: 'Argentina' } };

// ACT
const { ExpressionAttributeValues } = updateExpressionBuilder(item);

// ASSERT
expect(ExpressionAttributeValues[':value_3']).toEqual(item.company);
});
});
});

0 comments on commit 993538a

Please sign in to comment.