querier-ts 0.0.0 → 1.0.0

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.
Files changed (88) hide show
  1. package/lib/__tests__/query.spec.d.ts +1 -0
  2. package/lib/__tests__/query.spec.js +149 -0
  3. package/lib/core/errors/__tests__/invalid-argument-error.spec.d.ts +1 -0
  4. package/lib/core/errors/__tests__/invalid-argument-error.spec.js +54 -0
  5. package/lib/core/errors/index.d.ts +1 -0
  6. package/lib/core/errors/index.js +17 -0
  7. package/lib/core/errors/invalid-argument-error.d.ts +14 -0
  8. package/lib/core/errors/invalid-argument-error.js +16 -0
  9. package/lib/core/types/attribute-validation-function.d.ts +1 -0
  10. package/lib/core/types/attribute-validation-function.js +2 -0
  11. package/lib/core/types/column-condition.d.ts +6 -0
  12. package/lib/core/types/column-condition.js +2 -0
  13. package/lib/core/types/index.d.ts +4 -0
  14. package/lib/core/types/index.js +20 -0
  15. package/lib/core/types/query-conditions-group-nullable.d.ts +4 -0
  16. package/lib/core/types/query-conditions-group-nullable.js +2 -0
  17. package/lib/core/types/query-conditions-group.d.ts +4 -0
  18. package/lib/core/types/query-conditions-group.js +2 -0
  19. package/lib/core/types/query-row-validator-initializer.d.ts +8 -0
  20. package/lib/core/types/query-row-validator-initializer.js +2 -0
  21. package/lib/core/validation/__tests__/query-row-validator.spec.d.ts +1 -0
  22. package/lib/core/validation/__tests__/query-row-validator.spec.js +195 -0
  23. package/lib/core/validation/decorators/__tests__/number-validation.spec.d.ts +1 -0
  24. package/lib/core/validation/decorators/__tests__/number-validation.spec.js +114 -0
  25. package/lib/core/validation/decorators/index.d.ts +1 -0
  26. package/lib/core/validation/decorators/index.js +17 -0
  27. package/lib/core/validation/decorators/number-validaton.d.ts +36 -0
  28. package/lib/core/validation/decorators/number-validaton.js +123 -0
  29. package/lib/core/validation/index.d.ts +1 -0
  30. package/lib/core/validation/index.js +17 -0
  31. package/lib/core/validation/query-row-validator.d.ts +57 -0
  32. package/lib/core/validation/query-row-validator.js +84 -0
  33. package/lib/index.d.ts +1 -2
  34. package/lib/index.js +15 -3
  35. package/lib/query.d.ts +33 -38
  36. package/lib/query.js +51 -50
  37. package/lib/utils/functions/generic/__tests__/compare-arrays.spec.d.ts +1 -0
  38. package/lib/utils/functions/generic/__tests__/compare-arrays.spec.js +21 -0
  39. package/lib/utils/functions/generic/__tests__/deep-equal.spec.d.ts +1 -0
  40. package/lib/utils/functions/generic/__tests__/deep-equal.spec.js +82 -0
  41. package/lib/utils/functions/generic/__tests__/get-entries.spec.d.ts +1 -0
  42. package/lib/utils/functions/generic/__tests__/get-entries.spec.js +55 -0
  43. package/lib/utils/functions/generic/compare-arrays.d.ts +1 -9
  44. package/lib/utils/functions/generic/compare-arrays.js +2 -9
  45. package/lib/utils/functions/generic/deep-equal.d.ts +1 -0
  46. package/lib/utils/functions/generic/deep-equal.js +23 -0
  47. package/lib/utils/functions/generic/get-entries.d.ts +5 -8
  48. package/lib/utils/functions/generic/get-entries.js +7 -9
  49. package/lib/utils/functions/generic/index.d.ts +3 -3
  50. package/lib/utils/functions/generic/index.js +17 -5
  51. package/lib/utils/functions/sort/__tests__/sort-by-properties.spec.d.ts +1 -0
  52. package/lib/utils/functions/sort/__tests__/sort-by-properties.spec.js +69 -0
  53. package/lib/utils/functions/sort/__tests__/sort-by-property.spec.d.ts +1 -0
  54. package/lib/utils/functions/sort/__tests__/sort-by-property.spec.js +63 -0
  55. package/lib/utils/functions/sort/index.d.ts +2 -3
  56. package/lib/utils/functions/sort/index.js +16 -5
  57. package/lib/utils/functions/sort/sort-by-properties.d.ts +2 -2
  58. package/lib/utils/functions/sort/sort-by-properties.js +11 -9
  59. package/lib/utils/functions/sort/sort-by-property.d.ts +2 -2
  60. package/lib/utils/functions/sort/sort-by-property.js +18 -6
  61. package/lib/utils/functions/type-guards/__tests__/is-function.spec.d.ts +1 -0
  62. package/lib/utils/functions/type-guards/__tests__/is-function.spec.js +38 -0
  63. package/lib/utils/functions/type-guards/__tests__/is-number.spec.d.ts +1 -0
  64. package/lib/utils/functions/type-guards/__tests__/is-number.spec.js +35 -0
  65. package/lib/utils/functions/type-guards/__tests__/is-object.spec.d.ts +1 -0
  66. package/lib/utils/functions/type-guards/__tests__/is-object.spec.js +38 -0
  67. package/lib/utils/functions/type-guards/index.d.ts +3 -4
  68. package/lib/utils/functions/type-guards/index.js +17 -7
  69. package/lib/utils/functions/type-guards/is-function.d.ts +3 -3
  70. package/lib/utils/functions/type-guards/is-function.js +2 -2
  71. package/lib/utils/functions/type-guards/is-number.d.ts +3 -3
  72. package/lib/utils/functions/type-guards/is-number.js +2 -2
  73. package/lib/utils/functions/type-guards/is-object.d.ts +3 -3
  74. package/lib/utils/functions/type-guards/is-object.js +2 -2
  75. package/lib/utils/types/add-prefix-to-object.d.ts +1 -1
  76. package/lib/utils/types/allowed-names.d.ts +1 -1
  77. package/lib/utils/types/flag-excluded-type.d.ts +1 -1
  78. package/lib/utils/types/generic-object.d.ts +1 -1
  79. package/lib/utils/types/generic-object.js +0 -1
  80. package/lib/utils/types/index.d.ts +9 -10
  81. package/lib/utils/types/index.js +23 -0
  82. package/lib/utils/types/omit-type.d.ts +1 -1
  83. package/lib/utils/types/partial-of-properties.d.ts +1 -1
  84. package/lib/utils/types/prop-of.d.ts +1 -1
  85. package/lib/utils/types/property-only.d.ts +1 -1
  86. package/lib/utils/types/recursive-partial.d.ts +1 -1
  87. package/lib/utils/types/type.d.ts +1 -1
  88. package/package.json +23 -24
package/lib/query.js CHANGED
@@ -22,10 +22,10 @@ var __classPrivateFieldGet = (this && this.__classPrivateFieldGet) || function (
22
22
  var _Query_rows, _Query_columns, _Query_startAt, _Query_limit;
23
23
  Object.defineProperty(exports, "__esModule", { value: true });
24
24
  exports.Query = void 0;
25
+ const validation_1 = require("./core/validation");
26
+ const decorators_1 = require("./core/validation/decorators");
25
27
  const sort_1 = require("./utils/functions/sort");
26
28
  const type_guards_1 = require("./utils/functions/type-guards");
27
- const query_row_validator_1 = require("./query-row-validator");
28
- const number_validaton_1 = require("./utils/decorators/number-validaton");
29
29
  /**
30
30
  * Allows filtering data from an array of objects.
31
31
  *
@@ -76,7 +76,7 @@ class Query {
76
76
  /**
77
77
  * Initializes the query.
78
78
  *
79
- * @param {T[]} rows Rows to be queried.
79
+ * @param rows Rows to be queried.
80
80
  */
81
81
  constructor(rows) {
82
82
  /**
@@ -105,9 +105,9 @@ class Query {
105
105
  /**
106
106
  * Creates a new query based on the given data.
107
107
  *
108
- * @param {T[]} rows Rows to be queried.
108
+ * @param rows Rows to be queried.
109
109
  *
110
- * @returns {Query<T>} Query to the given rows.
110
+ * @returns Query to the given rows.
111
111
  */
112
112
  static from(rows) {
113
113
  return new Query(rows);
@@ -115,9 +115,9 @@ class Query {
115
115
  /**
116
116
  * Defines specific columns to be returned on the final results.
117
117
  *
118
- * @param {PropOf<T> | PropOf<T>[]} columns Selected columns.
118
+ * @param columns Selected columns.
119
119
  *
120
- * @returns {this} Current query.
120
+ * @returns Current query.
121
121
  */
122
122
  select(columns) {
123
123
  __classPrivateFieldSet(this, _Query_columns, Array.isArray(columns) ? columns : [columns], "f");
@@ -126,8 +126,7 @@ class Query {
126
126
  /**
127
127
  * Applies conditions to the query.
128
128
  *
129
- * @param {QueryConditionsGroup<T> | ((obj: T) => boolean)} condition Filter to
130
- * be applied to the query.
129
+ * @param condition Filter to be applied to the query.
131
130
  *
132
131
  * If a callback function is provided, it must return a boolean value.
133
132
  *
@@ -135,7 +134,7 @@ class Query {
135
134
  * corresponding values must be the expected values for the attributes or a
136
135
  * callback functions that return boolean values.
137
136
  *
138
- * @returns {this} Current query.
137
+ * @returns Current query.
139
138
  */
140
139
  where(condition) {
141
140
  this.filterRows(condition);
@@ -145,12 +144,12 @@ class Query {
145
144
  * Applies a set of conditions to the query ignoring `null` and `undefined`
146
145
  * values as conditions.
147
146
  *
148
- * @param {QueryConditionsGroupNullable<T>} condition An object where each
149
- * property represents an attribute to be validated. The values can be
150
- * literal or callback functions that return a boolean. If `null` or `undefined`
151
- * is passed, that condition will be skipped.
147
+ * @param condition An object where each property represents an attribute
148
+ * to be validated. The values can be literal or callback functions that
149
+ * return a boolean. If `null` or `undefined` is passed, that condition
150
+ * will be skipped.
152
151
  *
153
- * @returns {this} Current query.
152
+ * @returns Current query.
154
153
  */
155
154
  filterWhere(condition) {
156
155
  this.ignoreNullValues = true;
@@ -161,11 +160,10 @@ class Query {
161
160
  /**
162
161
  * Adds ordering to the results.
163
162
  *
164
- * @param {(PropOf<T> | keyof addPrefixToObject<PropertyOnly<T>, '-'>)[]} columns
165
- * Ascending or descending columns. To mark a field as descending, use `-` before
166
- * its name.
163
+ * @param columns Ascending or descending columns. To mark a field as
164
+ * descending, use `-` before its name.
167
165
  *
168
- * @returns {this} Current query.
166
+ * @returns Current query.
169
167
  */
170
168
  orderBy(...columns) {
171
169
  __classPrivateFieldGet(this, _Query_rows, "f").sort((0, sort_1.sortByProperties)(...columns));
@@ -174,7 +172,7 @@ class Query {
174
172
  /**
175
173
  * Returns the current number of rows.
176
174
  *
177
- * @return {number}
175
+ * @return Filtered rows count.
178
176
  */
179
177
  count() {
180
178
  return this.getLimitedRows().length;
@@ -182,7 +180,7 @@ class Query {
182
180
  /**
183
181
  * Checks if there is at least one row compatible with the query.
184
182
  *
185
- * @returns {boolean} Boolean indicating whether any row exists.
183
+ * @returns Whether any row exists after filtering.
186
184
  */
187
185
  exists() {
188
186
  return this.count() > 0;
@@ -190,7 +188,7 @@ class Query {
190
188
  /**
191
189
  * Returns the first result.
192
190
  *
193
- * @returns {T}
191
+ * @returns The first result.
194
192
  */
195
193
  first() {
196
194
  const rows = this.getLimitedRows();
@@ -199,7 +197,7 @@ class Query {
199
197
  /**
200
198
  * Returns the last result.
201
199
  *
202
- * @returns {T}
200
+ * @returns The last result.
203
201
  */
204
202
  last() {
205
203
  const rows = this.getLimitedRows();
@@ -208,7 +206,7 @@ class Query {
208
206
  /**
209
207
  * Returns all results.
210
208
  *
211
- * @returns {T[]}
209
+ * @returns All filtered rows.
212
210
  */
213
211
  all() {
214
212
  return this.getLimitedRows();
@@ -216,17 +214,19 @@ class Query {
216
214
  /**
217
215
  * Returns the value of the first (selected) column of the first row.
218
216
  *
219
- * @returns {T[Promise<T>]|false} First value or `false`, if none row exists.
217
+ * @returns First value or `false`, if none row exists.
220
218
  */
221
219
  scalar() {
222
220
  const firstObject = this.first();
223
221
  const firstColumn = this.getFirstColumn();
224
- return firstObject && firstColumn ? firstObject[firstColumn] ?? false : false;
222
+ return firstObject && firstColumn
223
+ ? (firstObject[firstColumn] ?? false)
224
+ : false;
225
225
  }
226
226
  /**
227
227
  * Returns the values of the first (selected) column of all rows.
228
228
  *
229
- * @returns {T[Promise<T>][]} Values from the first (selected) column.
229
+ * @returns Values from the first (selected) column.
230
230
  */
231
231
  column() {
232
232
  const firstColumn = this.getFirstColumn();
@@ -239,18 +239,20 @@ class Query {
239
239
  * Returns the values of the rows. If there are selected columns, only their
240
240
  * values will be returned.
241
241
  *
242
- * @returns {T[PropOf<T>][][]} Array with the values of all rows.
242
+ * @returns Array with the values of all rows.
243
243
  */
244
244
  values() {
245
- return this.getLimitedRows().map((row) => __classPrivateFieldGet(this, _Query_columns, "f").length ? __classPrivateFieldGet(this, _Query_columns, "f").map((column) => row[column]) : Object.values(row));
245
+ return this.getLimitedRows().map((row) => __classPrivateFieldGet(this, _Query_columns, "f").length
246
+ ? __classPrivateFieldGet(this, _Query_columns, "f").map((column) => row[column])
247
+ : Object.values(row));
246
248
  }
247
249
  /**
248
250
  * Defines the number of rows to skip.
249
251
  *
250
- * @param {number} numberOfRows Numbers of rows to skip. Only non negative integer numbers
252
+ * @param numberOfRows Numbers of rows to skip. Only non negative integer numbers
251
253
  * are allowed.
252
254
  *
253
- * @returns {this} Current query.
255
+ * @returns Current query.
254
256
  *
255
257
  * @throws {InvalidArgumentError} If the given number is less than 0.
256
258
  */
@@ -261,9 +263,9 @@ class Query {
261
263
  /**
262
264
  * Defines a limit for the number of results.
263
265
  *
264
- * @param {number} limit Limit of results. Only non negative integer numbers are allowed.
266
+ * @param limit Limit of results. Only non negative integer numbers are allowed.
265
267
  *
266
- * @returns {this} Current query.
268
+ * @returns Current query.
267
269
  *
268
270
  * @throws {InvalidArgumentError} If the given limit is less than 0.
269
271
  */
@@ -274,7 +276,7 @@ class Query {
274
276
  /**
275
277
  * Returns the rows that should be used in the final results.
276
278
  *
277
- * @returns {T[]} Rows within the specified limit.
279
+ * @returns Rows within the specified limit.
278
280
  */
279
281
  getLimitedRows() {
280
282
  return __classPrivateFieldGet(this, _Query_rows, "f").slice(__classPrivateFieldGet(this, _Query_startAt, "f")).slice(0, __classPrivateFieldGet(this, _Query_limit, "f"));
@@ -282,8 +284,7 @@ class Query {
282
284
  /**
283
285
  * Returns the first selected column or the first key of some row.
284
286
  *
285
- * @returns {Promise<T>|null} The first column or `null`, if none is selected
286
- * or there is no row.
287
+ * @returns The first column or `null`, if none is selected or there is no row.
287
288
  */
288
289
  getFirstColumn() {
289
290
  if (__classPrivateFieldGet(this, _Query_columns, "f").length) {
@@ -295,37 +296,37 @@ class Query {
295
296
  /**
296
297
  * Filters the rows according to the given conditions.
297
298
  *
298
- * @param {QueryConditionsGroupNullable<T> | ((obj: T) => boolean)} condition
299
- * Object or callback function.
299
+ * @param condition Object or callback function.
300
300
  */
301
301
  filterRows(condition) {
302
- const isCallbackValidator = (0, type_guards_1.isFunction)(condition);
303
- __classPrivateFieldSet(this, _Query_rows, __classPrivateFieldGet(this, _Query_rows, "f").filter((row) => (isCallbackValidator ? condition(row) : this.validateRow(row, condition))), "f");
302
+ __classPrivateFieldSet(this, _Query_rows, __classPrivateFieldGet(this, _Query_rows, "f").filter((row) => (0, type_guards_1.isFunction)(condition)
303
+ ? condition(row)
304
+ : this.validateRow(row, condition)), "f");
304
305
  }
305
306
  /**
306
307
  * Validates a row based on the given conditions object.
307
308
  *
308
- * @param {T} row Row to validate.
309
- * @param {QueryConditionsGroupNullable<T>} condition Conditions object.
309
+ * @param row Row to validate.
310
+ * @param condition Conditions object.
310
311
  *
311
312
  * @returns {boolean} Validation result.
312
313
  */
313
314
  validateRow(row, condition) {
314
- return query_row_validator_1.QueryRowValidator.validate(row, {
315
+ return validation_1.QueryRowValidator.validate(row, {
315
316
  conditionsObject: condition,
316
317
  ignoreNullValues: this.ignoreNullValues,
317
318
  });
318
319
  }
319
320
  }
321
+ exports.Query = Query;
320
322
  _Query_rows = new WeakMap(), _Query_columns = new WeakMap(), _Query_startAt = new WeakMap(), _Query_limit = new WeakMap();
321
323
  __decorate([
322
- number_validaton_1.validateNumbers,
323
- __param(0, number_validaton_1.integer),
324
- __param(0, (0, number_validaton_1.min)(0))
324
+ decorators_1.validateNumbers,
325
+ __param(0, decorators_1.integer),
326
+ __param(0, (0, decorators_1.min)(0))
325
327
  ], Query.prototype, "skip", null);
326
328
  __decorate([
327
- number_validaton_1.validateNumbers,
328
- __param(0, number_validaton_1.integer),
329
- __param(0, (0, number_validaton_1.min)(0))
329
+ decorators_1.validateNumbers,
330
+ __param(0, decorators_1.integer),
331
+ __param(0, (0, decorators_1.min)(0))
330
332
  ], Query.prototype, "limit", null);
331
- exports.Query = Query;
@@ -0,0 +1,21 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const compare_arrays_1 = require("../compare-arrays");
4
+ describe('compareArrays', () => {
5
+ it('returns true for ly equal arrays', () => {
6
+ const a = [{ x: 1 }, { y: 2 }];
7
+ const b = [{ x: 1 }, { y: 2 }];
8
+ expect((0, compare_arrays_1.compareArrays)(a, b)).toBe(true);
9
+ });
10
+ it('returns false for ly different arrays', () => {
11
+ expect((0, compare_arrays_1.compareArrays)([{ x: 1 }], [{ x: 2 }])).toBe(false);
12
+ });
13
+ it('returns false when order differs', () => {
14
+ expect((0, compare_arrays_1.compareArrays)([{ a: 1 }, { b: 2 }], [{ b: 2 }, { a: 1 }])).toBe(false);
15
+ });
16
+ it('works with nested objects', () => {
17
+ const a = [{ x: { y: 1 } }];
18
+ const b = [{ x: { y: 1 } }];
19
+ expect((0, compare_arrays_1.compareArrays)(a, b)).toBe(true);
20
+ });
21
+ });
@@ -0,0 +1,82 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const deep_equal_1 = require("../deep-equal");
4
+ describe('deepEqual', () => {
5
+ describe('primitive values', () => {
6
+ it('returns true for strictly equal primitives', () => {
7
+ expect((0, deep_equal_1.deepEqual)(1, 1)).toBe(true);
8
+ expect((0, deep_equal_1.deepEqual)('a', 'a')).toBe(true);
9
+ expect((0, deep_equal_1.deepEqual)(true, true)).toBe(true);
10
+ expect((0, deep_equal_1.deepEqual)(null, null)).toBe(true);
11
+ expect((0, deep_equal_1.deepEqual)(undefined, undefined)).toBe(true);
12
+ });
13
+ it('returns false for different primitive values', () => {
14
+ expect((0, deep_equal_1.deepEqual)(1, 2)).toBe(false);
15
+ expect((0, deep_equal_1.deepEqual)('a', 'b')).toBe(false);
16
+ expect((0, deep_equal_1.deepEqual)(true, false)).toBe(false);
17
+ expect((0, deep_equal_1.deepEqual)(null, undefined)).toBe(false);
18
+ });
19
+ });
20
+ describe('objects', () => {
21
+ it('returns true for deeply equal plain objects', () => {
22
+ const a = { x: 1, y: 2 };
23
+ const b = { x: 1, y: 2 };
24
+ expect((0, deep_equal_1.deepEqual)(a, b)).toBe(true);
25
+ });
26
+ it('returns false for objects with different keys', () => {
27
+ expect((0, deep_equal_1.deepEqual)({ x: 1 }, { y: 1 })).toBe(false);
28
+ });
29
+ it('returns false for objects with same keys but different values', () => {
30
+ expect((0, deep_equal_1.deepEqual)({ x: 1 }, { x: 2 })).toBe(false);
31
+ });
32
+ it('returns false when one object has extra keys', () => {
33
+ expect((0, deep_equal_1.deepEqual)({ x: 1 }, { x: 1, y: 2 })).toBe(false);
34
+ });
35
+ });
36
+ describe('nested structures', () => {
37
+ it('returns true for deeply nested objects', () => {
38
+ const a = { x: { y: { z: 1 } } };
39
+ const b = { x: { y: { z: 1 } } };
40
+ expect((0, deep_equal_1.deepEqual)(a, b)).toBe(true);
41
+ });
42
+ it('returns false for deeply nested differences', () => {
43
+ const a = { x: { y: { z: 1 } } };
44
+ const b = { x: { y: { z: 2 } } };
45
+ expect((0, deep_equal_1.deepEqual)(a, b)).toBe(false);
46
+ });
47
+ });
48
+ describe('arrays', () => {
49
+ it('returns true for deeply equal arrays', () => {
50
+ expect((0, deep_equal_1.deepEqual)([1, 2, 3], [1, 2, 3])).toBe(true);
51
+ });
52
+ it('returns false for arrays with different order', () => {
53
+ expect((0, deep_equal_1.deepEqual)([1, 2, 3], [3, 2, 1])).toBe(false);
54
+ });
55
+ it('returns true for arrays with nested objects', () => {
56
+ const a = [{ x: 1 }, { y: 2 }];
57
+ const b = [{ x: 1 }, { y: 2 }];
58
+ expect((0, deep_equal_1.deepEqual)(a, b)).toBe(true);
59
+ });
60
+ it('returns false for arrays with different lengths', () => {
61
+ expect((0, deep_equal_1.deepEqual)([1, 2], [1, 2, 3])).toBe(false);
62
+ });
63
+ });
64
+ describe('mixed and edge cases', () => {
65
+ it('returns false when comparing array and object', () => {
66
+ expect((0, deep_equal_1.deepEqual)([], {})).toBe(false);
67
+ });
68
+ it('returns false when one value is object and the other is primitive', () => {
69
+ expect((0, deep_equal_1.deepEqual)({ x: 1 }, 1)).toBe(false);
70
+ });
71
+ it('returns true for same object reference', () => {
72
+ const obj = { x: 1 };
73
+ expect((0, deep_equal_1.deepEqual)(obj, obj)).toBe(true);
74
+ });
75
+ it('returns false for Date objects with same value (by design)', () => {
76
+ const a = new Date(2020, 1, 1);
77
+ const b = new Date(2020, 1, 1);
78
+ // Date has no enumerable keys, so this documents the limitation
79
+ expect((0, deep_equal_1.deepEqual)(a, b)).toBe(true);
80
+ });
81
+ });
82
+ });
@@ -0,0 +1,55 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const get_entries_1 = require("../get-entries");
4
+ describe('getEntries', () => {
5
+ it('should return entries for a simple object', () => {
6
+ const obj = {
7
+ a: 1,
8
+ b: 2,
9
+ };
10
+ const entries = (0, get_entries_1.getEntries)(obj);
11
+ expect(entries).toEqual([
12
+ ['a', 1],
13
+ ['b', 2],
14
+ ]);
15
+ });
16
+ it('should return an empty array for an empty object', () => {
17
+ const obj = {};
18
+ const entries = (0, get_entries_1.getEntries)(obj);
19
+ expect(entries).toEqual([]);
20
+ });
21
+ it('should work with different value types', () => {
22
+ const obj = {
23
+ name: 'Alice',
24
+ age: 30,
25
+ active: true,
26
+ };
27
+ const entries = (0, get_entries_1.getEntries)(obj);
28
+ expect(entries).toEqual([
29
+ ['name', 'Alice'],
30
+ ['age', 30],
31
+ ['active', true],
32
+ ]);
33
+ });
34
+ it('should preserve key-value association', () => {
35
+ const obj = {
36
+ x: 10,
37
+ y: 20,
38
+ };
39
+ const entries = (0, get_entries_1.getEntries)(obj);
40
+ for (const [key, value] of entries) {
41
+ expect(obj[key]).toBe(value);
42
+ }
43
+ });
44
+ it('should provide correct typing for keys and values (type-level test)', () => {
45
+ const obj = {
46
+ id: 1,
47
+ title: 'Post',
48
+ };
49
+ const entries = (0, get_entries_1.getEntries)(obj);
50
+ const key = 'id';
51
+ const value = obj[key];
52
+ expect(key).toBe('id');
53
+ expect(value).toBe(1);
54
+ });
55
+ });
@@ -1,9 +1 @@
1
- /**
2
- * Compares two arrays.
3
- *
4
- * @param {any[]} a First array to compare.
5
- * @param {any[]} b Second array to compare.
6
- *
7
- * @returns {boolean} Validation result.
8
- */
9
- export declare const compareArrays: (a: any[], b: any[]) => boolean;
1
+ export declare const compareArrays: <T>(a: T[], b: T[]) => boolean;
@@ -1,13 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.compareArrays = void 0;
4
- /**
5
- * Compares two arrays.
6
- *
7
- * @param {any[]} a First array to compare.
8
- * @param {any[]} b Second array to compare.
9
- *
10
- * @returns {boolean} Validation result.
11
- */
12
- const compareArrays = (a, b) => a.length === b.length && a.every((v, i) => v === b[i]);
4
+ const deep_equal_1 = require("./deep-equal");
5
+ const compareArrays = (a, b) => a.length === b.length && a.every((v, i) => (0, deep_equal_1.deepEqual)(v, b[i]));
13
6
  exports.compareArrays = compareArrays;
@@ -0,0 +1 @@
1
+ export declare const deepEqual: (a: unknown, b: unknown) => boolean;
@@ -0,0 +1,23 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.deepEqual = void 0;
4
+ const type_guards_1 = require("../type-guards");
5
+ const deepEqual = (a, b) => {
6
+ if (a === b) {
7
+ return true;
8
+ }
9
+ if (!(0, type_guards_1.isObject)(a) || !(0, type_guards_1.isObject)(b)) {
10
+ return false;
11
+ }
12
+ if (Array.isArray(a) !== Array.isArray(b)) {
13
+ return false;
14
+ }
15
+ const keysA = Object.keys(a);
16
+ const keysB = Object.keys(b);
17
+ if (keysA.length !== keysB.length) {
18
+ return false;
19
+ }
20
+ return keysA.every((key) => Object.prototype.hasOwnProperty.call(b, key) &&
21
+ (0, exports.deepEqual)(a[key], b[key]));
22
+ };
23
+ exports.deepEqual = deepEqual;
@@ -1,8 +1,5 @@
1
- /**
2
- * Returns the entries of an object.
3
- *
4
- * @param {object} obj The object to retrieve entries.
5
- *
6
- * @returns {[string, any]} The entries of the object.
7
- */
8
- export declare const getEntries: <T extends object>(obj: T) => [[keyof T, T[keyof T]]];
1
+ type Entries<T> = {
2
+ [K in keyof T]: [K, T[K]];
3
+ }[keyof T][];
4
+ export declare function getEntries<T extends Record<PropertyKey, unknown>>(obj: T): Entries<T>;
5
+ export {};
@@ -1,12 +1,10 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getEntries = void 0;
4
- /**
5
- * Returns the entries of an object.
6
- *
7
- * @param {object} obj The object to retrieve entries.
8
- *
9
- * @returns {[string, any]} The entries of the object.
10
- */
11
- const getEntries = (obj) => Object.entries(obj);
12
3
  exports.getEntries = getEntries;
4
+ function getEntries(obj) {
5
+ const entries = [];
6
+ for (const key of Object.keys(obj)) {
7
+ entries.push([key, obj[key]]);
8
+ }
9
+ return entries;
10
+ }
@@ -1,3 +1,3 @@
1
- import { compareArrays } from './compare-arrays';
2
- import { getEntries } from './get-entries';
3
- export { compareArrays, getEntries, };
1
+ export * from './compare-arrays';
2
+ export * from './deep-equal';
3
+ export * from './get-entries';
@@ -1,7 +1,19 @@
1
1
  "use strict";
2
+ var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3
+ if (k2 === undefined) k2 = k;
4
+ var desc = Object.getOwnPropertyDescriptor(m, k);
5
+ if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
6
+ desc = { enumerable: true, get: function() { return m[k]; } };
7
+ }
8
+ Object.defineProperty(o, k2, desc);
9
+ }) : (function(o, m, k, k2) {
10
+ if (k2 === undefined) k2 = k;
11
+ o[k2] = m[k];
12
+ }));
13
+ var __exportStar = (this && this.__exportStar) || function(m, exports) {
14
+ for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
15
+ };
2
16
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.getEntries = exports.compareArrays = void 0;
4
- const compare_arrays_1 = require("./compare-arrays");
5
- Object.defineProperty(exports, "compareArrays", { enumerable: true, get: function () { return compare_arrays_1.compareArrays; } });
6
- const get_entries_1 = require("./get-entries");
7
- Object.defineProperty(exports, "getEntries", { enumerable: true, get: function () { return get_entries_1.getEntries; } });
17
+ __exportStar(require("./compare-arrays"), exports);
18
+ __exportStar(require("./deep-equal"), exports);
19
+ __exportStar(require("./get-entries"), exports);
@@ -0,0 +1,69 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
3
+ const sort_by_properties_1 = require("../sort-by-properties");
4
+ describe('sortByProperties', () => {
5
+ it('sorts by a single property', () => {
6
+ const data = [
7
+ { id: 2, name: 'B' },
8
+ { id: 1, name: 'A' },
9
+ ];
10
+ data.sort((0, sort_by_properties_1.sortByProperties)('id'));
11
+ expect(data).toEqual([
12
+ { id: 1, name: 'A' },
13
+ { id: 2, name: 'B' },
14
+ ]);
15
+ });
16
+ it('sorts by multiple properties in order', () => {
17
+ const data = [
18
+ { id: 1, name: 'Bob', age: 30 },
19
+ { id: 2, name: 'Alice', age: 30 },
20
+ { id: 3, name: 'Alice', age: 25 },
21
+ ];
22
+ data.sort((0, sort_by_properties_1.sortByProperties)('name', 'age'));
23
+ expect(data).toEqual([
24
+ { id: 3, name: 'Alice', age: 25 },
25
+ { id: 2, name: 'Alice', age: 30 },
26
+ { id: 1, name: 'Bob', age: 30 },
27
+ ]);
28
+ });
29
+ it('supports descending order with "-" prefix', () => {
30
+ const data = [
31
+ { id: 1, name: 'Bob', age: 30 },
32
+ { id: 2, name: 'Alice', age: 30 },
33
+ { id: 3, name: 'Alice', age: 25 },
34
+ ];
35
+ data.sort((0, sort_by_properties_1.sortByProperties)('name', '-age'));
36
+ expect(data).toEqual([
37
+ { id: 2, name: 'Alice', age: 30 },
38
+ { id: 3, name: 'Alice', age: 25 },
39
+ { id: 1, name: 'Bob', age: 30 },
40
+ ]);
41
+ });
42
+ it('places undefined values last when used as secondary key', () => {
43
+ const data = [
44
+ { id: 1, name: 'Alice' },
45
+ { id: 2, name: 'Alice', age: 20 },
46
+ { id: 3, name: 'Alice', age: 10 },
47
+ ];
48
+ data.sort((0, sort_by_properties_1.sortByProperties)('name', 'age'));
49
+ expect(data).toEqual([
50
+ { id: 3, name: 'Alice', age: 10 },
51
+ { id: 2, name: 'Alice', age: 20 },
52
+ { id: 1, name: 'Alice' },
53
+ ]);
54
+ });
55
+ it('returns 0 when all compared properties are equal', () => {
56
+ const comparator = (0, sort_by_properties_1.sortByProperties)('name', 'age');
57
+ expect(comparator({ id: 1, name: 'Alice', age: 20 }, { id: 2, name: 'Alice', age: 20 })).toBe(0);
58
+ });
59
+ it('returns 0 when no properties are provided', () => {
60
+ const comparator = (0, sort_by_properties_1.sortByProperties)();
61
+ expect(comparator({ id: 1, name: 'Alice' }, { id: 2, name: 'Bob' })).toBe(0);
62
+ });
63
+ it('enforces type safety at compile time', () => {
64
+ // @ts-expect-error
65
+ (0, sort_by_properties_1.sortByProperties)('invalid');
66
+ // @ts-expect-error
67
+ (0, sort_by_properties_1.sortByProperties)('-invalid');
68
+ });
69
+ });