@tmlmobilidade/interfaces 20260326.1644.50 → 20260326.2139.30

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.
@@ -1,4 +1,12 @@
1
1
  import { Dates } from '@tmlmobilidade/dates';
2
+ //
3
+ // Time thresholds
4
+ const LAST_SEEN_WINDOW = 30 * 1000; // 30 seconds
5
+ const OPERATIONAL_WINDOW = 60 * 1000 * 10; // 10 minutes
6
+ const DELAY_THRESHOLDS = {
7
+ delayed: 5 * 60 * 1000, // 5 minutes after scheduled time
8
+ early: -1 * 60 * 1000, // 1 minute before scheduled time
9
+ };
2
10
  /**
3
11
  * Creates MongoDB aggregation pipeline stages to calculate and categorize delay statuses.
4
12
  *
@@ -16,12 +24,6 @@ import { Dates } from '@tmlmobilidade/dates';
16
24
  * @returns {Array} Array of MongoDB aggregation pipeline stages
17
25
  */
18
26
  export function ridesPipelineDelayStatus({ filter } = {}) {
19
- //
20
- // Delay thresholds in milliseconds
21
- const DELAY_THRESHOLDS = {
22
- delayed: 300000, // 5 minutes after scheduled time
23
- early: -60000, // 1 minute before scheduled time
24
- };
25
27
  const pipeline = [
26
28
  // Stage 1: Calculate delay differences in milliseconds
27
29
  // Only compute if both scheduled and observed times exist
@@ -92,10 +94,10 @@ export function ridesPipelineDelayStatus({ filter } = {}) {
92
94
  { $project: { end_delay_diff: 0, start_delay_diff: 0 } },
93
95
  ];
94
96
  // Stage 5: Filter by delay status if provided
95
- if (filter && filter.end_delay_status) {
97
+ if (filter?.end_delay_status) {
96
98
  pipeline.push({ $match: { end_delay_status: { $in: filter.end_delay_status } } });
97
99
  }
98
- if (filter && filter.start_delay_status) {
100
+ if (filter?.start_delay_status) {
99
101
  pipeline.push({ $match: { start_delay_status: { $in: filter.start_delay_status } } });
100
102
  }
101
103
  return pipeline;
@@ -122,9 +124,6 @@ export function ridesPipelineDelayStatus({ filter } = {}) {
122
124
  * @returns {Array} Array of MongoDB aggregation pipeline stages
123
125
  */
124
126
  export function ridesPipelineOperationalStatus({ filter } = {}) {
125
- //
126
- // Time thresholds in milliseconds
127
- const OPERATIONAL_WINDOW = 600000; // 10 minutes
128
127
  const now = Dates.now('Europe/Lisbon').unix_timestamp;
129
128
  const pipeline = [
130
129
  // Stage 1: Add current timestamp to each document
@@ -191,7 +190,7 @@ export function ridesPipelineOperationalStatus({ filter } = {}) {
191
190
  },
192
191
  ];
193
192
  // Stage 5: Filter by operational status if provided
194
- if (filter && filter.operational_status) {
193
+ if (filter?.operational_status) {
195
194
  pipeline.push({ $match: { operational_status: { $in: filter.operational_status } } });
196
195
  }
197
196
  return pipeline;
@@ -217,9 +216,6 @@ export function ridesPipelineOperationalStatus({ filter } = {}) {
217
216
  * @returns {Array} Array of MongoDB aggregation pipeline stages
218
217
  */
219
218
  export function ridesPipelineSeenStatus({ filter } = {}) {
220
- //
221
- // Time thresholds in milliseconds
222
- const SEEN_WINDOW = 30000; // 30 seconds
223
219
  const now = Dates.now('Europe/Lisbon').unix_timestamp;
224
220
  const pipeline = [
225
221
  // Stage 1: Add current timestamp to each document
@@ -244,7 +240,7 @@ export function ridesPipelineSeenStatus({ filter } = {}) {
244
240
  $switch: {
245
241
  branches: [
246
242
  { case: { $eq: ['$seen_last_at', null] }, then: 'unseen' },
247
- { case: { $lte: ['$milliseconds_from_last_seen_to_now', SEEN_WINDOW] }, then: 'seen' },
243
+ { case: { $lte: ['$milliseconds_from_last_seen_to_now', LAST_SEEN_WINDOW] }, then: 'seen' },
248
244
  ],
249
245
  default: 'gone',
250
246
  },
@@ -261,7 +257,7 @@ export function ridesPipelineSeenStatus({ filter } = {}) {
261
257
  },
262
258
  ];
263
259
  // Stage 5: Filter by seen status if provided
264
- if (filter && filter.seen_status) {
260
+ if (filter?.seen_status) {
265
261
  pipeline.push({ $match: { seen_status: { $in: filter.seen_status } } });
266
262
  }
267
263
  return pipeline;
@@ -303,7 +299,16 @@ export function ridesBatchAggregationPipeline({ ...filter }) {
303
299
  const driverMatch = filter.search.match(/d:([\d,]+)/);
304
300
  // Remove v: and d: patterns from search string for ride ID matching
305
301
  const searchWithoutSpecialFilters = filter.search.replace(/v:[\d,]+/g, '').replace(/d:[\d,]+/g, '').trim();
306
- const keywords = searchWithoutSpecialFilters.split(/\s+/).filter(k => k.length > 0).map(v => v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&'));
302
+ const keywords = searchWithoutSpecialFilters
303
+ .split(/\s+/)
304
+ .filter(k => k.length > 0)
305
+ .map((v) => {
306
+ // Escape regex special chars EXCEPT %
307
+ let escaped = v.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
308
+ // Convert SQL wildcards to regex
309
+ escaped = escaped.replace(/%%/g, '.*');
310
+ return escaped;
311
+ });
307
312
  if (keywords.length > 0) {
308
313
  const pattern = keywords.map(k => `(?=.*${k})`).join('') + '.*';
309
314
  pipeline.push({
@@ -322,10 +327,7 @@ export function ridesBatchAggregationPipeline({ ...filter }) {
322
327
  }
323
328
  if (driverMatch) {
324
329
  const value = driverMatch[1];
325
- const driverIDs = value
326
- .split(',')
327
- .map(id => id.trim())
328
- .filter(id => id);
330
+ const driverIDs = value.split(',').map(id => id.trim()).filter(id => id);
329
331
  if (driverIDs.length > 0) {
330
332
  pipeline.push({ $match: { driver_ids: { $in: driverIDs } } });
331
333
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tmlmobilidade/interfaces",
3
- "version": "20260326.1644.50",
3
+ "version": "20260326.2139.30",
4
4
  "author": {
5
5
  "email": "iso@tmlmobilidade.pt",
6
6
  "name": "TML-ISO"