@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.
- package/.github/workflows/publish.yml +118 -0
- package/ARCHITECTURE.md +313 -0
- package/CHANGELOG.md +65 -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 +9 -1
- 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 +52 -29
- package/scripts/release.sh +123 -0
- package/src/core/repository.ts +865 -0
- package/src/{default → core}/types.ts +11 -2
- 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
package/docs/INDEX.md
ADDED
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
# Star DB Query Builder - Documentation Index
|
|
2
|
+
|
|
3
|
+
Welcome to the comprehensive documentation for the Star DB Query Builder library. This index provides quick access to all available documentation.
|
|
4
|
+
|
|
5
|
+
## 📚 Main Documentation
|
|
6
|
+
|
|
7
|
+
- **[README.md](./README.md)** - Complete library overview, installation, and quick start guide
|
|
8
|
+
- **[Raw Query Examples](./raw-query-examples.md)** - Detailed examples for raw SQL queries
|
|
9
|
+
|
|
10
|
+
## 🔧 Method Documentation
|
|
11
|
+
|
|
12
|
+
### Query Methods
|
|
13
|
+
|
|
14
|
+
- **[findFirst](./methods/findFirst.md)** - Find a single record with conditions
|
|
15
|
+
- **[findMany](./methods/findMany.md)** - Find multiple records with pagination and filtering
|
|
16
|
+
|
|
17
|
+
### Insert Methods
|
|
18
|
+
|
|
19
|
+
- **[insert](./methods/insert.md)** - Insert a single record
|
|
20
|
+
- **[insertMany](./methods/insertMany.md)** - Insert multiple records in batch
|
|
21
|
+
|
|
22
|
+
### Update Methods
|
|
23
|
+
|
|
24
|
+
- **[update](./methods/update.md)** - Update a single record by ID
|
|
25
|
+
- **[updateMany](./methods/updateMany.md)** - Update multiple records with conditions
|
|
26
|
+
|
|
27
|
+
### Delete Methods
|
|
28
|
+
|
|
29
|
+
- **[deleteOne](./methods/deleteOne.md)** - Delete a single record by ID
|
|
30
|
+
- **[deleteMany](./methods/deleteMany.md)** - Delete multiple records by IDs
|
|
31
|
+
|
|
32
|
+
### Advanced Methods
|
|
33
|
+
|
|
34
|
+
- **[joins](./methods/joins.md)** - Execute queries with JOIN operations
|
|
35
|
+
- **[rawQuery](./methods/rawQuery.md)** - Execute raw SQL queries
|
|
36
|
+
|
|
37
|
+
### Database Initialization
|
|
38
|
+
|
|
39
|
+
- **[initDb](./methods/initDb.md)** - Initialize database connections
|
|
40
|
+
- **[getDbClient](./methods/getDbClient.md)** - Retrieve database client instances
|
|
41
|
+
|
|
42
|
+
## 🏗️ Architecture Documentation
|
|
43
|
+
|
|
44
|
+
### Core Components
|
|
45
|
+
|
|
46
|
+
- **[Types and Interfaces](./architecture/types.md)** - TypeScript type definitions
|
|
47
|
+
- **[Database Clients](./architecture/database-clients.md)** - PostgreSQL and MySQL client implementations
|
|
48
|
+
- **[Query Builder](./architecture/query-builder.md)** - Internal query building logic
|
|
49
|
+
|
|
50
|
+
### Utilities
|
|
51
|
+
|
|
52
|
+
- **[Utils](./architecture/utils.md)** - Helper functions for query construction
|
|
53
|
+
- **[Error Handling](./architecture/error-handling.md)** - Error handling patterns and best practices
|
|
54
|
+
|
|
55
|
+
## 📖 Guides and Tutorials
|
|
56
|
+
|
|
57
|
+
### Getting Started
|
|
58
|
+
|
|
59
|
+
- **[Installation Guide](./guides/installation.md)** - Step-by-step installation instructions
|
|
60
|
+
- **[First Steps](./guides/first-steps.md)** - Your first database operations
|
|
61
|
+
- **[TypeScript Setup](./guides/typescript-setup.md)** - TypeScript configuration and usage
|
|
62
|
+
|
|
63
|
+
### Advanced Topics
|
|
64
|
+
|
|
65
|
+
- **[Performance Optimization](./guides/performance.md)** - Tips for optimizing database performance
|
|
66
|
+
- **[Security Best Practices](./guides/security.md)** - Security considerations and best practices
|
|
67
|
+
- **[Testing](./guides/testing.md)** - How to test your database operations
|
|
68
|
+
- **[Migration Guide](./guides/migration.md)** - Migrating from other ORMs
|
|
69
|
+
|
|
70
|
+
### Database-Specific Guides
|
|
71
|
+
|
|
72
|
+
- **[PostgreSQL Guide](./guides/postgresql.md)** - PostgreSQL-specific features and optimizations
|
|
73
|
+
- **[MySQL Guide](./guides/mysql.md)** - MySQL-specific features and optimizations
|
|
74
|
+
|
|
75
|
+
## 🎯 Use Cases and Examples
|
|
76
|
+
|
|
77
|
+
### Common Patterns
|
|
78
|
+
|
|
79
|
+
- **[User Management](./examples/user-management.md)** - Complete user CRUD operations
|
|
80
|
+
- **[E-commerce](./examples/ecommerce.md)** - Product catalog and order management
|
|
81
|
+
- **[Content Management](./examples/cms.md)** - Blog posts and content management
|
|
82
|
+
- **[Analytics](./examples/analytics.md)** - Data aggregation and reporting
|
|
83
|
+
|
|
84
|
+
### Real-World Scenarios
|
|
85
|
+
|
|
86
|
+
- **[API Development](./examples/api-development.md)** - Building REST APIs with the library
|
|
87
|
+
- **[Data Import/Export](./examples/data-import-export.md)** - Bulk data operations
|
|
88
|
+
- **[Audit Logging](./examples/audit-logging.md)** - Implementing audit trails
|
|
89
|
+
- **[Multi-tenant Applications](./examples/multi-tenant.md)** - Multi-tenant database patterns
|
|
90
|
+
|
|
91
|
+
## 🔍 Reference
|
|
92
|
+
|
|
93
|
+
### API Reference
|
|
94
|
+
|
|
95
|
+
- **[Method Signatures](./reference/method-signatures.md)** - Complete method signatures and parameters
|
|
96
|
+
- **[Type Definitions](./reference/type-definitions.md)** - All TypeScript interfaces and types
|
|
97
|
+
- **[Error Codes](./reference/error-codes.md)** - Complete list of error codes and messages
|
|
98
|
+
|
|
99
|
+
### Database Compatibility
|
|
100
|
+
|
|
101
|
+
- **[PostgreSQL Features](./reference/postgresql-features.md)** - PostgreSQL-specific features
|
|
102
|
+
- **[MySQL Features](./reference/mysql-features.md)** - MySQL-specific features
|
|
103
|
+
- **[SQL Generation](./reference/sql-generation.md)** - Examples of generated SQL queries
|
|
104
|
+
|
|
105
|
+
## 🚀 Quick Navigation
|
|
106
|
+
|
|
107
|
+
### By Task
|
|
108
|
+
|
|
109
|
+
- **Need to find data?** → [findFirst](./methods/findFirst.md) | [findMany](./methods/findMany.md)
|
|
110
|
+
- **Need to insert data?** → [insert](./methods/insert.md) | [insertMany](./methods/insertMany.md)
|
|
111
|
+
- **Need to update data?** → [update](./methods/update.md) | [updateMany](./methods/updateMany.md)
|
|
112
|
+
- **Need to delete data?** → [deleteOne](./methods/deleteOne.md) | [deleteMany](./methods/deleteMany.md)
|
|
113
|
+
- **Need complex queries?** → [joins](./methods/joins.md) | [rawQuery](./methods/rawQuery.md)
|
|
114
|
+
|
|
115
|
+
### By Experience Level
|
|
116
|
+
|
|
117
|
+
- **New to the library?** → [README.md](./README.md) → [First Steps](./guides/first-steps.md)
|
|
118
|
+
- **Familiar with basics?** → [Method Documentation](./methods/) → [Examples](./examples/)
|
|
119
|
+
- **Advanced user?** → [Architecture](./architecture/) → [Performance Guide](./guides/performance.md)
|
|
120
|
+
|
|
121
|
+
### By Database
|
|
122
|
+
|
|
123
|
+
- **Using PostgreSQL?** → [PostgreSQL Guide](./guides/postgresql.md) → [PostgreSQL Features](./reference/postgresql-features.md)
|
|
124
|
+
- **Using MySQL?** → [MySQL Guide](./guides/mysql.md) → [MySQL Features](./reference/mysql-features.md)
|
|
125
|
+
|
|
126
|
+
## 📝 Contributing to Documentation
|
|
127
|
+
|
|
128
|
+
If you find any issues with the documentation or want to contribute improvements:
|
|
129
|
+
|
|
130
|
+
1. Check the [Contributing Guidelines](../CONTRIBUTING.md)
|
|
131
|
+
2. Follow the [Documentation Style Guide](./style-guide.md)
|
|
132
|
+
3. Submit a pull request with your changes
|
|
133
|
+
|
|
134
|
+
## 🆘 Getting Help
|
|
135
|
+
|
|
136
|
+
- **Issues**: Check the [GitHub Issues](https://github.com/starbemtech/star-db-query-builder/issues)
|
|
137
|
+
- **Discussions**: Join the [GitHub Discussions](https://github.com/starbemtech/star-db-query-builder/discussions)
|
|
138
|
+
- **Examples**: Browse the [Examples](./examples/) directory
|
|
139
|
+
- **API Reference**: Check the [Reference](./reference/) section
|
|
140
|
+
|
|
141
|
+
---
|
|
142
|
+
|
|
143
|
+
**Last Updated**: September 2025
|
|
144
|
+
**Version**: 1.2.0
|
|
145
|
+
**Maintainer**: Starbem Tech Team
|
|
@@ -0,0 +1,394 @@
|
|
|
1
|
+
# findFirst
|
|
2
|
+
|
|
3
|
+
Finds the first record that matches the specified conditions from a database table.
|
|
4
|
+
|
|
5
|
+
## Signature
|
|
6
|
+
|
|
7
|
+
```typescript
|
|
8
|
+
findFirst<T>({
|
|
9
|
+
tableName: string,
|
|
10
|
+
dbClient: IDatabaseClient,
|
|
11
|
+
select?: string[],
|
|
12
|
+
where?: Conditions<T>,
|
|
13
|
+
groupBy?: string[],
|
|
14
|
+
orderBy?: OrderBy
|
|
15
|
+
}): Promise<T | null>
|
|
16
|
+
```
|
|
17
|
+
|
|
18
|
+
## Parameters
|
|
19
|
+
|
|
20
|
+
| Parameter | Type | Required | Description |
|
|
21
|
+
| ----------- | ----------------- | -------- | ---------------------------------------------------- |
|
|
22
|
+
| `tableName` | `string` | ✅ | Name of the database table |
|
|
23
|
+
| `dbClient` | `IDatabaseClient` | ✅ | Database client instance |
|
|
24
|
+
| `select` | `string[]` | ❌ | Array of field names to select (default: all fields) |
|
|
25
|
+
| `where` | `Conditions<T>` | ❌ | Conditions to filter records |
|
|
26
|
+
| `groupBy` | `string[]` | ❌ | Fields to group by |
|
|
27
|
+
| `orderBy` | `OrderBy` | ❌ | Sort order specification |
|
|
28
|
+
|
|
29
|
+
## Return Value
|
|
30
|
+
|
|
31
|
+
- **Type**: `Promise<T | null>`
|
|
32
|
+
- **Description**: Returns the first matching record or `null` if no record is found
|
|
33
|
+
|
|
34
|
+
## Examples
|
|
35
|
+
|
|
36
|
+
### Basic Usage
|
|
37
|
+
|
|
38
|
+
```typescript
|
|
39
|
+
import { findFirst } from '@starbemtech/star-db-query-builder'
|
|
40
|
+
|
|
41
|
+
// Find user by email
|
|
42
|
+
const user = await findFirst({
|
|
43
|
+
tableName: 'users',
|
|
44
|
+
dbClient,
|
|
45
|
+
where: {
|
|
46
|
+
email: { operator: '=', value: 'user@example.com' },
|
|
47
|
+
},
|
|
48
|
+
})
|
|
49
|
+
|
|
50
|
+
console.log(user) // { id: 'user-123', name: 'John Doe', email: 'user@example.com', ... }
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
### With Specific Fields
|
|
54
|
+
|
|
55
|
+
```typescript
|
|
56
|
+
// Select only specific fields
|
|
57
|
+
const user = await findFirst({
|
|
58
|
+
tableName: 'users',
|
|
59
|
+
dbClient,
|
|
60
|
+
select: ['id', 'name', 'email'],
|
|
61
|
+
where: {
|
|
62
|
+
status: { operator: '=', value: 'active' },
|
|
63
|
+
},
|
|
64
|
+
})
|
|
65
|
+
|
|
66
|
+
console.log(user) // { id: 'user-123', name: 'John Doe', email: 'user@example.com' }
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
### With Complex Conditions
|
|
70
|
+
|
|
71
|
+
```typescript
|
|
72
|
+
// Multiple conditions with AND
|
|
73
|
+
const user = await findFirst({
|
|
74
|
+
tableName: 'users',
|
|
75
|
+
dbClient,
|
|
76
|
+
where: {
|
|
77
|
+
AND: [
|
|
78
|
+
{ email: { operator: '=', value: 'user@example.com' } },
|
|
79
|
+
{ status: { operator: '=', value: 'active' } },
|
|
80
|
+
{ verified: { operator: '=', value: true } },
|
|
81
|
+
],
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
|
|
85
|
+
// Multiple conditions with OR
|
|
86
|
+
const user = await findFirst({
|
|
87
|
+
tableName: 'users',
|
|
88
|
+
dbClient,
|
|
89
|
+
where: {
|
|
90
|
+
OR: [
|
|
91
|
+
{ email: { operator: '=', value: 'user@example.com' } },
|
|
92
|
+
{ phone: { operator: '=', value: '+1234567890' } },
|
|
93
|
+
],
|
|
94
|
+
},
|
|
95
|
+
})
|
|
96
|
+
```
|
|
97
|
+
|
|
98
|
+
### With Ordering
|
|
99
|
+
|
|
100
|
+
```typescript
|
|
101
|
+
// Find the most recent user
|
|
102
|
+
const latestUser = await findFirst({
|
|
103
|
+
tableName: 'users',
|
|
104
|
+
dbClient,
|
|
105
|
+
orderBy: [{ field: 'created_at', direction: 'DESC' }],
|
|
106
|
+
})
|
|
107
|
+
|
|
108
|
+
// Find the oldest active user
|
|
109
|
+
const oldestUser = await findFirst({
|
|
110
|
+
tableName: 'users',
|
|
111
|
+
dbClient,
|
|
112
|
+
where: { status: { operator: '=', value: 'active' } },
|
|
113
|
+
orderBy: [{ field: 'created_at', direction: 'ASC' }],
|
|
114
|
+
})
|
|
115
|
+
```
|
|
116
|
+
|
|
117
|
+
### With Grouping
|
|
118
|
+
|
|
119
|
+
```typescript
|
|
120
|
+
// Find the first user in each status group
|
|
121
|
+
const userByStatus = await findFirst({
|
|
122
|
+
tableName: 'users',
|
|
123
|
+
dbClient,
|
|
124
|
+
select: ['status', 'name', 'created_at'],
|
|
125
|
+
groupBy: ['status'],
|
|
126
|
+
orderBy: [{ field: 'created_at', direction: 'ASC' }],
|
|
127
|
+
})
|
|
128
|
+
```
|
|
129
|
+
|
|
130
|
+
### Advanced Conditions
|
|
131
|
+
|
|
132
|
+
```typescript
|
|
133
|
+
// Using different operators
|
|
134
|
+
const user = await findFirst({
|
|
135
|
+
tableName: 'users',
|
|
136
|
+
dbClient,
|
|
137
|
+
where: {
|
|
138
|
+
age: { operator: '>=', value: 18 },
|
|
139
|
+
name: { operator: 'LIKE', value: '%John%' },
|
|
140
|
+
email: { operator: 'IS NOT NULL', value: null },
|
|
141
|
+
status: { operator: 'IN', value: ['active', 'pending'] },
|
|
142
|
+
},
|
|
143
|
+
})
|
|
144
|
+
|
|
145
|
+
// Using BETWEEN
|
|
146
|
+
const user = await findFirst({
|
|
147
|
+
tableName: 'users',
|
|
148
|
+
dbClient,
|
|
149
|
+
where: {
|
|
150
|
+
created_at: {
|
|
151
|
+
operator: 'BETWEEN',
|
|
152
|
+
value: [new Date('2023-01-01'), new Date('2023-12-31')],
|
|
153
|
+
},
|
|
154
|
+
},
|
|
155
|
+
})
|
|
156
|
+
```
|
|
157
|
+
|
|
158
|
+
### TypeScript Usage
|
|
159
|
+
|
|
160
|
+
```typescript
|
|
161
|
+
interface User {
|
|
162
|
+
id: string
|
|
163
|
+
name: string
|
|
164
|
+
email: string
|
|
165
|
+
age: number
|
|
166
|
+
status: 'active' | 'inactive' | 'pending'
|
|
167
|
+
created_at: Date
|
|
168
|
+
updated_at: Date
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
// Typed usage
|
|
172
|
+
const user: User | null = await findFirst<User>({
|
|
173
|
+
tableName: 'users',
|
|
174
|
+
dbClient,
|
|
175
|
+
where: {
|
|
176
|
+
email: { operator: '=', value: 'user@example.com' },
|
|
177
|
+
},
|
|
178
|
+
})
|
|
179
|
+
|
|
180
|
+
if (user) {
|
|
181
|
+
console.log(`Found user: ${user.name}`)
|
|
182
|
+
} else {
|
|
183
|
+
console.log('User not found')
|
|
184
|
+
}
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
### Error Handling
|
|
188
|
+
|
|
189
|
+
```typescript
|
|
190
|
+
try {
|
|
191
|
+
const user = await findFirst({
|
|
192
|
+
tableName: 'users',
|
|
193
|
+
dbClient,
|
|
194
|
+
where: { email: { operator: '=', value: 'user@example.com' } },
|
|
195
|
+
})
|
|
196
|
+
|
|
197
|
+
if (user) {
|
|
198
|
+
console.log('User found:', user.name)
|
|
199
|
+
} else {
|
|
200
|
+
console.log('No user found with this email')
|
|
201
|
+
}
|
|
202
|
+
} catch (error) {
|
|
203
|
+
console.error('Database error:', error.message)
|
|
204
|
+
// Handle error appropriately
|
|
205
|
+
}
|
|
206
|
+
```
|
|
207
|
+
|
|
208
|
+
## Generated SQL Examples
|
|
209
|
+
|
|
210
|
+
### Simple Query
|
|
211
|
+
|
|
212
|
+
```sql
|
|
213
|
+
SELECT * FROM users WHERE email = $1 LIMIT 1
|
|
214
|
+
```
|
|
215
|
+
|
|
216
|
+
### With Specific Fields
|
|
217
|
+
|
|
218
|
+
```sql
|
|
219
|
+
SELECT id, name, email FROM users WHERE status = $1 LIMIT 1
|
|
220
|
+
```
|
|
221
|
+
|
|
222
|
+
### With Complex Conditions
|
|
223
|
+
|
|
224
|
+
```sql
|
|
225
|
+
SELECT * FROM users
|
|
226
|
+
WHERE (email = $1 AND status = $2 AND verified = $3)
|
|
227
|
+
LIMIT 1
|
|
228
|
+
```
|
|
229
|
+
|
|
230
|
+
### With Ordering
|
|
231
|
+
|
|
232
|
+
```sql
|
|
233
|
+
SELECT * FROM users
|
|
234
|
+
ORDER BY created_at DESC
|
|
235
|
+
LIMIT 1
|
|
236
|
+
```
|
|
237
|
+
|
|
238
|
+
### With Grouping
|
|
239
|
+
|
|
240
|
+
```sql
|
|
241
|
+
SELECT status, name, created_at
|
|
242
|
+
FROM users
|
|
243
|
+
GROUP BY status
|
|
244
|
+
ORDER BY created_at ASC
|
|
245
|
+
LIMIT 1
|
|
246
|
+
```
|
|
247
|
+
|
|
248
|
+
## Best Practices
|
|
249
|
+
|
|
250
|
+
### 1. Use Specific Field Selection
|
|
251
|
+
|
|
252
|
+
```typescript
|
|
253
|
+
// Good: Select only needed fields
|
|
254
|
+
const user = await findFirst({
|
|
255
|
+
tableName: 'users',
|
|
256
|
+
dbClient,
|
|
257
|
+
select: ['id', 'name', 'email'],
|
|
258
|
+
where: { id: { operator: '=', value: 'user-123' } },
|
|
259
|
+
})
|
|
260
|
+
|
|
261
|
+
// Avoid: Selecting all fields when not needed
|
|
262
|
+
const user = await findFirst({
|
|
263
|
+
tableName: 'users',
|
|
264
|
+
dbClient,
|
|
265
|
+
where: { id: { operator: '=', value: 'user-123' } },
|
|
266
|
+
})
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
### 2. Use Appropriate Indexes
|
|
270
|
+
|
|
271
|
+
Ensure your database has indexes on fields used in WHERE clauses for better performance:
|
|
272
|
+
|
|
273
|
+
```sql
|
|
274
|
+
-- Example indexes for common queries
|
|
275
|
+
CREATE INDEX idx_users_email ON users(email);
|
|
276
|
+
CREATE INDEX idx_users_status ON users(status);
|
|
277
|
+
CREATE INDEX idx_users_created_at ON users(created_at);
|
|
278
|
+
```
|
|
279
|
+
|
|
280
|
+
### 3. Handle Null Results
|
|
281
|
+
|
|
282
|
+
```typescript
|
|
283
|
+
const user = await findFirst({
|
|
284
|
+
tableName: 'users',
|
|
285
|
+
dbClient,
|
|
286
|
+
where: { email: { operator: '=', value: 'nonexistent@example.com' } },
|
|
287
|
+
})
|
|
288
|
+
|
|
289
|
+
if (!user) {
|
|
290
|
+
// Handle case when no user is found
|
|
291
|
+
throw new Error('User not found')
|
|
292
|
+
}
|
|
293
|
+
```
|
|
294
|
+
|
|
295
|
+
### 4. Use TypeScript for Type Safety
|
|
296
|
+
|
|
297
|
+
```typescript
|
|
298
|
+
interface UserSearchParams {
|
|
299
|
+
email?: string
|
|
300
|
+
status?: string
|
|
301
|
+
age?: number
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
const findUserByParams = async (
|
|
305
|
+
params: UserSearchParams
|
|
306
|
+
): Promise<User | null> => {
|
|
307
|
+
const where: Conditions<User> = {}
|
|
308
|
+
|
|
309
|
+
if (params.email) {
|
|
310
|
+
where.email = { operator: '=', value: params.email }
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (params.status) {
|
|
314
|
+
where.status = { operator: '=', value: params.status }
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
if (params.age) {
|
|
318
|
+
where.age = { operator: '>=', value: params.age }
|
|
319
|
+
}
|
|
320
|
+
|
|
321
|
+
return findFirst<User>({
|
|
322
|
+
tableName: 'users',
|
|
323
|
+
dbClient,
|
|
324
|
+
where,
|
|
325
|
+
})
|
|
326
|
+
}
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
## Common Use Cases
|
|
330
|
+
|
|
331
|
+
### 1. User Authentication
|
|
332
|
+
|
|
333
|
+
```typescript
|
|
334
|
+
const authenticateUser = async (email: string, password: string) => {
|
|
335
|
+
const user = await findFirst({
|
|
336
|
+
tableName: 'users',
|
|
337
|
+
dbClient,
|
|
338
|
+
where: {
|
|
339
|
+
AND: [
|
|
340
|
+
{ email: { operator: '=', value: email } },
|
|
341
|
+
{ password: { operator: '=', value: password } },
|
|
342
|
+
{ status: { operator: '=', value: 'active' } },
|
|
343
|
+
],
|
|
344
|
+
},
|
|
345
|
+
})
|
|
346
|
+
|
|
347
|
+
return user
|
|
348
|
+
}
|
|
349
|
+
```
|
|
350
|
+
|
|
351
|
+
### 2. Finding Latest Record
|
|
352
|
+
|
|
353
|
+
```typescript
|
|
354
|
+
const getLatestOrder = async (userId: string) => {
|
|
355
|
+
const order = await findFirst({
|
|
356
|
+
tableName: 'orders',
|
|
357
|
+
dbClient,
|
|
358
|
+
where: { user_id: { operator: '=', value: userId } },
|
|
359
|
+
orderBy: [{ field: 'created_at', direction: 'DESC' }],
|
|
360
|
+
})
|
|
361
|
+
|
|
362
|
+
return order
|
|
363
|
+
}
|
|
364
|
+
```
|
|
365
|
+
|
|
366
|
+
### 3. Checking Existence
|
|
367
|
+
|
|
368
|
+
```typescript
|
|
369
|
+
const userExists = async (email: string): Promise<boolean> => {
|
|
370
|
+
const user = await findFirst({
|
|
371
|
+
tableName: 'users',
|
|
372
|
+
dbClient,
|
|
373
|
+
select: ['id'],
|
|
374
|
+
where: { email: { operator: '=', value: email } },
|
|
375
|
+
})
|
|
376
|
+
|
|
377
|
+
return user !== null
|
|
378
|
+
}
|
|
379
|
+
```
|
|
380
|
+
|
|
381
|
+
## Performance Considerations
|
|
382
|
+
|
|
383
|
+
- **Indexes**: Ensure proper indexes exist on fields used in WHERE clauses
|
|
384
|
+
- **Field Selection**: Use `select` to limit returned fields when possible
|
|
385
|
+
- **Limit Results**: `findFirst` automatically limits to 1 result, which is optimal
|
|
386
|
+
- **Connection Pooling**: Use connection pooling for better performance in high-traffic applications
|
|
387
|
+
|
|
388
|
+
## Error Messages
|
|
389
|
+
|
|
390
|
+
Common error messages you might encounter:
|
|
391
|
+
|
|
392
|
+
- `Table name is required` - The `tableName` parameter is missing
|
|
393
|
+
- `DB client is required` - The `dbClient` parameter is missing
|
|
394
|
+
- Database-specific errors from the underlying database driver
|