mirror of
https://github.com/Art051/immich.git
synced 2025-08-11 19:29:00 +00:00
chore: organize config, validation, decorators (#8118)
* refactor: validation * refactor: utilities * refactor: config
This commit is contained in:
@@ -1,38 +0,0 @@
|
||||
import { RegisterQueueOptions } from '@nestjs/bullmq';
|
||||
import { QueueOptions } from 'bullmq';
|
||||
import { RedisOptions } from 'ioredis';
|
||||
import { QueueName } from 'src/domain/job/job.constants';
|
||||
|
||||
function parseRedisConfig(): RedisOptions {
|
||||
const redisUrl = process.env.REDIS_URL;
|
||||
if (redisUrl && redisUrl.startsWith('ioredis://')) {
|
||||
try {
|
||||
const decodedString = Buffer.from(redisUrl.slice(10), 'base64').toString();
|
||||
return JSON.parse(decodedString);
|
||||
} catch (error) {
|
||||
throw new Error(`Failed to decode redis options: ${error}`);
|
||||
}
|
||||
}
|
||||
return {
|
||||
host: process.env.REDIS_HOSTNAME || 'immich_redis',
|
||||
port: Number.parseInt(process.env.REDIS_PORT || '6379'),
|
||||
db: Number.parseInt(process.env.REDIS_DBINDEX || '0'),
|
||||
username: process.env.REDIS_USERNAME || undefined,
|
||||
password: process.env.REDIS_PASSWORD || undefined,
|
||||
path: process.env.REDIS_SOCKET || undefined,
|
||||
};
|
||||
}
|
||||
|
||||
export const bullConfig: QueueOptions = {
|
||||
prefix: 'immich_bull',
|
||||
connection: parseRedisConfig(),
|
||||
defaultJobOptions: {
|
||||
attempts: 3,
|
||||
removeOnComplete: true,
|
||||
removeOnFail: false,
|
||||
},
|
||||
};
|
||||
|
||||
export const bullQueues: RegisterQueueOptions[] = Object.values(QueueName).map((name) => ({ name }));
|
||||
|
||||
export const excludePaths = ['/.well-known/immich', '/custom.css', '/favicon.ico'];
|
||||
@@ -5,7 +5,7 @@ import { EventEmitterModule } from '@nestjs/event-emitter';
|
||||
import { ScheduleModule, SchedulerRegistry } from '@nestjs/schedule';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { OpenTelemetryModule } from 'nestjs-otel';
|
||||
import { immichAppConfig } from 'src/domain/domain.config';
|
||||
import { bullConfig, bullQueues, immichAppConfig } from 'src/config';
|
||||
import { IAccessRepository } from 'src/domain/repositories/access.repository';
|
||||
import { IActivityRepository } from 'src/domain/repositories/activity.repository';
|
||||
import { IAlbumRepository } from 'src/domain/repositories/album.repository';
|
||||
@@ -35,7 +35,6 @@ import { IUserTokenRepository } from 'src/domain/repositories/user-token.reposit
|
||||
import { IUserRepository } from 'src/domain/repositories/user.repository';
|
||||
import { databaseConfig } from 'src/infra/database.config';
|
||||
import { databaseEntities } from 'src/infra/entities';
|
||||
import { bullConfig, bullQueues } from 'src/infra/infra.config';
|
||||
import { otelConfig } from 'src/infra/instrumentation';
|
||||
import { AccessRepository } from 'src/infra/repositories/access.repository';
|
||||
import { ActivityRepository } from 'src/infra/repositories/activity.repository';
|
||||
|
||||
@@ -1,30 +0,0 @@
|
||||
import { SetMetadata } from '@nestjs/common';
|
||||
|
||||
export const GENERATE_SQL_KEY = 'generate-sql-key';
|
||||
|
||||
export interface GenerateSqlQueries {
|
||||
name?: string;
|
||||
params: unknown[];
|
||||
}
|
||||
|
||||
/** Decorator to enable versioning/tracking of generated Sql */
|
||||
export const GenerateSql = (...options: GenerateSqlQueries[]) => SetMetadata(GENERATE_SQL_KEY, options);
|
||||
|
||||
const UUID = '00000000-0000-4000-a000-000000000000';
|
||||
|
||||
export const DummyValue = {
|
||||
UUID,
|
||||
UUID_SET: new Set([UUID]),
|
||||
PAGINATION: { take: 10, skip: 0 },
|
||||
EMAIL: 'user@immich.app',
|
||||
STRING: 'abcdefghi',
|
||||
BUFFER: Buffer.from('abcdefghi'),
|
||||
DATE: new Date(),
|
||||
TIME_BUCKET: '2024-01-01T00:00:00.000Z',
|
||||
};
|
||||
|
||||
// PostgreSQL uses a 16-bit integer to indicate the number of bound parameters. This means that the
|
||||
// maximum number of parameters is 65535. Any query that tries to bind more than that (e.g. searching
|
||||
// by a list of IDs) requires splitting the query into multiple chunks.
|
||||
// We are rounding down this limit, as queries commonly include other filters and parameters.
|
||||
export const DATABASE_PARAMETER_CHUNK_SIZE = 65_500;
|
||||
@@ -1,16 +1,7 @@
|
||||
import _ from 'lodash';
|
||||
import {
|
||||
Paginated,
|
||||
PaginatedBuilderOptions,
|
||||
PaginationMode,
|
||||
PaginationOptions,
|
||||
PaginationResult,
|
||||
chunks,
|
||||
setUnion,
|
||||
} from 'src/domain/domain.util';
|
||||
import { AssetSearchBuilderOptions } from 'src/domain/repositories/search.repository';
|
||||
import { AssetEntity } from 'src/infra/entities/asset.entity';
|
||||
import { DATABASE_PARAMETER_CHUNK_SIZE } from 'src/infra/infra.util';
|
||||
import { Paginated, PaginatedBuilderOptions, PaginationMode, PaginationOptions, PaginationResult } from 'src/utils';
|
||||
import {
|
||||
Between,
|
||||
FindManyOptions,
|
||||
@@ -37,11 +28,6 @@ export function OptionalBetween<T>(from?: T, to?: T) {
|
||||
}
|
||||
}
|
||||
|
||||
export const isValidInteger = (value: number, options: { min?: number; max?: number }): value is number => {
|
||||
const { min = Number.MIN_SAFE_INTEGER, max = Number.MAX_SAFE_INTEGER } = options;
|
||||
return Number.isInteger(value) && value >= min && value <= max;
|
||||
};
|
||||
|
||||
function paginationHelper<Entity extends ObjectLiteral>(items: Entity[], take: number): PaginationResult<Entity> {
|
||||
const hasNextPage = items.length > take;
|
||||
items.splice(take);
|
||||
@@ -86,70 +72,6 @@ export async function paginatedBuilder<Entity extends ObjectLiteral>(
|
||||
export const asVector = (embedding: number[], quote = false) =>
|
||||
quote ? `'[${embedding.join(',')}]'` : `[${embedding.join(',')}]`;
|
||||
|
||||
/**
|
||||
* Wraps a method that takes a collection of parameters and sequentially calls it with chunks of the collection,
|
||||
* to overcome the maximum number of parameters allowed by the database driver.
|
||||
*
|
||||
* @param options.paramIndex The index of the function parameter to chunk. Defaults to 0.
|
||||
* @param options.flatten Whether to flatten the results. Defaults to false.
|
||||
*/
|
||||
export function Chunked(options: { paramIndex?: number; mergeFn?: (results: any) => any } = {}): MethodDecorator {
|
||||
return (target: any, propertyKey: string | symbol, descriptor: PropertyDescriptor) => {
|
||||
const originalMethod = descriptor.value;
|
||||
const parameterIndex = options.paramIndex ?? 0;
|
||||
descriptor.value = async function (...arguments_: any[]) {
|
||||
const argument = arguments_[parameterIndex];
|
||||
|
||||
// Early return if argument length is less than or equal to the chunk size.
|
||||
if (
|
||||
(Array.isArray(argument) && argument.length <= DATABASE_PARAMETER_CHUNK_SIZE) ||
|
||||
(argument instanceof Set && argument.size <= DATABASE_PARAMETER_CHUNK_SIZE)
|
||||
) {
|
||||
return await originalMethod.apply(this, arguments_);
|
||||
}
|
||||
|
||||
return Promise.all(
|
||||
chunks(argument, DATABASE_PARAMETER_CHUNK_SIZE).map(async (chunk) => {
|
||||
await Reflect.apply(originalMethod, this, [
|
||||
...arguments_.slice(0, parameterIndex),
|
||||
chunk,
|
||||
...arguments_.slice(parameterIndex + 1),
|
||||
]);
|
||||
}),
|
||||
).then((results) => (options.mergeFn ? options.mergeFn(results) : results));
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
export function ChunkedArray(options?: { paramIndex?: number }): MethodDecorator {
|
||||
return Chunked({ ...options, mergeFn: _.flatten });
|
||||
}
|
||||
|
||||
export function ChunkedSet(options?: { paramIndex?: number }): MethodDecorator {
|
||||
return Chunked({ ...options, mergeFn: setUnion });
|
||||
}
|
||||
|
||||
// https://stackoverflow.com/a/74898678
|
||||
export function DecorateAll(
|
||||
decorator: <T>(
|
||||
target: any,
|
||||
propertyKey: string,
|
||||
descriptor: TypedPropertyDescriptor<T>,
|
||||
) => TypedPropertyDescriptor<T> | void,
|
||||
) {
|
||||
return (target: any) => {
|
||||
const descriptors = Object.getOwnPropertyDescriptors(target.prototype);
|
||||
for (const [propName, descriptor] of Object.entries(descriptors)) {
|
||||
const isMethod = typeof descriptor.value == 'function' && propName !== 'constructor';
|
||||
if (!isMethod) {
|
||||
continue;
|
||||
}
|
||||
decorator({ ...target, constructor: { ...target.constructor, name: target.name } as any }, propName, descriptor);
|
||||
Object.defineProperty(target.prototype, propName, descriptor);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
export function searchAssetBuilder(
|
||||
builder: SelectQueryBuilder<AssetEntity>,
|
||||
options: AssetSearchBuilderOptions,
|
||||
|
||||
@@ -13,9 +13,9 @@ import { snakeCase, startCase } from 'lodash';
|
||||
import { OpenTelemetryModuleOptions } from 'nestjs-otel/lib/interfaces';
|
||||
import { copyMetadataFromFunctionToFunction } from 'nestjs-otel/lib/opentelemetry.utils';
|
||||
import { performance } from 'node:perf_hooks';
|
||||
import { excludePaths } from 'src/config';
|
||||
import { DecorateAll } from 'src/decorators';
|
||||
import { serverVersion } from 'src/domain/domain.constant';
|
||||
import { excludePaths } from 'src/infra/infra.config';
|
||||
import { DecorateAll } from 'src/infra/infra.utils';
|
||||
|
||||
let metricsEnabled = process.env.IMMICH_METRICS === 'true';
|
||||
const hostMetrics =
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { ChunkedSet, DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { IAccessRepository } from 'src/domain/repositories/access.repository';
|
||||
import { ActivityEntity } from 'src/infra/entities/activity.entity';
|
||||
import { AlbumEntity } from 'src/infra/entities/album.entity';
|
||||
@@ -9,8 +10,6 @@ import { PartnerEntity } from 'src/infra/entities/partner.entity';
|
||||
import { PersonEntity } from 'src/infra/entities/person.entity';
|
||||
import { SharedLinkEntity } from 'src/infra/entities/shared-link.entity';
|
||||
import { UserTokenEntity } from 'src/infra/entities/user-token.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { ChunkedSet } from 'src/infra/infra.utils';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { Brackets, In, Repository } from 'typeorm';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { IActivityRepository } from 'src/domain/repositories/activity.repository';
|
||||
import { ActivityEntity } from 'src/infra/entities/activity.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { IsNull, Repository } from 'typeorm';
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectDataSource, InjectRepository } from '@nestjs/typeorm';
|
||||
import _ from 'lodash';
|
||||
import { setUnion } from 'src/domain/domain.util';
|
||||
import { Chunked, ChunkedArray, DATABASE_PARAMETER_CHUNK_SIZE, DummyValue, GenerateSql } from 'src/decorators';
|
||||
import {
|
||||
AlbumAsset,
|
||||
AlbumAssetCount,
|
||||
@@ -12,9 +12,8 @@ import {
|
||||
import { dataSource } from 'src/infra/database.config';
|
||||
import { AlbumEntity } from 'src/infra/entities/album.entity';
|
||||
import { AssetEntity } from 'src/infra/entities/asset.entity';
|
||||
import { DATABASE_PARAMETER_CHUNK_SIZE, DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { Chunked, ChunkedArray } from 'src/infra/infra.utils';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { setUnion } from 'src/utils';
|
||||
import { DataSource, FindOptionsOrder, FindOptionsRelations, In, IsNull, Not, Repository } from 'typeorm';
|
||||
|
||||
@Instrumentation()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { IKeyRepository } from 'src/domain/repositories/api-key.repository';
|
||||
import { APIKeyEntity } from 'src/infra/entities/api-key.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
|
||||
@@ -2,7 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { DateTime } from 'luxon';
|
||||
import path from 'node:path';
|
||||
import { Paginated, PaginationMode, PaginationOptions } from 'src/domain/domain.util';
|
||||
import { Chunked, ChunkedArray, DummyValue, GenerateSql } from 'src/decorators';
|
||||
import {
|
||||
AssetBuilderOptions,
|
||||
AssetCreate,
|
||||
@@ -30,16 +30,9 @@ import { AssetJobStatusEntity } from 'src/infra/entities/asset-job-status.entity
|
||||
import { AssetEntity, AssetType } from 'src/infra/entities/asset.entity';
|
||||
import { ExifEntity } from 'src/infra/entities/exif.entity';
|
||||
import { SmartInfoEntity } from 'src/infra/entities/smart-info.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import {
|
||||
Chunked,
|
||||
ChunkedArray,
|
||||
OptionalBetween,
|
||||
paginate,
|
||||
paginatedBuilder,
|
||||
searchAssetBuilder,
|
||||
} from 'src/infra/infra.utils';
|
||||
import { OptionalBetween, paginate, paginatedBuilder, searchAssetBuilder } from 'src/infra/infra.utils';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { Paginated, PaginationMode, PaginationOptions } from 'src/utils';
|
||||
import {
|
||||
Brackets,
|
||||
FindOptionsRelations,
|
||||
|
||||
@@ -12,9 +12,9 @@ import {
|
||||
extName,
|
||||
} from 'src/domain/repositories/database.repository';
|
||||
import { vectorExt } from 'src/infra/database.config';
|
||||
import { isValidInteger } from 'src/infra/infra.utils';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { ImmichLogger } from 'src/infra/logger';
|
||||
import { isValidInteger } from 'src/validation';
|
||||
import { DataSource, EntityManager, QueryRunner } from 'typeorm';
|
||||
|
||||
@Instrumentation()
|
||||
|
||||
@@ -5,6 +5,7 @@ import { SchedulerRegistry } from '@nestjs/schedule';
|
||||
import { Job, JobsOptions, Processor, Queue, Worker, WorkerOptions } from 'bullmq';
|
||||
import { CronJob, CronTime } from 'cron';
|
||||
import { setTimeout } from 'node:timers/promises';
|
||||
import { bullConfig } from 'src/config';
|
||||
import { JOBS_TO_QUEUE, JobName, QueueName } from 'src/domain/job/job.constants';
|
||||
import {
|
||||
IJobRepository,
|
||||
@@ -13,7 +14,6 @@ import {
|
||||
QueueCleanType,
|
||||
QueueStatus,
|
||||
} from 'src/domain/repositories/job.repository';
|
||||
import { bullConfig } from 'src/infra/infra.config';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { ImmichLogger } from 'src/infra/logger';
|
||||
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { LibraryStatsResponseDto } from 'src/domain/library/library.dto';
|
||||
import { ILibraryRepository } from 'src/domain/repositories/library.repository';
|
||||
import { LibraryEntity, LibraryType } from 'src/infra/entities/library.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { IsNull, Not } from 'typeorm';
|
||||
import { Repository } from 'typeorm/repository/Repository.js';
|
||||
|
||||
@@ -3,7 +3,6 @@ import fs from 'node:fs/promises';
|
||||
import { Writable } from 'node:stream';
|
||||
import { promisify } from 'node:util';
|
||||
import sharp from 'sharp';
|
||||
import { handlePromiseError } from 'src/domain/domain.util';
|
||||
import {
|
||||
CropOptions,
|
||||
IMediaRepository,
|
||||
@@ -14,6 +13,7 @@ import {
|
||||
import { Colorspace } from 'src/infra/entities/system-config.entity';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { ImmichLogger } from 'src/infra/logger';
|
||||
import { handlePromiseError } from 'src/utils';
|
||||
|
||||
const probe = promisify<string, FfprobeData>(ffmpeg.ffprobe);
|
||||
sharp.concurrency(0);
|
||||
|
||||
@@ -6,6 +6,7 @@ import { getName } from 'i18n-iso-countries';
|
||||
import { createReadStream, existsSync } from 'node:fs';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import readLine from 'node:readline';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import {
|
||||
citiesFile,
|
||||
geodataAdmin1Path,
|
||||
@@ -23,7 +24,6 @@ import { ISystemMetadataRepository } from 'src/domain/repositories/system-metada
|
||||
import { ExifEntity } from 'src/infra/entities/exif.entity';
|
||||
import { GeodataPlacesEntity } from 'src/infra/entities/geodata-places.entity';
|
||||
import { SystemMetadataKey } from 'src/infra/entities/system-metadata.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { ImmichLogger } from 'src/infra/logger';
|
||||
import { DataSource, QueryRunner, Repository } from 'typeorm';
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { IMoveRepository, MoveCreate } from 'src/domain/repositories/move.repository';
|
||||
import { MoveEntity, PathType } from 'src/infra/entities/move.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import _ from 'lodash';
|
||||
import { Paginated, PaginationOptions } from 'src/domain/domain.util';
|
||||
import { ChunkedArray, DummyValue, GenerateSql } from 'src/decorators';
|
||||
import {
|
||||
AssetFaceId,
|
||||
IPersonRepository,
|
||||
@@ -13,9 +13,9 @@ import {
|
||||
import { AssetFaceEntity } from 'src/infra/entities/asset-face.entity';
|
||||
import { AssetEntity } from 'src/infra/entities/asset.entity';
|
||||
import { PersonEntity } from 'src/infra/entities/person.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { ChunkedArray, asVector, paginate } from 'src/infra/infra.utils';
|
||||
import { asVector, paginate } from 'src/infra/infra.utils';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { Paginated, PaginationOptions } from 'src/utils';
|
||||
import { FindManyOptions, FindOptionsRelations, FindOptionsSelect, In, Repository } from 'typeorm';
|
||||
|
||||
@Instrumentation()
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { Paginated, PaginationMode, PaginationResult } from 'src/domain/domain.util';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { DatabaseExtension } from 'src/domain/repositories/database.repository';
|
||||
import {
|
||||
AssetSearchOptions,
|
||||
@@ -18,10 +18,11 @@ import { AssetEntity, AssetType } from 'src/infra/entities/asset.entity';
|
||||
import { GeodataPlacesEntity } from 'src/infra/entities/geodata-places.entity';
|
||||
import { SmartInfoEntity } from 'src/infra/entities/smart-info.entity';
|
||||
import { SmartSearchEntity } from 'src/infra/entities/smart-search.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { asVector, isValidInteger, paginatedBuilder, searchAssetBuilder } from 'src/infra/infra.utils';
|
||||
import { asVector, paginatedBuilder, searchAssetBuilder } from 'src/infra/infra.utils';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { ImmichLogger } from 'src/infra/logger';
|
||||
import { Paginated, PaginationMode, PaginationResult } from 'src/utils';
|
||||
import { isValidInteger } from 'src/validation';
|
||||
import { Repository, SelectQueryBuilder } from 'typeorm';
|
||||
|
||||
@Instrumentation()
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { ISharedLinkRepository } from 'src/domain/repositories/shared-link.repository';
|
||||
import { SharedLinkEntity } from 'src/infra/entities/shared-link.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { readFile } from 'node:fs/promises';
|
||||
import { Chunked, DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
|
||||
import { SystemConfigEntity } from 'src/infra/entities/system-config.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { Chunked } from 'src/infra/infra.utils';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { In, Repository } from 'typeorm';
|
||||
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import { IUserTokenRepository } from 'src/domain/repositories/user-token.repository';
|
||||
import { UserTokenEntity } from 'src/infra/entities/user-token.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { Repository } from 'typeorm';
|
||||
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { InjectRepository } from '@nestjs/typeorm';
|
||||
import { DummyValue, GenerateSql } from 'src/decorators';
|
||||
import {
|
||||
IUserRepository,
|
||||
UserFindOptions,
|
||||
@@ -8,7 +9,6 @@ import {
|
||||
} from 'src/domain/repositories/user.repository';
|
||||
import { AssetEntity } from 'src/infra/entities/asset.entity';
|
||||
import { UserEntity } from 'src/infra/entities/user.entity';
|
||||
import { DummyValue, GenerateSql } from 'src/infra/infra.util';
|
||||
import { Instrumentation } from 'src/infra/instrumentation';
|
||||
import { IsNull, Not, Repository } from 'typeorm';
|
||||
|
||||
|
||||
@@ -5,10 +5,10 @@ import { Test } from '@nestjs/testing';
|
||||
import { TypeOrmModule } from '@nestjs/typeorm';
|
||||
import { mkdir, rm, writeFile } from 'node:fs/promises';
|
||||
import { join } from 'node:path';
|
||||
import { GENERATE_SQL_KEY, GenerateSqlQueries } from 'src/decorators';
|
||||
import { ISystemConfigRepository } from 'src/domain/repositories/system-config.repository';
|
||||
import { databaseConfig } from 'src/infra/database.config';
|
||||
import { databaseEntities } from 'src/infra/entities';
|
||||
import { GENERATE_SQL_KEY, GenerateSqlQueries } from 'src/infra/infra.util';
|
||||
import { AccessRepository } from 'src/infra/repositories/access.repository';
|
||||
import { AlbumRepository } from 'src/infra/repositories/album.repository';
|
||||
import { ApiKeyRepository } from 'src/infra/repositories/api-key.repository';
|
||||
|
||||
Reference in New Issue
Block a user