mirror of
https://github.com/CherryHQ/cherry-studio.git
synced 2025-12-27 04:31:27 +08:00
refactor(dataApi): remove batch and transaction support from Data API
- Deleted batch and transaction related schemas, handlers, and IPC channels to streamline the Data API. - Updated related type definitions and import paths to reflect the removal of batch and transaction functionalities. - Simplified the API server and adapter logic by eliminating unused methods and handlers.
This commit is contained in:
parent
18df6085d7
commit
0b35029404
@ -346,8 +346,6 @@ export enum IpcChannel {
|
||||
|
||||
// Data: API Channels
|
||||
DataApi_Request = 'data-api:request',
|
||||
DataApi_Batch = 'data-api:batch',
|
||||
DataApi_Transaction = 'data-api:transaction',
|
||||
DataApi_Subscribe = 'data-api:subscribe',
|
||||
DataApi_Unsubscribe = 'data-api:unsubscribe',
|
||||
DataApi_Stream = 'data-api:stream',
|
||||
|
||||
@ -13,8 +13,7 @@ packages/shared/data/
|
||||
│ ├── errorCodes.ts # Error handling utilities
|
||||
│ ├── schemas/ # Domain-specific API schemas
|
||||
│ │ ├── index.ts # Schema composition
|
||||
│ │ ├── test.ts # Test API schema and DTOs
|
||||
│ │ └── batch.ts # Batch/transaction operations
|
||||
│ │ └── test.ts # Test API schema and DTOs
|
||||
│ └── README.md # Detailed API documentation
|
||||
├── cache/ # Cache system type definitions
|
||||
│ ├── cacheTypes.ts # Core cache infrastructure types
|
||||
|
||||
@ -12,8 +12,7 @@ packages/shared/data/api/
|
||||
├── errorCodes.ts # Error handling utilities and factories
|
||||
└── schemas/
|
||||
├── index.ts # Schema composition (merges all domain schemas)
|
||||
├── test.ts # Test API schema and DTOs
|
||||
└── batch.ts # Batch/transaction API schema
|
||||
└── test.ts # Test API schema and DTOs
|
||||
```
|
||||
|
||||
## File Responsibilities
|
||||
@ -109,7 +108,7 @@ export interface TopicSchemas {
|
||||
import type { TopicSchemas } from './topic'
|
||||
|
||||
// AssertValidSchemas provides fallback validation even if ValidateSchema is forgotten
|
||||
export type ApiSchemas = AssertValidSchemas<TestSchemas & BatchSchemas & TopicSchemas>
|
||||
export type ApiSchemas = AssertValidSchemas<TestSchemas & TopicSchemas>
|
||||
```
|
||||
|
||||
3. Implement handlers in `src/main/data/api/handlers/`
|
||||
|
||||
@ -168,52 +168,6 @@ export enum ErrorCode {
|
||||
CONCURRENT_MODIFICATION = 'CONCURRENT_MODIFICATION'
|
||||
}
|
||||
|
||||
/**
|
||||
* Transaction request wrapper for atomic operations
|
||||
*/
|
||||
export interface TransactionRequest {
|
||||
/** List of operations to execute in transaction */
|
||||
operations: DataRequest[]
|
||||
/** Transaction options */
|
||||
options?: {
|
||||
/** Database isolation level */
|
||||
isolation?: 'read-uncommitted' | 'read-committed' | 'repeatable-read' | 'serializable'
|
||||
/** Whether to rollback entire transaction on any error */
|
||||
rollbackOnError?: boolean
|
||||
/** Transaction timeout in milliseconds */
|
||||
timeout?: number
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch request for multiple operations
|
||||
*/
|
||||
export interface BatchRequest {
|
||||
/** List of requests to execute */
|
||||
requests: DataRequest[]
|
||||
/** Whether to execute requests in parallel */
|
||||
parallel?: boolean
|
||||
/** Stop on first error */
|
||||
stopOnError?: boolean
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch response containing results for all requests
|
||||
*/
|
||||
export interface BatchResponse {
|
||||
/** Individual response for each request */
|
||||
results: DataResponse[]
|
||||
/** Overall batch execution metadata */
|
||||
metadata: {
|
||||
/** Total execution time */
|
||||
duration: number
|
||||
/** Number of successful operations */
|
||||
successCount: number
|
||||
/** Number of failed operations */
|
||||
errorCount: number
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pagination parameters for list operations
|
||||
*/
|
||||
|
||||
@ -19,15 +19,12 @@
|
||||
// ============================================================================
|
||||
|
||||
export type {
|
||||
BatchRequest,
|
||||
BatchResponse,
|
||||
DataApiError,
|
||||
DataRequest,
|
||||
DataResponse,
|
||||
HttpMethod,
|
||||
PaginatedResponse,
|
||||
PaginationParams,
|
||||
TransactionRequest
|
||||
PaginationParams
|
||||
} from './apiTypes'
|
||||
|
||||
// ============================================================================
|
||||
|
||||
@ -1,140 +0,0 @@
|
||||
/**
|
||||
* Batch and Transaction API Schema definitions
|
||||
*
|
||||
* Contains cross-domain operations for batch processing and atomic transactions.
|
||||
* These endpoints are domain-agnostic and work with any API path.
|
||||
*/
|
||||
|
||||
import type { HttpMethod } from '../apiTypes'
|
||||
|
||||
// ============================================================================
|
||||
// Domain Models & DTOs
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Request for bulk operations on multiple items
|
||||
*/
|
||||
export interface BulkOperationRequest<TData = any> {
|
||||
/** Type of bulk operation to perform */
|
||||
operation: 'create' | 'update' | 'delete' | 'archive' | 'restore'
|
||||
/** Array of data items to process */
|
||||
data: TData[]
|
||||
}
|
||||
|
||||
/**
|
||||
* Response from a bulk operation
|
||||
*/
|
||||
export interface BulkOperationResponse {
|
||||
/** Number of successfully processed items */
|
||||
successful: number
|
||||
/** Number of items that failed processing */
|
||||
failed: number
|
||||
/** Array of errors that occurred during processing */
|
||||
errors: Array<{
|
||||
/** Index of the item that failed */
|
||||
index: number
|
||||
/** Error message */
|
||||
error: string
|
||||
/** Optional additional error data */
|
||||
data?: any
|
||||
}>
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// API Schema Definitions
|
||||
// ============================================================================
|
||||
|
||||
/**
|
||||
* Batch and Transaction API Schema definitions
|
||||
*
|
||||
* Validation is performed at composition level via AssertValidSchemas
|
||||
* in schemas/index.ts, which ensures:
|
||||
* - All methods are valid HTTP methods (GET, POST, PUT, DELETE, PATCH)
|
||||
* - All endpoints have a `response` field
|
||||
*/
|
||||
export interface BatchSchemas {
|
||||
/**
|
||||
* Batch execution of multiple requests
|
||||
* @example POST /batch { "requests": [...], "parallel": true }
|
||||
*/
|
||||
'/batch': {
|
||||
/** Execute multiple API requests in a single call */
|
||||
POST: {
|
||||
body: {
|
||||
/** Array of requests to execute */
|
||||
requests: Array<{
|
||||
/** HTTP method for the request */
|
||||
method: HttpMethod
|
||||
/** API path for the request */
|
||||
path: string
|
||||
/** URL parameters */
|
||||
params?: any
|
||||
/** Request body */
|
||||
body?: any
|
||||
}>
|
||||
/** Execute requests in parallel vs sequential */
|
||||
parallel?: boolean
|
||||
}
|
||||
response: {
|
||||
/** Results array matching input order */
|
||||
results: Array<{
|
||||
/** HTTP status code */
|
||||
status: number
|
||||
/** Response data if successful */
|
||||
data?: any
|
||||
/** Error information if failed */
|
||||
error?: any
|
||||
}>
|
||||
/** Batch execution metadata */
|
||||
metadata: {
|
||||
/** Total execution duration in ms */
|
||||
duration: number
|
||||
/** Number of successful requests */
|
||||
successCount: number
|
||||
/** Number of failed requests */
|
||||
errorCount: number
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Atomic transaction of multiple operations
|
||||
* @example POST /transaction { "operations": [...], "options": { "rollbackOnError": true } }
|
||||
*/
|
||||
'/transaction': {
|
||||
/** Execute multiple operations in a database transaction */
|
||||
POST: {
|
||||
body: {
|
||||
/** Array of operations to execute atomically */
|
||||
operations: Array<{
|
||||
/** HTTP method for the operation */
|
||||
method: HttpMethod
|
||||
/** API path for the operation */
|
||||
path: string
|
||||
/** URL parameters */
|
||||
params?: any
|
||||
/** Request body */
|
||||
body?: any
|
||||
}>
|
||||
/** Transaction configuration options */
|
||||
options?: {
|
||||
/** Database isolation level */
|
||||
isolation?: 'read-uncommitted' | 'read-committed' | 'repeatable-read' | 'serializable'
|
||||
/** Rollback all operations on any error */
|
||||
rollbackOnError?: boolean
|
||||
/** Transaction timeout in milliseconds */
|
||||
timeout?: number
|
||||
}
|
||||
}
|
||||
response: Array<{
|
||||
/** HTTP status code */
|
||||
status: number
|
||||
/** Response data if successful */
|
||||
data?: any
|
||||
/** Error information if failed */
|
||||
error?: any
|
||||
}>
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -19,7 +19,6 @@
|
||||
*/
|
||||
|
||||
import type { AssertValidSchemas } from '../apiTypes'
|
||||
import type { BatchSchemas } from './batch'
|
||||
import type { TestSchemas } from './test'
|
||||
|
||||
/**
|
||||
@ -37,7 +36,7 @@ import type { TestSchemas } from './test'
|
||||
* @example
|
||||
* ```typescript
|
||||
* import type { TopicSchemas } from './topic'
|
||||
* export type ApiSchemas = AssertValidSchemas<TestSchemas & BatchSchemas & TopicSchemas>
|
||||
* export type ApiSchemas = AssertValidSchemas<TestSchemas & TopicSchemas>
|
||||
* ```
|
||||
*/
|
||||
export type ApiSchemas = AssertValidSchemas<TestSchemas & BatchSchemas>
|
||||
export type ApiSchemas = AssertValidSchemas<TestSchemas>
|
||||
|
||||
@ -13,8 +13,7 @@ src/main/data/
|
||||
│ │ └── adapters/ # Communication adapters (IPC)
|
||||
│ ├── handlers/ # API endpoint implementations
|
||||
│ │ ├── index.ts # Handler aggregation and exports
|
||||
│ │ ├── test.ts # Test endpoint handlers
|
||||
│ │ └── batch.ts # Batch/transaction handlers
|
||||
│ │ └── test.ts # Test endpoint handlers
|
||||
│ └── index.ts # API framework exports
|
||||
│
|
||||
├── services/ # Business logic layer
|
||||
@ -102,7 +101,7 @@ The API framework provides the interface layer for data access:
|
||||
- Delegating to business services
|
||||
- Transforming responses for IPC
|
||||
- **Anti-pattern**: Do NOT put business logic in handlers
|
||||
- **Currently**: Contains test and batch handlers (business handlers pending)
|
||||
- **Currently**: Contains test handlers (business handlers pending)
|
||||
- **Type Safety**: Must implement all endpoints defined in `@shared/data/api/schemas/`
|
||||
|
||||
### Business Logic Layer (`services/`)
|
||||
|
||||
@ -105,37 +105,6 @@ export class ApiServer {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle batch requests
|
||||
*/
|
||||
async handleBatchRequest(batchRequest: DataRequest): Promise<DataResponse> {
|
||||
const requests = batchRequest.body?.requests || []
|
||||
|
||||
if (!Array.isArray(requests)) {
|
||||
throw DataApiErrorFactory.create(ErrorCode.VALIDATION_ERROR, 'Batch request body must contain requests array')
|
||||
}
|
||||
|
||||
logger.debug(`Processing batch request with ${requests.length} requests`)
|
||||
|
||||
// Use the batch handler from our handlers
|
||||
const batchHandler = this.handlers['/batch']?.POST
|
||||
if (!batchHandler) {
|
||||
throw DataApiErrorFactory.create(ErrorCode.NOT_FOUND, 'Batch handler not found')
|
||||
}
|
||||
|
||||
const result = await batchHandler({ body: batchRequest.body })
|
||||
|
||||
return {
|
||||
id: batchRequest.id,
|
||||
status: 200,
|
||||
data: result,
|
||||
metadata: {
|
||||
duration: 0,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find handler for given path and method
|
||||
*/
|
||||
|
||||
@ -57,55 +57,6 @@ export class IpcAdapter {
|
||||
}
|
||||
})
|
||||
|
||||
// Batch request handler
|
||||
ipcMain.handle(IpcChannel.DataApi_Batch, async (_event, batchRequest: DataRequest): Promise<DataResponse> => {
|
||||
try {
|
||||
logger.debug('Handling batch request', { requestCount: batchRequest.body?.requests?.length })
|
||||
|
||||
const response = await this.apiServer.handleBatchRequest(batchRequest)
|
||||
return response
|
||||
} catch (error) {
|
||||
logger.error('Batch request failed', error as Error)
|
||||
|
||||
const apiError = toDataApiError(error, 'batch request')
|
||||
return {
|
||||
id: batchRequest.id,
|
||||
status: apiError.status,
|
||||
error: apiError,
|
||||
metadata: {
|
||||
duration: 0,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Transaction handler (placeholder)
|
||||
ipcMain.handle(
|
||||
IpcChannel.DataApi_Transaction,
|
||||
async (_event, transactionRequest: DataRequest): Promise<DataResponse> => {
|
||||
try {
|
||||
logger.debug('Handling transaction request')
|
||||
|
||||
// TODO: Implement transaction support
|
||||
throw new Error('Transaction support not yet implemented')
|
||||
} catch (error) {
|
||||
logger.error('Transaction request failed', error as Error)
|
||||
|
||||
const apiError = toDataApiError(error, 'transaction request')
|
||||
return {
|
||||
id: transactionRequest.id,
|
||||
status: apiError.status,
|
||||
error: apiError,
|
||||
metadata: {
|
||||
duration: 0,
|
||||
timestamp: Date.now()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
)
|
||||
|
||||
// Subscription handlers (placeholder for future real-time features)
|
||||
ipcMain.handle(IpcChannel.DataApi_Subscribe, async (_event, path: string) => {
|
||||
logger.debug(`Data subscription request: ${path}`)
|
||||
@ -134,8 +85,6 @@ export class IpcAdapter {
|
||||
logger.debug('Removing IPC handlers...')
|
||||
|
||||
ipcMain.removeHandler(IpcChannel.DataApi_Request)
|
||||
ipcMain.removeHandler(IpcChannel.DataApi_Batch)
|
||||
ipcMain.removeHandler(IpcChannel.DataApi_Transaction)
|
||||
ipcMain.removeHandler(IpcChannel.DataApi_Subscribe)
|
||||
ipcMain.removeHandler(IpcChannel.DataApi_Unsubscribe)
|
||||
|
||||
|
||||
@ -1,55 +0,0 @@
|
||||
/**
|
||||
* Batch and Transaction API Handlers
|
||||
*
|
||||
* Implements cross-domain batch processing and atomic transaction operations.
|
||||
*/
|
||||
|
||||
import type { ApiHandler, ApiMethods } from '@shared/data/api/apiTypes'
|
||||
import type { BatchSchemas } from '@shared/data/api/schemas/batch'
|
||||
|
||||
/**
|
||||
* Handler type for a specific batch endpoint
|
||||
*/
|
||||
type BatchHandler<Path extends keyof BatchSchemas, Method extends ApiMethods<Path>> = ApiHandler<Path, Method>
|
||||
|
||||
/**
|
||||
* Batch API handlers implementation
|
||||
*/
|
||||
export const batchHandlers: {
|
||||
[Path in keyof BatchSchemas]: {
|
||||
[Method in keyof BatchSchemas[Path]]: BatchHandler<Path, Method & ApiMethods<Path>>
|
||||
}
|
||||
} = {
|
||||
'/batch': {
|
||||
POST: async ({ body }) => {
|
||||
// Mock batch implementation - can be enhanced with actual batch processing
|
||||
const { requests } = body
|
||||
|
||||
const results = requests.map(() => ({
|
||||
status: 200,
|
||||
data: { processed: true, timestamp: new Date().toISOString() }
|
||||
}))
|
||||
|
||||
return {
|
||||
results,
|
||||
metadata: {
|
||||
duration: Math.floor(Math.random() * 500) + 100,
|
||||
successCount: requests.length,
|
||||
errorCount: 0
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
'/transaction': {
|
||||
POST: async ({ body }) => {
|
||||
// Mock transaction implementation - can be enhanced with actual transaction support
|
||||
const { operations } = body
|
||||
|
||||
return operations.map(() => ({
|
||||
status: 200,
|
||||
data: { executed: true, timestamp: new Date().toISOString() }
|
||||
}))
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,6 @@
|
||||
*
|
||||
* Handler files are organized by domain:
|
||||
* - test.ts - Test API handlers
|
||||
* - batch.ts - Batch and transaction handlers
|
||||
*
|
||||
* @example Adding a new domain:
|
||||
* ```typescript
|
||||
@ -14,7 +13,6 @@
|
||||
*
|
||||
* export const apiHandlers: ApiImplementation = {
|
||||
* ...testHandlers,
|
||||
* ...batchHandlers,
|
||||
* ...topicHandlers // Add new domain handlers here
|
||||
* }
|
||||
* ```
|
||||
@ -22,7 +20,6 @@
|
||||
|
||||
import type { ApiImplementation } from '@shared/data/api/apiTypes'
|
||||
|
||||
import { batchHandlers } from './batch'
|
||||
import { testHandlers } from './test'
|
||||
|
||||
/**
|
||||
@ -33,6 +30,5 @@ import { testHandlers } from './test'
|
||||
* TypeScript ensures exhaustive coverage - missing handlers cause compile errors.
|
||||
*/
|
||||
export const apiHandlers: ApiImplementation = {
|
||||
...testHandlers,
|
||||
...batchHandlers
|
||||
...testHandlers
|
||||
}
|
||||
|
||||
@ -605,8 +605,6 @@ const api = {
|
||||
// Data API related APIs
|
||||
dataApi: {
|
||||
request: (req: any) => ipcRenderer.invoke(IpcChannel.DataApi_Request, req),
|
||||
batch: (req: any) => ipcRenderer.invoke(IpcChannel.DataApi_Batch, req),
|
||||
transaction: (req: any) => ipcRenderer.invoke(IpcChannel.DataApi_Transaction, req),
|
||||
subscribe: (path: string, callback: (data: any, event: string) => void) => {
|
||||
const channel = `${IpcChannel.DataApi_Stream}:${path}`
|
||||
const listener = (_: any, data: any, event: string) => callback(data, event)
|
||||
|
||||
@ -15,7 +15,6 @@
|
||||
* - Type-safe requests with full TypeScript inference
|
||||
* - Automatic retry with exponential backoff (network, timeout, 500/503 errors)
|
||||
* - Request timeout management (3s default)
|
||||
* - Batch request support for performance
|
||||
* - Subscription management (real-time updates)
|
||||
*
|
||||
* Architecture:
|
||||
@ -33,15 +32,11 @@
|
||||
import { loggerService } from '@logger'
|
||||
import type { ApiClient, ConcreteApiPaths } from '@shared/data/api/apiTypes'
|
||||
import type {
|
||||
BatchRequest,
|
||||
BatchResponse,
|
||||
DataRequest,
|
||||
DataResponse,
|
||||
HttpMethod,
|
||||
SubscriptionCallback,
|
||||
SubscriptionEvent,
|
||||
SubscriptionOptions,
|
||||
TransactionRequest
|
||||
SubscriptionOptions
|
||||
} from '@shared/data/api/apiTypes'
|
||||
import { toDataApiError } from '@shared/data/api/errorCodes'
|
||||
|
||||
@ -311,30 +306,6 @@ export class DataApiService implements ApiClient {
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute multiple requests in batch
|
||||
*/
|
||||
async batch(requests: DataRequest[], options: { parallel?: boolean } = {}): Promise<BatchResponse> {
|
||||
const batchRequest: BatchRequest = {
|
||||
requests,
|
||||
parallel: options.parallel ?? true
|
||||
}
|
||||
|
||||
return this.makeRequest<BatchResponse>('POST', '/batch', { body: batchRequest })
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute requests in a transaction
|
||||
*/
|
||||
async transaction(operations: DataRequest[], options?: TransactionRequest['options']): Promise<DataResponse[]> {
|
||||
const transactionRequest: TransactionRequest = {
|
||||
operations,
|
||||
options
|
||||
}
|
||||
|
||||
return this.makeRequest<DataResponse[]>('POST', '/transaction', { body: transactionRequest })
|
||||
}
|
||||
|
||||
/**
|
||||
* Subscribe to real-time updates
|
||||
*/
|
||||
|
||||
@ -82,9 +82,8 @@ const [recentFiles, setRecentFiles] = usePersistCache('app.recent_files')
|
||||
**Key Features**:
|
||||
- Type-safe request/response handling
|
||||
- Automatic retry with exponential backoff
|
||||
- Batch operations and transactions
|
||||
- Real-time subscriptions
|
||||
- Request cancellation and timeout handling
|
||||
- Request timeout handling
|
||||
|
||||
**Basic Usage**:
|
||||
```typescript
|
||||
@ -97,12 +96,6 @@ const topics = await dataApiService.get('/topics')
|
||||
const newTopic = await dataApiService.post('/topics', {
|
||||
body: { title: 'Hello', content: 'World' }
|
||||
})
|
||||
|
||||
// Batch operations
|
||||
const responses = await dataApiService.batch([
|
||||
{ method: 'GET', path: '/topics' },
|
||||
{ method: 'GET', path: '/messages' }
|
||||
])
|
||||
```
|
||||
|
||||
### PreferenceService
|
||||
|
||||
@ -252,7 +252,6 @@ export const mockPreferenceDefaults: Record<string, any> = {
|
||||
### 功能特性
|
||||
|
||||
- **完整HTTP支持**: GET, POST, PUT, PATCH, DELETE
|
||||
- **批量操作**: batch() 和 transaction() 支持
|
||||
- **订阅系统**: subscribe/unsubscribe 模拟
|
||||
- **连接管理**: connect/disconnect/ping 方法
|
||||
- **智能模拟数据**: 基于路径自动生成合理的响应
|
||||
|
||||
Loading…
Reference in New Issue
Block a user