Skip to content
This repository has been archived by the owner on Feb 16, 2024. It is now read-only.

Commit

Permalink
refactor: use interfaces for repositories
Browse files Browse the repository at this point in the history
  • Loading branch information
relby committed Feb 4, 2024
1 parent c72cc5f commit 8e71a9d
Show file tree
Hide file tree
Showing 36 changed files with 1,427 additions and 1,105 deletions.
4 changes: 2 additions & 2 deletions src/api/strategies/access-token-auth.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { ExtractJwt, Strategy } from 'passport-jwt';
import { AppAuthException, AppEntityNotFoundException } from 'src/core/exceptions';
import { Nullable } from 'src/common/types';
import { UserTokenPayload } from '../types';
import { UsersRepository } from 'src/core/repositories/users.repository';
import { IUsersRepository } from 'src/core/repositories/users.repository';
import { EnvVariables } from 'src/infra/config/env.config';
import { UserEntity } from 'src/infra/postgres/tables';

@Injectable()
export class AccessTokenAuthStrategy extends PassportStrategy(Strategy, 'access-token') {
public constructor(
private readonly usersRepository: UsersRepository,
private readonly usersRepository: IUsersRepository,
configService: ConfigService<EnvVariables>,
) {
super({
Expand Down
4 changes: 2 additions & 2 deletions src/api/strategies/local-auth.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,14 @@ import { Injectable } from '@nestjs/common';
import { PassportStrategy } from '@nestjs/passport';
import { Strategy } from 'passport-local';
import * as bcrypt from 'bcrypt';
import { UsersRepository } from 'src/core/repositories/users.repository';
import { IUsersRepository } from 'src/core/repositories/users.repository';
import { UserEntity } from 'src/infra/postgres/tables';
import { Nullable } from 'src/common/types';
import { AppAuthException } from 'src/core/exceptions';

@Injectable()
export class LocalAuthStrategy extends PassportStrategy(Strategy) {
public constructor(private readonly usersRepository: UsersRepository) {
public constructor(private readonly usersRepository: IUsersRepository) {
super();
}

Expand Down
4 changes: 2 additions & 2 deletions src/api/strategies/refresh-token-auth.strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ import { ExtractJwt, Strategy } from 'passport-jwt';
import { AppAuthException, AppEntityNotFoundException } from 'src/core/exceptions';
import { Nullable, } from 'src/common/types';
import { UserTokenPayload } from '../types';
import { UsersRepository } from 'src/core/repositories/users.repository';
import { IUsersRepository } from 'src/core/repositories/users.repository';
import { EnvVariables } from 'src/infra/config/env.config';
import { UserEntity } from 'src/infra/postgres/tables';

@Injectable()
export class RefreshTokenAuthStrategy extends PassportStrategy(Strategy, 'refresh-token') {
public constructor(
private readonly usersRepository: UsersRepository,
private readonly usersRepository: IUsersRepository,
configService: ConfigService<EnvVariables>,
) {
super({
Expand Down
37 changes: 5 additions & 32 deletions src/core/repositories/opened-packs.repository.ts
Original file line number Diff line number Diff line change
@@ -1,35 +1,8 @@
import { Injectable } from '@nestjs/common';
import { Database, Transaction } from 'src/infra/postgres/types';
import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator';
import { CreateOpenedPackEntityValues, OpenedPackEntity, openedPacksTable } from 'src/infra/postgres/tables';
import { CreateOpenedPackEntityValues, OpenedPackEntity } from 'src/infra/postgres/tables';

@Injectable()
export class OpenedPacksRepository {
public constructor(
@InjectDatabase()
private readonly db: Database,
) {}

public async createOpenedPack(
export abstract class IOpenedPacksRepository {
public abstract createOpenedPack(
values: CreateOpenedPackEntityValues,
tx?: Transaction,
): Promise<OpenedPackEntity> {
const { user, pack, pokemon } = values;

return (tx ?? this.db)
.insert(openedPacksTable)
.values({
...values,
userId: user.id,
packId: pack.id,
pokemonId: pokemon.id,
})
.returning()
.then(([openedPack]) => ({
...openedPack!,
user,
pack,
pokemon,
}));
}
tx?: unknown,
): Promise<OpenedPackEntity>;
}
113 changes: 12 additions & 101 deletions src/core/repositories/packs.repository.ts
Original file line number Diff line number Diff line change
@@ -1,12 +1,6 @@
import { Injectable } from '@nestjs/common';
import { Optional, PaginatedArray, UUIDv4 } from 'src/common/types';
import { PackEntity, packsTable, packsToPokemonsTable, PokemonEntity, pokemonsTable } from 'src/infra/postgres/tables';
import { and, eq, getTableColumns, inArray, like, SQL, sql } from 'drizzle-orm';
import { Database } from 'src/infra/postgres/types';
import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator';
import { mapArrayToPaginatedArray } from 'src/common/helpers/map-array-to-paginated-array.helper';
import { AppEntityNotFoundException, AppInternalException } from '../exceptions';
import { FindEntitiesOptions, FindEntitiesWithPaginationOptions, FindEntityByIdOptions, FindEntityOptions } from '../types';
import { PaginatedArray, UUIDv4 } from 'src/common/types';
import { PackEntity, PokemonEntity } from 'src/infra/postgres/tables';
import { FindEntitiesWithPaginationOptions, FindEntityByIdOptions, FindEntityOptions } from '../types';

export type FindPacksWhere = Partial<{
id: UUIDv4,
Expand All @@ -15,103 +9,20 @@ export type FindPacksWhere = Partial<{
nameLike: string,
}>;

@Injectable()
export class PacksRepository {
public constructor(
@InjectDatabase()
private readonly db: Database,
) {}

private mapWhereToSQL(
where: FindPacksWhere
): Optional<SQL> {
return and(
where.id !== undefined ? eq(packsTable.id, where.id) : undefined,
where.ids !== undefined ? inArray(packsTable.id, where.ids) : undefined,
where.name !== undefined ? eq(packsTable.name, where.name) : undefined,
where.nameLike !== undefined ? like(packsTable.name, `%${where.nameLike}%`) : undefined,
);
}

private baseSelectBuilder(
options: FindEntitiesOptions<FindPacksWhere>,
) {
const { where = {} } = options;

return this.db
.select()
.from(packsTable)
.where(this.mapWhereToSQL(where));
}

public async findPacksWithPagination(
export abstract class IPacksRepository {
public abstract findPacksWithPagination(
options: FindEntitiesWithPaginationOptions<FindPacksWhere>,
): Promise<PaginatedArray<PackEntity>> {
const {
paginationOptions: { page, limit },
} = options;
// TODO: check for boundaries
const offset = (page - 1) * limit;

return this
.baseSelectBuilder(options)
.offset(offset)
.limit(limit)
.then((packs) => mapArrayToPaginatedArray(packs, { page, limit }))
}
): Promise<PaginatedArray<PackEntity>>;

public async findPack(
public abstract findPack(
options: FindEntityOptions<FindPacksWhere>,
): Promise<PackEntity> {
const {
notFoundErrorMessage = 'Pack not found',
} = options;

const pack = await this
.baseSelectBuilder(options)
.limit(1)
.then(([pack]) => pack ?? null);
): Promise<PackEntity>;

if (!pack) {
throw new AppEntityNotFoundException(notFoundErrorMessage);
}

return pack;
}

public async findPackById(
public abstract findPackById(
options: FindEntityByIdOptions,
): Promise<PackEntity> {
const {
id,
notFoundErrorMessageFn = (id) => `Pack (\`${id}\`) not found`,
} = options;

return this.findPack({
where: { id },
notFoundErrorMessage: notFoundErrorMessageFn(id),
})
}
): Promise<PackEntity>;

public async findRandomPokemonFromPack(
public abstract findRandomPokemonFromPack(
pack: PackEntity
): Promise<PokemonEntity> {
const pokemon = await this.db
.select({ pokemon: getTableColumns(pokemonsTable) })
.from(packsTable)
.innerJoin(packsToPokemonsTable, eq(packsToPokemonsTable.packId, packsTable.id))
.innerJoin(pokemonsTable, eq(pokemonsTable.id, packsToPokemonsTable.pokemonId))
.where(eq(packsTable.id, pack.id))
.orderBy(sql<number>`random()`)
.limit(1)
.then(([row]) => row?.pokemon ?? null);

if (!pokemon) {
throw new AppInternalException(
'There are no pokemons in the pack. Please notify the developer about it :)',
);
}

return pokemon;
}
): Promise<PokemonEntity>;
}
37 changes: 9 additions & 28 deletions src/core/repositories/pokemons.repository.ts
Original file line number Diff line number Diff line change
@@ -1,32 +1,13 @@
import { Injectable } from '@nestjs/common';
import { Database, Transaction } from 'src/infra/postgres/types';
import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator';
import { CreatePokemonEntityValues, PokemonEntity, pokemonsTable } from 'src/infra/postgres/tables';
import { CreatePokemonEntityValues, PokemonEntity } from 'src/infra/postgres/tables';

@Injectable()
export class PokemonsRepository {
public constructor(
@InjectDatabase()
private readonly db: Database,
) {}

public async createPokemons(
export abstract class IPokemonsRepository {
public abstract createPokemons(
values: Array<CreatePokemonEntityValues>,
tx?: Transaction,
): Promise<Array<PokemonEntity>> {
if (!values.length) return [];

return (tx ?? this.db)
.insert(pokemonsTable)
.values(values)
.returning()
}
tx?: unknown,
): Promise<Array<PokemonEntity>>;

public async deleteAllPokemons(
tx?: Transaction,
): Promise<void> {
await (tx ?? this.db)
.delete(pokemonsTable)
.returning();
}
public abstract deleteAllPokemons(
tx?: unknown,
): Promise<void>;
}

39 changes: 5 additions & 34 deletions src/core/repositories/quick-sold-user-items.repository.ts
Original file line number Diff line number Diff line change
@@ -1,37 +1,8 @@
import { Injectable } from '@nestjs/common';
import { Database, Transaction } from 'src/infra/postgres/types';
import { InjectDatabase } from 'src/infra/ioc/decorators/inject-database.decorator';
import { QuickSoldUserItemEntity, quickSoldUserItemsTable, UserItemEntity } from 'src/infra/postgres/tables';
import { UserItemsRepository } from './user-items.repository';
import { QuickSoldUserItemEntity, UserItemEntity } from 'src/infra/postgres/tables';

@Injectable()
export class QuickSoldUserItemsRepository {
public constructor(
@InjectDatabase()
private readonly db: Database,

private readonly userItemsRepository: UserItemsRepository,
) {}

public async createQuickSoldUserItem(
export abstract class IQuickSoldUserItemsRepository {
public abstract createQuickSoldUserItem(
userItem: UserItemEntity,
tx?: Transaction,
): Promise<QuickSoldUserItemEntity> {
const { user, pokemon } = userItem;

const [quickSoldUserItem] = await Promise.all([
(tx ?? this.db)
.insert(quickSoldUserItemsTable)
.values(userItem)
.returning()
.then(([quickSoldUserItem]) => ({
...quickSoldUserItem!,
user,
pokemon,
})),
this.userItemsRepository.deleteUserItem(userItem, tx),
]);

return quickSoldUserItem;
}
tx?: unknown,
): Promise<QuickSoldUserItemEntity>;
}
Loading

0 comments on commit 8e71a9d

Please sign in to comment.