@onchaindb/sdk 0.4.5 → 2.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (117) hide show
  1. package/.claude/settings.local.json +10 -2
  2. package/README.md +422 -355
  3. package/dist/batch.d.ts +1 -10
  4. package/dist/batch.d.ts.map +1 -1
  5. package/dist/batch.js +4 -26
  6. package/dist/batch.js.map +1 -1
  7. package/dist/client.d.ts +31 -46
  8. package/dist/client.d.ts.map +1 -1
  9. package/dist/client.js +222 -357
  10. package/dist/client.js.map +1 -1
  11. package/dist/database.d.ts +14 -131
  12. package/dist/database.d.ts.map +1 -1
  13. package/dist/database.js +35 -131
  14. package/dist/database.js.map +1 -1
  15. package/dist/index.d.ts +10 -13
  16. package/dist/index.d.ts.map +1 -1
  17. package/dist/index.js +4 -18
  18. package/dist/index.js.map +1 -1
  19. package/dist/query-sdk/ConditionBuilder.d.ts +3 -11
  20. package/dist/query-sdk/ConditionBuilder.d.ts.map +1 -1
  21. package/dist/query-sdk/ConditionBuilder.js +10 -48
  22. package/dist/query-sdk/ConditionBuilder.js.map +1 -1
  23. package/dist/query-sdk/NestedBuilders.d.ts +33 -30
  24. package/dist/query-sdk/NestedBuilders.d.ts.map +1 -1
  25. package/dist/query-sdk/NestedBuilders.js +46 -43
  26. package/dist/query-sdk/NestedBuilders.js.map +1 -1
  27. package/{src/query-sdk/dist/OnChainDB.d.ts → dist/query-sdk/OnDB.d.ts} +10 -2
  28. package/dist/query-sdk/OnDB.d.ts.map +1 -0
  29. package/{src/query-sdk/dist/OnChainDB.js → dist/query-sdk/OnDB.js} +86 -18
  30. package/dist/query-sdk/OnDB.js.map +1 -0
  31. package/dist/query-sdk/QueryBuilder.d.ts +4 -2
  32. package/dist/query-sdk/QueryBuilder.d.ts.map +1 -1
  33. package/dist/query-sdk/QueryBuilder.js +47 -169
  34. package/dist/query-sdk/QueryBuilder.js.map +1 -1
  35. package/dist/query-sdk/QueryResult.d.ts +0 -38
  36. package/dist/query-sdk/QueryResult.d.ts.map +1 -1
  37. package/dist/query-sdk/QueryResult.js +1 -227
  38. package/dist/query-sdk/QueryResult.js.map +1 -1
  39. package/dist/query-sdk/index.d.ts +2 -2
  40. package/dist/query-sdk/index.d.ts.map +1 -1
  41. package/dist/query-sdk/index.js +3 -3
  42. package/dist/query-sdk/index.js.map +1 -1
  43. package/dist/query-sdk/operators.d.ts +32 -28
  44. package/dist/query-sdk/operators.d.ts.map +1 -1
  45. package/dist/query-sdk/operators.js +45 -155
  46. package/dist/query-sdk/operators.js.map +1 -1
  47. package/dist/types.d.ts +159 -36
  48. package/dist/types.d.ts.map +1 -1
  49. package/dist/types.js +8 -8
  50. package/dist/types.js.map +1 -1
  51. package/dist/x402/types.d.ts +1 -1
  52. package/dist/x402/types.d.ts.map +1 -1
  53. package/dist/x402/utils.js +2 -2
  54. package/dist/x402/utils.js.map +1 -1
  55. package/jest.config.js +4 -0
  56. package/package.json +1 -1
  57. package/skills.md +0 -1
  58. package/src/batch.d.ts +3 -3
  59. package/src/batch.js +1 -1
  60. package/src/client.ts +287 -823
  61. package/src/database.d.ts +1 -1
  62. package/src/database.js +4 -4
  63. package/src/database.ts +71 -494
  64. package/src/index.d.ts +18 -18
  65. package/src/index.js +16 -16
  66. package/src/index.ts +44 -198
  67. package/src/query-sdk/ConditionBuilder.ts +37 -89
  68. package/src/query-sdk/NestedBuilders.ts +90 -92
  69. package/src/query-sdk/{OnChainDB.ts → OnDB.ts} +1 -1
  70. package/src/query-sdk/QueryBuilder.ts +59 -218
  71. package/src/query-sdk/QueryResult.ts +4 -330
  72. package/src/query-sdk/README.md +218 -587
  73. package/src/query-sdk/index.ts +2 -2
  74. package/src/query-sdk/operators.ts +91 -200
  75. package/src/query-sdk/tests/FieldConditionBuilder.test.ts +70 -71
  76. package/src/query-sdk/tests/LogicalOperator.test.ts +43 -82
  77. package/src/query-sdk/tests/NestedBuilders.test.ts +229 -309
  78. package/src/query-sdk/tests/QueryBuilder.test.ts +5 -5
  79. package/src/query-sdk/tests/QueryResult.test.ts +41 -435
  80. package/src/query-sdk/tests/comprehensive.test.ts +4 -185
  81. package/src/tests/client-requests.test.ts +280 -0
  82. package/src/tests/client-validation.test.ts +80 -0
  83. package/src/types.d.ts +6 -6
  84. package/src/types.js +8 -8
  85. package/src/types.ts +239 -54
  86. package/src/x402/types.ts +3 -3
  87. package/src/x402/utils.ts +3 -3
  88. package/examples/blob-upload-example.ts +0 -140
  89. package/src/batch.ts +0 -257
  90. package/src/query-sdk/dist/ConditionBuilder.d.ts +0 -22
  91. package/src/query-sdk/dist/ConditionBuilder.js +0 -90
  92. package/src/query-sdk/dist/FieldConditionBuilder.d.ts +0 -1
  93. package/src/query-sdk/dist/FieldConditionBuilder.js +0 -6
  94. package/src/query-sdk/dist/NestedBuilders.d.ts +0 -43
  95. package/src/query-sdk/dist/NestedBuilders.js +0 -144
  96. package/src/query-sdk/dist/QueryBuilder.d.ts +0 -70
  97. package/src/query-sdk/dist/QueryBuilder.js +0 -295
  98. package/src/query-sdk/dist/QueryResult.d.ts +0 -52
  99. package/src/query-sdk/dist/QueryResult.js +0 -293
  100. package/src/query-sdk/dist/SelectionBuilder.d.ts +0 -20
  101. package/src/query-sdk/dist/SelectionBuilder.js +0 -80
  102. package/src/query-sdk/dist/adapters/HttpClientAdapter.d.ts +0 -27
  103. package/src/query-sdk/dist/adapters/HttpClientAdapter.js +0 -170
  104. package/src/query-sdk/dist/index.d.ts +0 -36
  105. package/src/query-sdk/dist/index.js +0 -27
  106. package/src/query-sdk/dist/operators.d.ts +0 -56
  107. package/src/query-sdk/dist/operators.js +0 -289
  108. package/src/query-sdk/dist/tests/setup.d.ts +0 -15
  109. package/src/query-sdk/dist/tests/setup.js +0 -46
  110. package/src/query-sdk/jest.config.js +0 -25
  111. package/src/query-sdk/package.json +0 -46
  112. package/src/query-sdk/tests/aggregations.test.ts +0 -653
  113. package/src/query-sdk/tests/integration.test.ts +0 -608
  114. package/src/query-sdk/tests/operators.test.ts +0 -327
  115. package/src/query-sdk/tests/unit.test.ts +0 -794
  116. package/src/query-sdk/tsconfig.json +0 -26
  117. package/src/query-sdk/yarn.lock +0 -3092
package/src/database.ts CHANGED
@@ -1,66 +1,28 @@
1
- // Database Management Client for OnChainDB SDK
2
- // Provides comprehensive collection and index management capabilities
1
+ // Database Management Client for OnDB SDK
3
2
 
4
- import { AxiosInstance, AxiosError } from 'axios';
5
- import { OnChainDBError } from './types';
6
- import { buildPaymentPayload, encodePaymentHeader } from './x402/utils';
7
- import type { X402PaymentRequirement } from './x402/types';
8
-
9
- // Database Management Types
10
- export interface Collection {
11
- name: string;
12
- schema?: CollectionSchema;
13
- indexes?: Index[];
14
- metadata?: CollectionMetadata;
15
- }
16
-
17
- export interface CollectionSchema {
18
- fields: { [fieldName: string]: FieldDefinition };
19
- required?: string[];
20
- relationships?: Relationship[];
21
- }
22
-
23
- export interface FieldDefinition {
24
- type: 'string' | 'number' | 'boolean' | 'date' | 'object' | 'array';
25
- index?: boolean;
26
- unique?: boolean;
27
- required?: boolean;
28
- default?: any;
29
- validation?: FieldValidation;
30
- }
31
-
32
- export interface FieldValidation {
33
- min?: number;
34
- max?: number;
35
- pattern?: string;
36
- enum?: any[];
37
- custom?: (value: any) => boolean | string;
38
- }
39
-
40
- export interface Relationship {
41
- type: 'one-to-one' | 'one-to-many' | 'many-to-many';
42
- collection: string;
43
- localField: string;
44
- foreignField: string;
45
- cascade?: boolean;
46
- }
3
+ import { AxiosInstance } from 'axios';
4
+ import {
5
+ OnDBError,
6
+ SqlCreateViewRequest,
7
+ ViewDataResponse,
8
+ ViewQueryRequest,
9
+ CreateApiCollectionRequest,
10
+ } from './types';
47
11
 
48
12
  export interface Index {
49
13
  name: string;
50
14
  collection: string;
51
15
  field_name: string;
52
16
  index_type: 'btree' | 'hash' | 'fulltext' | 'composite' | 'price';
53
- fields?: string[]; // For composite indexes
17
+ fields?: string[];
54
18
  options?: IndexOptions;
55
- price_config?: PriceConfig; // For price-based payment splits
56
- status?: IndexStatus;
57
- statistics?: IndexStatistics;
19
+ price_config?: PriceConfig;
58
20
  }
59
21
 
60
22
  export interface PriceConfig {
61
- app_owner_percentage: number; // e.g., 0.80 for 80%
62
- platform_percentage: number; // e.g., 0.20 for 20%
63
- app_owner_address: string; // Wallet to receive app owner share
23
+ app_owner_percentage: number;
24
+ platform_percentage: number;
25
+ app_owner_address: string;
64
26
  }
65
27
 
66
28
  export interface IndexOptions {
@@ -73,62 +35,6 @@ export interface IndexOptions {
73
35
  defaultLanguage?: string;
74
36
  }
75
37
 
76
- export interface IndexStatus {
77
- building: boolean;
78
- progress?: number;
79
- error?: string;
80
- created_at?: string;
81
- completed_at?: string;
82
- }
83
-
84
- export interface IndexStatistics {
85
- size: number;
86
- usage_count: number;
87
- last_used?: string;
88
- efficiency_score?: number;
89
- memory_usage?: number;
90
- }
91
-
92
- export interface CollectionMetadata {
93
- created_at: string;
94
- updated_at: string;
95
- document_count: number;
96
- storage_size: number;
97
- avg_document_size: number;
98
- }
99
-
100
- export interface DatabaseStats {
101
- total_collections: number;
102
- total_indexes: number;
103
- total_documents: number;
104
- storage_size: number;
105
- index_size: number;
106
- active_connections: number;
107
- }
108
-
109
- export interface QueryPlan {
110
- query: any;
111
- indexes_used: string[];
112
- estimated_cost: number;
113
- execution_time_estimate: number;
114
- optimization_hints: string[];
115
- }
116
-
117
- export interface BatchOperation {
118
- operation: 'create' | 'update' | 'delete';
119
- collection: string;
120
- data: any;
121
- conditions?: any;
122
- }
123
-
124
- export interface BatchResult {
125
- success: boolean;
126
- operation: string;
127
- collection: string;
128
- result?: any;
129
- error?: string;
130
- }
131
-
132
38
  // Materialized View Types
133
39
  export interface MaterializedView {
134
40
  name: string;
@@ -147,217 +53,49 @@ export interface ListViewsResponse {
147
53
  views: ViewInfo[];
148
54
  }
149
55
 
150
- /**
151
- * Comprehensive database management client for OnChainDB
152
- *
153
- * Provides full CRUD operations for collections, indexes, and schemas
154
- * with advanced features like query planning, batch operations, and statistics
155
- */
156
56
  export class DatabaseManager {
157
57
  constructor(
158
58
  private httpClient: AxiosInstance,
159
- private serverUrl: string,
160
59
  private appId: string,
161
60
  private apiKey?: string
162
61
  ) {}
163
62
 
164
63
  // ==================== Index Management ====================
165
64
 
166
- /**
167
- * Create a new index on a collection with x402 payment support
168
- *
169
- * Index creation is currently FREE but this method handles 402 responses
170
- * in case payment is required in the future.
171
- *
172
- * @param indexDefinition - Index definition without status/statistics
173
- * @param paymentOptions - Optional payment configuration (for future use)
174
- * @returns Created index
175
- */
176
- async createIndex(
177
- indexDefinition: Omit<Index, 'status' | 'statistics'>,
178
- paymentOptions?: {
179
- userWallet?: any;
180
- }
181
- ): Promise<Index> {
182
- const endpoint = `/api/apps/${this.appId}/indexes`;
183
-
184
- try {
185
- // First attempt - server will return 402 if payment required
186
- const response = await this.httpClient.post(
187
- endpoint,
188
- indexDefinition,
189
- { headers: this.getHeaders() }
190
- );
191
- return response.data;
192
- } catch (error) {
193
- const axiosError = error as AxiosError;
194
-
195
- // Handle 402 Payment Required (for future use when payment is enabled)
196
- if (axiosError.response?.status === 402) {
197
- if (!paymentOptions?.userWallet) {
198
- throw new OnChainDBError(
199
- 'Payment required but no wallet provided. Pass userWallet in paymentOptions.',
200
- 'PAYMENT_REQUIRED'
201
- );
202
- }
203
-
204
- console.log('[x402] Payment required for index creation');
205
-
206
- // Parse payment requirement from response
207
- const paymentData = axiosError.response.data as any;
208
- const accepts = paymentData?.accepts;
209
-
210
- if (!accepts || accepts.length === 0) {
211
- throw new OnChainDBError('Invalid 402 response: no payment options', 'PAYMENT_ERROR');
212
- }
213
-
214
- // Use first accepted payment option (native TIA)
215
- const requirement: X402PaymentRequirement = accepts[0];
216
- const amountUtia = parseInt(requirement.maxAmountRequired || '0', 10);
217
- const brokerAddress = requirement.payTo;
218
-
219
- console.log(`[x402] Index creation cost: ${amountUtia} utia to ${brokerAddress}`);
220
-
221
- // Execute payment via wallet
222
- const paymentResult = await paymentOptions.userWallet.signAndBroadcast(
223
- brokerAddress,
224
- `${amountUtia}utia`,
225
- `OnChainDB index creation - ${indexDefinition.field_name}`
226
- );
227
-
228
- if (!paymentResult.success) {
229
- throw new OnChainDBError(`Payment failed: ${paymentResult.error}`, 'PAYMENT_ERROR');
230
- }
231
-
232
- console.log(`[x402] Payment successful: ${paymentResult.txHash}`);
233
-
234
- // Build X-PAYMENT header and retry
235
- const x402Payload = buildPaymentPayload(requirement, {
236
- txHash: paymentResult.txHash,
237
- network: requirement.network,
238
- sender: paymentResult.sender || '',
239
- chainType: 'cosmos',
240
- paymentMethod: 'native'
241
- });
242
- const encodedPayment = encodePaymentHeader(x402Payload);
243
-
244
- const retryResponse = await this.httpClient.post(
245
- endpoint,
246
- indexDefinition,
247
- {
248
- headers: {
249
- ...this.getHeaders(),
250
- 'X-PAYMENT': encodedPayment
251
- }
252
- }
253
- );
254
-
255
- return retryResponse.data;
256
- }
257
-
258
- // Re-throw other errors
259
- throw error;
260
- }
65
+ async listIndexes(): Promise<Index[]> {
66
+ const response = await this.httpClient.get(
67
+ `/api/apps/${this.appId}/indexes`,
68
+ { headers: this.getHeaders() }
69
+ );
70
+ return response.data;
71
+ }
72
+
73
+ async createIndex(indexDefinition: Omit<Index, 'status' | 'statistics'>): Promise<Index> {
74
+ const response = await this.httpClient.post(
75
+ `/api/apps/${this.appId}/indexes`,
76
+ indexDefinition,
77
+ { headers: this.getHeaders() }
78
+ );
79
+ return response.data;
261
80
  }
262
81
 
263
- /**
264
- * Create multiple indexes in a batch operation
265
- */
266
82
  async createIndexes(
267
83
  collection: string,
268
84
  indexes: Omit<Index, 'collection' | 'status' | 'statistics'>[]
269
85
  ): Promise<Index[]> {
270
- // Since batch endpoint doesn't exist, create indexes individually
271
86
  const results: Index[] = [];
272
-
273
87
  for (const indexDef of indexes) {
274
88
  const result = await this.createIndex({ ...indexDef, collection });
275
89
  results.push(result);
276
90
  }
277
-
278
91
  return results;
279
92
  }
280
93
 
281
- /**
282
- * List all indexes for a collection or entire application
283
- */
284
- async listIndexes(collection?: string, includeStats?: boolean): Promise<Index[]> {
285
- const endpoint = collection
286
- ? `/api/apps/${this.appId}/collections/${collection}/indexes`
287
- : `/api/apps/${this.appId}/indexes`;
288
-
289
- const params = includeStats ? { include_stats: true } : {};
290
-
291
- const response = await this.httpClient.get(endpoint, {
292
- params,
293
- headers: this.getHeaders()
294
- });
295
-
296
- return response.data;
297
- }
298
-
299
- /**
300
- * Get detailed information about a specific index
301
- */
302
- async getIndex(collection: string, indexName: string): Promise<Index> {
303
- const response = await this.httpClient.get(
304
- `/api/apps/${this.appId}/collections/${collection}/indexes/${indexName}`,
305
- { headers: this.getHeaders() }
306
- );
307
-
308
- return response.data;
309
- }
310
-
311
- /**
312
- * Check the status of index building operations
313
- */
314
- async getIndexStatus(collection: string, indexName: string): Promise<IndexStatus> {
315
- const response = await this.httpClient.get(
316
- `/api/apps/${this.appId}/collections/${collection}/indexes/${indexName}/status`,
317
- { headers: this.getHeaders() }
318
- );
319
-
320
- return response.data;
321
- }
322
-
323
- /**
324
- * Get index performance statistics
325
- */
326
- async getIndexStatistics(collection: string, indexName: string): Promise<IndexStatistics> {
327
- const response = await this.httpClient.get(
328
- `/api/apps/${this.appId}/collections/${collection}/indexes/${indexName}/statistics`,
329
- { headers: this.getHeaders() }
330
- );
331
-
332
- return response.data;
333
- }
334
-
335
- /**
336
- * Rebuild an existing index
337
- */
338
- async rebuildIndex(
339
- collection: string,
340
- indexName: string,
341
- options?: { background?: boolean }
342
- ): Promise<{ success: boolean; message: string }> {
343
- const response = await this.httpClient.post(
344
- `/api/apps/${this.appId}/collections/${collection}/indexes/${indexName}/rebuild`,
345
- options || {},
346
- { headers: this.getHeaders() }
347
- );
348
-
349
- return response.data;
350
- }
351
-
352
- /**
353
- * Drop/delete an index
354
- */
355
- async dropIndex(collection: string, indexName: string): Promise<{ success: boolean; message: string }> {
94
+ async dropIndex(indexId: string): Promise<{ success: boolean; message: string }> {
356
95
  const response = await this.httpClient.delete(
357
- `/api/apps/${this.appId}/collections/${collection}/indexes/${indexName}`,
96
+ `/api/apps/${this.appId}/indexes/${indexId}`,
358
97
  { headers: this.getHeaders() }
359
98
  );
360
-
361
99
  return response.data;
362
100
  }
363
101
 
@@ -367,28 +105,13 @@ export class DatabaseManager {
367
105
  * Price indexes enable automatic payment splits when writing to collections.
368
106
  * Perfect for order/purchase collections where you want to charge based on item price.
369
107
  *
370
- * @param collection - Collection name (e.g., 'orders')
371
- * @param fieldName - Price field name (e.g., 'total_price')
372
- * @param config - Optional payment split configuration
373
- * @returns Created index
374
- *
375
108
  * @example
376
109
  * ```typescript
377
- * // Create price index on orders collection
378
- * await db.createPriceIndex('orders', 'total_price', {
379
- * app_owner_percentage: 0.80, // 80% to merchant
380
- * platform_percentage: 0.20, // 20% to platform
110
+ * await db.database().createPriceIndex('orders', 'total_price', {
111
+ * app_owner_percentage: 0.80,
112
+ * platform_percentage: 0.20,
381
113
  * app_owner_address: 'celestia1abc...'
382
114
  * });
383
- *
384
- * // Now when writing orders, price field triggers automatic split:
385
- * await client.store({
386
- * collection: 'orders',
387
- * data: {
388
- * order_id: '123',
389
- * total_price: 100 // 80 TIA to merchant, 20 TIA to platform
390
- * }
391
- * });
392
115
  * ```
393
116
  */
394
117
  async createPriceIndex(
@@ -411,285 +134,139 @@ export class DatabaseManager {
411
134
  });
412
135
  }
413
136
 
414
- // ==================== Schema Management ====================
415
-
416
- /**
417
- * Validate data against collection schema
418
- */
419
- async validateSchema(collection: string, data: any): Promise<{ valid: boolean; errors?: string[] }> {
420
- const response = await this.httpClient.post(
421
- `/api/apps/${this.appId}/collections/${collection}/validate`,
422
- { data },
423
- { headers: this.getHeaders() }
424
- );
425
-
426
- return response.data;
427
- }
428
-
429
- /**
430
- * Migrate collection data to new schema
431
- */
432
- async migrateSchema(
433
- collection: string,
434
- newSchema: CollectionSchema,
435
- options?: { dryRun?: boolean; batchSize?: number }
436
- ): Promise<{ success: boolean; migrated: number; errors?: any[] }> {
437
- const payload = { schema: newSchema, ...options };
137
+ // ==================== Materialized Views ====================
438
138
 
139
+ async createViewSql(sql: string, refreshMode?: 'live' | 'lazy'): Promise<MaterializedView> {
140
+ const body: SqlCreateViewRequest = { sql };
141
+ if (refreshMode) body.refresh_mode = refreshMode;
439
142
  const response = await this.httpClient.post(
440
- `/api/apps/${this.appId}/collections/${collection}/migrate`,
441
- payload,
143
+ `/apps/${this.appId}/views/sql`,
144
+ body,
442
145
  { headers: this.getHeaders() }
443
146
  );
444
-
445
147
  return response.data;
446
148
  }
447
149
 
448
- // ==================== Query Planning and Optimization ====================
449
-
450
- /**
451
- * Explain query execution plan
452
- */
453
- async explainQuery(collection: string, query: any): Promise<QueryPlan> {
150
+ async queryView<T = any>(viewName: string, query: ViewQueryRequest = {}): Promise<ViewDataResponse<T>> {
454
151
  const response = await this.httpClient.post(
455
- `/api/apps/${this.appId}/collections/${collection}/explain`,
456
- { query },
152
+ `/api/views/${this.appId}/${viewName}/data`,
153
+ query,
457
154
  { headers: this.getHeaders() }
458
155
  );
459
-
460
156
  return response.data;
461
157
  }
462
158
 
463
- /**
464
- * Get optimization suggestions for query performance
465
- */
466
- async getOptimizationSuggestions(collection: string): Promise<{
467
- missing_indexes: string[];
468
- unused_indexes: string[];
469
- slow_queries: any[];
470
- recommendations: string[];
471
- }> {
159
+ async countView(viewName: string, filter?: any): Promise<number> {
160
+ const params = filter ? { filter: JSON.stringify(filter) } : {};
472
161
  const response = await this.httpClient.get(
473
- `/api/apps/${this.appId}/collections/${collection}/optimize`,
474
- { headers: this.getHeaders() }
162
+ `/api/views/${this.appId}/${viewName}/count`,
163
+ { params, headers: this.getHeaders() }
475
164
  );
476
-
477
- return response.data;
165
+ return response.data?.count ?? response.data;
478
166
  }
479
167
 
480
- // ==================== Batch Operations ====================
481
-
482
- /**
483
- * Execute multiple database operations in a single transaction
484
- */
485
- async executeBatch(operations: BatchOperation[]): Promise<BatchResult[]> {
486
- const response = await this.httpClient.post(
487
- `/api/apps/${this.appId}/batch`,
488
- { operations },
489
- { headers: this.getHeaders() }
490
- );
491
-
492
- return response.data;
493
- }
494
-
495
- // ==================== Materialized Views Management ====================
496
-
497
- /**
498
- * Create a materialized view
499
- *
500
- * Materialized views are pre-computed query results that update automatically
501
- * when source data changes. Great for complex aggregations and joins.
502
- *
503
- * @param name - Unique name for the view
504
- * @param sourceCollections - Collections this view depends on
505
- * @param query - Query definition for the view
506
- * @returns Created view definition
507
- *
508
- * @example
509
- * ```typescript
510
- * // Create a view for top-selling products
511
- * await db.createView('topSellers', ['products', 'orders'], {
512
- * select: ['id', 'name', 'price', 'salesCount'],
513
- * where: { status: 'active' },
514
- * orderBy: { salesCount: 'desc' },
515
- * limit: 100
516
- * });
517
- * ```
518
- */
519
168
  async createView(
520
169
  name: string,
521
170
  sourceCollections: string[],
522
171
  query: any
523
172
  ): Promise<MaterializedView> {
524
- const payload = {
525
- name,
526
- source_collections: sourceCollections,
527
- query
528
- };
529
-
530
173
  const response = await this.httpClient.post(
531
174
  `/apps/${this.appId}/views`,
532
- payload,
175
+ { name, source_collections: sourceCollections, query },
533
176
  { headers: this.getHeaders() }
534
177
  );
535
-
536
178
  return response.data;
537
179
  }
538
180
 
539
- /**
540
- * List all materialized views for the app
541
- */
542
181
  async listViews(): Promise<ViewInfo[]> {
543
182
  const response = await this.httpClient.get(
544
183
  `/apps/${this.appId}/views`,
545
184
  { headers: this.getHeaders() }
546
185
  );
547
-
548
186
  return response.data.views || response.data;
549
187
  }
550
188
 
551
- /**
552
- * Get a specific materialized view
553
- */
554
189
  async getView(name: string): Promise<MaterializedView> {
555
190
  const response = await this.httpClient.get(
556
191
  `/apps/${this.appId}/views/${name}`,
557
192
  { headers: this.getHeaders() }
558
193
  );
559
-
560
194
  return response.data;
561
195
  }
562
196
 
563
- /**
564
- * Delete a materialized view
565
- */
566
197
  async deleteView(name: string): Promise<{ success: boolean; message: string }> {
567
198
  const response = await this.httpClient.delete(
568
199
  `/apps/${this.appId}/views/${name}`,
569
200
  { headers: this.getHeaders() }
570
201
  );
571
-
572
202
  return response.data;
573
203
  }
574
204
 
575
- /**
576
- * Refresh/rebuild a materialized view
577
- */
578
205
  async refreshView(name: string): Promise<{ success: boolean; message: string }> {
579
206
  const response = await this.httpClient.post(
580
207
  `/apps/${this.appId}/views/${name}/refresh`,
581
208
  {},
582
209
  { headers: this.getHeaders() }
583
210
  );
584
-
585
211
  return response.data;
586
212
  }
587
213
 
588
- // ==================== Statistics and Monitoring ====================
214
+ // ==================== API Collections ====================
589
215
 
590
- /**
591
- * Get overall database statistics
592
- */
593
- async getDatabaseStats(): Promise<DatabaseStats> {
216
+ async listApiCollections(): Promise<any[]> {
594
217
  const response = await this.httpClient.get(
595
- `/api/apps/${this.appId}/stats`,
218
+ `/apps/${this.appId}/api_collections`,
596
219
  { headers: this.getHeaders() }
597
220
  );
221
+ return response.data;
222
+ }
598
223
 
224
+ async createApiCollection(request: CreateApiCollectionRequest): Promise<any> {
225
+ const response = await this.httpClient.post(
226
+ `/apps/${this.appId}/api_collections`,
227
+ request,
228
+ { headers: this.getHeaders() }
229
+ );
599
230
  return response.data;
600
231
  }
601
232
 
602
- /**
603
- * Get collection-specific statistics
604
- */
605
- async getCollectionStats(collection: string): Promise<CollectionMetadata> {
233
+ async getApiCollection(collectionName: string): Promise<any> {
606
234
  const response = await this.httpClient.get(
607
- `/api/apps/${this.appId}/collections/${collection}/stats`,
235
+ `/apps/${this.appId}/api_collections/${collectionName}`,
608
236
  { headers: this.getHeaders() }
609
237
  );
610
-
611
238
  return response.data;
612
239
  }
613
240
 
614
- // ==================== Utility Methods ====================
615
-
616
- /**
617
- * Test database connection and basic functionality
618
- */
619
- async healthCheck(): Promise<{
620
- healthy: boolean;
621
- response_time: number;
622
- version: string;
623
- features: string[];
624
- }> {
625
- const startTime = Date.now();
626
-
627
- try {
628
- const response = await this.httpClient.get(
629
- `/api/apps/${this.appId}/health`,
630
- { headers: this.getHeaders() }
631
- );
632
-
633
- const responseTime = Date.now() - startTime;
634
-
635
- return {
636
- healthy: true,
637
- response_time: responseTime,
638
- version: response.data.version || '1.0.0',
639
- features: response.data.features || []
640
- };
641
- } catch (error) {
642
- return {
643
- healthy: false,
644
- response_time: Date.now() - startTime,
645
- version: 'unknown',
646
- features: []
647
- };
648
- }
241
+ async deleteApiCollection(collectionName: string): Promise<{ success: boolean }> {
242
+ const response = await this.httpClient.delete(
243
+ `/apps/${this.appId}/api_collections/${collectionName}`,
244
+ { headers: this.getHeaders() }
245
+ );
246
+ return response.data;
649
247
  }
650
248
 
651
- /**
652
- * Get API headers including authentication
653
- */
249
+ // ==================== Utility ====================
250
+
654
251
  private getHeaders(): { [key: string]: string } {
655
252
  const headers: { [key: string]: string } = {
656
253
  'Content-Type': 'application/json'
657
254
  };
658
-
659
255
  if (this.apiKey) {
660
256
  headers['Authorization'] = `Bearer ${this.apiKey}`;
661
257
  }
662
-
663
258
  return headers;
664
259
  }
665
260
 
666
- /**
667
- * Set API key for authenticated operations
668
- */
669
261
  setApiKey(apiKey: string): void {
670
262
  this.apiKey = apiKey;
671
263
  }
672
-
673
- /**
674
- * Update server configuration
675
- */
676
- updateConfig(httpClient: AxiosInstance, serverUrl: string, appId: string): void {
677
- this.httpClient = httpClient;
678
- this.serverUrl = serverUrl;
679
- this.appId = appId;
680
- }
681
264
  }
682
265
 
683
- /**
684
- * Factory function to create a DatabaseManager instance
685
- */
686
266
  export function createDatabaseManager(
687
267
  httpClient: AxiosInstance,
688
- serverUrl: string,
689
268
  appId: string,
690
269
  apiKey?: string
691
270
  ): DatabaseManager {
692
- return new DatabaseManager(httpClient, serverUrl, appId, apiKey);
271
+ return new DatabaseManager(httpClient, appId, apiKey);
693
272
  }
694
-
695
- // Types are available as imports, no need to re-export