@robosystems/client 0.2.14 → 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.
- package/extensions/FileClient.d.ts +57 -0
- package/extensions/{TableIngestClient.js → FileClient.js} +59 -80
- package/extensions/{TableIngestClient.ts → FileClient.ts} +71 -125
- package/extensions/MaterializationClient.d.ts +51 -0
- package/extensions/MaterializationClient.js +107 -0
- package/extensions/MaterializationClient.ts +163 -0
- package/extensions/TableClient.d.ts +38 -0
- package/extensions/TableClient.js +92 -0
- package/extensions/TableClient.ts +132 -0
- package/extensions/hooks.d.ts +9 -11
- package/extensions/hooks.js +21 -56
- package/extensions/hooks.ts +30 -79
- package/extensions/index.d.ts +14 -4
- package/extensions/index.js +32 -5
- package/extensions/index.test.ts +10 -2
- package/extensions/index.ts +46 -5
- package/package.json +1 -1
- package/sdk/sdk.gen.d.ts +324 -244
- package/sdk/sdk.gen.js +410 -274
- package/sdk/sdk.gen.ts +404 -268
- package/sdk/types.gen.d.ts +697 -239
- package/sdk/types.gen.ts +736 -253
- package/sdk-extensions/FileClient.d.ts +57 -0
- package/sdk-extensions/{TableIngestClient.js → FileClient.js} +59 -80
- package/sdk-extensions/{TableIngestClient.ts → FileClient.ts} +71 -125
- package/sdk-extensions/MaterializationClient.d.ts +51 -0
- package/sdk-extensions/MaterializationClient.js +107 -0
- package/sdk-extensions/MaterializationClient.ts +163 -0
- package/sdk-extensions/TableClient.d.ts +38 -0
- package/sdk-extensions/TableClient.js +92 -0
- package/sdk-extensions/TableClient.ts +132 -0
- package/sdk-extensions/hooks.d.ts +9 -11
- package/sdk-extensions/hooks.js +21 -56
- package/sdk-extensions/hooks.ts +30 -79
- package/sdk-extensions/index.d.ts +14 -4
- package/sdk-extensions/index.js +32 -5
- package/sdk-extensions/index.test.ts +10 -2
- package/sdk-extensions/index.ts +46 -5
- package/sdk.gen.d.ts +324 -244
- package/sdk.gen.js +410 -274
- package/sdk.gen.ts +404 -268
- package/types.gen.d.ts +697 -239
- package/types.gen.ts +736 -253
- package/extensions/TableIngestClient.d.ts +0 -75
- package/extensions/TableIngestClient.test.ts +0 -304
- package/sdk-extensions/TableIngestClient.d.ts +0 -75
- package/sdk-extensions/TableIngestClient.test.ts +0 -304
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
export interface FileUploadOptions {
|
|
2
|
+
onProgress?: (message: string) => void;
|
|
3
|
+
fixLocalStackUrl?: boolean;
|
|
4
|
+
fileName?: string;
|
|
5
|
+
ingestToGraph?: boolean;
|
|
6
|
+
}
|
|
7
|
+
export interface FileUploadResult {
|
|
8
|
+
fileId: string;
|
|
9
|
+
fileSize: number;
|
|
10
|
+
rowCount: number;
|
|
11
|
+
tableName: string;
|
|
12
|
+
fileName: string;
|
|
13
|
+
success: boolean;
|
|
14
|
+
error?: string;
|
|
15
|
+
}
|
|
16
|
+
export interface FileInfo {
|
|
17
|
+
fileId: string;
|
|
18
|
+
fileName: string;
|
|
19
|
+
tableName: string;
|
|
20
|
+
status: string;
|
|
21
|
+
fileSize: number;
|
|
22
|
+
rowCount: number;
|
|
23
|
+
createdAt: string;
|
|
24
|
+
}
|
|
25
|
+
export type FileInput = File | Blob | Buffer | ReadableStream<Uint8Array>;
|
|
26
|
+
export declare class FileClient {
|
|
27
|
+
private config;
|
|
28
|
+
constructor(config: {
|
|
29
|
+
baseUrl: string;
|
|
30
|
+
credentials?: 'include' | 'same-origin' | 'omit';
|
|
31
|
+
headers?: Record<string, string>;
|
|
32
|
+
token?: string;
|
|
33
|
+
});
|
|
34
|
+
/**
|
|
35
|
+
* Upload a Parquet file to staging
|
|
36
|
+
*
|
|
37
|
+
* Handles the complete 3-step upload process:
|
|
38
|
+
* 1. Get presigned upload URL
|
|
39
|
+
* 2. Upload file to S3
|
|
40
|
+
* 3. Mark file as 'uploaded' (backend validates, calculates size/row count)
|
|
41
|
+
*/
|
|
42
|
+
upload(graphId: string, tableName: string, fileOrBuffer: FileInput, options?: FileUploadOptions): Promise<FileUploadResult>;
|
|
43
|
+
/**
|
|
44
|
+
* List files in a graph
|
|
45
|
+
*/
|
|
46
|
+
list(graphId: string, tableName?: string, status?: string): Promise<FileInfo[]>;
|
|
47
|
+
/**
|
|
48
|
+
* Get file information
|
|
49
|
+
*/
|
|
50
|
+
get(graphId: string, fileId: string): Promise<FileInfo | null>;
|
|
51
|
+
/**
|
|
52
|
+
* Delete a file
|
|
53
|
+
*/
|
|
54
|
+
delete(graphId: string, fileId: string, cascade?: boolean): Promise<boolean>;
|
|
55
|
+
private getFileName;
|
|
56
|
+
private getFileContent;
|
|
57
|
+
}
|
|
@@ -1,39 +1,37 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
"use strict";
|
|
3
3
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
4
|
-
exports.
|
|
4
|
+
exports.FileClient = void 0;
|
|
5
5
|
/**
|
|
6
|
-
*
|
|
6
|
+
* File Client for RoboSystems API
|
|
7
7
|
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
8
|
+
* Manages file upload operations including presigned URLs, S3 uploads,
|
|
9
|
+
* and file status tracking.
|
|
10
10
|
*/
|
|
11
11
|
const sdk_gen_1 = require("../sdk/sdk.gen");
|
|
12
|
-
class
|
|
12
|
+
class FileClient {
|
|
13
13
|
constructor(config) {
|
|
14
14
|
this.config = config;
|
|
15
15
|
}
|
|
16
16
|
/**
|
|
17
|
-
* Upload a Parquet file to
|
|
17
|
+
* Upload a Parquet file to staging
|
|
18
18
|
*
|
|
19
|
-
*
|
|
19
|
+
* Handles the complete 3-step upload process:
|
|
20
20
|
* 1. Get presigned upload URL
|
|
21
21
|
* 2. Upload file to S3
|
|
22
22
|
* 3. Mark file as 'uploaded' (backend validates, calculates size/row count)
|
|
23
|
-
*
|
|
24
|
-
* Supports File (browser), Blob (browser), Buffer (Node.js), and ReadableStream.
|
|
25
23
|
*/
|
|
26
|
-
async
|
|
24
|
+
async upload(graphId, tableName, fileOrBuffer, options = {}) {
|
|
27
25
|
const fileName = this.getFileName(fileOrBuffer, options.fileName);
|
|
28
26
|
try {
|
|
29
|
-
// Step 1: Get presigned upload URL
|
|
30
27
|
options.onProgress?.(`Getting upload URL for ${fileName} -> table '${tableName}'...`);
|
|
31
28
|
const uploadRequest = {
|
|
32
29
|
file_name: fileName,
|
|
33
30
|
content_type: 'application/x-parquet',
|
|
31
|
+
table_name: tableName,
|
|
34
32
|
};
|
|
35
|
-
const uploadUrlResponse = await (0, sdk_gen_1.
|
|
36
|
-
path: { graph_id: graphId
|
|
33
|
+
const uploadUrlResponse = await (0, sdk_gen_1.createFileUpload)({
|
|
34
|
+
path: { graph_id: graphId },
|
|
37
35
|
body: uploadRequest,
|
|
38
36
|
});
|
|
39
37
|
if (uploadUrlResponse.error || !uploadUrlResponse.data) {
|
|
@@ -50,11 +48,9 @@ class TableIngestClient {
|
|
|
50
48
|
const uploadData = uploadUrlResponse.data;
|
|
51
49
|
let uploadUrl = uploadData.upload_url;
|
|
52
50
|
const fileId = uploadData.file_id;
|
|
53
|
-
// Fix LocalStack URL if needed
|
|
54
51
|
if (options.fixLocalStackUrl && uploadUrl.includes('localstack:4566')) {
|
|
55
52
|
uploadUrl = uploadUrl.replace('localstack:4566', 'localhost:4566');
|
|
56
53
|
}
|
|
57
|
-
// Step 2: Upload file to S3
|
|
58
54
|
options.onProgress?.(`Uploading ${fileName} to S3...`);
|
|
59
55
|
const fileContent = await this.getFileContent(fileOrBuffer);
|
|
60
56
|
const fileSize = fileContent.byteLength;
|
|
@@ -76,12 +72,11 @@ class TableIngestClient {
|
|
|
76
72
|
error: `S3 upload failed: ${s3Response.status} ${s3Response.statusText}`,
|
|
77
73
|
};
|
|
78
74
|
}
|
|
79
|
-
// Step 3: Mark file as uploaded (backend validates and calculates size/row count)
|
|
80
75
|
options.onProgress?.(`Marking ${fileName} as uploaded...`);
|
|
81
76
|
const statusUpdate = {
|
|
82
77
|
status: 'uploaded',
|
|
83
78
|
};
|
|
84
|
-
const updateResponse = await (0, sdk_gen_1.
|
|
79
|
+
const updateResponse = await (0, sdk_gen_1.updateFile)({
|
|
85
80
|
path: { graph_id: graphId, file_id: fileId },
|
|
86
81
|
body: statusUpdate,
|
|
87
82
|
});
|
|
@@ -96,7 +91,6 @@ class TableIngestClient {
|
|
|
96
91
|
error: 'Failed to complete file upload',
|
|
97
92
|
};
|
|
98
93
|
}
|
|
99
|
-
// Extract size and row count from response (calculated by backend)
|
|
100
94
|
const responseData = updateResponse.data;
|
|
101
95
|
const actualFileSize = responseData.file_size_bytes || 0;
|
|
102
96
|
const actualRowCount = responseData.row_count || 0;
|
|
@@ -123,110 +117,96 @@ class TableIngestClient {
|
|
|
123
117
|
}
|
|
124
118
|
}
|
|
125
119
|
/**
|
|
126
|
-
* List
|
|
120
|
+
* List files in a graph
|
|
127
121
|
*/
|
|
128
|
-
async
|
|
122
|
+
async list(graphId, tableName, status) {
|
|
129
123
|
try {
|
|
130
|
-
const response = await (0, sdk_gen_1.
|
|
124
|
+
const response = await (0, sdk_gen_1.listFiles)({
|
|
131
125
|
path: { graph_id: graphId },
|
|
126
|
+
query: {
|
|
127
|
+
table_name: tableName,
|
|
128
|
+
status: status,
|
|
129
|
+
},
|
|
132
130
|
});
|
|
133
131
|
if (response.error || !response.data) {
|
|
134
|
-
console.error('Failed to list
|
|
132
|
+
console.error('Failed to list files:', response.error);
|
|
135
133
|
return [];
|
|
136
134
|
}
|
|
137
|
-
const
|
|
138
|
-
return (
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
135
|
+
const fileData = response.data;
|
|
136
|
+
return (fileData.files?.map((file) => ({
|
|
137
|
+
fileId: file.file_id,
|
|
138
|
+
fileName: file.file_name,
|
|
139
|
+
tableName: file.table_name,
|
|
140
|
+
status: file.status,
|
|
141
|
+
fileSize: file.file_size_bytes || 0,
|
|
142
|
+
rowCount: file.row_count || 0,
|
|
143
|
+
createdAt: file.created_at,
|
|
143
144
|
})) || []);
|
|
144
145
|
}
|
|
145
146
|
catch (error) {
|
|
146
|
-
console.error('Failed to list
|
|
147
|
+
console.error('Failed to list files:', error);
|
|
147
148
|
return [];
|
|
148
149
|
}
|
|
149
150
|
}
|
|
150
151
|
/**
|
|
151
|
-
*
|
|
152
|
+
* Get file information
|
|
152
153
|
*/
|
|
153
|
-
async
|
|
154
|
+
async get(graphId, fileId) {
|
|
154
155
|
try {
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
ignore_errors: options.ignoreErrors ?? true,
|
|
158
|
-
rebuild: options.rebuild ?? false,
|
|
159
|
-
};
|
|
160
|
-
const response = await (0, sdk_gen_1.ingestTables)({
|
|
161
|
-
path: { graph_id: graphId },
|
|
162
|
-
body: ingestRequest,
|
|
156
|
+
const response = await (0, sdk_gen_1.getFile)({
|
|
157
|
+
path: { graph_id: graphId, file_id: fileId },
|
|
163
158
|
});
|
|
164
159
|
if (response.error || !response.data) {
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
error: `Failed to ingest tables: ${response.error}`,
|
|
168
|
-
};
|
|
160
|
+
console.error('Failed to get file:', response.error);
|
|
161
|
+
return null;
|
|
169
162
|
}
|
|
170
|
-
const
|
|
171
|
-
options.onProgress?.('✅ Table ingestion completed');
|
|
163
|
+
const file = response.data;
|
|
172
164
|
return {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
165
|
+
fileId: file.file_id,
|
|
166
|
+
fileName: file.file_name,
|
|
167
|
+
tableName: file.table_name,
|
|
168
|
+
status: file.status,
|
|
169
|
+
fileSize: file.file_size_bytes || 0,
|
|
170
|
+
rowCount: file.row_count || 0,
|
|
171
|
+
createdAt: file.created_at,
|
|
176
172
|
};
|
|
177
173
|
}
|
|
178
174
|
catch (error) {
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
error: error instanceof Error ? error.message : String(error),
|
|
182
|
-
};
|
|
175
|
+
console.error('Failed to get file:', error);
|
|
176
|
+
return null;
|
|
183
177
|
}
|
|
184
178
|
}
|
|
185
179
|
/**
|
|
186
|
-
*
|
|
180
|
+
* Delete a file
|
|
187
181
|
*/
|
|
188
|
-
async
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
182
|
+
async delete(graphId, fileId, cascade = false) {
|
|
183
|
+
try {
|
|
184
|
+
const response = await (0, sdk_gen_1.deleteFile)({
|
|
185
|
+
path: { graph_id: graphId, file_id: fileId },
|
|
186
|
+
query: { cascade },
|
|
187
|
+
});
|
|
188
|
+
return !response.error;
|
|
189
|
+
}
|
|
190
|
+
catch (error) {
|
|
191
|
+
console.error('Failed to delete file:', error);
|
|
192
|
+
return false;
|
|
196
193
|
}
|
|
197
|
-
// Ingest the table
|
|
198
|
-
const ingestResult = await this.ingestAllTables(graphId, ingestOptions);
|
|
199
|
-
return {
|
|
200
|
-
upload: uploadResult,
|
|
201
|
-
ingest: ingestResult,
|
|
202
|
-
};
|
|
203
194
|
}
|
|
204
|
-
/**
|
|
205
|
-
* Get file name from input or use provided override
|
|
206
|
-
*/
|
|
207
195
|
getFileName(fileOrBuffer, override) {
|
|
208
196
|
if (override)
|
|
209
197
|
return override;
|
|
210
|
-
// File object (browser)
|
|
211
198
|
if ('name' in fileOrBuffer && typeof fileOrBuffer.name === 'string') {
|
|
212
199
|
return fileOrBuffer.name;
|
|
213
200
|
}
|
|
214
|
-
// Default name for buffers/blobs/streams
|
|
215
201
|
return 'data.parquet';
|
|
216
202
|
}
|
|
217
|
-
/**
|
|
218
|
-
* Convert various file inputs to ArrayBuffer for upload
|
|
219
|
-
*/
|
|
220
203
|
async getFileContent(fileOrBuffer) {
|
|
221
|
-
// File or Blob (browser)
|
|
222
204
|
if (fileOrBuffer instanceof Blob || fileOrBuffer instanceof File) {
|
|
223
205
|
return fileOrBuffer.arrayBuffer();
|
|
224
206
|
}
|
|
225
|
-
// Buffer (Node.js)
|
|
226
207
|
if (Buffer.isBuffer(fileOrBuffer)) {
|
|
227
208
|
return fileOrBuffer.buffer.slice(fileOrBuffer.byteOffset, fileOrBuffer.byteOffset + fileOrBuffer.byteLength);
|
|
228
209
|
}
|
|
229
|
-
// ReadableStream
|
|
230
210
|
if ('getReader' in fileOrBuffer) {
|
|
231
211
|
const reader = fileOrBuffer.getReader();
|
|
232
212
|
const chunks = [];
|
|
@@ -237,7 +217,6 @@ class TableIngestClient {
|
|
|
237
217
|
if (value)
|
|
238
218
|
chunks.push(value);
|
|
239
219
|
}
|
|
240
|
-
// Concatenate chunks
|
|
241
220
|
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0);
|
|
242
221
|
const result = new Uint8Array(totalLength);
|
|
243
222
|
let offset = 0;
|
|
@@ -250,4 +229,4 @@ class TableIngestClient {
|
|
|
250
229
|
throw new Error('Unsupported file input type');
|
|
251
230
|
}
|
|
252
231
|
}
|
|
253
|
-
exports.
|
|
232
|
+
exports.FileClient = FileClient;
|
|
@@ -1,34 +1,23 @@
|
|
|
1
1
|
'use client'
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* File Client for RoboSystems API
|
|
5
5
|
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
6
|
+
* Manages file upload operations including presigned URLs, S3 uploads,
|
|
7
|
+
* and file status tracking.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
import type {
|
|
12
|
-
BulkIngestRequest,
|
|
13
|
-
FileStatusUpdate,
|
|
14
|
-
FileUploadRequest,
|
|
15
|
-
FileUploadResponse,
|
|
16
|
-
TableListResponse,
|
|
17
|
-
} from '../sdk/types.gen'
|
|
10
|
+
import { createFileUpload, deleteFile, getFile, listFiles, updateFile } from '../sdk/sdk.gen'
|
|
11
|
+
import type { FileStatusUpdate, FileUploadRequest, FileUploadResponse } from '../sdk/types.gen'
|
|
18
12
|
|
|
19
|
-
export interface
|
|
13
|
+
export interface FileUploadOptions {
|
|
20
14
|
onProgress?: (message: string) => void
|
|
21
|
-
fixLocalStackUrl?: boolean
|
|
22
|
-
fileName?: string
|
|
15
|
+
fixLocalStackUrl?: boolean
|
|
16
|
+
fileName?: string
|
|
17
|
+
ingestToGraph?: boolean
|
|
23
18
|
}
|
|
24
19
|
|
|
25
|
-
export interface
|
|
26
|
-
ignoreErrors?: boolean
|
|
27
|
-
rebuild?: boolean
|
|
28
|
-
onProgress?: (message: string) => void
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
export interface UploadResult {
|
|
20
|
+
export interface FileUploadResult {
|
|
32
21
|
fileId: string
|
|
33
22
|
fileSize: number
|
|
34
23
|
rowCount: number
|
|
@@ -38,24 +27,19 @@ export interface UploadResult {
|
|
|
38
27
|
error?: string
|
|
39
28
|
}
|
|
40
29
|
|
|
41
|
-
export interface
|
|
30
|
+
export interface FileInfo {
|
|
31
|
+
fileId: string
|
|
32
|
+
fileName: string
|
|
42
33
|
tableName: string
|
|
34
|
+
status: string
|
|
35
|
+
fileSize: number
|
|
43
36
|
rowCount: number
|
|
44
|
-
|
|
45
|
-
totalSizeBytes: number
|
|
37
|
+
createdAt: string
|
|
46
38
|
}
|
|
47
39
|
|
|
48
|
-
export interface IngestResult {
|
|
49
|
-
success: boolean
|
|
50
|
-
operationId?: string
|
|
51
|
-
message?: string
|
|
52
|
-
error?: string
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
// Union type for all supported file inputs
|
|
56
40
|
export type FileInput = File | Blob | Buffer | ReadableStream<Uint8Array>
|
|
57
41
|
|
|
58
|
-
export class
|
|
42
|
+
export class FileClient {
|
|
59
43
|
private config: {
|
|
60
44
|
baseUrl: string
|
|
61
45
|
credentials?: 'include' | 'same-origin' | 'omit'
|
|
@@ -73,34 +57,32 @@ export class TableIngestClient {
|
|
|
73
57
|
}
|
|
74
58
|
|
|
75
59
|
/**
|
|
76
|
-
* Upload a Parquet file to
|
|
60
|
+
* Upload a Parquet file to staging
|
|
77
61
|
*
|
|
78
|
-
*
|
|
62
|
+
* Handles the complete 3-step upload process:
|
|
79
63
|
* 1. Get presigned upload URL
|
|
80
64
|
* 2. Upload file to S3
|
|
81
65
|
* 3. Mark file as 'uploaded' (backend validates, calculates size/row count)
|
|
82
|
-
*
|
|
83
|
-
* Supports File (browser), Blob (browser), Buffer (Node.js), and ReadableStream.
|
|
84
66
|
*/
|
|
85
|
-
async
|
|
67
|
+
async upload(
|
|
86
68
|
graphId: string,
|
|
87
69
|
tableName: string,
|
|
88
70
|
fileOrBuffer: FileInput,
|
|
89
|
-
options:
|
|
90
|
-
): Promise<
|
|
71
|
+
options: FileUploadOptions = {}
|
|
72
|
+
): Promise<FileUploadResult> {
|
|
91
73
|
const fileName = this.getFileName(fileOrBuffer, options.fileName)
|
|
92
74
|
|
|
93
75
|
try {
|
|
94
|
-
// Step 1: Get presigned upload URL
|
|
95
76
|
options.onProgress?.(`Getting upload URL for ${fileName} -> table '${tableName}'...`)
|
|
96
77
|
|
|
97
78
|
const uploadRequest: FileUploadRequest = {
|
|
98
79
|
file_name: fileName,
|
|
99
80
|
content_type: 'application/x-parquet',
|
|
81
|
+
table_name: tableName,
|
|
100
82
|
}
|
|
101
83
|
|
|
102
|
-
const uploadUrlResponse = await
|
|
103
|
-
path: { graph_id: graphId
|
|
84
|
+
const uploadUrlResponse = await createFileUpload({
|
|
85
|
+
path: { graph_id: graphId },
|
|
104
86
|
body: uploadRequest,
|
|
105
87
|
})
|
|
106
88
|
|
|
@@ -120,12 +102,10 @@ export class TableIngestClient {
|
|
|
120
102
|
let uploadUrl = uploadData.upload_url
|
|
121
103
|
const fileId = uploadData.file_id
|
|
122
104
|
|
|
123
|
-
// Fix LocalStack URL if needed
|
|
124
105
|
if (options.fixLocalStackUrl && uploadUrl.includes('localstack:4566')) {
|
|
125
106
|
uploadUrl = uploadUrl.replace('localstack:4566', 'localhost:4566')
|
|
126
107
|
}
|
|
127
108
|
|
|
128
|
-
// Step 2: Upload file to S3
|
|
129
109
|
options.onProgress?.(`Uploading ${fileName} to S3...`)
|
|
130
110
|
|
|
131
111
|
const fileContent = await this.getFileContent(fileOrBuffer)
|
|
@@ -151,14 +131,13 @@ export class TableIngestClient {
|
|
|
151
131
|
}
|
|
152
132
|
}
|
|
153
133
|
|
|
154
|
-
// Step 3: Mark file as uploaded (backend validates and calculates size/row count)
|
|
155
134
|
options.onProgress?.(`Marking ${fileName} as uploaded...`)
|
|
156
135
|
|
|
157
136
|
const statusUpdate: FileStatusUpdate = {
|
|
158
137
|
status: 'uploaded',
|
|
159
138
|
}
|
|
160
139
|
|
|
161
|
-
const updateResponse = await
|
|
140
|
+
const updateResponse = await updateFile({
|
|
162
141
|
path: { graph_id: graphId, file_id: fileId },
|
|
163
142
|
body: statusUpdate,
|
|
164
143
|
})
|
|
@@ -175,7 +154,6 @@ export class TableIngestClient {
|
|
|
175
154
|
}
|
|
176
155
|
}
|
|
177
156
|
|
|
178
|
-
// Extract size and row count from response (calculated by backend)
|
|
179
157
|
const responseData = updateResponse.data as any
|
|
180
158
|
const actualFileSize = responseData.file_size_bytes || 0
|
|
181
159
|
const actualRowCount = responseData.row_count || 0
|
|
@@ -206,135 +184,105 @@ export class TableIngestClient {
|
|
|
206
184
|
}
|
|
207
185
|
|
|
208
186
|
/**
|
|
209
|
-
* List
|
|
187
|
+
* List files in a graph
|
|
210
188
|
*/
|
|
211
|
-
async
|
|
189
|
+
async list(graphId: string, tableName?: string, status?: string): Promise<FileInfo[]> {
|
|
212
190
|
try {
|
|
213
|
-
const response = await
|
|
191
|
+
const response = await listFiles({
|
|
214
192
|
path: { graph_id: graphId },
|
|
193
|
+
query: {
|
|
194
|
+
table_name: tableName,
|
|
195
|
+
status: status as any,
|
|
196
|
+
},
|
|
215
197
|
})
|
|
216
198
|
|
|
217
199
|
if (response.error || !response.data) {
|
|
218
|
-
console.error('Failed to list
|
|
200
|
+
console.error('Failed to list files:', response.error)
|
|
219
201
|
return []
|
|
220
202
|
}
|
|
221
203
|
|
|
222
|
-
const
|
|
204
|
+
const fileData = response.data as any
|
|
223
205
|
|
|
224
206
|
return (
|
|
225
|
-
|
|
226
|
-
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
207
|
+
fileData.files?.map((file: any) => ({
|
|
208
|
+
fileId: file.file_id,
|
|
209
|
+
fileName: file.file_name,
|
|
210
|
+
tableName: file.table_name,
|
|
211
|
+
status: file.status,
|
|
212
|
+
fileSize: file.file_size_bytes || 0,
|
|
213
|
+
rowCount: file.row_count || 0,
|
|
214
|
+
createdAt: file.created_at,
|
|
230
215
|
})) || []
|
|
231
216
|
)
|
|
232
217
|
} catch (error) {
|
|
233
|
-
console.error('Failed to list
|
|
218
|
+
console.error('Failed to list files:', error)
|
|
234
219
|
return []
|
|
235
220
|
}
|
|
236
221
|
}
|
|
237
222
|
|
|
238
223
|
/**
|
|
239
|
-
*
|
|
224
|
+
* Get file information
|
|
240
225
|
*/
|
|
241
|
-
async
|
|
226
|
+
async get(graphId: string, fileId: string): Promise<FileInfo | null> {
|
|
242
227
|
try {
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
const ingestRequest: BulkIngestRequest = {
|
|
246
|
-
ignore_errors: options.ignoreErrors ?? true,
|
|
247
|
-
rebuild: options.rebuild ?? false,
|
|
248
|
-
}
|
|
249
|
-
|
|
250
|
-
const response = await ingestTables({
|
|
251
|
-
path: { graph_id: graphId },
|
|
252
|
-
body: ingestRequest,
|
|
228
|
+
const response = await getFile({
|
|
229
|
+
path: { graph_id: graphId, file_id: fileId },
|
|
253
230
|
})
|
|
254
231
|
|
|
255
232
|
if (response.error || !response.data) {
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
error: `Failed to ingest tables: ${response.error}`,
|
|
259
|
-
}
|
|
233
|
+
console.error('Failed to get file:', response.error)
|
|
234
|
+
return null
|
|
260
235
|
}
|
|
261
236
|
|
|
262
|
-
const
|
|
263
|
-
|
|
264
|
-
options.onProgress?.('✅ Table ingestion completed')
|
|
237
|
+
const file = response.data as any
|
|
265
238
|
|
|
266
239
|
return {
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
240
|
+
fileId: file.file_id,
|
|
241
|
+
fileName: file.file_name,
|
|
242
|
+
tableName: file.table_name,
|
|
243
|
+
status: file.status,
|
|
244
|
+
fileSize: file.file_size_bytes || 0,
|
|
245
|
+
rowCount: file.row_count || 0,
|
|
246
|
+
createdAt: file.created_at,
|
|
270
247
|
}
|
|
271
248
|
} catch (error) {
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
error: error instanceof Error ? error.message : String(error),
|
|
275
|
-
}
|
|
249
|
+
console.error('Failed to get file:', error)
|
|
250
|
+
return null
|
|
276
251
|
}
|
|
277
252
|
}
|
|
278
253
|
|
|
279
254
|
/**
|
|
280
|
-
*
|
|
255
|
+
* Delete a file
|
|
281
256
|
*/
|
|
282
|
-
async
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
): Promise<{ upload: UploadResult; ingest: IngestResult | null }> {
|
|
289
|
-
// Upload the file
|
|
290
|
-
const uploadResult = await this.uploadParquetFile(
|
|
291
|
-
graphId,
|
|
292
|
-
tableName,
|
|
293
|
-
fileOrBuffer,
|
|
294
|
-
uploadOptions
|
|
295
|
-
)
|
|
296
|
-
|
|
297
|
-
if (!uploadResult.success) {
|
|
298
|
-
return {
|
|
299
|
-
upload: uploadResult,
|
|
300
|
-
ingest: null,
|
|
301
|
-
}
|
|
302
|
-
}
|
|
303
|
-
|
|
304
|
-
// Ingest the table
|
|
305
|
-
const ingestResult = await this.ingestAllTables(graphId, ingestOptions)
|
|
257
|
+
async delete(graphId: string, fileId: string, cascade: boolean = false): Promise<boolean> {
|
|
258
|
+
try {
|
|
259
|
+
const response = await deleteFile({
|
|
260
|
+
path: { graph_id: graphId, file_id: fileId },
|
|
261
|
+
query: { cascade },
|
|
262
|
+
})
|
|
306
263
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
264
|
+
return !response.error
|
|
265
|
+
} catch (error) {
|
|
266
|
+
console.error('Failed to delete file:', error)
|
|
267
|
+
return false
|
|
310
268
|
}
|
|
311
269
|
}
|
|
312
270
|
|
|
313
|
-
/**
|
|
314
|
-
* Get file name from input or use provided override
|
|
315
|
-
*/
|
|
316
271
|
private getFileName(fileOrBuffer: FileInput, override?: string): string {
|
|
317
272
|
if (override) return override
|
|
318
273
|
|
|
319
|
-
// File object (browser)
|
|
320
274
|
if ('name' in fileOrBuffer && typeof fileOrBuffer.name === 'string') {
|
|
321
275
|
return fileOrBuffer.name
|
|
322
276
|
}
|
|
323
277
|
|
|
324
|
-
// Default name for buffers/blobs/streams
|
|
325
278
|
return 'data.parquet'
|
|
326
279
|
}
|
|
327
280
|
|
|
328
|
-
/**
|
|
329
|
-
* Convert various file inputs to ArrayBuffer for upload
|
|
330
|
-
*/
|
|
331
281
|
private async getFileContent(fileOrBuffer: FileInput): Promise<ArrayBuffer> {
|
|
332
|
-
// File or Blob (browser)
|
|
333
282
|
if (fileOrBuffer instanceof Blob || fileOrBuffer instanceof File) {
|
|
334
283
|
return fileOrBuffer.arrayBuffer()
|
|
335
284
|
}
|
|
336
285
|
|
|
337
|
-
// Buffer (Node.js)
|
|
338
286
|
if (Buffer.isBuffer(fileOrBuffer)) {
|
|
339
287
|
return fileOrBuffer.buffer.slice(
|
|
340
288
|
fileOrBuffer.byteOffset,
|
|
@@ -342,7 +290,6 @@ export class TableIngestClient {
|
|
|
342
290
|
)
|
|
343
291
|
}
|
|
344
292
|
|
|
345
|
-
// ReadableStream
|
|
346
293
|
if ('getReader' in fileOrBuffer) {
|
|
347
294
|
const reader = fileOrBuffer.getReader()
|
|
348
295
|
const chunks: Uint8Array[] = []
|
|
@@ -353,7 +300,6 @@ export class TableIngestClient {
|
|
|
353
300
|
if (value) chunks.push(value)
|
|
354
301
|
}
|
|
355
302
|
|
|
356
|
-
// Concatenate chunks
|
|
357
303
|
const totalLength = chunks.reduce((sum, chunk) => sum + chunk.length, 0)
|
|
358
304
|
const result = new Uint8Array(totalLength)
|
|
359
305
|
let offset = 0
|