@aetherframework/database 1.0.9
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/LICENSE +21 -0
- package/README.md +846 -0
- package/index.js +31 -0
- package/package.json +56 -0
- package/src/DatabaseManager.js +565 -0
- package/src/core/ConnectionManager.js +351 -0
- package/src/core/DatabaseFactory.js +188 -0
- package/src/core/MongoQueryBuilder.js +576 -0
- package/src/core/PluginManager.js +968 -0
- package/src/core/QueryBuilder.js +4398 -0
- package/src/core/TransactionManager.js +40 -0
- package/src/drivers/clickhouse-driver.js +272 -0
- package/src/drivers/index.js +273 -0
- package/src/drivers/mongodb-driver.js +87 -0
- package/src/drivers/mssql-driver.js +117 -0
- package/src/drivers/mysql-driver.js +169 -0
- package/src/drivers/oracle-driver.js +101 -0
- package/src/drivers/postgres-driver.js +234 -0
- package/src/drivers/redis-driver.js +52 -0
- package/src/drivers/sqlite-driver.js +67 -0
- package/src/middleware/connection-pool.js +455 -0
- package/src/middleware/performance-monitor.js +652 -0
- package/src/middleware/query-cache.js +500 -0
- package/src/middleware/query-logger.js +262 -0
- package/src/plugins/AuditPlugin.js +447 -0
- package/src/plugins/BasePlugin.js +418 -0
- package/src/plugins/BatchOperationPlugin.js +165 -0
- package/src/plugins/CachePlugin.js +407 -0
- package/src/plugins/CtePlugin.js +523 -0
- package/src/plugins/DistributedPlugin.js +543 -0
- package/src/plugins/EncryptionPlugin.js +211 -0
- package/src/plugins/FullTextSearchPlugin.js +164 -0
- package/src/plugins/GeospatialPlugin.js +219 -0
- package/src/plugins/GraphQLPlugin.js +162 -0
- package/src/plugins/HookPlugin.js +211 -0
- package/src/plugins/JsonPlugin.js +366 -0
- package/src/plugins/OptimisticLockPlugin.js +374 -0
- package/src/plugins/PerformancePlugin.js +175 -0
- package/src/plugins/ResiliencePlugin.js +114 -0
- package/src/plugins/ShardingPlugin.js +227 -0
- package/src/plugins/SoftDeletePlugin.js +258 -0
- package/src/plugins/SyncPlugin.js +373 -0
- package/src/plugins/VersioningPlugin.js +314 -0
- package/src/plugins/WindowFunctionPlugin.js +343 -0
- package/src/utils/config-loader.js +632 -0
- package/src/utils/error-handler.js +724 -0
- package/src/utils/migration-runner.js +1066 -0
- package/types.js +129 -0
package/README.md
ADDED
|
@@ -0,0 +1,846 @@
|
|
|
1
|
+
AetherFramework Database - Zero-Dependency Multi-Database Integration for Node.js
|
|
2
|
+
|
|
3
|
+
🚀 Why Choose AetherFramework Database?
|
|
4
|
+
|
|
5
|
+
AetherFramework Database is a revolutionary database integration solution designed specifically for the AetherJS API framework, but flexible enough to work with any Node.js application. In a world of bloated dependencies and complex ORMs, we offer a refreshing alternative that prioritizes performance, simplicity, and developer experience.
|
|
6
|
+
|
|
7
|
+
📊 Key Advantages Over Other Solutions
|
|
8
|
+
|
|
9
|
+
| Feature | AetherFramework Database | TypeORM | Sequelize | Knex.js | Prisma |
|
|
10
|
+
|---------|-----------------------------|---------|-----------|---------|--------|
|
|
11
|
+
| Zero Dependencies | ✅ No external dependencies | ❌ 50+ dependencies | ❌ 40+ dependencies | ❌ 15+ dependencies | ❌ 100+ dependencies |
|
|
12
|
+
| Bundle Size | ✅ ~100KB | ❌ ~10MB | ❌ ~8MB | ❌ ~2MB | ❌ ~20MB |
|
|
13
|
+
| Multi-Database Support | ✅ 8+ databases unified API | ✅ 7+ databases | ✅ 6+ databases | ✅ 7+ databases | ✅ 5+ databases |
|
|
14
|
+
| Built-in Features | ✅ Pooling, Caching, Monitoring, Migrations | ❌ Requires plugins | ❌ Requires plugins | ❌ Basic only | ❌ Limited |
|
|
15
|
+
| TypeScript Support | ✅ First-class with full types | ✅ Excellent | ✅ Good | ✅ Basic | ✅ Excellent |
|
|
16
|
+
| Learning Curve | ✅ Gentle, intuitive API | 🔴 Complex | 🟡 Moderate | 🟢 Simple | 🔴 Complex |
|
|
17
|
+
| Performance | ✅ Native speed, no overhead | 🟡 Good | 🟡 Good | 🟢 Excellent | 🟢 Good |
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
📦 Installation
|
|
21
|
+
|
|
22
|
+
```bash
|
|
23
|
+
Using npm
|
|
24
|
+
npm install @aetherframework/database
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
🚀 Quick Start
|
|
28
|
+
|
|
29
|
+
With AetherJS
|
|
30
|
+
|
|
31
|
+
```javascript
|
|
32
|
+
// In your AetherJS project
|
|
33
|
+
import { Database } from '@aetherframework/database';
|
|
34
|
+
|
|
35
|
+
// Minimal configuration
|
|
36
|
+
const db = new Database({
|
|
37
|
+
connections: {
|
|
38
|
+
primary: {
|
|
39
|
+
type: 'sqlite',
|
|
40
|
+
database: './data/app.db'
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
// Initialize
|
|
46
|
+
await db.init();
|
|
47
|
+
|
|
48
|
+
// Start using immediately
|
|
49
|
+
const users = await db.table('users').select('*').execute();
|
|
50
|
+
console.log(users.rows);
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
With Express.js
|
|
54
|
+
|
|
55
|
+
```javascript
|
|
56
|
+
import express from 'express';
|
|
57
|
+
import { Database } from '@aetherframework/database';
|
|
58
|
+
|
|
59
|
+
const app = express();
|
|
60
|
+
const db = new Database({
|
|
61
|
+
connections: {
|
|
62
|
+
primary: {
|
|
63
|
+
type: 'mysql',
|
|
64
|
+
host: 'localhost',
|
|
65
|
+
user: 'root',
|
|
66
|
+
password: 'password',
|
|
67
|
+
database: 'myapp'
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
await db.init();
|
|
73
|
+
|
|
74
|
+
app.get('/users', async (req, res) => {
|
|
75
|
+
const users = await db.table('users').select('*').execute();
|
|
76
|
+
res.json(users.rows);
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
app.listen(3000, () => {
|
|
80
|
+
console.log('Server running with @aetherframework/database');
|
|
81
|
+
});
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
With Fastify
|
|
85
|
+
|
|
86
|
+
```javascript
|
|
87
|
+
import Fastify from 'fastify';
|
|
88
|
+
import { Database } from '@aetherframework/database';
|
|
89
|
+
|
|
90
|
+
const fastify = Fastify();
|
|
91
|
+
const db = new Database({
|
|
92
|
+
connections: {
|
|
93
|
+
primary: {
|
|
94
|
+
type: 'postgresql',
|
|
95
|
+
host: 'localhost',
|
|
96
|
+
user: 'postgres',
|
|
97
|
+
password: 'password',
|
|
98
|
+
database: 'myapp'
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
});
|
|
102
|
+
|
|
103
|
+
await db.init();
|
|
104
|
+
|
|
105
|
+
fastify.get('/users', async (request, reply) => {
|
|
106
|
+
const users = await db.table('users').select('*').execute();
|
|
107
|
+
return users.rows;
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
fastify.listen({ port: 3000 }, (err) => {
|
|
111
|
+
if (err) throw err;
|
|
112
|
+
console.log('Fastify server running with @aetherframework/database');
|
|
113
|
+
});
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
With NestJS
|
|
117
|
+
|
|
118
|
+
```javascript
|
|
119
|
+
// database.module.ts
|
|
120
|
+
import { Module } from '@nestjs/common';
|
|
121
|
+
import { Database } from '@aetherframework/database';
|
|
122
|
+
|
|
123
|
+
@Module({
|
|
124
|
+
providers: [
|
|
125
|
+
{
|
|
126
|
+
provide: 'DATABASE',
|
|
127
|
+
useFactory: async () => {
|
|
128
|
+
const db = new Database({
|
|
129
|
+
connections: {
|
|
130
|
+
primary: {
|
|
131
|
+
type: 'mysql',
|
|
132
|
+
host: 'localhost',
|
|
133
|
+
user: 'root',
|
|
134
|
+
password: 'password',
|
|
135
|
+
database: 'myapp'
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
});
|
|
139
|
+
await db.init();
|
|
140
|
+
return db;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
],
|
|
144
|
+
exports: ['DATABASE']
|
|
145
|
+
})
|
|
146
|
+
export class DatabaseModule {}
|
|
147
|
+
|
|
148
|
+
// users.service.ts
|
|
149
|
+
import { Injectable, Inject } from '@nestjs/common';
|
|
150
|
+
|
|
151
|
+
@Injectable()
|
|
152
|
+
export class UsersService {
|
|
153
|
+
constructor(@Inject('DATABASE') private db) {}
|
|
154
|
+
|
|
155
|
+
async findAll() {
|
|
156
|
+
return await this.db.table('users').select('*').execute();
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
📚 Basic Usage Guide
|
|
162
|
+
|
|
163
|
+
1. Simple Configuration
|
|
164
|
+
|
|
165
|
+
```javascript
|
|
166
|
+
import { Database } from '@aetherframework/database';
|
|
167
|
+
|
|
168
|
+
// Basic setup for a single database
|
|
169
|
+
const db = new Database({
|
|
170
|
+
connections: {
|
|
171
|
+
primary: {
|
|
172
|
+
type: 'sqlite', // or 'mysql', 'postgresql', 'mongodb', 'redis'
|
|
173
|
+
database: './data/myapp.db' // SQLite file path
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
});
|
|
177
|
+
|
|
178
|
+
await db.init();
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
2. Creating Tables
|
|
182
|
+
|
|
183
|
+
```javascript
|
|
184
|
+
// Create a simple users table
|
|
185
|
+
await db.query(`
|
|
186
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
187
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
188
|
+
name TEXT NOT NULL,
|
|
189
|
+
email TEXT UNIQUE NOT NULL,
|
|
190
|
+
age INTEGER,
|
|
191
|
+
created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP
|
|
192
|
+
)
|
|
193
|
+
`);
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
3. Basic CRUD Operations
|
|
197
|
+
|
|
198
|
+
Create (Insert)
|
|
199
|
+
|
|
200
|
+
```javascript
|
|
201
|
+
// Insert a single record
|
|
202
|
+
const result = await db.table('users')
|
|
203
|
+
.insert({
|
|
204
|
+
name: 'John Doe',
|
|
205
|
+
email: 'john@example.com',
|
|
206
|
+
age: 30
|
|
207
|
+
})
|
|
208
|
+
.execute();
|
|
209
|
+
|
|
210
|
+
console.log(`Inserted user with ID: ${result.lastID}`);
|
|
211
|
+
|
|
212
|
+
// Insert multiple records
|
|
213
|
+
const batchResult = await db.table('users')
|
|
214
|
+
.insert([
|
|
215
|
+
{ name: 'Alice', email: 'alice@example.com', age: 25 },
|
|
216
|
+
{ name: 'Bob', email: 'bob@example.com', age: 35 },
|
|
217
|
+
{ name: 'Charlie', email: 'charlie@example.com', age: 28 }
|
|
218
|
+
])
|
|
219
|
+
.execute();
|
|
220
|
+
|
|
221
|
+
console.log(`Inserted ${batchResult.affectedRows} users`);
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
Read (Select)
|
|
225
|
+
|
|
226
|
+
```javascript
|
|
227
|
+
// Get all users
|
|
228
|
+
const allUsers = await db.table('users').select('*').execute();
|
|
229
|
+
console.log(`Total users: ${allUsers.rows.length}`);
|
|
230
|
+
|
|
231
|
+
// Get specific columns
|
|
232
|
+
const names = await db.table('users')
|
|
233
|
+
.select('id', 'name', 'email')
|
|
234
|
+
.execute();
|
|
235
|
+
|
|
236
|
+
// Get with conditions
|
|
237
|
+
const adults = await db.table('users')
|
|
238
|
+
.select('*')
|
|
239
|
+
.where('age', '>=', 18)
|
|
240
|
+
.execute();
|
|
241
|
+
|
|
242
|
+
// Get with multiple conditions
|
|
243
|
+
const activeUsers = await db.table('users')
|
|
244
|
+
.select('*')
|
|
245
|
+
.where('age', '>=', 18)
|
|
246
|
+
.where('status', '=', 'active')
|
|
247
|
+
.execute();
|
|
248
|
+
|
|
249
|
+
// Get with OR conditions
|
|
250
|
+
const specificUsers = await db.table('users')
|
|
251
|
+
.select('*')
|
|
252
|
+
.where('name', '=', 'John')
|
|
253
|
+
.orWhere('name', '=', 'Jane')
|
|
254
|
+
.execute();
|
|
255
|
+
|
|
256
|
+
// Get with ordering and limits
|
|
257
|
+
const recentUsers = await db.table('users')
|
|
258
|
+
.select('*')
|
|
259
|
+
.orderBy('created_at', 'desc')
|
|
260
|
+
.limit(10)
|
|
261
|
+
.execute();
|
|
262
|
+
|
|
263
|
+
// Get single record
|
|
264
|
+
const user = await db.table('users')
|
|
265
|
+
.where('id', '=', 1)
|
|
266
|
+
.first();
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Update
|
|
270
|
+
|
|
271
|
+
```javascript
|
|
272
|
+
// Update single record
|
|
273
|
+
const updateResult = await db.table('users')
|
|
274
|
+
.where('id', '=', 1)
|
|
275
|
+
.update({
|
|
276
|
+
name: 'John Updated',
|
|
277
|
+
age: 31
|
|
278
|
+
})
|
|
279
|
+
.execute();
|
|
280
|
+
|
|
281
|
+
console.log(`Updated ${updateResult.affectedRows} user(s)`);
|
|
282
|
+
|
|
283
|
+
// Update multiple records
|
|
284
|
+
const bulkUpdate = await db.table('users')
|
|
285
|
+
.where('status', '=', 'inactive')
|
|
286
|
+
.update({ status: 'active' })
|
|
287
|
+
.execute();
|
|
288
|
+
|
|
289
|
+
// Increment/decrement values
|
|
290
|
+
await db.table('users')
|
|
291
|
+
.where('id', '=', 1)
|
|
292
|
+
.increment('login_count', 1)
|
|
293
|
+
.execute();
|
|
294
|
+
|
|
295
|
+
await db.table('users')
|
|
296
|
+
.where('id', '=', 2)
|
|
297
|
+
.decrement('balance', 100)
|
|
298
|
+
.execute();
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Delete
|
|
302
|
+
|
|
303
|
+
```javascript
|
|
304
|
+
// Delete single record
|
|
305
|
+
const deleteResult = await db.table('users')
|
|
306
|
+
.where('id', '=', 1)
|
|
307
|
+
.delete()
|
|
308
|
+
.execute();
|
|
309
|
+
|
|
310
|
+
console.log(`Deleted ${deleteResult.affectedRows} user(s)`);
|
|
311
|
+
|
|
312
|
+
// Delete with conditions
|
|
313
|
+
await db.table('users')
|
|
314
|
+
.where('status', '=', 'banned')
|
|
315
|
+
.where('last_login', '<', new Date('2023-01-01'))
|
|
316
|
+
.delete()
|
|
317
|
+
.execute();
|
|
318
|
+
```
|
|
319
|
+
|
|
320
|
+
4. Working with Different Databases
|
|
321
|
+
|
|
322
|
+
MySQL
|
|
323
|
+
|
|
324
|
+
```javascript
|
|
325
|
+
const mysqlDB = new Database({
|
|
326
|
+
connections: {
|
|
327
|
+
primary: {
|
|
328
|
+
type: 'mysql',
|
|
329
|
+
host: 'localhost',
|
|
330
|
+
port: 3306,
|
|
331
|
+
user: 'root',
|
|
332
|
+
password: 'password',
|
|
333
|
+
database: 'myapp',
|
|
334
|
+
charset: 'utf8mb4'
|
|
335
|
+
}
|
|
336
|
+
}
|
|
337
|
+
});
|
|
338
|
+
```
|
|
339
|
+
|
|
340
|
+
PostgreSQL
|
|
341
|
+
|
|
342
|
+
```javascript
|
|
343
|
+
const pgDB = new Database({
|
|
344
|
+
connections: {
|
|
345
|
+
primary: {
|
|
346
|
+
type: 'postgresql',
|
|
347
|
+
host: 'localhost',
|
|
348
|
+
port: 5432,
|
|
349
|
+
user: 'postgres',
|
|
350
|
+
password: 'password',
|
|
351
|
+
database: 'myapp',
|
|
352
|
+
ssl: false
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
});
|
|
356
|
+
```
|
|
357
|
+
|
|
358
|
+
SQLite
|
|
359
|
+
|
|
360
|
+
```javascript
|
|
361
|
+
const sqliteDB = new Database({
|
|
362
|
+
connections: {
|
|
363
|
+
primary: {
|
|
364
|
+
type: 'sqlite',
|
|
365
|
+
database: './data/app.db' // File path
|
|
366
|
+
// or ':memory:' for in-memory database
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
});
|
|
370
|
+
```
|
|
371
|
+
|
|
372
|
+
MongoDB
|
|
373
|
+
|
|
374
|
+
```javascript
|
|
375
|
+
const mongoDB = new Database({
|
|
376
|
+
connections: {
|
|
377
|
+
primary: {
|
|
378
|
+
type: 'mongodb',
|
|
379
|
+
host: 'localhost',
|
|
380
|
+
port: 27017,
|
|
381
|
+
database: 'myapp',
|
|
382
|
+
// Optional authentication
|
|
383
|
+
username: 'admin',
|
|
384
|
+
password: 'password'
|
|
385
|
+
}
|
|
386
|
+
}
|
|
387
|
+
});
|
|
388
|
+
|
|
389
|
+
// MongoDB specific operations
|
|
390
|
+
const users = await mongoDB.collection('users')
|
|
391
|
+
.find({ age: { $gt: 18 } })
|
|
392
|
+
.sort({ name: 1 })
|
|
393
|
+
.limit(10)
|
|
394
|
+
.execute();
|
|
395
|
+
```
|
|
396
|
+
|
|
397
|
+
Redis
|
|
398
|
+
|
|
399
|
+
```javascript
|
|
400
|
+
const redisDB = new Database({
|
|
401
|
+
connections: {
|
|
402
|
+
cache: {
|
|
403
|
+
type: 'redis',
|
|
404
|
+
host: 'localhost',
|
|
405
|
+
port: 6379,
|
|
406
|
+
// Optional authentication
|
|
407
|
+
password: 'password',
|
|
408
|
+
db: 0,
|
|
409
|
+
keyPrefix: 'myapp:'
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
});
|
|
413
|
+
|
|
414
|
+
// Redis operations
|
|
415
|
+
await redisDB.getConnection('cache').set('user:1', JSON.stringify(user));
|
|
416
|
+
const cachedUser = await redisDB.getConnection('cache').get('user:1');
|
|
417
|
+
```
|
|
418
|
+
|
|
419
|
+
5. Simple Joins and Relationships
|
|
420
|
+
|
|
421
|
+
```javascript
|
|
422
|
+
// Basic join
|
|
423
|
+
const usersWithOrders = await db.table('users')
|
|
424
|
+
.select('users.*', 'orders.total_amount')
|
|
425
|
+
.join('orders', 'users.id', '=', 'orders.user_id')
|
|
426
|
+
.execute();
|
|
427
|
+
|
|
428
|
+
// Left join
|
|
429
|
+
const allUsersWithOrders = await db.table('users')
|
|
430
|
+
.select('users.*', 'orders.total_amount')
|
|
431
|
+
.leftJoin('orders', 'users.id', '=', 'orders.user_id')
|
|
432
|
+
.execute();
|
|
433
|
+
|
|
434
|
+
// Multiple joins
|
|
435
|
+
const detailedData = await db.table('users')
|
|
436
|
+
.select(
|
|
437
|
+
'users.name',
|
|
438
|
+
'orders.order_number',
|
|
439
|
+
'products.name as product_name',
|
|
440
|
+
'order_items.quantity'
|
|
441
|
+
)
|
|
442
|
+
.join('orders', 'users.id', '=', 'orders.user_id')
|
|
443
|
+
.join('order_items', 'orders.id', '=', 'order_items.order_id')
|
|
444
|
+
.join('products', 'order_items.product_id', '=', 'products.id')
|
|
445
|
+
.where('users.status', '=', 'active')
|
|
446
|
+
.execute();
|
|
447
|
+
```
|
|
448
|
+
|
|
449
|
+
6. Aggregation Functions
|
|
450
|
+
|
|
451
|
+
```javascript
|
|
452
|
+
// Count records
|
|
453
|
+
const userCount = await db.table('users').count().execute();
|
|
454
|
+
console.log(`Total users: ${userCount.rows.count}`);
|
|
455
|
+
|
|
456
|
+
// Count with condition
|
|
457
|
+
const activeUsers = await db.table('users')
|
|
458
|
+
.where('status', '=', 'active')
|
|
459
|
+
.count()
|
|
460
|
+
.execute();
|
|
461
|
+
|
|
462
|
+
// Sum values
|
|
463
|
+
const totalSales = await db.table('orders')
|
|
464
|
+
.where('status', '=', 'completed')
|
|
465
|
+
.sum('amount')
|
|
466
|
+
.execute();
|
|
467
|
+
|
|
468
|
+
// Average values
|
|
469
|
+
const avgAge = await db.table('users').avg('age').execute();
|
|
470
|
+
|
|
471
|
+
// Minimum and maximum
|
|
472
|
+
const youngest = await db.table('users').min('age').execute();
|
|
473
|
+
const oldest = await db.table('users').max('age').execute();
|
|
474
|
+
|
|
475
|
+
// Group by
|
|
476
|
+
const salesByMonth = await db.table('orders')
|
|
477
|
+
.select(
|
|
478
|
+
db.raw('YEAR(created_at) as year'),
|
|
479
|
+
db.raw('MONTH(created_at) as month'),
|
|
480
|
+
db.raw('SUM(amount) as total_sales')
|
|
481
|
+
)
|
|
482
|
+
.where('status', '=', 'completed')
|
|
483
|
+
.groupBy('year', 'month')
|
|
484
|
+
.orderBy('year', 'desc')
|
|
485
|
+
.orderBy('month', 'desc')
|
|
486
|
+
.execute();
|
|
487
|
+
```
|
|
488
|
+
|
|
489
|
+
7. Simple Transactions
|
|
490
|
+
|
|
491
|
+
```javascript
|
|
492
|
+
// Basic transaction
|
|
493
|
+
try {
|
|
494
|
+
const result = await db.transaction(async (trx) => {
|
|
495
|
+
// Insert user
|
|
496
|
+
const user = await trx.table('users')
|
|
497
|
+
.insert({
|
|
498
|
+
name: 'John',
|
|
499
|
+
email: 'john@example.com'
|
|
500
|
+
})
|
|
501
|
+
.execute();
|
|
502
|
+
|
|
503
|
+
// Insert user profile
|
|
504
|
+
await trx.table('profiles')
|
|
505
|
+
.insert({
|
|
506
|
+
user_id: user.lastID,
|
|
507
|
+
bio: 'Software Developer'
|
|
508
|
+
})
|
|
509
|
+
.execute();
|
|
510
|
+
|
|
511
|
+
return user;
|
|
512
|
+
});
|
|
513
|
+
|
|
514
|
+
console.log('Transaction completed:', result);
|
|
515
|
+
} catch (error) {
|
|
516
|
+
console.error('Transaction failed:', error);
|
|
517
|
+
}
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
8. Error Handling
|
|
521
|
+
|
|
522
|
+
```javascript
|
|
523
|
+
try {
|
|
524
|
+
const result = await db.table('users')
|
|
525
|
+
.where('id', '=', 999)
|
|
526
|
+
.first();
|
|
527
|
+
|
|
528
|
+
if (!result) {
|
|
529
|
+
console.log('User not found');
|
|
530
|
+
}
|
|
531
|
+
} catch (error) {
|
|
532
|
+
console.error('Database error:', {
|
|
533
|
+
message: error.message,
|
|
534
|
+
code: error.code,
|
|
535
|
+
sql: error.sql,
|
|
536
|
+
params: error.params
|
|
537
|
+
});
|
|
538
|
+
|
|
539
|
+
// Handle specific error types
|
|
540
|
+
if (error.code === 'ER_DUP_ENTRY') {
|
|
541
|
+
console.log('Duplicate entry error');
|
|
542
|
+
} else if (error.code === 'ER_NO_SUCH_TABLE') {
|
|
543
|
+
console.log('Table does not exist');
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
9. Connection Management
|
|
549
|
+
|
|
550
|
+
```javascript
|
|
551
|
+
// Check connection status
|
|
552
|
+
const health = await db.getAllHealthChecks();
|
|
553
|
+
console.log('Database health:', health);
|
|
554
|
+
|
|
555
|
+
// Get connection statistics
|
|
556
|
+
const stats = db.getMetrics();
|
|
557
|
+
console.log('Query statistics:', {
|
|
558
|
+
totalQueries: stats.totalQueries,
|
|
559
|
+
successfulQueries: stats.successfulQueries,
|
|
560
|
+
failedQueries: stats.failedQueries,
|
|
561
|
+
avgQueryTime: stats.avgQueryTime
|
|
562
|
+
});
|
|
563
|
+
|
|
564
|
+
// Close connections when done
|
|
565
|
+
await db.close();
|
|
566
|
+
console.log('Database connections closed');
|
|
567
|
+
```
|
|
568
|
+
|
|
569
|
+
🔧 Common Patterns
|
|
570
|
+
|
|
571
|
+
1. Pagination
|
|
572
|
+
|
|
573
|
+
```javascript
|
|
574
|
+
async function getUsers(page = 1, limit = 10) {
|
|
575
|
+
const offset = (page - 1) * limit;
|
|
576
|
+
|
|
577
|
+
const users = await db.table('users')
|
|
578
|
+
.select('*')
|
|
579
|
+
.orderBy('created_at', 'desc')
|
|
580
|
+
.limit(limit)
|
|
581
|
+
.offset(offset)
|
|
582
|
+
.execute();
|
|
583
|
+
|
|
584
|
+
const total = await db.table('users').count().execute();
|
|
585
|
+
|
|
586
|
+
return {
|
|
587
|
+
data: users.rows,
|
|
588
|
+
pagination: {
|
|
589
|
+
page,
|
|
590
|
+
limit,
|
|
591
|
+
total: total.rows.count,
|
|
592
|
+
pages: Math.ceil(total.rows.count / limit)
|
|
593
|
+
}
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
```
|
|
597
|
+
|
|
598
|
+
2. Search Functionality
|
|
599
|
+
|
|
600
|
+
```javascript
|
|
601
|
+
async function searchUsers(query, filters = {}) {
|
|
602
|
+
let builder = db.table('users').select('*');
|
|
603
|
+
|
|
604
|
+
// Search in multiple fields
|
|
605
|
+
if (query) {
|
|
606
|
+
builder = builder.where(function(qb) {
|
|
607
|
+
qb.where('name', 'LIKE', `%${query}%`)
|
|
608
|
+
.orWhere('email', 'LIKE', `%${query}%`)
|
|
609
|
+
.orWhere('bio', 'LIKE', `%${query}%`);
|
|
610
|
+
});
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
// Apply filters
|
|
614
|
+
if (filters.status) {
|
|
615
|
+
builder = builder.where('status', '=', filters.status);
|
|
616
|
+
}
|
|
617
|
+
|
|
618
|
+
if (filters.minAge) {
|
|
619
|
+
builder = builder.where('age', '>=', filters.minAge);
|
|
620
|
+
}
|
|
621
|
+
|
|
622
|
+
if (filters.maxAge) {
|
|
623
|
+
builder = builder.where('age', '<=', filters.maxAge);
|
|
624
|
+
}
|
|
625
|
+
|
|
626
|
+
// Order and paginate
|
|
627
|
+
const result = await builder
|
|
628
|
+
.orderBy(filters.sortBy || 'created_at', filters.sortOrder || 'desc')
|
|
629
|
+
.limit(filters.limit || 20)
|
|
630
|
+
.offset(filters.offset || 0)
|
|
631
|
+
.execute();
|
|
632
|
+
|
|
633
|
+
return result.rows;
|
|
634
|
+
}
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
3. Batch Operations
|
|
638
|
+
|
|
639
|
+
```javascript
|
|
640
|
+
// Batch insert with validation
|
|
641
|
+
async function batchCreateUsers(users) {
|
|
642
|
+
const validUsers = users.filter(user =>
|
|
643
|
+
user.name && user.email && user.age > 0
|
|
644
|
+
);
|
|
645
|
+
|
|
646
|
+
if (validUsers.length === 0) {
|
|
647
|
+
return { success: false, message: 'No valid users to insert' };
|
|
648
|
+
}
|
|
649
|
+
|
|
650
|
+
try {
|
|
651
|
+
const result = await db.table('users')
|
|
652
|
+
.insert(validUsers)
|
|
653
|
+
.execute();
|
|
654
|
+
|
|
655
|
+
return {
|
|
656
|
+
success: true,
|
|
657
|
+
inserted: result.affectedRows,
|
|
658
|
+
skipped: users.length - validUsers.length
|
|
659
|
+
};
|
|
660
|
+
} catch (error) {
|
|
661
|
+
console.error('Batch insert failed:', error);
|
|
662
|
+
return { success: false, error: error.message };
|
|
663
|
+
}
|
|
664
|
+
}
|
|
665
|
+
```
|
|
666
|
+
|
|
667
|
+
⚙️ Configuration Examples
|
|
668
|
+
|
|
669
|
+
Minimal Configuration
|
|
670
|
+
|
|
671
|
+
```javascript
|
|
672
|
+
const minimalConfig = {
|
|
673
|
+
connections: {
|
|
674
|
+
primary: {
|
|
675
|
+
type: 'sqlite',
|
|
676
|
+
database: './data/app.db'
|
|
677
|
+
}
|
|
678
|
+
}
|
|
679
|
+
};
|
|
680
|
+
```
|
|
681
|
+
|
|
682
|
+
Production Configuration
|
|
683
|
+
|
|
684
|
+
```javascript
|
|
685
|
+
const productionConfig = {
|
|
686
|
+
enabled: true,
|
|
687
|
+
crossDb: true,
|
|
688
|
+
default: 'primary',
|
|
689
|
+
|
|
690
|
+
connections: {
|
|
691
|
+
primary: {
|
|
692
|
+
type: 'mysql',
|
|
693
|
+
host: process.env.DB_HOST,
|
|
694
|
+
port: parseInt(process.env.DB_PORT),
|
|
695
|
+
user: process.env.DB_USER,
|
|
696
|
+
password: process.env.DB_PASSWORD,
|
|
697
|
+
database: process.env.DB_NAME,
|
|
698
|
+
charset: 'utf8mb4',
|
|
699
|
+
timezone: '+00:00',
|
|
700
|
+
pool: {
|
|
701
|
+
min: 2,
|
|
702
|
+
max: 10,
|
|
703
|
+
idleTimeout: 30000,
|
|
704
|
+
acquireTimeout: 10000
|
|
705
|
+
}
|
|
706
|
+
},
|
|
707
|
+
cache: {
|
|
708
|
+
type: 'redis',
|
|
709
|
+
host: process.env.REDIS_HOST,
|
|
710
|
+
port: parseInt(process.env.REDIS_PORT),
|
|
711
|
+
password: process.env.REDIS_PASSWORD,
|
|
712
|
+
db: 0,
|
|
713
|
+
keyPrefix: 'app:'
|
|
714
|
+
}
|
|
715
|
+
},
|
|
716
|
+
|
|
717
|
+
driverModules: {
|
|
718
|
+
mysql: true,
|
|
719
|
+
redis: true,
|
|
720
|
+
sqlite: false,
|
|
721
|
+
postgres: false,
|
|
722
|
+
mongodb: false,
|
|
723
|
+
mssql: false,
|
|
724
|
+
oracle: false
|
|
725
|
+
},
|
|
726
|
+
|
|
727
|
+
middleware: {
|
|
728
|
+
queryLogger: {
|
|
729
|
+
enabled: process.env.NODE_ENV !== 'production',
|
|
730
|
+
logLevel: 'info',
|
|
731
|
+
slowQueryThreshold: 1000
|
|
732
|
+
},
|
|
733
|
+
connectionPool: {
|
|
734
|
+
enabled: true,
|
|
735
|
+
maxConnections: 10,
|
|
736
|
+
minConnections: 2
|
|
737
|
+
},
|
|
738
|
+
queryCache: {
|
|
739
|
+
enabled: true,
|
|
740
|
+
ttl: 300000
|
|
741
|
+
}
|
|
742
|
+
}
|
|
743
|
+
};
|
|
744
|
+
```
|
|
745
|
+
|
|
746
|
+
🔄 Migration from Other Libraries
|
|
747
|
+
|
|
748
|
+
From Knex.js
|
|
749
|
+
|
|
750
|
+
```javascript
|
|
751
|
+
// Knex.js
|
|
752
|
+
knex('users').where('id', 1).first();
|
|
753
|
+
|
|
754
|
+
// @aetherframework/database
|
|
755
|
+
db.table('users').where('id', '=', 1).first();
|
|
756
|
+
```
|
|
757
|
+
|
|
758
|
+
From Sequelize
|
|
759
|
+
|
|
760
|
+
```javascript
|
|
761
|
+
// Sequelize
|
|
762
|
+
User.findAll({ where: { status: 'active' } });
|
|
763
|
+
|
|
764
|
+
// @aetherframework/database
|
|
765
|
+
db.table('users').where('status', '=', 'active').execute();
|
|
766
|
+
```
|
|
767
|
+
|
|
768
|
+
From TypeORM
|
|
769
|
+
|
|
770
|
+
```javascript
|
|
771
|
+
// TypeORM
|
|
772
|
+
userRepository.find({ where: { age: MoreThan(18) } });
|
|
773
|
+
|
|
774
|
+
// @aetherframework/database
|
|
775
|
+
db.table('users').where('age', '>', 18).execute();
|
|
776
|
+
```
|
|
777
|
+
|
|
778
|
+
🏆 Best Practices
|
|
779
|
+
|
|
780
|
+
1. Always use parameterized queries - Prevents SQL injection
|
|
781
|
+
2. Close connections when done - Prevents connection leaks
|
|
782
|
+
3. Use transactions for multiple operations - Ensures data consistency
|
|
783
|
+
4. Enable query logging in development - Helps with debugging
|
|
784
|
+
5. Use connection pooling in production - Improves performance
|
|
785
|
+
6. Implement proper error handling - Graceful degradation
|
|
786
|
+
7. Use TypeScript for type safety - Catches errors at compile time
|
|
787
|
+
|
|
788
|
+
🔧 Troubleshooting
|
|
789
|
+
|
|
790
|
+
Common Issues
|
|
791
|
+
|
|
792
|
+
1. Connection refused
|
|
793
|
+
```javascript
|
|
794
|
+
// Check your connection settings
|
|
795
|
+
const db = new Database({
|
|
796
|
+
connections: {
|
|
797
|
+
primary: {
|
|
798
|
+
type: 'mysql',
|
|
799
|
+
host: 'localhost', // Make sure this is correct
|
|
800
|
+
port: 3306, // Default MySQL port
|
|
801
|
+
user: 'root', // Check username
|
|
802
|
+
password: 'password', // Check password
|
|
803
|
+
database: 'myapp' // Database must exist
|
|
804
|
+
}
|
|
805
|
+
}
|
|
806
|
+
});
|
|
807
|
+
```
|
|
808
|
+
|
|
809
|
+
2. Table doesn't exist
|
|
810
|
+
```javascript
|
|
811
|
+
// Create the table first
|
|
812
|
+
await db.query(`
|
|
813
|
+
CREATE TABLE IF NOT EXISTS users (
|
|
814
|
+
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
|
815
|
+
name TEXT NOT NULL
|
|
816
|
+
)
|
|
817
|
+
`);
|
|
818
|
+
```
|
|
819
|
+
|
|
820
|
+
3. Slow queries
|
|
821
|
+
```javascript
|
|
822
|
+
// Enable query logging to identify slow queries
|
|
823
|
+
const db = new Database({
|
|
824
|
+
middleware: {
|
|
825
|
+
queryLogger: {
|
|
826
|
+
enabled: true,
|
|
827
|
+
slowQueryThreshold: 100 // Log queries slower than 100ms
|
|
828
|
+
}
|
|
829
|
+
}
|
|
830
|
+
});
|
|
831
|
+
```
|
|
832
|
+
|
|
833
|
+
🚀 Next Steps
|
|
834
|
+
|
|
835
|
+
Once you're comfortable with the basics, explore these advanced features:
|
|
836
|
+
|
|
837
|
+
1. Query Caching - Improve performance with built-in caching
|
|
838
|
+
2. Performance Monitoring - Track and optimize query performance
|
|
839
|
+
3. Database Migrations - Version control for your database schema
|
|
840
|
+
4. Multiple Database Connections - Work with different databases simultaneously
|
|
841
|
+
5. Custom Drivers - Extend support for other database systems
|
|
842
|
+
|
|
843
|
+
|
|
844
|
+
📄 License
|
|
845
|
+
|
|
846
|
+
MIT © AetherJS Team
|