findAdByUuid, functional basic AdModule
This commit is contained in:
parent
47e4abf594
commit
5fbc399924
|
@ -0,0 +1,54 @@
|
||||||
|
image: docker:20.10.22
|
||||||
|
|
||||||
|
stages:
|
||||||
|
- test
|
||||||
|
- build
|
||||||
|
|
||||||
|
##############
|
||||||
|
# TEST STAGE #
|
||||||
|
##############
|
||||||
|
|
||||||
|
test:
|
||||||
|
stage: test
|
||||||
|
image: docker/compose:latest
|
||||||
|
variables:
|
||||||
|
DOCKER_TLS_CERTDIR: ''
|
||||||
|
services:
|
||||||
|
- docker:dind
|
||||||
|
script:
|
||||||
|
- docker-compose -f docker-compose.ci.tools.yml -p ad-tools --env-file ci/.env.ci up -d
|
||||||
|
- sh ci/wait-up.sh
|
||||||
|
- docker-compose -f docker-compose.ci.service.yml -p ad-service --env-file ci/.env.ci up -d
|
||||||
|
# - docker exec -t v3-ad-api sh -c "npm run test:integration:ci"
|
||||||
|
coverage: /All files[^|]*\|[^|]*\s+([\d\.]+)/
|
||||||
|
rules:
|
||||||
|
- if: '$CI_MERGE_REQUEST_TARGET_BRANCH_NAME == $CI_DEFAULT_BRANCH || $CI_COMMIT_MESSAGE =~ /--check/ || $CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
|
||||||
|
when: always
|
||||||
|
|
||||||
|
###############
|
||||||
|
# BUILD STAGE #
|
||||||
|
###############
|
||||||
|
|
||||||
|
build:
|
||||||
|
stage: build
|
||||||
|
image: docker:20.10.22
|
||||||
|
variables:
|
||||||
|
DOCKER_TLS_CERTDIR: ''
|
||||||
|
services:
|
||||||
|
- docker:dind
|
||||||
|
before_script:
|
||||||
|
- echo -n $CI_REGISTRY_PASSWORD | docker login -u $CI_REGISTRY_USER --password-stdin $CI_REGISTRY
|
||||||
|
script:
|
||||||
|
- export VERSION=$(docker run --rm -v "$PWD":/usr/src/app:ro -w /usr/src/app node:slim node -p "require('./package.json').version")
|
||||||
|
- docker pull $CI_REGISTRY_IMAGE:latest || true
|
||||||
|
- >
|
||||||
|
docker build
|
||||||
|
--pull
|
||||||
|
--cache-from $CI_REGISTRY_IMAGE:latest
|
||||||
|
--tag $CI_REGISTRY_IMAGE:$VERSION
|
||||||
|
--tag $CI_REGISTRY_IMAGE:latest
|
||||||
|
.
|
||||||
|
- docker push $CI_REGISTRY_IMAGE:$VERSION
|
||||||
|
- docker push $CI_REGISTRY_IMAGE:latest
|
||||||
|
only:
|
||||||
|
- main
|
|
@ -0,0 +1,15 @@
|
||||||
|
# SERVICE
|
||||||
|
SERVICE_URL=0.0.0.0
|
||||||
|
SERVICE_PORT=5006
|
||||||
|
|
||||||
|
# PRISMA
|
||||||
|
DATABASE_URL="postgresql://mobicoop:mobicoop@v3-db:5432/mobicoop?schema=public"
|
||||||
|
|
||||||
|
# RABBIT MQ
|
||||||
|
RMQ_URI=amqp://v3-broker:5672
|
||||||
|
|
||||||
|
# MESSAGE BROKER
|
||||||
|
BROKER_IMAGE=rabbitmq:3-alpine
|
||||||
|
|
||||||
|
# POSTGRES
|
||||||
|
POSTGRES_IMAGE=postgis/postgis:15-3.3
|
|
@ -0,0 +1,33 @@
|
||||||
|
###################
|
||||||
|
# BUILD FOR CI TESTING
|
||||||
|
###################
|
||||||
|
|
||||||
|
FROM node:18-alpine3.16
|
||||||
|
|
||||||
|
# Create app directory
|
||||||
|
WORKDIR /usr/src/app
|
||||||
|
|
||||||
|
# A wildcard is used to ensure both package.json AND package-lock.json are copied
|
||||||
|
COPY package*.json ./
|
||||||
|
|
||||||
|
# Install app dependencies
|
||||||
|
RUN npm ci
|
||||||
|
|
||||||
|
# Bundle app source
|
||||||
|
COPY . .
|
||||||
|
|
||||||
|
# Generate prisma client
|
||||||
|
RUN npx prisma generate
|
||||||
|
|
||||||
|
# Create a "dist" folder
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
# Run unit tests
|
||||||
|
RUN npm run test:unit:ci
|
||||||
|
|
||||||
|
# ESLint / Prettier
|
||||||
|
RUN npm run lint:check
|
||||||
|
RUN npm run pretty:check
|
||||||
|
|
||||||
|
# Start the server
|
||||||
|
CMD [ "node", "dist/main.js" ]
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/bash
|
||||||
|
testlog() {
|
||||||
|
docker logs v3-db | grep -q "database system is ready to accept connections"
|
||||||
|
}
|
||||||
|
|
||||||
|
testlog 2> /dev/null
|
||||||
|
while [ $? -ne 0 ];
|
||||||
|
do
|
||||||
|
sleep 5
|
||||||
|
echo "Waiting for Test DB to be up..."
|
||||||
|
testlog 2> /dev/null
|
||||||
|
done
|
|
@ -0,0 +1,19 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
v3-ad-api:
|
||||||
|
container_name: v3-ad-api
|
||||||
|
build:
|
||||||
|
dockerfile: ci/Dockerfile
|
||||||
|
context: .
|
||||||
|
env_file:
|
||||||
|
- ci/.env.ci
|
||||||
|
ports:
|
||||||
|
- 5006:5006
|
||||||
|
networks:
|
||||||
|
- v3-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
v3-network:
|
||||||
|
name: v3-network
|
||||||
|
external: true
|
|
@ -0,0 +1,26 @@
|
||||||
|
version: '3.8'
|
||||||
|
|
||||||
|
services:
|
||||||
|
db:
|
||||||
|
container_name: v3-db
|
||||||
|
image: ${POSTGRES_IMAGE}
|
||||||
|
environment:
|
||||||
|
POSTGRES_DB: mobicoop
|
||||||
|
POSTGRES_USER: mobicoop
|
||||||
|
POSTGRES_PASSWORD: mobicoop
|
||||||
|
ports:
|
||||||
|
- 5432:5432
|
||||||
|
networks:
|
||||||
|
- v3-network
|
||||||
|
|
||||||
|
broker:
|
||||||
|
container_name: v3-broker
|
||||||
|
image: ${BROKER_IMAGE}
|
||||||
|
ports:
|
||||||
|
- 5672:5672
|
||||||
|
networks:
|
||||||
|
- v3-network
|
||||||
|
|
||||||
|
networks:
|
||||||
|
v3-network:
|
||||||
|
name: v3-network
|
|
@ -24,6 +24,7 @@
|
||||||
"@nestjs/platform-express": "^9.0.0",
|
"@nestjs/platform-express": "^9.0.0",
|
||||||
"@nestjs/terminus": "^9.2.2",
|
"@nestjs/terminus": "^9.2.2",
|
||||||
"@prisma/client": "^4.13.0",
|
"@prisma/client": "^4.13.0",
|
||||||
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.0",
|
"class-validator": "^0.14.0",
|
||||||
"ioredis": "^5.3.2",
|
"ioredis": "^5.3.2",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
|
@ -3564,6 +3565,11 @@
|
||||||
"integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==",
|
"integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==",
|
||||||
"dev": true
|
"dev": true
|
||||||
},
|
},
|
||||||
|
"node_modules/class-transformer": {
|
||||||
|
"version": "0.5.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/class-transformer/-/class-transformer-0.5.1.tgz",
|
||||||
|
"integrity": "sha512-SQa1Ws6hUbfC98vKGxZH3KFY0Y1lm5Zm0SY8XX9zbK7FJCyVEac3ATW0RIpwzW+oOfmHE5PMPufDG9hCfoEOMw=="
|
||||||
|
},
|
||||||
"node_modules/class-validator": {
|
"node_modules/class-validator": {
|
||||||
"version": "0.14.0",
|
"version": "0.14.0",
|
||||||
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz",
|
"resolved": "https://registry.npmjs.org/class-validator/-/class-validator-0.14.0.tgz",
|
||||||
|
|
|
@ -46,6 +46,7 @@
|
||||||
"@nestjs/platform-express": "^9.0.0",
|
"@nestjs/platform-express": "^9.0.0",
|
||||||
"@nestjs/terminus": "^9.2.2",
|
"@nestjs/terminus": "^9.2.2",
|
||||||
"@prisma/client": "^4.13.0",
|
"@prisma/client": "^4.13.0",
|
||||||
|
"class-transformer": "^0.5.1",
|
||||||
"class-validator": "^0.14.0",
|
"class-validator": "^0.14.0",
|
||||||
"ioredis": "^5.3.2",
|
"ioredis": "^5.3.2",
|
||||||
"reflect-metadata": "^0.1.13",
|
"reflect-metadata": "^0.1.13",
|
||||||
|
|
|
@ -1,28 +1,34 @@
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "Frequency" AS ENUM ('PUNCTUAL', 'RECURRENT');
|
||||||
|
|
||||||
|
-- CreateEnum
|
||||||
|
CREATE TYPE "AddressType" AS ENUM ('HOUSE_NUMBER', 'STREET_ADDRESS', 'LOCALITY', 'VENUE', 'OTHER');
|
||||||
|
|
||||||
-- CreateTable
|
-- CreateTable
|
||||||
CREATE TABLE "ad" (
|
CREATE TABLE "ad" (
|
||||||
"uuid" UUID NOT NULL,
|
"uuid" UUID NOT NULL,
|
||||||
"userUuid" UUID NOT NULL,
|
"userUuid" UUID NOT NULL,
|
||||||
"driver" BOOLEAN NOT NULL,
|
"driver" BOOLEAN,
|
||||||
"passenger" BOOLEAN NOT NULL,
|
"passenger" BOOLEAN,
|
||||||
"frequency" INTEGER NOT NULL,
|
"frequency" "Frequency" NOT NULL DEFAULT 'RECURRENT',
|
||||||
"fromDate" DATE NOT NULL,
|
"fromDate" DATE NOT NULL,
|
||||||
"toDate" DATE NOT NULL,
|
"toDate" DATE,
|
||||||
"monTime" TIMESTAMPTZ NOT NULL,
|
"monTime" TIMESTAMPTZ,
|
||||||
"tueTime" TIMESTAMPTZ NOT NULL,
|
"tueTime" TIMESTAMPTZ,
|
||||||
"wedTime" TIMESTAMPTZ NOT NULL,
|
"wedTime" TIMESTAMPTZ,
|
||||||
"thuTime" TIMESTAMPTZ NOT NULL,
|
"thuTime" TIMESTAMPTZ,
|
||||||
"friTime" TIMESTAMPTZ NOT NULL,
|
"friTime" TIMESTAMPTZ,
|
||||||
"satTime" TIMESTAMPTZ NOT NULL,
|
"satTime" TIMESTAMPTZ,
|
||||||
"sunTime" TIMESTAMPTZ NOT NULL,
|
"sunTime" TIMESTAMPTZ,
|
||||||
"monMargin" INTEGER NOT NULL,
|
"monMargin" INTEGER,
|
||||||
"tueMargin" INTEGER NOT NULL,
|
"tueMargin" INTEGER,
|
||||||
"wedMargin" INTEGER NOT NULL,
|
"wedMargin" INTEGER,
|
||||||
"thuMargin" INTEGER NOT NULL,
|
"thuMargin" INTEGER,
|
||||||
"friMargin" INTEGER NOT NULL,
|
"friMargin" INTEGER,
|
||||||
"satMargin" INTEGER NOT NULL,
|
"satMargin" INTEGER,
|
||||||
"sunMargin" INTEGER NOT NULL,
|
"sunMargin" INTEGER,
|
||||||
"seatsDriver" SMALLINT NOT NULL,
|
"seatsDriver" SMALLINT,
|
||||||
"seatsPassenger" SMALLINT NOT NULL,
|
"seatsPassenger" SMALLINT,
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
@ -33,14 +39,15 @@ CREATE TABLE "ad" (
|
||||||
CREATE TABLE "address" (
|
CREATE TABLE "address" (
|
||||||
"uuid" UUID NOT NULL,
|
"uuid" UUID NOT NULL,
|
||||||
"adUuid" UUID NOT NULL,
|
"adUuid" UUID NOT NULL,
|
||||||
|
"position" SMALLINT NOT NULL,
|
||||||
"lon" DOUBLE PRECISION NOT NULL,
|
"lon" DOUBLE PRECISION NOT NULL,
|
||||||
"lat" DOUBLE PRECISION NOT NULL,
|
"lat" DOUBLE PRECISION NOT NULL,
|
||||||
"houseNumber" TEXT NOT NULL,
|
"houseNumber" TEXT,
|
||||||
"street" TEXT NOT NULL,
|
"street" TEXT,
|
||||||
"locality" TEXT NOT NULL,
|
"locality" TEXT,
|
||||||
"postalCode" TEXT NOT NULL,
|
"postalCode" TEXT,
|
||||||
"country" TEXT NOT NULL,
|
"country" TEXT,
|
||||||
"type" SMALLINT NOT NULL,
|
"type" "AddressType" DEFAULT 'OTHER',
|
||||||
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"createdAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
"updatedAt" TIMESTAMP(3) NOT NULL DEFAULT CURRENT_TIMESTAMP,
|
||||||
|
|
||||||
|
@ -60,4 +67,4 @@ CREATE INDEX "ad_fromDate_idx" ON "ad"("fromDate");
|
||||||
CREATE INDEX "ad_toDate_idx" ON "ad"("toDate");
|
CREATE INDEX "ad_toDate_idx" ON "ad"("toDate");
|
||||||
|
|
||||||
-- AddForeignKey
|
-- AddForeignKey
|
||||||
ALTER TABLE "address" ADD CONSTRAINT "address_adUuid_fkey" FOREIGN KEY ("adUuid") REFERENCES "ad"("uuid") ON DELETE RESTRICT ON UPDATE CASCADE;
|
ALTER TABLE "address" ADD CONSTRAINT "address_adUuid_fkey" FOREIGN KEY ("adUuid") REFERENCES "ad"("uuid") ON DELETE CASCADE ON UPDATE CASCADE;
|
|
@ -13,27 +13,27 @@ datasource db {
|
||||||
model Ad {
|
model Ad {
|
||||||
uuid String @id @default(uuid()) @db.Uuid
|
uuid String @id @default(uuid()) @db.Uuid
|
||||||
userUuid String @db.Uuid
|
userUuid String @db.Uuid
|
||||||
driver Boolean
|
driver Boolean?
|
||||||
passenger Boolean
|
passenger Boolean?
|
||||||
frequency Int
|
frequency Frequency @default(RECURRENT)
|
||||||
fromDate DateTime @db.Date
|
fromDate DateTime @db.Date
|
||||||
toDate DateTime @db.Date
|
toDate DateTime? @db.Date
|
||||||
monTime DateTime @db.Timestamptz()
|
monTime DateTime? @db.Timestamptz()
|
||||||
tueTime DateTime @db.Timestamptz()
|
tueTime DateTime? @db.Timestamptz()
|
||||||
wedTime DateTime @db.Timestamptz()
|
wedTime DateTime? @db.Timestamptz()
|
||||||
thuTime DateTime @db.Timestamptz()
|
thuTime DateTime? @db.Timestamptz()
|
||||||
friTime DateTime @db.Timestamptz()
|
friTime DateTime? @db.Timestamptz()
|
||||||
satTime DateTime @db.Timestamptz()
|
satTime DateTime? @db.Timestamptz()
|
||||||
sunTime DateTime @db.Timestamptz()
|
sunTime DateTime? @db.Timestamptz()
|
||||||
monMargin Int
|
monMargin Int?
|
||||||
tueMargin Int
|
tueMargin Int?
|
||||||
wedMargin Int
|
wedMargin Int?
|
||||||
thuMargin Int
|
thuMargin Int?
|
||||||
friMargin Int
|
friMargin Int?
|
||||||
satMargin Int
|
satMargin Int?
|
||||||
sunMargin Int
|
sunMargin Int?
|
||||||
seatsDriver Int @db.SmallInt
|
seatsDriver Int? @db.SmallInt
|
||||||
seatsPassenger Int @db.SmallInt
|
seatsPassenger Int? @db.SmallInt
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
addresses Address[]
|
addresses Address[]
|
||||||
|
@ -48,17 +48,31 @@ model Ad {
|
||||||
model Address {
|
model Address {
|
||||||
uuid String @id @default(uuid()) @db.Uuid
|
uuid String @id @default(uuid()) @db.Uuid
|
||||||
adUuid String @db.Uuid
|
adUuid String @db.Uuid
|
||||||
|
position Int @db.SmallInt
|
||||||
lon Float
|
lon Float
|
||||||
lat Float
|
lat Float
|
||||||
houseNumber String
|
houseNumber String?
|
||||||
street String
|
street String?
|
||||||
locality String
|
locality String?
|
||||||
postalCode String
|
postalCode String?
|
||||||
country String
|
country String?
|
||||||
type Int @db.SmallInt
|
type AddressType? @default(OTHER)
|
||||||
createdAt DateTime @default(now())
|
createdAt DateTime @default(now())
|
||||||
updatedAt DateTime @default(now()) @updatedAt
|
updatedAt DateTime @default(now()) @updatedAt
|
||||||
Ad Ad @relation(fields: [adUuid], references: [uuid])
|
Ad Ad @relation(fields: [adUuid], references: [uuid], onDelete: Cascade)
|
||||||
|
|
||||||
@@map("address")
|
@@map("address")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
enum Frequency {
|
||||||
|
PUNCTUAL
|
||||||
|
RECURRENT
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AddressType {
|
||||||
|
HOUSE_NUMBER
|
||||||
|
STREET_ADDRESS
|
||||||
|
LOCALITY
|
||||||
|
VENUE
|
||||||
|
OTHER
|
||||||
|
}
|
||||||
|
|
|
@ -3,10 +3,13 @@ import { ConfigModule } from '@nestjs/config';
|
||||||
import { ConfigurationModule } from './modules/configuration/configuration.module';
|
import { ConfigurationModule } from './modules/configuration/configuration.module';
|
||||||
import { HealthModule } from './modules/health/health.module';
|
import { HealthModule } from './modules/health/health.module';
|
||||||
import { AdModule } from './modules/ad/ad.module';
|
import { AdModule } from './modules/ad/ad.module';
|
||||||
|
import { AutomapperModule } from '@automapper/nestjs';
|
||||||
|
import { classes } from '@automapper/classes';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
ConfigModule.forRoot({ isGlobal: true }),
|
ConfigModule.forRoot({ isGlobal: true }),
|
||||||
|
AutomapperModule.forRoot({ strategyInitializer: classes() }),
|
||||||
ConfigurationModule,
|
ConfigurationModule,
|
||||||
HealthModule,
|
HealthModule,
|
||||||
AdModule,
|
AdModule,
|
||||||
|
|
|
@ -11,10 +11,9 @@ async function bootstrap() {
|
||||||
app.connectMicroservice<MicroserviceOptions>({
|
app.connectMicroservice<MicroserviceOptions>({
|
||||||
transport: Transport.GRPC,
|
transport: Transport.GRPC,
|
||||||
options: {
|
options: {
|
||||||
// package: ['ad', 'health'],
|
package: ['ad', 'health'],
|
||||||
package: ['health'],
|
|
||||||
protoPath: [
|
protoPath: [
|
||||||
// join(__dirname, 'modules/ad/adapters/primaries/ad.proto'),
|
join(__dirname, 'modules/ad/adapters/primaries/ad.proto'),
|
||||||
join(__dirname, 'modules/health/adapters/primaries/health.proto'),
|
join(__dirname, 'modules/health/adapters/primaries/health.proto'),
|
||||||
],
|
],
|
||||||
url: process.env.SERVICE_URL + ':' + process.env.SERVICE_PORT,
|
url: process.env.SERVICE_URL + ':' + process.env.SERVICE_PORT,
|
||||||
|
|
|
@ -1,8 +1,34 @@
|
||||||
import { Module } from '@nestjs/common';
|
import { Module } from '@nestjs/common';
|
||||||
|
import { AdController } from './adapters/primaries/ad.controller';
|
||||||
|
import { DatabaseModule } from '../database/database.module';
|
||||||
|
import { CqrsModule } from '@nestjs/cqrs';
|
||||||
|
import { RabbitMQModule } from '@golevelup/nestjs-rabbitmq';
|
||||||
|
import { ConfigModule, ConfigService } from '@nestjs/config';
|
||||||
|
import { AdProfile } from './mappers/ad.profile';
|
||||||
|
import { AdsRepository } from './adapters/secondaries/ads.repository';
|
||||||
|
import { Messager } from './adapters/secondaries/messager';
|
||||||
|
import { FindAdByUuidUseCase } from './domain/usecases/find-ad-by-uuid.usecase';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [],
|
imports: [
|
||||||
controllers: [],
|
DatabaseModule,
|
||||||
providers: [],
|
CqrsModule,
|
||||||
|
RabbitMQModule.forRootAsync(RabbitMQModule, {
|
||||||
|
imports: [ConfigModule],
|
||||||
|
useFactory: async (configService: ConfigService) => ({
|
||||||
|
exchanges: [
|
||||||
|
{
|
||||||
|
name: configService.get<string>('RMQ_EXCHANGE'),
|
||||||
|
type: 'topic',
|
||||||
|
},
|
||||||
|
],
|
||||||
|
uri: configService.get<string>('RMQ_URI'),
|
||||||
|
connectionInitOptions: { wait: false },
|
||||||
|
}),
|
||||||
|
inject: [ConfigService],
|
||||||
|
}),
|
||||||
|
],
|
||||||
|
controllers: [AdController],
|
||||||
|
providers: [AdProfile, AdsRepository, Messager, FindAdByUuidUseCase],
|
||||||
})
|
})
|
||||||
export class AdModule {}
|
export class AdModule {}
|
||||||
|
|
|
@ -0,0 +1,38 @@
|
||||||
|
import { Mapper } from '@automapper/core';
|
||||||
|
import { InjectMapper } from '@automapper/nestjs';
|
||||||
|
import { Controller, UsePipes } from '@nestjs/common';
|
||||||
|
import { QueryBus } from '@nestjs/cqrs';
|
||||||
|
import { GrpcMethod, RpcException } from '@nestjs/microservices';
|
||||||
|
import { RpcValidationPipe } from '../../../../utils/pipes/rpc.validation-pipe';
|
||||||
|
import { FindAdByUuidRequest } from '../../domain/dtos/find-ad-by-uuid.request';
|
||||||
|
import { AdPresenter } from './ad.presenter';
|
||||||
|
import { FindAdByUuidQuery } from '../../queries/find-ad-by-uuid.query';
|
||||||
|
import { Ad } from '../../domain/entities/ad';
|
||||||
|
|
||||||
|
@UsePipes(
|
||||||
|
new RpcValidationPipe({
|
||||||
|
whitelist: false,
|
||||||
|
forbidUnknownValues: false,
|
||||||
|
}),
|
||||||
|
)
|
||||||
|
@Controller()
|
||||||
|
export class AdController {
|
||||||
|
constructor(
|
||||||
|
private readonly queryBus: QueryBus,
|
||||||
|
@InjectMapper() private readonly _mapper: Mapper,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@GrpcMethod('AdsService', 'FindOneByUuid')
|
||||||
|
async findOnebyUuid(data: FindAdByUuidRequest): Promise<AdPresenter> {
|
||||||
|
try {
|
||||||
|
console.log('ici');
|
||||||
|
const ad = await this.queryBus.execute(new FindAdByUuidQuery(data));
|
||||||
|
return this._mapper.map(ad, Ad, AdPresenter);
|
||||||
|
} catch (e) {
|
||||||
|
throw new RpcException({
|
||||||
|
code: e.code,
|
||||||
|
message: e.message,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { AutoMap } from '@automapper/classes';
|
||||||
|
|
||||||
|
export class AdPresenter {
|
||||||
|
@AutoMap()
|
||||||
|
uuid: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
|
driver: boolean;
|
||||||
|
}
|
|
@ -0,0 +1,86 @@
|
||||||
|
syntax = "proto3";
|
||||||
|
|
||||||
|
package ad;
|
||||||
|
|
||||||
|
service AdsService {
|
||||||
|
rpc FindOneByUuid(AdByUuid) returns (Ad);
|
||||||
|
rpc FindAll(AdFilter) returns (Ads);
|
||||||
|
rpc Create(Ad) returns (Ad);
|
||||||
|
rpc Update(Ad) returns (Ad);
|
||||||
|
rpc Delete(AdByUuid) returns (Empty);
|
||||||
|
}
|
||||||
|
|
||||||
|
message AdByUuid {
|
||||||
|
string uuid = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Ad {
|
||||||
|
string uuid = 1;
|
||||||
|
string userUuid = 2;
|
||||||
|
bool driver = 3;
|
||||||
|
bool passenger = 4;
|
||||||
|
int32 frequency = 5;
|
||||||
|
string fromDate = 6;
|
||||||
|
string toDate = 7;
|
||||||
|
Schedule schedule = 8;
|
||||||
|
MarginDurations marginDurations = 9;
|
||||||
|
int32 seatsPassenger = 10;
|
||||||
|
int32 seatsDriver = 11;
|
||||||
|
bool strict = 12;
|
||||||
|
Addresses addresses = 13;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Schedule {
|
||||||
|
string mon = 1;
|
||||||
|
string tue = 2;
|
||||||
|
string wed = 3;
|
||||||
|
string thu = 4;
|
||||||
|
string fri = 5;
|
||||||
|
string sat = 6;
|
||||||
|
string sun = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message MarginDurations {
|
||||||
|
int32 mon = 1;
|
||||||
|
int32 tue = 2;
|
||||||
|
int32 wed = 3;
|
||||||
|
int32 thu = 4;
|
||||||
|
int32 fri = 5;
|
||||||
|
int32 sat = 6;
|
||||||
|
int32 sun = 7;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Addresses {
|
||||||
|
repeated Address address = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Address {
|
||||||
|
float lon = 1;
|
||||||
|
float lat = 2;
|
||||||
|
string houseNumber = 3;
|
||||||
|
string street = 4;
|
||||||
|
string locality = 5;
|
||||||
|
string postalCode = 6;
|
||||||
|
string country = 7;
|
||||||
|
AddressType type = 8;
|
||||||
|
}
|
||||||
|
|
||||||
|
enum AddressType {
|
||||||
|
HOUSE_NUMBER = 1;
|
||||||
|
STREET_ADDRESS = 2;
|
||||||
|
LOCALITY = 3;
|
||||||
|
VENUE = 4;
|
||||||
|
OTHER = 5;
|
||||||
|
}
|
||||||
|
|
||||||
|
message AdFilter {
|
||||||
|
optional int32 page = 1;
|
||||||
|
optional int32 perPage = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Ads {
|
||||||
|
repeated Ad data = 1;
|
||||||
|
int32 total = 2;
|
||||||
|
}
|
||||||
|
|
||||||
|
message Empty {}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { AmqpConnection } from '@golevelup/nestjs-rabbitmq';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { ConfigService } from '@nestjs/config';
|
||||||
|
import { IMessageBroker } from '../../domain/interfaces/message-broker';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class Messager extends IMessageBroker {
|
||||||
|
constructor(
|
||||||
|
private readonly _amqpConnection: AmqpConnection,
|
||||||
|
configService: ConfigService,
|
||||||
|
) {
|
||||||
|
super(configService.get<string>('RMQ_EXCHANGE'));
|
||||||
|
}
|
||||||
|
|
||||||
|
publish(routingKey: string, message: string): void {
|
||||||
|
this._amqpConnection.publish(this.exchange, routingKey, message);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
import { IsNotEmpty, IsString } from 'class-validator';
|
||||||
|
|
||||||
|
export class FindAdByUuidRequest {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
uuid: string;
|
||||||
|
}
|
|
@ -3,4 +3,7 @@ import { AutoMap } from '@automapper/classes';
|
||||||
export class Ad {
|
export class Ad {
|
||||||
@AutoMap()
|
@AutoMap()
|
||||||
uuid: string;
|
uuid: string;
|
||||||
|
|
||||||
|
@AutoMap()
|
||||||
|
driver: boolean;
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,12 @@
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export abstract class IMessageBroker {
|
||||||
|
exchange: string;
|
||||||
|
|
||||||
|
constructor(exchange: string) {
|
||||||
|
this.exchange = exchange;
|
||||||
|
}
|
||||||
|
|
||||||
|
abstract publish(routingKey: string, message: string): void;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
import { NotFoundException } from '@nestjs/common';
|
||||||
|
import { QueryHandler } from '@nestjs/cqrs';
|
||||||
|
import { FindAdByUuidQuery } from '../../queries/find-ad-by-uuid.query';
|
||||||
|
import { AdsRepository } from '../../adapters/secondaries/ads.repository';
|
||||||
|
import { Messager } from '../../adapters/secondaries/messager';
|
||||||
|
import { Ad } from '../entities/ad';
|
||||||
|
|
||||||
|
@QueryHandler(FindAdByUuidQuery)
|
||||||
|
export class FindAdByUuidUseCase {
|
||||||
|
constructor(
|
||||||
|
private readonly repository: AdsRepository,
|
||||||
|
private readonly messager: Messager,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
async execute(findAdByUuid: FindAdByUuidQuery): Promise<Ad> {
|
||||||
|
try {
|
||||||
|
const ad = await this.repository.findOneByUuid(findAdByUuid.uuid);
|
||||||
|
if (!ad) throw new NotFoundException();
|
||||||
|
return ad;
|
||||||
|
} catch (error) {
|
||||||
|
this.messager.publish(
|
||||||
|
'logging.ad.read.warning',
|
||||||
|
JSON.stringify({
|
||||||
|
query: findAdByUuid,
|
||||||
|
error,
|
||||||
|
}),
|
||||||
|
);
|
||||||
|
throw error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,18 @@
|
||||||
|
import { createMap, Mapper } from '@automapper/core';
|
||||||
|
import { AutomapperProfile, InjectMapper } from '@automapper/nestjs';
|
||||||
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { Ad } from '../domain/entities/ad';
|
||||||
|
import { AdPresenter } from '../adapters/primaries/ad.presenter';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class AdProfile extends AutomapperProfile {
|
||||||
|
constructor(@InjectMapper() mapper: Mapper) {
|
||||||
|
super(mapper);
|
||||||
|
}
|
||||||
|
|
||||||
|
override get profile() {
|
||||||
|
return (mapper) => {
|
||||||
|
createMap(mapper, Ad, AdPresenter);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
import { FindAdByUuidRequest } from '../domain/dtos/find-ad-by-uuid.request';
|
||||||
|
|
||||||
|
export class FindAdByUuidQuery {
|
||||||
|
readonly uuid: string;
|
||||||
|
|
||||||
|
constructor(findAdByUuidRequest: FindAdByUuidRequest) {
|
||||||
|
this.uuid = findAdByUuidRequest.uuid;
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue