server/src/models/bike.js   A
last analyzed

Complexity

Total Complexity 18
Complexity/F 1.2

Size

Lines of Code 213
Function Count 15

Duplication

Duplicated Lines 0
Ratio 0 %

Test Coverage

Coverage 100%

Importance

Changes 0
Metric Value
wmc 18
eloc 65
mnd 3
bc 3
fnc 15
dl 0
loc 213
ccs 34
cts 34
cp 1
bpm 0.2
cpm 1.2
noi 0
c 0
b 0
f 0
rs 10
1
import { db } from "./db.js"
2
import tripModel from "./trip.js"
3
import apiModel from "./api-key.js"
4
5
6 1
const bike = {
7
    /**
8
     * All params except integers
9
     * are returned from DB as wrong type,
10
     * mostly as string values.
11
     * This function converts those
12
     * attributes to correct types
13
     * @param {Object} bikeObj 
14
     * @returns the bike object with type-corrected
15
     * attributes
16
     */
17
    adjTypes: function(bikeObj) {
18 38
        return {
19
            id: bikeObj.id,
20
            city_id: bikeObj.city_id,
21
            status_id: bikeObj.status_id,
22
            status_descr: bikeObj.status_descr,
23
            charge_perc: parseFloat(bikeObj.charge_perc),
24
            coords: JSON.parse(bikeObj.coords),
25
            active: bikeObj.active === 1,
26
        };
27
    },
28
    /**
29
     * Returns true if the bike has an
30
     * ongoing trip, otherwise returns
31
     * false
32
     * @param {Number} bikeId
33
     * @returns {Promise<Boolean>}
34
     */
35
    isRented: async function(bikeId) {
36 21
        const result = await db.queryWithArgs(`CALL is_rented(?);`, [bikeId]);
37 21
        if (result[0][0]) {
38 12
            return true;
39
        }
40 9
        return false;
41
    },
42
    /**
43
     * To be used by admin for deactivating
44
     * a bike. Deactivating a bike
45
     * changes the value of active from
46
     * true to false. Any ongoing trip
47
     * will be ended. The status_id of
48
     * the bike will only be
49
     * changed if current status is
50
     * rented -> in this case it will
51
     * be changed to 1 - available.
52
     * 
53
     * Returns a object with a bike
54
     * object: id, city_id, status_id,
55
     * status_descr, charge_perc (0.00-1.00),
56
     * coords (array<float>) and active
57
     * (bool). If an ongoing trip
58
     * was ended, also the trip-object:
59
     * 
60
     * @param {Number} bikeId
61
     * @returns {Promise<Object>}
62
     */
63
    deactivate: async function(bikeId) {
64 3
        const result = await db.queryWithArgs(`CALL deactivate(?);`, [bikeId]);
65
        // if there is a trip db query returns
66
        // a resultset of three elements
67 3
        if (result.length > 2) {
68 1
            return {
69
                bike: this.adjTypes(result[1][0]),
70
                trip: tripModel.adjTypes(result[0][0])
71
            };
72
        }
73
        // if there is no ongoing trip the
74
        // resultset from db contains two elements
75 2
        return {
76
            bike: this.adjTypes(result[0][0])
77
        };
78
    },
79
    /**
80
     * Changes a bikes active attribute
81
     * to true and returns a bike-object:
82
     * id, city_id, status_id,
83
     * status_descr, charge_perc (0.00-1.00),
84
     * coords (array<float>) and active
85
     * (bool).
86
     * @param {Number} bikeId
87
     * @returns {Promise<Object>}
88
     */
89
    activate: async function(bikeId) {
90 2
        const result = await db.queryWithArgs(`CALL activate(?);`, [bikeId]);
91 2
        return this.adjTypes(result[0][0]);
92
    },
93
    /**
94
     * Returns a bike object:
95
     * id (int), city_id (string), status_id (int),
96
     * status_descr (string), charge_perc (float 0.00-1.00),
97
     * coords (array), active (bool)
98
     * @param {Number} bikeId
99
     * @returns {Promise<Object>}
100
     */
101
    getOne: async function(bikeId) {
102 19
        const result = await db.queryWithArgs(`CALL single_bike(?);`, [bikeId]);
103
104 19
        return this.adjTypes(result[0][0]);
105
    },
106
107
    /**
108
     * Returns all bikes regardless
109
     * of status_id, including
110
     * inactive and unavailable ones.
111
     * @returns {Promise<Array>}
112
     */
113
    getAll: async function() {
114 1
        const result = await db.queryNoArgs(`CALL all_bikes();`);
115 1
        return result[0].map((bikeObj) => {
116 3
            return this.adjTypes(bikeObj);
117
        });
118
    },
119
120
    /**
121
     * Returns only available bikes in one
122
     * city (for ordinary users)
123
     * @param {String} cityId
124
     * @returns {Promise<Array>}
125
     */
126
    getAvail: async function(cityId) {
127 2
        const result = await db.queryWithArgs(`CALL available_bikes(?);`, [cityId]);
128 2
        return result[0].map((bikeObj) => {
129 1
            return this.adjTypes(bikeObj);
130
        });
131
    },
132
133
    /**
134
     * Returns all bikes in one city (for admin)
135
     * @param {String} cityId
136
     * @returns {Promise<Array>}
137
     */
138
    getAllInCity: async function(cityId) {
139 2
            const result = await db.queryWithArgs(`CALL bikes_in_city(?);`, [cityId]);
140 2
            return result[0].map((bikeObj) => {
141 2
                return this.adjTypes(bikeObj);
142
        });
143
    },
144
    /**
145
     * An array with all available statuses.
146
     * Each status object contains id and descr
147
     * @returns {Promise<Array>}
148
     */
149
    statuses: async function() {
150 1
        const result = await db.queryNoArgs(`CALL bike_statuses();`);
151 1
        return result[0];
152
    },
153
154
    /**
155
     * Updates status_id of a bike,
156
     * returns the updated bike-object:
157
     * id, city_id, status_id, status_descr,
158
     * charge_perc, coords, active (bool)
159
     * @param {Number} bikeId
160
     * @param {Number} statusId
161
     * @returns {Promise<Object>}
162
     */
163
    updStatus: async function(bikeId, statusId) {
164 6
        const result = await db.queryWithArgs(`CALL upd_bike_status(?, ?);`, [bikeId, statusId]);
165 6
        return this.adjTypes(result[0][0]);
166
    },
167
168
    /**
169
     * Updates the city_id of a bike,
170
     * returns the updated bike-object:
171
     * id, city_id, status_id, status_descr,
172
     * charge_perc, coords, active (bool)
173
     * @param {Number} bikeId
174
     * @param {String} cityId
175
     * @returns {Promise<Object>}
176
     */
177
    updCity: async function(bikeId, cityId) {
178 3
        const result = await db.queryWithArgs(`CALL update_bike_city(?, ?);`, [bikeId, cityId]);
179 2
        return this.adjTypes(result[0][0]);
180
    },
181
182
    /**
183
     * Updates the bikes status,
184
     * charge percentrage and
185
     * coordinates.
186
     * Does not return anything
187
     * @param {Number} bikeId
188
     * @param {Number} bikeStatus
189
     * @param {Number} chargePerc
190
     * @param {Array} bikeCoords
191
     */
192
    updateBike: async function(
193
        bikeId,
194
        bikeStatus,
195
        chargePerc,
196
        bikeCoords,
197
        apiKey
198
    ) {
199
        // this method will throw an error if the apiKey does
200
        // not belong to a bike
201 15
        apiModel.isBikeKey(apiKey);
202
203 14
        const endedTrip = await db.queryWithArgs(`CALL update_bike(?, ?, ?, ?);`, [bikeId, bikeStatus, chargePerc, JSON.stringify(bikeCoords)]);
204 12
        if (endedTrip.length > 0) {
205 2
            return tripModel.adjTypes(endedTrip[0][0]);
206
        }
207 10
        return undefined;
208
    }
209
210
211
}
212
213
export default bike;