dynamo-query-engine 1.0.2 → 1.0.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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "dynamo-query-engine",
3
- "version": "1.0.2",
3
+ "version": "1.0.3",
4
4
  "description": "Type-safe DynamoDB query builder for GraphQL with support for filtering, sorting, pagination, and relation expansion",
5
5
  "type": "module",
6
6
  "main": "index.js",
@@ -83,22 +83,65 @@ export function validateExpandField(field, gridConfig) {
83
83
  }
84
84
 
85
85
  /**
86
- * Validates pagination model
86
+ * Validates pagination model and ensures numeric types
87
87
  * @param {PaginationModel} paginationModel - Pagination model to validate
88
88
  * @throws {Error} If pagination model is invalid
89
+ * @returns {PaginationModel} Normalized pagination model with numeric values
89
90
  */
90
91
  export function validatePaginationModel(paginationModel) {
91
92
  if (!paginationModel) {
92
93
  throw new Error("paginationModel is required");
93
94
  }
94
95
 
95
- if (!paginationModel.pageSize || paginationModel.pageSize < 1) {
96
+ // Check if pageSize exists first
97
+ if (!paginationModel.pageSize) {
96
98
  throw new Error("paginationModel.pageSize must be a positive number");
97
99
  }
98
100
 
99
- if (paginationModel.pageSize > 1000) {
101
+ // Convert pageSize to number if it's a string
102
+ let pageSize = paginationModel.pageSize;
103
+ if (typeof pageSize === "string") {
104
+ pageSize = Number(pageSize);
105
+ if (isNaN(pageSize)) {
106
+ throw new Error(
107
+ `paginationModel.pageSize must be a valid number, received '${paginationModel.pageSize}'`
108
+ );
109
+ }
110
+ // Mutate the original object to ensure downstream code uses the number
111
+ paginationModel.pageSize = pageSize;
112
+ } else if (typeof pageSize !== "number") {
113
+ throw new Error(
114
+ `paginationModel.pageSize must be a number, received ${typeof pageSize}`
115
+ );
116
+ }
117
+
118
+ if (pageSize < 1) {
119
+ throw new Error("paginationModel.pageSize must be a positive number");
120
+ }
121
+
122
+ if (pageSize > 1000) {
100
123
  throw new Error(
101
124
  "paginationModel.pageSize cannot exceed 1000 (DynamoDB limit)"
102
125
  );
103
126
  }
127
+
128
+ // Convert page to number if it exists and is a string
129
+ if (paginationModel.page !== undefined) {
130
+ let page = paginationModel.page;
131
+ if (typeof page === "string") {
132
+ page = Number(page);
133
+ if (isNaN(page)) {
134
+ throw new Error(
135
+ `paginationModel.page must be a valid number, received '${paginationModel.page}'`
136
+ );
137
+ }
138
+ paginationModel.page = page;
139
+ } else if (typeof page !== "number") {
140
+ throw new Error(
141
+ `paginationModel.page must be a number, received ${typeof page}`
142
+ );
143
+ }
144
+ }
145
+
146
+ return paginationModel;
104
147
  }
@@ -311,6 +311,67 @@ describe("Validation Utils", () => {
311
311
  validatePaginationModel({ pageSize: 2000 });
312
312
  }).toThrow(/DynamoDB limit/);
313
313
  });
314
+
315
+ describe("String to Number Conversion", () => {
316
+ it("should convert pageSize string to number", () => {
317
+ const paginationModel = { pageSize: "25" };
318
+ validatePaginationModel(paginationModel);
319
+ expect(paginationModel.pageSize).toBe(25);
320
+ expect(typeof paginationModel.pageSize).toBe("number");
321
+ });
322
+
323
+ it("should convert page string to number", () => {
324
+ const paginationModel = { pageSize: 25, page: "1" };
325
+ validatePaginationModel(paginationModel);
326
+ expect(paginationModel.page).toBe(1);
327
+ expect(typeof paginationModel.page).toBe("number");
328
+ });
329
+
330
+ it("should convert both pageSize and page strings to numbers", () => {
331
+ const paginationModel = { pageSize: "50", page: "2" };
332
+ validatePaginationModel(paginationModel);
333
+ expect(paginationModel.pageSize).toBe(50);
334
+ expect(paginationModel.page).toBe(2);
335
+ expect(typeof paginationModel.pageSize).toBe("number");
336
+ expect(typeof paginationModel.page).toBe("number");
337
+ });
338
+
339
+ it("should throw error for invalid pageSize string", () => {
340
+ expect(() => {
341
+ validatePaginationModel({ pageSize: "abc" });
342
+ }).toThrow("must be a valid number");
343
+ });
344
+
345
+ it("should throw error for invalid page string", () => {
346
+ expect(() => {
347
+ validatePaginationModel({ pageSize: 25, page: "invalid" });
348
+ }).toThrow("must be a valid number");
349
+ });
350
+
351
+ it("should throw error for non-string, non-number pageSize", () => {
352
+ expect(() => {
353
+ validatePaginationModel({ pageSize: true });
354
+ }).toThrow("must be a number");
355
+ });
356
+
357
+ it("should throw error for object pageSize", () => {
358
+ expect(() => {
359
+ validatePaginationModel({ pageSize: { value: 25 } });
360
+ }).toThrow("must be a number");
361
+ });
362
+
363
+ it("should validate converted string pageSize against limits", () => {
364
+ expect(() => {
365
+ validatePaginationModel({ pageSize: "1001" });
366
+ }).toThrow("cannot exceed 1000");
367
+ });
368
+
369
+ it("should validate converted string pageSize is positive", () => {
370
+ expect(() => {
371
+ validatePaginationModel({ pageSize: "0" });
372
+ }).toThrow("must be a positive number");
373
+ });
374
+ });
314
375
  });
315
376
 
316
377
  describe("Edge Cases", () => {