Merge commit 'd803bfe2b1fe7f5e219e50ac20d6801a0a58ac75' as 'vendor/ruvector'
This commit is contained in:
106
vendor/ruvector/npm/packages/graph-node/README.md
vendored
Normal file
106
vendor/ruvector/npm/packages/graph-node/README.md
vendored
Normal file
@@ -0,0 +1,106 @@
|
||||
# @ruvector/graph-node
|
||||
|
||||
Native Node.js bindings for RuVector Graph Database with hypergraph support, Cypher queries, and persistence. **10x faster than WASM**.
|
||||
|
||||
## Features
|
||||
|
||||
- **Native Performance**: Direct NAPI-RS bindings - no WASM overhead
|
||||
- **Hypergraph Support**: Multi-node relationships with vector embeddings
|
||||
- **Cypher Queries**: Neo4j-compatible query language
|
||||
- **Persistence**: ACID-compliant storage with redb backend
|
||||
- **Vector Similarity Search**: Fast k-NN search on embeddings
|
||||
- **Graph Traversal**: k-hop neighbor discovery
|
||||
- **Transactions**: Full ACID support with begin/commit/rollback
|
||||
- **Batch Operations**: High-throughput bulk inserts (131K+ ops/sec)
|
||||
- **Zero-Copy**: Efficient Float32Array handling
|
||||
- **TypeScript**: Full type definitions included
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
npm install @ruvector/graph-node
|
||||
```
|
||||
|
||||
## Quick Start
|
||||
|
||||
```javascript
|
||||
const { GraphDatabase } = require('@ruvector/graph-node');
|
||||
|
||||
// Create an in-memory database
|
||||
const db = new GraphDatabase({
|
||||
distanceMetric: 'Cosine',
|
||||
dimensions: 384
|
||||
});
|
||||
|
||||
// Or create a persistent database
|
||||
const persistentDb = new GraphDatabase({
|
||||
distanceMetric: 'Cosine',
|
||||
dimensions: 384,
|
||||
storagePath: './my-graph.db'
|
||||
});
|
||||
|
||||
// Or open an existing database
|
||||
const existingDb = GraphDatabase.open('./my-graph.db');
|
||||
|
||||
// Create nodes
|
||||
await db.createNode({
|
||||
id: 'alice',
|
||||
embedding: new Float32Array([1.0, 0.0, 0.0, /* ... */]),
|
||||
labels: ['Person', 'Employee'],
|
||||
properties: { name: 'Alice', age: '30' }
|
||||
});
|
||||
|
||||
// Create edges
|
||||
await db.createEdge({
|
||||
from: 'alice',
|
||||
to: 'bob',
|
||||
description: 'KNOWS',
|
||||
embedding: new Float32Array([0.5, 0.5, 0.0, /* ... */]),
|
||||
confidence: 0.95
|
||||
});
|
||||
|
||||
// Create hyperedges (multi-node relationships)
|
||||
await db.createHyperedge({
|
||||
nodes: ['alice', 'bob', 'charlie'],
|
||||
description: 'COLLABORATED_ON_PROJECT',
|
||||
embedding: new Float32Array([0.33, 0.33, 0.33, /* ... */]),
|
||||
confidence: 0.85
|
||||
});
|
||||
|
||||
// Query with Cypher
|
||||
const results = await db.query('MATCH (n:Person) RETURN n');
|
||||
|
||||
// Vector similarity search
|
||||
const similar = await db.searchHyperedges({
|
||||
embedding: new Float32Array([0.3, 0.3, 0.3, /* ... */]),
|
||||
k: 10
|
||||
});
|
||||
|
||||
// Get statistics
|
||||
const stats = await db.stats();
|
||||
console.log(\`Nodes: \${stats.totalNodes}, Edges: \${stats.totalEdges}\`);
|
||||
```
|
||||
|
||||
## Benchmarks
|
||||
|
||||
| Operation | Throughput | Latency |
|
||||
|-----------|------------|---------|
|
||||
| Node Creation | 9.17K ops/sec | 109ms |
|
||||
| Batch Node Creation | 131.10K ops/sec | 7.63ms |
|
||||
| Edge Creation | 9.30K ops/sec | 107ms |
|
||||
| Vector Search (k=10) | 2.35K ops/sec | 42ms |
|
||||
| k-hop Traversal | 10.28K ops/sec | 9.73ms |
|
||||
|
||||
## Platform Support
|
||||
|
||||
| Platform | Architecture | Status |
|
||||
|----------|--------------|--------|
|
||||
| Linux | x64 (glibc) | Supported |
|
||||
| Linux | arm64 (glibc) | Supported |
|
||||
| macOS | x64 | Supported |
|
||||
| macOS | arm64 (M1/M2) | Supported |
|
||||
| Windows | x64 | Supported |
|
||||
|
||||
## License
|
||||
|
||||
MIT
|
||||
216
vendor/ruvector/npm/packages/graph-node/benchmark.js
vendored
Normal file
216
vendor/ruvector/npm/packages/graph-node/benchmark.js
vendored
Normal file
@@ -0,0 +1,216 @@
|
||||
/**
|
||||
* RuVector Graph Node Benchmark
|
||||
*
|
||||
* Tests performance of graph operations including:
|
||||
* - Node creation
|
||||
* - Edge creation
|
||||
* - Hyperedge creation
|
||||
* - Batch inserts
|
||||
* - Vector similarity search
|
||||
* - k-hop neighbor traversal
|
||||
* - Cypher queries
|
||||
*/
|
||||
|
||||
const { GraphDatabase, version } = require('./index.js');
|
||||
|
||||
const DIMENSIONS = 384;
|
||||
const NUM_NODES = 10000;
|
||||
const NUM_EDGES = 50000;
|
||||
const NUM_HYPEREDGES = 5000;
|
||||
const SEARCH_K = 10;
|
||||
|
||||
function randomEmbedding(dims) {
|
||||
const arr = new Float32Array(dims);
|
||||
for (let i = 0; i < dims; i++) {
|
||||
arr[i] = Math.random();
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
function formatTime(ms) {
|
||||
if (ms < 1) return `${(ms * 1000).toFixed(2)}μs`;
|
||||
if (ms < 1000) return `${ms.toFixed(2)}ms`;
|
||||
return `${(ms / 1000).toFixed(2)}s`;
|
||||
}
|
||||
|
||||
function formatOps(count, ms) {
|
||||
const ops = (count / ms) * 1000;
|
||||
if (ops >= 1000000) return `${(ops / 1000000).toFixed(2)}M ops/sec`;
|
||||
if (ops >= 1000) return `${(ops / 1000).toFixed(2)}K ops/sec`;
|
||||
return `${ops.toFixed(2)} ops/sec`;
|
||||
}
|
||||
|
||||
async function benchmark() {
|
||||
console.log('╔════════════════════════════════════════════════════════════════╗');
|
||||
console.log('║ RuVector Graph Node Benchmark Suite ║');
|
||||
console.log('╠════════════════════════════════════════════════════════════════╣');
|
||||
console.log(`║ Version: ${version().padEnd(54)}║`);
|
||||
console.log(`║ Dimensions: ${DIMENSIONS.toString().padEnd(51)}║`);
|
||||
console.log(`║ Nodes: ${NUM_NODES.toLocaleString().padEnd(56)}║`);
|
||||
console.log(`║ Edges: ${NUM_EDGES.toLocaleString().padEnd(56)}║`);
|
||||
console.log(`║ Hyperedges: ${NUM_HYPEREDGES.toLocaleString().padEnd(51)}║`);
|
||||
console.log('╚════════════════════════════════════════════════════════════════╝\n');
|
||||
|
||||
const db = new GraphDatabase({
|
||||
distanceMetric: 'Cosine',
|
||||
dimensions: DIMENSIONS
|
||||
});
|
||||
|
||||
const results = [];
|
||||
|
||||
// Benchmark 1: Node Creation
|
||||
console.log('📌 Benchmark 1: Individual Node Creation');
|
||||
const nodeCount = 1000;
|
||||
const nodeStart = performance.now();
|
||||
for (let i = 0; i < nodeCount; i++) {
|
||||
await db.createNode({
|
||||
id: `node_${i}`,
|
||||
embedding: randomEmbedding(DIMENSIONS),
|
||||
labels: ['TestNode'],
|
||||
properties: { index: String(i) }
|
||||
});
|
||||
}
|
||||
const nodeEnd = performance.now();
|
||||
const nodeTime = nodeEnd - nodeStart;
|
||||
console.log(` Created ${nodeCount} nodes in ${formatTime(nodeTime)}`);
|
||||
console.log(` Throughput: ${formatOps(nodeCount, nodeTime)}\n`);
|
||||
results.push({ name: 'Node Creation', count: nodeCount, time: nodeTime });
|
||||
|
||||
// Benchmark 2: Batch Node Creation
|
||||
console.log('📌 Benchmark 2: Batch Node Creation');
|
||||
const batchSize = 1000;
|
||||
const batchNodes = [];
|
||||
for (let i = 0; i < batchSize; i++) {
|
||||
batchNodes.push({
|
||||
id: `batch_node_${i}`,
|
||||
embedding: randomEmbedding(DIMENSIONS),
|
||||
labels: ['BatchNode']
|
||||
});
|
||||
}
|
||||
const batchNodeStart = performance.now();
|
||||
await db.batchInsert({ nodes: batchNodes, edges: [] });
|
||||
const batchNodeEnd = performance.now();
|
||||
const batchNodeTime = batchNodeEnd - batchNodeStart;
|
||||
console.log(` Inserted ${batchSize} nodes in ${formatTime(batchNodeTime)}`);
|
||||
console.log(` Throughput: ${formatOps(batchSize, batchNodeTime)}\n`);
|
||||
results.push({ name: 'Batch Node Creation', count: batchSize, time: batchNodeTime });
|
||||
|
||||
// Benchmark 3: Edge Creation
|
||||
console.log('📌 Benchmark 3: Edge Creation');
|
||||
const edgeCount = 1000;
|
||||
const edgeStart = performance.now();
|
||||
for (let i = 0; i < edgeCount; i++) {
|
||||
const from = `node_${i % nodeCount}`;
|
||||
const to = `node_${(i + 1) % nodeCount}`;
|
||||
await db.createEdge({
|
||||
from,
|
||||
to,
|
||||
description: 'CONNECTED_TO',
|
||||
embedding: randomEmbedding(DIMENSIONS),
|
||||
confidence: Math.random()
|
||||
});
|
||||
}
|
||||
const edgeEnd = performance.now();
|
||||
const edgeTime = edgeEnd - edgeStart;
|
||||
console.log(` Created ${edgeCount} edges in ${formatTime(edgeTime)}`);
|
||||
console.log(` Throughput: ${formatOps(edgeCount, edgeTime)}\n`);
|
||||
results.push({ name: 'Edge Creation', count: edgeCount, time: edgeTime });
|
||||
|
||||
// Benchmark 4: Hyperedge Creation
|
||||
console.log('📌 Benchmark 4: Hyperedge Creation');
|
||||
const hyperedgeCount = 500;
|
||||
const hyperedgeStart = performance.now();
|
||||
for (let i = 0; i < hyperedgeCount; i++) {
|
||||
const nodes = [];
|
||||
const numNodes = 3 + Math.floor(Math.random() * 5); // 3-7 nodes per hyperedge
|
||||
for (let j = 0; j < numNodes; j++) {
|
||||
nodes.push(`node_${(i + j) % nodeCount}`);
|
||||
}
|
||||
await db.createHyperedge({
|
||||
nodes,
|
||||
description: `RELATIONSHIP_${i}`,
|
||||
embedding: randomEmbedding(DIMENSIONS),
|
||||
confidence: Math.random()
|
||||
});
|
||||
}
|
||||
const hyperedgeEnd = performance.now();
|
||||
const hyperedgeTime = hyperedgeEnd - hyperedgeStart;
|
||||
console.log(` Created ${hyperedgeCount} hyperedges in ${formatTime(hyperedgeTime)}`);
|
||||
console.log(` Throughput: ${formatOps(hyperedgeCount, hyperedgeTime)}\n`);
|
||||
results.push({ name: 'Hyperedge Creation', count: hyperedgeCount, time: hyperedgeTime });
|
||||
|
||||
// Benchmark 5: Vector Similarity Search
|
||||
console.log('📌 Benchmark 5: Vector Similarity Search');
|
||||
const searchCount = 100;
|
||||
const searchStart = performance.now();
|
||||
for (let i = 0; i < searchCount; i++) {
|
||||
await db.searchHyperedges({
|
||||
embedding: randomEmbedding(DIMENSIONS),
|
||||
k: SEARCH_K
|
||||
});
|
||||
}
|
||||
const searchEnd = performance.now();
|
||||
const searchTime = searchEnd - searchStart;
|
||||
console.log(` Performed ${searchCount} searches (k=${SEARCH_K}) in ${formatTime(searchTime)}`);
|
||||
console.log(` Throughput: ${formatOps(searchCount, searchTime)}\n`);
|
||||
results.push({ name: 'Vector Search', count: searchCount, time: searchTime });
|
||||
|
||||
// Benchmark 6: k-hop Neighbor Traversal
|
||||
console.log('📌 Benchmark 6: k-hop Neighbor Traversal');
|
||||
const traversalCount = 100;
|
||||
const traversalStart = performance.now();
|
||||
for (let i = 0; i < traversalCount; i++) {
|
||||
await db.kHopNeighbors(`node_${i % nodeCount}`, 2);
|
||||
}
|
||||
const traversalEnd = performance.now();
|
||||
const traversalTime = traversalEnd - traversalStart;
|
||||
console.log(` Performed ${traversalCount} 2-hop traversals in ${formatTime(traversalTime)}`);
|
||||
console.log(` Throughput: ${formatOps(traversalCount, traversalTime)}\n`);
|
||||
results.push({ name: 'k-hop Traversal', count: traversalCount, time: traversalTime });
|
||||
|
||||
// Benchmark 7: Statistics Query
|
||||
console.log('📌 Benchmark 7: Statistics Query');
|
||||
const statsCount = 1000;
|
||||
const statsStart = performance.now();
|
||||
for (let i = 0; i < statsCount; i++) {
|
||||
await db.stats();
|
||||
}
|
||||
const statsEnd = performance.now();
|
||||
const statsTime = statsEnd - statsStart;
|
||||
console.log(` Performed ${statsCount} stats queries in ${formatTime(statsTime)}`);
|
||||
console.log(` Throughput: ${formatOps(statsCount, statsTime)}\n`);
|
||||
results.push({ name: 'Stats Query', count: statsCount, time: statsTime });
|
||||
|
||||
// Benchmark 8: Transaction Overhead
|
||||
console.log('📌 Benchmark 8: Transaction Overhead');
|
||||
const txCount = 100;
|
||||
const txStart = performance.now();
|
||||
for (let i = 0; i < txCount; i++) {
|
||||
const txId = await db.begin();
|
||||
await db.commit(txId);
|
||||
}
|
||||
const txEnd = performance.now();
|
||||
const txTime = txEnd - txStart;
|
||||
console.log(` Performed ${txCount} transactions in ${formatTime(txTime)}`);
|
||||
console.log(` Throughput: ${formatOps(txCount, txTime)}\n`);
|
||||
results.push({ name: 'Transaction', count: txCount, time: txTime });
|
||||
|
||||
// Summary
|
||||
console.log('╔════════════════════════════════════════════════════════════════╗');
|
||||
console.log('║ BENCHMARK SUMMARY ║');
|
||||
console.log('╠════════════════════════════════════════════════════════════════╣');
|
||||
for (const r of results) {
|
||||
const ops = formatOps(r.count, r.time);
|
||||
console.log(`║ ${r.name.padEnd(25)} ${ops.padStart(20)} ${formatTime(r.time).padStart(12)} ║`);
|
||||
}
|
||||
console.log('╚════════════════════════════════════════════════════════════════╝');
|
||||
|
||||
// Final stats
|
||||
const finalStats = await db.stats();
|
||||
console.log(`\n📊 Final Database State:`);
|
||||
console.log(` Total Nodes: ${finalStats.totalNodes.toLocaleString()}`);
|
||||
console.log(` Total Edges: ${finalStats.totalEdges.toLocaleString()}`);
|
||||
console.log(` Avg Degree: ${finalStats.avgDegree.toFixed(4)}`);
|
||||
}
|
||||
|
||||
benchmark().catch(console.error);
|
||||
370
vendor/ruvector/npm/packages/graph-node/index.d.ts
vendored
Normal file
370
vendor/ruvector/npm/packages/graph-node/index.d.ts
vendored
Normal file
@@ -0,0 +1,370 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
|
||||
/* auto-generated by NAPI-RS */
|
||||
|
||||
/** Distance metric for similarity calculation */
|
||||
export const enum JsDistanceMetric {
|
||||
Euclidean = 'Euclidean',
|
||||
Cosine = 'Cosine',
|
||||
DotProduct = 'DotProduct',
|
||||
Manhattan = 'Manhattan'
|
||||
}
|
||||
/** Graph database configuration options */
|
||||
export interface JsGraphOptions {
|
||||
/** Distance metric for embeddings */
|
||||
distanceMetric?: JsDistanceMetric
|
||||
/** Vector dimensions */
|
||||
dimensions?: number
|
||||
/** Storage path */
|
||||
storagePath?: string
|
||||
}
|
||||
/** Node in the graph */
|
||||
export interface JsNode {
|
||||
/** Node ID */
|
||||
id: string
|
||||
/** Node embedding */
|
||||
embedding: Float32Array
|
||||
/** Node labels (e.g., ["Person", "Employee"]) */
|
||||
labels?: Array<string>
|
||||
/** Optional properties */
|
||||
properties?: Record<string, string>
|
||||
}
|
||||
/** Edge between two nodes */
|
||||
export interface JsEdge {
|
||||
/** Source node ID */
|
||||
from: string
|
||||
/** Target node ID */
|
||||
to: string
|
||||
/** Edge description/label */
|
||||
description: string
|
||||
/** Edge embedding */
|
||||
embedding: Float32Array
|
||||
/** Confidence score (0.0-1.0) */
|
||||
confidence?: number
|
||||
/** Optional metadata */
|
||||
metadata?: Record<string, string>
|
||||
}
|
||||
/** Hyperedge connecting multiple nodes */
|
||||
export interface JsHyperedge {
|
||||
/** Node IDs connected by this hyperedge */
|
||||
nodes: Array<string>
|
||||
/** Natural language description of the relationship */
|
||||
description: string
|
||||
/** Embedding of the hyperedge description */
|
||||
embedding: Float32Array
|
||||
/** Confidence weight (0.0-1.0) */
|
||||
confidence?: number
|
||||
/** Optional metadata */
|
||||
metadata?: Record<string, string>
|
||||
}
|
||||
/** Query for searching hyperedges */
|
||||
export interface JsHyperedgeQuery {
|
||||
/** Query embedding */
|
||||
embedding: Float32Array
|
||||
/** Number of results to return */
|
||||
k: number
|
||||
}
|
||||
/** Hyperedge search result */
|
||||
export interface JsHyperedgeResult {
|
||||
/** Hyperedge ID */
|
||||
id: string
|
||||
/** Similarity score */
|
||||
score: number
|
||||
}
|
||||
/** Node result from query (without embedding) */
|
||||
export interface JsNodeResult {
|
||||
/** Node ID */
|
||||
id: string
|
||||
/** Node labels */
|
||||
labels: Array<string>
|
||||
/** Node properties */
|
||||
properties: Record<string, string>
|
||||
}
|
||||
/** Edge result from query */
|
||||
export interface JsEdgeResult {
|
||||
/** Edge ID */
|
||||
id: string
|
||||
/** Source node ID */
|
||||
from: string
|
||||
/** Target node ID */
|
||||
to: string
|
||||
/** Edge type/label */
|
||||
edgeType: string
|
||||
/** Edge properties */
|
||||
properties: Record<string, string>
|
||||
}
|
||||
/** Query result */
|
||||
export interface JsQueryResult {
|
||||
/** Nodes returned by the query */
|
||||
nodes: Array<JsNodeResult>
|
||||
/** Edges returned by the query */
|
||||
edges: Array<JsEdgeResult>
|
||||
/** Optional statistics */
|
||||
stats?: JsGraphStats
|
||||
}
|
||||
/** Graph statistics */
|
||||
export interface JsGraphStats {
|
||||
/** Total number of nodes */
|
||||
totalNodes: number
|
||||
/** Total number of edges */
|
||||
totalEdges: number
|
||||
/** Average node degree */
|
||||
avgDegree: number
|
||||
}
|
||||
/** Batch insert data */
|
||||
export interface JsBatchInsert {
|
||||
/** Nodes to insert */
|
||||
nodes: Array<JsNode>
|
||||
/** Edges to insert */
|
||||
edges: Array<JsEdge>
|
||||
}
|
||||
/** Batch insert result */
|
||||
export interface JsBatchResult {
|
||||
/** IDs of inserted nodes */
|
||||
nodeIds: Array<string>
|
||||
/** IDs of inserted edges */
|
||||
edgeIds: Array<string>
|
||||
}
|
||||
/** Temporal granularity */
|
||||
export const enum JsTemporalGranularity {
|
||||
Hourly = 'Hourly',
|
||||
Daily = 'Daily',
|
||||
Monthly = 'Monthly',
|
||||
Yearly = 'Yearly'
|
||||
}
|
||||
/** Temporal hyperedge */
|
||||
export interface JsTemporalHyperedge {
|
||||
/** Base hyperedge */
|
||||
hyperedge: JsHyperedge
|
||||
/** Creation timestamp (Unix epoch seconds) */
|
||||
timestamp: number
|
||||
/** Optional expiration timestamp */
|
||||
expiresAt?: number
|
||||
/** Temporal context */
|
||||
granularity: JsTemporalGranularity
|
||||
}
|
||||
/** Get the version of the library */
|
||||
export declare function version(): string
|
||||
/** Test function to verify bindings */
|
||||
export declare function hello(): string
|
||||
/** Streaming query result iterator */
|
||||
export declare class QueryResultStream {
|
||||
/**
|
||||
* Get the next result from the stream
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const stream = await db.queryStream('MATCH (n) RETURN n');
|
||||
* while (true) {
|
||||
* const result = await stream.next();
|
||||
* if (!result) break;
|
||||
* console.log(result);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
next(): JsQueryResult | null
|
||||
}
|
||||
/** Streaming hyperedge result iterator */
|
||||
export declare class HyperedgeStream {
|
||||
/**
|
||||
* Get the next hyperedge result
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const stream = await db.searchHyperedgesStream(query);
|
||||
* for await (const result of stream) {
|
||||
* console.log(result);
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
next(): JsHyperedgeResult | null
|
||||
/** Collect all remaining results */
|
||||
collect(): Array<JsHyperedgeResult>
|
||||
}
|
||||
/** Node stream iterator */
|
||||
export declare class NodeStream {
|
||||
/** Get the next node */
|
||||
next(): JsNode | null
|
||||
/** Collect all remaining nodes */
|
||||
collect(): Array<JsNode>
|
||||
}
|
||||
/** Graph database for complex relationship queries */
|
||||
export declare class GraphDatabase {
|
||||
/**
|
||||
* Create a new graph database
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const db = new GraphDatabase({
|
||||
* distanceMetric: 'Cosine',
|
||||
* dimensions: 384
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
constructor(options?: JsGraphOptions | undefined | null)
|
||||
/**
|
||||
* Open an existing graph database from disk
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const db = GraphDatabase.open('./my-graph.db');
|
||||
* ```
|
||||
*/
|
||||
static open(path: string): GraphDatabase
|
||||
/**
|
||||
* Check if persistence is enabled
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* if (db.isPersistent()) {
|
||||
* console.log('Data is being saved to:', db.getStoragePath());
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
isPersistent(): boolean
|
||||
/** Get the storage path (if persisted) */
|
||||
getStoragePath(): string | null
|
||||
/**
|
||||
* Create a node in the graph
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const nodeId = await db.createNode({
|
||||
* id: 'node1',
|
||||
* embedding: new Float32Array([1, 2, 3]),
|
||||
* properties: { name: 'Alice', age: 30 }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
createNode(node: JsNode): Promise<string>
|
||||
/**
|
||||
* Create an edge between two nodes
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const edgeId = await db.createEdge({
|
||||
* from: 'node1',
|
||||
* to: 'node2',
|
||||
* description: 'knows',
|
||||
* embedding: new Float32Array([0.5, 0.5, 0.5]),
|
||||
* confidence: 0.95
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
createEdge(edge: JsEdge): Promise<string>
|
||||
/**
|
||||
* Create a hyperedge connecting multiple nodes
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const hyperedgeId = await db.createHyperedge({
|
||||
* nodes: ['node1', 'node2', 'node3'],
|
||||
* description: 'collaborated_on_project',
|
||||
* embedding: new Float32Array([0.3, 0.6, 0.9]),
|
||||
* confidence: 0.85,
|
||||
* metadata: { project: 'AI Research' }
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
createHyperedge(hyperedge: JsHyperedge): Promise<string>
|
||||
/**
|
||||
* Query the graph using Cypher-like syntax
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const results = await db.query('MATCH (n) RETURN n LIMIT 10');
|
||||
* ```
|
||||
*/
|
||||
query(cypher: string): Promise<JsQueryResult>
|
||||
/**
|
||||
* Query the graph synchronously
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const results = db.querySync('MATCH (n) RETURN n LIMIT 10');
|
||||
* ```
|
||||
*/
|
||||
querySync(cypher: string): JsQueryResult
|
||||
/**
|
||||
* Search for similar hyperedges
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const results = await db.searchHyperedges({
|
||||
* embedding: new Float32Array([0.5, 0.5, 0.5]),
|
||||
* k: 10
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
searchHyperedges(query: JsHyperedgeQuery): Promise<Array<JsHyperedgeResult>>
|
||||
/**
|
||||
* Get k-hop neighbors from a starting node
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const neighbors = await db.kHopNeighbors('node1', 2);
|
||||
* ```
|
||||
*/
|
||||
kHopNeighbors(startNode: string, k: number): Promise<Array<string>>
|
||||
/**
|
||||
* Begin a new transaction
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const txId = await db.begin();
|
||||
* ```
|
||||
*/
|
||||
begin(): Promise<string>
|
||||
/**
|
||||
* Commit a transaction
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* await db.commit(txId);
|
||||
* ```
|
||||
*/
|
||||
commit(txId: string): Promise<void>
|
||||
/**
|
||||
* Rollback a transaction
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* await db.rollback(txId);
|
||||
* ```
|
||||
*/
|
||||
rollback(txId: string): Promise<void>
|
||||
/**
|
||||
* Batch insert nodes and edges
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* await db.batchInsert({
|
||||
* nodes: [{ id: 'n1', embedding: new Float32Array([1, 2]) }],
|
||||
* edges: [{ from: 'n1', to: 'n2', description: 'knows' }]
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
batchInsert(batch: JsBatchInsert): Promise<JsBatchResult>
|
||||
/**
|
||||
* Subscribe to graph changes (returns a change stream)
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const unsubscribe = db.subscribe((change) => {
|
||||
* console.log('Graph changed:', change);
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
subscribe(callback: (...args: any[]) => any): void
|
||||
/**
|
||||
* Get graph statistics
|
||||
*
|
||||
* # Example
|
||||
* ```javascript
|
||||
* const stats = await db.stats();
|
||||
* console.log(`Nodes: ${stats.totalNodes}, Edges: ${stats.totalEdges}`);
|
||||
* ```
|
||||
*/
|
||||
stats(): Promise<JsGraphStats>
|
||||
}
|
||||
322
vendor/ruvector/npm/packages/graph-node/index.js
vendored
Normal file
322
vendor/ruvector/npm/packages/graph-node/index.js
vendored
Normal file
@@ -0,0 +1,322 @@
|
||||
/* tslint:disable */
|
||||
/* eslint-disable */
|
||||
/* prettier-ignore */
|
||||
|
||||
/* auto-generated by NAPI-RS */
|
||||
|
||||
const { existsSync, readFileSync } = require('fs')
|
||||
const { join } = require('path')
|
||||
|
||||
const { platform, arch } = process
|
||||
|
||||
let nativeBinding = null
|
||||
let localFileExisted = false
|
||||
let loadError = null
|
||||
|
||||
function isMusl() {
|
||||
// For Node 10
|
||||
if (!process.report || typeof process.report.getReport !== 'function') {
|
||||
try {
|
||||
const lddPath = require('child_process').execSync('which ldd').toString().trim()
|
||||
return readFileSync(lddPath, 'utf8').includes('musl')
|
||||
} catch (e) {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
const { glibcVersionRuntime } = process.report.getReport().header
|
||||
return !glibcVersionRuntime
|
||||
}
|
||||
}
|
||||
|
||||
switch (platform) {
|
||||
case 'android':
|
||||
switch (arch) {
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(join(__dirname, 'index.android-arm64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.android-arm64.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-android-arm64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm':
|
||||
localFileExisted = existsSync(join(__dirname, 'index.android-arm-eabi.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.android-arm-eabi.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-android-arm-eabi')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Android ${arch}`)
|
||||
}
|
||||
break
|
||||
case 'win32':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.win32-x64-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.win32-x64-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-win32-x64-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'ia32':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.win32-ia32-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.win32-ia32-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-win32-ia32-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.win32-arm64-msvc.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.win32-arm64-msvc.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-win32-arm64-msvc')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Windows: ${arch}`)
|
||||
}
|
||||
break
|
||||
case 'darwin':
|
||||
localFileExisted = existsSync(join(__dirname, 'index.darwin-universal.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.darwin-universal.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-darwin-universal')
|
||||
}
|
||||
break
|
||||
} catch {}
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
localFileExisted = existsSync(join(__dirname, 'index.darwin-x64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.darwin-x64.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-darwin-x64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.darwin-arm64.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.darwin-arm64.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-darwin-arm64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on macOS: ${arch}`)
|
||||
}
|
||||
break
|
||||
case 'freebsd':
|
||||
if (arch !== 'x64') {
|
||||
throw new Error(`Unsupported architecture on FreeBSD: ${arch}`)
|
||||
}
|
||||
localFileExisted = existsSync(join(__dirname, 'index.freebsd-x64.node'))
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.freebsd-x64.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-freebsd-x64')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
case 'linux':
|
||||
switch (arch) {
|
||||
case 'x64':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.linux-x64-musl.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.linux-x64-musl.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-linux-x64-musl')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.linux-x64-gnu.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.linux-x64-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-linux-x64-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'arm64':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.linux-arm64-musl.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.linux-arm64-musl.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-linux-arm64-musl')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.linux-arm64-gnu.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.linux-arm64-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-linux-arm64-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'arm':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.linux-arm-musleabihf.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.linux-arm-musleabihf.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-linux-arm-musleabihf')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.linux-arm-gnueabihf.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.linux-arm-gnueabihf.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-linux-arm-gnueabihf')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 'riscv64':
|
||||
if (isMusl()) {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.linux-riscv64-musl.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.linux-riscv64-musl.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-linux-riscv64-musl')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
} else {
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.linux-riscv64-gnu.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.linux-riscv64-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-linux-riscv64-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
}
|
||||
break
|
||||
case 's390x':
|
||||
localFileExisted = existsSync(
|
||||
join(__dirname, 'index.linux-s390x-gnu.node')
|
||||
)
|
||||
try {
|
||||
if (localFileExisted) {
|
||||
nativeBinding = require('./index.linux-s390x-gnu.node')
|
||||
} else {
|
||||
nativeBinding = require('@ruvector/graph-node-linux-s390x-gnu')
|
||||
}
|
||||
} catch (e) {
|
||||
loadError = e
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported architecture on Linux: ${arch}`)
|
||||
}
|
||||
break
|
||||
default:
|
||||
throw new Error(`Unsupported OS: ${platform}, architecture: ${arch}`)
|
||||
}
|
||||
|
||||
if (!nativeBinding) {
|
||||
if (loadError) {
|
||||
throw loadError
|
||||
}
|
||||
throw new Error(`Failed to load native binding`)
|
||||
}
|
||||
|
||||
const { QueryResultStream, HyperedgeStream, NodeStream, JsDistanceMetric, JsTemporalGranularity, GraphDatabase, version, hello } = nativeBinding
|
||||
|
||||
module.exports.QueryResultStream = QueryResultStream
|
||||
module.exports.HyperedgeStream = HyperedgeStream
|
||||
module.exports.NodeStream = NodeStream
|
||||
module.exports.JsDistanceMetric = JsDistanceMetric
|
||||
module.exports.JsTemporalGranularity = JsTemporalGranularity
|
||||
module.exports.GraphDatabase = GraphDatabase
|
||||
module.exports.version = version
|
||||
module.exports.hello = hello
|
||||
10
vendor/ruvector/npm/packages/graph-node/npm/darwin-arm64/package.json
vendored
Normal file
10
vendor/ruvector/npm/packages/graph-node/npm/darwin-arm64/package.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@ruvector/graph-node-darwin-arm64",
|
||||
"version": "0.1.26",
|
||||
"os": ["darwin"],
|
||||
"cpu": ["arm64"],
|
||||
"main": "ruvector-graph.node",
|
||||
"files": ["ruvector-graph.node"],
|
||||
"license": "MIT",
|
||||
"repository": {"type": "git", "url": "https://github.com/ruvnet/ruvector.git"}
|
||||
}
|
||||
10
vendor/ruvector/npm/packages/graph-node/npm/darwin-x64/package.json
vendored
Normal file
10
vendor/ruvector/npm/packages/graph-node/npm/darwin-x64/package.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@ruvector/graph-node-darwin-x64",
|
||||
"version": "0.1.26",
|
||||
"os": ["darwin"],
|
||||
"cpu": ["x64"],
|
||||
"main": "ruvector-graph.node",
|
||||
"files": ["ruvector-graph.node"],
|
||||
"license": "MIT",
|
||||
"repository": {"type": "git", "url": "https://github.com/ruvnet/ruvector.git"}
|
||||
}
|
||||
10
vendor/ruvector/npm/packages/graph-node/npm/linux-arm64-gnu/package.json
vendored
Normal file
10
vendor/ruvector/npm/packages/graph-node/npm/linux-arm64-gnu/package.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@ruvector/graph-node-linux-arm64-gnu",
|
||||
"version": "0.1.26",
|
||||
"os": ["linux"],
|
||||
"cpu": ["arm64"],
|
||||
"main": "ruvector-graph.node",
|
||||
"files": ["ruvector-graph.node"],
|
||||
"license": "MIT",
|
||||
"repository": {"type": "git", "url": "https://github.com/ruvnet/ruvector.git"}
|
||||
}
|
||||
10
vendor/ruvector/npm/packages/graph-node/npm/win32-x64-msvc/package.json
vendored
Normal file
10
vendor/ruvector/npm/packages/graph-node/npm/win32-x64-msvc/package.json
vendored
Normal file
@@ -0,0 +1,10 @@
|
||||
{
|
||||
"name": "@ruvector/graph-node-win32-x64-msvc",
|
||||
"version": "0.1.26",
|
||||
"os": ["win32"],
|
||||
"cpu": ["x64"],
|
||||
"main": "ruvector-graph.node",
|
||||
"files": ["ruvector-graph.node"],
|
||||
"license": "MIT",
|
||||
"repository": {"type": "git", "url": "https://github.com/ruvnet/ruvector.git"}
|
||||
}
|
||||
67
vendor/ruvector/npm/packages/graph-node/package.json
vendored
Normal file
67
vendor/ruvector/npm/packages/graph-node/package.json
vendored
Normal file
@@ -0,0 +1,67 @@
|
||||
{
|
||||
"name": "@ruvector/graph-node",
|
||||
"version": "2.0.2",
|
||||
"description": "Native Node.js bindings for RuVector Graph Database with hypergraph support, Cypher queries, and persistence - 10x faster than WASM",
|
||||
"main": "index.js",
|
||||
"types": "index.d.ts",
|
||||
"author": "ruv.io Team <info@ruv.io> (https://ruv.io)",
|
||||
"homepage": "https://ruv.io",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/ruvnet/ruvector.git",
|
||||
"directory": "npm/packages/graph-node"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/ruvnet/ruvector/issues"
|
||||
},
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18.0.0"
|
||||
},
|
||||
"files": [
|
||||
"index.js",
|
||||
"index.d.ts",
|
||||
"README.md"
|
||||
],
|
||||
"scripts": {
|
||||
"build:napi": "napi build --platform --release --cargo-cwd ../../../crates/ruvector-graph-node",
|
||||
"test": "node test.js",
|
||||
"benchmark": "node benchmark.js",
|
||||
"publish:platforms": "node scripts/publish-platforms.js"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@napi-rs/cli": "^2.18.0"
|
||||
},
|
||||
"optionalDependencies": {
|
||||
"@ruvector/graph-node-linux-x64-gnu": "2.0.2",
|
||||
"@ruvector/graph-node-linux-arm64-gnu": "2.0.2",
|
||||
"@ruvector/graph-node-darwin-x64": "2.0.2",
|
||||
"@ruvector/graph-node-darwin-arm64": "2.0.2",
|
||||
"@ruvector/graph-node-win32-x64-msvc": "2.0.2"
|
||||
},
|
||||
"publishConfig": {
|
||||
"access": "public"
|
||||
},
|
||||
"keywords": [
|
||||
"graph-database",
|
||||
"graph",
|
||||
"hypergraph",
|
||||
"cypher",
|
||||
"neo4j",
|
||||
"vector-database",
|
||||
"graph-query",
|
||||
"knowledge-graph",
|
||||
"property-graph",
|
||||
"native",
|
||||
"napi",
|
||||
"rust",
|
||||
"fast",
|
||||
"performance",
|
||||
"zero-copy",
|
||||
"ai",
|
||||
"machine-learning",
|
||||
"rag",
|
||||
"ruv",
|
||||
"ruvector"
|
||||
]
|
||||
}
|
||||
78
vendor/ruvector/npm/packages/graph-node/scripts/publish-platforms.js
vendored
Executable file
78
vendor/ruvector/npm/packages/graph-node/scripts/publish-platforms.js
vendored
Executable file
@@ -0,0 +1,78 @@
|
||||
#!/usr/bin/env node
|
||||
/**
|
||||
* Publish platform-specific @ruvector/graph-node packages to npm
|
||||
*/
|
||||
|
||||
const { execSync } = require('child_process');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const platforms = [
|
||||
{ name: 'linux-x64-gnu', nodeFile: 'index.linux-x64-gnu.node' },
|
||||
{ name: 'linux-arm64-gnu', nodeFile: 'index.linux-arm64-gnu.node' },
|
||||
{ name: 'darwin-x64', nodeFile: 'index.darwin-x64.node' },
|
||||
{ name: 'darwin-arm64', nodeFile: 'index.darwin-arm64.node' },
|
||||
{ name: 'win32-x64-msvc', nodeFile: 'index.win32-x64-msvc.node' },
|
||||
];
|
||||
|
||||
const rootDir = path.join(__dirname, '..');
|
||||
const version = require(path.join(rootDir, 'package.json')).version;
|
||||
|
||||
console.log('Publishing @ruvector/graph-node platform packages v' + version + '\n');
|
||||
|
||||
for (const platform of platforms) {
|
||||
const pkgName = '@ruvector/graph-node-' + platform.name;
|
||||
const nodeFile = path.join(rootDir, platform.nodeFile);
|
||||
|
||||
if (!fs.existsSync(nodeFile)) {
|
||||
console.log('Skipping ' + pkgName + ' - ' + platform.nodeFile + ' not found');
|
||||
continue;
|
||||
}
|
||||
|
||||
const tmpDir = path.join(rootDir, 'npm', platform.name);
|
||||
fs.mkdirSync(tmpDir, { recursive: true });
|
||||
|
||||
// Create package.json for platform package
|
||||
const pkgJson = {
|
||||
name: pkgName,
|
||||
version: version,
|
||||
description: 'RuVector Graph Node.js bindings for ' + platform.name,
|
||||
main: 'ruvector-graph.node',
|
||||
files: ['ruvector-graph.node'],
|
||||
os: platform.name.includes('linux') ? ['linux'] :
|
||||
platform.name.includes('darwin') ? ['darwin'] :
|
||||
platform.name.includes('win32') ? ['win32'] : [],
|
||||
cpu: platform.name.includes('x64') ? ['x64'] :
|
||||
platform.name.includes('arm64') ? ['arm64'] : [],
|
||||
engines: { node: '>=18.0.0' },
|
||||
license: 'MIT',
|
||||
repository: {
|
||||
type: 'git',
|
||||
url: 'https://github.com/ruvnet/ruvector.git',
|
||||
directory: 'npm/packages/graph-node'
|
||||
},
|
||||
publishConfig: { access: 'public' }
|
||||
};
|
||||
|
||||
fs.writeFileSync(
|
||||
path.join(tmpDir, 'package.json'),
|
||||
JSON.stringify(pkgJson, null, 2)
|
||||
);
|
||||
|
||||
// Copy the .node file
|
||||
fs.copyFileSync(nodeFile, path.join(tmpDir, 'ruvector-graph.node'));
|
||||
|
||||
// Publish
|
||||
console.log('Publishing ' + pkgName + '@' + version + '...');
|
||||
try {
|
||||
execSync('npm publish --access public', { cwd: tmpDir, stdio: 'inherit' });
|
||||
console.log('Published ' + pkgName + '@' + version + '\n');
|
||||
} catch (e) {
|
||||
console.error('Failed to publish ' + pkgName + ': ' + e.message + '\n');
|
||||
}
|
||||
|
||||
// Cleanup
|
||||
fs.rmSync(tmpDir, { recursive: true, force: true });
|
||||
}
|
||||
|
||||
console.log('Done!');
|
||||
172
vendor/ruvector/npm/packages/graph-node/test.js
vendored
Normal file
172
vendor/ruvector/npm/packages/graph-node/test.js
vendored
Normal file
@@ -0,0 +1,172 @@
|
||||
const { GraphDatabase, version, hello } = require('./index.js');
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const os = require('os');
|
||||
|
||||
console.log('RuVector Graph Node Test');
|
||||
console.log('========================\n');
|
||||
|
||||
// Test 1: Version and hello
|
||||
console.log('1. Testing version and hello functions:');
|
||||
console.log(' Version:', version());
|
||||
console.log(' Hello:', hello());
|
||||
console.log(' ✓ Basic functions work\n');
|
||||
|
||||
// Test 2: Create database
|
||||
console.log('2. Creating graph database:');
|
||||
const db = new GraphDatabase({
|
||||
distanceMetric: 'Cosine',
|
||||
dimensions: 3
|
||||
});
|
||||
console.log(' ✓ Database created\n');
|
||||
|
||||
// Test 3: Create nodes
|
||||
console.log('3. Creating nodes:');
|
||||
(async () => {
|
||||
try {
|
||||
const nodeId1 = await db.createNode({
|
||||
id: 'alice',
|
||||
embedding: new Float32Array([1.0, 0.0, 0.0]),
|
||||
labels: ['Person', 'Employee'],
|
||||
properties: { name: 'Alice', age: '30' }
|
||||
});
|
||||
console.log(' Created node:', nodeId1);
|
||||
|
||||
const nodeId2 = await db.createNode({
|
||||
id: 'bob',
|
||||
embedding: new Float32Array([0.0, 1.0, 0.0]),
|
||||
labels: ['Person'],
|
||||
properties: { name: 'Bob', age: '25' }
|
||||
});
|
||||
console.log(' Created node:', nodeId2);
|
||||
console.log(' ✓ Nodes created\n');
|
||||
|
||||
// Test 4: Create edge
|
||||
console.log('4. Creating edge:');
|
||||
const edgeId = await db.createEdge({
|
||||
from: 'alice',
|
||||
to: 'bob',
|
||||
description: 'knows',
|
||||
embedding: new Float32Array([0.5, 0.5, 0.0]),
|
||||
confidence: 0.95
|
||||
});
|
||||
console.log(' Created edge:', edgeId);
|
||||
console.log(' ✓ Edge created\n');
|
||||
|
||||
// Test 5: Create hyperedge
|
||||
console.log('5. Creating hyperedge:');
|
||||
const nodeId3 = await db.createNode({
|
||||
id: 'charlie',
|
||||
embedding: new Float32Array([0.0, 0.0, 1.0])
|
||||
});
|
||||
|
||||
const hyperedgeId = await db.createHyperedge({
|
||||
nodes: ['alice', 'bob', 'charlie'],
|
||||
description: 'collaborated_on_project',
|
||||
embedding: new Float32Array([0.33, 0.33, 0.33]),
|
||||
confidence: 0.85
|
||||
});
|
||||
console.log(' Created hyperedge:', hyperedgeId);
|
||||
console.log(' ✓ Hyperedge created\n');
|
||||
|
||||
// Test 6: Query
|
||||
console.log('6. Querying graph:');
|
||||
const results = await db.query('MATCH (n) RETURN n');
|
||||
console.log(' Query results:', JSON.stringify(results, null, 2));
|
||||
console.log(' ✓ Query executed\n');
|
||||
|
||||
// Test 7: Search hyperedges
|
||||
console.log('7. Searching hyperedges:');
|
||||
const searchResults = await db.searchHyperedges({
|
||||
embedding: new Float32Array([0.3, 0.3, 0.3]),
|
||||
k: 5
|
||||
});
|
||||
console.log(' Search results:', searchResults);
|
||||
console.log(' ✓ Search completed\n');
|
||||
|
||||
// Test 8: k-hop neighbors
|
||||
console.log('8. Finding k-hop neighbors:');
|
||||
const neighbors = await db.kHopNeighbors('alice', 2);
|
||||
console.log(' Neighbors:', neighbors);
|
||||
console.log(' ✓ Neighbors found\n');
|
||||
|
||||
// Test 9: Statistics
|
||||
console.log('9. Getting statistics:');
|
||||
const stats = await db.stats();
|
||||
console.log(' Stats:', stats);
|
||||
console.log(' ✓ Statistics retrieved\n');
|
||||
|
||||
// Test 10: Transactions
|
||||
console.log('10. Testing transactions:');
|
||||
const txId = await db.begin();
|
||||
console.log(' Transaction started:', txId);
|
||||
await db.commit(txId);
|
||||
console.log(' Transaction committed');
|
||||
console.log(' ✓ Transaction test passed\n');
|
||||
|
||||
// Test 11: Batch insert
|
||||
console.log('11. Testing batch insert:');
|
||||
const batchResult = await db.batchInsert({
|
||||
nodes: [
|
||||
{ id: 'n1', embedding: new Float32Array([1, 0, 0]) },
|
||||
{ id: 'n2', embedding: new Float32Array([0, 1, 0]) }
|
||||
],
|
||||
edges: [
|
||||
{
|
||||
from: 'n1',
|
||||
to: 'n2',
|
||||
description: 'connects',
|
||||
embedding: new Float32Array([0.5, 0.5, 0])
|
||||
}
|
||||
]
|
||||
});
|
||||
console.log(' Batch result:', batchResult);
|
||||
console.log(' ✓ Batch insert completed\n');
|
||||
|
||||
// Test 12: Persistence
|
||||
console.log('12. Testing persistence:');
|
||||
const tmpDir = os.tmpdir();
|
||||
const dbPath = path.join(tmpDir, `ruvector-test-${Date.now()}.db`);
|
||||
|
||||
console.log(' Creating persistent database at:', dbPath);
|
||||
const persistentDb = new GraphDatabase({
|
||||
distanceMetric: 'Cosine',
|
||||
dimensions: 3,
|
||||
storagePath: dbPath
|
||||
});
|
||||
|
||||
console.log(' isPersistent():', persistentDb.isPersistent());
|
||||
console.log(' getStoragePath():', persistentDb.getStoragePath());
|
||||
|
||||
// Add data to persistent database
|
||||
await persistentDb.createNode({
|
||||
id: 'persistent_node_1',
|
||||
embedding: new Float32Array([1.0, 0.5, 0.2]),
|
||||
labels: ['PersistentTest'],
|
||||
properties: { testKey: 'testValue' }
|
||||
});
|
||||
console.log(' Created node in persistent database');
|
||||
|
||||
const persistentStats = await persistentDb.stats();
|
||||
console.log(' Persistent DB stats:', persistentStats);
|
||||
|
||||
// Test opening existing database
|
||||
console.log(' Opening existing database with GraphDatabase.open()...');
|
||||
const reopenedDb = GraphDatabase.open(dbPath);
|
||||
console.log(' Reopened isPersistent():', reopenedDb.isPersistent());
|
||||
|
||||
// Cleanup
|
||||
try {
|
||||
fs.unlinkSync(dbPath);
|
||||
console.log(' Cleaned up test database');
|
||||
} catch (e) {
|
||||
// Ignore cleanup errors
|
||||
}
|
||||
console.log(' ✓ Persistence test passed\n');
|
||||
|
||||
console.log('✅ All tests passed!');
|
||||
} catch (error) {
|
||||
console.error('❌ Test failed:', error);
|
||||
process.exit(1);
|
||||
}
|
||||
})();
|
||||
Reference in New Issue
Block a user