Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
15 changes: 13 additions & 2 deletions .github/workflows/code-quality.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
name: Code quality

on:
push:
pull_request:

jobs:
Expand All @@ -14,6 +13,7 @@ jobs:
uses: actions/checkout@v5
with:
persist-credentials: false
fetch-depth: 0
- name: Setup Node.js
uses: actions/setup-node@v4
with:
Expand All @@ -25,5 +25,16 @@ jobs:
uses: biomejs/setup-biome@v2
with:
version: 2.4.0
- name: Get changed backend files
id: changed
run: |
files=$(git diff --name-only --diff-filter=ACMR \
"${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" \
-- 'backend/' \
| grep -E '\.(ts|tsx|js|jsx|json)$' \
| tr '\n' ' ' || true)
echo "files=$files" >> "$GITHUB_OUTPUT"
echo "Changed backend files: $files"
- name: Run Biome
run: biome ci --formatter-enabled=false --assist-enabled=false .
if: steps.changed.outputs.files != ''
run: biome ci --formatter-enabled=false --assist-enabled=false ${{ steps.changed.outputs.files }}
Comment on lines 38 to +40

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Potential command injection via filename interpolation.

Directly interpolating ${{ steps.changed.outputs.files }} into the shell command is unsafe. If a PR introduces a file with shell metacharacters in its name (e.g., backend/foo$(whoami).ts), the expression is evaluated by the runner before shell execution, potentially allowing command injection.

Consider piping the file list through xargs for safer handling:

🛡️ Proposed fix using xargs
      - name: Get changed backend files
        id: changed
        run: |
-         files=$(git diff --name-only --diff-filter=ACMR \
+         git diff --name-only --diff-filter=ACMR \
            "${{ github.event.pull_request.base.sha }}...${{ github.event.pull_request.head.sha }}" \
            -- 'backend/' \
-           | grep -E '\.(ts|tsx|js|jsx|json)$' \
-           | tr '\n' ' ' || true)
-         echo "files=$files" >> "$GITHUB_OUTPUT"
-         echo "Changed backend files: $files"
+           | grep -E '\.(ts|tsx|js|jsx|json)$' > /tmp/changed_files.txt || true
+         if [ -s /tmp/changed_files.txt ]; then
+           echo "has_changes=true" >> "$GITHUB_OUTPUT"
+           echo "Changed backend files:"
+           cat /tmp/changed_files.txt
+         fi
      - name: Run Biome
-       if: steps.changed.outputs.files != ''
-       run: biome ci --formatter-enabled=false --assist-enabled=false ${{ steps.changed.outputs.files }}
+       if: steps.changed.outputs.has_changes == 'true'
+       run: xargs -a /tmp/changed_files.txt biome ci --formatter-enabled=false --assist-enabled=false
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/code-quality.yml around lines 38 - 40, The "Run Biome"
step is vulnerable because it interpolates `${{ steps.changed.outputs.files }}`
directly into the shell; change the step to safely pass filenames (avoid direct
shell interpolation of the variable) by piping the output into a safe invoker
like `xargs` or by iterating over the filenames and quoting each before
invocation so biome receives each path as an argument rather than allowing shell
evaluation of metacharacters; update the step that currently runs `biome ci
--formatter-enabled=false --assist-enabled=false ${{ steps.changed.outputs.files
}}` to use a safe invocation pattern (e.g., echo/piping to xargs or a loop) to
prevent command injection.

Original file line number Diff line number Diff line change
Expand Up @@ -127,7 +127,7 @@ export class FilteringFieldsDs {
field: string;

@ApiProperty()
value: string;
value: unknown;
}

export class AutocompleteFieldsDs {
Expand Down
2 changes: 1 addition & 1 deletion backend/src/entities/table/table-datastructures.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ export class FilteringFieldsDs {
criteria: FilterCriteriaEnum;

@ApiProperty()
value: string;
value: unknown;
}

export class ForeignKeyDSInfo {
Expand Down
2 changes: 2 additions & 0 deletions backend/src/entities/table/table.controller.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import {
Controller,
Delete,
Get,
HttpCode,
HttpException,
HttpStatus,
Inject,
Expand Down Expand Up @@ -248,6 +249,7 @@ export class TableController {
@ApiQuery({ name: 'search', required: false })
@UseGuards(TableReadGuard)
@Timeout(TimeoutDefaults.EXTENDED)
@HttpCode(HttpStatus.OK)
@Post('/table/rows/find/:connectionId')
async findAllRowsWithBodyFilter(
@QueryTableName() tableName: string,
Expand Down
28 changes: 27 additions & 1 deletion backend/src/entities/table/utils/find-filtering-fields.util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,32 @@ export function findFilteringFieldsUtil(
value: filters[`f_${fieldname}__empty`],
});
}

if (isObjectPropertyExists(filters, `f_${fieldname}__in`)) {
const rawValue = filters[`f_${fieldname}__in`];
filteringItems.push({
field: fieldname,
criteria: FilterCriteriaEnum.in,
value: Array.isArray(rawValue)
? rawValue
: String(rawValue)
.split(',')
.map((v) => v.trim()),
});
}

if (isObjectPropertyExists(filters, `f_${fieldname}__between`)) {
const rawValue = filters[`f_${fieldname}__between`];
filteringItems.push({
field: fieldname,
criteria: FilterCriteriaEnum.between,
value: Array.isArray(rawValue)
? rawValue
: String(rawValue)
.split(',')
.map((v) => v.trim()),
});
Comment on lines +93 to +114

Copilot AI Apr 3, 2026

Copy link

Choose a reason for hiding this comment

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

__in values are split and trimmed, but empty entries are not removed and empty arrays are allowed. Downstream DAOs may generate invalid queries for an empty set (e.g., IN ()). Consider filtering out empty strings and rejecting/handling the empty-set case here so behavior is consistent across drivers.

Suggested change
filteringItems.push({
field: fieldname,
criteria: FilterCriteriaEnum.in,
value: Array.isArray(rawValue)
? rawValue
: String(rawValue)
.split(',')
.map((v) => v.trim()),
});
const inValues = (Array.isArray(rawValue)
? rawValue.map((value) => (typeof value === 'string' ? value.trim() : value))
: String(rawValue)
.split(',')
.map((value) => value.trim())
).filter((value) => value !== '');
if (inValues.length > 0) {
filteringItems.push({
field: fieldname,
criteria: FilterCriteriaEnum.in,
value: inValues,
});
}

Copilot uses AI. Check for mistakes.
}
Comment on lines +91 to +115

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Validate __in / __between values before storing filter criteria.

Line 91-115 accepts empty tokens and arbitrary between arity. That can propagate malformed filters and break DAO query generation (IN () / undefined upper bound).

Suggested fix
 		if (isObjectPropertyExists(filters, `f_${fieldname}__in`)) {
 			const rawValue = filters[`f_${fieldname}__in`];
+			const inValues = (Array.isArray(rawValue) ? rawValue : String(rawValue).split(','))
+				.map((v) => String(v).trim())
+				.filter((v) => v.length > 0);
+			if (inValues.length === 0) {
+				continue;
+			}
 			filteringItems.push({
 				field: fieldname,
 				criteria: FilterCriteriaEnum.in,
-				value: Array.isArray(rawValue)
-					? rawValue
-					: String(rawValue)
-							.split(',')
-							.map((v) => v.trim()),
+				value: inValues,
 			});
 		}
 
 		if (isObjectPropertyExists(filters, `f_${fieldname}__between`)) {
 			const rawValue = filters[`f_${fieldname}__between`];
+			const betweenValues = (Array.isArray(rawValue) ? rawValue : String(rawValue).split(','))
+				.map((v) => String(v).trim())
+				.filter((v) => v.length > 0);
+			if (betweenValues.length !== 2) {
+				throw new Error(`Invalid between filter for "${fieldname}". Expected exactly 2 values.`);
+			}
 			filteringItems.push({
 				field: fieldname,
 				criteria: FilterCriteriaEnum.between,
-				value: Array.isArray(rawValue)
-					? rawValue
-					: String(rawValue)
-							.split(',')
-							.map((v) => v.trim()),
+				value: betweenValues,
 			});
 		}
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
if (isObjectPropertyExists(filters, `f_${fieldname}__in`)) {
const rawValue = filters[`f_${fieldname}__in`];
filteringItems.push({
field: fieldname,
criteria: FilterCriteriaEnum.in,
value: Array.isArray(rawValue)
? rawValue
: String(rawValue)
.split(',')
.map((v) => v.trim()),
});
}
if (isObjectPropertyExists(filters, `f_${fieldname}__between`)) {
const rawValue = filters[`f_${fieldname}__between`];
filteringItems.push({
field: fieldname,
criteria: FilterCriteriaEnum.between,
value: Array.isArray(rawValue)
? rawValue
: String(rawValue)
.split(',')
.map((v) => v.trim()),
});
}
if (isObjectPropertyExists(filters, `f_${fieldname}__in`)) {
const rawValue = filters[`f_${fieldname}__in`];
const inValues = (Array.isArray(rawValue) ? rawValue : String(rawValue).split(','))
.map((v) => String(v).trim())
.filter((v) => v.length > 0);
if (inValues.length === 0) {
continue;
}
filteringItems.push({
field: fieldname,
criteria: FilterCriteriaEnum.in,
value: inValues,
});
}
if (isObjectPropertyExists(filters, `f_${fieldname}__between`)) {
const rawValue = filters[`f_${fieldname}__between`];
const betweenValues = (Array.isArray(rawValue) ? rawValue : String(rawValue).split(','))
.map((v) => String(v).trim())
.filter((v) => v.length > 0);
if (betweenValues.length !== 2) {
throw new Error(`Invalid between filter for "${fieldname}". Expected exactly 2 values.`);
}
filteringItems.push({
field: fieldname,
criteria: FilterCriteriaEnum.between,
value: betweenValues,
});
}
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/entities/table/utils/find-filtering-fields.util.ts` around lines
91 - 115, The current handling of filters[`f_${fieldname}__in`] and
filters[`f_${fieldname}__between`] can produce empty tokens or wrong arity;
before pushing into filteringItems (for FilterCriteriaEnum.in and
FilterCriteriaEnum.between) validate and normalize rawValue: convert non-array
to String(...).split(',').map(v=>v.trim()).filter(Boolean) and for __in only
push if the resulting array.length > 0; for __between ensure the resulting
array.length === 2 and both values are non-empty (or otherwise skip/throw),
using the existing symbols filters, fieldname, filteringItems,
FilterCriteriaEnum.in and FilterCriteriaEnum.between to locate and update the
logic.

}
return filteringItems;
}
Expand All @@ -99,7 +125,7 @@ export function parseFilteringFieldsFromBodyData(
const rowNames = tableStructure.map((el) => el.column_name);
rowNames.forEach((rowName) => {
if (isObjectPropertyExists(filtersDataFromBody, rowName)) {
const filterData = filtersDataFromBody[rowName] as Record<string, string>;
const filterData = filtersDataFromBody[rowName] as Record<string, unknown>;
for (const key in filterData) {
Comment on lines +128 to 129

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major

Guard body filter payload shape before iterating.

Line 128 assumes filtersDataFromBody[rowName] is an object. If it is null, array, or primitive, iteration can throw or produce invalid criteria parsing.

Suggested fix
-			const filterData = filtersDataFromBody[rowName] as Record<string, unknown>;
+			const rawFilterData = filtersDataFromBody[rowName];
+			if (!rawFilterData || typeof rawFilterData !== 'object' || Array.isArray(rawFilterData)) {
+				throw new Error(`Invalid filters payload for "${rowName}".`);
+			}
+			const filterData = rawFilterData as Record<string, unknown>;
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
const filterData = filtersDataFromBody[rowName] as Record<string, unknown>;
for (const key in filterData) {
const rawFilterData = filtersDataFromBody[rowName];
if (!rawFilterData || typeof rawFilterData !== 'object' || Array.isArray(rawFilterData)) {
throw new Error(`Invalid filters payload for "${rowName}".`);
}
const filterData = rawFilterData as Record<string, unknown>;
for (const key in filterData) {
🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In `@backend/src/entities/table/utils/find-filtering-fields.util.ts` around lines
128 - 129, Guard against non-object payloads before iterating
filtersDataFromBody[rowName]: ensure the value (assigned to filterData) is a
non-null plain object (typeof === 'object' && filterData !== null &&
!Array.isArray(filterData)) and bail/continue if not, so iteration over
filterData in the loop does not throw or produce invalid criteria; apply this
check around where filtersDataFromBody, rowName, and filterData are used (in the
function in find-filtering-fields.util.ts) and handle invalid shapes by skipping
or returning an appropriate default.

if (!validateStringWithEnum(key, FilterCriteriaEnum)) {
throw new Error(`Invalid filter criteria: "${key}".`);
Expand Down
2 changes: 2 additions & 0 deletions backend/src/enums/filter-criteria.enum.ts
Original file line number Diff line number Diff line change
Expand Up @@ -9,4 +9,6 @@ export enum FilterCriteriaEnum {
icontains = 'icontains',
eq = 'eq',
empty = 'empty',
in = 'in',
between = 'between',
}
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ test.serial(`POST /table/rows/find/:connectionId - Should return filtered rows f
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(findRowsResponse.status, 201);
t.is(findRowsResponse.status, 200);
const findRowsRO = JSON.parse(findRowsResponse.text);
t.truthy(findRowsRO.rows);
t.is(findRowsRO.rows.length, 1);
Expand Down Expand Up @@ -886,7 +886,7 @@ test.serial(
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(findRowsResponse.status, 201);
t.is(findRowsResponse.status, 200);
const findRowsRO = JSON.parse(findRowsResponse.text);
t.truthy(findRowsRO.rows);
for (const row of findRowsRO.rows) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ test.serial(`POST /table/rows/find/:connectionId - Should return filtered rows f
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(findRowsResponse.status, 201);
t.is(findRowsResponse.status, 200);
const findRowsRO = JSON.parse(findRowsResponse.text);
t.truthy(findRowsRO.rows);
t.is(findRowsRO.rows.length, 1);
Expand Down Expand Up @@ -886,7 +886,7 @@ test.serial(
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(findRowsResponse.status, 201);
t.is(findRowsResponse.status, 200);
const findRowsRO = JSON.parse(findRowsResponse.text);
t.truthy(findRowsRO.rows);
for (const row of findRowsRO.rows) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ test.serial(`POST /table/rows/find/:connectionId - Should return filtered rows f
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(findRowsResponse.status, 201);
t.is(findRowsResponse.status, 200);
const findRowsRO = JSON.parse(findRowsResponse.text);
t.truthy(findRowsRO.rows);
t.is(findRowsRO.rows.length, 1);
Expand Down Expand Up @@ -886,7 +886,7 @@ test.serial(
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(findRowsResponse.status, 201);
t.is(findRowsResponse.status, 200);
const findRowsRO = JSON.parse(findRowsResponse.text);
t.truthy(findRowsRO.rows);
for (const row of findRowsRO.rows) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ test.serial(`POST /table/rows/find/:connectionId - Should return filtered rows f
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(findRowsResponse.status, 201);
t.is(findRowsResponse.status, 200);
const findRowsRO = JSON.parse(findRowsResponse.text);
t.truthy(findRowsRO.rows);
t.is(findRowsRO.rows.length, 1);
Expand Down Expand Up @@ -886,7 +886,7 @@ test.serial(
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(findRowsResponse.status, 201);
t.is(findRowsResponse.status, 200);
const findRowsRO = JSON.parse(findRowsResponse.text);
t.truthy(findRowsRO.rows);
for (const row of findRowsRO.rows) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -844,7 +844,7 @@ test.serial(`POST /table/rows/find/:connectionId - Should return filtered rows f
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(findRowsResponse.status, 201);
t.is(findRowsResponse.status, 200);
const findRowsRO = JSON.parse(findRowsResponse.text);
t.truthy(findRowsRO.rows);
t.is(findRowsRO.rows.length, 1);
Expand Down Expand Up @@ -886,7 +886,7 @@ test.serial(
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

t.is(findRowsResponse.status, 201);
t.is(findRowsResponse.status, 200);
const findRowsRO = JSON.parse(findRowsResponse.text);
t.truthy(findRowsRO.rows);
for (const row of findRowsRO.rows) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -1647,7 +1647,7 @@ should return all found rows with search, pagination: page=1, perPage=10 and DES
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');
t.is(getTableRowsResponse.status, 201);
t.is(getTableRowsResponse.status, 200);

const getTableRowsRO = JSON.parse(getTableRowsResponse.text);
t.is(typeof getTableRowsRO, 'object');
Expand Down Expand Up @@ -1749,7 +1749,7 @@ should return all found rows with search, pagination: page=1, perPage=2 and DESC
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');
t.is(getTableRowsResponse.status, 201);
t.is(getTableRowsResponse.status, 200);

const getTableRowsRO = JSON.parse(getTableRowsResponse.text);

Expand Down
128 changes: 128 additions & 0 deletions backend/test/ava-tests/non-saas-tests/non-saas-table-mysql-e2e.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3663,3 +3663,131 @@ test.serial(`${currentTest} should test connection and return result`, async (t)
const { message } = JSON.parse(testConnectionResponse.text);
t.is(message, 'Successfully connected');
});

currentTest = 'POST /table/rows/find/:slug';

test.serial(`${currentTest} should return rows filtered by IN operator in body`, async (t) => {
const connectionToTestDB = getTestData(mockFactory).connectionToMySQL;
const firstUserToken = (await registerUserAndReturnUserInfo(app)).token;
const { testTableName } = await createTestTable(connectionToTestDB);

testTables.push(testTableName);

const createConnectionResponse = await request(app.getHttpServer())
.post('/connection')
.send(connectionToTestDB)
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');
const createConnectionRO = JSON.parse(createConnectionResponse.text);
t.is(createConnectionResponse.status, 201);

const filters = {
id: { in: ['1', '22', '38'] },
};

const getTableRowsResponse = await request(app.getHttpServer())
.post(`/table/rows/find/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=20`)
.send({ filters })
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

const getTableRowsRO = JSON.parse(getTableRowsResponse.text);
t.is(getTableRowsResponse.status, 200);
t.is(getTableRowsRO.rows.length, 3);
const returnedIds = getTableRowsRO.rows.map((row) => row.id).sort((a, b) => a - b);
t.deepEqual(returnedIds, [1, 22, 38]);
});

test.serial(`${currentTest} should return rows filtered by IN operator in query params`, async (t) => {
const connectionToTestDB = getTestData(mockFactory).connectionToMySQL;
const firstUserToken = (await registerUserAndReturnUserInfo(app)).token;
const { testTableName } = await createTestTable(connectionToTestDB);

testTables.push(testTableName);

const createConnectionResponse = await request(app.getHttpServer())
.post('/connection')
.send(connectionToTestDB)
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');
const createConnectionRO = JSON.parse(createConnectionResponse.text);
t.is(createConnectionResponse.status, 201);

const getTableRowsResponse = await request(app.getHttpServer())
.get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=20&f_id__in=1,22,38`)
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

const getTableRowsRO = JSON.parse(getTableRowsResponse.text);
t.is(getTableRowsResponse.status, 200);
t.is(getTableRowsRO.rows.length, 3);
const returnedIds = getTableRowsRO.rows.map((row) => row.id).sort((a, b) => a - b);
t.deepEqual(returnedIds, [1, 22, 38]);
});

test.serial(`${currentTest} should return rows filtered by BETWEEN operator in body`, async (t) => {
const connectionToTestDB = getTestData(mockFactory).connectionToMySQL;
const firstUserToken = (await registerUserAndReturnUserInfo(app)).token;
const { testTableName } = await createTestTable(connectionToTestDB);

testTables.push(testTableName);

const createConnectionResponse = await request(app.getHttpServer())
.post('/connection')
.send(connectionToTestDB)
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');
const createConnectionRO = JSON.parse(createConnectionResponse.text);
t.is(createConnectionResponse.status, 201);

const filters = {
id: { between: ['20', '25'] },
};

const getTableRowsResponse = await request(app.getHttpServer())
.post(`/table/rows/find/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=20`)
.send({ filters })
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

const getTableRowsRO = JSON.parse(getTableRowsResponse.text);
t.is(getTableRowsResponse.status, 200);
t.is(getTableRowsRO.rows.length, 6);
const returnedIds = getTableRowsRO.rows.map((row) => row.id).sort((a, b) => a - b);
t.deepEqual(returnedIds, [20, 21, 22, 23, 24, 25]);
});

test.serial(`${currentTest} should return rows filtered by BETWEEN operator in query params`, async (t) => {
const connectionToTestDB = getTestData(mockFactory).connectionToMySQL;
const firstUserToken = (await registerUserAndReturnUserInfo(app)).token;
const { testTableName } = await createTestTable(connectionToTestDB);

testTables.push(testTableName);

const createConnectionResponse = await request(app.getHttpServer())
.post('/connection')
.send(connectionToTestDB)
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');
const createConnectionRO = JSON.parse(createConnectionResponse.text);
t.is(createConnectionResponse.status, 201);

const getTableRowsResponse = await request(app.getHttpServer())
.get(`/table/rows/${createConnectionRO.id}?tableName=${testTableName}&page=1&perPage=20&f_id__between=20,25`)
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');

const getTableRowsRO = JSON.parse(getTableRowsResponse.text);
t.is(getTableRowsResponse.status, 200);
t.is(getTableRowsRO.rows.length, 6);
const returnedIds = getTableRowsRO.rows.map((row) => row.id).sort((a, b) => a - b);
t.deepEqual(returnedIds, [20, 21, 22, 23, 24, 25]);
});
Original file line number Diff line number Diff line change
Expand Up @@ -1643,7 +1643,7 @@ should return all found rows with search, pagination: page=1, perPage=10 and DES
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');
t.is(getTableRowsResponse.status, 201);
t.is(getTableRowsResponse.status, 200);

const getTableRowsRO = JSON.parse(getTableRowsResponse.text);
t.is(typeof getTableRowsRO, 'object');
Expand Down Expand Up @@ -1745,7 +1745,7 @@ should return all found rows with search, pagination: page=1, perPage=2 and DESC
.set('Cookie', firstUserToken)
.set('Content-Type', 'application/json')
.set('Accept', 'application/json');
t.is(getTableRowsResponse.status, 201);
t.is(getTableRowsResponse.status, 200);

const getTableRowsRO = JSON.parse(getTableRowsResponse.text);
console.log('🚀 ~ getTableRowsRO:', getTableRowsRO);
Expand Down
Loading
Loading