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