Updated semantic, and added entities/relationship implementation
This commit is contained in:
111
packages/memory-service/src/entities/index.js
Normal file
111
packages/memory-service/src/entities/index.js
Normal file
@@ -0,0 +1,111 @@
|
||||
const {getDB} = require('../db');
|
||||
|
||||
/******* Entities ********/
|
||||
|
||||
// Upsert an entity - insert or update if (name, type) already exists
|
||||
function upsertEntity(name, type, notes = null, metadata = null) {
|
||||
const db = getDB();
|
||||
const stmt = db.prepare(`
|
||||
INSERT INTO entities (name, type, notes, metadata)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(name, type) DO UPDATE SET
|
||||
notes = excluded.notes,
|
||||
metadata = excluded.metadata,
|
||||
updated_at = unixepoch()
|
||||
`);
|
||||
const result = stmt.run(name, type, notes, metadata ? JSON.stringify(metadata) : null);
|
||||
|
||||
return getEntityByNameType(name, type);
|
||||
}
|
||||
|
||||
// Get an entity by its ID
|
||||
function getEntity(id) {
|
||||
const db = getDB();
|
||||
return parseEntity(db.prepare(`SELECT * FROM entities WHERE id = ?`).get(id));
|
||||
}
|
||||
|
||||
// Get all entities of a given type
|
||||
function getEntitiesByType(type) {
|
||||
const db = getDB();
|
||||
return db.prepare(`SELECT * FROM entities WHERE type = ? ORDER BY name`).all(type).map(parseEntity);
|
||||
}
|
||||
|
||||
// Delete an entity by ID, cascades to delete relationships involving this entity
|
||||
function deleteEntity(id) {
|
||||
const db = getDB();
|
||||
db.prepare(`DELETE FROM entities WHERE id = ?`).run(id);
|
||||
}
|
||||
|
||||
/********* Relationships *********/
|
||||
|
||||
// Upsert a relationship, insert or ignore if (from_id, to_id, label) already exists
|
||||
function upsertRelationship(fromId, toId, label, metadata = null){
|
||||
const db = getDB();
|
||||
const stmt = db.prepare(`
|
||||
INSERT INTO relationships (from_id, to_id, label, metadata)
|
||||
VALUES (?, ?, ?, ?)
|
||||
ON CONFLICT(from_id, to_id, label) DO NOTHING
|
||||
`);
|
||||
|
||||
const result = stmt.run(fromId, toId, label, metadata ?JSON.stringify(metadata) : null);
|
||||
return getRelationship(fromId, toId, label);
|
||||
}
|
||||
|
||||
// Retrieve a relationship by (from_id, to_id, label)
|
||||
function getRelationship(fromId, toId, label) {
|
||||
const db = getDB();
|
||||
|
||||
return parseRelationship(
|
||||
db.prepare(`SELECT * FROM relationships WHERE from_id = ? AND to_id = ? AND label = ?`)
|
||||
.get(fromId, toId, label)
|
||||
);
|
||||
}
|
||||
|
||||
// Retrieves an entity by its unique (name, type) combination
|
||||
function getEntityByNameType(name, type) {
|
||||
const db = getDB();
|
||||
return parseEntity(db.prepare(`SELECT * FROM entities WHERE name = ? AND type = ?`).get(name, type));
|
||||
}
|
||||
|
||||
// Retrive all relationships originating from a given entity
|
||||
function getRelationshipsByEntity(entityId) {
|
||||
const db = getDB();
|
||||
return db.prepare(`SELECT * FROM relationships WHERE from_id = ?`).all(entityId).map(parseRelationship);
|
||||
}
|
||||
|
||||
// Delete a specific relationship by (from_id, to_id, label)
|
||||
function deleteRelationship(fromid, toId, label) {
|
||||
const db = getDB();
|
||||
|
||||
db.prepare(`DELETE FROM relationships WHERE from_id = ? AND to_id = ? AND label = ?`).run(fromId, toId, label);
|
||||
}
|
||||
|
||||
/*********** Parse Functions ***********/
|
||||
|
||||
function parseEntity(row) {
|
||||
if (!row) return null;
|
||||
return {
|
||||
...row,
|
||||
metadata: row.metadata ? JSON.parse(row.metadata) : null
|
||||
};
|
||||
}
|
||||
|
||||
function parseRelationship(row) {
|
||||
if (!row) return null;
|
||||
return {
|
||||
...row,
|
||||
metadata: row.metadata ? JSON.parse(row.metadata) : null
|
||||
};
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
upsertEntity,
|
||||
getEntity,
|
||||
getEntitiesByType,
|
||||
getEntityByNameType,
|
||||
deleteEntity,
|
||||
upsertRelationship,
|
||||
getRelationship,
|
||||
getRelationshipsByEntity,
|
||||
deleteRelationship
|
||||
}
|
||||
@@ -4,6 +4,7 @@ const {getEnv} = require('@nexusai/shared');
|
||||
const { getDB } = require('./db');
|
||||
const episodic = require('./episodic');
|
||||
const semantic = require('./semantic');
|
||||
const entities = require('./entities');
|
||||
|
||||
const app = express();
|
||||
app.use(express.json());
|
||||
@@ -94,6 +95,68 @@ app.delete('/episodes/:id', (req, res) => {
|
||||
res.status(204).send();
|
||||
});
|
||||
|
||||
/*********************************** */
|
||||
/********** Entity Routes ********** */
|
||||
/*********************************** */
|
||||
//Upsert an entity, creates or updates if already exists
|
||||
app.post('/entities', (req, res) => {
|
||||
const {name, type, notes, metadata} = req.body;
|
||||
if (!name || !type) {
|
||||
return res.status(400).json({ error: 'name and type are required' });
|
||||
}
|
||||
const entity = entities.upsertEntity(name, type, notes, metadata);
|
||||
res.status(201).json(entity);
|
||||
});
|
||||
|
||||
// Get an entity by ID
|
||||
app.get('/entities/:id', (req, res) => {
|
||||
const entity = entities.getEntity(req.params.id);
|
||||
if (!entity) return res.status(404).json({ error: 'Entity not found' });
|
||||
res.json(entity);
|
||||
});
|
||||
|
||||
// Get all entities of a given type
|
||||
app.get('/entities/by-type/:type', (req, res) => {
|
||||
res.json(entities.getEntitiesByType(req.params.type));
|
||||
});
|
||||
|
||||
// Delete an entity by ID
|
||||
app.delete('/entities/:id', (req, res) => {
|
||||
entities.deleteEntity(req.params.id);
|
||||
res.status(204).send();
|
||||
});
|
||||
|
||||
/***************************************** */
|
||||
/********** Relationship Routes ********** */
|
||||
/***************************************** */
|
||||
|
||||
// Upsert a relationship between two entities
|
||||
app.post('/relationships', (req, res) => {
|
||||
const {fromId, toId, label, metadata } = req.body;
|
||||
if (!fromId || !toId || !label) {
|
||||
return res.status(400).json({ error: 'fromId, toId and label are required' });
|
||||
}
|
||||
const relationship = entities.upsertRelationship(fromId, toId, label, metadata);
|
||||
res.status(201).json(relationship);
|
||||
});
|
||||
|
||||
// Get all relationships for a given entity ID
|
||||
app.get('/entities/:id/relationships', (req, res) => {
|
||||
res.json(entities.getRelationshipsByEntity(req.params.id));
|
||||
});
|
||||
|
||||
// Delete a specific relationship
|
||||
app.delete('/relationships', (req, res) => {
|
||||
const {fromId, toId, label} = req.body;
|
||||
if (!fromId || !toId || !label) {
|
||||
return res.status(400).json({ error: 'fromId, toId and label are required' });
|
||||
}
|
||||
entities.deleteRelationship(fromId, toId, label);
|
||||
res.status(204).send();
|
||||
})
|
||||
|
||||
|
||||
|
||||
/********************************** */
|
||||
/********** Start Server ********** */
|
||||
/********************************** */
|
||||
|
||||
Reference in New Issue
Block a user