dynamodb-toolbox
Version:
Lightweight and type-safe query builder for DynamoDB and TypeScript.
75 lines (74 loc) • 2.97 kB
JavaScript
import { DynamoDBToolboxError } from '../../../../errors/index.js';
import { ConditionParser } from '../../../../schema/actions/parseCondition/index.js';
import { BinarySchema } from '../../../../schema/binary/schema.js';
import { ItemSchema } from '../../../../schema/item/schema.js';
import { NumberSchema } from '../../../../schema/number/schema.js';
import { StringSchema } from '../../../../schema/string/schema.js';
import { pick } from '../../../../utils/pick.js';
const queryOperatorSet = new Set([
'eq',
'gt',
'gte',
'lt',
'lte',
'between',
'beginsWith'
]);
const getIndexKeySchema = (key) => {
switch (key.type) {
case 'number':
return new NumberSchema({ required: 'never', big: true });
case 'string':
return new StringSchema({ required: 'never' });
case 'binary':
return new BinarySchema({ required: 'never' });
}
};
export const parseQuery = (table, query) => {
const { index, partition, range } = query;
let primaryKeySchema;
if (index !== undefined) {
const indexKeySchema = table.indexes[index];
if (indexKeySchema === undefined) {
const indexes = Object.keys(table.indexes);
const hasIndex = indexes.length > 0;
throw new DynamoDBToolboxError('queryCommand.invalidIndex', {
message: `Unknown index: ${index}. ${hasIndex ? ` Expected one of: ${indexes.join(', ')}.` : ''}`,
payload: { received: index, ...(hasIndex ? { expected: Object.keys(table.indexes) } : {}) }
});
}
primaryKeySchema = indexKeySchema;
}
else {
primaryKeySchema = table;
}
const { partitionKey = table.partitionKey, sortKey } = primaryKeySchema;
if (partition === undefined) {
throw new DynamoDBToolboxError('queryCommand.invalidPartition', {
message: `Missing query partition. Expected: ${partitionKey.type}.`,
path: partitionKey.name,
payload: { partition }
});
}
const indexSchema = new ItemSchema({
[partitionKey.name]: getIndexKeySchema(partitionKey),
...(sortKey !== undefined && range !== undefined
? { [sortKey.name]: getIndexKeySchema(sortKey) }
: {})
});
let condition = { attr: partitionKey.name, eq: partition };
if (sortKey !== undefined && range !== undefined) {
const sortKeyCondition = {
attr: sortKey.name,
...pick(range, ...queryOperatorSet)
};
condition = { and: [condition, sortKeyCondition] };
}
const conditionParser = new ConditionParser(indexSchema);
const { ConditionExpression, ExpressionAttributeNames, ExpressionAttributeValues } = conditionParser.parse(condition, { expressionId: '0' });
return {
KeyConditionExpression: ConditionExpression,
ExpressionAttributeNames,
ExpressionAttributeValues
};
};