feat: add verb and noun metadata handling in storage adapters
- Implement saveVerbMetadata and getVerbMetadata methods for managing verb metadata. - Implement saveNounMetadata and getNounMetadata methods for managing noun metadata. - Update storage adapters to use HNSWVerb instead of GraphVerb for improved performance. - Deprecate methods that require loading metadata for edges, returning empty arrays instead.
This commit is contained in:
parent
9905a5dc35
commit
1040f1ce34
4 changed files with 386 additions and 137 deletions
|
|
@ -41,6 +41,10 @@ export abstract class BaseStorageAdapter implements StorageAdapter {
|
|||
|
||||
abstract getMetadata(id: string): Promise<any | null>
|
||||
|
||||
abstract saveVerbMetadata(id: string, metadata: any): Promise<void>
|
||||
|
||||
abstract getVerbMetadata(id: string): Promise<any | null>
|
||||
|
||||
abstract clear(): Promise<void>
|
||||
|
||||
abstract getStorageStatus(): Promise<{
|
||||
|
|
|
|||
|
|
@ -3,7 +3,7 @@
|
|||
* File system storage adapter for Node.js environments
|
||||
*/
|
||||
|
||||
import { GraphVerb, HNSWNoun, StatisticsData } from '../../coreTypes.js'
|
||||
import { GraphVerb, HNSWNoun, HNSWVerb, StatisticsData } from '../../coreTypes.js'
|
||||
import {
|
||||
BaseStorage,
|
||||
NOUNS_DIR,
|
||||
|
|
@ -17,7 +17,7 @@ import {
|
|||
|
||||
// Type aliases for better readability
|
||||
type HNSWNode = HNSWNoun
|
||||
type Edge = GraphVerb
|
||||
type Edge = HNSWVerb
|
||||
|
||||
// Node.js modules - dynamically imported to avoid issues in browser environments
|
||||
let fs: any
|
||||
|
|
@ -345,12 +345,7 @@ export class FileSystemStorage extends BaseStorage {
|
|||
return {
|
||||
id: parsedEdge.id,
|
||||
vector: parsedEdge.vector,
|
||||
connections,
|
||||
sourceId: parsedEdge.sourceId,
|
||||
targetId: parsedEdge.targetId,
|
||||
type: parsedEdge.type,
|
||||
weight: parsedEdge.weight,
|
||||
metadata: parsedEdge.metadata
|
||||
connections
|
||||
}
|
||||
} catch (error: any) {
|
||||
if (error.code !== 'ENOENT') {
|
||||
|
|
@ -386,12 +381,7 @@ export class FileSystemStorage extends BaseStorage {
|
|||
allEdges.push({
|
||||
id: parsedEdge.id,
|
||||
vector: parsedEdge.vector,
|
||||
connections,
|
||||
sourceId: parsedEdge.sourceId,
|
||||
targetId: parsedEdge.targetId,
|
||||
type: parsedEdge.type,
|
||||
weight: parsedEdge.weight,
|
||||
metadata: parsedEdge.metadata
|
||||
connections
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
@ -407,24 +397,30 @@ export class FileSystemStorage extends BaseStorage {
|
|||
* Get edges by source
|
||||
*/
|
||||
protected async getEdgesBySource(sourceId: string): Promise<Edge[]> {
|
||||
const edges = await this.getAllEdges()
|
||||
return edges.filter((edge) => edge.sourceId === sourceId)
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getEdgesBySource is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Get edges by target
|
||||
*/
|
||||
protected async getEdgesByTarget(targetId: string): Promise<Edge[]> {
|
||||
const edges = await this.getAllEdges()
|
||||
return edges.filter((edge) => edge.targetId === targetId)
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getEdgesByTarget is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Get edges by type
|
||||
*/
|
||||
protected async getEdgesByType(type: string): Promise<Edge[]> {
|
||||
const edges = await this.getAllEdges()
|
||||
return edges.filter((edge) => edge.type === type)
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getEdgesByType is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -751,21 +747,21 @@ export class FileSystemStorage extends BaseStorage {
|
|||
/**
|
||||
* Save a verb to storage
|
||||
*/
|
||||
protected async saveVerb_internal(verb: GraphVerb): Promise<void> {
|
||||
protected async saveVerb_internal(verb: HNSWVerb): Promise<void> {
|
||||
return this.saveEdge(verb)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a verb from storage
|
||||
*/
|
||||
protected async getVerb_internal(id: string): Promise<GraphVerb | null> {
|
||||
protected async getVerb_internal(id: string): Promise<HNSWVerb | null> {
|
||||
return this.getEdge(id)
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all verbs from storage
|
||||
*/
|
||||
protected async getAllVerbs_internal(): Promise<GraphVerb[]> {
|
||||
protected async getAllVerbs_internal(): Promise<HNSWVerb[]> {
|
||||
return this.getAllEdges()
|
||||
}
|
||||
|
||||
|
|
@ -775,7 +771,10 @@ export class FileSystemStorage extends BaseStorage {
|
|||
protected async getVerbsBySource_internal(
|
||||
sourceId: string
|
||||
): Promise<GraphVerb[]> {
|
||||
return this.getEdgesBySource(sourceId)
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getVerbsBySource_internal is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -784,14 +783,20 @@ export class FileSystemStorage extends BaseStorage {
|
|||
protected async getVerbsByTarget_internal(
|
||||
targetId: string
|
||||
): Promise<GraphVerb[]> {
|
||||
return this.getEdgesByTarget(targetId)
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getVerbsByTarget_internal is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Get verbs by type
|
||||
*/
|
||||
protected async getVerbsByType_internal(type: string): Promise<GraphVerb[]> {
|
||||
return this.getEdgesByType(type)
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getVerbsByType_internal is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -3,17 +3,17 @@
|
|||
* Provides persistent storage for the vector database using the Origin Private File System API
|
||||
*/
|
||||
|
||||
import {GraphVerb, HNSWNoun, StatisticsData} from '../../coreTypes.js'
|
||||
import {BaseStorage, NOUNS_DIR, VERBS_DIR, METADATA_DIR, INDEX_DIR, STATISTICS_KEY} from '../baseStorage.js'
|
||||
import {GraphVerb, HNSWNoun, HNSWVerb, StatisticsData} from '../../coreTypes.js'
|
||||
import {BaseStorage, NOUNS_DIR, VERBS_DIR, METADATA_DIR, NOUN_METADATA_DIR, VERB_METADATA_DIR, INDEX_DIR, STATISTICS_KEY} from '../baseStorage.js'
|
||||
import '../../types/fileSystemTypes.js'
|
||||
|
||||
// Type alias for HNSWNode
|
||||
type HNSWNode = HNSWNoun
|
||||
|
||||
/**
|
||||
* Type alias for GraphVerb to make the code more readable
|
||||
* Type alias for HNSWVerb to make the code more readable
|
||||
*/
|
||||
type Edge = GraphVerb
|
||||
type Edge = HNSWVerb
|
||||
|
||||
/**
|
||||
* Helper function to safely get a file from a FileSystemHandle
|
||||
|
|
@ -41,6 +41,8 @@ export class OPFSStorage extends BaseStorage {
|
|||
private nounsDir: FileSystemDirectoryHandle | null = null
|
||||
private verbsDir: FileSystemDirectoryHandle | null = null
|
||||
private metadataDir: FileSystemDirectoryHandle | null = null
|
||||
private nounMetadataDir: FileSystemDirectoryHandle | null = null
|
||||
private verbMetadataDir: FileSystemDirectoryHandle | null = null
|
||||
private indexDir: FileSystemDirectoryHandle | null = null
|
||||
private isAvailable = false
|
||||
private isPersistentRequested = false
|
||||
|
|
@ -94,6 +96,16 @@ export class OPFSStorage extends BaseStorage {
|
|||
create: true
|
||||
})
|
||||
|
||||
// Create or get noun metadata directory
|
||||
this.nounMetadataDir = await this.rootDir.getDirectoryHandle(NOUN_METADATA_DIR, {
|
||||
create: true
|
||||
})
|
||||
|
||||
// Create or get verb metadata directory
|
||||
this.verbMetadataDir = await this.rootDir.getDirectoryHandle(VERB_METADATA_DIR, {
|
||||
create: true
|
||||
})
|
||||
|
||||
// Create or get index directory
|
||||
this.indexDir = await this.rootDir.getDirectoryHandle(INDEX_DIR, {
|
||||
create: true
|
||||
|
|
@ -345,7 +357,7 @@ export class OPFSStorage extends BaseStorage {
|
|||
/**
|
||||
* Save a verb to storage (internal implementation)
|
||||
*/
|
||||
protected async saveVerb_internal(verb: GraphVerb): Promise<void> {
|
||||
protected async saveVerb_internal(verb: HNSWVerb): Promise<void> {
|
||||
return this.saveEdge(verb)
|
||||
}
|
||||
|
||||
|
|
@ -382,7 +394,7 @@ export class OPFSStorage extends BaseStorage {
|
|||
/**
|
||||
* Get a verb from storage (internal implementation)
|
||||
*/
|
||||
protected async getVerb_internal(id: string): Promise<GraphVerb | null> {
|
||||
protected async getVerb_internal(id: string): Promise<HNSWVerb | null> {
|
||||
return this.getEdge(id)
|
||||
}
|
||||
|
||||
|
|
@ -422,17 +434,7 @@ export class OPFSStorage extends BaseStorage {
|
|||
return {
|
||||
id: data.id,
|
||||
vector: data.vector,
|
||||
connections,
|
||||
sourceId: data.sourceId || data.source,
|
||||
targetId: data.targetId || data.target,
|
||||
source: data.sourceId || data.source,
|
||||
target: data.targetId || data.target,
|
||||
verb: data.type || data.verb,
|
||||
weight: data.weight,
|
||||
metadata: data.metadata,
|
||||
createdAt: data.createdAt || defaultTimestamp,
|
||||
updatedAt: data.updatedAt || defaultTimestamp,
|
||||
createdBy: data.createdBy || defaultCreatedBy
|
||||
connections
|
||||
}
|
||||
} catch (error) {
|
||||
// Edge not found or other error
|
||||
|
|
@ -443,7 +445,7 @@ export class OPFSStorage extends BaseStorage {
|
|||
/**
|
||||
* Get all verbs from storage (internal implementation)
|
||||
*/
|
||||
protected async getAllVerbs_internal(): Promise<GraphVerb[]> {
|
||||
protected async getAllVerbs_internal(): Promise<HNSWVerb[]> {
|
||||
return this.getAllEdges()
|
||||
}
|
||||
|
||||
|
|
@ -485,17 +487,7 @@ export class OPFSStorage extends BaseStorage {
|
|||
allEdges.push({
|
||||
id: data.id,
|
||||
vector: data.vector,
|
||||
connections,
|
||||
sourceId: data.sourceId || data.source,
|
||||
targetId: data.targetId || data.target,
|
||||
source: data.sourceId || data.source,
|
||||
target: data.targetId || data.target,
|
||||
verb: data.type || data.verb,
|
||||
weight: data.weight,
|
||||
metadata: data.metadata,
|
||||
createdAt: data.createdAt || defaultTimestamp,
|
||||
updatedAt: data.updatedAt || defaultTimestamp,
|
||||
createdBy: data.createdBy || defaultCreatedBy
|
||||
connections
|
||||
})
|
||||
} catch (error) {
|
||||
console.error(`Error reading edge file ${name}:`, error)
|
||||
|
|
@ -513,45 +505,60 @@ export class OPFSStorage extends BaseStorage {
|
|||
* Get verbs by source (internal implementation)
|
||||
*/
|
||||
protected async getVerbsBySource_internal(sourceId: string): Promise<GraphVerb[]> {
|
||||
return this.getEdgesBySource(sourceId)
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getVerbsBySource_internal is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Get edges by source
|
||||
*/
|
||||
protected async getEdgesBySource(sourceId: string): Promise<Edge[]> {
|
||||
const edges = await this.getAllEdges()
|
||||
return edges.filter((edge) => (edge.sourceId || edge.source) === sourceId)
|
||||
protected async getEdgesBySource(sourceId: string): Promise<GraphVerb[]> {
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getEdgesBySource is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Get verbs by target (internal implementation)
|
||||
*/
|
||||
protected async getVerbsByTarget_internal(targetId: string): Promise<GraphVerb[]> {
|
||||
return this.getEdgesByTarget(targetId)
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getVerbsByTarget_internal is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Get edges by target
|
||||
*/
|
||||
protected async getEdgesByTarget(targetId: string): Promise<Edge[]> {
|
||||
const edges = await this.getAllEdges()
|
||||
return edges.filter((edge) => (edge.targetId || edge.target) === targetId)
|
||||
protected async getEdgesByTarget(targetId: string): Promise<GraphVerb[]> {
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getEdgesByTarget is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Get verbs by type (internal implementation)
|
||||
*/
|
||||
protected async getVerbsByType_internal(type: string): Promise<GraphVerb[]> {
|
||||
return this.getEdgesByType(type)
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getVerbsByType_internal is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
* Get edges by type
|
||||
*/
|
||||
protected async getEdgesByType(type: string): Promise<Edge[]> {
|
||||
const edges = await this.getAllEdges()
|
||||
return edges.filter((edge) => (edge.type || edge.verb) === type)
|
||||
protected async getEdgesByType(type: string): Promise<GraphVerb[]> {
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getEdgesByType is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -620,6 +627,72 @@ export class OPFSStorage extends BaseStorage {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save verb metadata to storage
|
||||
*/
|
||||
public async saveVerbMetadata(id: string, metadata: any): Promise<void> {
|
||||
await this.ensureInitialized()
|
||||
|
||||
const fileName = `${id}.json`
|
||||
const fileHandle = await (this.verbMetadataDir as FileSystemDirectoryHandle).getFileHandle(fileName, { create: true })
|
||||
const writable = await (fileHandle as FileSystemFileHandle).createWritable()
|
||||
await writable.write(JSON.stringify(metadata, null, 2))
|
||||
await writable.close()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get verb metadata from storage
|
||||
*/
|
||||
public async getVerbMetadata(id: string): Promise<any | null> {
|
||||
await this.ensureInitialized()
|
||||
|
||||
const fileName = `${id}.json`
|
||||
try {
|
||||
const fileHandle = await (this.verbMetadataDir as FileSystemDirectoryHandle).getFileHandle(fileName)
|
||||
const file = await safeGetFile(fileHandle)
|
||||
const text = await file.text()
|
||||
return JSON.parse(text)
|
||||
} catch (error: any) {
|
||||
if (error.name !== 'NotFoundError') {
|
||||
console.error(`Error reading verb metadata ${id}:`, error)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save noun metadata to storage
|
||||
*/
|
||||
public async saveNounMetadata(id: string, metadata: any): Promise<void> {
|
||||
await this.ensureInitialized()
|
||||
|
||||
const fileName = `${id}.json`
|
||||
const fileHandle = await (this.nounMetadataDir as FileSystemDirectoryHandle).getFileHandle(fileName, { create: true })
|
||||
const writable = await fileHandle.createWritable()
|
||||
await writable.write(JSON.stringify(metadata, null, 2))
|
||||
await writable.close()
|
||||
}
|
||||
|
||||
/**
|
||||
* Get noun metadata from storage
|
||||
*/
|
||||
public async getNounMetadata(id: string): Promise<any | null> {
|
||||
await this.ensureInitialized()
|
||||
|
||||
const fileName = `${id}.json`
|
||||
try {
|
||||
const fileHandle = await (this.nounMetadataDir as FileSystemDirectoryHandle).getFileHandle(fileName)
|
||||
const file = await safeGetFile(fileHandle)
|
||||
const text = await file.text()
|
||||
return JSON.parse(text)
|
||||
} catch (error: any) {
|
||||
if (error.name !== 'NotFoundError') {
|
||||
console.error(`Error reading noun metadata ${id}:`, error)
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear all data from storage
|
||||
*/
|
||||
|
|
@ -651,6 +724,12 @@ export class OPFSStorage extends BaseStorage {
|
|||
// Remove all files in the metadata directory
|
||||
await removeDirectoryContents(this.metadataDir!)
|
||||
|
||||
// Remove all files in the noun metadata directory
|
||||
await removeDirectoryContents(this.nounMetadataDir!)
|
||||
|
||||
// Remove all files in the verb metadata directory
|
||||
await removeDirectoryContents(this.verbMetadataDir!)
|
||||
|
||||
// Remove all files in the index directory
|
||||
await removeDirectoryContents(this.indexDir!)
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
* including Amazon S3, Cloudflare R2, and Google Cloud Storage
|
||||
*/
|
||||
|
||||
import { GraphVerb, HNSWNoun, StatisticsData } from '../../coreTypes.js'
|
||||
import { GraphVerb, HNSWNoun, HNSWVerb, StatisticsData } from '../../coreTypes.js'
|
||||
import {
|
||||
BaseStorage,
|
||||
NOUNS_DIR,
|
||||
|
|
@ -22,7 +22,7 @@ import { CacheManager } from '../cacheManager.js'
|
|||
|
||||
// Type aliases for better readability
|
||||
type HNSWNode = HNSWNoun
|
||||
type Edge = GraphVerb
|
||||
type Edge = HNSWVerb
|
||||
|
||||
// Change log entry interface for tracking data modifications
|
||||
interface ChangeLogEntry {
|
||||
|
|
@ -712,7 +712,7 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
/**
|
||||
* Save a verb to storage (internal implementation)
|
||||
*/
|
||||
protected async saveVerb_internal(verb: GraphVerb): Promise<void> {
|
||||
protected async saveVerb_internal(verb: HNSWVerb): Promise<void> {
|
||||
return this.saveEdge(verb)
|
||||
}
|
||||
|
||||
|
|
@ -751,11 +751,7 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
entityType: 'verb',
|
||||
entityId: edge.id,
|
||||
data: {
|
||||
sourceId: edge.sourceId || edge.source,
|
||||
targetId: edge.targetId || edge.target,
|
||||
type: edge.type || edge.verb,
|
||||
vector: edge.vector,
|
||||
metadata: edge.metadata
|
||||
vector: edge.vector
|
||||
}
|
||||
})
|
||||
} catch (error) {
|
||||
|
|
@ -767,7 +763,7 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
/**
|
||||
* Get a verb from storage (internal implementation)
|
||||
*/
|
||||
protected async getVerb_internal(id: string): Promise<GraphVerb | null> {
|
||||
protected async getVerb_internal(id: string): Promise<HNSWVerb | null> {
|
||||
return this.getEdge(id)
|
||||
}
|
||||
|
||||
|
|
@ -815,10 +811,7 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
!parsedEdge ||
|
||||
!parsedEdge.id ||
|
||||
!parsedEdge.vector ||
|
||||
!parsedEdge.connections ||
|
||||
!(parsedEdge.sourceId || parsedEdge.source) ||
|
||||
!(parsedEdge.targetId || parsedEdge.target) ||
|
||||
!(parsedEdge.type || parsedEdge.verb)
|
||||
!parsedEdge.connections
|
||||
) {
|
||||
console.error(`Invalid edge data for ${id}:`, parsedEdge)
|
||||
return null
|
||||
|
|
@ -830,33 +823,10 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
connections.set(Number(level), new Set(nodeIds as string[]))
|
||||
}
|
||||
|
||||
// Create default timestamp if not present
|
||||
const defaultTimestamp = {
|
||||
seconds: Math.floor(Date.now() / 1000),
|
||||
nanoseconds: (Date.now() % 1000) * 1000000
|
||||
}
|
||||
|
||||
// Create default createdBy if not present
|
||||
const defaultCreatedBy = {
|
||||
augmentation: 'unknown',
|
||||
version: '1.0'
|
||||
}
|
||||
|
||||
const edge = {
|
||||
id: parsedEdge.id,
|
||||
vector: parsedEdge.vector,
|
||||
connections,
|
||||
sourceId: parsedEdge.sourceId || parsedEdge.source,
|
||||
targetId: parsedEdge.targetId || parsedEdge.target,
|
||||
source: parsedEdge.sourceId || parsedEdge.source,
|
||||
target: parsedEdge.targetId || parsedEdge.target,
|
||||
verb: parsedEdge.type || parsedEdge.verb,
|
||||
type: parsedEdge.type || parsedEdge.verb,
|
||||
weight: parsedEdge.weight || 1.0, // Default weight if not provided
|
||||
metadata: parsedEdge.metadata || {},
|
||||
createdAt: parsedEdge.createdAt || defaultTimestamp,
|
||||
updatedAt: parsedEdge.updatedAt || defaultTimestamp,
|
||||
createdBy: parsedEdge.createdBy || defaultCreatedBy
|
||||
connections
|
||||
}
|
||||
|
||||
console.log(`Successfully retrieved edge ${id}:`, edge)
|
||||
|
|
@ -877,7 +847,7 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
* @deprecated This method is deprecated and will be removed in a future version.
|
||||
* It can cause memory issues with large datasets. Use getVerbsWithPagination() instead.
|
||||
*/
|
||||
protected async getAllVerbs_internal(): Promise<GraphVerb[]> {
|
||||
protected async getAllVerbs_internal(): Promise<HNSWVerb[]> {
|
||||
console.warn('WARNING: getAllVerbs_internal() is deprecated and will be removed in a future version. Use getVerbsWithPagination() instead.')
|
||||
return this.getAllEdges()
|
||||
}
|
||||
|
|
@ -1053,27 +1023,10 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
targetId?: string
|
||||
type?: string
|
||||
}): boolean {
|
||||
// If no filter, include all edges
|
||||
if (!filter.sourceId && !filter.targetId && !filter.type) {
|
||||
return true
|
||||
}
|
||||
|
||||
// Filter by source ID
|
||||
if (filter.sourceId && edge.sourceId !== filter.sourceId) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Filter by target ID
|
||||
if (filter.targetId && edge.targetId !== filter.targetId) {
|
||||
return false
|
||||
}
|
||||
|
||||
// Filter by type
|
||||
if (filter.type && edge.type !== filter.type) {
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
// HNSWVerb filtering is not supported since metadata is stored separately
|
||||
// This method is deprecated and should not be used with the new storage pattern
|
||||
console.warn('Edge filtering is deprecated and not supported with the new storage pattern')
|
||||
return true // Return all edges since filtering requires metadata
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1137,9 +1090,17 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
filter: edgeFilter
|
||||
})
|
||||
|
||||
// Convert edges to verbs (they're the same in this implementation)
|
||||
// Convert HNSWVerbs to GraphVerbs by combining with metadata
|
||||
const graphVerbs: GraphVerb[] = []
|
||||
for (const hnswVerb of result.edges) {
|
||||
const graphVerb = await this.convertHNSWVerbToGraphVerb(hnswVerb)
|
||||
if (graphVerb) {
|
||||
graphVerbs.push(graphVerb)
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
items: result.edges,
|
||||
items: graphVerbs,
|
||||
hasMore: result.hasMore,
|
||||
nextCursor: result.nextCursor
|
||||
}
|
||||
|
|
@ -1157,9 +1118,11 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
/**
|
||||
* Get edges by source
|
||||
*/
|
||||
protected async getEdgesBySource(sourceId: string): Promise<Edge[]> {
|
||||
const edges = await this.getAllEdges()
|
||||
return edges.filter((edge) => (edge.sourceId || edge.source) === sourceId)
|
||||
protected async getEdgesBySource(sourceId: string): Promise<GraphVerb[]> {
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getEdgesBySource is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1174,9 +1137,11 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
/**
|
||||
* Get edges by target
|
||||
*/
|
||||
protected async getEdgesByTarget(targetId: string): Promise<Edge[]> {
|
||||
const edges = await this.getAllEdges()
|
||||
return edges.filter((edge) => (edge.targetId || edge.target) === targetId)
|
||||
protected async getEdgesByTarget(targetId: string): Promise<GraphVerb[]> {
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getEdgesByTarget is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1189,9 +1154,11 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
/**
|
||||
* Get edges by type
|
||||
*/
|
||||
protected async getEdgesByType(type: string): Promise<Edge[]> {
|
||||
const edges = await this.getAllEdges()
|
||||
return edges.filter((edge) => (edge.type || edge.verb) === type)
|
||||
protected async getEdgesByType(type: string): Promise<GraphVerb[]> {
|
||||
// This method is deprecated and would require loading metadata for each edge
|
||||
// For now, return empty array since this is not efficiently implementable with new storage pattern
|
||||
console.warn('getEdgesByType is deprecated and not efficiently supported in new storage pattern')
|
||||
return []
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -1303,6 +1270,200 @@ export class S3CompatibleStorage extends BaseStorage {
|
|||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save verb metadata to storage
|
||||
*/
|
||||
public async saveVerbMetadata(id: string, metadata: any): Promise<void> {
|
||||
await this.ensureInitialized()
|
||||
|
||||
try {
|
||||
console.log(`Saving verb metadata for ${id} to bucket ${this.bucketName}`)
|
||||
|
||||
// Import the PutObjectCommand only when needed
|
||||
const { PutObjectCommand } = await import('@aws-sdk/client-s3')
|
||||
|
||||
const key = `verb-metadata/${id}.json`
|
||||
const body = JSON.stringify(metadata, null, 2)
|
||||
|
||||
console.log(`Saving verb metadata to key: ${key}`)
|
||||
console.log(`Verb Metadata: ${body}`)
|
||||
|
||||
// Save the verb metadata to S3-compatible storage
|
||||
const result = await this.s3Client!.send(
|
||||
new PutObjectCommand({
|
||||
Bucket: this.bucketName,
|
||||
Key: key,
|
||||
Body: body,
|
||||
ContentType: 'application/json'
|
||||
})
|
||||
)
|
||||
|
||||
console.log(`Verb metadata for ${id} saved successfully:`, result)
|
||||
} catch (error) {
|
||||
console.error(`Failed to save verb metadata for ${id}:`, error)
|
||||
throw new Error(`Failed to save verb metadata for ${id}: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get verb metadata from storage
|
||||
*/
|
||||
public async getVerbMetadata(id: string): Promise<any | null> {
|
||||
await this.ensureInitialized()
|
||||
|
||||
try {
|
||||
// Import the GetObjectCommand only when needed
|
||||
const { GetObjectCommand } = await import('@aws-sdk/client-s3')
|
||||
|
||||
console.log(`Getting verb metadata for ${id} from bucket ${this.bucketName}`)
|
||||
const key = `verb-metadata/${id}.json`
|
||||
console.log(`Looking for verb metadata at key: ${key}`)
|
||||
|
||||
// Try to get the verb metadata
|
||||
const response = await this.s3Client!.send(
|
||||
new GetObjectCommand({
|
||||
Bucket: this.bucketName,
|
||||
Key: key
|
||||
})
|
||||
)
|
||||
|
||||
// Check if response is null or undefined
|
||||
if (!response || !response.Body) {
|
||||
console.log(`No verb metadata found for ${id}`)
|
||||
return null
|
||||
}
|
||||
|
||||
// Convert the response body to a string
|
||||
const bodyContents = await response.Body.transformToString()
|
||||
console.log(`Retrieved verb metadata body: ${bodyContents}`)
|
||||
|
||||
// Parse the JSON string
|
||||
try {
|
||||
const parsedMetadata = JSON.parse(bodyContents)
|
||||
console.log(
|
||||
`Successfully retrieved verb metadata for ${id}:`,
|
||||
parsedMetadata
|
||||
)
|
||||
return parsedMetadata
|
||||
} catch (parseError) {
|
||||
console.error(`Failed to parse verb metadata for ${id}:`, parseError)
|
||||
return null
|
||||
}
|
||||
} catch (error: any) {
|
||||
// Check if this is a "NoSuchKey" error (object doesn't exist)
|
||||
if (
|
||||
error.name === 'NoSuchKey' ||
|
||||
(error.message &&
|
||||
(error.message.includes('NoSuchKey') ||
|
||||
error.message.includes('not found') ||
|
||||
error.message.includes('does not exist')))
|
||||
) {
|
||||
console.log(`Verb metadata not found for ${id}`)
|
||||
return null
|
||||
}
|
||||
|
||||
// For other types of errors, convert to BrainyError for better classification
|
||||
throw BrainyError.fromError(error, `getVerbMetadata(${id})`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Save noun metadata to storage
|
||||
*/
|
||||
public async saveNounMetadata(id: string, metadata: any): Promise<void> {
|
||||
await this.ensureInitialized()
|
||||
|
||||
try {
|
||||
console.log(`Saving noun metadata for ${id} to bucket ${this.bucketName}`)
|
||||
|
||||
// Import the PutObjectCommand only when needed
|
||||
const { PutObjectCommand } = await import('@aws-sdk/client-s3')
|
||||
|
||||
const key = `noun-metadata/${id}.json`
|
||||
const body = JSON.stringify(metadata, null, 2)
|
||||
|
||||
console.log(`Saving noun metadata to key: ${key}`)
|
||||
console.log(`Noun Metadata: ${body}`)
|
||||
|
||||
// Save the noun metadata to S3-compatible storage
|
||||
const result = await this.s3Client!.send(
|
||||
new PutObjectCommand({
|
||||
Bucket: this.bucketName,
|
||||
Key: key,
|
||||
Body: body,
|
||||
ContentType: 'application/json'
|
||||
})
|
||||
)
|
||||
|
||||
console.log(`Noun metadata for ${id} saved successfully:`, result)
|
||||
} catch (error) {
|
||||
console.error(`Failed to save noun metadata for ${id}:`, error)
|
||||
throw new Error(`Failed to save noun metadata for ${id}: ${error}`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get noun metadata from storage
|
||||
*/
|
||||
public async getNounMetadata(id: string): Promise<any | null> {
|
||||
await this.ensureInitialized()
|
||||
|
||||
try {
|
||||
// Import the GetObjectCommand only when needed
|
||||
const { GetObjectCommand } = await import('@aws-sdk/client-s3')
|
||||
|
||||
console.log(`Getting noun metadata for ${id} from bucket ${this.bucketName}`)
|
||||
const key = `noun-metadata/${id}.json`
|
||||
console.log(`Looking for noun metadata at key: ${key}`)
|
||||
|
||||
// Try to get the noun metadata
|
||||
const response = await this.s3Client!.send(
|
||||
new GetObjectCommand({
|
||||
Bucket: this.bucketName,
|
||||
Key: key
|
||||
})
|
||||
)
|
||||
|
||||
// Check if response is null or undefined
|
||||
if (!response || !response.Body) {
|
||||
console.log(`No noun metadata found for ${id}`)
|
||||
return null
|
||||
}
|
||||
|
||||
// Convert the response body to a string
|
||||
const bodyContents = await response.Body.transformToString()
|
||||
console.log(`Retrieved noun metadata body: ${bodyContents}`)
|
||||
|
||||
// Parse the JSON string
|
||||
try {
|
||||
const parsedMetadata = JSON.parse(bodyContents)
|
||||
console.log(
|
||||
`Successfully retrieved noun metadata for ${id}:`,
|
||||
parsedMetadata
|
||||
)
|
||||
return parsedMetadata
|
||||
} catch (parseError) {
|
||||
console.error(`Failed to parse noun metadata for ${id}:`, parseError)
|
||||
return null
|
||||
}
|
||||
} catch (error: any) {
|
||||
// Check if this is a "NoSuchKey" error (object doesn't exist)
|
||||
if (
|
||||
error.name === 'NoSuchKey' ||
|
||||
(error.message &&
|
||||
(error.message.includes('NoSuchKey') ||
|
||||
error.message.includes('not found') ||
|
||||
error.message.includes('does not exist')))
|
||||
) {
|
||||
console.log(`Noun metadata not found for ${id}`)
|
||||
return null
|
||||
}
|
||||
|
||||
// For other types of errors, convert to BrainyError for better classification
|
||||
throw BrainyError.fromError(error, `getNounMetadata(${id})`)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get metadata from storage
|
||||
*/
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue