From e7b16fcc4f582dd82f84f5ff2b2605d64dd184c5 Mon Sep 17 00:00:00 2001 From: cab-mikee Date: Tue, 31 Dec 2024 02:41:45 +0800 Subject: [PATCH] docs: more api docs --- docs/api/dd.md | 296 ++++++++++++++++++++++++++++ docs/api/debug.md | 311 +++++++++++++++++++++++++++++ docs/api/dump.md | 296 ++++++++++++++++++++++++++++ docs/api/fromStream.md | 375 +++++++++++++++++++++++++++++++++++ docs/api/fuzzyMatch.md | 404 ++++++++++++++++++++++++++++++++++++++ docs/api/metrics.md | 311 +++++++++++++++++++++++++++++ docs/api/movingAverage.md | 322 ++++++++++++++++++++++++++++++ docs/api/profile.md | 391 ++++++++++++++++++++++++++++++++++++ docs/api/stream.md | 359 +++++++++++++++++++++++++++++++++ docs/api/timeSeries.md | 344 ++++++++++++++++++++++++++++++++ docs/api/validate.md | 392 ++++++++++++++++++++++++++++++++++++ docs/api/validateSync.md | 361 ++++++++++++++++++++++++++++++++++ 12 files changed, 4162 insertions(+) create mode 100644 docs/api/dd.md create mode 100644 docs/api/debug.md create mode 100644 docs/api/dump.md create mode 100644 docs/api/fromStream.md create mode 100644 docs/api/fuzzyMatch.md create mode 100644 docs/api/metrics.md create mode 100644 docs/api/movingAverage.md create mode 100644 docs/api/profile.md create mode 100644 docs/api/stream.md create mode 100644 docs/api/timeSeries.md create mode 100644 docs/api/validate.md create mode 100644 docs/api/validateSync.md diff --git a/docs/api/dd.md b/docs/api/dd.md new file mode 100644 index 0000000..9087ccf --- /dev/null +++ b/docs/api/dd.md @@ -0,0 +1,296 @@ +# dd Method ("Dump and Die") + +The `dd()` method dumps the contents of the collection to the console and immediately terminates script execution. This is particularly useful during development for inspecting collection state at critical points and halting execution for debugging. + +## Basic Syntax + +```typescript +collect(items).dd(): never +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Simple dump and die +const numbers = collect([1, 2, 3, 4]) +numbers.dd() // Logs: [1, 2, 3, 4] and exits + +// Inspect transformation result +collect([1, 2, 3]) + .map(n => n * 2) + .dd() // Logs transformed collection and exits +``` + +### Working with Objects + +```typescript +interface Product { + id: string + name: string + price: number +} + +const products = collect([ + { id: '1', name: 'Widget', price: 100 }, + { id: '2', name: 'Gadget', price: 200 } +]) + +// Debug critical point +products + .filter(p => p.price > 150) + .dd() // Dumps filtered products and exits +``` + +### Real-world Examples + +#### Order Validation System + +```typescript +interface Order { + id: string + items: Array<{ productId: string; quantity: number }> + total: number + status: string +} + +class OrderValidator { + validateOrders(orders: Collection): void { + // Inspect initial state + if (orders.isEmpty()) { + collect({ error: 'No orders to process' }).dd() + } + + // Check for invalid totals + const suspiciousOrders = orders.filter(order => { + const calculatedTotal = this.calculateTotal(order) + return Math.abs(calculatedTotal - order.total) > 0.01 + }) + + if (suspiciousOrders.isNotEmpty()) { + collect({ + error: 'Invalid order totals detected', + orders: suspiciousOrders.toArray() + }).dd() + } + + // Process continues if no issues found... + } + + private calculateTotal(order: Order): number { + // Total calculation logic + return 0 + } +} +``` + +#### Inventory Debugger + +```typescript +interface InventoryAdjustment { + sku: string + quantityChange: number + reason: string + timestamp: Date +} + +class InventoryDebugger { + debugAdjustments( + adjustments: Collection, + threshold: number + ): void { + // Debug large adjustments + const largeAdjustments = adjustments + .filter(adj => Math.abs(adj.quantityChange) > threshold) + + if (largeAdjustments.isNotEmpty()) { + collect({ + warning: 'Large inventory adjustments detected', + timestamp: new Date(), + adjustments: largeAdjustments + .map(adj => ({ + sku: adj.sku, + change: adj.quantityChange, + reason: adj.reason + })) + .toArray() + }).dd() + } + + // Additional processing would be here... + } +} +``` + +### Advanced Usage + +#### Transaction Validator + +```typescript +interface Transaction { + id: string + amount: number + type: 'credit' | 'debit' + metadata: Record +} + +class TransactionValidator { + validateBatch( + transactions: Collection, + options: { + maxAmount: number + suspiciousPatterns: RegExp[] + } + ): void { + // Debug high-value transactions + const highValue = transactions + .filter(t => t.amount > options.maxAmount) + + if (highValue.isNotEmpty()) { + collect({ + alert: 'High-value transactions require review', + timestamp: new Date(), + transactions: highValue.toArray() + }).dd() + } + + // Debug suspicious patterns + const suspicious = transactions.filter(t => + options.suspiciousPatterns.some(pattern => + pattern.test(JSON.stringify(t.metadata)) + ) + ) + + if (suspicious.isNotEmpty()) { + collect({ + alert: 'Suspicious transaction patterns detected', + details: suspicious.map(t => ({ + id: t.id, + flags: options.suspiciousPatterns + .filter(p => p.test(JSON.stringify(t.metadata))) + .map(p => p.source) + })) + }).dd() + } + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: string +} + +const items = collect([ + { id: 1, value: 'A' }, + { id: 2, value: 'B' } +]) + +// Type-safe debugging +items + .map(item => ({ + ...item, + value: item.value.toLowerCase() + })) + .dd() + +// Function never returns due to exit +const result = items.dd() // TypeScript knows this is unreachable +``` + +## Return Value + +- Return type is `never` (function doesn't return) +- Dumps collection contents to console +- Immediately exits process with code 1 +- Stops all further execution +- Useful for debugging critical points +- Should not be used in production + +## Common Use Cases + +### 1. Development Debugging + +- Critical point inspection +- State verification +- Flow interruption +- Data validation +- Process inspection + +### 2. Data Validation + +- Format checking +- Content verification +- Structure validation +- Type confirmation +- Rule enforcement + +### 3. Error Investigation + +- State inspection +- Data examination +- Flow verification +- Issue diagnosis +- Bug tracking + +### 4. Process Verification + +- State checking +- Transform validation +- Flow inspection +- Logic verification +- Result confirmation + +### 5. Security Checks + +- Input validation +- Pattern detection +- Anomaly inspection +- Rule verification +- Access validation + +### 6. Data Processing + +- Format validation +- Content verification +- Transform inspection +- Rule checking +- Result validation + +### 7. Flow Control + +- Critical checks +- State verification +- Process validation +- Logic inspection +- Flow control + +### 8. Testing Support + +- State inspection +- Result verification +- Process validation +- Error checking +- Flow testing + +### 9. Performance Issues + +- State examination +- Process inspection +- Flow analysis +- Bottleneck detection +- Resource usage + +### 10. Quality Assurance + +- Data validation +- Process verification +- Rule enforcement +- Content checking +- Type confirmation diff --git a/docs/api/debug.md b/docs/api/debug.md new file mode 100644 index 0000000..e096316 --- /dev/null +++ b/docs/api/debug.md @@ -0,0 +1,311 @@ +# debug Method + +The `debug()` method logs the current state of the collection and memory usage to the console. It returns the original collection, allowing for method chaining. This is particularly useful during development and troubleshooting. + +## Basic Syntax + +```typescript +collect(items).debug(): Collection +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Simple debugging +const numbers = collect([1, 2, 3, 4]) + .debug() // Logs current state + .map(n => n * 2) + .debug() // Logs state after transformation + .filter(n => n > 4) + .debug() // Logs final state + +// Debug during transformations +collect([1, 2, 3]) + .debug() + .map(n => { + console.log(`Processing: ${n}`) + return n * 2 + }) + .debug() +``` + +### Working with Objects + +```typescript +interface Product { + id: string + name: string + price: number +} + +const products = collect([ + { id: '1', name: 'Widget', price: 100 }, + { id: '2', name: 'Gadget', price: 200 } +]) + +// Debug product processing +products + .debug() // Initial state + .map(product => ({ + ...product, + price: product.price * 1.1 + })) + .debug() // After price increase + .filter(product => product.price < 250) + .debug() // After filtering +``` + +### Real-world Examples + +#### Order Processing Pipeline + +```typescript +interface Order { + id: string + items: Array<{ id: string; quantity: number }> + total: number + status: 'pending' | 'processing' | 'completed' +} + +class OrderProcessor { + processOrders(orders: Collection): Collection { + return orders + .debug() // Log initial orders + .filter(order => order.status === 'pending') + .debug() // Log filtered pending orders + .map(order => this.calculateTotals(order)) + .debug() // Log orders with calculated totals + .map(order => this.validateInventory(order)) + .debug() // Log after inventory validation + .map(order => ({ ...order, status: 'processing' })) + .debug() // Log final processed orders + + } + + private calculateTotals(order: Order): Order { + // Calculation logic + return order + } + + private validateInventory(order: Order): Order { + // Validation logic + return order + } +} +``` + +#### Price Update System + +```typescript +interface PriceUpdate { + productId: string + oldPrice: number + newPrice: number + reason: string +} + +class PriceUpdateManager { + applyPriceUpdates( + products: Collection, + updates: PriceUpdate[] + ): Collection { + return products + .debug() // Initial product state + .map(product => { + const update = updates.find(u => u.productId === product.id) + if (!update) return product + + console.log(`Updating price for product ${product.id}`) + console.log(`Old price: ${product.price}, New price: ${update.newPrice}`) + + return { + ...product, + price: update.newPrice + } + }) + .debug() // After price updates + .tap(updated => { + const changedCount = updated.filter(p => + updates.some(u => u.productId === p.id) + ).count() + console.log(`Updated ${changedCount} products`) + }) + .debug() // Final state + } +} +``` + +### Advanced Usage + +#### Performance Monitoring + +```typescript +interface PerformanceMetrics { + operationName: string + itemCount: number + memoryUsage: { + before: number + after: number + difference: number + } + timeElapsed: number +} + +class PerformanceMonitor { + monitorOperation( + collection: Collection, + operation: (items: Collection) => Collection + ): { + result: Collection + metrics: PerformanceMetrics + } { + const startTime = performance.now() + const initialMemory = process.memoryUsage().heapUsed + + const result = collection + .debug() // Pre-operation state + .pipe(operation) + .debug() // Post-operation state + + const endMemory = process.memoryUsage().heapUsed + const timeElapsed = performance.now() - startTime + + const metrics: PerformanceMetrics = { + operationName: operation.name, + itemCount: result.count(), + memoryUsage: { + before: initialMemory, + after: endMemory, + difference: endMemory - initialMemory + }, + timeElapsed + } + + console.log('Performance Metrics:', metrics) + return { result, metrics } + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: string +} + +const items = collect([ + { id: 1, value: 'A' }, + { id: 2, value: 'B' } +]) + +// Type-safe debugging +items + .debug() // Logs initial state + .map(item => ({ + ...item, + value: item.value.toLowerCase() + })) + .debug() // Logs transformed state + +// TypeScript maintains type information through debug calls +const result: Collection = items.debug() +``` + +## Return Value + +- Returns the original collection unmodified +- Logs to console: + - Collection items + - Collection length + - Memory usage statistics +- Maintains type safety with TypeScript +- Can be chained with other collection methods +- Does not affect collection state + +## Common Use Cases + +### 1. Development + +- State inspection +- Transform validation +- Flow tracking +- Error detection +- Type verification + +### 2. Performance Monitoring + +- Memory usage +- Operation impact +- State changes +- Resource tracking +- Bottleneck detection + +### 3. Data Processing + +- Transform validation +- Filter inspection +- Map verification +- Reduce tracking +- Sort checking + +### 4. Pipeline Debugging + +- Step validation +- Flow tracking +- State inspection +- Error detection +- Process monitoring + +### 5. Memory Analysis + +- Usage patterns +- Leak detection +- Allocation tracking +- Garbage collection +- Resource management + +### 6. Operation Validation + +- Transform checking +- Filter verification +- Sort inspection +- Group validation +- Merge checking + +### 7. State Tracking + +- Process flow +- Data changes +- Operation sequence +- State transitions +- Value updates + +### 8. Error Detection + +- Value inspection +- Type checking +- Null verification +- Undefined tracking +- Exception monitoring + +### 9. Testing Support + +- State verification +- Process validation +- Value checking +- Flow inspection +- Output validation + +### 10. Optimization + +- Performance tracking +- Resource usage +- Operation impact +- Memory patterns +- Processing efficiency diff --git a/docs/api/dump.md b/docs/api/dump.md new file mode 100644 index 0000000..055f909 --- /dev/null +++ b/docs/api/dump.md @@ -0,0 +1,296 @@ +# dump Method + +The `dump()` method outputs the contents of the collection to the console. Unlike `debug()`, it only logs the collection items without additional metadata and doesn't return the collection. + +## Basic Syntax + +```typescript +collect(items).dump(): void +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Simple dump +const numbers = collect([1, 2, 3, 4]) +numbers.dump() // Logs: [1, 2, 3, 4] + +// Dump after transformation +collect([1, 2, 3]) + .map(n => n * 2) + .dump() // Logs: [2, 4, 6] +``` + +### Working with Objects + +```typescript +interface Product { + id: string + name: string + price: number +} + +const products = collect([ + { id: '1', name: 'Widget', price: 100 }, + { id: '2', name: 'Gadget', price: 200 } +]) + +// Inspect products +products.dump() +// Logs: +// [ +// { id: '1', name: 'Widget', price: 100 }, +// { id: '2', name: 'Gadget', price: 200 } +// ] +``` + +### Real-world Examples + +#### Order Processing Inspection + +```typescript +interface Order { + id: string + items: Array<{ productId: string; quantity: number }> + total: number + status: 'pending' | 'processing' | 'completed' +} + +class OrderInspector { + inspectOrderProcessing(orders: Collection): void { + // Inspect initial orders + console.log('Initial Orders:') + orders.dump() + + // Filter pending orders + console.log('\nPending Orders:') + orders + .filter(order => order.status === 'pending') + .dump() + + // Check high-value orders + console.log('\nHigh Value Orders:') + orders + .filter(order => order.total > 1000) + .dump() + + // Inspect items count + console.log('\nOrders by Item Count:') + orders + .map(order => ({ + id: order.id, + itemCount: order.items.length + })) + .dump() + } +} +``` + +#### Inventory Checker + +```typescript +interface StockItem { + sku: string + quantity: number + location: string + reorderPoint: number +} + +class StockChecker { + checkInventoryLevels(inventory: Collection): void { + // Check low stock items + console.log('Low Stock Items:') + inventory + .filter(item => item.quantity <= item.reorderPoint) + .dump() + + // Check by location + console.log('\nWarehouse A Stock:') + inventory + .where('location', 'Warehouse A') + .dump() + + // Check critical items + console.log('\nOut of Stock Items:') + inventory + .filter(item => item.quantity === 0) + .dump() + + // Check reorder quantities + console.log('\nReorder Quantities:') + inventory + .map(item => ({ + sku: item.sku, + reorderQuantity: Math.max(0, item.reorderPoint - item.quantity) + })) + .filter(item => item.reorderQuantity > 0) + .dump() + } +} +``` + +### Advanced Usage + +#### Price Update Verification + +```typescript +interface PriceUpdate { + productId: string + oldPrice: number + newPrice: number + effective: Date +} + +class PriceUpdateVerifier { + verifyUpdates(updates: Collection): void { + // Check significant price increases + console.log('Significant Price Increases:') + updates + .filter(update => + (update.newPrice - update.oldPrice) / update.oldPrice > 0.2 + ) + .dump() + + // Check price decreases + console.log('\nPrice Decreases:') + updates + .filter(update => update.newPrice < update.oldPrice) + .dump() + + // Check updates by date + console.log('\nUpcoming Updates:') + updates + .filter(update => update.effective > new Date()) + .dump() + + // Check average change + console.log('\nPrice Change Summary:') + updates + .map(update => ({ + productId: update.productId, + changePercent: ((update.newPrice - update.oldPrice) / update.oldPrice) * 100 + })) + .dump() + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: string +} + +const items = collect([ + { id: 1, value: 'A' }, + { id: 2, value: 'B' } +]) + +// Simple dump of typed collection +items.dump() + +// Dump after transformation +items + .map(item => ({ + ...item, + value: item.value.toLowerCase() + })) + .dump() +``` + +## Return Value + +- Returns void (no return value) +- Logs collection contents to console +- Does not modify the collection +- Can be used in method chains +- Shows raw data without formatting +- Useful for quick inspections + +## Common Use Cases + +### 1. Development + +- Quick inspection +- Value verification +- State checking +- Data validation +- Type confirmation + +### 2. Debugging + +- Value checking +- Transform verification +- Filter validation +- Process inspection +- Error investigation + +### 3. Data Inspection + +- Content review +- Format checking +- Structure validation +- Value verification +- Type confirmation + +### 4. Process Validation + +- State inspection +- Flow checking +- Transform verification +- Filter validation +- Result confirmation + +### 5. Testing Support + +- Value verification +- Output validation +- State inspection +- Result checking +- Error detection + +### 6. Data Monitoring + +- Value tracking +- Change inspection +- Update verification +- State monitoring +- Result validation + +### 7. Quality Control + +- Data validation +- Format checking +- Structure verification +- Content inspection +- Type confirmation + +### 8. Development Flow + +- Quick checks +- Process verification +- State inspection +- Result validation +- Error detection + +### 9. Troubleshooting + +- Value inspection +- State checking +- Process verification +- Error investigation +- Result validation + +### 10. Data Verification + +- Content checking +- Structure validation +- Format inspection +- Value verification +- Type confirmation diff --git a/docs/api/fromStream.md b/docs/api/fromStream.md new file mode 100644 index 0000000..39efa9b --- /dev/null +++ b/docs/api/fromStream.md @@ -0,0 +1,375 @@ +# fromStream Method + +The `fromStream()` method creates a collection from a ReadableStream. This method is useful for converting streaming data into a collection that can be manipulated using collection operations. + +## Basic Syntax + +```typescript +collect(items).fromStream(stream: ReadableStream): Promise> +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Create collection from number stream +const numberStream = new ReadableStream({ + start(controller) { + [1, 2, 3, 4, 5].forEach(n => controller.enqueue(n)) + controller.close() + } +}) + +const numbers = await collect([]).fromStream(numberStream) +console.log(numbers.all()) // [1, 2, 3, 4, 5] + +// Create from string stream +const textStream = new ReadableStream({ + start(controller) { + ['hello', 'world'].forEach(s => controller.enqueue(s)) + controller.close() + } +}) + +const words = await collect([]).fromStream(textStream) +``` + +### Working with Objects + +```typescript +interface Product { + id: string + name: string + price: number +} + +// Create product stream +const productStream = new ReadableStream({ + start(controller) { + const products = [ + { id: '1', name: 'Widget', price: 100 }, + { id: '2', name: 'Gadget', price: 200 } + ] + products.forEach(p => controller.enqueue(p)) + controller.close() + } +}) + +// Convert to collection +const products = await collect([]).fromStream(productStream) +``` + +### Real-world Examples + +#### Data Import System + +```typescript +interface ImportRecord { + line: number + data: Record + errors: string[] +} + +class DataImporter { + async importFromStream( + dataStream: ReadableStream + ): Promise<{ + imported: Collection + success: number + failed: number + errors: Map + }> { + const records = await collect([]) + .fromStream(dataStream) + + const validRecords = records.filter(record => record.errors.length === 0) + const invalidRecords = records.filter(record => record.errors.length > 0) + + const errors = new Map() + invalidRecords.each(record => { + errors.set(record.line, record.errors) + }) + + return { + imported: validRecords, + success: validRecords.count(), + failed: invalidRecords.count(), + errors + } + } + + async processImport( + dataStream: ReadableStream + ): Promise { + const { imported, failed, errors } = await this.importFromStream(dataStream) + + if (failed > 0) { + console.error(`Failed to import ${failed} records:`) + errors.forEach((errs, line) => { + console.error(`Line ${line}:`, errs) + }) + } + + await this.saveImportedRecords(imported) + } + + private async saveImportedRecords( + records: Collection + ): Promise { + // Save records logic + } +} +``` + +#### File Upload Processor + +```typescript +interface FileChunk { + index: number + data: Uint8Array + filename: string +} + +class FileProcessor { + async processUploadStream( + chunkStream: ReadableStream + ): Promise<{ + processedFiles: string[] + totalSize: number + errors: Array<{ file: string; error: string }> + }> { + const chunks = await collect([]) + .fromStream(chunkStream) + + const fileGroups = chunks + .sortBy('index') + .groupBy('filename') + + const processedFiles: string[] = [] + const errors: Array<{ file: string; error: string }> = [] + let totalSize = 0 + + for (const [filename, fileChunks] of fileGroups.entries()) { + try { + const combinedData = this.combineChunks(fileChunks) + await this.processFile(filename, combinedData) + processedFiles.push(filename) + totalSize += combinedData.length + } catch (error) { + errors.push({ + file: filename, + error: error instanceof Error ? error.message : 'Unknown error' + }) + } + } + + return { + processedFiles, + totalSize, + errors + } + } + + private combineChunks(chunks: Collection): Uint8Array { + const totalSize = chunks.sum(chunk => chunk.data.length) + const result = new Uint8Array(totalSize) + let offset = 0 + + chunks.each(chunk => { + result.set(chunk.data, offset) + offset += chunk.data.length + }) + + return result + } + + private async processFile( + filename: string, + data: Uint8Array + ): Promise { + // File processing logic + } +} +``` + +### Advanced Usage + +#### Real-time Data Processor + +```typescript +interface DataPoint { + timestamp: Date + value: number + source: string +} + +class RealTimeProcessor { + async processDataStream( + dataStream: ReadableStream, + windowSize: number = 100 + ): Promise<{ + summary: Map + alerts: Array<{ + source: string + timestamp: Date + reason: string + }> + }> { + const dataPoints = await collect([]) + .fromStream(dataStream) + + const bySource = dataPoints.groupBy('source') + const summary = new Map() + const alerts: Array<{ + source: string + timestamp: Date + reason: string + }> = [] + + bySource.forEach((points, source) => { + const values = points.pluck('value') + const average = values.avg() + const max = values.max() ?? 0 + const min = values.min() ?? 0 + + summary.set(source, { average, max, min }) + + // Check for anomalies + points.each(point => { + if (point.value > average * 2) { + alerts.push({ + source, + timestamp: point.timestamp, + reason: 'Value exceeds 2x average' + }) + } + }) + }) + + return { summary, alerts } + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: string +} + +// Create typed stream +const stream = new ReadableStream({ + start(controller) { + controller.enqueue({ id: 1, value: 'A' }) + controller.enqueue({ id: 2, value: 'B' }) + controller.close() + } +}) + +// Type-safe collection creation +const items = await collect([]) + .fromStream(stream) + +// TypeScript knows the type +const firstValue: string = items.first()?.value +``` + +## Return Value + +- Returns a Promise that resolves to a Collection +- Collection contains all stream items +- Maintains item order from stream +- Preserves item types +- Supports all collection methods +- Memory efficient processing + +## Common Use Cases + +### 1. Data Import + +- File uploads +- Bulk imports +- Data migration +- Content transfer +- System integration + +### 2. Real-time Processing + +- Event streams +- Sensor data +- Log processing +- Metrics collection +- System monitoring + +### 3. File Processing + +- Upload handling +- Chunk processing +- Document parsing +- Media processing +- Content streaming + +### 4. Data Transformation + +- Format conversion +- Data cleaning +- Content processing +- Structure mapping +- Type conversion + +### 5. Batch Operations + +- Record processing +- Bulk updates +- Data validation +- Content moderation +- System updates + +### 6. Integration + +- API consumption +- Service integration +- Data synchronization +- Platform connection +- System bridging + +### 7. Analytics + +- Data collection +- Metric processing +- Log analysis +- Event tracking +- Performance monitoring + +### 8. Content Management + +- Content imports +- Media processing +- Document handling +- Asset management +- Resource processing + +### 9. System Migration + +- Data transfer +- Content migration +- System updates +- Platform moves +- Service transitions + +### 10. Performance Optimization + +- Memory efficiency +- Resource management +- Load handling +- Process scaling +- Stream processing diff --git a/docs/api/fuzzyMatch.md b/docs/api/fuzzyMatch.md new file mode 100644 index 0000000..b663d11 --- /dev/null +++ b/docs/api/fuzzyMatch.md @@ -0,0 +1,404 @@ +# fuzzyMatch Method + +The `fuzzyMatch()` method filters items based on fuzzy string matching against a specified key's value. This is particularly useful for implementing search functionality that tolerates typos and approximate matches. + +## Basic Syntax + +```typescript +collect(items).fuzzyMatch( + key: keyof T, + pattern: string, + threshold: number = 0.7 +): Collection +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Simple fuzzy matching +const items = collect([ + { name: 'iPhone 12 Pro' }, + { name: 'iPhone 13 Pro' }, + { name: 'Samsung Galaxy' } +]) + +// Find matching items +const matches = items.fuzzyMatch('name', 'iphone pro', 0.7) +console.log(matches.all()) +// [ +// { name: 'iPhone 12 Pro' }, +// { name: 'iPhone 13 Pro' } +// ] +``` + +### Working with Objects + +```typescript +interface Product { + id: string + name: string + description: string + category: string +} + +const products = collect([ + { + id: '1', + name: 'Wireless Headphones', + description: 'Bluetooth enabled headphones', + category: 'Electronics' + }, + { + id: '2', + name: 'Wireless Earbuds', + description: 'True wireless earbuds', + category: 'Electronics' + } +]) + +// Search products +const searchResults = products.fuzzyMatch('name', 'wireless head', 0.6) +``` + +### Real-world Examples + +#### Product Search System + +```typescript +interface SearchableProduct { + id: string + name: string + brand: string + category: string + description: string + tags: string[] +} + +class ProductSearcher { + constructor( + private products: Collection, + private thresholds: { + name: number + brand: number + description: number + } = { + name: 0.7, + brand: 0.8, + description: 0.6 + } + ) {} + + search(query: string): Collection { + // Search across multiple fields with different thresholds + const nameMatches = this.products.fuzzyMatch('name', query, this.thresholds.name) + const brandMatches = this.products.fuzzyMatch('brand', query, this.thresholds.brand) + const descMatches = this.products.fuzzyMatch('description', query, this.thresholds.description) + + // Combine results without duplicates + return nameMatches + .union(brandMatches.toArray()) + .union(descMatches.toArray()) + .sortBy('name') + } + + findSimilarProducts(product: SearchableProduct): Collection { + // Find products with similar names or descriptions + const similarNames = this.products + .filter(p => p.id !== product.id) + .fuzzyMatch('name', product.name, 0.6) + + const similarDesc = this.products + .filter(p => p.id !== product.id) + .fuzzyMatch('description', product.description, 0.5) + + return similarNames + .union(similarDesc.toArray()) + .sortBy('name') + } +} +``` + +#### Customer Support Lookup + +```typescript +interface CustomerQuery { + id: string + subject: string + description: string + status: 'open' | 'closed' + category: string +} + +class SupportQueryMatcher { + constructor(private queries: Collection) {} + + findSimilarQueries( + newQuery: CustomerQuery, + options: { + subjectThreshold?: number + descriptionThreshold?: number + includeResolved?: boolean + } = {} + ): { + matches: Collection + categories: string[] + } { + const { + subjectThreshold = 0.7, + descriptionThreshold = 0.6, + includeResolved = false + } = options + + let activeQueries = this.queries + if (!includeResolved) { + activeQueries = this.queries.where('status', 'open') + } + + // Find queries with similar subjects + const subjectMatches = activeQueries + .fuzzyMatch('subject', newQuery.subject, subjectThreshold) + + // Find queries with similar descriptions + const descriptionMatches = activeQueries + .fuzzyMatch('description', newQuery.description, descriptionThreshold) + + // Combine matches + const allMatches = subjectMatches + .union(descriptionMatches.toArray()) + .sortByDesc('id') + + // Get suggested categories based on matches + const suggestedCategories = allMatches + .pluck('category') + .unique() + .toArray() + + return { + matches: allMatches, + categories: suggestedCategories + } + } + + findKnowledgeBaseArticles(query: string): Collection { + return this.queries + .where('status', 'closed') + .fuzzyMatch('subject', query, 0.6) + .sortByDesc('id') + .take(5) + } +} +``` + +### Advanced Usage + +#### Address Matcher + +```typescript +interface Address { + id: string + street: string + city: string + state: string + postalCode: string +} + +class AddressMatcher { + constructor(private addresses: Collection
) {} + + findDuplicates( + threshold: number = 0.8 + ): Array<{ + group: Address[] + similarity: number + }> { + const duplicateGroups: Array<{ + group: Address[] + similarity: number + }> = [] + + this.addresses.each(address => { + // Find similar addresses + const matches = this.addresses + .filter(a => a.id !== address.id) + .fuzzyMatch('street', address.street, threshold) + .filter(a => this.isSameArea(address, a)) + + if (matches.isNotEmpty()) { + duplicateGroups.push({ + group: [address, ...matches.toArray()], + similarity: threshold + }) + } + }) + + return this.consolidateGroups(duplicateGroups) + } + + findAddress(searchText: string): Collection
{ + // Search across all address fields + const streetMatches = this.addresses + .fuzzyMatch('street', searchText, 0.7) + + const cityMatches = this.addresses + .fuzzyMatch('city', searchText, 0.8) + + const stateMatches = this.addresses + .fuzzyMatch('state', searchText, 0.9) + + return streetMatches + .union(cityMatches.toArray()) + .union(stateMatches.toArray()) + .sortBy('street') + } + + private isSameArea(addr1: Address, addr2: Address): boolean { + return addr1.city === addr2.city && + addr1.state === addr2.state && + addr1.postalCode === addr2.postalCode + } + + private consolidateGroups( + groups: Array<{ + group: Address[] + similarity: number + }> + ): Array<{ + group: Address[] + similarity: number + }> { + // Consolidate overlapping groups + return groups.reduce((acc, curr) => { + const overlapping = acc.find(g => + g.group.some(addr => + curr.group.some(currAddr => currAddr.id === addr.id) + ) + ) + + if (overlapping) { + overlapping.group = [...new Set([...overlapping.group, ...curr.group])] + overlapping.similarity = Math.min(overlapping.similarity, curr.similarity) + } else { + acc.push(curr) + } + + return acc + }, [] as Array<{ group: Address[]; similarity: number }>) + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + name: string + description: string +} + +const items = collect([ + { id: 1, name: 'Test Item', description: 'A test item' }, + { id: 2, name: 'Another Item', description: 'Another test' } +]) + +// Type-safe fuzzy matching +const matches = items.fuzzyMatch('name', 'test', 0.7) + +// TypeScript enforces valid keys +// items.fuzzyMatch('invalid', 'test') // ✗ TypeScript error +``` + +## Return Value + +- Returns a new Collection of matching items +- Original collection remains unchanged +- Maintains type safety with TypeScript +- Can be chained with other methods +- Results ordered by match quality +- Empty collection if no matches + +## Common Use Cases + +### 1. Product Search + +- Name matching +- Description search +- Category matching +- Brand lookup +- Tag matching + +### 2. Customer Support + +- Query matching +- Knowledge base search +- Ticket routing +- FAQ matching +- Solution lookup + +### 3. Address Validation + +- Duplicate detection +- Address matching +- Location search +- Area lookup +- Postal matching + +### 4. Content Search + +- Title matching +- Description search +- Tag matching +- Category lookup +- Keyword search + +### 5. User Lookup + +- Name search +- Email matching +- Username lookup +- Profile search +- Contact matching + +### 6. Error Handling + +- Error matching +- Log searching +- Issue lookup +- Problem matching +- Solution finding + +### 7. Data Cleaning + +- Duplicate detection +- Record matching +- Entry validation +- Data normalization +- Format matching + +### 8. Navigation + +- Menu search +- Category matching +- Route lookup +- Link matching +- Path finding + +### 9. Autocomplete + +- Suggestion generation +- Term completion +- Query matching +- Search assistance +- Input helping + +### 10. Reference Data + +- Code lookup +- ID matching +- Reference search +- Key finding +- Value matching diff --git a/docs/api/metrics.md b/docs/api/metrics.md new file mode 100644 index 0000000..44058be --- /dev/null +++ b/docs/api/metrics.md @@ -0,0 +1,311 @@ +# metrics Method + +The `metrics()` method returns a comprehensive set of metrics about the collection, including count, null values, unique values, and memory usage. This is particularly useful for data quality assessment and performance monitoring. + +## Basic Syntax + +```typescript +collect(items).metrics(): CollectionMetrics +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Simple metrics collection +const items = collect([1, 2, 2, null, 3]) +const metrics = items.metrics() +console.log(metrics) +// { +// count: 5, +// nullCount: 1, +// uniqueCount: 4, +// heapUsed: 1024, // Example value +// heapTotal: 2048 // Example value +// } +``` + +### Working with Objects + +```typescript +interface Product { + id: string + name: string | null + price: number | null + category: string +} + +const products = collect([ + { id: '1', name: 'Widget', price: 100, category: 'A' }, + { id: '2', name: null, price: null, category: 'B' } +]) + +const productMetrics = products.metrics() +// Includes field counts and null distribution +``` + +### Real-world Examples + +#### Data Quality Monitor + +```typescript +interface DataQualityReport { + collectionName: string + timestamp: Date + metrics: CollectionMetrics + recommendations: string[] +} + +class DataQualityMonitor { + generateReport( + data: Collection, + collectionName: string + ): DataQualityReport { + const metrics = data.metrics() + + return { + collectionName, + timestamp: new Date(), + metrics, + recommendations: this.generateRecommendations(metrics) + } + } + + generateDailyReport( + collections: Map> + ): Map { + const reports = new Map() + + collections.forEach((collection, name) => { + reports.set(name, this.generateReport(collection, name)) + }) + + return reports + } + + private generateRecommendations( + metrics: CollectionMetrics + ): string[] { + const recommendations: string[] = [] + + if (metrics.nullCount > (metrics.count * 0.1)) { + recommendations.push('High number of null values detected') + } + + if (metrics.uniqueCount === metrics.count) { + recommendations.push('All values are unique - potential ID field') + } + + // Memory usage recommendations + const memoryUsageRatio = metrics.heapUsed / metrics.heapTotal + if (memoryUsageRatio > 0.8) { + recommendations.push('High memory usage - consider optimization') + } + + return recommendations + } +} +``` + +#### Performance Monitor + +```typescript +interface PerformanceMetrics { + timestamp: Date + metrics: CollectionMetrics + performance: { + memoryEfficiency: number + dataQuality: number + uniquenessRatio: number + } +} + +class PerformanceMonitor { + constructor( + private thresholds: { + memoryUsage: number + nullRatio: number + uniquenessRatio: number + } = { + memoryUsage: 0.8, + nullRatio: 0.1, + uniquenessRatio: 0.5 + } + ) {} + + analyzePerformance( + collection: Collection + ): PerformanceMetrics { + const metrics = collection.metrics() + + return { + timestamp: new Date(), + metrics, + performance: { + memoryEfficiency: this.calculateMemoryEfficiency(metrics), + dataQuality: this.calculateDataQuality(metrics), + uniquenessRatio: metrics.uniqueCount / metrics.count + } + } + } + + private calculateMemoryEfficiency( + metrics: CollectionMetrics + ): number { + const usageRatio = metrics.heapUsed / metrics.heapTotal + return Math.max(0, 1 - (usageRatio / this.thresholds.memoryUsage)) + } + + private calculateDataQuality( + metrics: CollectionMetrics + ): number { + const nullRatio = metrics.nullCount / metrics.count + return Math.max(0, 1 - (nullRatio / this.thresholds.nullRatio)) + } + + shouldOptimize(metrics: CollectionMetrics): boolean { + return metrics.heapUsed / metrics.heapTotal > this.thresholds.memoryUsage + } + + generateRecommendations(metrics: CollectionMetrics): string[] { + const recommendations: string[] = [] + + // Memory recommendations + if (this.shouldOptimize(metrics)) { + recommendations.push('Consider implementing pagination') + recommendations.push('Review data structure for optimization') + } + + // Data quality recommendations + if (metrics.nullFieldsDistribution) { + metrics.nullFieldsDistribution.forEach((count, field) => { + if (count / metrics.count > this.thresholds.nullRatio) { + recommendations.push(`High null count in field: ${field}`) + } + }) + } + + return recommendations + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: string | null +} + +const items = collect([ + { id: 1, value: 'A' }, + { id: 2, value: null } +]) + +// Type-safe metrics collection +const metrics: CollectionMetrics = items.metrics() + +// Access metrics properties with type safety +const nullCount: number = metrics.nullCount +const uniqueCount: number = metrics.uniqueCount +``` + +## Return Value (CollectionMetrics) + +```typescript +interface CollectionMetrics { + count: number // Total number of items + nullCount: number // Number of null values + uniqueCount: number // Number of unique values + heapUsed: number // Current heap usage + heapTotal: number // Total heap size + fieldCount?: number // Number of fields (for objects) + nullFieldsDistribution?: Map // Null values by field +} +``` + +## Common Use Cases + +### 1. Data Quality + +- Completeness checking +- Null value analysis +- Uniqueness validation +- Field distribution +- Quality scoring + +### 2. Performance + +- Memory monitoring +- Resource usage +- Optimization needs +- Scaling decisions +- Capacity planning + +### 3. Monitoring + +- Health checks +- Usage patterns +- Resource tracking +- System metrics +- Load analysis + +### 4. Reporting + +- Quality reports +- Usage statistics +- Health status +- Performance metrics +- Resource utilization + +### 5. Optimization + +- Memory usage +- Data structure +- Resource allocation +- Performance tuning +- Capacity planning + +### 6. Validation + +- Data integrity +- Quality assurance +- Format checking +- Structure validation +- Completeness verification + +### 7. Analysis + +- Pattern detection +- Usage analysis +- Trend monitoring +- Behavior tracking +- Performance assessment + +### 8. Maintenance + +- Health monitoring +- Resource tracking +- System optimization +- Performance tuning +- Capacity management + +### 9. Debugging + +- Issue diagnosis +- Problem detection +- Error tracking +- Performance bottlenecks +- Resource leaks + +### 10. Planning + +- Resource allocation +- Capacity planning +- Scaling decisions +- Optimization strategy +- Maintenance scheduling diff --git a/docs/api/movingAverage.md b/docs/api/movingAverage.md new file mode 100644 index 0000000..8e927ba --- /dev/null +++ b/docs/api/movingAverage.md @@ -0,0 +1,322 @@ +# movingAverage Method + +The `movingAverage()` method calculates a moving average over a specified window of values. It can be centered or trailing, making it useful for trend analysis and smoothing time series data. + +## Basic Syntax + +```typescript +collect(items).movingAverage({ + window: number, // Size of the moving window + centered?: boolean = false // Whether to center the window +}): Collection +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Simple trailing moving average +const values = collect([1, 2, 3, 4, 5, 6]) +const movingAvg = values.movingAverage({ window: 3 }) +console.log(movingAvg.all()) // [2, 3, 4, 5] + +// Centered moving average +const centeredAvg = values.movingAverage({ + window: 3, + centered: true +}) +console.log(centeredAvg.all()) // [2, 3, 4, 5] +``` + +### Working with Objects + +```typescript +interface DailySales { + date: string + revenue: number + orders: number +} + +const sales = collect([ + { date: '2024-01-01', revenue: 1000, orders: 10 }, + { date: '2024-01-02', revenue: 1200, orders: 12 }, + { date: '2024-01-03', revenue: 800, orders: 8 }, + { date: '2024-01-04', revenue: 1500, orders: 15 }, + { date: '2024-01-05', revenue: 1300, orders: 13 } +]) + +// Calculate 3-day moving average of revenue +const revenueMA = sales + .pluck('revenue') + .movingAverage({ window: 3 }) +``` + +### Real-world Examples + +#### Sales Trend Analyzer + +```typescript +interface SalesMetric { + date: Date + revenue: number + units: number + avgOrderValue: number +} + +class SalesTrendAnalyzer { + constructor(private sales: Collection) {} + + analyzeTrends(window: number = 7): { + revenue: Collection + units: Collection + orderValue: Collection + } { + return { + revenue: this.calculateSmoothedTrend('revenue', window), + units: this.calculateSmoothedTrend('units', window), + orderValue: this.calculateSmoothedTrend('avgOrderValue', window) + } + } + + private calculateSmoothedTrend( + metric: keyof SalesMetric, + window: number + ): Collection { + return this.sales + .pluck(metric) + .movingAverage({ + window, + centered: true + }) + } + + detectAnomalies(threshold: number = 2): { + dates: Date[] + metrics: Array + } { + const anomalies = new Map>() + + // Check each metric for anomalies + const metrics: Array = ['revenue', 'units', 'avgOrderValue'] + metrics.forEach(metric => { + const values = this.sales.pluck(metric) + const ma = values.movingAverage({ window: 7 }) + const stdDev = values.standardDeviation() + + values.each((value, index) => { + const deviation = Math.abs(value - (ma.nth(index) || 0)) + if (deviation > threshold * stdDev.population) { + const date = this.sales.nth(index)?.date + if (date) { + if (!anomalies.has(date)) { + anomalies.set(date, new Set()) + } + anomalies.get(date)?.add(metric) + } + } + }) + }) + + return { + dates: Array.from(anomalies.keys()), + metrics: Array.from( + new Set( + Array.from(anomalies.values()) + .flatMap(set => Array.from(set)) + ) + ) + } + } +} +``` + +#### Demand Forecaster + +```typescript +interface DemandData { + product: string + date: Date + demand: number + price: number +} + +class DemandForecaster { + constructor(private data: Collection) {} + + generateForecast( + options: { + window: number + productId: string + smoothingFactor?: number + } + ): { + trend: Collection + forecast: Collection + confidence: number + } { + const productDemand = this.data + .where('product', options.productId) + .pluck('demand') + + // Calculate smoothed trend + const trend = productDemand.movingAverage({ + window: options.window, + centered: false + }) + + // Calculate forecast using exponential smoothing + const alpha = options.smoothingFactor || 0.2 + const forecast = this.exponentialSmoothing(trend, alpha) + + // Calculate forecast confidence based on error variance + const confidence = this.calculateConfidence(trend, forecast) + + return { trend, forecast, confidence } + } + + private exponentialSmoothing( + values: Collection, + alpha: number + ): Collection { + const result: number[] = [] + let lastForecast = values.first() || 0 + + values.each(value => { + lastForecast = alpha * value + (1 - alpha) * lastForecast + result.push(lastForecast) + }) + + return collect(result) + } + + private calculateConfidence( + actual: Collection, + forecast: Collection + ): number { + const errors = actual.map((value, index) => + Math.abs(value - (forecast.nth(index) || 0)) + ) + + const mape = errors.avg() / actual.avg() * 100 + return Math.max(0, 100 - mape) + } +} +``` + +## Type Safety + +```typescript +interface TypedMetric { + id: number + value: number +} + +const metrics = collect([ + { id: 1, value: 100 }, + { id: 2, value: 200 }, + { id: 3, value: 150 } +]) + +// Type-safe moving average calculation +const values = metrics.pluck('value') +const ma: Collection = values.movingAverage({ window: 2 }) + +// TypeScript enforces correct options +// metrics.movingAverage({ +// window: 'invalid' // ✗ TypeScript error +// }) +``` + +## Return Value + +- Returns a new Collection of moving averages +- Length is smaller than original collection +- Only contains numeric values +- Handles edge cases appropriately +- Maintains chronological order +- Can be chained with other methods + +## Common Use Cases + +### 1. Sales Analysis + +- Daily revenue trends +- Order volume patterns +- Seasonal adjustments +- Growth analysis +- Performance smoothing + +### 2. Price Analysis + +- Price trend smoothing +- Volatility analysis +- Cost averaging +- Market trends +- Competition tracking + +### 3. Demand Forecasting + +- Trend analysis +- Seasonal patterns +- Growth prediction +- Inventory planning +- Capacity planning + +### 4. Performance Metrics + +- Response time trends +- Error rate patterns +- Load averaging +- Usage patterns +- Efficiency trends + +### 5. Inventory Management + +- Stock level trends +- Usage patterns +- Reorder timing +- Demand smoothing +- Supply planning + +### 6. Customer Analytics + +- Behavior patterns +- Engagement trends +- Value averaging +- Activity smoothing +- Retention analysis + +### 7. Marketing Analysis + +- Campaign performance +- Conversion trends +- ROI patterns +- Engagement smoothing +- Response analysis + +### 8. Financial Analysis + +- Cost trends +- Revenue patterns +- Profit smoothing +- Growth analysis +- Budget tracking + +### 9. Operational Metrics + +- Processing trends +- Efficiency patterns +- Utilization smoothing +- Resource usage +- Capacity analysis + +### 10. Quality Control + +- Error trends +- Defect patterns +- Performance smoothing +- Process control +- Variation analysis diff --git a/docs/api/profile.md b/docs/api/profile.md new file mode 100644 index 0000000..fd4763e --- /dev/null +++ b/docs/api/profile.md @@ -0,0 +1,391 @@ +# profile Method + +The `profile()` method measures the execution time and memory consumption of collection operations. Returns a Promise that resolves to time and memory metrics, useful for performance optimization and resource monitoring. + +## Basic Syntax + +```typescript +collect(items).profile(): Promise<{ time: number, memory: number }> +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Simple profiling +const numbers = collect([1, 2, 3, 4, 5]) +const profile = await numbers.profile() +console.log(profile) +// { +// time: 0.123, // Time in milliseconds +// memory: 1024 // Memory usage in bytes +// } + +// Profile with operations +const result = await collect([1, 2, 3]) + .map(n => n * 2) + .filter(n => n > 4) + .profile() +``` + +### Working with Objects + +```typescript +interface Product { + id: string + name: string + price: number + variants: string[] +} + +const products = collect([ + { + id: '1', + name: 'Widget', + price: 100, + variants: ['red', 'blue'] + }, + { + id: '2', + name: 'Gadget', + price: 200, + variants: ['small', 'large'] + } +]) + +// Profile complex operations +const metrics = await products + .map(p => ({ ...p, variants: p.variants.length })) + .sortBy('price') + .profile() +``` + +### Real-world Examples + +#### Performance Analyzer + +```typescript +interface OperationProfile { + operationName: string + time: number + memory: number + itemCount: number + memoryPerItem: number + timePerItem: number +} + +class PerformanceAnalyzer { + async analyzeOperations( + collection: Collection, + operations: Array<{ + name: string + operation: (items: Collection) => Collection + }> + ): Promise<{ + profiles: OperationProfile[] + recommendations: string[] + }> { + const profiles: OperationProfile[] = [] + + for (const op of operations) { + const beforeOp = collection + const afterOp = op.operation(collection) + const profile = await afterOp.profile() + + profiles.push({ + operationName: op.name, + time: profile.time, + memory: profile.memory, + itemCount: afterOp.count(), + memoryPerItem: profile.memory / afterOp.count(), + timePerItem: profile.time / afterOp.count() + }) + } + + return { + profiles, + recommendations: this.generateRecommendations(profiles) + } + } + + private generateRecommendations( + profiles: OperationProfile[] + ): string[] { + const recommendations: string[] = [] + + // Time-based recommendations + const slowOperations = profiles + .filter(p => p.timePerItem > 1) // More than 1ms per item + + if (slowOperations.length > 0) { + recommendations.push( + `Consider optimizing slow operations: ${ + slowOperations.map(op => op.operationName).join(', ') + }` + ) + } + + // Memory-based recommendations + const highMemoryOps = profiles + .filter(p => p.memoryPerItem > 1024) // More than 1KB per item + + if (highMemoryOps.length > 0) { + recommendations.push( + `High memory usage in operations: ${ + highMemoryOps.map(op => op.operationName).join(', ') + }` + ) + } + + return recommendations + } +} +``` + +#### Query Optimizer + +```typescript +interface QueryProfile { + query: string + results: number + time: number + memory: number + optimizationPotential: 'low' | 'medium' | 'high' +} + +class QueryOptimizer { + async analyzeQuery( + collection: Collection, + query: { + filter?: (item: T) => boolean + sort?: keyof T + limit?: number + } + ): Promise { + let operation = collection + + // Apply operations + if (query.filter) { + operation = operation.filter(query.filter) + } + if (query.sort) { + operation = operation.sortBy(query.sort) + } + if (query.limit) { + operation = operation.take(query.limit) + } + + // Profile the operation + const profile = await operation.profile() + const resultCount = operation.count() + + return { + query: this.stringifyQuery(query), + results: resultCount, + time: profile.time, + memory: profile.memory, + optimizationPotential: this.calculateOptimizationPotential( + profile, + resultCount + ) + } + } + + async compareQueries( + collection: Collection, + queries: Array<{ + name: string + query: { + filter?: (item: T) => boolean + sort?: keyof T + limit?: number + } + }> + ): Promise<{ + profiles: Array + recommendations: string[] + }> { + const profiles = await Promise.all( + queries.map(async ({ name, query }) => ({ + name, + ...(await this.analyzeQuery(collection, query)) + })) + ) + + return { + profiles, + recommendations: this.generateOptimizationRecommendations(profiles) + } + } + + private stringifyQuery(query: any): string { + return JSON.stringify(query, (key, value) => + typeof value === 'function' ? value.toString() : value + ) + } + + private calculateOptimizationPotential( + profile: { time: number, memory: number }, + resultCount: number + ): 'low' | 'medium' | 'high' { + const timePerResult = profile.time / resultCount + const memoryPerResult = profile.memory / resultCount + + if (timePerResult > 1 || memoryPerResult > 1024) { + return 'high' + } + if (timePerResult > 0.1 || memoryPerResult > 512) { + return 'medium' + } + return 'low' + } + + private generateOptimizationRecommendations( + profiles: Array + ): string[] { + const recommendations: string[] = [] + + // Find queries needing optimization + const highPotentialQueries = profiles + .filter(p => p.optimizationPotential === 'high') + .map(p => p.name) + + if (highPotentialQueries.length > 0) { + recommendations.push( + `Consider optimizing queries: ${highPotentialQueries.join(', ')}` + ) + } + + // Compare query performance + const slowestQuery = profiles + .reduce((prev, curr) => + prev.time > curr.time ? prev : curr + ) + + if (slowestQuery.time > 100) { + recommendations.push( + `Query "${slowestQuery.name}" is particularly slow` + ) + } + + return recommendations + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: string +} + +const items = collect([ + { id: 1, value: 'A' }, + { id: 2, value: 'B' } +]) + +// Type-safe profiling +const profile = await items + .map(item => ({ ...item, processed: true })) + .profile() + +// Type-safe profile result +const time: number = profile.time +const memory: number = profile.memory +``` + +## Return Value + +```typescript +interface ProfileResult { + time: number // Execution time in milliseconds + memory: number // Memory usage in bytes +} +``` + +## Common Use Cases + +### 1. Performance Optimization + +- Operation profiling +- Resource usage +- Bottleneck detection +- Query optimization +- Memory analysis + +### 2. Resource Monitoring + +- Memory usage +- Execution time +- Resource allocation +- Usage patterns +- Capacity planning + +### 3. Query Analysis + +- Query performance +- Execution metrics +- Operation costs +- Resource usage +- Optimization needs + +### 4. Development + +- Performance testing +- Resource monitoring +- Operation analysis +- Code optimization +- Memory leaks + +### 5. System Tuning + +- Performance tweaks +- Resource allocation +- Operation costs +- Memory management +- Execution optimization + +### 6. Benchmarking + +- Operation comparison +- Performance metrics +- Resource usage +- Execution time +- Memory consumption + +### 7. Debugging + +- Performance issues +- Resource problems +- Memory leaks +- Execution bottlenecks +- Operation costs + +### 8. Capacity Planning + +- Resource needs +- Performance limits +- Scaling decisions +- Usage patterns +- Growth planning + +### 9. Quality Assurance + +- Performance testing +- Resource validation +- Operation verification +- Memory checks +- Execution analysis + +### 10. Production Monitoring + +- Live performance +- Resource usage +- Operation costs +- System health +- Memory status diff --git a/docs/api/stream.md b/docs/api/stream.md new file mode 100644 index 0000000..7d23847 --- /dev/null +++ b/docs/api/stream.md @@ -0,0 +1,359 @@ +# stream Method + +The `stream()` method converts the collection into a ReadableStream, allowing for efficient processing of large datasets one item at a time. This is particularly useful when dealing with large amounts of data that shouldn't be processed all at once. + +## Basic Syntax + +```typescript +collect(items).stream(): ReadableStream +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Simple streaming +const numbers = collect([1, 2, 3, 4, 5]) +const stream = numbers.stream() + +// Process stream +const reader = stream.getReader() +while (true) { + const { done, value } = await reader.read() + if (done) break + console.log(value) // Logs each number +} + +// Stream with processing +const products = collect([ + { id: 1, name: 'Widget A' }, + { id: 2, name: 'Widget B' } +]) + +for await (const chunk of products.stream()) { + await processProduct(chunk) +} +``` + +### Working with Objects + +```typescript +interface Product { + id: string + name: string + price: number + description: string +} + +const products = collect([ + { + id: '1', + name: 'Widget', + price: 100, + description: 'A fantastic widget' + }, + // ... many more products +]) + +// Process products streaming +const stream = products.stream() +const reader = stream.getReader() + +try { + while (true) { + const { done, value } = await reader.read() + if (done) break + await updateProduct(value) + } +} finally { + reader.releaseLock() +} +``` + +### Real-world Examples + +#### Large Catalog Processor + +```typescript +interface CatalogItem { + sku: string + name: string + description: string + price: number + images: string[] + metadata: Record +} + +class CatalogProcessor { + async processCatalog( + catalog: Collection, + batchSize: number = 100 + ): Promise<{ + processed: number + failed: string[] + }> { + const stream = catalog.stream() + const reader = stream.getReader() + + let processed = 0 + const failed: string[] = [] + let batch: CatalogItem[] = [] + + try { + while (true) { + const { done, value } = await reader.read() + + if (done) { + if (batch.length > 0) { + await this.processBatch(batch, failed) + processed += batch.length + } + break + } + + batch.push(value) + if (batch.length >= batchSize) { + await this.processBatch(batch, failed) + processed += batch.length + batch = [] + } + } + } finally { + reader.releaseLock() + } + + return { processed, failed } + } + + private async processBatch( + items: CatalogItem[], + failed: string[] + ): Promise { + await Promise.all( + items.map(async item => { + try { + await this.processItem(item) + } catch (error) { + failed.push(item.sku) + console.error(`Failed to process ${item.sku}:`, error) + } + }) + ) + } + + private async processItem(item: CatalogItem): Promise { + // Process individual catalog item + await this.validateData(item) + await this.enrichMetadata(item) + await this.updateSearchIndex(item) + } + + private async validateData(item: CatalogItem): Promise { + // Validation logic + } + + private async enrichMetadata(item: CatalogItem): Promise { + // Metadata enrichment + } + + private async updateSearchIndex(item: CatalogItem): Promise { + // Search index update + } +} +``` + +#### Order History Exporter + +```typescript +interface Order { + id: string + date: Date + customer: string + items: Array<{ + productId: string + quantity: number + price: number + }> + total: number +} + +class OrderExporter { + async exportOrders( + orders: Collection, + outputStream: WritableStream + ): Promise<{ + exported: number + errors: Array<{ id: string; error: string }> + }> { + const writer = outputStream.getWriter() + const stream = orders.stream() + const reader = stream.getReader() + + let exported = 0 + const errors: Array<{ id: string; error: string }> = [] + + // Write CSV header + await writer.write(this.getHeaderRow()) + + try { + while (true) { + const { done, value } = await reader.read() + + if (done) break + + try { + await writer.write(this.formatOrder(value)) + exported++ + } catch (error) { + errors.push({ + id: value.id, + error: error instanceof Error ? error.message : 'Unknown error' + }) + } + } + } finally { + reader.releaseLock() + await writer.close() + } + + return { exported, errors } + } + + private getHeaderRow(): string { + return 'Order ID,Date,Customer,Items,Total\n' + } + + private formatOrder(order: Order): string { + return `${order.id},${order.date.toISOString()},${order.customer},` + + `${this.formatItems(order.items)},${order.total}\n` + } + + private formatItems(items: Order['items']): string { + return items + .map(item => `${item.productId}(${item.quantity})`) + .join(';') + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + value: string +} + +const items = collect([ + { id: 1, value: 'A' }, + { id: 2, value: 'B' } +]) + +// Type-safe streaming +const stream: ReadableStream = items.stream() + +// Process with type safety +const reader = stream.getReader() +while (true) { + const { done, value } = await reader.read() + if (done) break + + // TypeScript knows value type + const id: number = value.id + const val: string = value.value +} +``` + +## Return Value + +- Returns a ReadableStream of collection items +- Stream yields one item at a time +- Maintains original item types +- Supports async iteration +- Preserves item order +- Memory efficient for large datasets + +## Common Use Cases + +### 1. Large Data Processing + +- Catalog updates +- Order processing +- Log analysis +- Data migration +- Batch operations + +### 2. Data Export + +- CSV generation +- Report creation +- Data dumps +- Backup creation +- Archive generation + +### 3. Import Operations + +- Data import +- Catalog updates +- Price updates +- Inventory sync +- Product updates + +### 4. Content Processing + +- Image processing +- Content updates +- Media handling +- Document processing +- File operations + +### 5. Batch Operations + +- Order processing +- Invoice generation +- Email sending +- Report creation +- Data updates + +### 6. Data Migration + +- System updates +- Platform migration +- Data transfer +- Content moving +- Archive creation + +### 7. Resource Management + +- Memory optimization +- Processing control +- Resource utilization +- Load management +- Performance tuning + +### 8. Reporting + +- Large reports +- Data analysis +- Statistics generation +- Performance metrics +- Usage tracking + +### 9. Integration + +- API integration +- System sync +- Data exchange +- Service integration +- Platform connection + +### 10. Performance Optimization + +- Memory usage +- Processing speed +- Resource efficiency +- Load handling +- Scalability diff --git a/docs/api/timeSeries.md b/docs/api/timeSeries.md new file mode 100644 index 0000000..7a781b7 --- /dev/null +++ b/docs/api/timeSeries.md @@ -0,0 +1,344 @@ +# timeSeries Method + +The `timeSeries()` method transforms a collection into a series of time-based data points, optionally filling gaps in the timeline. This is particularly useful for analyzing trends, patterns, and changes over time. + +## Basic Syntax + +```typescript +collect(items).timeSeries({ + dateField: keyof T, // Field containing dates + valueField: keyof T, // Field containing values + interval?: 'day' | 'week' | 'month' = 'day', // Time interval + fillGaps?: boolean = true // Whether to fill missing intervals +}): Collection +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Simple daily sales data +const sales = collect([ + { date: '2024-01-01', amount: 100 }, + { date: '2024-01-03', amount: 300 }, + { date: '2024-01-05', amount: 200 } +]) + +// Convert to time series with gap filling +const dailySales = sales.timeSeries({ + dateField: 'date', + valueField: 'amount' +}) +// Results in: +// [ +// { date: '2024-01-01', value: 100 }, +// { date: '2024-01-02', value: 0 }, +// { date: '2024-01-03', value: 300 }, +// { date: '2024-01-04', value: 0 }, +// { date: '2024-01-05', value: 200 } +// ] +``` + +### Working with Objects + +```typescript +interface SalesData { + transactionDate: Date + revenue: number + orders: number +} + +const salesData = collect([ + { transactionDate: new Date('2024-01-01'), revenue: 1000, orders: 10 }, + { transactionDate: new Date('2024-01-03'), revenue: 1500, orders: 15 }, + { transactionDate: new Date('2024-01-05'), revenue: 2000, orders: 20 } +]) + +// Analyze daily revenue +const revenueTimeSeries = salesData.timeSeries({ + dateField: 'transactionDate', + valueField: 'revenue' +}) + +// Analyze daily orders +const orderTimeSeries = salesData.timeSeries({ + dateField: 'transactionDate', + valueField: 'orders' +}) +``` + +### Real-world Examples + +#### Sales Trend Analyzer + +```typescript +interface SaleRecord { + saleDate: Date + amount: number + channel: string + productCategory: string +} + +class SalesTrendAnalyzer { + constructor(private sales: Collection) {} + + analyzeTrends(options: { + startDate: Date + endDate: Date + interval: 'day' | 'week' | 'month' + }): { + overall: Collection + byChannel: Map> + byCategory: Map> + } { + const filteredSales = this.sales.filter(sale => + sale.saleDate >= options.startDate && + sale.saleDate <= options.endDate + ) + + // Overall trend + const overallTrend = filteredSales.timeSeries({ + dateField: 'saleDate', + valueField: 'amount', + interval: options.interval + }) + + // Trends by channel + const byChannel = new Map() + for (const channel of new Set(filteredSales.pluck('channel'))) { + byChannel.set( + channel, + filteredSales + .where('channel', channel) + .timeSeries({ + dateField: 'saleDate', + valueField: 'amount', + interval: options.interval + }) + ) + } + + // Trends by category + const byCategory = new Map() + for (const category of new Set(filteredSales.pluck('productCategory'))) { + byCategory.set( + category, + filteredSales + .where('productCategory', category) + .timeSeries({ + dateField: 'saleDate', + valueField: 'amount', + interval: options.interval + }) + ) + } + + return { overall: overallTrend, byChannel, byCategory } + } + + calculateGrowthRate(timePoints: Collection): { + overall: number, + periodic: Collection<{ date: Date, growth: number }> + } { + const values = timePoints.pluck('value') + const firstValue = values.first() || 0 + const lastValue = values.last() || 0 + const overallGrowth = ((lastValue - firstValue) / firstValue) * 100 + + const periodicGrowth = timePoints + .map((point, index, array) => { + if (index === 0) return { date: point.date, growth: 0 } + const previousValue = array[index - 1].value + const growth = previousValue === 0 ? 0 : + ((point.value - previousValue) / previousValue) * 100 + return { date: point.date, growth } + }) + .filter((_, index) => index > 0) + + return { + overall: overallGrowth, + periodic: collect(periodicGrowth) + } + } +} +``` + +#### Customer Activity Monitor + +```typescript +interface UserActivity { + userId: string + activityDate: Date + action: string + value: number +} + +class ActivityAnalyzer { + constructor(private activities: Collection) {} + + analyzeEngagement( + interval: 'day' | 'week' | 'month' = 'day' + ): { + activityTrend: Collection + valueGenerated: Collection + peakTimes: Date[] + } { + // Activity frequency trend + const activityTrend = this.activities + .groupBy('activityDate') + .map(group => ({ + date: group.first()?.activityDate, + count: group.count() + })) + .timeSeries({ + dateField: 'date', + valueField: 'count', + interval: interval, + fillGaps: true + }) + + // Value generation trend + const valueTrend = this.activities.timeSeries({ + dateField: 'activityDate', + valueField: 'value', + interval: interval, + fillGaps: true + }) + + // Identify peak activity times + const averageValue = activityTrend.avg('value') + const peakTimes = activityTrend + .filter(point => point.value > averageValue * 1.5) + .pluck('date') + .toArray() + + return { + activityTrend, + valueGenerated: valueTrend, + peakTimes + } + } +} +``` + +## Type Safety + +```typescript +interface TypedActivity { + timestamp: Date + metric: number +} + +const activities = collect([ + { timestamp: new Date('2024-01-01'), metric: 100 }, + { timestamp: new Date('2024-01-02'), metric: 200 } +]) + +// Type-safe time series creation +const timeSeries = activities.timeSeries({ + dateField: 'timestamp', + valueField: 'metric' +}) + +// TypeScript enforces correct field names +// activities.timeSeries({ +// dateField: 'invalid', // ✗ TypeScript error +// valueField: 'metric' +// }) +``` + +## Return Value + +Returns a Collection of TimeSeriesPoint objects: + +```typescript +interface TimeSeriesPoint { + date: Date // Point in time + value: number // Value at that time +} +``` + +## Common Use Cases + +### 1. Sales Analysis + +- Daily revenue trends +- Order volume patterns +- Seasonal variations +- Growth analysis +- Performance tracking + +### 2. User Engagement + +- Activity patterns +- Usage trends +- Session analysis +- Feature adoption +- Retention tracking + +### 3. Inventory Management + +- Stock level trends +- Usage patterns +- Reorder timing +- Seasonal demand +- Supply chain analysis + +### 4. Performance Metrics + +- Response times +- Error rates +- Load patterns +- Resource usage +- System health + +### 5. Financial Analysis + +- Revenue trends +- Cost patterns +- Profit analysis +- Budget tracking +- Expense monitoring + +### 6. Marketing Analytics + +- Campaign performance +- Conversion trends +- Engagement patterns +- ROI analysis +- Channel effectiveness + +### 7. Customer Behavior + +- Purchase patterns +- Visit frequency +- Interaction trends +- Feature usage +- Satisfaction trends + +### 8. Operational Metrics + +- Processing times +- Queue lengths +- Efficiency trends +- Resource utilization +- Service levels + +### 9. Growth Analysis + +- User growth +- Revenue growth +- Adoption rates +- Churn patterns +- Expansion metrics + +### 10. Content Performance + +- View patterns +- Engagement trends +- Rating analysis +- Comment activity +- Share frequency diff --git a/docs/api/validate.md b/docs/api/validate.md new file mode 100644 index 0000000..1d2bd30 --- /dev/null +++ b/docs/api/validate.md @@ -0,0 +1,392 @@ +# validate Method + +The `validate()` method performs asynchronous validation of collection items against a provided schema. Returns a Promise that resolves to a validation result containing success status and any validation errors. + +## Basic Syntax + +```typescript +collect(items).validate(schema: ValidationSchema): Promise +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Simple validation +const items = collect([ + { id: 1, email: 'test@example.com' }, + { id: 2, email: 'invalid-email' } +]) + +const schema = { + email: [ + async (value: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) + ] +} + +const result = await items.validate(schema) +console.log(result) +// { +// isValid: false, +// errors: Map { +// 'email' => ['Validation failed for email'] +// } +// } +``` + +### Working with Objects + +```typescript +interface Product { + id: string + name: string + price: number + stock: number +} + +const products = collect([ + { id: '1', name: 'Widget', price: 100, stock: 10 }, + { id: '2', name: '', price: -50, stock: -5 } +]) + +const productSchema = { + name: [ + async (value: string) => value.length > 0, + async (value: string) => value.length <= 100 + ], + price: [ + async (value: number) => value > 0 + ], + stock: [ + async (value: number) => value >= 0 + ] +} + +const validationResult = await products.validate(productSchema) +``` + +### Real-world Examples + +#### Product Validator + +```typescript +interface ProductData { + sku: string + name: string + description: string + price: number + category: string + attributes: Record +} + +class ProductValidator { + constructor( + private externalApi: string, + private categoryList: string[] + ) {} + + async validateProducts( + products: Collection + ): Promise<{ + validationResult: ValidationResult, + validProducts: ProductData[], + invalidProducts: Array<{ + product: ProductData, + errors: string[] + }> + }> { + const schema: ValidationSchema = { + sku: [ + async (sku) => this.isSkuUnique(sku), + async (sku) => /^[A-Z0-9-]{5,20}$/.test(sku) + ], + name: [ + async (name) => name.length >= 3 && name.length <= 100, + async (name) => !/[<>]/.test(name) // No HTML tags + ], + description: [ + async (desc) => desc.length <= 5000, + async (desc) => this.containsValidHtml(desc) + ], + price: [ + async (price) => price > 0 && price < 1000000, + async (price) => Number.isFinite(price) + ], + category: [ + async (category) => this.categoryList.includes(category) + ], + attributes: [ + async (attrs) => this.validateAttributes(attrs) + ] + } + + const result = await products.validate(schema) + + const validProducts = products + .filter(product => !this.hasErrors(result.errors, product.sku)) + .toArray() + + const invalidProducts = products + .filter(product => this.hasErrors(result.errors, product.sku)) + .map(product => ({ + product, + errors: this.getErrorsForProduct(result.errors, product.sku) + })) + .toArray() + + return { + validationResult: result, + validProducts, + invalidProducts + } + } + + private async isSkuUnique(sku: string): Promise { + const response = await fetch(`${this.externalApi}/check-sku/${sku}`) + return response.json() + } + + private containsValidHtml(text: string): boolean { + // HTML validation logic + return true + } + + private async validateAttributes( + attrs: Record + ): Promise { + // Attribute validation logic + return true + } + + private hasErrors( + errors: Map, + sku: string + ): boolean { + return Array.from(errors.keys()).some(key => key.includes(sku)) + } + + private getErrorsForProduct( + errors: Map, + sku: string + ): string[] { + return Array.from(errors.entries()) + .filter(([key]) => key.includes(sku)) + .flatMap(([_, errs]) => errs) + } +} +``` + +#### Order Validator + +```typescript +interface OrderData { + orderId: string + customerId: string + items: Array<{ + productId: string + quantity: number + }> + shippingAddress: { + country: string + zipCode: string + } + paymentMethod: string +} + +class OrderValidator { + constructor( + private inventoryApi: string, + private customerApi: string, + private shippingApi: string + ) {} + + async validateOrders( + orders: Collection + ): Promise { + const schema: ValidationSchema = { + customerId: [ + async (id) => this.customerExists(id), + async (id) => this.customerIsActive(id) + ], + items: [ + async (items) => items.length > 0, + async (items) => this.validateOrderItems(items) + ], + shippingAddress: [ + async (address) => this.validateShippingAddress(address) + ], + paymentMethod: [ + async (method) => this.validatePaymentMethod(method) + ] + } + + return orders.validate(schema) + } + + private async customerExists(id: string): Promise { + const response = await fetch(`${this.customerApi}/exists/${id}`) + return response.json() + } + + private async customerIsActive(id: string): Promise { + const response = await fetch(`${this.customerApi}/status/${id}`) + const { status } = await response.json() + return status === 'active' + } + + private async validateOrderItems( + items: OrderData['items'] + ): Promise { + const inventoryChecks = await Promise.all( + items.map(async item => { + const response = await fetch( + `${this.inventoryApi}/check/${item.productId}/${item.quantity}` + ) + return response.json() + }) + ) + + return inventoryChecks.every(check => check.available) + } + + private async validateShippingAddress( + address: OrderData['shippingAddress'] + ): Promise { + const response = await fetch( + `${this.shippingApi}/validate-address`, + { + method: 'POST', + body: JSON.stringify(address) + } + ) + return response.json() + } + + private async validatePaymentMethod(method: string): Promise { + // Payment method validation logic + return true + } +} +``` + +## Type Safety + +```typescript +interface TypedItem { + id: number + email: string + age: number +} + +const items = collect([ + { id: 1, email: 'test@example.com', age: 25 }, + { id: 2, email: 'invalid', age: -5 } +]) + +// Type-safe validation schema +const schema: ValidationSchema = { + email: [ + async (value: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) + ], + age: [ + async (value: number) => value >= 0 && value <= 120 + ] +} + +// TypeScript enforces schema types +const result = await items.validate(schema) +``` + +## Return Value + +```typescript +interface ValidationResult { + isValid: boolean // Overall validation status + errors: Map // Map of field names to error messages +} +``` + +## Common Use Cases + +### 1. Product Validation + +- SKU validation +- Price constraints +- Stock levels +- Category rules +- Attribute validation + +### 2. Order Validation + +- Customer verification +- Stock availability +- Payment validation +- Shipping rules +- Price checks + +### 3. Customer Data + +- Contact information +- Address validation +- Account rules +- Profile requirements +- Permission checks + +### 4. Inventory Management + +- Stock levels +- Location validation +- Reorder rules +- Supplier checks +- Category validation + +### 5. Price Validation + +- Range checks +- Margin rules +- Discount validation +- Currency checks +- Tax calculations + +### 6. Shipping Rules + +- Address validation +- Weight limits +- Zone restrictions +- Service availability +- Cost validation + +### 7. Content Validation + +- Format checking +- Size limits +- Type validation +- Structure rules +- Metadata requirements + +### 8. Account Validation + +- Credentials +- Permissions +- Status checks +- Role requirements +- Access rules + +### 9. Payment Validation + +- Method verification +- Amount limits +- Currency rules +- Gateway checks +- Security validation + +### 10. Business Rules + +- Policy compliance +- Process rules +- Workflow validation +- Constraint checks +- Requirement validation diff --git a/docs/api/validateSync.md b/docs/api/validateSync.md new file mode 100644 index 0000000..25b4bde --- /dev/null +++ b/docs/api/validateSync.md @@ -0,0 +1,361 @@ +# validateSync Method + +The `validateSync()` method performs synchronous validation of collection items against a provided schema. Returns a validation result containing success status and any validation errors. Unlike `validate()`, this method cannot perform async operations. + +## Basic Syntax + +```typescript +collect(items).validateSync(schema: ValidationSchema): ValidationResult +``` + +## Examples + +### Basic Usage + +```typescript +import { collect } from 'ts-collect' + +// Simple validation +const items = collect([ + { id: 1, email: 'test@example.com' }, + { id: 2, email: 'invalid-email' } +]) + +const schema = { + email: [ + (value: string) => /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value) + ] +} + +const result = items.validateSync(schema) +console.log(result) +// { +// isValid: false, +// errors: Map { +// 'email' => ['Validation failed for email'] +// } +// } +``` + +### Working with Objects + +```typescript +interface Product { + id: string + name: string + price: number + stock: number +} + +const products = collect([ + { id: '1', name: 'Widget', price: 100, stock: 10 }, + { id: '2', name: '', price: -50, stock: -5 } +]) + +const productSchema = { + name: [ + (value: string) => value.length > 0, + (value: string) => value.length <= 100 + ], + price: [ + (value: number) => value > 0, + (value: number) => Number.isFinite(value) + ], + stock: [ + (value: number) => value >= 0, + (value: number) => Number.isInteger(value) + ] +} + +const validationResult = products.validateSync(productSchema) +``` + +### Real-world Examples + +#### Product Input Validator + +```typescript +interface ProductInput { + sku: string + name: string + description: string + price: number + dimensions: { + length: number + width: number + height: number + } + weight: number +} + +class ProductInputValidator { + private readonly rules = { + sku: [ + (sku: string) => /^[A-Z0-9-]{5,20}$/.test(sku), + (sku: string) => !sku.includes('--') + ], + name: [ + (name: string) => name.length >= 3, + (name: string) => name.length <= 100, + (name: string) => !/[<>]/.test(name) + ], + description: [ + (desc: string) => desc.length <= 5000, + (desc: string) => !/