@vulog/aima-vehicle 1.2.5 → 1.2.7

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vulog/aima-vehicle",
3
- "version": "1.2.5",
3
+ "version": "1.2.7",
4
4
  "main": "dist/index.js",
5
5
  "module": "dist/index.mjs",
6
6
  "types": "dist/index.d.ts",
@@ -19,8 +19,8 @@
19
19
  "author": "Vulog",
20
20
  "license": "MIT",
21
21
  "dependencies": {
22
- "@vulog/aima-client": "1.2.5",
23
- "@vulog/aima-core": "1.2.5"
22
+ "@vulog/aima-client": "1.2.7",
23
+ "@vulog/aima-core": "1.2.7"
24
24
  },
25
25
  "peerDependencies": {
26
26
  "zod": "^3.25.76"
@@ -0,0 +1,193 @@
1
+ import { describe, test, vi, expect, beforeEach } from 'vitest';
2
+ import { Client } from '@vulog/aima-client';
3
+ import { getModelVehicles } from './getModelVehicles';
4
+ import { ModelVehicle } from './types';
5
+
6
+ describe('getModelVehicles', () => {
7
+ const getMock = vi.fn();
8
+ const client = {
9
+ get: getMock,
10
+ clientOptions: {
11
+ fleetId: 'FLEET_ID',
12
+ },
13
+ } as unknown as Client;
14
+
15
+ beforeEach(() => {
16
+ vi.clearAllMocks();
17
+ });
18
+
19
+ test('should return model vehicles with default options', async () => {
20
+ const mockData: ModelVehicle[] = [
21
+ {
22
+ serviceId: 'service-1',
23
+ serviceVisibility: 'PUBLIC',
24
+ modelId: 1,
25
+ vehicles: ['vehicle-1', 'vehicle-2'],
26
+ },
27
+ {
28
+ serviceId: 'service-2',
29
+ serviceVisibility: 'PRIVATE',
30
+ modelId: 2,
31
+ vehicles: ['vehicle-3'],
32
+ },
33
+ ];
34
+
35
+ const mockHeaders = {
36
+ number: 0,
37
+ size: 100,
38
+ totalelements: 2,
39
+ totalpages: 1,
40
+ };
41
+
42
+ getMock.mockResolvedValueOnce({
43
+ data: mockData,
44
+ headers: mockHeaders,
45
+ });
46
+
47
+ const result = await getModelVehicles(client);
48
+
49
+ expect(result).toEqual({
50
+ data: mockData,
51
+ page: 0,
52
+ pageSize: 100,
53
+ total: 2,
54
+ totalPages: 1,
55
+ });
56
+
57
+ expect(getMock).toHaveBeenCalledWith(
58
+ expect.stringContaining('boapi/proxy/user/vehicle/fleets/FLEET_ID/vehicles/models/modelvehicles')
59
+ );
60
+
61
+ const calledUrl = getMock.mock.calls[0][0];
62
+ const url = new URL(calledUrl, 'http://example.com');
63
+ expect(url.searchParams.get('page')).toBe('0');
64
+ expect(url.searchParams.get('pageSize')).toBe('100');
65
+ // sort is not provided in default options, so it should not be in URL
66
+ expect(url.searchParams.get('sort')).toBe(null);
67
+ });
68
+
69
+ test('should return model vehicles with custom options', async () => {
70
+ const mockData: ModelVehicle[] = [
71
+ {
72
+ serviceId: 'service-1',
73
+ serviceVisibility: 'PUBLIC',
74
+ modelId: 1,
75
+ vehicles: ['vehicle-1'],
76
+ },
77
+ ];
78
+
79
+ const mockHeaders = {
80
+ number: 1,
81
+ size: 50,
82
+ totalelements: 10,
83
+ totalpages: 1,
84
+ };
85
+
86
+ getMock.mockResolvedValueOnce({
87
+ data: mockData,
88
+ headers: mockHeaders,
89
+ });
90
+
91
+ const options = {
92
+ page: 1,
93
+ pageSize: 50,
94
+ sort: 'modelId',
95
+ sortDirection: 'DESC' as const,
96
+ };
97
+
98
+ const result = await getModelVehicles(client, options);
99
+
100
+ expect(result).toEqual({
101
+ data: mockData,
102
+ page: 1,
103
+ pageSize: 50,
104
+ total: 10,
105
+ totalPages: 1,
106
+ });
107
+
108
+ const calledUrl = getMock.mock.calls[0][0];
109
+ const url = new URL(calledUrl, 'http://example.com');
110
+ expect(url.searchParams.get('page')).toBe('1');
111
+ expect(url.searchParams.get('pageSize')).toBe('50');
112
+ expect(url.searchParams.get('sort')).toBe('modelId,DESC');
113
+ });
114
+
115
+ test('should handle default filters as empty object', async () => {
116
+ const mockData: ModelVehicle[] = [];
117
+ const mockHeaders = {
118
+ number: 0,
119
+ size: 100,
120
+ totalelements: 0,
121
+ totalpages: 0,
122
+ };
123
+
124
+ getMock.mockResolvedValueOnce({
125
+ data: mockData,
126
+ headers: mockHeaders,
127
+ });
128
+
129
+ const result = await getModelVehicles(client);
130
+
131
+ expect(result).toEqual({
132
+ data: mockData,
133
+ page: 0,
134
+ pageSize: 100,
135
+ total: 0,
136
+ totalPages: 0,
137
+ });
138
+
139
+ const calledUrl = getMock.mock.calls[0][0];
140
+ const url = new URL(calledUrl, 'http://example.com');
141
+ // Should only have page and pageSize parameters since sort and filters are not provided
142
+ expect(url.searchParams.toString()).toBe('page=0&pageSize=100');
143
+ });
144
+
145
+ test('should throw error for invalid page number', async () => {
146
+ const options = {
147
+ page: -1, // Invalid: negative page number
148
+ };
149
+
150
+ await expect(getModelVehicles(client, options)).rejects.toThrow('Invalid options');
151
+ });
152
+
153
+ test('should throw error for invalid page size', async () => {
154
+ const options = {
155
+ pageSize: 0, // Invalid: page size must be positive
156
+ };
157
+
158
+ await expect(getModelVehicles(client, options)).rejects.toThrow('Invalid options');
159
+ });
160
+
161
+ test('should throw error for invalid sort direction', async () => {
162
+ const options = {
163
+ sortDirection: 'INVALID' as any, // Invalid: not ASC or DESC
164
+ };
165
+
166
+ await expect(getModelVehicles(client, options)).rejects.toThrow('Invalid options');
167
+ });
168
+
169
+ test('should handle empty response', async () => {
170
+ const mockData: ModelVehicle[] = [];
171
+ const mockHeaders = {
172
+ number: 0,
173
+ size: 100,
174
+ totalelements: 0,
175
+ totalpages: 0,
176
+ };
177
+
178
+ getMock.mockResolvedValueOnce({
179
+ data: mockData,
180
+ headers: mockHeaders,
181
+ });
182
+
183
+ const result = await getModelVehicles(client);
184
+
185
+ expect(result).toEqual({
186
+ data: [],
187
+ page: 0,
188
+ pageSize: 100,
189
+ total: 0,
190
+ totalPages: 0,
191
+ });
192
+ });
193
+ });
@@ -0,0 +1,52 @@
1
+ import { Client } from '@vulog/aima-client';
2
+ import { PaginableOptions, PaginableResponse, createPaginableOptionsSchema } from '@vulog/aima-core';
3
+
4
+ import { ModelVehicle } from './types';
5
+
6
+ export const getModelVehicles = async (
7
+ client: Client,
8
+ options?: PaginableOptions
9
+ ): Promise<PaginableResponse<ModelVehicle>> => {
10
+ const PaginableOptionsSchema = createPaginableOptionsSchema().default({});
11
+
12
+ const resultOptions = PaginableOptionsSchema.safeParse(options);
13
+ if (!resultOptions.success) {
14
+ throw new TypeError('Invalid options', {
15
+ cause: resultOptions.error.issues,
16
+ });
17
+ }
18
+
19
+ const finalOptions = resultOptions.data;
20
+
21
+ const searchParams = new URLSearchParams();
22
+ searchParams.append('page', finalOptions.page!.toString());
23
+ searchParams.append('pageSize', finalOptions.pageSize!.toString());
24
+
25
+ // Handle optional sort parameter
26
+ if (finalOptions.sort) {
27
+ searchParams.append('sort', `${finalOptions.sort.toString()},${finalOptions.sortDirection!.toString()}`);
28
+ }
29
+
30
+ // Handle optional filters parameter
31
+ if (finalOptions.filters) {
32
+ Object.entries(finalOptions.filters).forEach(([key, value]) => {
33
+ if (value === undefined) {
34
+ return;
35
+ }
36
+ searchParams.append(key, value as string);
37
+ });
38
+ }
39
+
40
+ const basePath = `boapi/proxy/user/vehicle/fleets/${client.clientOptions.fleetId}/vehicles/models/modelvehicles`;
41
+ const urlWithParams = `${basePath}?${searchParams.toString()}`;
42
+
43
+ return client.get<ModelVehicle[]>(urlWithParams).then(({ data, headers }) => {
44
+ return {
45
+ data,
46
+ page: headers.number,
47
+ pageSize: headers.size,
48
+ total: headers.totalelements,
49
+ totalPages: headers.totalpages,
50
+ };
51
+ });
52
+ };
package/src/index.ts CHANGED
@@ -8,3 +8,4 @@ export * from './types';
8
8
  export * from './pingVehicle';
9
9
  export * from './enableVehicle';
10
10
  export * from './disableVehicle';
11
+ export * from './getModelVehicles';
package/src/types.ts CHANGED
@@ -221,3 +221,10 @@ export type Assets = {
221
221
  }[];
222
222
  [key: string]: any;
223
223
  };
224
+
225
+ export type ModelVehicle = {
226
+ serviceId: string;
227
+ serviceVisibility: 'PUBLIC' | 'PRIVATE';
228
+ modelId: number;
229
+ vehicles: string[];
230
+ };