@starbemtech/star-db-query-builder 1.3.1 → 1.4.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.
- package/.claude/skills/star-db-query-builder/SKILL.md +104 -0
- package/CHANGELOG.md +82 -45
- package/LICENSE +21 -0
- package/README.md +194 -94
- package/bin/install-skill.js +53 -0
- package/dist/src/core/repository.d.ts +92 -9
- package/dist/src/core/repository.js +275 -27
- package/dist/src/core/repository.js.map +1 -1
- package/dist/src/core/types.d.ts +16 -1
- package/dist/src/core/utils.d.ts +102 -0
- package/dist/src/core/utils.js +287 -70
- package/dist/src/core/utils.js.map +1 -1
- package/dist/src/db/initDb.d.ts +60 -50
- package/dist/src/db/initDb.js +96 -64
- package/dist/src/db/initDb.js.map +1 -1
- package/dist/src/db/mysqlClient.d.ts +3 -8
- package/dist/src/db/mysqlClient.js +9 -11
- package/dist/src/db/mysqlClient.js.map +1 -1
- package/dist/src/db/pgClient.js +0 -2
- package/dist/src/db/pgClient.js.map +1 -1
- package/dist/src/monitor/monitor.js +7 -0
- package/dist/src/monitor/monitor.js.map +1 -1
- package/package.json +27 -19
- package/.github/workflows/publish.yml +0 -118
- package/.prettierignore +0 -3
- package/.prettierrc +0 -5
- package/ARCHITECTURE.md +0 -313
- package/coverage/base.css +0 -224
- package/coverage/block-navigation.js +0 -87
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +0 -131
- package/coverage/lcov-report/base.css +0 -224
- package/coverage/lcov-report/block-navigation.js +0 -87
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +0 -131
- package/coverage/lcov-report/mysqlClient.ts.html +0 -685
- package/coverage/lcov-report/pgClient.ts.html +0 -823
- package/coverage/lcov-report/prettify.css +0 -1
- package/coverage/lcov-report/prettify.js +0 -2
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +0 -210
- package/coverage/lcov.info +0 -533
- package/coverage/mysqlClient.ts.html +0 -685
- package/coverage/pgClient.ts.html +0 -823
- package/coverage/prettify.css +0 -1
- package/coverage/prettify.js +0 -2
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +0 -210
- package/dist/src/setupTests.d.ts +0 -26
- package/dist/src/setupTests.js +0 -43
- package/dist/src/setupTests.js.map +0 -1
- package/docs/INDEX.md +0 -145
- package/docs/methods/findFirst.md +0 -394
- package/docs/methods/findMany.md +0 -587
- package/docs/methods/insert.md +0 -536
- package/docs/methods/insertMany.md +0 -627
- package/docs/methods/joins.md +0 -781
- package/docs/methods/rawQuery.md +0 -284
- package/docs/methods/transactions.md +0 -737
- package/eslint.config.mjs +0 -77
- package/index.ts +0 -16
- package/jest.config.ts +0 -194
- package/scripts/release.sh +0 -123
- package/src/core/repository.ts +0 -865
- package/src/core/types.ts +0 -97
- package/src/core/utils.ts +0 -357
- package/src/db/IDatabaseClient.ts +0 -16
- package/src/db/__tests__/mysqlClient.test.ts +0 -262
- package/src/db/__tests__/pgClient.test.ts +0 -260
- package/src/db/initDb.ts +0 -181
- package/src/db/mysqlClient.ts +0 -200
- package/src/db/pgClient.ts +0 -246
- package/src/monitor/monitor.ts +0 -16
- package/src/setupTests.ts +0 -45
- package/tsconfig.test.json +0 -21
package/docs/methods/findMany.md
DELETED
|
@@ -1,587 +0,0 @@
|
|
|
1
|
-
# findMany
|
|
2
|
-
|
|
3
|
-
Finds multiple records that match the specified conditions from a database table.
|
|
4
|
-
|
|
5
|
-
## Signature
|
|
6
|
-
|
|
7
|
-
```typescript
|
|
8
|
-
findMany<T>({
|
|
9
|
-
tableName: string,
|
|
10
|
-
dbClient: IDatabaseClient,
|
|
11
|
-
select?: string[],
|
|
12
|
-
where?: Conditions<T>,
|
|
13
|
-
groupBy?: string[],
|
|
14
|
-
orderBy?: OrderBy,
|
|
15
|
-
limit?: number,
|
|
16
|
-
offset?: number,
|
|
17
|
-
unaccent?: boolean
|
|
18
|
-
}): Promise<T[]>
|
|
19
|
-
```
|
|
20
|
-
|
|
21
|
-
## Parameters
|
|
22
|
-
|
|
23
|
-
| Parameter | Type | Required | Description |
|
|
24
|
-
| ----------- | ----------------- | -------- | ---------------------------------------------------- |
|
|
25
|
-
| `tableName` | `string` | ✅ | Name of the database table |
|
|
26
|
-
| `dbClient` | `IDatabaseClient` | ✅ | Database client instance |
|
|
27
|
-
| `select` | `string[]` | ❌ | Array of field names to select (default: all fields) |
|
|
28
|
-
| `where` | `Conditions<T>` | ❌ | Conditions to filter records |
|
|
29
|
-
| `groupBy` | `string[]` | ❌ | Fields to group by |
|
|
30
|
-
| `orderBy` | `OrderBy` | ❌ | Sort order specification |
|
|
31
|
-
| `limit` | `number` | ❌ | Maximum number of records to return |
|
|
32
|
-
| `offset` | `number` | ❌ | Number of records to skip |
|
|
33
|
-
| `unaccent` | `boolean` | ❌ | Enable unaccent search for PostgreSQL |
|
|
34
|
-
|
|
35
|
-
## Return Value
|
|
36
|
-
|
|
37
|
-
- **Type**: `Promise<T[]>`
|
|
38
|
-
- **Description**: Returns an array of matching records (empty array if no records found)
|
|
39
|
-
|
|
40
|
-
## Examples
|
|
41
|
-
|
|
42
|
-
### Basic Usage
|
|
43
|
-
|
|
44
|
-
```typescript
|
|
45
|
-
import { findMany } from '@starbemtech/star-db-query-builder'
|
|
46
|
-
|
|
47
|
-
// Find all active users
|
|
48
|
-
const users = await findMany({
|
|
49
|
-
tableName: 'users',
|
|
50
|
-
dbClient,
|
|
51
|
-
where: {
|
|
52
|
-
status: { operator: '=', value: 'active' },
|
|
53
|
-
},
|
|
54
|
-
})
|
|
55
|
-
|
|
56
|
-
console.log(users) // [{ id: 'user-1', name: 'John', ... }, { id: 'user-2', name: 'Jane', ... }]
|
|
57
|
-
```
|
|
58
|
-
|
|
59
|
-
### With Pagination
|
|
60
|
-
|
|
61
|
-
```typescript
|
|
62
|
-
// Get first 10 users
|
|
63
|
-
const users = await findMany({
|
|
64
|
-
tableName: 'users',
|
|
65
|
-
dbClient,
|
|
66
|
-
limit: 10,
|
|
67
|
-
offset: 0,
|
|
68
|
-
orderBy: [{ field: 'created_at', direction: 'DESC' }],
|
|
69
|
-
})
|
|
70
|
-
|
|
71
|
-
// Get next 10 users (page 2)
|
|
72
|
-
const nextUsers = await findMany({
|
|
73
|
-
tableName: 'users',
|
|
74
|
-
dbClient,
|
|
75
|
-
limit: 10,
|
|
76
|
-
offset: 10,
|
|
77
|
-
orderBy: [{ field: 'created_at', direction: 'DESC' }],
|
|
78
|
-
})
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### With Specific Fields
|
|
82
|
-
|
|
83
|
-
```typescript
|
|
84
|
-
// Select only specific fields
|
|
85
|
-
const users = await findMany({
|
|
86
|
-
tableName: 'users',
|
|
87
|
-
dbClient,
|
|
88
|
-
select: ['id', 'name', 'email', 'created_at'],
|
|
89
|
-
where: {
|
|
90
|
-
status: { operator: '=', value: 'active' },
|
|
91
|
-
},
|
|
92
|
-
})
|
|
93
|
-
```
|
|
94
|
-
|
|
95
|
-
### With Complex Conditions
|
|
96
|
-
|
|
97
|
-
```typescript
|
|
98
|
-
// Multiple conditions with AND
|
|
99
|
-
const users = await findMany({
|
|
100
|
-
tableName: 'users',
|
|
101
|
-
dbClient,
|
|
102
|
-
where: {
|
|
103
|
-
AND: [
|
|
104
|
-
{ status: { operator: '=', value: 'active' } },
|
|
105
|
-
{ age: { operator: '>=', value: 18 } },
|
|
106
|
-
{ verified: { operator: '=', value: true } },
|
|
107
|
-
],
|
|
108
|
-
},
|
|
109
|
-
})
|
|
110
|
-
|
|
111
|
-
// Multiple conditions with OR
|
|
112
|
-
const users = await findMany({
|
|
113
|
-
tableName: 'users',
|
|
114
|
-
dbClient,
|
|
115
|
-
where: {
|
|
116
|
-
OR: [
|
|
117
|
-
{ status: { operator: '=', value: 'active' } },
|
|
118
|
-
{ status: { operator: '=', value: 'pending' } },
|
|
119
|
-
],
|
|
120
|
-
created_at: {
|
|
121
|
-
operator: '>=',
|
|
122
|
-
value: new Date('2023-01-01'),
|
|
123
|
-
},
|
|
124
|
-
},
|
|
125
|
-
})
|
|
126
|
-
```
|
|
127
|
-
|
|
128
|
-
### With Grouping and Aggregation
|
|
129
|
-
|
|
130
|
-
```typescript
|
|
131
|
-
// Group users by status and count them
|
|
132
|
-
const userStats = await findMany({
|
|
133
|
-
tableName: 'users',
|
|
134
|
-
dbClient,
|
|
135
|
-
select: ['status', 'COUNT(*) as count'],
|
|
136
|
-
groupBy: ['status'],
|
|
137
|
-
})
|
|
138
|
-
|
|
139
|
-
console.log(userStats) // [{ status: 'active', count: 150 }, { status: 'inactive', count: 25 }]
|
|
140
|
-
|
|
141
|
-
// Group by multiple fields
|
|
142
|
-
const userStatsByAge = await findMany({
|
|
143
|
-
tableName: 'users',
|
|
144
|
-
dbClient,
|
|
145
|
-
select: ['status', 'age_group', 'COUNT(*) as count', 'AVG(age) as avg_age'],
|
|
146
|
-
groupBy: ['status', 'age_group'],
|
|
147
|
-
where: { status: { operator: '=', value: 'active' } },
|
|
148
|
-
})
|
|
149
|
-
```
|
|
150
|
-
|
|
151
|
-
### With Different Operators
|
|
152
|
-
|
|
153
|
-
```typescript
|
|
154
|
-
// Using various operators
|
|
155
|
-
const users = await findMany({
|
|
156
|
-
tableName: 'users',
|
|
157
|
-
dbClient,
|
|
158
|
-
where: {
|
|
159
|
-
age: { operator: '>=', value: 18 },
|
|
160
|
-
name: { operator: 'LIKE', value: '%John%' },
|
|
161
|
-
email: { operator: 'IS NOT NULL', value: null },
|
|
162
|
-
status: { operator: 'IN', value: ['active', 'pending'] },
|
|
163
|
-
created_at: {
|
|
164
|
-
operator: 'BETWEEN',
|
|
165
|
-
value: [new Date('2023-01-01'), new Date('2023-12-31')],
|
|
166
|
-
},
|
|
167
|
-
},
|
|
168
|
-
})
|
|
169
|
-
```
|
|
170
|
-
|
|
171
|
-
### With Unaccent Search (PostgreSQL)
|
|
172
|
-
|
|
173
|
-
```typescript
|
|
174
|
-
// Search with unaccent for better text matching
|
|
175
|
-
const users = await findMany({
|
|
176
|
-
tableName: 'users',
|
|
177
|
-
dbClient,
|
|
178
|
-
where: {
|
|
179
|
-
name: { operator: 'ILIKE', value: '%joão%' },
|
|
180
|
-
},
|
|
181
|
-
unaccent: true, // Enables unaccent search
|
|
182
|
-
})
|
|
183
|
-
```
|
|
184
|
-
|
|
185
|
-
### TypeScript Usage
|
|
186
|
-
|
|
187
|
-
```typescript
|
|
188
|
-
interface User {
|
|
189
|
-
id: string
|
|
190
|
-
name: string
|
|
191
|
-
email: string
|
|
192
|
-
age: number
|
|
193
|
-
status: 'active' | 'inactive' | 'pending'
|
|
194
|
-
created_at: Date
|
|
195
|
-
updated_at: Date
|
|
196
|
-
}
|
|
197
|
-
|
|
198
|
-
// Typed usage
|
|
199
|
-
const users: User[] = await findMany<User>({
|
|
200
|
-
tableName: 'users',
|
|
201
|
-
dbClient,
|
|
202
|
-
where: {
|
|
203
|
-
status: { operator: '=', value: 'active' },
|
|
204
|
-
},
|
|
205
|
-
})
|
|
206
|
-
|
|
207
|
-
console.log(`Found ${users.length} active users`)
|
|
208
|
-
```
|
|
209
|
-
|
|
210
|
-
### Advanced Pagination
|
|
211
|
-
|
|
212
|
-
```typescript
|
|
213
|
-
interface PaginationParams {
|
|
214
|
-
page: number
|
|
215
|
-
limit: number
|
|
216
|
-
sortBy?: string
|
|
217
|
-
sortOrder?: 'ASC' | 'DESC'
|
|
218
|
-
}
|
|
219
|
-
|
|
220
|
-
const getUsersPaginated = async (params: PaginationParams) => {
|
|
221
|
-
const offset = (params.page - 1) * params.limit
|
|
222
|
-
|
|
223
|
-
const users = await findMany({
|
|
224
|
-
tableName: 'users',
|
|
225
|
-
dbClient,
|
|
226
|
-
limit: params.limit,
|
|
227
|
-
offset,
|
|
228
|
-
orderBy: params.sortBy
|
|
229
|
-
? [
|
|
230
|
-
{
|
|
231
|
-
field: params.sortBy,
|
|
232
|
-
direction: params.sortOrder || 'ASC',
|
|
233
|
-
},
|
|
234
|
-
]
|
|
235
|
-
: undefined,
|
|
236
|
-
})
|
|
237
|
-
|
|
238
|
-
return users
|
|
239
|
-
}
|
|
240
|
-
|
|
241
|
-
// Usage
|
|
242
|
-
const page1Users = await getUsersPaginated({
|
|
243
|
-
page: 1,
|
|
244
|
-
limit: 20,
|
|
245
|
-
sortBy: 'created_at',
|
|
246
|
-
sortOrder: 'DESC',
|
|
247
|
-
})
|
|
248
|
-
```
|
|
249
|
-
|
|
250
|
-
### Error Handling
|
|
251
|
-
|
|
252
|
-
```typescript
|
|
253
|
-
try {
|
|
254
|
-
const users = await findMany({
|
|
255
|
-
tableName: 'users',
|
|
256
|
-
dbClient,
|
|
257
|
-
where: { status: { operator: '=', value: 'active' } },
|
|
258
|
-
})
|
|
259
|
-
|
|
260
|
-
console.log(`Found ${users.length} users`)
|
|
261
|
-
} catch (error) {
|
|
262
|
-
console.error('Database error:', error.message)
|
|
263
|
-
// Handle error appropriately
|
|
264
|
-
}
|
|
265
|
-
```
|
|
266
|
-
|
|
267
|
-
## Generated SQL Examples
|
|
268
|
-
|
|
269
|
-
### Simple Query
|
|
270
|
-
|
|
271
|
-
```sql
|
|
272
|
-
SELECT * FROM users WHERE status = $1
|
|
273
|
-
```
|
|
274
|
-
|
|
275
|
-
### With Pagination
|
|
276
|
-
|
|
277
|
-
```sql
|
|
278
|
-
SELECT * FROM users
|
|
279
|
-
ORDER BY created_at DESC
|
|
280
|
-
LIMIT 10 OFFSET 20
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
### With Specific Fields
|
|
284
|
-
|
|
285
|
-
```sql
|
|
286
|
-
SELECT id, name, email FROM users WHERE status = $1
|
|
287
|
-
```
|
|
288
|
-
|
|
289
|
-
### With Complex Conditions
|
|
290
|
-
|
|
291
|
-
```sql
|
|
292
|
-
SELECT * FROM users
|
|
293
|
-
WHERE (status = $1 AND age >= $2 AND verified = $3)
|
|
294
|
-
```
|
|
295
|
-
|
|
296
|
-
### With Grouping
|
|
297
|
-
|
|
298
|
-
```sql
|
|
299
|
-
SELECT status, COUNT(*) as count
|
|
300
|
-
FROM users
|
|
301
|
-
GROUP BY status
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
### With Unaccent (PostgreSQL)
|
|
305
|
-
|
|
306
|
-
```sql
|
|
307
|
-
SELECT * FROM users
|
|
308
|
-
WHERE unaccent(name) ILIKE unaccent($1)
|
|
309
|
-
```
|
|
310
|
-
|
|
311
|
-
## Best Practices
|
|
312
|
-
|
|
313
|
-
### 1. Always Use Pagination for Large Datasets
|
|
314
|
-
|
|
315
|
-
```typescript
|
|
316
|
-
// Good: Use pagination
|
|
317
|
-
const users = await findMany({
|
|
318
|
-
tableName: 'users',
|
|
319
|
-
dbClient,
|
|
320
|
-
limit: 100,
|
|
321
|
-
offset: 0,
|
|
322
|
-
orderBy: [{ field: 'created_at', direction: 'DESC' }],
|
|
323
|
-
})
|
|
324
|
-
|
|
325
|
-
// Avoid: Loading all records at once
|
|
326
|
-
const allUsers = await findMany({
|
|
327
|
-
tableName: 'users',
|
|
328
|
-
dbClient,
|
|
329
|
-
})
|
|
330
|
-
```
|
|
331
|
-
|
|
332
|
-
### 2. Use Specific Field Selection
|
|
333
|
-
|
|
334
|
-
```typescript
|
|
335
|
-
// Good: Select only needed fields
|
|
336
|
-
const users = await findMany({
|
|
337
|
-
tableName: 'users',
|
|
338
|
-
dbClient,
|
|
339
|
-
select: ['id', 'name', 'email'],
|
|
340
|
-
where: { status: { operator: '=', value: 'active' } },
|
|
341
|
-
})
|
|
342
|
-
|
|
343
|
-
// Avoid: Selecting all fields when not needed
|
|
344
|
-
const users = await findMany({
|
|
345
|
-
tableName: 'users',
|
|
346
|
-
dbClient,
|
|
347
|
-
where: { status: { operator: '=', value: 'active' } },
|
|
348
|
-
})
|
|
349
|
-
```
|
|
350
|
-
|
|
351
|
-
### 3. Use Appropriate Indexes
|
|
352
|
-
|
|
353
|
-
Ensure your database has indexes on fields used in WHERE clauses:
|
|
354
|
-
|
|
355
|
-
```sql
|
|
356
|
-
-- Example indexes for common queries
|
|
357
|
-
CREATE INDEX idx_users_status ON users(status);
|
|
358
|
-
CREATE INDEX idx_users_created_at ON users(created_at);
|
|
359
|
-
CREATE INDEX idx_users_email ON users(email);
|
|
360
|
-
CREATE INDEX idx_users_age ON users(age);
|
|
361
|
-
```
|
|
362
|
-
|
|
363
|
-
### 4. Handle Empty Results
|
|
364
|
-
|
|
365
|
-
```typescript
|
|
366
|
-
const users = await findMany({
|
|
367
|
-
tableName: 'users',
|
|
368
|
-
dbClient,
|
|
369
|
-
where: { status: { operator: '=', value: 'nonexistent' } },
|
|
370
|
-
})
|
|
371
|
-
|
|
372
|
-
if (users.length === 0) {
|
|
373
|
-
console.log('No users found')
|
|
374
|
-
} else {
|
|
375
|
-
console.log(`Found ${users.length} users`)
|
|
376
|
-
}
|
|
377
|
-
```
|
|
378
|
-
|
|
379
|
-
### 5. Use TypeScript for Type Safety
|
|
380
|
-
|
|
381
|
-
```typescript
|
|
382
|
-
interface UserSearchParams {
|
|
383
|
-
status?: string
|
|
384
|
-
minAge?: number
|
|
385
|
-
maxAge?: number
|
|
386
|
-
searchTerm?: string
|
|
387
|
-
}
|
|
388
|
-
|
|
389
|
-
const searchUsers = async (params: UserSearchParams): Promise<User[]> => {
|
|
390
|
-
const where: Conditions<User> = {}
|
|
391
|
-
|
|
392
|
-
if (params.status) {
|
|
393
|
-
where.status = { operator: '=', value: params.status }
|
|
394
|
-
}
|
|
395
|
-
|
|
396
|
-
if (params.minAge || params.maxAge) {
|
|
397
|
-
if (params.minAge && params.maxAge) {
|
|
398
|
-
where.age = {
|
|
399
|
-
operator: 'BETWEEN',
|
|
400
|
-
value: [params.minAge, params.maxAge],
|
|
401
|
-
}
|
|
402
|
-
} else if (params.minAge) {
|
|
403
|
-
where.age = { operator: '>=', value: params.minAge }
|
|
404
|
-
} else if (params.maxAge) {
|
|
405
|
-
where.age = { operator: '<=', value: params.maxAge }
|
|
406
|
-
}
|
|
407
|
-
}
|
|
408
|
-
|
|
409
|
-
if (params.searchTerm) {
|
|
410
|
-
where.name = { operator: 'ILIKE', value: `%${params.searchTerm}%` }
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
return findMany<User>({
|
|
414
|
-
tableName: 'users',
|
|
415
|
-
dbClient,
|
|
416
|
-
where,
|
|
417
|
-
})
|
|
418
|
-
}
|
|
419
|
-
```
|
|
420
|
-
|
|
421
|
-
## Common Use Cases
|
|
422
|
-
|
|
423
|
-
### 1. User Management
|
|
424
|
-
|
|
425
|
-
```typescript
|
|
426
|
-
// Get all active users with pagination
|
|
427
|
-
const getActiveUsers = async (page: number = 1, limit: number = 20) => {
|
|
428
|
-
const offset = (page - 1) * limit
|
|
429
|
-
|
|
430
|
-
return findMany({
|
|
431
|
-
tableName: 'users',
|
|
432
|
-
dbClient,
|
|
433
|
-
select: ['id', 'name', 'email', 'created_at'],
|
|
434
|
-
where: { status: { operator: '=', value: 'active' } },
|
|
435
|
-
limit,
|
|
436
|
-
offset,
|
|
437
|
-
orderBy: [{ field: 'created_at', direction: 'DESC' }],
|
|
438
|
-
})
|
|
439
|
-
}
|
|
440
|
-
```
|
|
441
|
-
|
|
442
|
-
### 2. Search Functionality
|
|
443
|
-
|
|
444
|
-
```typescript
|
|
445
|
-
const searchUsers = async (searchTerm: string) => {
|
|
446
|
-
return findMany({
|
|
447
|
-
tableName: 'users',
|
|
448
|
-
dbClient,
|
|
449
|
-
where: {
|
|
450
|
-
OR: [
|
|
451
|
-
{ name: { operator: 'ILIKE', value: `%${searchTerm}%` } },
|
|
452
|
-
{ email: { operator: 'ILIKE', value: `%${searchTerm}%` } },
|
|
453
|
-
],
|
|
454
|
-
},
|
|
455
|
-
orderBy: [{ field: 'name', direction: 'ASC' }],
|
|
456
|
-
})
|
|
457
|
-
}
|
|
458
|
-
```
|
|
459
|
-
|
|
460
|
-
### 3. Analytics and Reporting
|
|
461
|
-
|
|
462
|
-
```typescript
|
|
463
|
-
// Get user statistics by status
|
|
464
|
-
const getUserStats = async () => {
|
|
465
|
-
return findMany({
|
|
466
|
-
tableName: 'users',
|
|
467
|
-
dbClient,
|
|
468
|
-
select: ['status', 'COUNT(*) as count'],
|
|
469
|
-
groupBy: ['status'],
|
|
470
|
-
})
|
|
471
|
-
}
|
|
472
|
-
|
|
473
|
-
// Get monthly user registrations
|
|
474
|
-
const getMonthlyRegistrations = async (year: number) => {
|
|
475
|
-
return findMany({
|
|
476
|
-
tableName: 'users',
|
|
477
|
-
dbClient,
|
|
478
|
-
select: ['EXTRACT(MONTH FROM created_at) as month', 'COUNT(*) as count'],
|
|
479
|
-
where: {
|
|
480
|
-
created_at: {
|
|
481
|
-
operator: 'BETWEEN',
|
|
482
|
-
value: [new Date(`${year}-01-01`), new Date(`${year}-12-31`)],
|
|
483
|
-
},
|
|
484
|
-
},
|
|
485
|
-
groupBy: ['EXTRACT(MONTH FROM created_at)'],
|
|
486
|
-
orderBy: [{ field: 'month', direction: 'ASC' }],
|
|
487
|
-
})
|
|
488
|
-
}
|
|
489
|
-
```
|
|
490
|
-
|
|
491
|
-
### 4. Data Export
|
|
492
|
-
|
|
493
|
-
```typescript
|
|
494
|
-
const exportUsers = async (filters: UserSearchParams) => {
|
|
495
|
-
const where: Conditions<User> = {}
|
|
496
|
-
|
|
497
|
-
if (filters.status) {
|
|
498
|
-
where.status = { operator: '=', value: filters.status }
|
|
499
|
-
}
|
|
500
|
-
|
|
501
|
-
if (filters.createdAfter) {
|
|
502
|
-
where.created_at = { operator: '>=', value: filters.createdAfter }
|
|
503
|
-
}
|
|
504
|
-
|
|
505
|
-
return findMany({
|
|
506
|
-
tableName: 'users',
|
|
507
|
-
dbClient,
|
|
508
|
-
select: ['id', 'name', 'email', 'status', 'created_at'],
|
|
509
|
-
where,
|
|
510
|
-
orderBy: [{ field: 'created_at', direction: 'DESC' }],
|
|
511
|
-
})
|
|
512
|
-
}
|
|
513
|
-
```
|
|
514
|
-
|
|
515
|
-
## Performance Considerations
|
|
516
|
-
|
|
517
|
-
### 1. Indexing Strategy
|
|
518
|
-
|
|
519
|
-
```sql
|
|
520
|
-
-- Composite indexes for common query patterns
|
|
521
|
-
CREATE INDEX idx_users_status_created_at ON users(status, created_at);
|
|
522
|
-
CREATE INDEX idx_users_age_status ON users(age, status);
|
|
523
|
-
|
|
524
|
-
-- Partial indexes for specific conditions
|
|
525
|
-
CREATE INDEX idx_users_active_created_at ON users(created_at)
|
|
526
|
-
WHERE status = 'active';
|
|
527
|
-
```
|
|
528
|
-
|
|
529
|
-
### 2. Query Optimization
|
|
530
|
-
|
|
531
|
-
```typescript
|
|
532
|
-
// Good: Use indexed fields in WHERE clause
|
|
533
|
-
const users = await findMany({
|
|
534
|
-
tableName: 'users',
|
|
535
|
-
dbClient,
|
|
536
|
-
where: {
|
|
537
|
-
status: { operator: '=', value: 'active' }, // Indexed field
|
|
538
|
-
created_at: { operator: '>=', value: new Date('2023-01-01') }, // Indexed field
|
|
539
|
-
},
|
|
540
|
-
})
|
|
541
|
-
|
|
542
|
-
// Avoid: Using non-indexed fields in WHERE clause
|
|
543
|
-
const users = await findMany({
|
|
544
|
-
tableName: 'users',
|
|
545
|
-
dbClient,
|
|
546
|
-
where: {
|
|
547
|
-
bio: { operator: 'LIKE', value: '%developer%' }, // Non-indexed field
|
|
548
|
-
},
|
|
549
|
-
})
|
|
550
|
-
```
|
|
551
|
-
|
|
552
|
-
### 3. Memory Management
|
|
553
|
-
|
|
554
|
-
```typescript
|
|
555
|
-
// For large datasets, process in batches
|
|
556
|
-
const processUsersInBatches = async (batchSize: number = 1000) => {
|
|
557
|
-
let offset = 0
|
|
558
|
-
let hasMore = true
|
|
559
|
-
|
|
560
|
-
while (hasMore) {
|
|
561
|
-
const users = await findMany({
|
|
562
|
-
tableName: 'users',
|
|
563
|
-
dbClient,
|
|
564
|
-
limit: batchSize,
|
|
565
|
-
offset,
|
|
566
|
-
orderBy: [{ field: 'id', direction: 'ASC' }],
|
|
567
|
-
})
|
|
568
|
-
|
|
569
|
-
if (users.length === 0) {
|
|
570
|
-
hasMore = false
|
|
571
|
-
} else {
|
|
572
|
-
// Process batch
|
|
573
|
-
await processBatch(users)
|
|
574
|
-
offset += batchSize
|
|
575
|
-
}
|
|
576
|
-
}
|
|
577
|
-
}
|
|
578
|
-
```
|
|
579
|
-
|
|
580
|
-
## Error Messages
|
|
581
|
-
|
|
582
|
-
Common error messages you might encounter:
|
|
583
|
-
|
|
584
|
-
- `Table name is required` - The `tableName` parameter is missing
|
|
585
|
-
- `DB client is required` - The `dbClient` parameter is missing
|
|
586
|
-
- Database-specific errors from the underlying database driver
|
|
587
|
-
- Memory errors when trying to load too many records at once
|