Skip to content

Commit b291314

Browse files
authored
Merge pull request #1294 from rocket-admin/backend_dynamodb_fixes
fix dynamodb filters
2 parents c12133f + ed2e2b9 commit b291314

3 files changed

Lines changed: 110 additions & 7 deletions

File tree

backend/test/ava-tests/saas-tests/table-dynamodb-e2e.test.ts

Lines changed: 90 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1526,6 +1526,96 @@ should return all found rows with search, pagination: page=1, perPage=2 and DESC
15261526
},
15271527
);
15281528

1529+
test.serial(`${currentTest} with search, with pagination, with sorting and with filtering by id
1530+
should return all found rows with search, pagination: page=1, perPage=2 and DESC sorting and with multi filtering`, async (t) => {
1531+
try {
1532+
const connectionToTestDB = getTestData(mockFactory).dynamoDBConnection;
1533+
const firstUserToken = (await registerUserAndReturnUserInfo(app)).token;
1534+
const { testTableName, testTableColumnName, insertedSearchedIds } = await createTestTable(connectionToTestDB);
1535+
1536+
testTables.push(testTableName);
1537+
1538+
const createConnectionResponse = await request(app.getHttpServer())
1539+
.post('/connection')
1540+
.send(connectionToTestDB)
1541+
.set('Cookie', firstUserToken)
1542+
.set('Content-Type', 'application/json')
1543+
.set('Accept', 'application/json');
1544+
const createConnectionRO = JSON.parse(createConnectionResponse.text);
1545+
t.is(createConnectionResponse.status, 201);
1546+
1547+
const createTableSettingsDTO = mockFactory.generateTableSettings(
1548+
createConnectionRO.id,
1549+
testTableName,
1550+
[],
1551+
undefined,
1552+
undefined,
1553+
3,
1554+
QueryOrderingEnum.DESC,
1555+
'id',
1556+
undefined,
1557+
undefined,
1558+
undefined,
1559+
undefined,
1560+
undefined,
1561+
);
1562+
1563+
const createTableSettingsResponse = await request(app.getHttpServer())
1564+
.post(`/settings?connectionId=${createConnectionRO.id}&tableName=${testTableName}`)
1565+
.send(createTableSettingsDTO)
1566+
.set('Cookie', firstUserToken)
1567+
.set('Content-Type', 'application/json')
1568+
.set('Accept', 'application/json');
1569+
t.is(createTableSettingsResponse.status, 201);
1570+
1571+
const fieldname = 'age';
1572+
const idFieldName = 'id';
1573+
const idFieldValue = 21;
1574+
const fieldGtvalue = 14;
1575+
// const fieldLtvalue = 95;
1576+
1577+
const filters = {
1578+
// [fieldname]: { gt: fieldGtvalue },
1579+
[idFieldName]: { eq: idFieldValue },
1580+
};
1581+
1582+
const getTableRowsResponse = await request(app.getHttpServer())
1583+
.post(
1584+
`/table/rows/find/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=3`,
1585+
)
1586+
.send({ filters })
1587+
.set('Cookie', firstUserToken)
1588+
.set('Content-Type', 'application/json')
1589+
.set('Accept', 'application/json');
1590+
t.is(getTableRowsResponse.status, 201);
1591+
1592+
const getTableRowsRO = JSON.parse(getTableRowsResponse.text);
1593+
console.log('🚀 ~ getTableRowsRO:', getTableRowsRO.rows);
1594+
1595+
t.is(typeof getTableRowsRO, 'object');
1596+
t.is(getTableRowsRO.hasOwnProperty('rows'), true);
1597+
t.is(getTableRowsRO.hasOwnProperty('primaryColumns'), true);
1598+
t.is(getTableRowsRO.hasOwnProperty('pagination'), true);
1599+
t.is(getTableRowsRO.rows.length, 1);
1600+
t.is(Object.keys(getTableRowsRO.rows[0]).length, 11);
1601+
1602+
const findRowId = 21;
1603+
1604+
t.is(getTableRowsRO.rows[0].id, findRowId);
1605+
t.is(getTableRowsRO.rows[0][testTableColumnName], testSearchedUserName);
1606+
1607+
t.is(getTableRowsRO.pagination.currentPage, 1);
1608+
t.is(getTableRowsRO.pagination.perPage, 3);
1609+
1610+
t.is(typeof getTableRowsRO.primaryColumns, 'object');
1611+
t.is(getTableRowsRO.primaryColumns[0].hasOwnProperty('column_name'), true);
1612+
t.is(getTableRowsRO.primaryColumns[0].hasOwnProperty('data_type'), true);
1613+
} catch (e) {
1614+
console.error(e);
1615+
throw e;
1616+
}
1617+
});
1618+
15291619
test.serial(`${currentTest} should throw an exception when connection id is not passed in request`, async (t) => {
15301620
try {
15311621
const connectionToTestDB = getTestData(mockFactory).dynamoDBConnection;

backend/test/utils/create-test-table.ts

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -525,7 +525,7 @@ export async function createTestDynamoDBTable(
525525
} catch (error) {
526526
console.error(`Error creating dynamodb table: ${error.message}`);
527527
}
528-
528+
const insertedSearchedIds: Array<{ number: number; id: string }> = [];
529529
const documentClient = DynamoDBDocumentClient.from(dynamoDb);
530530
try {
531531
for (let i = 0; i < testEntitiesSeedsCount; i++) {
@@ -552,6 +552,13 @@ export async function createTestDynamoDBTable(
552552
binary_set_column: { BS: [Buffer.from('value1'), Buffer.from('value2')] },
553553
};
554554

555+
if (isSearchedUser) {
556+
insertedSearchedIds.push({
557+
number: i,
558+
id: String(item.id.N),
559+
});
560+
}
561+
555562
const params: PutItemCommandInput = {
556563
TableName: testTableName,
557564
Item: item as any,
@@ -568,6 +575,7 @@ export async function createTestDynamoDBTable(
568575
testTableColumnName: testTableColumnName,
569576
testTableSecondColumnName: testTableSecondColumnName,
570577
testEntitiesSeedsCount: testEntitiesSeedsCount,
578+
insertedSearchedIds,
571579
};
572580
}
573581

shared-code/src/data-access-layer/data-access-objects/data-access-object-dynamodb.ts

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -305,30 +305,33 @@ export class DataAccessObjectDynamoDB extends BasicDataAccessObject implements I
305305
const { field, criteria, value } = filter;
306306
expressionAttributeNames[`#${field}`] = field;
307307
const uniquePlaceholder = `:${field}${index}`;
308+
const fieldInfo = tableStructure.find((el) => el.column_name === field);
309+
const isNumberField = fieldInfo?.data_type === 'number';
310+
308311
switch (criteria) {
309312
case FilterCriteriaEnum.eq:
310313
filterExpression += ` AND #${field} = ${uniquePlaceholder}`;
311-
expressionAttributeValues[uniquePlaceholder] = { S: value };
314+
expressionAttributeValues[uniquePlaceholder] = isNumberField ? { N: String(value) } : { S: value };
312315
break;
313316
case FilterCriteriaEnum.contains:
314317
filterExpression += ` AND contains(#${field}, ${uniquePlaceholder})`;
315318
expressionAttributeValues[uniquePlaceholder] = { S: value };
316319
break;
317320
case FilterCriteriaEnum.gt:
318321
filterExpression += ` AND #${field} > ${uniquePlaceholder}`;
319-
expressionAttributeValues[uniquePlaceholder] = { N: value };
322+
expressionAttributeValues[uniquePlaceholder] = isNumberField ? { N: String(value) } : { S: value };
320323
break;
321324
case FilterCriteriaEnum.lt:
322325
filterExpression += ` AND #${field} < ${uniquePlaceholder}`;
323-
expressionAttributeValues[uniquePlaceholder] = { N: value };
326+
expressionAttributeValues[uniquePlaceholder] = isNumberField ? { N: String(value) } : { S: value };
324327
break;
325328
case FilterCriteriaEnum.gte:
326329
filterExpression += ` AND #${field} >= ${uniquePlaceholder}`;
327-
expressionAttributeValues[uniquePlaceholder] = { N: value };
330+
expressionAttributeValues[uniquePlaceholder] = isNumberField ? { N: String(value) } : { S: value };
328331
break;
329332
case FilterCriteriaEnum.lte:
330333
filterExpression += ` AND #${field} <= ${uniquePlaceholder}`;
331-
expressionAttributeValues[uniquePlaceholder] = { N: value };
334+
expressionAttributeValues[uniquePlaceholder] = isNumberField ? { N: String(value) } : { S: value };
332335
break;
333336
case FilterCriteriaEnum.icontains:
334337
filterExpression += ` AND NOT contains(#${field}, ${uniquePlaceholder})`;
@@ -348,6 +351,9 @@ export class DataAccessObjectDynamoDB extends BasicDataAccessObject implements I
348351
default:
349352
break;
350353
}
354+
if (index === 0) {
355+
filterExpression = filterExpression.replace(/^ AND /, '');
356+
}
351357
});
352358
}
353359

@@ -383,7 +389,6 @@ export class DataAccessObjectDynamoDB extends BasicDataAccessObject implements I
383389
const result = await dynamoDb.scan(params);
384390

385391
rows = rows.concat(result.Items);
386-
387392
lastEvaluatedKey = result.LastEvaluatedKey;
388393
} while (lastEvaluatedKey);
389394

0 commit comments

Comments
 (0)