@robosystems/client 0.2.15 → 0.2.16

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 (37) hide show
  1. package/extensions/FileClient.d.ts +57 -0
  2. package/extensions/{TableIngestClient.js → FileClient.js} +55 -77
  3. package/extensions/{TableIngestClient.ts → FileClient.ts} +67 -122
  4. package/extensions/MaterializationClient.d.ts +51 -0
  5. package/extensions/MaterializationClient.js +107 -0
  6. package/extensions/MaterializationClient.ts +163 -0
  7. package/extensions/TableClient.d.ts +38 -0
  8. package/extensions/TableClient.js +92 -0
  9. package/extensions/TableClient.ts +132 -0
  10. package/extensions/hooks.d.ts +9 -11
  11. package/extensions/hooks.js +21 -56
  12. package/extensions/hooks.ts +30 -79
  13. package/extensions/index.d.ts +14 -4
  14. package/extensions/index.js +32 -5
  15. package/extensions/index.test.ts +10 -2
  16. package/extensions/index.ts +46 -5
  17. package/package.json +1 -1
  18. package/sdk-extensions/FileClient.d.ts +57 -0
  19. package/sdk-extensions/{TableIngestClient.js → FileClient.js} +55 -77
  20. package/sdk-extensions/{TableIngestClient.ts → FileClient.ts} +67 -122
  21. package/sdk-extensions/MaterializationClient.d.ts +51 -0
  22. package/sdk-extensions/MaterializationClient.js +107 -0
  23. package/sdk-extensions/MaterializationClient.ts +163 -0
  24. package/sdk-extensions/TableClient.d.ts +38 -0
  25. package/sdk-extensions/TableClient.js +92 -0
  26. package/sdk-extensions/TableClient.ts +132 -0
  27. package/sdk-extensions/hooks.d.ts +9 -11
  28. package/sdk-extensions/hooks.js +21 -56
  29. package/sdk-extensions/hooks.ts +30 -79
  30. package/sdk-extensions/index.d.ts +14 -4
  31. package/sdk-extensions/index.js +32 -5
  32. package/sdk-extensions/index.test.ts +10 -2
  33. package/sdk-extensions/index.ts +46 -5
  34. package/extensions/TableIngestClient.d.ts +0 -75
  35. package/extensions/TableIngestClient.test.ts +0 -304
  36. package/sdk-extensions/TableIngestClient.d.ts +0 -75
  37. package/sdk-extensions/TableIngestClient.test.ts +0 -304
@@ -1,304 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest'
2
- import { TableIngestClient } from './TableIngestClient'
3
-
4
- // Helper to create proper mock Response objects
5
- function createMockResponse(data: any, options: { ok?: boolean; status?: number } = {}) {
6
- return {
7
- ok: options.ok ?? true,
8
- status: options.status ?? 200,
9
- statusText: options.status === 200 ? 'OK' : 'Error',
10
- headers: new Headers({ 'content-type': 'application/json' }),
11
- json: async () => data,
12
- text: async () => JSON.stringify(data),
13
- blob: async () => new Blob([JSON.stringify(data)]),
14
- arrayBuffer: async () => new TextEncoder().encode(JSON.stringify(data)).buffer,
15
- }
16
- }
17
-
18
- describe('TableIngestClient', () => {
19
- let tableClient: TableIngestClient
20
- let mockFetch: any
21
-
22
- beforeEach(() => {
23
- tableClient = new TableIngestClient({
24
- baseUrl: 'http://localhost:8000',
25
- headers: { 'X-API-Key': 'test-key' },
26
- })
27
-
28
- // Mock global fetch
29
- mockFetch = vi.fn()
30
- global.fetch = mockFetch
31
-
32
- // Reset all mocks
33
- vi.clearAllMocks()
34
- })
35
-
36
- describe('uploadParquetFile', () => {
37
- it('should upload a Buffer successfully', async () => {
38
- mockFetch
39
- // 1. Get upload URL
40
- .mockResolvedValueOnce(
41
- createMockResponse({
42
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
43
- file_id: 'file_123',
44
- })
45
- )
46
- // 2. S3 upload
47
- .mockResolvedValueOnce(createMockResponse(null))
48
- // 3. Update metadata
49
- .mockResolvedValueOnce(createMockResponse({ success: true }))
50
-
51
- const buffer = Buffer.from('test parquet data')
52
- const result = await tableClient.uploadParquetFile('graph_123', 'Entity', buffer, {
53
- fileName: 'test.parquet',
54
- })
55
-
56
- expect(result.success).toBe(true)
57
- expect(result.fileId).toBe('file_123')
58
- expect(result.tableName).toBe('Entity')
59
- expect(result.fileName).toBe('test.parquet')
60
- expect(mockFetch).toHaveBeenCalledTimes(3)
61
- })
62
-
63
- it('should handle upload URL fetch failure', async () => {
64
- mockFetch.mockResolvedValueOnce(
65
- createMockResponse({ detail: 'Failed to get upload URL' }, { ok: false, status: 500 })
66
- )
67
-
68
- const buffer = Buffer.from('test data')
69
- const result = await tableClient.uploadParquetFile('graph_123', 'Entity', buffer)
70
-
71
- expect(result.success).toBe(false)
72
- expect(result.error).toBeDefined()
73
- })
74
-
75
- it('should handle S3 upload failure', async () => {
76
- mockFetch
77
- // Get upload URL succeeds
78
- .mockResolvedValueOnce(
79
- createMockResponse({
80
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
81
- file_id: 'file_123',
82
- })
83
- )
84
- // S3 upload fails
85
- .mockResolvedValueOnce(createMockResponse(null, { ok: false, status: 500 }))
86
-
87
- const buffer = Buffer.from('test data')
88
- const result = await tableClient.uploadParquetFile('graph_123', 'Entity', buffer)
89
-
90
- expect(result.success).toBe(false)
91
- expect(result.error).toContain('S3 upload failed')
92
- expect(result.error).toContain('500')
93
- })
94
-
95
- it('should fix LocalStack URLs when enabled', async () => {
96
- mockFetch
97
- .mockResolvedValueOnce(
98
- createMockResponse({
99
- upload_url: 'http://localstack:4566/bucket/file.parquet',
100
- file_id: 'file_123',
101
- })
102
- )
103
- .mockResolvedValueOnce(createMockResponse(null))
104
- .mockResolvedValueOnce(createMockResponse({ success: true }))
105
-
106
- const buffer = Buffer.from('test data')
107
- await tableClient.uploadParquetFile('graph_123', 'Entity', buffer, {
108
- fixLocalStackUrl: true,
109
- })
110
-
111
- // Check that the S3 upload (2nd call) used the fixed URL
112
- const s3Call = mockFetch.mock.calls[1]
113
- expect(s3Call[0]).toBe('http://localhost:4566/bucket/file.parquet')
114
- })
115
-
116
- it('should call progress callback', async () => {
117
- mockFetch
118
- .mockResolvedValueOnce(
119
- createMockResponse({
120
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
121
- file_id: 'file_123',
122
- })
123
- )
124
- .mockResolvedValueOnce(createMockResponse(null))
125
- .mockResolvedValueOnce(createMockResponse({ success: true }))
126
-
127
- const progressMessages: string[] = []
128
- const buffer = Buffer.from('test data')
129
-
130
- await tableClient.uploadParquetFile('graph_123', 'Entity', buffer, {
131
- onProgress: (msg) => progressMessages.push(msg),
132
- })
133
-
134
- expect(progressMessages.length).toBeGreaterThan(0)
135
- expect(progressMessages.some((msg) => msg.includes('Getting upload URL'))).toBe(true)
136
- expect(progressMessages.some((msg) => msg.includes('Uploading'))).toBe(true)
137
- })
138
-
139
- it('should handle metadata update failure', async () => {
140
- mockFetch
141
- .mockResolvedValueOnce(
142
- createMockResponse({
143
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
144
- file_id: 'file_123',
145
- })
146
- )
147
- .mockResolvedValueOnce(createMockResponse(null))
148
- .mockResolvedValueOnce(
149
- createMockResponse({ detail: 'Failed to update' }, { ok: false, status: 500 })
150
- )
151
-
152
- const buffer = Buffer.from('test data')
153
- const result = await tableClient.uploadParquetFile('graph_123', 'Entity', buffer)
154
-
155
- expect(result.success).toBe(false)
156
- expect(result.error).toContain('Failed to complete file upload')
157
- })
158
- })
159
-
160
- describe('listStagingTables', () => {
161
- it('should list staging tables successfully', async () => {
162
- mockFetch.mockResolvedValueOnce(
163
- createMockResponse({
164
- tables: [
165
- {
166
- table_name: 'Entity',
167
- row_count: 1000,
168
- file_count: 2,
169
- total_size_bytes: 5000000,
170
- },
171
- ],
172
- })
173
- )
174
-
175
- const tables = await tableClient.listStagingTables('graph_123')
176
-
177
- expect(tables).toHaveLength(1)
178
- expect(tables[0].tableName).toBe('Entity')
179
- expect(tables[0].rowCount).toBe(1000)
180
- expect(tables[0].fileCount).toBe(2)
181
- expect(tables[0].totalSizeBytes).toBe(5000000)
182
- })
183
-
184
- it('should return empty array on error', async () => {
185
- mockFetch.mockResolvedValueOnce(
186
- createMockResponse({ detail: 'Failed to list tables' }, { ok: false, status: 500 })
187
- )
188
-
189
- const tables = await tableClient.listStagingTables('graph_123')
190
-
191
- expect(tables).toEqual([])
192
- })
193
- })
194
-
195
- describe('ingestAllTables', () => {
196
- it('should ingest tables successfully', async () => {
197
- mockFetch.mockResolvedValueOnce(
198
- createMockResponse({
199
- operation_id: 'op_123',
200
- message: 'Ingestion started',
201
- })
202
- )
203
-
204
- const result = await tableClient.ingestAllTables('graph_123', {
205
- ignoreErrors: true,
206
- rebuild: false,
207
- })
208
-
209
- expect(result.success).toBe(true)
210
- expect(result.operationId).toBe('op_123')
211
- expect(result.message).toBe('Ingestion started')
212
- })
213
-
214
- it('should handle ingestion failure', async () => {
215
- mockFetch.mockResolvedValueOnce(
216
- createMockResponse({ detail: 'Ingestion failed' }, { ok: false, status: 500 })
217
- )
218
-
219
- const result = await tableClient.ingestAllTables('graph_123')
220
-
221
- expect(result.success).toBe(false)
222
- expect(result.error).toBeDefined()
223
- })
224
-
225
- it('should call progress callback', async () => {
226
- mockFetch.mockResolvedValueOnce(
227
- createMockResponse({
228
- operation_id: 'op_123',
229
- message: 'Ingestion started',
230
- })
231
- )
232
-
233
- const progressMessages: string[] = []
234
-
235
- await tableClient.ingestAllTables('graph_123', {
236
- onProgress: (msg) => progressMessages.push(msg),
237
- })
238
-
239
- expect(progressMessages.length).toBeGreaterThan(0)
240
- expect(progressMessages.some((msg) => msg.includes('Starting'))).toBe(true)
241
- expect(progressMessages.some((msg) => msg.includes('completed'))).toBe(true)
242
- })
243
- })
244
-
245
- describe('uploadAndIngest', () => {
246
- it('should upload and ingest in one operation', async () => {
247
- mockFetch
248
- // Upload URL
249
- .mockResolvedValueOnce(
250
- createMockResponse({
251
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
252
- file_id: 'file_123',
253
- })
254
- )
255
- // S3 upload
256
- .mockResolvedValueOnce(createMockResponse(null))
257
- // Update metadata
258
- .mockResolvedValueOnce(createMockResponse({ success: true }))
259
- // Ingest
260
- .mockResolvedValueOnce(createMockResponse({ operation_id: 'op_123' }))
261
-
262
- const buffer = Buffer.from('test data')
263
- const result = await tableClient.uploadAndIngest('graph_123', 'Entity', buffer)
264
-
265
- expect(result.upload.success).toBe(true)
266
- expect(result.ingest?.success).toBe(true)
267
- expect(result.ingest?.operationId).toBe('op_123')
268
- })
269
-
270
- it('should not ingest if upload fails', async () => {
271
- mockFetch.mockResolvedValueOnce(
272
- createMockResponse({ detail: 'Upload failed' }, { ok: false, status: 500 })
273
- )
274
-
275
- const buffer = Buffer.from('test data')
276
- const result = await tableClient.uploadAndIngest('graph_123', 'Entity', buffer)
277
-
278
- expect(result.upload.success).toBe(false)
279
- expect(result.ingest).toBeNull()
280
- // Should only have 1 fetch call (failed upload URL), not the ingest call
281
- expect(mockFetch).toHaveBeenCalledTimes(1)
282
- })
283
- })
284
-
285
- describe('file conversion helpers', () => {
286
- it('should handle File objects', async () => {
287
- mockFetch
288
- .mockResolvedValueOnce(
289
- createMockResponse({
290
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
291
- file_id: 'file_123',
292
- })
293
- )
294
- .mockResolvedValueOnce(createMockResponse(null))
295
- .mockResolvedValueOnce(createMockResponse({ success: true }))
296
-
297
- const file = new File(['test data'], 'test.parquet', { type: 'application/x-parquet' })
298
- const result = await tableClient.uploadParquetFile('graph_123', 'Entity', file)
299
-
300
- expect(result.success).toBe(true)
301
- expect(result.fileName).toBe('test.parquet')
302
- })
303
- })
304
- })
@@ -1,75 +0,0 @@
1
- export interface UploadOptions {
2
- onProgress?: (message: string) => void;
3
- fixLocalStackUrl?: boolean;
4
- fileName?: string;
5
- }
6
- export interface IngestOptions {
7
- ignoreErrors?: boolean;
8
- rebuild?: boolean;
9
- onProgress?: (message: string) => void;
10
- }
11
- export interface UploadResult {
12
- fileId: string;
13
- fileSize: number;
14
- rowCount: number;
15
- tableName: string;
16
- fileName: string;
17
- success: boolean;
18
- error?: string;
19
- }
20
- export interface TableInfo {
21
- tableName: string;
22
- rowCount: number;
23
- fileCount: number;
24
- totalSizeBytes: number;
25
- }
26
- export interface IngestResult {
27
- success: boolean;
28
- operationId?: string;
29
- message?: string;
30
- error?: string;
31
- }
32
- export type FileInput = File | Blob | Buffer | ReadableStream<Uint8Array>;
33
- export declare class TableIngestClient {
34
- private config;
35
- constructor(config: {
36
- baseUrl: string;
37
- credentials?: 'include' | 'same-origin' | 'omit';
38
- headers?: Record<string, string>;
39
- token?: string;
40
- });
41
- /**
42
- * Upload a Parquet file to a staging table
43
- *
44
- * This method handles the complete 3-step upload process:
45
- * 1. Get presigned upload URL
46
- * 2. Upload file to S3
47
- * 3. Mark file as 'uploaded' (backend validates, calculates size/row count)
48
- *
49
- * Supports File (browser), Blob (browser), Buffer (Node.js), and ReadableStream.
50
- */
51
- uploadParquetFile(graphId: string, tableName: string, fileOrBuffer: FileInput, options?: UploadOptions): Promise<UploadResult>;
52
- /**
53
- * List all staging tables in a graph
54
- */
55
- listStagingTables(graphId: string): Promise<TableInfo[]>;
56
- /**
57
- * Ingest all staging tables into the graph
58
- */
59
- ingestAllTables(graphId: string, options?: IngestOptions): Promise<IngestResult>;
60
- /**
61
- * Convenience method to upload a file and immediately ingest it
62
- */
63
- uploadAndIngest(graphId: string, tableName: string, fileOrBuffer: FileInput, uploadOptions?: UploadOptions, ingestOptions?: IngestOptions): Promise<{
64
- upload: UploadResult;
65
- ingest: IngestResult | null;
66
- }>;
67
- /**
68
- * Get file name from input or use provided override
69
- */
70
- private getFileName;
71
- /**
72
- * Convert various file inputs to ArrayBuffer for upload
73
- */
74
- private getFileContent;
75
- }
@@ -1,304 +0,0 @@
1
- import { beforeEach, describe, expect, it, vi } from 'vitest'
2
- import { TableIngestClient } from './TableIngestClient'
3
-
4
- // Helper to create proper mock Response objects
5
- function createMockResponse(data: any, options: { ok?: boolean; status?: number } = {}) {
6
- return {
7
- ok: options.ok ?? true,
8
- status: options.status ?? 200,
9
- statusText: options.status === 200 ? 'OK' : 'Error',
10
- headers: new Headers({ 'content-type': 'application/json' }),
11
- json: async () => data,
12
- text: async () => JSON.stringify(data),
13
- blob: async () => new Blob([JSON.stringify(data)]),
14
- arrayBuffer: async () => new TextEncoder().encode(JSON.stringify(data)).buffer,
15
- }
16
- }
17
-
18
- describe('TableIngestClient', () => {
19
- let tableClient: TableIngestClient
20
- let mockFetch: any
21
-
22
- beforeEach(() => {
23
- tableClient = new TableIngestClient({
24
- baseUrl: 'http://localhost:8000',
25
- headers: { 'X-API-Key': 'test-key' },
26
- })
27
-
28
- // Mock global fetch
29
- mockFetch = vi.fn()
30
- global.fetch = mockFetch
31
-
32
- // Reset all mocks
33
- vi.clearAllMocks()
34
- })
35
-
36
- describe('uploadParquetFile', () => {
37
- it('should upload a Buffer successfully', async () => {
38
- mockFetch
39
- // 1. Get upload URL
40
- .mockResolvedValueOnce(
41
- createMockResponse({
42
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
43
- file_id: 'file_123',
44
- })
45
- )
46
- // 2. S3 upload
47
- .mockResolvedValueOnce(createMockResponse(null))
48
- // 3. Update metadata
49
- .mockResolvedValueOnce(createMockResponse({ success: true }))
50
-
51
- const buffer = Buffer.from('test parquet data')
52
- const result = await tableClient.uploadParquetFile('graph_123', 'Entity', buffer, {
53
- fileName: 'test.parquet',
54
- })
55
-
56
- expect(result.success).toBe(true)
57
- expect(result.fileId).toBe('file_123')
58
- expect(result.tableName).toBe('Entity')
59
- expect(result.fileName).toBe('test.parquet')
60
- expect(mockFetch).toHaveBeenCalledTimes(3)
61
- })
62
-
63
- it('should handle upload URL fetch failure', async () => {
64
- mockFetch.mockResolvedValueOnce(
65
- createMockResponse({ detail: 'Failed to get upload URL' }, { ok: false, status: 500 })
66
- )
67
-
68
- const buffer = Buffer.from('test data')
69
- const result = await tableClient.uploadParquetFile('graph_123', 'Entity', buffer)
70
-
71
- expect(result.success).toBe(false)
72
- expect(result.error).toBeDefined()
73
- })
74
-
75
- it('should handle S3 upload failure', async () => {
76
- mockFetch
77
- // Get upload URL succeeds
78
- .mockResolvedValueOnce(
79
- createMockResponse({
80
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
81
- file_id: 'file_123',
82
- })
83
- )
84
- // S3 upload fails
85
- .mockResolvedValueOnce(createMockResponse(null, { ok: false, status: 500 }))
86
-
87
- const buffer = Buffer.from('test data')
88
- const result = await tableClient.uploadParquetFile('graph_123', 'Entity', buffer)
89
-
90
- expect(result.success).toBe(false)
91
- expect(result.error).toContain('S3 upload failed')
92
- expect(result.error).toContain('500')
93
- })
94
-
95
- it('should fix LocalStack URLs when enabled', async () => {
96
- mockFetch
97
- .mockResolvedValueOnce(
98
- createMockResponse({
99
- upload_url: 'http://localstack:4566/bucket/file.parquet',
100
- file_id: 'file_123',
101
- })
102
- )
103
- .mockResolvedValueOnce(createMockResponse(null))
104
- .mockResolvedValueOnce(createMockResponse({ success: true }))
105
-
106
- const buffer = Buffer.from('test data')
107
- await tableClient.uploadParquetFile('graph_123', 'Entity', buffer, {
108
- fixLocalStackUrl: true,
109
- })
110
-
111
- // Check that the S3 upload (2nd call) used the fixed URL
112
- const s3Call = mockFetch.mock.calls[1]
113
- expect(s3Call[0]).toBe('http://localhost:4566/bucket/file.parquet')
114
- })
115
-
116
- it('should call progress callback', async () => {
117
- mockFetch
118
- .mockResolvedValueOnce(
119
- createMockResponse({
120
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
121
- file_id: 'file_123',
122
- })
123
- )
124
- .mockResolvedValueOnce(createMockResponse(null))
125
- .mockResolvedValueOnce(createMockResponse({ success: true }))
126
-
127
- const progressMessages: string[] = []
128
- const buffer = Buffer.from('test data')
129
-
130
- await tableClient.uploadParquetFile('graph_123', 'Entity', buffer, {
131
- onProgress: (msg) => progressMessages.push(msg),
132
- })
133
-
134
- expect(progressMessages.length).toBeGreaterThan(0)
135
- expect(progressMessages.some((msg) => msg.includes('Getting upload URL'))).toBe(true)
136
- expect(progressMessages.some((msg) => msg.includes('Uploading'))).toBe(true)
137
- })
138
-
139
- it('should handle metadata update failure', async () => {
140
- mockFetch
141
- .mockResolvedValueOnce(
142
- createMockResponse({
143
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
144
- file_id: 'file_123',
145
- })
146
- )
147
- .mockResolvedValueOnce(createMockResponse(null))
148
- .mockResolvedValueOnce(
149
- createMockResponse({ detail: 'Failed to update' }, { ok: false, status: 500 })
150
- )
151
-
152
- const buffer = Buffer.from('test data')
153
- const result = await tableClient.uploadParquetFile('graph_123', 'Entity', buffer)
154
-
155
- expect(result.success).toBe(false)
156
- expect(result.error).toContain('Failed to complete file upload')
157
- })
158
- })
159
-
160
- describe('listStagingTables', () => {
161
- it('should list staging tables successfully', async () => {
162
- mockFetch.mockResolvedValueOnce(
163
- createMockResponse({
164
- tables: [
165
- {
166
- table_name: 'Entity',
167
- row_count: 1000,
168
- file_count: 2,
169
- total_size_bytes: 5000000,
170
- },
171
- ],
172
- })
173
- )
174
-
175
- const tables = await tableClient.listStagingTables('graph_123')
176
-
177
- expect(tables).toHaveLength(1)
178
- expect(tables[0].tableName).toBe('Entity')
179
- expect(tables[0].rowCount).toBe(1000)
180
- expect(tables[0].fileCount).toBe(2)
181
- expect(tables[0].totalSizeBytes).toBe(5000000)
182
- })
183
-
184
- it('should return empty array on error', async () => {
185
- mockFetch.mockResolvedValueOnce(
186
- createMockResponse({ detail: 'Failed to list tables' }, { ok: false, status: 500 })
187
- )
188
-
189
- const tables = await tableClient.listStagingTables('graph_123')
190
-
191
- expect(tables).toEqual([])
192
- })
193
- })
194
-
195
- describe('ingestAllTables', () => {
196
- it('should ingest tables successfully', async () => {
197
- mockFetch.mockResolvedValueOnce(
198
- createMockResponse({
199
- operation_id: 'op_123',
200
- message: 'Ingestion started',
201
- })
202
- )
203
-
204
- const result = await tableClient.ingestAllTables('graph_123', {
205
- ignoreErrors: true,
206
- rebuild: false,
207
- })
208
-
209
- expect(result.success).toBe(true)
210
- expect(result.operationId).toBe('op_123')
211
- expect(result.message).toBe('Ingestion started')
212
- })
213
-
214
- it('should handle ingestion failure', async () => {
215
- mockFetch.mockResolvedValueOnce(
216
- createMockResponse({ detail: 'Ingestion failed' }, { ok: false, status: 500 })
217
- )
218
-
219
- const result = await tableClient.ingestAllTables('graph_123')
220
-
221
- expect(result.success).toBe(false)
222
- expect(result.error).toBeDefined()
223
- })
224
-
225
- it('should call progress callback', async () => {
226
- mockFetch.mockResolvedValueOnce(
227
- createMockResponse({
228
- operation_id: 'op_123',
229
- message: 'Ingestion started',
230
- })
231
- )
232
-
233
- const progressMessages: string[] = []
234
-
235
- await tableClient.ingestAllTables('graph_123', {
236
- onProgress: (msg) => progressMessages.push(msg),
237
- })
238
-
239
- expect(progressMessages.length).toBeGreaterThan(0)
240
- expect(progressMessages.some((msg) => msg.includes('Starting'))).toBe(true)
241
- expect(progressMessages.some((msg) => msg.includes('completed'))).toBe(true)
242
- })
243
- })
244
-
245
- describe('uploadAndIngest', () => {
246
- it('should upload and ingest in one operation', async () => {
247
- mockFetch
248
- // Upload URL
249
- .mockResolvedValueOnce(
250
- createMockResponse({
251
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
252
- file_id: 'file_123',
253
- })
254
- )
255
- // S3 upload
256
- .mockResolvedValueOnce(createMockResponse(null))
257
- // Update metadata
258
- .mockResolvedValueOnce(createMockResponse({ success: true }))
259
- // Ingest
260
- .mockResolvedValueOnce(createMockResponse({ operation_id: 'op_123' }))
261
-
262
- const buffer = Buffer.from('test data')
263
- const result = await tableClient.uploadAndIngest('graph_123', 'Entity', buffer)
264
-
265
- expect(result.upload.success).toBe(true)
266
- expect(result.ingest?.success).toBe(true)
267
- expect(result.ingest?.operationId).toBe('op_123')
268
- })
269
-
270
- it('should not ingest if upload fails', async () => {
271
- mockFetch.mockResolvedValueOnce(
272
- createMockResponse({ detail: 'Upload failed' }, { ok: false, status: 500 })
273
- )
274
-
275
- const buffer = Buffer.from('test data')
276
- const result = await tableClient.uploadAndIngest('graph_123', 'Entity', buffer)
277
-
278
- expect(result.upload.success).toBe(false)
279
- expect(result.ingest).toBeNull()
280
- // Should only have 1 fetch call (failed upload URL), not the ingest call
281
- expect(mockFetch).toHaveBeenCalledTimes(1)
282
- })
283
- })
284
-
285
- describe('file conversion helpers', () => {
286
- it('should handle File objects', async () => {
287
- mockFetch
288
- .mockResolvedValueOnce(
289
- createMockResponse({
290
- upload_url: 'https://s3.amazonaws.com/bucket/file.parquet',
291
- file_id: 'file_123',
292
- })
293
- )
294
- .mockResolvedValueOnce(createMockResponse(null))
295
- .mockResolvedValueOnce(createMockResponse({ success: true }))
296
-
297
- const file = new File(['test data'], 'test.parquet', { type: 'application/x-parquet' })
298
- const result = await tableClient.uploadParquetFile('graph_123', 'Entity', file)
299
-
300
- expect(result.success).toBe(true)
301
- expect(result.fileName).toBe('test.parquet')
302
- })
303
- })
304
- })