@starbemtech/star-db-query-builder 1.1.0 → 1.3.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/.github/workflows/publish.yml +118 -0
- package/ARCHITECTURE.md +313 -0
- package/CHANGELOG.md +67 -0
- package/README.md +1275 -210
- package/coverage/base.css +224 -0
- package/coverage/block-navigation.js +87 -0
- package/coverage/favicon.png +0 -0
- package/coverage/index.html +131 -0
- package/coverage/lcov-report/base.css +224 -0
- package/coverage/lcov-report/block-navigation.js +87 -0
- package/coverage/lcov-report/favicon.png +0 -0
- package/coverage/lcov-report/index.html +131 -0
- package/coverage/lcov-report/mysqlClient.ts.html +685 -0
- package/coverage/lcov-report/pgClient.ts.html +823 -0
- package/coverage/lcov-report/prettify.css +1 -0
- package/coverage/lcov-report/prettify.js +2 -0
- package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
- package/coverage/lcov-report/sorter.js +210 -0
- package/coverage/lcov.info +533 -0
- package/coverage/mysqlClient.ts.html +685 -0
- package/coverage/pgClient.ts.html +823 -0
- package/coverage/prettify.css +1 -0
- package/coverage/prettify.js +2 -0
- package/coverage/sort-arrow-sprite.png +0 -0
- package/coverage/sorter.js +210 -0
- package/dist/index.d.ts +5 -4
- package/dist/index.js +1 -1
- package/dist/index.js.map +1 -1
- package/dist/src/core/repository.d.ts +374 -0
- package/dist/src/core/repository.js +677 -0
- package/dist/src/core/repository.js.map +1 -0
- package/dist/src/{default → core}/types.d.ts +8 -0
- package/dist/src/{default → core}/types.js.map +1 -1
- package/dist/src/core/utils.d.ts +133 -0
- package/dist/src/{default → core}/utils.js +167 -0
- package/dist/src/core/utils.js.map +1 -0
- package/dist/src/db/IDatabaseClient.d.ts +10 -1
- package/dist/src/db/initDb.d.ts +120 -1
- package/dist/src/db/initDb.js +119 -0
- package/dist/src/db/initDb.js.map +1 -1
- package/dist/src/db/mysqlClient.d.ts +23 -1
- package/dist/src/db/mysqlClient.js +115 -0
- package/dist/src/db/mysqlClient.js.map +1 -1
- package/dist/src/db/pgClient.d.ts +22 -1
- package/dist/src/db/pgClient.js +127 -0
- package/dist/src/db/pgClient.js.map +1 -1
- package/dist/src/monitor/monitor.d.ts +6 -1
- package/dist/src/monitor/monitor.js +5 -0
- package/dist/src/monitor/monitor.js.map +1 -1
- package/dist/src/setupTests.d.ts +26 -0
- package/dist/src/setupTests.js +43 -0
- package/dist/src/setupTests.js.map +1 -0
- package/docs/INDEX.md +145 -0
- package/docs/methods/findFirst.md +394 -0
- package/docs/methods/findMany.md +587 -0
- package/docs/methods/insert.md +536 -0
- package/docs/methods/insertMany.md +627 -0
- package/docs/methods/joins.md +781 -0
- package/docs/methods/rawQuery.md +284 -0
- package/docs/methods/transactions.md +737 -0
- package/eslint.config.mjs +77 -0
- package/index.ts +5 -4
- package/jest.config.ts +23 -28
- package/package.json +53 -30
- package/scripts/release.sh +123 -0
- package/src/core/repository.ts +865 -0
- package/src/{default → core}/types.ts +10 -1
- package/src/{default → core}/utils.ts +168 -0
- package/src/db/IDatabaseClient.ts +11 -1
- package/src/db/__tests__/mysqlClient.test.ts +262 -0
- package/src/db/__tests__/pgClient.test.ts +260 -0
- package/src/db/initDb.ts +120 -1
- package/src/db/mysqlClient.ts +119 -3
- package/src/db/pgClient.ts +131 -3
- package/src/monitor/monitor.ts +5 -0
- package/src/setupTests.ts +45 -0
- package/tsconfig.test.json +21 -0
- package/.eslintignore +0 -4
- package/.eslintrc.json +0 -32
- package/dist/.eslintrc.json +0 -32
- package/dist/src/default/genericRepository.d.ts +0 -28
- package/dist/src/default/genericRepository.js +0 -284
- package/dist/src/default/genericRepository.js.map +0 -1
- package/dist/src/default/utils.d.ts +0 -9
- package/dist/src/default/utils.js.map +0 -1
- package/index.d.ts +0 -60
- package/src/default/genericRepository.ts +0 -461
- /package/dist/src/{default → core}/types.js +0 -0
|
@@ -0,0 +1,284 @@
|
|
|
1
|
+
# Raw Query - Usage Examples
|
|
2
|
+
|
|
3
|
+
The `rawQuery` method allows you to execute pure SQL queries directly on the database, offering maximum flexibility for complex cases that cannot be resolved with the standard generic repository methods.
|
|
4
|
+
|
|
5
|
+
## Import
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
import { rawQuery } from 'star-db-query-builder'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Method Signature
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
rawQuery<T = any>({
|
|
15
|
+
dbClient: IDatabaseClient,
|
|
16
|
+
sql: string,
|
|
17
|
+
params?: any[]
|
|
18
|
+
}): Promise<T>
|
|
19
|
+
```
|
|
20
|
+
|
|
21
|
+
## Usage Examples
|
|
22
|
+
|
|
23
|
+
### 1. Simple Query without Parameters
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
// Find all active users
|
|
27
|
+
const activeUsers = await rawQuery({
|
|
28
|
+
dbClient,
|
|
29
|
+
sql: 'SELECT * FROM users WHERE active = true',
|
|
30
|
+
})
|
|
31
|
+
```
|
|
32
|
+
|
|
33
|
+
### 2. Query with Parameters
|
|
34
|
+
|
|
35
|
+
```typescript
|
|
36
|
+
// Find specific user
|
|
37
|
+
const user = await rawQuery({
|
|
38
|
+
dbClient,
|
|
39
|
+
sql: 'SELECT * FROM users WHERE id = ? AND email = ?',
|
|
40
|
+
params: ['user-123', 'user@example.com'],
|
|
41
|
+
})
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### 3. Aggregation Queries
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
// User statistics
|
|
48
|
+
const stats = await rawQuery({
|
|
49
|
+
dbClient,
|
|
50
|
+
sql: `
|
|
51
|
+
SELECT
|
|
52
|
+
COUNT(*) as total_users,
|
|
53
|
+
AVG(age) as avg_age,
|
|
54
|
+
MIN(created_at) as first_user,
|
|
55
|
+
MAX(created_at) as last_user
|
|
56
|
+
FROM users
|
|
57
|
+
WHERE created_at >= ?
|
|
58
|
+
`,
|
|
59
|
+
params: [new Date('2023-01-01')],
|
|
60
|
+
})
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
### 4. Queries with Complex JOINs
|
|
64
|
+
|
|
65
|
+
```typescript
|
|
66
|
+
// Complex report with multiple JOINs
|
|
67
|
+
const report = await rawQuery({
|
|
68
|
+
dbClient,
|
|
69
|
+
sql: `
|
|
70
|
+
SELECT
|
|
71
|
+
u.name,
|
|
72
|
+
u.email,
|
|
73
|
+
COUNT(o.id) as total_orders,
|
|
74
|
+
SUM(o.total) as total_spent,
|
|
75
|
+
p.name as plan_name
|
|
76
|
+
FROM users u
|
|
77
|
+
LEFT JOIN orders o ON u.id = o.user_id
|
|
78
|
+
LEFT JOIN user_plans up ON u.id = up.user_id
|
|
79
|
+
LEFT JOIN plans p ON up.plan_id = p.id
|
|
80
|
+
WHERE u.created_at >= ?
|
|
81
|
+
GROUP BY u.id, u.name, u.email, p.name
|
|
82
|
+
HAVING COUNT(o.id) > ?
|
|
83
|
+
ORDER BY total_spent DESC
|
|
84
|
+
`,
|
|
85
|
+
params: [new Date('2023-01-01'), 5],
|
|
86
|
+
})
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### 5. Queries with Subqueries
|
|
90
|
+
|
|
91
|
+
```typescript
|
|
92
|
+
// Users with more orders than average
|
|
93
|
+
const topUsers = await rawQuery({
|
|
94
|
+
dbClient,
|
|
95
|
+
sql: `
|
|
96
|
+
SELECT
|
|
97
|
+
u.*,
|
|
98
|
+
COUNT(o.id) as order_count
|
|
99
|
+
FROM users u
|
|
100
|
+
INNER JOIN orders o ON u.id = o.user_id
|
|
101
|
+
GROUP BY u.id
|
|
102
|
+
HAVING COUNT(o.id) > (
|
|
103
|
+
SELECT AVG(order_count)
|
|
104
|
+
FROM (
|
|
105
|
+
SELECT COUNT(*) as order_count
|
|
106
|
+
FROM orders
|
|
107
|
+
GROUP BY user_id
|
|
108
|
+
) as avg_orders
|
|
109
|
+
)
|
|
110
|
+
`,
|
|
111
|
+
})
|
|
112
|
+
```
|
|
113
|
+
|
|
114
|
+
### 6. Queries with Window Functions
|
|
115
|
+
|
|
116
|
+
```typescript
|
|
117
|
+
// User ranking by spending
|
|
118
|
+
const userRanking = await rawQuery({
|
|
119
|
+
dbClient,
|
|
120
|
+
sql: `
|
|
121
|
+
SELECT
|
|
122
|
+
u.name,
|
|
123
|
+
u.email,
|
|
124
|
+
SUM(o.total) as total_spent,
|
|
125
|
+
ROW_NUMBER() OVER (ORDER BY SUM(o.total) DESC) as rank,
|
|
126
|
+
PERCENT_RANK() OVER (ORDER BY SUM(o.total) DESC) as percentile
|
|
127
|
+
FROM users u
|
|
128
|
+
INNER JOIN orders o ON u.id = o.user_id
|
|
129
|
+
WHERE o.created_at >= ?
|
|
130
|
+
GROUP BY u.id, u.name, u.email
|
|
131
|
+
ORDER BY total_spent DESC
|
|
132
|
+
`,
|
|
133
|
+
params: [new Date('2023-01-01')],
|
|
134
|
+
})
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
### 7. Queries with CTEs (Common Table Expressions)
|
|
138
|
+
|
|
139
|
+
```typescript
|
|
140
|
+
// Monthly growth analysis
|
|
141
|
+
const monthlyGrowth = await rawQuery({
|
|
142
|
+
dbClient,
|
|
143
|
+
sql: `
|
|
144
|
+
WITH monthly_stats AS (
|
|
145
|
+
SELECT
|
|
146
|
+
DATE_TRUNC('month', created_at) as month,
|
|
147
|
+
COUNT(*) as new_users,
|
|
148
|
+
SUM(total) as revenue
|
|
149
|
+
FROM users u
|
|
150
|
+
LEFT JOIN orders o ON u.id = o.user_id
|
|
151
|
+
WHERE u.created_at >= ?
|
|
152
|
+
GROUP BY DATE_TRUNC('month', created_at)
|
|
153
|
+
),
|
|
154
|
+
growth_calc AS (
|
|
155
|
+
SELECT
|
|
156
|
+
month,
|
|
157
|
+
new_users,
|
|
158
|
+
revenue,
|
|
159
|
+
LAG(new_users) OVER (ORDER BY month) as prev_users,
|
|
160
|
+
LAG(revenue) OVER (ORDER BY month) as prev_revenue
|
|
161
|
+
FROM monthly_stats
|
|
162
|
+
)
|
|
163
|
+
SELECT
|
|
164
|
+
month,
|
|
165
|
+
new_users,
|
|
166
|
+
revenue,
|
|
167
|
+
CASE
|
|
168
|
+
WHEN prev_users > 0
|
|
169
|
+
THEN ROUND(((new_users - prev_users)::float / prev_users) * 100, 2)
|
|
170
|
+
ELSE 0
|
|
171
|
+
END as user_growth_percent,
|
|
172
|
+
CASE
|
|
173
|
+
WHEN prev_revenue > 0
|
|
174
|
+
THEN ROUND(((revenue - prev_revenue)::float / prev_revenue) * 100, 2)
|
|
175
|
+
ELSE 0
|
|
176
|
+
END as revenue_growth_percent
|
|
177
|
+
FROM growth_calc
|
|
178
|
+
ORDER BY month
|
|
179
|
+
`,
|
|
180
|
+
params: [new Date('2023-01-01')],
|
|
181
|
+
})
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### 8. Batch Update Queries
|
|
185
|
+
|
|
186
|
+
```typescript
|
|
187
|
+
// Update status of multiple records
|
|
188
|
+
const updateResult = await rawQuery({
|
|
189
|
+
dbClient,
|
|
190
|
+
sql: `
|
|
191
|
+
UPDATE users
|
|
192
|
+
SET
|
|
193
|
+
last_login = ?,
|
|
194
|
+
login_count = login_count + 1,
|
|
195
|
+
updated_at = ?
|
|
196
|
+
WHERE id IN (${userIds.map(() => '?').join(',')})
|
|
197
|
+
`,
|
|
198
|
+
params: [new Date(), new Date(), ...userIds],
|
|
199
|
+
})
|
|
200
|
+
```
|
|
201
|
+
|
|
202
|
+
### 9. Queries with TypeScript Typing
|
|
203
|
+
|
|
204
|
+
```typescript
|
|
205
|
+
// Define interface for the result
|
|
206
|
+
interface UserStats {
|
|
207
|
+
total_users: number
|
|
208
|
+
active_users: number
|
|
209
|
+
avg_age: number
|
|
210
|
+
last_created: Date
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
// Typed query
|
|
214
|
+
const stats: UserStats = await rawQuery<UserStats>({
|
|
215
|
+
dbClient,
|
|
216
|
+
sql: `
|
|
217
|
+
SELECT
|
|
218
|
+
COUNT(*) as total_users,
|
|
219
|
+
COUNT(CASE WHEN active = true THEN 1 END) as active_users,
|
|
220
|
+
AVG(age) as avg_age,
|
|
221
|
+
MAX(created_at) as last_created
|
|
222
|
+
FROM users
|
|
223
|
+
`,
|
|
224
|
+
})
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
### 10. Error Handling
|
|
228
|
+
|
|
229
|
+
```typescript
|
|
230
|
+
try {
|
|
231
|
+
const result = await rawQuery({
|
|
232
|
+
dbClient,
|
|
233
|
+
sql: 'SELECT * FROM non_existent_table',
|
|
234
|
+
})
|
|
235
|
+
} catch (error) {
|
|
236
|
+
console.error('Query error:', error.message)
|
|
237
|
+
// The error will be: "Raw query execution failed: [database message]"
|
|
238
|
+
}
|
|
239
|
+
```
|
|
240
|
+
|
|
241
|
+
## Important Considerations
|
|
242
|
+
|
|
243
|
+
### Security
|
|
244
|
+
|
|
245
|
+
- **ALWAYS** use prepared parameters to avoid SQL injection
|
|
246
|
+
- Validate and sanitize data before using in queries
|
|
247
|
+
- Avoid concatenating strings directly in SQL
|
|
248
|
+
|
|
249
|
+
### Performance
|
|
250
|
+
|
|
251
|
+
- Use `rawQuery` only when necessary
|
|
252
|
+
- Consider using appropriate indexes for complex queries
|
|
253
|
+
- Monitor the performance of raw queries
|
|
254
|
+
|
|
255
|
+
### Compatibility
|
|
256
|
+
|
|
257
|
+
- The method works with PostgreSQL and MySQL
|
|
258
|
+
- Database-specific syntax (like `DATE_TRUNC` in PostgreSQL) may not work in other DBMS
|
|
259
|
+
- Test queries in different environments
|
|
260
|
+
|
|
261
|
+
### Limitations
|
|
262
|
+
|
|
263
|
+
- No automatic type validation
|
|
264
|
+
- No automatic query caching
|
|
265
|
+
- No automatic retry on failure
|
|
266
|
+
- No automatic query logging
|
|
267
|
+
|
|
268
|
+
## Recommended Use Cases
|
|
269
|
+
|
|
270
|
+
✅ **Use `rawQuery` when:**
|
|
271
|
+
|
|
272
|
+
- You need very complex queries with multiple JOINs
|
|
273
|
+
- You want to use database-specific functions (window functions, CTEs, etc.)
|
|
274
|
+
- You need maximum performance for critical queries
|
|
275
|
+
- You want to do complex aggregation queries
|
|
276
|
+
- You need queries that don't fit the CRUD pattern
|
|
277
|
+
|
|
278
|
+
❌ **Avoid `rawQuery` when:**
|
|
279
|
+
|
|
280
|
+
- You can use the standard repository methods
|
|
281
|
+
- The query is simple (basic SELECT, INSERT, UPDATE, DELETE)
|
|
282
|
+
- You need automatic type validation
|
|
283
|
+
- You want to take advantage of automatic caching
|
|
284
|
+
- The query can be reused across different DBMS
|