@starbemtech/star-db-query-builder 1.1.0 → 1.2.1

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/.github/workflows/publish.yml +118 -0
  2. package/ARCHITECTURE.md +313 -0
  3. package/CHANGELOG.md +65 -0
  4. package/README.md +1275 -210
  5. package/coverage/base.css +224 -0
  6. package/coverage/block-navigation.js +87 -0
  7. package/coverage/favicon.png +0 -0
  8. package/coverage/index.html +131 -0
  9. package/coverage/lcov-report/base.css +224 -0
  10. package/coverage/lcov-report/block-navigation.js +87 -0
  11. package/coverage/lcov-report/favicon.png +0 -0
  12. package/coverage/lcov-report/index.html +131 -0
  13. package/coverage/lcov-report/mysqlClient.ts.html +685 -0
  14. package/coverage/lcov-report/pgClient.ts.html +823 -0
  15. package/coverage/lcov-report/prettify.css +1 -0
  16. package/coverage/lcov-report/prettify.js +2 -0
  17. package/coverage/lcov-report/sort-arrow-sprite.png +0 -0
  18. package/coverage/lcov-report/sorter.js +210 -0
  19. package/coverage/lcov.info +533 -0
  20. package/coverage/mysqlClient.ts.html +685 -0
  21. package/coverage/pgClient.ts.html +823 -0
  22. package/coverage/prettify.css +1 -0
  23. package/coverage/prettify.js +2 -0
  24. package/coverage/sort-arrow-sprite.png +0 -0
  25. package/coverage/sorter.js +210 -0
  26. package/dist/index.d.ts +5 -4
  27. package/dist/index.js +1 -1
  28. package/dist/index.js.map +1 -1
  29. package/dist/src/core/repository.d.ts +374 -0
  30. package/dist/src/core/repository.js +677 -0
  31. package/dist/src/core/repository.js.map +1 -0
  32. package/dist/src/{default → core}/types.d.ts +9 -1
  33. package/dist/src/{default → core}/types.js.map +1 -1
  34. package/dist/src/core/utils.d.ts +133 -0
  35. package/dist/src/{default → core}/utils.js +167 -0
  36. package/dist/src/core/utils.js.map +1 -0
  37. package/dist/src/db/IDatabaseClient.d.ts +10 -1
  38. package/dist/src/db/initDb.d.ts +120 -1
  39. package/dist/src/db/initDb.js +119 -0
  40. package/dist/src/db/initDb.js.map +1 -1
  41. package/dist/src/db/mysqlClient.d.ts +23 -1
  42. package/dist/src/db/mysqlClient.js +115 -0
  43. package/dist/src/db/mysqlClient.js.map +1 -1
  44. package/dist/src/db/pgClient.d.ts +22 -1
  45. package/dist/src/db/pgClient.js +127 -0
  46. package/dist/src/db/pgClient.js.map +1 -1
  47. package/dist/src/monitor/monitor.d.ts +6 -1
  48. package/dist/src/monitor/monitor.js +5 -0
  49. package/dist/src/monitor/monitor.js.map +1 -1
  50. package/dist/src/setupTests.d.ts +26 -0
  51. package/dist/src/setupTests.js +43 -0
  52. package/dist/src/setupTests.js.map +1 -0
  53. package/docs/INDEX.md +145 -0
  54. package/docs/methods/findFirst.md +394 -0
  55. package/docs/methods/findMany.md +587 -0
  56. package/docs/methods/insert.md +536 -0
  57. package/docs/methods/insertMany.md +627 -0
  58. package/docs/methods/joins.md +781 -0
  59. package/docs/methods/rawQuery.md +284 -0
  60. package/docs/methods/transactions.md +737 -0
  61. package/eslint.config.mjs +77 -0
  62. package/index.ts +5 -4
  63. package/jest.config.ts +23 -28
  64. package/package.json +52 -29
  65. package/scripts/release.sh +123 -0
  66. package/src/core/repository.ts +865 -0
  67. package/src/{default → core}/types.ts +11 -2
  68. package/src/{default → core}/utils.ts +168 -0
  69. package/src/db/IDatabaseClient.ts +11 -1
  70. package/src/db/__tests__/mysqlClient.test.ts +262 -0
  71. package/src/db/__tests__/pgClient.test.ts +260 -0
  72. package/src/db/initDb.ts +120 -1
  73. package/src/db/mysqlClient.ts +119 -3
  74. package/src/db/pgClient.ts +131 -3
  75. package/src/monitor/monitor.ts +5 -0
  76. package/src/setupTests.ts +45 -0
  77. package/tsconfig.test.json +21 -0
  78. package/.eslintignore +0 -4
  79. package/.eslintrc.json +0 -32
  80. package/dist/.eslintrc.json +0 -32
  81. package/dist/src/default/genericRepository.d.ts +0 -28
  82. package/dist/src/default/genericRepository.js +0 -284
  83. package/dist/src/default/genericRepository.js.map +0 -1
  84. package/dist/src/default/utils.d.ts +0 -9
  85. package/dist/src/default/utils.js.map +0 -1
  86. package/index.d.ts +0 -60
  87. package/src/default/genericRepository.ts +0 -461
  88. /package/dist/src/{default → core}/types.js +0 -0
@@ -0,0 +1,536 @@
1
+ # insert
2
+
3
+ Inserts a single record into a database table and returns the inserted record.
4
+
5
+ ## Signature
6
+
7
+ ```typescript
8
+ insert<P, R>({
9
+ tableName: string,
10
+ dbClient: IDatabaseClient,
11
+ data: P,
12
+ returning?: string[]
13
+ }): Promise<R>
14
+ ```
15
+
16
+ ## Parameters
17
+
18
+ | Parameter | Type | Required | Description |
19
+ | ----------- | ----------------- | -------- | ---------------------------------------------- |
20
+ | `tableName` | `string` | ✅ | Name of the database table |
21
+ | `dbClient` | `IDatabaseClient` | ✅ | Database client instance |
22
+ | `data` | `P` | ✅ | Object containing the data to insert |
23
+ | `returning` | `string[]` | ❌ | Array of field names to return after insertion |
24
+
25
+ ## Return Value
26
+
27
+ - **Type**: `Promise<R>`
28
+ - **Description**: Returns the inserted record with all fields (including auto-generated ones like `id`, `created_at`, `updated_at`)
29
+
30
+ ## Auto-Generated Fields
31
+
32
+ The `insert` method automatically adds the following fields to every record:
33
+
34
+ - **`id`**: A UUID v4 string
35
+ - **`updated_at`**: Current timestamp
36
+
37
+ ## Examples
38
+
39
+ ### Basic Usage
40
+
41
+ ```typescript
42
+ import { insert } from '@starbemtech/star-db-query-builder'
43
+
44
+ // Insert a new user
45
+ const user = await insert({
46
+ tableName: 'users',
47
+ dbClient,
48
+ data: {
49
+ name: 'John Doe',
50
+ email: 'john@example.com',
51
+ age: 30,
52
+ },
53
+ })
54
+
55
+ console.log(user)
56
+ // {
57
+ // id: '550e8400-e29b-41d4-a716-446655440000',
58
+ // name: 'John Doe',
59
+ // email: 'john@example.com',
60
+ // age: 30,
61
+ // created_at: '2023-12-01T10:00:00.000Z',
62
+ // updated_at: '2023-12-01T10:00:00.000Z'
63
+ // }
64
+ ```
65
+
66
+ ### With Specific Returning Fields
67
+
68
+ ```typescript
69
+ // Return only specific fields after insertion
70
+ const user = await insert({
71
+ tableName: 'users',
72
+ dbClient,
73
+ data: {
74
+ name: 'Jane Doe',
75
+ email: 'jane@example.com',
76
+ age: 25,
77
+ },
78
+ returning: ['id', 'name', 'email', 'created_at'],
79
+ })
80
+
81
+ console.log(user)
82
+ // {
83
+ // id: '550e8400-e29b-41d4-a716-446655440001',
84
+ // name: 'Jane Doe',
85
+ // email: 'jane@example.com',
86
+ // created_at: '2023-12-01T10:00:00.000Z'
87
+ // }
88
+ ```
89
+
90
+ ### TypeScript Usage
91
+
92
+ ```typescript
93
+ interface UserData {
94
+ name: string
95
+ email: string
96
+ age: number
97
+ bio?: string
98
+ }
99
+
100
+ interface User {
101
+ id: string
102
+ name: string
103
+ email: string
104
+ age: number
105
+ bio?: string
106
+ created_at: Date
107
+ updated_at: Date
108
+ }
109
+
110
+ // Typed usage
111
+ const userData: UserData = {
112
+ name: 'John Doe',
113
+ email: 'john@example.com',
114
+ age: 30,
115
+ bio: 'Software developer',
116
+ }
117
+
118
+ const user: User = await insert<UserData, User>({
119
+ tableName: 'users',
120
+ dbClient,
121
+ data: userData,
122
+ })
123
+
124
+ console.log(`Created user with ID: ${user.id}`)
125
+ ```
126
+
127
+ ### Inserting with Optional Fields
128
+
129
+ ```typescript
130
+ // Insert with some optional fields
131
+ const user = await insert({
132
+ tableName: 'users',
133
+ dbClient,
134
+ data: {
135
+ name: 'John Doe',
136
+ email: 'john@example.com',
137
+ age: 30,
138
+ bio: 'Software developer',
139
+ phone: '+1234567890',
140
+ website: 'https://johndoe.com',
141
+ },
142
+ })
143
+ ```
144
+
145
+ ### Inserting with Date Fields
146
+
147
+ ```typescript
148
+ // Insert with custom date
149
+ const user = await insert({
150
+ tableName: 'users',
151
+ dbClient,
152
+ data: {
153
+ name: 'John Doe',
154
+ email: 'john@example.com',
155
+ birth_date: new Date('1990-01-01'),
156
+ last_login: new Date(),
157
+ },
158
+ })
159
+ ```
160
+
161
+ ### Inserting with Boolean Fields
162
+
163
+ ```typescript
164
+ // Insert with boolean values
165
+ const user = await insert({
166
+ tableName: 'users',
167
+ dbClient,
168
+ data: {
169
+ name: 'John Doe',
170
+ email: 'john@example.com',
171
+ is_active: true,
172
+ is_verified: false,
173
+ newsletter_subscribed: true,
174
+ },
175
+ })
176
+ ```
177
+
178
+ ### Inserting with JSON Fields
179
+
180
+ ```typescript
181
+ // Insert with JSON data
182
+ const user = await insert({
183
+ tableName: 'users',
184
+ dbClient,
185
+ data: {
186
+ name: 'John Doe',
187
+ email: 'john@example.com',
188
+ preferences: {
189
+ theme: 'dark',
190
+ language: 'en',
191
+ notifications: {
192
+ email: true,
193
+ push: false,
194
+ },
195
+ },
196
+ metadata: {
197
+ source: 'web',
198
+ campaign: 'summer2023',
199
+ },
200
+ },
201
+ })
202
+ ```
203
+
204
+ ### Error Handling
205
+
206
+ ```typescript
207
+ try {
208
+ const user = await insert({
209
+ tableName: 'users',
210
+ dbClient,
211
+ data: {
212
+ name: 'John Doe',
213
+ email: 'john@example.com',
214
+ },
215
+ })
216
+
217
+ console.log('User created successfully:', user.id)
218
+ } catch (error) {
219
+ if (error.message.includes('duplicate key')) {
220
+ console.error('User with this email already exists')
221
+ } else {
222
+ console.error('Failed to create user:', error.message)
223
+ }
224
+ }
225
+ ```
226
+
227
+ ## Generated SQL Examples
228
+
229
+ ### PostgreSQL
230
+
231
+ ```sql
232
+ INSERT INTO users (id, name, email, age, updated_at)
233
+ VALUES ($1, $2, $3, $4, $5)
234
+ RETURNING *
235
+ ```
236
+
237
+ ### MySQL
238
+
239
+ ```sql
240
+ INSERT INTO users (id, name, email, age, updated_at)
241
+ VALUES (?, ?, ?, ?, ?)
242
+
243
+ SELECT * FROM users WHERE id = ?
244
+ ```
245
+
246
+ ### With Specific Returning Fields (PostgreSQL)
247
+
248
+ ```sql
249
+ INSERT INTO users (id, name, email, age, updated_at)
250
+ VALUES ($1, $2, $3, $4, $5)
251
+ RETURNING id, name, email, created_at
252
+ ```
253
+
254
+ ## Best Practices
255
+
256
+ ### 1. Use TypeScript for Type Safety
257
+
258
+ ```typescript
259
+ interface CreateUserRequest {
260
+ name: string
261
+ email: string
262
+ age: number
263
+ bio?: string
264
+ }
265
+
266
+ interface User {
267
+ id: string
268
+ name: string
269
+ email: string
270
+ age: number
271
+ bio?: string
272
+ created_at: Date
273
+ updated_at: Date
274
+ }
275
+
276
+ const createUser = async (userData: CreateUserRequest): Promise<User> => {
277
+ return insert<CreateUserRequest, User>({
278
+ tableName: 'users',
279
+ dbClient,
280
+ data: userData,
281
+ })
282
+ }
283
+ ```
284
+
285
+ ### 2. Validate Data Before Insertion
286
+
287
+ ```typescript
288
+ const createUser = async (userData: any) => {
289
+ // Validate required fields
290
+ if (!userData.name || !userData.email) {
291
+ throw new Error('Name and email are required')
292
+ }
293
+
294
+ // Validate email format
295
+ const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/
296
+ if (!emailRegex.test(userData.email)) {
297
+ throw new Error('Invalid email format')
298
+ }
299
+
300
+ // Validate age
301
+ if (userData.age && (userData.age < 0 || userData.age > 150)) {
302
+ throw new Error('Age must be between 0 and 150')
303
+ }
304
+
305
+ return insert({
306
+ tableName: 'users',
307
+ dbClient,
308
+ data: userData,
309
+ })
310
+ }
311
+ ```
312
+
313
+ ### 3. Handle Duplicate Key Errors
314
+
315
+ ```typescript
316
+ const createUser = async (userData: any) => {
317
+ try {
318
+ return await insert({
319
+ tableName: 'users',
320
+ dbClient,
321
+ data: userData,
322
+ })
323
+ } catch (error) {
324
+ if (
325
+ error.message.includes('duplicate key') ||
326
+ error.message.includes('UNIQUE constraint')
327
+ ) {
328
+ throw new Error('User with this email already exists')
329
+ }
330
+ throw error
331
+ }
332
+ }
333
+ ```
334
+
335
+ ### 4. Use Specific Returning Fields
336
+
337
+ ```typescript
338
+ // Good: Return only needed fields
339
+ const user = await insert({
340
+ tableName: 'users',
341
+ dbClient,
342
+ data: userData,
343
+ returning: ['id', 'name', 'email', 'created_at'],
344
+ })
345
+
346
+ // Avoid: Returning all fields when not needed
347
+ const user = await insert({
348
+ tableName: 'users',
349
+ dbClient,
350
+ data: userData,
351
+ })
352
+ ```
353
+
354
+ ### 5. Sanitize Input Data
355
+
356
+ ```typescript
357
+ const sanitizeUserData = (data: any) => {
358
+ return {
359
+ name: data.name?.trim(),
360
+ email: data.email?.toLowerCase().trim(),
361
+ age: data.age ? parseInt(data.age) : undefined,
362
+ bio: data.bio?.trim(),
363
+ }
364
+ }
365
+
366
+ const createUser = async (rawData: any) => {
367
+ const sanitizedData = sanitizeUserData(rawData)
368
+
369
+ return insert({
370
+ tableName: 'users',
371
+ dbClient,
372
+ data: sanitizedData,
373
+ })
374
+ }
375
+ ```
376
+
377
+ ## Common Use Cases
378
+
379
+ ### 1. User Registration
380
+
381
+ ```typescript
382
+ const registerUser = async (registrationData: {
383
+ name: string
384
+ email: string
385
+ password: string
386
+ age?: number
387
+ }) => {
388
+ // Hash password before storing
389
+ const hashedPassword = await hashPassword(registrationData.password)
390
+
391
+ const user = await insert({
392
+ tableName: 'users',
393
+ dbClient,
394
+ data: {
395
+ name: registrationData.name,
396
+ email: registrationData.email,
397
+ password: hashedPassword,
398
+ age: registrationData.age,
399
+ status: 'pending',
400
+ verification_token: generateVerificationToken(),
401
+ },
402
+ returning: ['id', 'name', 'email', 'status', 'created_at'],
403
+ })
404
+
405
+ // Send verification email
406
+ await sendVerificationEmail(user.email, user.verification_token)
407
+
408
+ return user
409
+ }
410
+ ```
411
+
412
+ ### 2. Creating Related Records
413
+
414
+ ```typescript
415
+ const createUserWithProfile = async (userData: any, profileData: any) => {
416
+ // Create user first
417
+ const user = await insert({
418
+ tableName: 'users',
419
+ dbClient,
420
+ data: userData,
421
+ returning: ['id'],
422
+ })
423
+
424
+ // Create user profile
425
+ const profile = await insert({
426
+ tableName: 'user_profiles',
427
+ dbClient,
428
+ data: {
429
+ ...profileData,
430
+ user_id: user.id,
431
+ },
432
+ })
433
+
434
+ return { user, profile }
435
+ }
436
+ ```
437
+
438
+ ### 3. Audit Trail
439
+
440
+ ```typescript
441
+ const createAuditLog = async (action: string, userId: string, details: any) => {
442
+ return insert({
443
+ tableName: 'audit_logs',
444
+ dbClient,
445
+ data: {
446
+ action,
447
+ user_id: userId,
448
+ details: JSON.stringify(details),
449
+ ip_address: details.ipAddress,
450
+ user_agent: details.userAgent,
451
+ timestamp: new Date(),
452
+ },
453
+ })
454
+ }
455
+ ```
456
+
457
+ ### 4. Configuration Management
458
+
459
+ ```typescript
460
+ const createConfiguration = async (
461
+ key: string,
462
+ value: any,
463
+ description?: string
464
+ ) => {
465
+ return insert({
466
+ tableName: 'configurations',
467
+ dbClient,
468
+ data: {
469
+ key,
470
+ value: JSON.stringify(value),
471
+ description,
472
+ is_active: true,
473
+ },
474
+ })
475
+ }
476
+ ```
477
+
478
+ ## Database-Specific Considerations
479
+
480
+ ### PostgreSQL
481
+
482
+ - Uses `RETURNING` clause for efficient data retrieval
483
+ - Supports complex data types (JSON, arrays, etc.)
484
+ - Better performance with `RETURNING` clause
485
+
486
+ ### MySQL
487
+
488
+ - Requires separate `SELECT` query after `INSERT`
489
+ - Good performance for simple inserts
490
+ - Limited support for complex data types
491
+
492
+ ## Performance Considerations
493
+
494
+ ### 1. Index Impact
495
+
496
+ ```sql
497
+ -- Ensure proper indexes exist for unique constraints
498
+ CREATE UNIQUE INDEX idx_users_email ON users(email);
499
+ CREATE INDEX idx_users_created_at ON users(created_at);
500
+ ```
501
+
502
+ ### 2. Batch Operations
503
+
504
+ For multiple inserts, consider using `insertMany` instead:
505
+
506
+ ```typescript
507
+ // Good: Use insertMany for multiple records
508
+ const users = await insertMany({
509
+ tableName: 'users',
510
+ dbClient,
511
+ data: [
512
+ { name: 'John', email: 'john@example.com' },
513
+ { name: 'Jane', email: 'jane@example.com' },
514
+ ],
515
+ })
516
+
517
+ // Avoid: Multiple individual inserts
518
+ for (const userData of usersData) {
519
+ await insert({ tableName: 'users', dbClient, data: userData })
520
+ }
521
+ ```
522
+
523
+ ### 3. Connection Pooling
524
+
525
+ Ensure your database client is properly configured with connection pooling for better performance in high-traffic applications.
526
+
527
+ ## Error Messages
528
+
529
+ Common error messages you might encounter:
530
+
531
+ - `Table name is required` - The `tableName` parameter is missing
532
+ - `DB client is required` - The `dbClient` parameter is missing
533
+ - `Data object is required` - The `data` parameter is missing
534
+ - `duplicate key value violates unique constraint` - Attempting to insert duplicate unique values
535
+ - `column "field_name" of relation "table_name" does not exist` - Invalid field name
536
+ - `null value in column "field_name" violates not-null constraint` - Required field is missing