@gravito/dark-matter 1.0.0 → 1.1.2

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
@@ -35,17 +35,30 @@ const users = await Mongo.collection('users')
35
35
  await Mongo.disconnect()
36
36
  ```
37
37
 
38
- ## Features
39
-
40
- - 🚀 **Bun Native** - Optimized for Bun runtime
41
- - 🎯 **Laravel-style API** - Familiar fluent interface
42
- - 🔍 **Query Builder** - Type-safe query building
43
- - 📊 **Aggregation Pipeline** - Fluent aggregation API
44
- - 🔌 **Multi-connection** - Named connections support
45
- - 🛡️ **Transactions** - ACID transactions with convenient API
46
- - 📦 **GridFS** - Handle large file uploads/downloads
47
- - **Change Streams** - Real-time database event listening
48
- - ✅ **Schema Validation** - JSON Schema enforcement
38
+ ## Features
39
+
40
+ - 🚀 **Bun Native Performance**: Optimized for the Bun runtime with zero-copy data handling.
41
+ - 🌌 **Galaxy-Ready Persistence**: Native integration with PlanetCore for universal NoSQL data management.
42
+ - 🎯 **Laravel-style API**: Familiar, fluent interface for MongoDB collections and aggregation pipelines.
43
+ - 🛡️ **Distributed Document State**: ACID transactions and robust multi-connection management across the Galaxy.
44
+ - 🗑️ **Soft Deletes**: Built-in logic for logical record deletion with restoration support.
45
+ - 📦 **GridFS & Streams**: Specialized support for large-scale file storage and real-time change listening.
46
+
47
+ ## 🌌 Role in Galaxy Architecture
48
+
49
+ In the **Gravito Galaxy Architecture**, Dark Matter acts as the **MongoDB Gravity Core (NoSQL Persistence)**.
50
+
51
+ - **Document Focus**: Provides an alternative gravity core for Satellites that require schema-less flexibility or massive-scale document storage.
52
+ - **Micro-State Bridge**: Enables real-time reactive logic via MongoDB Change Streams, allowing one Satellite to react instantly to data changes in another.
53
+ - **File Distribution**: Leverages GridFS to provide a distributed file storage layer that works alongside `@gravito/nebula`.
54
+
55
+ ```mermaid
56
+ graph TD
57
+ S1[Satellite: Analytics] -- "Save" --> DM{Dark Matter}
58
+ S2[Satellite: Logs] -- "Query" --> DM
59
+ DM -->|Native Driver| MongoDB[(MongoDB Atlas)]
60
+ DM -.->|Watch| Realtime[Real-time Events]
61
+ ```
49
62
 
50
63
  ## API Reference
51
64
 
@@ -123,6 +136,52 @@ await Mongo.collection('logs').bulkWrite([
123
136
  ])
124
137
  ```
125
138
 
139
+ ### Soft Deletes
140
+
141
+ Dark Matter 支援開箱即用的軟刪除功能:
142
+
143
+ ```typescript
144
+ // 軟刪除一筆記錄(設置 deletedAt)
145
+ await Mongo.collection('users')
146
+ .where('_id', userId)
147
+ .softDelete()
148
+
149
+ // 查詢時自動排除已軟刪除的記錄
150
+ const activeUsers = await Mongo.collection('users').get()
151
+
152
+ // 包含已軟刪除的記錄
153
+ const allUsers = await Mongo.collection('users')
154
+ .withTrashed()
155
+ .get()
156
+
157
+ // 只查詢已軟刪除的記錄
158
+ const trashedUsers = await Mongo.collection('users')
159
+ .onlyTrashed()
160
+ .get()
161
+
162
+ // 恢復軟刪除的記錄
163
+ await Mongo.collection('users')
164
+ .where('_id', userId)
165
+ .restore()
166
+
167
+ // 批次軟刪除
168
+ await Mongo.collection('users')
169
+ .where('status', 'inactive')
170
+ .softDeleteMany()
171
+
172
+ // 批次恢復
173
+ await Mongo.collection('users')
174
+ .onlyTrashed()
175
+ .restoreMany()
176
+
177
+ // 永久刪除記錄
178
+ await Mongo.collection('users')
179
+ .where('_id', userId)
180
+ .forceDelete()
181
+ ```
182
+
183
+ **注意**:軟刪除使用 `deletedAt` 欄位(`Date | null`)。請確保在文檔中加入此欄位。
184
+
126
185
  ### Aggregation Pipeline
127
186
 
128
187
  ```typescript
@@ -152,6 +211,54 @@ const ordersWithCustomers = await Mongo.collection('orders')
152
211
  .get()
153
212
  ```
154
213
 
214
+ ### Schema Validation
215
+
216
+ 使用友善的 Schema Builder API 建立型別安全的 MongoDB Schema 驗證:
217
+
218
+ ```typescript
219
+ import { schema } from '@gravito/dark-matter'
220
+
221
+ // 建構 Schema
222
+ const userSchema = schema()
223
+ .required('username', 'email', 'createdAt')
224
+ .string('username', { minLength: 3, maxLength: 50 })
225
+ .string('email', { pattern: '^.+@.+$' })
226
+ .integer('age', { minimum: 0, maximum: 150 })
227
+ .boolean('isActive')
228
+ .date('createdAt')
229
+ .array('roles', 'string', { minItems: 1 })
230
+ .object('profile', (s) =>
231
+ s
232
+ .string('bio', { maxLength: 500 })
233
+ .string('avatar')
234
+ .integer('followers')
235
+ )
236
+
237
+ // 建立帶有 Schema 驗證的 Collection
238
+ await Mongo.database().createCollectionWithSchema('users', userSchema)
239
+
240
+ // 或使用原生 API
241
+ await Mongo.database().createCollection('users', {
242
+ schema: userSchema.toValidationOptions({
243
+ validationLevel: 'strict',
244
+ validationAction: 'error'
245
+ })
246
+ })
247
+ ```
248
+
249
+ #### 支援的欄位類型
250
+
251
+ ```typescript
252
+ schema()
253
+ .string('field', { minLength, maxLength, pattern, enum })
254
+ .number('field', { minimum, maximum, exclusiveMinimum, exclusiveMaximum })
255
+ .integer('field', { minimum, maximum })
256
+ .boolean('field')
257
+ .date('field')
258
+ .array('field', 'string', { minItems, maxItems, uniqueItems })
259
+ .object('field', (s) => s.string('nested'))
260
+ ```
261
+
155
262
  ### Advanced Features
156
263
 
157
264
  #### Transactions
@@ -184,14 +291,53 @@ for await (const event of stream) {
184
291
 
185
292
  #### GridFS (File Storage)
186
293
 
294
+ GridFS 支援大檔案(>16MB)的儲存與串流處理:
295
+
187
296
  ```typescript
188
- const grid = new MongoGridFS(Mongo.database())
297
+ import { MongoGridFS } from '@gravito/dark-matter'
189
298
 
190
- // Upload
191
- const fileId = await grid.upload(Buffer.from('Hello'), { filename: 'hello.txt' })
299
+ const grid = new MongoGridFS(Mongo.database())
192
300
 
193
- // Download
301
+ // 基本上傳下載
302
+ const fileId = await grid.upload(Buffer.from('Hello'), {
303
+ filename: 'hello.txt',
304
+ contentType: 'text/plain',
305
+ metadata: { author: 'John' }
306
+ })
194
307
  const content = await grid.download(fileId)
308
+
309
+ // 串流上傳(適合大檔案)
310
+ const stream = file.stream()
311
+ const fileId = await grid.uploadStream(stream, {
312
+ filename: 'large-video.mp4'
313
+ }, (progress) => {
314
+ console.log(`上傳進度: ${progress.bytesWritten} bytes`)
315
+ })
316
+
317
+ // 串流下載
318
+ const downloadStream = grid.downloadStream(fileId)
319
+ const reader = downloadStream.getReader()
320
+ while (true) {
321
+ const { done, value } = await reader.read()
322
+ if (done) break
323
+ // 處理 chunk
324
+ }
325
+
326
+ // 大檔案分片上傳(帶進度追蹤)
327
+ const fileId = await grid.uploadLargeFile(largeFile, {
328
+ filename: 'movie.mp4',
329
+ chunkSizeBytes: 255 * 1024 // 255 KB
330
+ }, (progress) => {
331
+ console.log(`進度: ${progress.percentage}%`)
332
+ console.log(`已上傳: ${progress.bytesWritten} / ${progress.totalBytes}`)
333
+ })
334
+
335
+ // 取得檔案中繼資料
336
+ const fileInfo = await grid.findById(fileId)
337
+ console.log(fileInfo.filename, fileInfo.length, fileInfo.uploadDate)
338
+
339
+ // 刪除檔案
340
+ await grid.delete(fileId)
195
341
  ```
196
342
 
197
343
  #### Schema Validation
@@ -227,6 +373,77 @@ const health = await Mongo.connection().getHealthStatus()
227
373
  console.log(health.latencyMs) // e.g. 15
228
374
  ```
229
375
 
376
+ ## Performance Optimization
377
+
378
+ ### Indexing
379
+
380
+ ```typescript
381
+ // Create indexes for frequently queried fields
382
+ await Mongo.collection('users').createIndex({ email: 1 }, { unique: true })
383
+ await Mongo.collection('users').createIndex({ status: 1, createdAt: -1 })
384
+ ```
385
+
386
+ ### Query Optimization
387
+
388
+ ```typescript
389
+ // Use projection to reduce data transfer
390
+ const users = await Mongo.collection('users')
391
+ .select('name', 'email') // Only fetch needed fields
392
+ .where('status', 'active')
393
+ .get()
394
+
395
+ // Use limit for large result sets
396
+ const recentPosts = await Mongo.collection('posts')
397
+ .orderBy('createdAt', 'desc')
398
+ .limit(20) // Prevent fetching too much data
399
+ .get()
400
+ ```
401
+
402
+ ### Connection Pool
403
+
404
+ ```typescript
405
+ Mongo.configure({
406
+ default: 'main',
407
+ connections: {
408
+ main: {
409
+ uri: 'mongodb://localhost:27017',
410
+ database: 'myapp',
411
+ maxPoolSize: 50, // Adjust based on load
412
+ minPoolSize: 10, // Keep minimum connections
413
+ maxIdleTimeMS: 30000 // Idle connection timeout
414
+ }
415
+ }
416
+ })
417
+ ```
418
+
419
+ ### Batch Operations
420
+
421
+ ```typescript
422
+ // Use bulkWrite to reduce round trips
423
+ await Mongo.collection('logs').bulkWrite([
424
+ { insertOne: { document: { event: 'login', userId: 1 } } },
425
+ { updateOne: { filter: { _id: 2 }, update: { $set: { status: 'active' } } } },
426
+ { deleteOne: { filter: { _id: 3 } } }
427
+ ])
428
+ ```
429
+
430
+ ### Monitoring
431
+
432
+ ```typescript
433
+ import { MongoPoolMonitor } from '@gravito/dark-matter'
434
+
435
+ const monitor = new MongoPoolMonitor(Mongo.connection())
436
+ const metrics = monitor.getMetrics()
437
+
438
+ console.log('Pool status:', {
439
+ totalConnections: metrics.totalConnections,
440
+ availableConnections: metrics.availableConnections,
441
+ waitQueueSize: metrics.waitQueueSize
442
+ })
443
+ ```
444
+
445
+ 詳細的效能調優指南請參考 [docs/performance-analysis.md](./docs/performance-analysis.md)
446
+
230
447
  ## Roadmap
231
448
 
232
449
  - [x] Connection retry & health check
@@ -234,6 +451,9 @@ console.log(health.latencyMs) // e.g. 15
234
451
  - [x] Schema validation
235
452
  - [x] Change streams
236
453
  - [x] GridFS support
454
+ - [x] Soft deletes
455
+ - [x] Schema Builder API
456
+ - [x] GridFS streaming & progress tracking
237
457
 
238
458
  ## License
239
459