@schmock/query 1.1.0 → 1.2.1

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 CHANGED
@@ -1,102 +1 @@
1
- /// <reference path="../../../types/schmock.d.ts" />
2
- export function queryPlugin(options) {
3
- return {
4
- name: "query",
5
- version: "1.0.0",
6
- process(context, response) {
7
- // Only process array responses
8
- if (!Array.isArray(response)) {
9
- return { context, response };
10
- }
11
- let items = [...response];
12
- const query = context.query || {};
13
- // Apply filtering
14
- if (options.filtering) {
15
- items = applyFiltering(items, query, options.filtering);
16
- }
17
- // Apply sorting
18
- if (options.sorting) {
19
- items = applySorting(items, query, options.sorting);
20
- }
21
- // Apply pagination
22
- if (options.pagination) {
23
- const result = applyPagination(items, query, options.pagination);
24
- return { context, response: result };
25
- }
26
- return { context, response: items };
27
- },
28
- };
29
- }
30
- function applyFiltering(items, query, options) {
31
- const prefix = options.filterPrefix ?? "filter";
32
- let result = items;
33
- for (const field of options.allowed) {
34
- // Support filter[field]=value format
35
- const bracketKey = `${prefix}[${field}]`;
36
- // Support filter.field=value format
37
- const dotKey = `${prefix}.${field}`;
38
- // Support plain field=value format as fallback
39
- const value = query[bracketKey] ?? query[dotKey] ?? query[field];
40
- if (value !== undefined) {
41
- result = result.filter((item) => {
42
- const itemValue = item[field];
43
- if (itemValue === undefined)
44
- return false;
45
- return String(itemValue) === value;
46
- });
47
- }
48
- }
49
- return result;
50
- }
51
- function applySorting(items, query, options) {
52
- const sortParam = options.sortParam ?? "sort";
53
- const orderParam = options.orderParam ?? "order";
54
- const sortField = query[sortParam] ?? options.default;
55
- const rawOrder = query[orderParam] ?? options.defaultOrder ?? "asc";
56
- const sortOrder = rawOrder === "desc" ? "desc" : "asc";
57
- if (!sortField)
58
- return items;
59
- // Only sort by allowed fields
60
- if (!options.allowed.includes(sortField))
61
- return items;
62
- return items.sort((a, b) => {
63
- const aVal = a[sortField];
64
- const bVal = b[sortField];
65
- if (aVal === bVal)
66
- return 0;
67
- if (aVal === undefined)
68
- return 1;
69
- if (bVal === undefined)
70
- return -1;
71
- let comparison;
72
- if (typeof aVal === "number" && typeof bVal === "number") {
73
- comparison = aVal - bVal;
74
- }
75
- else {
76
- comparison = String(aVal).localeCompare(String(bVal));
77
- }
78
- return sortOrder === "desc" ? -comparison : comparison;
79
- });
80
- }
81
- function applyPagination(items, query, options) {
82
- const pageParam = options.pageParam ?? "page";
83
- const limitParam = options.limitParam ?? "limit";
84
- const defaultLimit = options.defaultLimit ?? 10;
85
- const maxLimit = options.maxLimit ?? 100;
86
- const page = Math.max(1, Number.parseInt(query[pageParam] || "1", 10) || 1);
87
- const limit = Math.min(maxLimit, Math.max(1, Number.parseInt(query[limitParam] || String(defaultLimit), 10) ||
88
- defaultLimit));
89
- const total = items.length;
90
- const totalPages = Math.ceil(total / limit);
91
- const start = (page - 1) * limit;
92
- const data = items.slice(start, start + limit);
93
- return {
94
- data,
95
- pagination: {
96
- page,
97
- limit,
98
- total,
99
- totalPages,
100
- },
101
- };
102
- }
1
+ function W(z){return{name:"query",version:"1.0.0",process(A,j){if(!Array.isArray(j))return{context:A,response:j};let C=[...j],D=A.query||{};if(z.filtering)C=R(C,D,z.filtering);if(z.sorting)C=T(C,D,z.sorting);if(z.pagination){let B=U(C,D,z.pagination);return{context:A,response:B}}return{context:A,response:C}}}}function R(z,A,j){let C=j.filterPrefix??"filter",D=z;for(let B of j.allowed){let Q=`${C}[${B}]`,J=`${C}.${B}`,G=A[Q]??A[J]??A[B];if(G!==void 0)D=D.filter((M)=>{let E=M[B];if(E===void 0)return!1;return String(E)===G})}return D}function T(z,A,j){let C=j.sortParam??"sort",D=j.orderParam??"order",B=A[C]??j.default,J=(A[D]??j.defaultOrder??"asc")==="desc"?"desc":"asc";if(!B)return z;if(!j.allowed.includes(B))return z;return z.sort((G,M)=>{let E=G[B],H=M[B];if(E===H)return 0;if(E===void 0)return 1;if(H===void 0)return-1;let N;if(typeof E==="number"&&typeof H==="number")N=E-H;else N=String(E).localeCompare(String(H));return J==="desc"?-N:N})}function U(z,A,j){let C=j.pageParam??"page",D=j.limitParam??"limit",B=j.defaultLimit??10,Q=j.maxLimit??100,J=Math.max(1,Number.parseInt(A[C]||"1",10)||1),G=Math.min(Q,Math.max(1,Number.parseInt(A[D]||String(B),10)||B)),M=z.length,E=Math.ceil(M/G),H=(J-1)*G;return{data:z.slice(H,H+G),pagination:{page:J,limit:G,total:M,totalPages:E}}}export{W as queryPlugin};
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": "1.1.0",
4
+ "version": "1.2.1",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
7
7
  "types": "./dist/index.d.ts",
@@ -33,7 +33,7 @@
33
33
  },
34
34
  "devDependencies": {
35
35
  "@amiceli/vitest-cucumber": "^6.2.0",
36
- "@types/node": "^25.1.0",
37
- "vitest": "^4.0.15"
36
+ "@types/node": "^25.2.1",
37
+ "vitest": "^4.0.18"
38
38
  }
39
39
  }
package/src/index.ts CHANGED
@@ -95,6 +95,7 @@ function applyFiltering(
95
95
  result = result.filter((item) => {
96
96
  const itemValue = item[field];
97
97
  if (itemValue === undefined) return false;
98
+ // Intentional string coercion: query params are inherently strings
98
99
  return String(itemValue) === value;
99
100
  });
100
101
  }