@anvailabs/proximadb-client 0.3.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.
- package/README.md +160 -0
- package/dist/client.d.ts +319 -0
- package/dist/client.d.ts.map +1 -0
- package/dist/client.js +681 -0
- package/dist/client.js.map +1 -0
- package/dist/collection.d.ts +227 -0
- package/dist/collection.d.ts.map +1 -0
- package/dist/collection.js +436 -0
- package/dist/collection.js.map +1 -0
- package/dist/esm/client.js +674 -0
- package/dist/esm/client.js.map +1 -0
- package/dist/esm/collection.js +428 -0
- package/dist/esm/collection.js.map +1 -0
- package/dist/esm/filter.js +228 -0
- package/dist/esm/filter.js.map +1 -0
- package/dist/esm/generated/schema.js +6 -0
- package/dist/esm/generated/schema.js.map +1 -0
- package/dist/esm/graph.js +678 -0
- package/dist/esm/graph.js.map +1 -0
- package/dist/esm/index.js +86 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/search.js +317 -0
- package/dist/esm/search.js.map +1 -0
- package/dist/esm/transport.js +33 -0
- package/dist/esm/transport.js.map +1 -0
- package/dist/esm/types.js +181 -0
- package/dist/esm/types.js.map +1 -0
- package/dist/filter.d.ts +51 -0
- package/dist/filter.d.ts.map +1 -0
- package/dist/filter.js +241 -0
- package/dist/filter.js.map +1 -0
- package/dist/generated/schema.d.ts +4271 -0
- package/dist/generated/schema.d.ts.map +1 -0
- package/dist/generated/schema.js +7 -0
- package/dist/generated/schema.js.map +1 -0
- package/dist/graph.d.ts +350 -0
- package/dist/graph.d.ts.map +1 -0
- package/dist/graph.js +690 -0
- package/dist/graph.js.map +1 -0
- package/dist/index.d.ts +58 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/dist/search.d.ts +160 -0
- package/dist/search.d.ts.map +1 -0
- package/dist/search.js +322 -0
- package/dist/search.js.map +1 -0
- package/dist/transport.d.ts +40 -0
- package/dist/transport.d.ts.map +1 -0
- package/dist/transport.js +39 -0
- package/dist/transport.js.map +1 -0
- package/dist/types.d.ts +632 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +185 -0
- package/dist/types.js.map +1 -0
- package/package.json +72 -0
- package/src/client.ts +856 -0
- package/src/collection.ts +578 -0
- package/src/filter.ts +280 -0
- package/src/generated/schema.ts +4271 -0
- package/src/graph.ts +811 -0
- package/src/index.ts +184 -0
- package/src/search.ts +401 -0
- package/src/transport.ts +52 -0
- package/src/types.ts +726 -0
package/dist/graph.js
ADDED
|
@@ -0,0 +1,690 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* ProximaDB TypeScript SDK - Graph Operations
|
|
4
|
+
*
|
|
5
|
+
* Provides a fluent API for graph database operations including
|
|
6
|
+
* node and edge management, traversal queries, and graph analytics.
|
|
7
|
+
*
|
|
8
|
+
* Copyright 2025 ProximaDB Contributors
|
|
9
|
+
* Licensed under the Apache License, Version 2.0
|
|
10
|
+
*/
|
|
11
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
12
|
+
exports.GraphBuilder = exports.GraphHandle = exports.TraversalBuilder = exports.EdgeBuilder = exports.NodeBuilder = void 0;
|
|
13
|
+
exports.createNode = createNode;
|
|
14
|
+
exports.node = node;
|
|
15
|
+
exports.createEdge = createEdge;
|
|
16
|
+
exports.edge = edge;
|
|
17
|
+
const types_1 = require("./types");
|
|
18
|
+
// ============================================================================
|
|
19
|
+
// NODE BUILDER
|
|
20
|
+
// ============================================================================
|
|
21
|
+
/**
|
|
22
|
+
* Builder for creating graph nodes
|
|
23
|
+
*/
|
|
24
|
+
class NodeBuilder {
|
|
25
|
+
handle;
|
|
26
|
+
nodeId = null;
|
|
27
|
+
nodeLabel = null;
|
|
28
|
+
nodeProperties = {};
|
|
29
|
+
nodeVector = null;
|
|
30
|
+
constructor(handle) {
|
|
31
|
+
this.handle = handle;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Set the node ID
|
|
35
|
+
*/
|
|
36
|
+
id(nodeId) {
|
|
37
|
+
this.nodeId = nodeId;
|
|
38
|
+
return this;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* Set the node label (type)
|
|
42
|
+
*/
|
|
43
|
+
label(nodeLabel) {
|
|
44
|
+
this.nodeLabel = nodeLabel;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Add a property to the node
|
|
49
|
+
*/
|
|
50
|
+
property(key, value) {
|
|
51
|
+
this.nodeProperties[key] = value;
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Add multiple properties at once
|
|
56
|
+
*/
|
|
57
|
+
properties(props) {
|
|
58
|
+
Object.assign(this.nodeProperties, props);
|
|
59
|
+
return this;
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Set the embedding vector for semantic operations
|
|
63
|
+
*/
|
|
64
|
+
vector(vec) {
|
|
65
|
+
this.nodeVector = vec;
|
|
66
|
+
return this;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Execute the node addition.
|
|
70
|
+
*
|
|
71
|
+
* Wire endpoint: POST /api/v2/graphs/{graph_id}/nodes
|
|
72
|
+
* OpenAPI operationId: createNode
|
|
73
|
+
*
|
|
74
|
+
* Body shape (server-true, per `CreateNodeRequest`):
|
|
75
|
+
* `{ node: NodeInput }` — NodeInput = `{ id, labels?, properties?, embedding? }`.
|
|
76
|
+
*/
|
|
77
|
+
async execute() {
|
|
78
|
+
if (this.nodeId === null) {
|
|
79
|
+
throw new Error("Node ID is required");
|
|
80
|
+
}
|
|
81
|
+
const node = { id: this.nodeId };
|
|
82
|
+
if (this.nodeLabel !== null) {
|
|
83
|
+
node.labels = [this.nodeLabel];
|
|
84
|
+
}
|
|
85
|
+
if (Object.keys(this.nodeProperties).length > 0) {
|
|
86
|
+
node.properties = this.nodeProperties;
|
|
87
|
+
}
|
|
88
|
+
if (this.nodeVector !== null) {
|
|
89
|
+
const embedding = { vector: this.nodeVector };
|
|
90
|
+
node.embedding = embedding;
|
|
91
|
+
}
|
|
92
|
+
const request = { node };
|
|
93
|
+
await this.handle.getClient().createNodeRequest(this.handle.getName(), request);
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Build the node without executing
|
|
97
|
+
*/
|
|
98
|
+
build() {
|
|
99
|
+
if (this.nodeId === null) {
|
|
100
|
+
throw new Error("Node ID is required");
|
|
101
|
+
}
|
|
102
|
+
return {
|
|
103
|
+
id: this.nodeId,
|
|
104
|
+
label: this.nodeLabel ?? undefined,
|
|
105
|
+
properties: this.nodeProperties,
|
|
106
|
+
vector: this.nodeVector ?? undefined,
|
|
107
|
+
};
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
exports.NodeBuilder = NodeBuilder;
|
|
111
|
+
// ============================================================================
|
|
112
|
+
// EDGE BUILDER
|
|
113
|
+
// ============================================================================
|
|
114
|
+
/**
|
|
115
|
+
* Builder for creating graph edges
|
|
116
|
+
*/
|
|
117
|
+
class EdgeBuilder {
|
|
118
|
+
handle;
|
|
119
|
+
edgeId = null;
|
|
120
|
+
sourceNode = null;
|
|
121
|
+
targetNode = null;
|
|
122
|
+
relationshipType = null;
|
|
123
|
+
edgeProperties = {};
|
|
124
|
+
edgeWeight = null;
|
|
125
|
+
constructor(handle) {
|
|
126
|
+
this.handle = handle;
|
|
127
|
+
}
|
|
128
|
+
/**
|
|
129
|
+
* Set the edge ID (required by server `EdgeInput.id`).
|
|
130
|
+
*/
|
|
131
|
+
id(edgeId) {
|
|
132
|
+
this.edgeId = edgeId;
|
|
133
|
+
return this;
|
|
134
|
+
}
|
|
135
|
+
/**
|
|
136
|
+
* Set the source node ID
|
|
137
|
+
*/
|
|
138
|
+
from(nodeId) {
|
|
139
|
+
this.sourceNode = nodeId;
|
|
140
|
+
return this;
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Set the target node ID
|
|
144
|
+
*/
|
|
145
|
+
to(nodeId) {
|
|
146
|
+
this.targetNode = nodeId;
|
|
147
|
+
return this;
|
|
148
|
+
}
|
|
149
|
+
/**
|
|
150
|
+
* Set the relationship / edge type (server field: `edge_type`).
|
|
151
|
+
*/
|
|
152
|
+
relationship(relType) {
|
|
153
|
+
this.relationshipType = relType;
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
/**
|
|
157
|
+
* Alias for `relationship(...)` matching the server-side field name.
|
|
158
|
+
*/
|
|
159
|
+
edgeType(edgeType) {
|
|
160
|
+
this.relationshipType = edgeType;
|
|
161
|
+
return this;
|
|
162
|
+
}
|
|
163
|
+
/**
|
|
164
|
+
* Add a property to the edge
|
|
165
|
+
*/
|
|
166
|
+
property(key, value) {
|
|
167
|
+
this.edgeProperties[key] = value;
|
|
168
|
+
return this;
|
|
169
|
+
}
|
|
170
|
+
/**
|
|
171
|
+
* Add multiple properties at once
|
|
172
|
+
*/
|
|
173
|
+
properties(props) {
|
|
174
|
+
Object.assign(this.edgeProperties, props);
|
|
175
|
+
return this;
|
|
176
|
+
}
|
|
177
|
+
/**
|
|
178
|
+
* Set the edge weight
|
|
179
|
+
*/
|
|
180
|
+
weight(w) {
|
|
181
|
+
this.edgeWeight = w;
|
|
182
|
+
return this;
|
|
183
|
+
}
|
|
184
|
+
/**
|
|
185
|
+
* Execute the edge addition.
|
|
186
|
+
*
|
|
187
|
+
* Wire endpoint: POST /api/v2/graphs/{graph_id}/edges
|
|
188
|
+
* OpenAPI operationId: createEdge
|
|
189
|
+
*
|
|
190
|
+
* Body shape (server-true, per `CreateEdgeRequest`):
|
|
191
|
+
* `{ edge: EdgeInput }` — EdgeInput = `{ id, from_node_id, to_node_id,
|
|
192
|
+
* edge_type, properties?, weight? }`.
|
|
193
|
+
*/
|
|
194
|
+
async execute() {
|
|
195
|
+
if (this.edgeId === null) {
|
|
196
|
+
throw new Error("Edge ID is required (call .id(...))");
|
|
197
|
+
}
|
|
198
|
+
if (this.sourceNode === null) {
|
|
199
|
+
throw new Error("Source node ID is required");
|
|
200
|
+
}
|
|
201
|
+
if (this.targetNode === null) {
|
|
202
|
+
throw new Error("Target node ID is required");
|
|
203
|
+
}
|
|
204
|
+
if (this.relationshipType === null) {
|
|
205
|
+
throw new Error("Edge type / relationship is required");
|
|
206
|
+
}
|
|
207
|
+
const edge = {
|
|
208
|
+
id: this.edgeId,
|
|
209
|
+
from_node_id: this.sourceNode,
|
|
210
|
+
to_node_id: this.targetNode,
|
|
211
|
+
edge_type: this.relationshipType,
|
|
212
|
+
};
|
|
213
|
+
if (Object.keys(this.edgeProperties).length > 0) {
|
|
214
|
+
edge.properties = this.edgeProperties;
|
|
215
|
+
}
|
|
216
|
+
if (this.edgeWeight !== null) {
|
|
217
|
+
edge.weight = this.edgeWeight;
|
|
218
|
+
}
|
|
219
|
+
const request = { edge };
|
|
220
|
+
await this.handle.getClient().createEdgeRequest(this.handle.getName(), request);
|
|
221
|
+
}
|
|
222
|
+
/**
|
|
223
|
+
* Build the edge without executing
|
|
224
|
+
*/
|
|
225
|
+
build() {
|
|
226
|
+
if (this.sourceNode === null) {
|
|
227
|
+
throw new Error("Source node ID is required");
|
|
228
|
+
}
|
|
229
|
+
if (this.targetNode === null) {
|
|
230
|
+
throw new Error("Target node ID is required");
|
|
231
|
+
}
|
|
232
|
+
if (this.relationshipType === null) {
|
|
233
|
+
throw new Error("Relationship type is required");
|
|
234
|
+
}
|
|
235
|
+
return {
|
|
236
|
+
source: this.sourceNode,
|
|
237
|
+
target: this.targetNode,
|
|
238
|
+
relationship: this.relationshipType,
|
|
239
|
+
properties: this.edgeProperties,
|
|
240
|
+
weight: this.edgeWeight ?? undefined,
|
|
241
|
+
};
|
|
242
|
+
}
|
|
243
|
+
}
|
|
244
|
+
exports.EdgeBuilder = EdgeBuilder;
|
|
245
|
+
// ============================================================================
|
|
246
|
+
// TRAVERSAL BUILDER
|
|
247
|
+
// ============================================================================
|
|
248
|
+
/**
|
|
249
|
+
* Builder for graph traversal queries
|
|
250
|
+
*/
|
|
251
|
+
class TraversalBuilder {
|
|
252
|
+
handle;
|
|
253
|
+
startNodeId = null;
|
|
254
|
+
relationshipTypes = [];
|
|
255
|
+
nodeLabelsList = [];
|
|
256
|
+
traversalDirection = types_1.TraversalDirection.Outgoing;
|
|
257
|
+
maxDepthValue = 3;
|
|
258
|
+
limitValue = null;
|
|
259
|
+
algorithmValue = null;
|
|
260
|
+
filterExpr = null;
|
|
261
|
+
constructor(handle) {
|
|
262
|
+
this.handle = handle;
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Set the starting node
|
|
266
|
+
*/
|
|
267
|
+
start(nodeId) {
|
|
268
|
+
this.startNodeId = nodeId;
|
|
269
|
+
return this;
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Add a relationship type to follow
|
|
273
|
+
*/
|
|
274
|
+
relationship(relType) {
|
|
275
|
+
this.relationshipTypes.push(relType);
|
|
276
|
+
return this;
|
|
277
|
+
}
|
|
278
|
+
/**
|
|
279
|
+
* Add multiple relationship types
|
|
280
|
+
*/
|
|
281
|
+
relationships(relTypes) {
|
|
282
|
+
this.relationshipTypes.push(...relTypes);
|
|
283
|
+
return this;
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Set the traversal direction
|
|
287
|
+
*/
|
|
288
|
+
direction(dir) {
|
|
289
|
+
this.traversalDirection = dir;
|
|
290
|
+
return this;
|
|
291
|
+
}
|
|
292
|
+
/**
|
|
293
|
+
* Traverse outgoing edges only
|
|
294
|
+
*/
|
|
295
|
+
outgoing() {
|
|
296
|
+
this.traversalDirection = types_1.TraversalDirection.Outgoing;
|
|
297
|
+
return this;
|
|
298
|
+
}
|
|
299
|
+
/**
|
|
300
|
+
* Traverse incoming edges only
|
|
301
|
+
*/
|
|
302
|
+
incoming() {
|
|
303
|
+
this.traversalDirection = types_1.TraversalDirection.Incoming;
|
|
304
|
+
return this;
|
|
305
|
+
}
|
|
306
|
+
/**
|
|
307
|
+
* Traverse both directions
|
|
308
|
+
*/
|
|
309
|
+
both() {
|
|
310
|
+
this.traversalDirection = types_1.TraversalDirection.Both;
|
|
311
|
+
return this;
|
|
312
|
+
}
|
|
313
|
+
/**
|
|
314
|
+
* Set the maximum traversal depth
|
|
315
|
+
*/
|
|
316
|
+
maxDepth(depth) {
|
|
317
|
+
this.maxDepthValue = depth;
|
|
318
|
+
return this;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Set the maximum number of results
|
|
322
|
+
*/
|
|
323
|
+
limit(lim) {
|
|
324
|
+
this.limitValue = lim;
|
|
325
|
+
return this;
|
|
326
|
+
}
|
|
327
|
+
/**
|
|
328
|
+
* Add a label to filter visited nodes by.
|
|
329
|
+
*/
|
|
330
|
+
nodeLabel(label) {
|
|
331
|
+
this.nodeLabelsList.push(label);
|
|
332
|
+
return this;
|
|
333
|
+
}
|
|
334
|
+
/**
|
|
335
|
+
* Replace the set of node-label filters.
|
|
336
|
+
*/
|
|
337
|
+
nodeLabels(labels) {
|
|
338
|
+
this.nodeLabelsList = [...labels];
|
|
339
|
+
return this;
|
|
340
|
+
}
|
|
341
|
+
/**
|
|
342
|
+
* Select traversal algorithm (server accepts `bfs`, `dfs`, or `shortest_path`).
|
|
343
|
+
*/
|
|
344
|
+
algorithm(name) {
|
|
345
|
+
this.algorithmValue = name;
|
|
346
|
+
return this;
|
|
347
|
+
}
|
|
348
|
+
/**
|
|
349
|
+
* Add a filter expression for nodes (client-side helper, not sent on wire).
|
|
350
|
+
*/
|
|
351
|
+
filter(filterStr) {
|
|
352
|
+
this.filterExpr = filterStr;
|
|
353
|
+
return this;
|
|
354
|
+
}
|
|
355
|
+
/**
|
|
356
|
+
* Execute the traversal.
|
|
357
|
+
*
|
|
358
|
+
* Wire endpoint: POST /api/v2/graphs/{graph_id}/traverse
|
|
359
|
+
* OpenAPI operationId: traverseGraph
|
|
360
|
+
*
|
|
361
|
+
* Body shape (server-true, per `TraverseRequest`):
|
|
362
|
+
* `{ start_node_id, max_depth, edge_types?, node_labels?, algorithm?, limit? }`.
|
|
363
|
+
* Note: spec is flat (no `graph` wrapper — `graph_id` is the URL path
|
|
364
|
+
* parameter) and has no `direction` field; legacy `direction` /
|
|
365
|
+
* `start_node` / `relationships` keys are intentionally not sent.
|
|
366
|
+
*/
|
|
367
|
+
async execute() {
|
|
368
|
+
if (this.startNodeId === null) {
|
|
369
|
+
throw new Error("Start node is required for traversal");
|
|
370
|
+
}
|
|
371
|
+
const request = {
|
|
372
|
+
start_node_id: this.startNodeId,
|
|
373
|
+
max_depth: this.maxDepthValue,
|
|
374
|
+
};
|
|
375
|
+
if (this.relationshipTypes.length > 0) {
|
|
376
|
+
request.edge_types = this.relationshipTypes;
|
|
377
|
+
}
|
|
378
|
+
if (this.nodeLabelsList.length > 0) {
|
|
379
|
+
request.node_labels = this.nodeLabelsList;
|
|
380
|
+
}
|
|
381
|
+
if (this.algorithmValue !== null) {
|
|
382
|
+
request.algorithm = this.algorithmValue;
|
|
383
|
+
}
|
|
384
|
+
if (this.limitValue !== null) {
|
|
385
|
+
request.limit = this.limitValue;
|
|
386
|
+
}
|
|
387
|
+
// Note: direction (this.traversalDirection) and filter (this.filterExpr)
|
|
388
|
+
// are intentionally NOT sent — the server `TraverseRequest` does not
|
|
389
|
+
// accept them. The setters remain for SDK ergonomic continuity.
|
|
390
|
+
void this.traversalDirection;
|
|
391
|
+
void this.filterExpr;
|
|
392
|
+
const data = await this.handle.getClient().traverseGraphRequest(this.handle.getName(), request);
|
|
393
|
+
return data;
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
exports.TraversalBuilder = TraversalBuilder;
|
|
397
|
+
// ============================================================================
|
|
398
|
+
// GRAPH HANDLE
|
|
399
|
+
// ============================================================================
|
|
400
|
+
/**
|
|
401
|
+
* Handle to a graph for fluent operations
|
|
402
|
+
*/
|
|
403
|
+
class GraphHandle {
|
|
404
|
+
client;
|
|
405
|
+
graphName;
|
|
406
|
+
constructor(client, name) {
|
|
407
|
+
this.client = client;
|
|
408
|
+
this.graphName = name;
|
|
409
|
+
}
|
|
410
|
+
/**
|
|
411
|
+
* Get the graph name
|
|
412
|
+
*/
|
|
413
|
+
getName() {
|
|
414
|
+
return this.graphName;
|
|
415
|
+
}
|
|
416
|
+
/**
|
|
417
|
+
* Get the HTTP client (internal use)
|
|
418
|
+
*/
|
|
419
|
+
getClient() {
|
|
420
|
+
return this.client;
|
|
421
|
+
}
|
|
422
|
+
/**
|
|
423
|
+
* Start building a node addition
|
|
424
|
+
*/
|
|
425
|
+
addNode() {
|
|
426
|
+
return new NodeBuilder(this);
|
|
427
|
+
}
|
|
428
|
+
/**
|
|
429
|
+
* Start building an edge addition
|
|
430
|
+
*/
|
|
431
|
+
addEdge() {
|
|
432
|
+
return new EdgeBuilder(this);
|
|
433
|
+
}
|
|
434
|
+
/**
|
|
435
|
+
* Start building a traversal query
|
|
436
|
+
*/
|
|
437
|
+
traverse() {
|
|
438
|
+
return new TraversalBuilder(this);
|
|
439
|
+
}
|
|
440
|
+
/**
|
|
441
|
+
* Add a batch of nodes.
|
|
442
|
+
*
|
|
443
|
+
* Wire endpoint: POST /api/v2/graphs/{graph_id}/nodes/batch
|
|
444
|
+
* OpenAPI operationId: batchCreateNodes
|
|
445
|
+
*
|
|
446
|
+
* Body shape (server-true, per `BatchCreateNodesRequest`):
|
|
447
|
+
* `{ nodes: [NodeInput, ...] }`. `graph_id` lives in the URL path.
|
|
448
|
+
*
|
|
449
|
+
* Accepts either spec-true `NodeInput[]` or legacy `GraphNode[]`; the
|
|
450
|
+
* latter is normalized (singular `label` → `labels: [label]`,
|
|
451
|
+
* `vector` → `embedding.vector`).
|
|
452
|
+
*/
|
|
453
|
+
async addNodes(nodes) {
|
|
454
|
+
const normalized = nodes.map(n => normalizeNodeInput(n));
|
|
455
|
+
const request = { nodes: normalized };
|
|
456
|
+
const response = (await this.client.batchCreateNodesRequest(this.graphName, request));
|
|
457
|
+
return response?.data?.count ?? response?.count ?? normalized.length;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Add a batch of edges.
|
|
461
|
+
*
|
|
462
|
+
* Wire endpoint: POST /api/v2/graphs/{graph_id}/edges/batch
|
|
463
|
+
* OpenAPI operationId: batchCreateEdges
|
|
464
|
+
*
|
|
465
|
+
* Body shape (server-true, per `BatchCreateEdgesRequest`):
|
|
466
|
+
* `{ edges: [EdgeInput, ...] }`. `graph_id` lives in the URL path.
|
|
467
|
+
*
|
|
468
|
+
* Accepts either spec-true `EdgeInput[]` or legacy `GraphEdge[]`; the
|
|
469
|
+
* latter is normalized (`source` → `from_node_id`, `target` →
|
|
470
|
+
* `to_node_id`, `relationship` → `edge_type`). Legacy `GraphEdge` has no
|
|
471
|
+
* `id` field; callers MUST upgrade to `EdgeInput` for batch use (the
|
|
472
|
+
* normalizer throws if `id` is missing).
|
|
473
|
+
*/
|
|
474
|
+
async addEdges(edges) {
|
|
475
|
+
const normalized = edges.map(e => normalizeEdgeInput(e));
|
|
476
|
+
const request = { edges: normalized };
|
|
477
|
+
const response = (await this.client.batchCreateEdgesRequest(this.graphName, request));
|
|
478
|
+
return response?.data?.count ?? response?.count ?? normalized.length;
|
|
479
|
+
}
|
|
480
|
+
/**
|
|
481
|
+
* Get a node by ID
|
|
482
|
+
*/
|
|
483
|
+
async getNode(nodeId) {
|
|
484
|
+
try {
|
|
485
|
+
const data = await this.client.getNodeRequest(this.graphName, nodeId);
|
|
486
|
+
return data;
|
|
487
|
+
}
|
|
488
|
+
catch (e) {
|
|
489
|
+
// The facade maps a 404 to a ProximaDBError (statusCode 404, message =
|
|
490
|
+
// server body). Treat "not found" as a null result, preserving the
|
|
491
|
+
// pre-rebase behavior; match on status or the body text.
|
|
492
|
+
const status = e.statusCode;
|
|
493
|
+
if (status === 404) {
|
|
494
|
+
return null;
|
|
495
|
+
}
|
|
496
|
+
if (e instanceof Error && e.message.includes("404")) {
|
|
497
|
+
return null;
|
|
498
|
+
}
|
|
499
|
+
throw e;
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
/**
|
|
503
|
+
* Delete a node by ID
|
|
504
|
+
*/
|
|
505
|
+
async deleteNode(nodeId) {
|
|
506
|
+
await this.client.deleteNodeRequest(this.graphName, nodeId);
|
|
507
|
+
}
|
|
508
|
+
// deleteEdge is intentionally LEFT facade-built (generic URL path): the
|
|
509
|
+
// generated REST client has no matching typed op for this 3-segment route
|
|
510
|
+
// shape. The OpenAPI spec / generated client model edge deletion as
|
|
511
|
+
// `DELETE /api/v2/graphs/{graph_id}/edges/{edge_id}` (single `edge_id`),
|
|
512
|
+
// whereas this SDK's public signature is `(source, target, relationship)` →
|
|
513
|
+
// `/edges/{source}/{target}/{relationship}`. Until the SDK signature is
|
|
514
|
+
// reconciled to `{edge_id}` (separate change), this cannot route through the
|
|
515
|
+
// generated client. Tracked separately.
|
|
516
|
+
/**
|
|
517
|
+
* Delete an edge
|
|
518
|
+
*/
|
|
519
|
+
async deleteEdge(source, target, relationship) {
|
|
520
|
+
const url = this.client.url() + "/api/v2/graphs/" + this.graphName + "/edges/" + source + "/" + target + "/" + relationship;
|
|
521
|
+
await this.client.delete(url);
|
|
522
|
+
}
|
|
523
|
+
/**
|
|
524
|
+
* Get graph statistics.
|
|
525
|
+
*
|
|
526
|
+
* Routed through the generated typed transport (TD-126 Phase 4).
|
|
527
|
+
* Wire endpoint: GET /api/v2/graphs/{graph_id} (getGraph)
|
|
528
|
+
*/
|
|
529
|
+
async info() {
|
|
530
|
+
const data = await this.client.getGraphRequest(this.graphName);
|
|
531
|
+
return data;
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
exports.GraphHandle = GraphHandle;
|
|
535
|
+
// ============================================================================
|
|
536
|
+
// GRAPH BUILDER
|
|
537
|
+
// ============================================================================
|
|
538
|
+
/**
|
|
539
|
+
* Builder for creating graphs
|
|
540
|
+
*/
|
|
541
|
+
class GraphBuilder {
|
|
542
|
+
client;
|
|
543
|
+
graphId;
|
|
544
|
+
graphDisplayName = null;
|
|
545
|
+
graphDescription = null;
|
|
546
|
+
constructor(client, graphId) {
|
|
547
|
+
this.client = client;
|
|
548
|
+
this.graphId = graphId;
|
|
549
|
+
}
|
|
550
|
+
/**
|
|
551
|
+
* Set an optional human-readable name (defaults server-side to graph_id).
|
|
552
|
+
*/
|
|
553
|
+
name(displayName) {
|
|
554
|
+
this.graphDisplayName = displayName;
|
|
555
|
+
return this;
|
|
556
|
+
}
|
|
557
|
+
/**
|
|
558
|
+
* Set the graph description
|
|
559
|
+
*/
|
|
560
|
+
description(desc) {
|
|
561
|
+
this.graphDescription = desc;
|
|
562
|
+
return this;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Execute the graph creation.
|
|
566
|
+
*
|
|
567
|
+
* Wire endpoint: POST /api/v2/graphs
|
|
568
|
+
* OpenAPI operationId: createGraph
|
|
569
|
+
*
|
|
570
|
+
* Body shape (server-true, per `CreateGraphRequest`):
|
|
571
|
+
* `{ graph_id, name?, description? }`.
|
|
572
|
+
*/
|
|
573
|
+
async execute() {
|
|
574
|
+
const request = { graph_id: this.graphId };
|
|
575
|
+
if (this.graphDisplayName !== null) {
|
|
576
|
+
request.name = this.graphDisplayName;
|
|
577
|
+
}
|
|
578
|
+
if (this.graphDescription !== null) {
|
|
579
|
+
request.description = this.graphDescription;
|
|
580
|
+
}
|
|
581
|
+
await this.client.createGraphRequest(request);
|
|
582
|
+
}
|
|
583
|
+
}
|
|
584
|
+
exports.GraphBuilder = GraphBuilder;
|
|
585
|
+
// ============================================================================
|
|
586
|
+
// INTERNAL: legacy -> spec normalizers
|
|
587
|
+
// ============================================================================
|
|
588
|
+
function normalizeNodeInput(input) {
|
|
589
|
+
// Distinguish legacy `GraphNode` (has singular `label` and/or `vector`) from
|
|
590
|
+
// spec-true `NodeInput` (has `labels[]` / `embedding`). Field absence is
|
|
591
|
+
// fine — `NodeInput` only requires `id`.
|
|
592
|
+
const out = { id: input.id };
|
|
593
|
+
// Inline structural check avoids a hard cross-cast.
|
|
594
|
+
const legacy = input;
|
|
595
|
+
const spec = input;
|
|
596
|
+
if (spec.labels !== undefined) {
|
|
597
|
+
out.labels = spec.labels;
|
|
598
|
+
}
|
|
599
|
+
else if (legacy.label !== undefined) {
|
|
600
|
+
out.labels = [legacy.label];
|
|
601
|
+
}
|
|
602
|
+
if (spec.properties !== undefined) {
|
|
603
|
+
out.properties = spec.properties;
|
|
604
|
+
}
|
|
605
|
+
else if (legacy.properties !== undefined) {
|
|
606
|
+
out.properties = legacy.properties;
|
|
607
|
+
}
|
|
608
|
+
if (spec.embedding !== undefined) {
|
|
609
|
+
out.embedding = spec.embedding;
|
|
610
|
+
}
|
|
611
|
+
else if (legacy.vector !== undefined) {
|
|
612
|
+
out.embedding = { vector: legacy.vector };
|
|
613
|
+
}
|
|
614
|
+
return out;
|
|
615
|
+
}
|
|
616
|
+
function normalizeEdgeInput(input) {
|
|
617
|
+
const spec = input;
|
|
618
|
+
const legacy = input;
|
|
619
|
+
// Spec edge has `id` (required), legacy has none. If absent on a legacy
|
|
620
|
+
// value, surface a hard error — server `EdgeInput.id` is required.
|
|
621
|
+
if (spec.id === undefined) {
|
|
622
|
+
throw new Error("addEdges: edge.id is required by EdgeInput (legacy GraphEdge has no id; pass an EdgeInput)");
|
|
623
|
+
}
|
|
624
|
+
const out = {
|
|
625
|
+
id: spec.id,
|
|
626
|
+
from_node_id: spec.from_node_id ?? legacy.source,
|
|
627
|
+
to_node_id: spec.to_node_id ?? legacy.target,
|
|
628
|
+
edge_type: spec.edge_type ?? legacy.relationship,
|
|
629
|
+
};
|
|
630
|
+
if (spec.properties !== undefined) {
|
|
631
|
+
out.properties = spec.properties;
|
|
632
|
+
}
|
|
633
|
+
else if (legacy.properties !== undefined) {
|
|
634
|
+
out.properties = legacy.properties;
|
|
635
|
+
}
|
|
636
|
+
if (spec.weight !== undefined) {
|
|
637
|
+
out.weight = spec.weight;
|
|
638
|
+
}
|
|
639
|
+
else if (legacy.weight !== undefined) {
|
|
640
|
+
out.weight = legacy.weight;
|
|
641
|
+
}
|
|
642
|
+
return out;
|
|
643
|
+
}
|
|
644
|
+
// ============================================================================
|
|
645
|
+
// CONVENIENCE FUNCTIONS
|
|
646
|
+
// ============================================================================
|
|
647
|
+
/**
|
|
648
|
+
* Create a new GraphNode
|
|
649
|
+
*/
|
|
650
|
+
function createNode(id) {
|
|
651
|
+
return {
|
|
652
|
+
id,
|
|
653
|
+
properties: {},
|
|
654
|
+
};
|
|
655
|
+
}
|
|
656
|
+
/**
|
|
657
|
+
* Create a new GraphNode with builder pattern
|
|
658
|
+
*/
|
|
659
|
+
function node(id) {
|
|
660
|
+
const n = { id, properties: {} };
|
|
661
|
+
return {
|
|
662
|
+
label: (l) => { n.label = l; return node(id); },
|
|
663
|
+
property: (k, v) => { n.properties[k] = v; return node(id); },
|
|
664
|
+
vector: (v) => { n.vector = v; return node(id); },
|
|
665
|
+
build: () => n,
|
|
666
|
+
};
|
|
667
|
+
}
|
|
668
|
+
/**
|
|
669
|
+
* Create a new GraphEdge
|
|
670
|
+
*/
|
|
671
|
+
function createEdge(source, target, relationship) {
|
|
672
|
+
return {
|
|
673
|
+
source,
|
|
674
|
+
target,
|
|
675
|
+
relationship,
|
|
676
|
+
properties: {},
|
|
677
|
+
};
|
|
678
|
+
}
|
|
679
|
+
/**
|
|
680
|
+
* Create a new GraphEdge with builder pattern
|
|
681
|
+
*/
|
|
682
|
+
function edge(source, target, relationship) {
|
|
683
|
+
const e = { source, target, relationship, properties: {} };
|
|
684
|
+
return {
|
|
685
|
+
property: (k, v) => { e.properties[k] = v; return edge(source, target, relationship); },
|
|
686
|
+
weight: (w) => { e.weight = w; return edge(source, target, relationship); },
|
|
687
|
+
build: () => e,
|
|
688
|
+
};
|
|
689
|
+
}
|
|
690
|
+
//# sourceMappingURL=graph.js.map
|