@schmock/query 2.1.2 → 2.1.3
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/dist/index.js +113 -1
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1 +1,113 @@
|
|
|
1
|
-
|
|
1
|
+
/// <reference path="../../core/schmock.d.ts" />
|
|
2
|
+
import { version as packageVersion } from "../package.json";
|
|
3
|
+
export function queryPlugin(options) {
|
|
4
|
+
return {
|
|
5
|
+
name: "query",
|
|
6
|
+
version: packageVersion,
|
|
7
|
+
process(context, response) {
|
|
8
|
+
// Only process array responses
|
|
9
|
+
if (!Array.isArray(response)) {
|
|
10
|
+
return { context, response };
|
|
11
|
+
}
|
|
12
|
+
let items = [...response];
|
|
13
|
+
const query = context.query || {};
|
|
14
|
+
// Apply filtering
|
|
15
|
+
if (options.filtering) {
|
|
16
|
+
items = applyFiltering(items, query, options.filtering);
|
|
17
|
+
}
|
|
18
|
+
// Apply sorting
|
|
19
|
+
if (options.sorting) {
|
|
20
|
+
items = applySorting(items, query, options.sorting);
|
|
21
|
+
}
|
|
22
|
+
// Apply pagination
|
|
23
|
+
if (options.pagination) {
|
|
24
|
+
const result = applyPagination(items, query, options.pagination);
|
|
25
|
+
return { context, response: result };
|
|
26
|
+
}
|
|
27
|
+
return { context, response: items };
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
function applyFiltering(items, query, options) {
|
|
32
|
+
const prefix = options.filterPrefix ?? "filter";
|
|
33
|
+
let result = items;
|
|
34
|
+
for (const field of options.allowed) {
|
|
35
|
+
// Support filter[field]=value format
|
|
36
|
+
const bracketKey = `${prefix}[${field}]`;
|
|
37
|
+
// Support filter.field=value format
|
|
38
|
+
const dotKey = `${prefix}.${field}`;
|
|
39
|
+
// Support plain field=value format as fallback
|
|
40
|
+
const value = query[bracketKey] ?? query[dotKey] ?? query[field];
|
|
41
|
+
if (value !== undefined) {
|
|
42
|
+
result = result.filter((item) => {
|
|
43
|
+
if (typeof item !== "object" || item === null)
|
|
44
|
+
return false;
|
|
45
|
+
const record = item;
|
|
46
|
+
const itemValue = record[field];
|
|
47
|
+
if (itemValue === undefined)
|
|
48
|
+
return false;
|
|
49
|
+
// Intentional string coercion: query params are inherently strings
|
|
50
|
+
return String(itemValue) === value;
|
|
51
|
+
});
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
return result;
|
|
55
|
+
}
|
|
56
|
+
function applySorting(items, query, options) {
|
|
57
|
+
const sortParam = options.sortParam ?? "sort";
|
|
58
|
+
const orderParam = options.orderParam ?? "order";
|
|
59
|
+
const sortField = query[sortParam] ?? options.default;
|
|
60
|
+
const rawOrder = query[orderParam] ?? options.defaultOrder ?? "asc";
|
|
61
|
+
const sortOrder = rawOrder === "desc" ? "desc" : "asc";
|
|
62
|
+
if (!sortField)
|
|
63
|
+
return items;
|
|
64
|
+
// Only sort by allowed fields
|
|
65
|
+
if (!options.allowed.includes(sortField))
|
|
66
|
+
return items;
|
|
67
|
+
return items.sort((a, b) => {
|
|
68
|
+
if (typeof a !== "object" || a === null)
|
|
69
|
+
return 0;
|
|
70
|
+
if (typeof b !== "object" || b === null)
|
|
71
|
+
return 0;
|
|
72
|
+
const aRecord = a;
|
|
73
|
+
const bRecord = b;
|
|
74
|
+
const aVal = aRecord[sortField];
|
|
75
|
+
const bVal = bRecord[sortField];
|
|
76
|
+
if (aVal === bVal)
|
|
77
|
+
return 0;
|
|
78
|
+
if (aVal === undefined)
|
|
79
|
+
return 1;
|
|
80
|
+
if (bVal === undefined)
|
|
81
|
+
return -1;
|
|
82
|
+
let comparison;
|
|
83
|
+
if (typeof aVal === "number" && typeof bVal === "number") {
|
|
84
|
+
comparison = aVal - bVal;
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
comparison = String(aVal).localeCompare(String(bVal));
|
|
88
|
+
}
|
|
89
|
+
return sortOrder === "desc" ? -comparison : comparison;
|
|
90
|
+
});
|
|
91
|
+
}
|
|
92
|
+
function applyPagination(items, query, options) {
|
|
93
|
+
const pageParam = options.pageParam ?? "page";
|
|
94
|
+
const limitParam = options.limitParam ?? "limit";
|
|
95
|
+
const defaultLimit = options.defaultLimit ?? 10;
|
|
96
|
+
const maxLimit = options.maxLimit ?? 100;
|
|
97
|
+
const page = Math.max(1, Number.parseInt(query[pageParam] || "1", 10) || 1);
|
|
98
|
+
const limit = Math.min(maxLimit, Math.max(1, Number.parseInt(query[limitParam] || String(defaultLimit), 10) ||
|
|
99
|
+
defaultLimit));
|
|
100
|
+
const total = items.length;
|
|
101
|
+
const totalPages = Math.ceil(total / limit);
|
|
102
|
+
const start = (page - 1) * limit;
|
|
103
|
+
const data = items.slice(start, start + limit);
|
|
104
|
+
return {
|
|
105
|
+
data,
|
|
106
|
+
pagination: {
|
|
107
|
+
page,
|
|
108
|
+
limit,
|
|
109
|
+
total,
|
|
110
|
+
totalPages,
|
|
111
|
+
},
|
|
112
|
+
};
|
|
113
|
+
}
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@schmock/query",
|
|
3
3
|
"description": "Pagination, filtering, and sorting plugin for Schmock",
|
|
4
|
-
"version": "2.1.
|
|
4
|
+
"version": "2.1.3",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
7
7
|
"types": "./dist/index.d.ts",
|
|
@@ -30,11 +30,11 @@
|
|
|
30
30
|
},
|
|
31
31
|
"license": "MIT",
|
|
32
32
|
"peerDependencies": {
|
|
33
|
-
"@schmock/core": "^2.1.
|
|
33
|
+
"@schmock/core": "^2.1.3"
|
|
34
34
|
},
|
|
35
35
|
"devDependencies": {
|
|
36
36
|
"@amiceli/vitest-cucumber": "^6.5.0",
|
|
37
37
|
"@types/node": "^25.8.0",
|
|
38
|
-
"vitest": "^4.1.
|
|
38
|
+
"vitest": "^4.1.7"
|
|
39
39
|
}
|
|
40
40
|
}
|