dynamo-query-engine 1.0.1 → 1.0.2
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/README.md +49 -7
- package/package.json +9 -2
- package/src/core/expandResolver.js +1 -1
- package/src/core/gridQueryBuilder.js +3 -3
- package/src/utils/validation.js +4 -4
- package/tests/README.md +279 -0
- package/tests/mocks/dynamoose.mock.js +124 -0
- package/tests/unit/cursor.test.js +167 -0
- package/tests/unit/gridQueryBuilder.test.js +474 -0
- package/tests/unit/validation.test.js +350 -0
- package/vitest.config.js +20 -0
package/README.md
CHANGED
|
@@ -39,7 +39,7 @@ const UserSchema = new dynamoose.Schema({
|
|
|
39
39
|
createdAt: {
|
|
40
40
|
type: String,
|
|
41
41
|
rangeKey: true,
|
|
42
|
-
|
|
42
|
+
query: {
|
|
43
43
|
sort: { type: "key" },
|
|
44
44
|
filter: {
|
|
45
45
|
type: "key",
|
|
@@ -54,7 +54,7 @@ const UserSchema = new dynamoose.Schema({
|
|
|
54
54
|
global: true,
|
|
55
55
|
rangeKey: "createdAt",
|
|
56
56
|
},
|
|
57
|
-
|
|
57
|
+
query: {
|
|
58
58
|
filter: {
|
|
59
59
|
type: "key",
|
|
60
60
|
operators: ["eq"],
|
|
@@ -65,7 +65,7 @@ const UserSchema = new dynamoose.Schema({
|
|
|
65
65
|
teamIds: {
|
|
66
66
|
type: Array,
|
|
67
67
|
schema: [String],
|
|
68
|
-
|
|
68
|
+
query: {
|
|
69
69
|
expand: {
|
|
70
70
|
type: "Team",
|
|
71
71
|
relation: "MANY",
|
|
@@ -176,7 +176,7 @@ query UsersGrid(
|
|
|
176
176
|
### Filter Configuration
|
|
177
177
|
|
|
178
178
|
```javascript
|
|
179
|
-
|
|
179
|
+
query: {
|
|
180
180
|
filter: {
|
|
181
181
|
type: "key", // Only "key" supported
|
|
182
182
|
operators: ["eq", "gte", "lte"], // Allowed operators
|
|
@@ -190,7 +190,7 @@ grid: {
|
|
|
190
190
|
### Sort Configuration
|
|
191
191
|
|
|
192
192
|
```javascript
|
|
193
|
-
|
|
193
|
+
query: {
|
|
194
194
|
sort: { type: "key" } // Only range keys can be sorted
|
|
195
195
|
}
|
|
196
196
|
```
|
|
@@ -200,7 +200,7 @@ grid: {
|
|
|
200
200
|
### Expand Configuration
|
|
201
201
|
|
|
202
202
|
```javascript
|
|
203
|
-
|
|
203
|
+
query: {
|
|
204
204
|
expand: {
|
|
205
205
|
type: "Team", // Model name (must be registered)
|
|
206
206
|
relation: "MANY", // "ONE" or "MANY"
|
|
@@ -316,7 +316,7 @@ status: {
|
|
|
316
316
|
global: true,
|
|
317
317
|
rangeKey: "createdAt",
|
|
318
318
|
},
|
|
319
|
-
|
|
319
|
+
query: {
|
|
320
320
|
filter: {
|
|
321
321
|
type: "key",
|
|
322
322
|
operators: ["eq"],
|
|
@@ -376,10 +376,52 @@ The library provides descriptive errors:
|
|
|
376
376
|
- `"Cursor does not match query"` - Query params changed between pages
|
|
377
377
|
- `"Model 'X' not found in registry"` - Model not registered
|
|
378
378
|
|
|
379
|
+
## Testing
|
|
380
|
+
|
|
381
|
+
The package includes comprehensive unit tests with Vitest.
|
|
382
|
+
|
|
383
|
+
### Run Tests
|
|
384
|
+
|
|
385
|
+
```bash
|
|
386
|
+
# Run all tests
|
|
387
|
+
npm test
|
|
388
|
+
|
|
389
|
+
# Run tests with UI
|
|
390
|
+
npm run test:ui
|
|
391
|
+
|
|
392
|
+
# Run tests once (CI mode)
|
|
393
|
+
npm run test:run
|
|
394
|
+
|
|
395
|
+
# Generate coverage report
|
|
396
|
+
npm run coverage
|
|
397
|
+
```
|
|
398
|
+
|
|
399
|
+
### Test Coverage
|
|
400
|
+
|
|
401
|
+
- **Cursor Utils**: ~80% coverage
|
|
402
|
+
- **Validation**: ~70% coverage
|
|
403
|
+
- **GridQueryBuilder**: ~50% coverage
|
|
404
|
+
- **Overall**: ~50-60% coverage
|
|
405
|
+
|
|
406
|
+
See [tests/README.md](./tests/README.md) for detailed testing documentation.
|
|
407
|
+
|
|
379
408
|
## Contributing
|
|
380
409
|
|
|
381
410
|
Contributions are welcome! Please open an issue or pull request.
|
|
382
411
|
|
|
412
|
+
### Development Setup
|
|
413
|
+
|
|
414
|
+
```bash
|
|
415
|
+
# Install dependencies
|
|
416
|
+
npm install
|
|
417
|
+
|
|
418
|
+
# Run tests
|
|
419
|
+
npm test
|
|
420
|
+
|
|
421
|
+
# Check coverage
|
|
422
|
+
npm run coverage
|
|
423
|
+
```
|
|
424
|
+
|
|
383
425
|
## License
|
|
384
426
|
|
|
385
427
|
MIT © Sascha Eckstein
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dynamo-query-engine",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.2",
|
|
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",
|
|
@@ -10,7 +10,10 @@
|
|
|
10
10
|
"./utils": "./src/utils/index.js"
|
|
11
11
|
},
|
|
12
12
|
"scripts": {
|
|
13
|
-
"test": "
|
|
13
|
+
"test": "vitest",
|
|
14
|
+
"test:ui": "vitest --ui",
|
|
15
|
+
"test:run": "vitest run",
|
|
16
|
+
"coverage": "vitest --coverage"
|
|
14
17
|
},
|
|
15
18
|
"keywords": [
|
|
16
19
|
"dynamodb",
|
|
@@ -39,6 +42,10 @@
|
|
|
39
42
|
"dependencies": {
|
|
40
43
|
"graphql-parse-resolve-info": "^4.13.0"
|
|
41
44
|
},
|
|
45
|
+
"devDependencies": {
|
|
46
|
+
"@vitest/ui": "^2.1.8",
|
|
47
|
+
"vitest": "^2.1.8"
|
|
48
|
+
},
|
|
42
49
|
"engines": {
|
|
43
50
|
"node": ">=18.0.0"
|
|
44
51
|
}
|
|
@@ -11,7 +11,7 @@ import { extractGridConfig } from "./gridQueryBuilder.js";
|
|
|
11
11
|
/**
|
|
12
12
|
* Extract expand policy from schema
|
|
13
13
|
* @param {*} schema - Dynamoose schema
|
|
14
|
-
* @returns {Object.<string, ExpandConfig>} Expand policies by field name
|
|
14
|
+
* @returns {Object.<string, import("../types/jsdoc.js").ExpandConfig>} Expand policies by field name
|
|
15
15
|
*/
|
|
16
16
|
export function extractExpandPolicy(schema) {
|
|
17
17
|
const gridConfig = extractGridConfig(schema);
|
|
@@ -31,15 +31,15 @@ function hashQuery({ filterModel, sortModel, pageSize }) {
|
|
|
31
31
|
/**
|
|
32
32
|
* Extract grid configuration from Dynamoose schema
|
|
33
33
|
* @param {*} schema - Dynamoose schema
|
|
34
|
-
* @returns {
|
|
34
|
+
* @returns {Object.<string, import("../types/jsdoc.js").GridConfig>} Extracted grid configuration
|
|
35
35
|
*/
|
|
36
36
|
export function extractGridConfig(schema) {
|
|
37
37
|
const attributes = schema.getAttributes();
|
|
38
38
|
const gridConfig = {};
|
|
39
39
|
|
|
40
40
|
for (const [field, definition] of Object.entries(attributes)) {
|
|
41
|
-
if (definition.
|
|
42
|
-
gridConfig[field] = definition.
|
|
41
|
+
if (definition.query) {
|
|
42
|
+
gridConfig[field] = definition.query;
|
|
43
43
|
}
|
|
44
44
|
}
|
|
45
45
|
|
package/src/utils/validation.js
CHANGED
|
@@ -20,7 +20,7 @@ export function validateSingleSort(sortModel) {
|
|
|
20
20
|
/**
|
|
21
21
|
* Validates that a field can be filtered based on grid config
|
|
22
22
|
* @param {string} field - Field name to filter
|
|
23
|
-
* @param {
|
|
23
|
+
* @param {Object.<string, import("../types/jsdoc.js").GridConfig>} gridConfig - Extracted grid configuration
|
|
24
24
|
* @throws {Error} If filtering is not allowed on this field
|
|
25
25
|
*/
|
|
26
26
|
export function validateFilterField(field, gridConfig) {
|
|
@@ -35,7 +35,7 @@ export function validateFilterField(field, gridConfig) {
|
|
|
35
35
|
/**
|
|
36
36
|
* Validates that a field can be sorted based on grid config
|
|
37
37
|
* @param {string} field - Field name to sort
|
|
38
|
-
* @param {
|
|
38
|
+
* @param {Object.<string, import("../types/jsdoc.js").GridConfig>} gridConfig - Extracted grid configuration
|
|
39
39
|
* @throws {Error} If sorting is not allowed on this field
|
|
40
40
|
*/
|
|
41
41
|
export function validateSortField(field, gridConfig) {
|
|
@@ -51,7 +51,7 @@ export function validateSortField(field, gridConfig) {
|
|
|
51
51
|
* Validates that operator is allowed for a filter field
|
|
52
52
|
* @param {string} field - Field name
|
|
53
53
|
* @param {string} operator - Operator to validate
|
|
54
|
-
* @param {
|
|
54
|
+
* @param {Object.<string, import("../types/jsdoc.js").GridConfig>} gridConfig - Extracted grid configuration
|
|
55
55
|
* @throws {Error} If operator is not allowed for this field
|
|
56
56
|
*/
|
|
57
57
|
export function validateFilterOperator(field, operator, gridConfig) {
|
|
@@ -70,7 +70,7 @@ export function validateFilterOperator(field, operator, gridConfig) {
|
|
|
70
70
|
/**
|
|
71
71
|
* Validates that a field can be expanded based on grid config
|
|
72
72
|
* @param {string} field - Field name to expand
|
|
73
|
-
* @param {
|
|
73
|
+
* @param {Object.<string, import("../types/jsdoc.js").GridConfig>} gridConfig - Extracted grid configuration
|
|
74
74
|
* @throws {Error} If expand is not allowed on this field
|
|
75
75
|
*/
|
|
76
76
|
export function validateExpandField(field, gridConfig) {
|
package/tests/README.md
ADDED
|
@@ -0,0 +1,279 @@
|
|
|
1
|
+
# Tests
|
|
2
|
+
|
|
3
|
+
Unit-Tests für DynamoDB Query Engine mit Vitest.
|
|
4
|
+
|
|
5
|
+
## Test-Struktur
|
|
6
|
+
|
|
7
|
+
```
|
|
8
|
+
tests/
|
|
9
|
+
├── unit/
|
|
10
|
+
│ ├── cursor.test.js # Cursor Utils Tests
|
|
11
|
+
│ ├── validation.test.js # Validation Tests
|
|
12
|
+
│ └── gridQueryBuilder.test.js # Query Builder Tests
|
|
13
|
+
└── mocks/
|
|
14
|
+
└── dynamoose.mock.js # Dynamoose Mock Utilities
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Tests ausführen
|
|
18
|
+
|
|
19
|
+
### Alle Tests
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npm test
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
### Tests im Watch-Modus
|
|
26
|
+
|
|
27
|
+
```bash
|
|
28
|
+
npm test -- --watch
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
### Tests mit UI
|
|
32
|
+
|
|
33
|
+
```bash
|
|
34
|
+
npm run test:ui
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
### Einzelne Tests
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
npm test cursor
|
|
41
|
+
npm test validation
|
|
42
|
+
npm test gridQueryBuilder
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### Coverage-Report
|
|
46
|
+
|
|
47
|
+
```bash
|
|
48
|
+
npm run coverage
|
|
49
|
+
```
|
|
50
|
+
|
|
51
|
+
Der Coverage-Report wird in `coverage/` generiert. Öffnen Sie `coverage/index.html` im Browser für eine detaillierte Ansicht.
|
|
52
|
+
|
|
53
|
+
## Test-Abdeckung
|
|
54
|
+
|
|
55
|
+
### Cursor Utils (~80% Coverage)
|
|
56
|
+
|
|
57
|
+
**Getestete Funktionen:**
|
|
58
|
+
- `encodeCursor()` - Base64-Encoding von Cursor-Daten
|
|
59
|
+
- `decodeCursor()` - Base64-Decoding von Cursors
|
|
60
|
+
- `validateCursor()` - Cursor-Hash-Validierung
|
|
61
|
+
|
|
62
|
+
**Test-Cases:**
|
|
63
|
+
- ✅ Erfolgreiche Encodierung
|
|
64
|
+
- ✅ Erfolgreiche Decodierung
|
|
65
|
+
- ✅ Roundtrip encode/decode
|
|
66
|
+
- ✅ Error-Handling für fehlende Parameter
|
|
67
|
+
- ✅ Error-Handling für ungültige Cursors
|
|
68
|
+
- ✅ Cursor-Validierung
|
|
69
|
+
- ✅ Hash-Mismatch-Erkennung
|
|
70
|
+
|
|
71
|
+
### Validation Utils (~70% Coverage)
|
|
72
|
+
|
|
73
|
+
**Getestete Funktionen:**
|
|
74
|
+
- `validateSingleSort()` - Validierung von Sort-Feldern
|
|
75
|
+
- `validateFilterField()` - Validierung von Filter-Feldern
|
|
76
|
+
- `validateSortField()` - Validierung von Sort-Feldern
|
|
77
|
+
- `validateFilterOperator()` - Validierung von Operatoren
|
|
78
|
+
- `validateExpandField()` - Validierung von Expand-Feldern
|
|
79
|
+
- `validatePaginationModel()` - Validierung von Pagination
|
|
80
|
+
|
|
81
|
+
**Test-Cases:**
|
|
82
|
+
- ✅ Erlaubte Konfigurationen
|
|
83
|
+
- ✅ Error bei nicht-konfigurierten Feldern
|
|
84
|
+
- ✅ Error bei ungültigen Operatoren
|
|
85
|
+
- ✅ Error bei mehrfachen Sort-Feldern
|
|
86
|
+
- ✅ Edge-Cases (leere Configs, null, undefined)
|
|
87
|
+
- ✅ Hilfreiche Fehlermeldungen
|
|
88
|
+
|
|
89
|
+
### GridQueryBuilder (~50% Coverage)
|
|
90
|
+
|
|
91
|
+
**Getestete Funktionen:**
|
|
92
|
+
- `extractGridConfig()` - Config-Extraktion aus Schema
|
|
93
|
+
- `buildGridQuery()` - Query-Generierung
|
|
94
|
+
|
|
95
|
+
**Test-Cases:**
|
|
96
|
+
- ✅ Basis-Query mit Partition Key
|
|
97
|
+
- ✅ Filter-Anwendung (eq, gte, between)
|
|
98
|
+
- ✅ Sort-Anwendung (asc/desc)
|
|
99
|
+
- ✅ Pagination mit Limit
|
|
100
|
+
- ✅ Cursor-Handling
|
|
101
|
+
- ✅ GSI-Verwendung
|
|
102
|
+
- ✅ Query-Hash-Generierung
|
|
103
|
+
- ✅ Error-Handling
|
|
104
|
+
- ✅ Komplexe Szenarien
|
|
105
|
+
|
|
106
|
+
## Mocks
|
|
107
|
+
|
|
108
|
+
### Dynamoose Mock
|
|
109
|
+
|
|
110
|
+
Der `dynamoose.mock.js` bietet Utilities zum Mocken von Dynamoose-Models:
|
|
111
|
+
|
|
112
|
+
```javascript
|
|
113
|
+
import { createMockSchema, createMockModel } from "../mocks/dynamoose.mock.js";
|
|
114
|
+
|
|
115
|
+
// Schema mocken
|
|
116
|
+
const schema = createMockSchema(attributes);
|
|
117
|
+
|
|
118
|
+
// Model mocken
|
|
119
|
+
const model = createMockModel(schema, queryResult);
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Features:**
|
|
123
|
+
- Chainable Query-Methoden
|
|
124
|
+
- Konfigurierbare Exec-Ergebnisse
|
|
125
|
+
- Schema mit `getAttributes()`
|
|
126
|
+
- Vordefinierte Test-Attribute
|
|
127
|
+
|
|
128
|
+
## Best Practices
|
|
129
|
+
|
|
130
|
+
### Test-Struktur
|
|
131
|
+
|
|
132
|
+
```javascript
|
|
133
|
+
describe("FunctionName", () => {
|
|
134
|
+
describe("Happy Path", () => {
|
|
135
|
+
it("should do X when Y", () => {
|
|
136
|
+
// Arrange
|
|
137
|
+
const input = ...;
|
|
138
|
+
|
|
139
|
+
// Act
|
|
140
|
+
const result = functionName(input);
|
|
141
|
+
|
|
142
|
+
// Assert
|
|
143
|
+
expect(result).toBe(expected);
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
describe("Error Handling", () => {
|
|
148
|
+
it("should throw error when Z", () => {
|
|
149
|
+
expect(() => {
|
|
150
|
+
functionName(invalidInput);
|
|
151
|
+
}).toThrow("Expected error message");
|
|
152
|
+
});
|
|
153
|
+
});
|
|
154
|
+
});
|
|
155
|
+
```
|
|
156
|
+
|
|
157
|
+
### beforeEach für Setup
|
|
158
|
+
|
|
159
|
+
```javascript
|
|
160
|
+
describe("MyTests", () => {
|
|
161
|
+
let mockModel;
|
|
162
|
+
let mockQuery;
|
|
163
|
+
|
|
164
|
+
beforeEach(() => {
|
|
165
|
+
mockQuery = createMockQuery();
|
|
166
|
+
mockModel = createMockModel(schema);
|
|
167
|
+
});
|
|
168
|
+
|
|
169
|
+
it("test case", () => {
|
|
170
|
+
// mockModel ist hier verfügbar
|
|
171
|
+
});
|
|
172
|
+
});
|
|
173
|
+
```
|
|
174
|
+
|
|
175
|
+
### Assertions
|
|
176
|
+
|
|
177
|
+
```javascript
|
|
178
|
+
// Exakte Gleichheit
|
|
179
|
+
expect(result).toBe(expected);
|
|
180
|
+
expect(result).toEqual(expected);
|
|
181
|
+
|
|
182
|
+
// Fehler
|
|
183
|
+
expect(() => func()).toThrow("error message");
|
|
184
|
+
expect(() => func()).toThrow(/regex pattern/);
|
|
185
|
+
|
|
186
|
+
// Mock-Aufrufe
|
|
187
|
+
expect(mockFn).toHaveBeenCalled();
|
|
188
|
+
expect(mockFn).toHaveBeenCalledWith(arg1, arg2);
|
|
189
|
+
expect(mockFn).toHaveBeenCalledTimes(1);
|
|
190
|
+
|
|
191
|
+
// Objekt-Properties
|
|
192
|
+
expect(obj).toBeDefined();
|
|
193
|
+
expect(obj.prop).toBeUndefined();
|
|
194
|
+
expect(array.length).toBeGreaterThan(0);
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Debugging
|
|
198
|
+
|
|
199
|
+
### Einzelnen Test ausführen
|
|
200
|
+
|
|
201
|
+
```javascript
|
|
202
|
+
it.only("should test specific case", () => {
|
|
203
|
+
// Nur dieser Test wird ausgeführt
|
|
204
|
+
});
|
|
205
|
+
```
|
|
206
|
+
|
|
207
|
+
### Test überspringen
|
|
208
|
+
|
|
209
|
+
```javascript
|
|
210
|
+
it.skip("should test later", () => {
|
|
211
|
+
// Wird übersprungen
|
|
212
|
+
});
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Debug-Output
|
|
216
|
+
|
|
217
|
+
```javascript
|
|
218
|
+
it("should debug test", () => {
|
|
219
|
+
console.log("Debug info:", someValue);
|
|
220
|
+
expect(someValue).toBeDefined();
|
|
221
|
+
});
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## Coverage-Ziele
|
|
225
|
+
|
|
226
|
+
- **Gesamt**: ~50-60% Coverage
|
|
227
|
+
- **Kritische Utils**: >70% Coverage
|
|
228
|
+
- **Core Logic**: ~50% Coverage
|
|
229
|
+
|
|
230
|
+
## Continuous Integration
|
|
231
|
+
|
|
232
|
+
Für CI/CD-Pipelines:
|
|
233
|
+
|
|
234
|
+
```bash
|
|
235
|
+
# Tests ohne Watch-Modus
|
|
236
|
+
npm run test:run
|
|
237
|
+
|
|
238
|
+
# Mit Coverage
|
|
239
|
+
npm run coverage
|
|
240
|
+
|
|
241
|
+
# Exit-Code bei Fehler
|
|
242
|
+
npm run test:run -- --reporter=verbose
|
|
243
|
+
```
|
|
244
|
+
|
|
245
|
+
## Erweiterung
|
|
246
|
+
|
|
247
|
+
### Neue Tests hinzufügen
|
|
248
|
+
|
|
249
|
+
1. Datei in `tests/unit/` erstellen
|
|
250
|
+
2. Vitest importieren: `import { describe, it, expect } from "vitest"`
|
|
251
|
+
3. Tests schreiben
|
|
252
|
+
4. Ausführen: `npm test`
|
|
253
|
+
|
|
254
|
+
### Neue Mocks hinzufügen
|
|
255
|
+
|
|
256
|
+
Mocks für zusätzliche Dependencies in `tests/mocks/` ablegen.
|
|
257
|
+
|
|
258
|
+
## Troubleshooting
|
|
259
|
+
|
|
260
|
+
### "Cannot find module"
|
|
261
|
+
|
|
262
|
+
```bash
|
|
263
|
+
# Dependencies installieren
|
|
264
|
+
npm install
|
|
265
|
+
```
|
|
266
|
+
|
|
267
|
+
### Tests schlagen fehl nach Code-Änderungen
|
|
268
|
+
|
|
269
|
+
```bash
|
|
270
|
+
# Cache leeren
|
|
271
|
+
npm test -- --clearCache
|
|
272
|
+
```
|
|
273
|
+
|
|
274
|
+
### Coverage zu niedrig
|
|
275
|
+
|
|
276
|
+
Fokus auf kritische Pfade:
|
|
277
|
+
- Happy Path
|
|
278
|
+
- Error-Handling
|
|
279
|
+
- Edge-Cases
|
|
@@ -0,0 +1,124 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Mock for Dynamoose models and schemas
|
|
3
|
+
*/
|
|
4
|
+
|
|
5
|
+
import { vi } from "vitest";
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Creates a mock Dynamoose schema
|
|
9
|
+
* @param {Object} attributes - Schema attributes with query config
|
|
10
|
+
* @returns {Object} Mock schema
|
|
11
|
+
*/
|
|
12
|
+
export function createMockSchema(attributes) {
|
|
13
|
+
return {
|
|
14
|
+
getAttributes: vi.fn(() => attributes),
|
|
15
|
+
};
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
/**
|
|
19
|
+
* Creates a chainable mock query object
|
|
20
|
+
* @param {*} execResult - Result to return from exec()
|
|
21
|
+
* @returns {Object} Mock query object
|
|
22
|
+
*/
|
|
23
|
+
export function createMockQuery(execResult = []) {
|
|
24
|
+
const mockQuery = {
|
|
25
|
+
eq: vi.fn().mockReturnThis(),
|
|
26
|
+
ne: vi.fn().mockReturnThis(),
|
|
27
|
+
gt: vi.fn().mockReturnThis(),
|
|
28
|
+
ge: vi.fn().mockReturnThis(),
|
|
29
|
+
lt: vi.fn().mockReturnThis(),
|
|
30
|
+
le: vi.fn().mockReturnThis(),
|
|
31
|
+
between: vi.fn().mockReturnThis(),
|
|
32
|
+
beginsWith: vi.fn().mockReturnThis(),
|
|
33
|
+
contains: vi.fn().mockReturnThis(),
|
|
34
|
+
where: vi.fn().mockReturnThis(),
|
|
35
|
+
using: vi.fn().mockReturnThis(),
|
|
36
|
+
limit: vi.fn().mockReturnThis(),
|
|
37
|
+
sort: vi.fn().mockReturnThis(),
|
|
38
|
+
startAt: vi.fn().mockReturnThis(),
|
|
39
|
+
exec: vi.fn().mockResolvedValue(execResult),
|
|
40
|
+
};
|
|
41
|
+
|
|
42
|
+
return mockQuery;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Creates a mock Dynamoose model
|
|
47
|
+
* @param {Object} schema - Mock schema
|
|
48
|
+
* @param {*} queryResult - Result to return from query execution
|
|
49
|
+
* @returns {Object} Mock model
|
|
50
|
+
*/
|
|
51
|
+
export function createMockModel(schema, queryResult = []) {
|
|
52
|
+
const mockQuery = createMockQuery(queryResult);
|
|
53
|
+
|
|
54
|
+
return {
|
|
55
|
+
schema,
|
|
56
|
+
query: vi.fn(() => mockQuery),
|
|
57
|
+
_mockQuery: mockQuery, // Expose for testing
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
/**
|
|
62
|
+
* Common schema attributes for testing
|
|
63
|
+
*/
|
|
64
|
+
export const mockAttributes = {
|
|
65
|
+
pk: {
|
|
66
|
+
type: String,
|
|
67
|
+
hashKey: true,
|
|
68
|
+
},
|
|
69
|
+
createdAt: {
|
|
70
|
+
type: String,
|
|
71
|
+
rangeKey: true,
|
|
72
|
+
query: {
|
|
73
|
+
sort: { type: "key" },
|
|
74
|
+
filter: {
|
|
75
|
+
type: "key",
|
|
76
|
+
operators: ["between", "gte", "lte"],
|
|
77
|
+
},
|
|
78
|
+
},
|
|
79
|
+
},
|
|
80
|
+
status: {
|
|
81
|
+
type: String,
|
|
82
|
+
index: {
|
|
83
|
+
name: "status-createdAt-index",
|
|
84
|
+
global: true,
|
|
85
|
+
rangeKey: "createdAt",
|
|
86
|
+
},
|
|
87
|
+
query: {
|
|
88
|
+
filter: {
|
|
89
|
+
type: "key",
|
|
90
|
+
operators: ["eq"],
|
|
91
|
+
index: "status-createdAt-index",
|
|
92
|
+
},
|
|
93
|
+
},
|
|
94
|
+
},
|
|
95
|
+
email: {
|
|
96
|
+
type: String,
|
|
97
|
+
index: {
|
|
98
|
+
name: "email-index",
|
|
99
|
+
global: true,
|
|
100
|
+
},
|
|
101
|
+
query: {
|
|
102
|
+
filter: {
|
|
103
|
+
type: "key",
|
|
104
|
+
operators: ["eq"],
|
|
105
|
+
index: "email-index",
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
name: {
|
|
110
|
+
type: String,
|
|
111
|
+
},
|
|
112
|
+
teamIds: {
|
|
113
|
+
type: Array,
|
|
114
|
+
schema: [String],
|
|
115
|
+
query: {
|
|
116
|
+
expand: {
|
|
117
|
+
type: "Team",
|
|
118
|
+
relation: "MANY",
|
|
119
|
+
defaultLimit: 5,
|
|
120
|
+
maxLimit: 20,
|
|
121
|
+
},
|
|
122
|
+
},
|
|
123
|
+
},
|
|
124
|
+
};
|