feat(core): Add option to filter for empty variables (#12112)

This commit is contained in:
Danny Martini 2024-12-10 12:46:57 +01:00 committed by GitHub
parent 8bb0d3d823
commit a63f0e878e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 50 additions and 8 deletions

View file

@ -3,3 +3,4 @@ export { RoleChangeRequestDto } from './user/role-change-request.dto';
export { SettingsUpdateRequestDto } from './user/settings-update-request.dto';
export { UserUpdateRequestDto } from './user/user-update-request.dto';
export { CommunityRegisteredRequestDto } from './license/community-registered-request.dto';
export { VariableListRequestDto } from './variables/variables-list-request.dto';

View file

@ -0,0 +1,6 @@
import { z } from 'zod';
import { Z } from 'zod-class';
export class VariableListRequestDto extends Z.class({
state: z.literal('empty').optional(),
}) {}

View file

@ -1,4 +1,7 @@
import { VariableListRequestDto } from '@n8n/api-types';
import { Delete, Get, GlobalScope, Licensed, Patch, Post, RestController } from '@/decorators';
import { Query } from '@/decorators/args';
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
import { NotFoundError } from '@/errors/response-errors/not-found.error';
import { VariableCountLimitReachedError } from '@/errors/variable-count-limit-reached.error';
@ -13,8 +16,8 @@ export class VariablesController {
@Get('/')
@GlobalScope('variable:list')
async getVariables() {
return await this.variablesService.getAllCached();
async getVariables(_req: unknown, _res: unknown, @Query query: VariableListRequestDto) {
return await this.variablesService.getAllCached(query.state);
}
@Post('/')

View file

@ -18,13 +18,22 @@ export class VariablesService {
private readonly eventService: EventService,
) {}
async getAllCached(): Promise<Variables[]> {
const variables = await this.cacheService.get('variables', {
async getAllCached(state?: 'empty'): Promise<Variables[]> {
let variables = await this.cacheService.get('variables', {
async refreshFn() {
return await Container.get(VariablesService).findAll();
},
});
return (variables as Array<Partial<Variables>>).map((v) => this.variablesRepository.create(v));
if (variables === undefined) {
return [];
}
if (state === 'empty') {
variables = variables.filter((v) => v.value === '');
}
return variables.map((v) => this.variablesRepository.create(v));
}
async getCount(): Promise<number> {

View file

@ -4,6 +4,7 @@ import type { Variables } from '@/databases/entities/variables';
import { VariablesRepository } from '@/databases/repositories/variables.repository';
import { generateNanoId } from '@/databases/utils/generators';
import { VariablesService } from '@/environments/variables/variables.service.ee';
import { CacheService } from '@/services/cache/cache.service';
import { createOwner, createUser } from './shared/db/users';
import * as testDb from './shared/test-db';
@ -65,19 +66,41 @@ beforeEach(async () => {
// ----------------------------------------
describe('GET /variables', () => {
beforeEach(async () => {
await Promise.all([createVariable('test1', 'value1'), createVariable('test2', 'value2')]);
await Promise.all([
createVariable('test1', 'value1'),
createVariable('test2', 'value2'),
createVariable('empty', ''),
]);
});
test('should return an empty array if there is nothing in the cache', async () => {
const cacheService = Container.get(CacheService);
const spy = jest.spyOn(cacheService, 'get').mockResolvedValueOnce(undefined);
const response = await authOwnerAgent.get('/variables');
expect(spy).toHaveBeenCalledTimes(1);
expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(0);
});
test('should return all variables for an owner', async () => {
const response = await authOwnerAgent.get('/variables');
expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(2);
expect(response.body.data.length).toBe(3);
});
test('should return all variables for a member', async () => {
const response = await authMemberAgent.get('/variables');
expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(2);
expect(response.body.data.length).toBe(3);
});
describe('state:empty', () => {
test('only return empty variables', async () => {
const response = await authOwnerAgent.get('/variables').query({ state: 'empty' });
expect(response.statusCode).toBe(200);
expect(response.body.data.length).toBe(1);
expect(response.body.data[0]).toMatchObject({ key: 'empty', value: '', type: 'string' });
});
});
});