mirror of
https://github.com/n8n-io/n8n.git
synced 2025-03-05 20:50:17 -08:00
refactor(core): Move more typeorm
operators to repositories (no-changelog) (#8143)
Follow-up to #8139
This commit is contained in:
parent
4007163651
commit
a59d78de18
|
@ -14,6 +14,7 @@ import type { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||||
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
import { BadRequestError } from '@/errors/response-errors/bad-request.error';
|
||||||
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
import { NotFoundError } from '@/errors/response-errors/not-found.error';
|
||||||
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
import { UnauthorizedError } from '@/errors/response-errors/unauthorized.error';
|
||||||
|
import { CredentialsRepository } from '@/databases/repositories/credentials.repository';
|
||||||
|
|
||||||
export const EECredentialsController = express.Router();
|
export const EECredentialsController = express.Router();
|
||||||
|
|
||||||
|
@ -155,10 +156,11 @@ EECredentialsController.put(
|
||||||
let newShareeIds: string[] = [];
|
let newShareeIds: string[] = [];
|
||||||
await Db.transaction(async (trx) => {
|
await Db.transaction(async (trx) => {
|
||||||
// remove all sharings that are not supposed to exist anymore
|
// remove all sharings that are not supposed to exist anymore
|
||||||
const { affected } = await EECredentials.pruneSharings(trx, credentialId, [
|
const { affected } = await Container.get(CredentialsRepository).pruneSharings(
|
||||||
...ownerIds,
|
trx,
|
||||||
...shareWithIds,
|
credentialId,
|
||||||
]);
|
[...ownerIds, ...shareWithIds],
|
||||||
|
);
|
||||||
if (affected) amountRemoved = affected;
|
if (affected) amountRemoved = affected;
|
||||||
|
|
||||||
const sharings = await EECredentials.getSharings(trx, credentialId);
|
const sharings = await EECredentials.getSharings(trx, credentialId);
|
||||||
|
|
|
@ -1,7 +1,6 @@
|
||||||
import type { DeleteResult, EntityManager, FindOptionsWhere } from 'typeorm';
|
import type { EntityManager, FindOptionsWhere } from 'typeorm';
|
||||||
import { In, Not } from 'typeorm';
|
|
||||||
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
import { CredentialsEntity } from '@db/entities/CredentialsEntity';
|
||||||
import { SharedCredentials } from '@db/entities/SharedCredentials';
|
import type { SharedCredentials } from '@db/entities/SharedCredentials';
|
||||||
import type { User } from '@db/entities/User';
|
import type { User } from '@db/entities/User';
|
||||||
import { UserService } from '@/services/user.service';
|
import { UserService } from '@/services/user.service';
|
||||||
import { CredentialsService, type CredentialsGetSharedOptions } from './credentials.service';
|
import { CredentialsService, type CredentialsGetSharedOptions } from './credentials.service';
|
||||||
|
@ -62,18 +61,6 @@ export class EECredentialsService extends CredentialsService {
|
||||||
return credential?.shared ?? [];
|
return credential?.shared ?? [];
|
||||||
}
|
}
|
||||||
|
|
||||||
static async pruneSharings(
|
|
||||||
transaction: EntityManager,
|
|
||||||
credentialId: string,
|
|
||||||
userIds: string[],
|
|
||||||
): Promise<DeleteResult> {
|
|
||||||
const conditions: FindOptionsWhere<SharedCredentials> = {
|
|
||||||
credentialsId: credentialId,
|
|
||||||
userId: Not(In(userIds)),
|
|
||||||
};
|
|
||||||
return transaction.delete(SharedCredentials, conditions);
|
|
||||||
}
|
|
||||||
|
|
||||||
static async share(
|
static async share(
|
||||||
transaction: EntityManager,
|
transaction: EntityManager,
|
||||||
credential: CredentialsEntity,
|
credential: CredentialsEntity,
|
||||||
|
|
|
@ -1,10 +1,39 @@
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { DataSource, Repository } from 'typeorm';
|
import {
|
||||||
|
DataSource,
|
||||||
|
In,
|
||||||
|
Not,
|
||||||
|
Repository,
|
||||||
|
type DeleteResult,
|
||||||
|
type EntityManager,
|
||||||
|
type FindOptionsWhere,
|
||||||
|
Like,
|
||||||
|
} from 'typeorm';
|
||||||
import { CredentialsEntity } from '../entities/CredentialsEntity';
|
import { CredentialsEntity } from '../entities/CredentialsEntity';
|
||||||
|
import { SharedCredentials } from '../entities/SharedCredentials';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
export class CredentialsRepository extends Repository<CredentialsEntity> {
|
export class CredentialsRepository extends Repository<CredentialsEntity> {
|
||||||
constructor(dataSource: DataSource) {
|
constructor(dataSource: DataSource) {
|
||||||
super(CredentialsEntity, dataSource.manager);
|
super(CredentialsEntity, dataSource.manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async pruneSharings(
|
||||||
|
transaction: EntityManager,
|
||||||
|
credentialId: string,
|
||||||
|
userIds: string[],
|
||||||
|
): Promise<DeleteResult> {
|
||||||
|
const conditions: FindOptionsWhere<SharedCredentials> = {
|
||||||
|
credentialsId: credentialId,
|
||||||
|
userId: Not(In(userIds)),
|
||||||
|
};
|
||||||
|
return transaction.delete(SharedCredentials, conditions);
|
||||||
|
}
|
||||||
|
|
||||||
|
async findStartingWith(credentialName: string) {
|
||||||
|
return this.find({
|
||||||
|
select: ['name'],
|
||||||
|
where: { name: Like(`${credentialName}%`) },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -425,4 +425,13 @@ export class ExecutionRepository extends Repository<ExecutionEntity> {
|
||||||
await this.delete(batch);
|
await this.delete(batch);
|
||||||
} while (executionIds.length > 0);
|
} while (executionIds.length > 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async getIdsSince(date: Date) {
|
||||||
|
return this.find({
|
||||||
|
select: ['id'],
|
||||||
|
where: {
|
||||||
|
startedAt: MoreThanOrEqual(DateUtils.mixedDateToUtcDatetimeString(date)),
|
||||||
|
},
|
||||||
|
}).then((executions) => executions.map(({ id }) => id));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { DataSource, Repository } from 'typeorm';
|
import { DataSource, In, Repository } from 'typeorm';
|
||||||
import { ExecutionData } from '../entities/ExecutionData';
|
import { ExecutionData } from '../entities/ExecutionData';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
|
@ -7,4 +7,13 @@ export class ExecutionDataRepository extends Repository<ExecutionData> {
|
||||||
constructor(dataSource: DataSource) {
|
constructor(dataSource: DataSource) {
|
||||||
super(ExecutionData, dataSource.manager);
|
super(ExecutionData, dataSource.manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findByExecutionIds(executionIds: string[]) {
|
||||||
|
return this.find({
|
||||||
|
select: ['workflowData'],
|
||||||
|
where: {
|
||||||
|
executionId: In(executionIds),
|
||||||
|
},
|
||||||
|
}).then((executionData) => executionData.map(({ workflowData }) => workflowData));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -172,4 +172,11 @@ export class WorkflowRepository extends Repository<WorkflowEntity> {
|
||||||
|
|
||||||
return { workflows, count };
|
return { workflows, count };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async findStartingWith(workflowName: string): Promise<Array<{ name: string }>> {
|
||||||
|
return this.find({
|
||||||
|
select: ['name'],
|
||||||
|
where: { name: Like(`${workflowName}%`) },
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { DataSource, Repository } from 'typeorm';
|
import { DataSource, LessThan, Repository } from 'typeorm';
|
||||||
import { WorkflowHistory } from '../entities/WorkflowHistory';
|
import { WorkflowHistory } from '../entities/WorkflowHistory';
|
||||||
|
|
||||||
@Service()
|
@Service()
|
||||||
|
@ -7,4 +7,8 @@ export class WorkflowHistoryRepository extends Repository<WorkflowHistory> {
|
||||||
constructor(dataSource: DataSource) {
|
constructor(dataSource: DataSource) {
|
||||||
super(WorkflowHistory, dataSource.manager);
|
super(WorkflowHistory, dataSource.manager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async deleteEarlierThan(date: Date) {
|
||||||
|
return this.delete({ createdAt: LessThan(date) });
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,3 @@
|
||||||
import { In, MoreThanOrEqual } from 'typeorm';
|
|
||||||
import { DateUtils } from 'typeorm/util/DateUtils';
|
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import type { IWorkflowBase } from 'n8n-workflow';
|
import type { IWorkflowBase } from 'n8n-workflow';
|
||||||
import config from '@/config';
|
import config from '@/config';
|
||||||
|
@ -119,23 +117,9 @@ export class CredentialsRiskReporter implements RiskReporter {
|
||||||
|
|
||||||
date.setDate(date.getDate() - days);
|
date.setDate(date.getDate() - days);
|
||||||
|
|
||||||
const executionIds = await this.executionRepository
|
const executionIds = await this.executionRepository.getIdsSince(date);
|
||||||
.find({
|
|
||||||
select: ['id'],
|
|
||||||
where: {
|
|
||||||
startedAt: MoreThanOrEqual(DateUtils.mixedDateToUtcDatetimeString(date) as Date),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then((executions) => executions.map(({ id }) => id));
|
|
||||||
|
|
||||||
return this.executionDataRepository
|
return this.executionDataRepository.findByExecutionIds(executionIds);
|
||||||
.find({
|
|
||||||
select: ['workflowData'],
|
|
||||||
where: {
|
|
||||||
executionId: In(executionIds),
|
|
||||||
},
|
|
||||||
})
|
|
||||||
.then((executionData) => executionData.map(({ workflowData }) => workflowData));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { Like } from 'typeorm';
|
|
||||||
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
import { WorkflowRepository } from '@/databases/repositories/workflow.repository';
|
||||||
import { CredentialsRepository } from '@/databases/repositories/credentials.repository';
|
import { CredentialsRepository } from '@/databases/repositories/credentials.repository';
|
||||||
|
|
||||||
|
@ -21,10 +20,7 @@ export class NamingService {
|
||||||
private async getUniqueName(requestedName: string, entity: 'workflow' | 'credential') {
|
private async getUniqueName(requestedName: string, entity: 'workflow' | 'credential') {
|
||||||
const repository = entity === 'workflow' ? this.workflowRepository : this.credentialsRepository;
|
const repository = entity === 'workflow' ? this.workflowRepository : this.credentialsRepository;
|
||||||
|
|
||||||
const found: Array<{ name: string }> = await repository.find({
|
const found = await repository.findStartingWith(requestedName);
|
||||||
select: ['name'],
|
|
||||||
where: { name: Like(`${requestedName}%`) },
|
|
||||||
});
|
|
||||||
|
|
||||||
if (found.length === 0) return requestedName;
|
if (found.length === 0) return requestedName;
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,4 @@
|
||||||
import { Service } from 'typedi';
|
import { Service } from 'typedi';
|
||||||
import { LessThan } from 'typeorm';
|
|
||||||
import { DateTime } from 'luxon';
|
import { DateTime } from 'luxon';
|
||||||
import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository';
|
import { WorkflowHistoryRepository } from '@db/repositories/workflowHistory.repository';
|
||||||
import { WORKFLOW_HISTORY_PRUNE_INTERVAL } from './constants';
|
import { WORKFLOW_HISTORY_PRUNE_INTERVAL } from './constants';
|
||||||
|
@ -38,8 +37,6 @@ export class WorkflowHistoryManager {
|
||||||
}
|
}
|
||||||
const pruneDateTime = DateTime.now().minus({ hours: pruneHours }).toJSDate();
|
const pruneDateTime = DateTime.now().minus({ hours: pruneHours }).toJSDate();
|
||||||
|
|
||||||
await this.workflowHistoryRepo.delete({
|
await this.workflowHistoryRepo.deleteEarlierThan(pruneDateTime);
|
||||||
createdAt: LessThan(pruneDateTime),
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -17,7 +17,7 @@ describe('NamingService', () => {
|
||||||
|
|
||||||
describe('getUniqueWorkflowName()', () => {
|
describe('getUniqueWorkflowName()', () => {
|
||||||
test('should return requested name if already unique', async () => {
|
test('should return requested name if already unique', async () => {
|
||||||
workflowRepository.find.mockResolvedValue([]);
|
workflowRepository.findStartingWith.mockResolvedValue([]);
|
||||||
|
|
||||||
const name = await namingService.getUniqueWorkflowName('foo');
|
const name = await namingService.getUniqueWorkflowName('foo');
|
||||||
|
|
||||||
|
@ -25,7 +25,7 @@ describe('NamingService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return requested name suffixed if already existing once', async () => {
|
test('should return requested name suffixed if already existing once', async () => {
|
||||||
workflowRepository.find.mockResolvedValue([{ name: 'foo' }] as WorkflowEntity[]);
|
workflowRepository.findStartingWith.mockResolvedValue([{ name: 'foo' }] as WorkflowEntity[]);
|
||||||
|
|
||||||
const name = await namingService.getUniqueWorkflowName('foo');
|
const name = await namingService.getUniqueWorkflowName('foo');
|
||||||
|
|
||||||
|
@ -35,7 +35,7 @@ describe('NamingService', () => {
|
||||||
test('should return requested name with incremented suffix if already suffixed', async () => {
|
test('should return requested name with incremented suffix if already suffixed', async () => {
|
||||||
const existingNames = [{ name: 'foo' }, { name: 'foo 2' }] as WorkflowEntity[];
|
const existingNames = [{ name: 'foo' }, { name: 'foo 2' }] as WorkflowEntity[];
|
||||||
|
|
||||||
workflowRepository.find.mockResolvedValue(existingNames);
|
workflowRepository.findStartingWith.mockResolvedValue(existingNames);
|
||||||
|
|
||||||
const name = await namingService.getUniqueWorkflowName('foo');
|
const name = await namingService.getUniqueWorkflowName('foo');
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ describe('NamingService', () => {
|
||||||
|
|
||||||
describe('getUniqueCredentialName()', () => {
|
describe('getUniqueCredentialName()', () => {
|
||||||
test('should return requested name if already unique', async () => {
|
test('should return requested name if already unique', async () => {
|
||||||
credentialsRepository.find.mockResolvedValue([]);
|
credentialsRepository.findStartingWith.mockResolvedValue([]);
|
||||||
|
|
||||||
const name = await namingService.getUniqueCredentialName('foo');
|
const name = await namingService.getUniqueCredentialName('foo');
|
||||||
|
|
||||||
|
@ -59,7 +59,9 @@ describe('NamingService', () => {
|
||||||
});
|
});
|
||||||
|
|
||||||
test('should return requested name suffixed if already existing once', async () => {
|
test('should return requested name suffixed if already existing once', async () => {
|
||||||
credentialsRepository.find.mockResolvedValue([{ name: 'foo' }] as CredentialsEntity[]);
|
credentialsRepository.findStartingWith.mockResolvedValue([
|
||||||
|
{ name: 'foo' },
|
||||||
|
] as CredentialsEntity[]);
|
||||||
|
|
||||||
const name = await namingService.getUniqueCredentialName('foo');
|
const name = await namingService.getUniqueCredentialName('foo');
|
||||||
|
|
||||||
|
@ -69,7 +71,7 @@ describe('NamingService', () => {
|
||||||
test('should return requested name with incremented suffix if already suffixed', async () => {
|
test('should return requested name with incremented suffix if already suffixed', async () => {
|
||||||
const existingNames = [{ name: 'foo' }, { name: 'foo 2' }] as CredentialsEntity[];
|
const existingNames = [{ name: 'foo' }, { name: 'foo 2' }] as CredentialsEntity[];
|
||||||
|
|
||||||
credentialsRepository.find.mockResolvedValue(existingNames);
|
credentialsRepository.findStartingWith.mockResolvedValue(existingNames);
|
||||||
|
|
||||||
const name = await namingService.getUniqueCredentialName('foo');
|
const name = await namingService.getUniqueCredentialName('foo');
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue