@gravito/dark-matter 1.0.0 → 1.1.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/README.md CHANGED
@@ -43,9 +43,10 @@ await Mongo.disconnect()
43
43
  - 📊 **Aggregation Pipeline** - Fluent aggregation API
44
44
  - 🔌 **Multi-connection** - Named connections support
45
45
  - 🛡️ **Transactions** - ACID transactions with convenient API
46
+ - 🗑️ **Soft Deletes** - Built-in soft delete support with restore capability
46
47
  - 📦 **GridFS** - Handle large file uploads/downloads
47
48
  - ⚡ **Change Streams** - Real-time database event listening
48
- - ✅ **Schema Validation** - JSON Schema enforcement
49
+ - ✅ **Schema Validation** - Type-safe Schema Builder API for MongoDB validation
49
50
 
50
51
  ## API Reference
51
52
 
@@ -123,6 +124,52 @@ await Mongo.collection('logs').bulkWrite([
123
124
  ])
124
125
  ```
125
126
 
127
+ ### Soft Deletes
128
+
129
+ Dark Matter 支援開箱即用的軟刪除功能:
130
+
131
+ ```typescript
132
+ // 軟刪除一筆記錄(設置 deletedAt)
133
+ await Mongo.collection('users')
134
+ .where('_id', userId)
135
+ .softDelete()
136
+
137
+ // 查詢時自動排除已軟刪除的記錄
138
+ const activeUsers = await Mongo.collection('users').get()
139
+
140
+ // 包含已軟刪除的記錄
141
+ const allUsers = await Mongo.collection('users')
142
+ .withTrashed()
143
+ .get()
144
+
145
+ // 只查詢已軟刪除的記錄
146
+ const trashedUsers = await Mongo.collection('users')
147
+ .onlyTrashed()
148
+ .get()
149
+
150
+ // 恢復軟刪除的記錄
151
+ await Mongo.collection('users')
152
+ .where('_id', userId)
153
+ .restore()
154
+
155
+ // 批次軟刪除
156
+ await Mongo.collection('users')
157
+ .where('status', 'inactive')
158
+ .softDeleteMany()
159
+
160
+ // 批次恢復
161
+ await Mongo.collection('users')
162
+ .onlyTrashed()
163
+ .restoreMany()
164
+
165
+ // 永久刪除記錄
166
+ await Mongo.collection('users')
167
+ .where('_id', userId)
168
+ .forceDelete()
169
+ ```
170
+
171
+ **注意**:軟刪除使用 `deletedAt` 欄位(`Date | null`)。請確保在文檔中加入此欄位。
172
+
126
173
  ### Aggregation Pipeline
127
174
 
128
175
  ```typescript
@@ -152,6 +199,54 @@ const ordersWithCustomers = await Mongo.collection('orders')
152
199
  .get()
153
200
  ```
154
201
 
202
+ ### Schema Validation
203
+
204
+ 使用友善的 Schema Builder API 建立型別安全的 MongoDB Schema 驗證:
205
+
206
+ ```typescript
207
+ import { schema } from '@gravito/dark-matter'
208
+
209
+ // 建構 Schema
210
+ const userSchema = schema()
211
+ .required('username', 'email', 'createdAt')
212
+ .string('username', { minLength: 3, maxLength: 50 })
213
+ .string('email', { pattern: '^.+@.+$' })
214
+ .integer('age', { minimum: 0, maximum: 150 })
215
+ .boolean('isActive')
216
+ .date('createdAt')
217
+ .array('roles', 'string', { minItems: 1 })
218
+ .object('profile', (s) =>
219
+ s
220
+ .string('bio', { maxLength: 500 })
221
+ .string('avatar')
222
+ .integer('followers')
223
+ )
224
+
225
+ // 建立帶有 Schema 驗證的 Collection
226
+ await Mongo.database().createCollectionWithSchema('users', userSchema)
227
+
228
+ // 或使用原生 API
229
+ await Mongo.database().createCollection('users', {
230
+ schema: userSchema.toValidationOptions({
231
+ validationLevel: 'strict',
232
+ validationAction: 'error'
233
+ })
234
+ })
235
+ ```
236
+
237
+ #### 支援的欄位類型
238
+
239
+ ```typescript
240
+ schema()
241
+ .string('field', { minLength, maxLength, pattern, enum })
242
+ .number('field', { minimum, maximum, exclusiveMinimum, exclusiveMaximum })
243
+ .integer('field', { minimum, maximum })
244
+ .boolean('field')
245
+ .date('field')
246
+ .array('field', 'string', { minItems, maxItems, uniqueItems })
247
+ .object('field', (s) => s.string('nested'))
248
+ ```
249
+
155
250
  ### Advanced Features
156
251
 
157
252
  #### Transactions
@@ -184,14 +279,53 @@ for await (const event of stream) {
184
279
 
185
280
  #### GridFS (File Storage)
186
281
 
282
+ GridFS 支援大檔案(>16MB)的儲存與串流處理:
283
+
187
284
  ```typescript
188
- const grid = new MongoGridFS(Mongo.database())
285
+ import { MongoGridFS } from '@gravito/dark-matter'
189
286
 
190
- // Upload
191
- const fileId = await grid.upload(Buffer.from('Hello'), { filename: 'hello.txt' })
287
+ const grid = new MongoGridFS(Mongo.database())
192
288
 
193
- // Download
289
+ // 基本上傳下載
290
+ const fileId = await grid.upload(Buffer.from('Hello'), {
291
+ filename: 'hello.txt',
292
+ contentType: 'text/plain',
293
+ metadata: { author: 'John' }
294
+ })
194
295
  const content = await grid.download(fileId)
296
+
297
+ // 串流上傳(適合大檔案)
298
+ const stream = file.stream()
299
+ const fileId = await grid.uploadStream(stream, {
300
+ filename: 'large-video.mp4'
301
+ }, (progress) => {
302
+ console.log(`上傳進度: ${progress.bytesWritten} bytes`)
303
+ })
304
+
305
+ // 串流下載
306
+ const downloadStream = grid.downloadStream(fileId)
307
+ const reader = downloadStream.getReader()
308
+ while (true) {
309
+ const { done, value } = await reader.read()
310
+ if (done) break
311
+ // 處理 chunk
312
+ }
313
+
314
+ // 大檔案分片上傳(帶進度追蹤)
315
+ const fileId = await grid.uploadLargeFile(largeFile, {
316
+ filename: 'movie.mp4',
317
+ chunkSizeBytes: 255 * 1024 // 255 KB
318
+ }, (progress) => {
319
+ console.log(`進度: ${progress.percentage}%`)
320
+ console.log(`已上傳: ${progress.bytesWritten} / ${progress.totalBytes}`)
321
+ })
322
+
323
+ // 取得檔案中繼資料
324
+ const fileInfo = await grid.findById(fileId)
325
+ console.log(fileInfo.filename, fileInfo.length, fileInfo.uploadDate)
326
+
327
+ // 刪除檔案
328
+ await grid.delete(fileId)
195
329
  ```
196
330
 
197
331
  #### Schema Validation
@@ -227,6 +361,77 @@ const health = await Mongo.connection().getHealthStatus()
227
361
  console.log(health.latencyMs) // e.g. 15
228
362
  ```
229
363
 
364
+ ## Performance Optimization
365
+
366
+ ### Indexing
367
+
368
+ ```typescript
369
+ // Create indexes for frequently queried fields
370
+ await Mongo.collection('users').createIndex({ email: 1 }, { unique: true })
371
+ await Mongo.collection('users').createIndex({ status: 1, createdAt: -1 })
372
+ ```
373
+
374
+ ### Query Optimization
375
+
376
+ ```typescript
377
+ // Use projection to reduce data transfer
378
+ const users = await Mongo.collection('users')
379
+ .select('name', 'email') // Only fetch needed fields
380
+ .where('status', 'active')
381
+ .get()
382
+
383
+ // Use limit for large result sets
384
+ const recentPosts = await Mongo.collection('posts')
385
+ .orderBy('createdAt', 'desc')
386
+ .limit(20) // Prevent fetching too much data
387
+ .get()
388
+ ```
389
+
390
+ ### Connection Pool
391
+
392
+ ```typescript
393
+ Mongo.configure({
394
+ default: 'main',
395
+ connections: {
396
+ main: {
397
+ uri: 'mongodb://localhost:27017',
398
+ database: 'myapp',
399
+ maxPoolSize: 50, // Adjust based on load
400
+ minPoolSize: 10, // Keep minimum connections
401
+ maxIdleTimeMS: 30000 // Idle connection timeout
402
+ }
403
+ }
404
+ })
405
+ ```
406
+
407
+ ### Batch Operations
408
+
409
+ ```typescript
410
+ // Use bulkWrite to reduce round trips
411
+ await Mongo.collection('logs').bulkWrite([
412
+ { insertOne: { document: { event: 'login', userId: 1 } } },
413
+ { updateOne: { filter: { _id: 2 }, update: { $set: { status: 'active' } } } },
414
+ { deleteOne: { filter: { _id: 3 } } }
415
+ ])
416
+ ```
417
+
418
+ ### Monitoring
419
+
420
+ ```typescript
421
+ import { MongoPoolMonitor } from '@gravito/dark-matter'
422
+
423
+ const monitor = new MongoPoolMonitor(Mongo.connection())
424
+ const metrics = monitor.getMetrics()
425
+
426
+ console.log('Pool status:', {
427
+ totalConnections: metrics.totalConnections,
428
+ availableConnections: metrics.availableConnections,
429
+ waitQueueSize: metrics.waitQueueSize
430
+ })
431
+ ```
432
+
433
+ 詳細的效能調優指南請參考 [docs/performance-analysis.md](./docs/performance-analysis.md)
434
+
230
435
  ## Roadmap
231
436
 
232
437
  - [x] Connection retry & health check
@@ -234,6 +439,9 @@ console.log(health.latencyMs) // e.g. 15
234
439
  - [x] Schema validation
235
440
  - [x] Change streams
236
441
  - [x] GridFS support
442
+ - [x] Soft deletes
443
+ - [x] Schema Builder API
444
+ - [x] GridFS streaming & progress tracking
237
445
 
238
446
  ## License
239
447