Passed
Push — development ( cae74d...4e024d )
by Peter
09:26 queued 14s
created

BicyclesService.updatePositionsParallel   A

Complexity

Conditions 3

Size

Total Lines 30
Code Lines 23

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 9.3211

Importance

Changes 0
Metric Value
cc 3
eloc 23
dl 0
loc 30
ccs 1
cts 9
cp 0.1111
crap 9.3211
rs 9.328
c 0
b 0
f 0
1 11
import { Injectable } from '@nestjs/common';
2 11
import { InjectRepository } from '@nestjs/typeorm';
3 11
import { Repository } from 'typeorm';
4 11
import { Bicycle } from './entities/bicycle.entity';
5 11
import { NotFoundException } from '@nestjs/common';
0 ignored issues
show
introduced by
'@nestjs/common' import is duplicated.
Loading history...
6
import { UpdateBicycleDto } from './dto/update-bicycle.dto';
7
import { BicycleResponse } from './types/bicycle-response.interface';
8 11
import { getDistance } from 'src/utils/geo.utils';
9
import { CreateBicycleDto } from './dto/create-bicycle.dto';
10 11
import { City } from 'src/cities/entities/city.entity';
11 11
import { CityName } from 'src/cities/types/city.enum';
12
import { BicyclePositionDto } from './dto/batch-update.dto';
13
import { BicycleBatchResponse } from './types/BicycleBatchResponse';
14
15
@Injectable()
16 11
export class BicyclesService {
17
0 ignored issues
show
introduced by
Delete
Loading history...
18
  async updatePositionsParallel(updates: BicyclePositionDto[]): Promise<BicycleBatchResponse[]> {
19
    const updatePromises = updates.map(async (update) => {
20
      try {
21
        const bicycle = await this.bicycleRepository.findOne({
22
          where: { id: update.id }
0 ignored issues
show
introduced by
Insert ,
Loading history...
23
        });
24
25 1
        if (!bicycle) {
26
          return {
27
            id: update.id,
28
            success: false,
29
            error: `Bicycle with id ${update.id} not found`
0 ignored issues
show
introduced by
Insert ,
Loading history...
30
          };
31
        }
32
33
        await this.bicycleRepository.update(
0 ignored issues
show
introduced by
Replace ⏎··········u...d,⏎········· with update.id,
Loading history...
34
          update.id,
35
          {
36
            latitude: update.latitude,
0 ignored issues
show
introduced by
Delete ··
Loading history...
37
            longitude: update.longitude,
0 ignored issues
show
introduced by
Delete ··
Loading history...
38
          }
0 ignored issues
show
introduced by
Replace ··········}⏎········ with ········}
Loading history...
39
        );
40
        return { id: update.id, success: true };
41
      } catch (error) {
42
        return { id: update.id, success: false, error: error.message };
43
      }
44
    });
45
46
    return await Promise.all(updatePromises);
47
  }
48
  constructor(
49
    @InjectRepository(Bicycle)
50 5
    private readonly bicycleRepository: Repository<Bicycle>,
51
    @InjectRepository(City)
52 5
    private cityRepository: Repository<City>,
53
  ) { }
0 ignored issues
show
introduced by
Delete ·
Loading history...
54
55
  async findAll(): Promise<Bicycle[]> {
56
    const bikes = await this.bicycleRepository.find({
57
      relations: {
58
        city: true,
59
      },
60
      select: {
61
        id: true,
62
        batteryLevel: true,
63
        latitude: true,
64
        longitude: true,
65
        status: true,
66
        createdAt: true,
67
        updatedAt: true,
68
        city: {
69
          name: true,
70
        },
71
      },
72
    });
73
74
    return bikes;
75
  }
76
77
  async setRented(bikeId: string): Promise<Bicycle> {
78 2
    const result = await this.bicycleRepository.update(
79
      { id: bikeId, status: 'Available' },
80
      { status: 'Rented' },
81
    );
82 2
    if (result.affected === 0) {
83 1
      throw new NotFoundException(
84
        "Bike couldn't be rented. Bike might not exist or it is not available.",
85
      );
86
    }
87 1
    return await this.findById(bikeId);
88
  }
89
90
  async createBike(createBicycleDto: CreateBicycleDto): Promise<Bicycle> {
91
    const bike = this.bicycleRepository.create({
92
      batteryLevel: createBicycleDto.batteryLevel ?? 100,
93
      latitude: createBicycleDto.latitude,
94
      longitude: createBicycleDto.longitude,
95
      status: createBicycleDto.status ?? 'Available',
96
    });
97
98 2
    const city = createBicycleDto.city ?? 'Göteborg';
99
    // Find the city by name
100
    const cityEntity = await this.cityRepository.findOne({
101
      where: { name: city as CityName },
102
    });
103
104 1
    if (cityEntity) {
105
      bike.city = cityEntity;
106
    }
107
108
    return await this.bicycleRepository.save(bike);
109
  }
110
111
  async createManyBikes(createBicycleDto: CreateBicycleDto[]): Promise<Bicycle[]> {
112
    const defaultCity = await this.cityRepository.findOne({
113
      where: { name: CityName.Göteborg }
0 ignored issues
show
introduced by
Insert ,
Loading history...
114
    });
115
    const Karlshamn = await this.cityRepository.findOne({
116
      where: { name: CityName.Karlshamn }
0 ignored issues
show
introduced by
Insert ,
Loading history...
117
    });
118
    const Jönköping = await this.cityRepository.findOne({
119
      where: { name: CityName.Jönköping }
0 ignored issues
show
introduced by
Insert ,
Loading history...
120
    });
121
122
    const bikes = createBicycleDto.map((bike) => {
123
      return this.bicycleRepository.create({
124
        batteryLevel: bike.batteryLevel ?? 100,
125
        latitude: bike.latitude,
126
        longitude: bike.longitude,
127
        status: bike.status ?? 'Available',
128
        city:
129
          bike.city === 'Jönköping'
130
            ? Jönköping
131
            : bike.city === 'Karlshamn'
132
              ? Karlshamn
133
              : defaultCity,
134
      });
135
    });
136
137
    return await this.bicycleRepository.save(bikes);
138
  }
139
140
  async findById(id: string): Promise<Bicycle> {
141
    const bike = await this.bicycleRepository.findOne({
142
      where: { id },
143
      relations: {
144
        city: true,
145
      },
146
    });
147 1
    if (!bike) {
148
      throw new NotFoundException('Bike not found');
149
    }
150
    return bike;
151
  }
152
153
  async update(id: string, updateBicycleDto: UpdateBicycleDto): Promise<Bicycle> {
154
    const bike = await this.findById(id);
155
156
    return this.bicycleRepository.save({ ...bike, ...updateBicycleDto });
157
  }
158
159
  async findByCity(cityName: CityName): Promise<Bicycle[]> {
160
    const bikes = await this.bicycleRepository.find({
161
      where: {
162
        city: {
163
          name: cityName,
164
        },
165
      },
166
      relations: ['city'],
167
    });
168
169
    return bikes;
170
  }
171
  async findByLocation(lat: number, lon: number, radius: number): Promise<Bicycle[]> {
172
    const allBikes = await this.findAll();
173
    const filteredBikes = allBikes.filter((bike) => {
174
      return getDistance(bike.latitude, bike.longitude, lat, lon) <= radius;
175
    });
176
    return filteredBikes;
177
  }
178
  async findByCityAndLocation(
179
    city: any,
180
    lat: number,
181
    lon: number,
182
    radius: number,
183
  ): Promise<Bicycle[]> {
184 2
    const bikesInCity = await this.findByCity(city);
185 2
    const filteredBikes = bikesInCity.filter((bike) => {
186 1
      return getDistance(bike.latitude, bike.longitude, lat, lon) <= radius;
187
    });
188 2
    return filteredBikes;
189
  }
190
191
  private toBicycleResponse(bike: Bicycle): BicycleResponse {
192
    return {
193
      id: bike.id,
194
      batteryLevel: bike.batteryLevel,
195
      latitude: bike.latitude,
196
      longitude: bike.longitude,
197
      status: bike.status,
198
      city: bike.city?.name,
199
      createdAt: bike.createdAt,
200
      updatedAt: bike.updatedAt,
201
    };
202
  }
203
204
  toBicycleResponses(bikes: Bicycle[]): BicycleResponse[] {
205
    return bikes.map((bike) => this.toBicycleResponse(bike));
206
  }
207
}
208